This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push:
new 51d2c3e Space update
51d2c3e is described below
commit 51d2c3e7502f9e734aa47973beb6db5a679b1c23
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Thu Dec 1 19:59:54 2022 -0500
Space update
---
karavan-designer/src/App.tsx | 6 +-
.../snippets/org.apache.camel.AggregationStrategy | 22 +++
.../public/snippets/org.apache.camel.Processor | 14 ++
karavan-space/src/App.tsx | 9 +-
karavan-space/src/components/ComponentCard.tsx | 2 +-
karavan-space/src/designer/DesignerPage.tsx | 113 --------------
karavan-space/src/designer/KaravanDesigner.tsx | 56 ++++---
.../src/designer/error/ErrorHandlerCard.tsx | 48 ++++++
.../src/designer/error/ErrorHandlerDesigner.tsx | 164 +++++++++++++++++++++
karavan-space/src/designer/karavan.css | 37 +++--
karavan-space/src/designer/route/RouteDesigner.tsx | 1 +
.../designer/route/property/DslPropertyField.tsx | 106 ++++++++-----
.../src/designer/route/property/ModalEditor.tsx | 99 +++++++++++++
karavan-space/src/designer/utils/CamelUi.tsx | 55 ++++---
karavan-space/src/eip/EipCard.tsx | 2 +-
karavan-space/src/kamelets/KameletCard.tsx | 11 +-
karavan-space/src/kamelets/KameletsPage.tsx | 43 +++---
karavan-space/src/space/SpacePage.tsx | 11 +-
18 files changed, 574 insertions(+), 225 deletions(-)
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index cbf6150..fb876c1 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -112,11 +112,11 @@ class App extends React.Component<Props, State> {
components.forEach(c => jsons.push(JSON.stringify(c)));
ComponentApi.saveComponents(jsons, true);
- TemplateApi.saveTemplate("org.apache.camel.AggregationStrategy",
data[2]);
- TemplateApi.saveTemplate("org.apache.camel.Processor", data[3]);
-
this.toast("Success", "Loaded " + jsons.length + " components",
'success');
this.setState({loaded: true});
+
+ TemplateApi.saveTemplate("org.apache.camel.AggregationStrategy",
data[2]);
+ TemplateApi.saveTemplate("org.apache.camel.Processor", data[3]);
}).catch(err =>
this.toast("Error", err.text, 'danger')
);
diff --git a/karavan-space/public/snippets/org.apache.camel.AggregationStrategy
b/karavan-space/public/snippets/org.apache.camel.AggregationStrategy
new file mode 100644
index 0000000..4dcc882
--- /dev/null
+++ b/karavan-space/public/snippets/org.apache.camel.AggregationStrategy
@@ -0,0 +1,22 @@
+import org.apache.camel.AggregationStrategy;
+import org.apache.camel.Exchange;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+@Singleton
+@Named("NAME")
+public class NAME implements AggregationStrategy {
+ @Override
+ public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
+
+ if (oldExchange == null) {
+ return newExchange;
+ }
+
+ String oldBody = oldExchange.getIn().getBody(String.class);
+ String newBody = newExchange.getIn().getBody(String.class);
+ oldExchange.getIn().setBody(oldBody + "+" + newBody);
+ return oldExchange;
+ }
+}
\ No newline at end of file
diff --git a/karavan-space/public/snippets/org.apache.camel.Processor
b/karavan-space/public/snippets/org.apache.camel.Processor
new file mode 100644
index 0000000..6b81323
--- /dev/null
+++ b/karavan-space/public/snippets/org.apache.camel.Processor
@@ -0,0 +1,14 @@
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+@Singleton
+@Named("NAME")
+public class NAME implements Processor {
+
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("Hello World");
+ }
+}
\ No newline at end of file
diff --git a/karavan-space/src/App.tsx b/karavan-space/src/App.tsx
index 9f12428..227a5cb 100644
--- a/karavan-space/src/App.tsx
+++ b/karavan-space/src/App.tsx
@@ -35,8 +35,8 @@ import './designer/karavan.css';
import {SpacePage} from "./space/SpacePage";
import {GithubModal} from "./space/GithubModal";
import {Subscription} from "rxjs";
-import {DslPosition, EventBus} from "./designer/utils/EventBus";
import {AlertMessage, SpaceBus} from "./space/SpaceBus";
+import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
class ToastMessage {
id: string = ''
@@ -104,7 +104,9 @@ class App extends React.Component<Props, State> {
this.setState({sub: sub});
Promise.all([
fetch("kamelets/kamelets.yaml"),
- fetch("components/components.json")
+ fetch("components/components.json"),
+ fetch("snippets/org.apache.camel.AggregationStrategy"),
+ fetch("snippets/org.apache.camel.Processor")
]).then(responses =>
Promise.all(responses.map(response => response.text()))
).then(data => {
@@ -120,6 +122,9 @@ class App extends React.Component<Props, State> {
this.toast("Success", "Loaded " + jsons.length + " components",
'success');
this.setState({loaded: true, key: Math.random().toString()});
+
+ TemplateApi.saveTemplate("org.apache.camel.AggregationStrategy",
data[2]);
+ TemplateApi.saveTemplate("org.apache.camel.Processor", data[3]);
}).catch(err =>
this.toast("Error", err.text, 'danger')
);
diff --git a/karavan-space/src/components/ComponentCard.tsx
b/karavan-space/src/components/ComponentCard.tsx
index 1fe5269..ba18bd4 100644
--- a/karavan-space/src/components/ComponentCard.tsx
+++ b/karavan-space/src/components/ComponentCard.tsx
@@ -51,7 +51,7 @@ export class ComponentCard extends React.Component<Props,
State> {
<CardHeader>
{CamelUi.getIconFromSource(camelIcon)}
</CardHeader>
-
<CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardTitle>{component.component.title}</CardTitle>
<CardBody>{component.component.description}</CardBody>
<CardFooter>
<Badge isRead
className="labels">{component.component.label}</Badge>
diff --git a/karavan-space/src/designer/DesignerPage.tsx
b/karavan-space/src/designer/DesignerPage.tsx
deleted file mode 100644
index baee350..0000000
--- a/karavan-space/src/designer/DesignerPage.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react';
-import {
- Toolbar,
- ToolbarContent,
- ToolbarItem,
- PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem,
Badge, Button, Tooltip
-} from '@patternfly/react-core';
-import '../designer/karavan.css';
-import DownloadIcon from
"@patternfly/react-icons/dist/esm/icons/download-icon";
-import DownloadImageIcon from
"@patternfly/react-icons/dist/esm/icons/image-icon";
-import {KaravanDesigner} from "./KaravanDesigner";
-
-interface Props {
- name: string,
- yaml: string,
- dark: boolean,
- onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
-}
-
-interface State {
- karavanDesignerRef: any,
-}
-
-export class DesignerPage extends React.Component<Props, State> {
-
- public state: State = {
-
- karavanDesignerRef: React.createRef(),
- };
-
- componentDidMount() {
- }
-
- save(filename: string, yaml: string, propertyOnly: boolean) {
- this.props.onSave?.call(this, filename, yaml, propertyOnly);
- }
-
- download = () => {
- const {name, yaml} = this.props;
- if (name && yaml) {
- const a = document.createElement('a');
- a.setAttribute('download', 'example.yaml');
- a.setAttribute('href', 'data:text/plain;charset=utf-8,' +
encodeURIComponent(yaml));
- a.click();
- }
- }
-
- downloadImage = () => {
- if (this.state.karavanDesignerRef) {
- this.state.karavanDesignerRef.current.downloadImage();
- }
- }
-
- render() {
- const {name, yaml} = this.props;
- return (
- <PageSection className="kamelet-section designer-page"
padding={{default: 'noPadding'}}>
- <PageSection className="tools-section" padding={{default:
'noPadding'}}
- style={{backgroundColor:"transparent",
paddingLeft: "var(--pf-c-page__main-section--PaddingLeft)"}}>
- <Flex className="tools" justifyContent={{default:
'justifyContentSpaceBetween'}}>
- <FlexItem>
- <TextContent className="header">
- <Text component="h2">Designer</Text>
- </TextContent>
- </FlexItem>
- <FlexItem>
- <Toolbar id="toolbar-group-types">
- <ToolbarContent>
- <ToolbarItem>
- <Tooltip content="Download YAML"
position={"bottom"}>
- <Button variant="primary"
icon={<DownloadIcon/>} onClick={e => this.download()}>
- YAML
- </Button>
- </Tooltip>
- </ToolbarItem>
- <ToolbarItem>
- <Tooltip content="Download image"
position={"bottom"}>
- <Button variant="secondary"
icon={<DownloadImageIcon/>} onClick={e => this.downloadImage()}>
- Image
- </Button>
- </Tooltip>
- </ToolbarItem>
- </ToolbarContent>
- </Toolbar>
- </FlexItem>
- </Flex>
- </PageSection>
- <KaravanDesigner
- dark={this.props.dark}
- ref={this.state.karavanDesignerRef}
- filename={name}
- yaml={yaml}
- onSave={(filename, yaml, propertyOnly) =>
this.save(filename, yaml, propertyOnly)}/>
- </PageSection>
- );
- }
-};
\ No newline at end of file
diff --git a/karavan-space/src/designer/KaravanDesigner.tsx
b/karavan-space/src/designer/KaravanDesigner.tsx
index 6333b37..b215192 100644
--- a/karavan-space/src/designer/KaravanDesigner.tsx
+++ b/karavan-space/src/designer/KaravanDesigner.tsx
@@ -27,13 +27,13 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {CamelUi} from "./utils/CamelUi";
import {BeansDesigner} from "./beans/BeansDesigner";
import {RestDesigner} from "./rest/RestDesigner";
-import {ErrorDesigner} from "./error/ErrorDesigner";
-import {ExceptionDesigner} from "./exception/ExceptionDesigner";
+import {ErrorHandlerDesigner} from "./error/ErrorHandlerDesigner";
import {getDesignerIcon} from "./utils/KaravanIcons";
interface Props {
- onSave?: (filename: string, yaml: string, propertyOnly: boolean) => void
- onDisableHelp?: () => void
+ onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
+ onSaveCustomCode: (name: string, code: string) => void
+ onGetCustomCode: (name: string, javaType: string) => Promise<string |
undefined>
filename: string
yaml: string
dark: boolean
@@ -48,6 +48,22 @@ interface State {
routeDesignerRef?: any
}
+export class KaravanInstance {
+ static designer: KaravanDesigner;
+
+ static set(designer: KaravanDesigner): void {
+ KaravanInstance.designer = designer;
+ }
+
+ static get(): KaravanDesigner {
+ return KaravanInstance.designer;
+ }
+
+ static getProps(): Props {
+ return KaravanInstance.designer?.props;
+ }
+}
+
export class KaravanDesigner extends React.Component<Props, State> {
getIntegration = (yaml: string, filename: string): Integration => {
@@ -66,6 +82,10 @@ export class KaravanDesigner extends React.Component<Props,
State> {
routeDesignerRef: React.createRef(),
}
+ componentDidMount() {
+ KaravanInstance.set(this);
+ }
+
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
if (prevState.key !== this.state.key) {
this.props.onSave?.call(this, this.props.filename,
this.getCode(this.state.integration), this.state.propertyOnly);
@@ -112,21 +132,21 @@ export class KaravanDesigner extends
React.Component<Props, State> {
<Tab eventKey='routes' title={this.getTab("Routes",
"Integration flows", "routes")}></Tab>
<Tab eventKey='rest' title={this.getTab("REST", "REST
services", "rest")}></Tab>
<Tab eventKey='beans' title={this.getTab("Beans", "Beans
Configuration", "beans")}></Tab>
- <Tab eventKey='error' title={this.getTab("Error", "Error
Handler", "error")}></Tab>
+ <Tab eventKey='error' title={this.getTab("Error Handler",
"Global Error Handler", "error")}></Tab>
</Tabs>
- {tab === 'routes' && <RouteDesigner
integration={this.state.integration}
- onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}
-
ref={this.state.routeDesignerRef}/>}
- {tab === 'rest' && <RestDesigner
integration={this.state.integration}
- onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}/>}
- {tab === 'beans' && <BeansDesigner
integration={this.state.integration}
- onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}/>}
- {tab === 'error' && <ErrorDesigner
integration={this.state.integration}
- onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}/>}
+ {tab === 'routes' && <RouteDesigner
integration={this.state.integration}
+ onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
+ dark={this.props.dark}
+
ref={this.state.routeDesignerRef}/>}
+ {tab === 'rest' && <RestDesigner
integration={this.state.integration}
+ onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
+ dark={this.props.dark}/>}
+ {tab === 'beans' && <BeansDesigner
integration={this.state.integration}
+ onSave={(integration,
propertyOnly) => this.save(integration, propertyOnly)}
+
dark={this.props.dark}/>}
+ {tab === 'error' && <ErrorHandlerDesigner
integration={this.state.integration}
+
onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
+
dark={this.props.dark}/>}
</PageSection>
)
}
diff --git a/karavan-space/src/designer/error/ErrorHandlerCard.tsx
b/karavan-space/src/designer/error/ErrorHandlerCard.tsx
new file mode 100644
index 0000000..f0d534c
--- /dev/null
+++ b/karavan-space/src/designer/error/ErrorHandlerCard.tsx
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {ErrorHandlerDefinition} from "karavan-core/lib/model/CamelDefinition";
+import DeleteIcon from
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
+
+interface Props {
+ errorHandler: ErrorHandlerDefinition
+ deleteElement: (element: ErrorHandlerDefinition) => void
+}
+
+export class ErrorHandlerCard extends React.Component<Props, any> {
+
+ delete = (evt: React.MouseEvent) => {
+ evt.stopPropagation();
+ this.props.deleteElement.call(this, this.props.errorHandler);
+ }
+
+ render() {
+ return (
+ <div className="rest-card rest-card-selected">
+ <div className="header">
+ <div className="title">Error Handler</div>
+ <div className="description">Global error handler for the
RouteBuilder</div>
+ <Button variant="link" className="delete-button"
onClick={e => this.delete(e)}><DeleteIcon/></Button>
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/karavan-space/src/designer/error/ErrorHandlerDesigner.tsx
b/karavan-space/src/designer/error/ErrorHandlerDesigner.tsx
new file mode 100644
index 0000000..ba35ccc
--- /dev/null
+++ b/karavan-space/src/designer/error/ErrorHandlerDesigner.tsx
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button, Drawer, DrawerContent, DrawerContentBody, DrawerPanelContent,
Modal, PageSection
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {ErrorHandlerDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {CamelElement, Integration} from
"karavan-core/lib/model/IntegrationDefinition";
+import {CamelUi} from "../utils/CamelUi";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {ErrorHandlerCard} from "./ErrorHandlerCard";
+import {DslProperties} from "../route/DslProperties";
+
+interface Props {
+ onSave?: (integration: Integration, propertyOnly: boolean) => void
+ integration: Integration
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ showDeleteConfirmation: boolean
+ errorHandler?: ErrorHandlerDefinition
+ key: string
+ propertyOnly: boolean
+}
+
+export class ErrorHandlerDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ showDeleteConfirmation: false,
+ key: "",
+ propertyOnly: false
+ }
+
+ componentDidMount() {
+ this.setState({key: Math.random().toString()})
+ }
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration,
this.state.propertyOnly);
+ }
+ }
+
+ showDeleteConfirmation = (errorHandler: ErrorHandlerDefinition) => {
+ this.setState({errorHandler: errorHandler, showDeleteConfirmation:
true});
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, propertyOnly: false,
showDeleteConfirmation: false, key: Math.random().toString()});
+ }
+
+ deleteErrorHandler = () => {
+ const i =
CamelDefinitionApiExt.deleteErrorHandlerFromIntegration(this.state.integration);
+ this.setState({
+ integration: i,
+ showDeleteConfirmation: false,
+ key: Math.random().toString(),
+ errorHandler: undefined,
+ propertyOnly: false
+ });
+ }
+
+ changeErrorHandler = (errorHandler: ErrorHandlerDefinition) => {
+ const clone = CamelUtil.cloneIntegration(this.state.integration);
+ const i = CamelDefinitionApiExt.addErrorHandlerToIntegration(clone,
errorHandler);
+ this.setState({integration: i, propertyOnly: false, key:
Math.random().toString(), errorHandler: errorHandler});
+ }
+
+ getDeleteConfirmation() {
+ return (<Modal
+ className="modal-delete"
+ title="Confirmation"
+ isOpen={this.state.showDeleteConfirmation}
+ onClose={() => this.setState({showDeleteConfirmation: false})}
+ actions={[
+ <Button key="confirm" variant="primary" onClick={e =>
this.deleteErrorHandler()}>Delete</Button>,
+ <Button key="cancel" variant="link"
+ onClick={e => this.setState({showDeleteConfirmation:
false})}>Cancel</Button>
+ ]}
+ onEscapePress={e => this.setState({showDeleteConfirmation:
false})}>
+ <div>
+ Delete Global Error Handler from integration?
+ </div>
+ </Modal>)
+ }
+
+ createErrorHandlerErrorHandle = () => {
+ this.changeErrorHandler(new ErrorHandlerDefinition());
+ }
+
+ onPropertyUpdate = (element: CamelElement) => {
+ const clone = CamelUtil.cloneIntegration(this.state.integration);
+ const i = CamelDefinitionApiExt.addErrorHandlerToIntegration(clone,
element);
+ this.setState({integration: i, propertyOnly: true, key:
Math.random().toString()});
+ }
+
+ getPropertiesPanel(errorHandler?: ErrorHandlerDefinition) {
+ return (
+ <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'}
maxSize={'800px'} minSize={'300px'}>
+ <DslProperties
+ integration={this.props.integration}
+ step={errorHandler}
+ onIntegrationUpdate={this.onIntegrationUpdate}
+ onPropertyUpdate={this.onPropertyUpdate}
+ clipboardStep={undefined}
+ isRouteDesigner={false}
+ onClone={element => {}}
+ dark={this.props.dark}/>
+ </DrawerPanelContent>
+ )
+ }
+
+ render() {
+ const errorHandler = CamelUi.getErrorHandler(this.state.integration);
+ return (
+ <PageSection className="rest-page" isFilled padding={{default:
'noPadding'}}>
+ <div className="rest-page-columns">
+ <Drawer isExpanded isInline>
+ <DrawerContent
panelContent={this.getPropertiesPanel(errorHandler)}>
+ <DrawerContentBody>
+ <div className="graph" data-click="REST">
+ <div className="flows">
+ {errorHandler && <ErrorHandlerCard
key={errorHandler.uuid + this.state.key}
+
errorHandler={errorHandler}
+
deleteElement={this.showDeleteConfirmation}/>}
+ <div className="add-rest">
+ {errorHandler === undefined &&
<Button
+ variant="primary"
+ data-click="ADD_REST"
+ icon={<PlusIcon/>}
+ onClick={e =>
this.createErrorHandlerErrorHandle()}>Create new error handler
+ </Button>}
+ </div>
+ </div>
+ </div>
+ </DrawerContentBody>
+ </DrawerContent>
+ </Drawer>
+ </div>
+ {this.getDeleteConfirmation()}
+ </PageSection>
+ )
+ }
+}
diff --git a/karavan-space/src/designer/karavan.css
b/karavan-space/src/designer/karavan.css
index 38e2973..2ae90aa 100644
--- a/karavan-space/src/designer/karavan.css
+++ b/karavan-space/src/designer/karavan.css
@@ -125,7 +125,16 @@
}
.kamelets-page .kamelet-card .pf-c-card__header {
- padding-right: 6px;
+ /*padding-right: 6px;*/
+}
+
+.kamelets-page .kamelet-card .pf-c-card__header .custom {
+ margin-left: auto;
+}
+
+.kamelets-page .kamelet-card .pf-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
}
.kamelets-page .kamelet-card .pf-c-card__body {
@@ -145,6 +154,13 @@
user-select: none;
}
+.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+
/*kamelet modal*/
.kamelet-modal-card .pf-c-card__header {
padding-right: 6px;
@@ -452,7 +468,7 @@
width: 350px;
}
-.karavan .properties .add-button {
+.karavan .properties .change-button {
font-size: 15px;
height: 15px;
line-height: 1;
@@ -462,10 +478,18 @@
background: transparent;
}
-.karavan .properties .add-button svg {
+.karavan .properties .change-button svg {
margin-right: 6px;
}
+.karavan .properties .add-button {
+ color: var(--pf-global--active-color--100);
+}
+
+.karavan .properties .delete-button {
+ color: #909090;
+}
+
.karavan .properties .pf-c-expandable-section__toggle {
margin: 0;
padding: 0;
@@ -1133,12 +1157,6 @@
margin-right: auto;
}
-/*Catalogues*/
-.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
.karavan .tools-section .tools .header {
display: flex;
@@ -1274,6 +1292,7 @@
overflow: auto;
flex-shrink: unset;
flex-grow: 1;
+ background-color: var(--pf-global--BackgroundColor--light-300);
}
.karavan .designer-page {
diff --git a/karavan-space/src/designer/route/RouteDesigner.tsx
b/karavan-space/src/designer/route/RouteDesigner.tsx
index 14ded06..6c976a9 100644
--- a/karavan-space/src/designer/route/RouteDesigner.tsx
+++ b/karavan-space/src/designer/route/RouteDesigner.tsx
@@ -40,6 +40,7 @@ import {CamelUi, RouteToCreate} from "../utils/CamelUi";
import {findDOMNode} from "react-dom";
import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
import {toPng} from 'html-to-image';
+import {KaravanDesigner} from "../KaravanDesigner";
interface Props {
onSave?: (integration: Integration, propertyOnly: boolean) => void
diff --git a/karavan-space/src/designer/route/property/DslPropertyField.tsx
b/karavan-space/src/designer/route/property/DslPropertyField.tsx
index 9f4504e..f553cfe 100644
--- a/karavan-space/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-space/src/designer/route/property/DslPropertyField.tsx
@@ -36,8 +36,6 @@ import {
Tooltip,
Card,
InputGroup,
- Modal,
- ModalVariant, Title, TitleSizes
} from '@patternfly/react-core';
import '../../karavan.css';
import "@patternfly/patternfly/patternfly.css";
@@ -64,8 +62,10 @@ import ExpandIcon from
"@patternfly/react-icons/dist/js/icons/expand-icon";
import KubernetesIcon from
"@patternfly/react-icons/dist/js/icons/openshift-icon";
import {KubernetesSelector} from "./KubernetesSelector";
import {KubernetesAPI} from "../../utils/KubernetesAPI";
-import Editor from "@monaco-editor/react";
import EditorIcon from "@patternfly/react-icons/dist/js/icons/code-icon";
+import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
+import {ModalEditor} from "./ModalEditor";
+import {KaravanInstance} from "../../KaravanDesigner";
interface Props {
property: PropertyMeta,
@@ -88,6 +88,7 @@ interface State {
showEditor: boolean
showKubernetesSelector: boolean
kubernetesSelectorProperty?: string
+ customCode?: string
ref: any
}
@@ -148,13 +149,14 @@ export class DslPropertyField extends
React.Component<Props, State> {
getLabel = (property: PropertyMeta, value: any) => {
if (!this.isMultiValueField(property) && property.isObject &&
!property.isArray && !["ExpressionDefinition"].includes(property.type)) {
const tooltip = value ? "Delete " + property.name : "Add " +
property.name;
+ const className = value ? "change-button delete-button" :
"change-button add-button";
const x = value ? undefined :
CamelDefinitionApi.createStep(property.type, {});
const icon = value ? (<DeleteIcon noVerticalAlign/>) : (<AddIcon
noVerticalAlign/>);
return (
<div style={{display: "flex"}}>
<Text>{property.displayName} </Text>
- <Tooltip position={"bottom"}
content={<div>{tooltip}</div>}>
- <button className="add-button" onClick={e =>
this.props.onChange?.call(this, property.name, x)} aria-label="Add element">
+ <Tooltip position={"top"} content={<div>{tooltip}</div>}>
+ <button className={className} onClick={e =>
this.props.onChange?.call(this, property.name, x)} aria-label="Add element">
{icon}
</button>
</Tooltip>
@@ -243,9 +245,52 @@ export class DslPropertyField extends
React.Component<Props, State> {
</InputGroup>)
}
+ showCode = (name: string, javaType: string) => {
+ const {property} = this.props;
+ KaravanInstance.getProps().onGetCustomCode.call(this, name,
property.javaType).then(value => {
+ if (value === undefined) {
+ const code = TemplateApi.generateCode(property.javaType, name);
+ this.setState({customCode: code, showEditor: true})
+ } else {
+ this.setState({customCode: value, showEditor: true})
+ }
+ }).catch(reason => console.log(reason))
+ }
+
+ getJavaTypeGeneratedInput = (property: PropertyMeta, value: any) => {
+ const {dslLanguage, dark} = this.props;
+ const {showEditor, customCode} = this.state;
+ return (<InputGroup>
+ <TextInput
+ ref={this.state.ref}
+ className="text-field" isRequired
isReadOnly={this.isUriReadOnly(property)}
+ type="text"
+ id={property.name} name={property.name}
+ value={value?.toString()}
+ onChange={e => this.propertyChanged(property.name,
CamelUtil.capitalizeName(e?.replace(/\s/g, '')))}/>
+ <Tooltip position="bottom-end" content={"Create Java Class"}>
+ <Button variant="control" onClick={e => this.showCode(value,
property.javaType)}>
+ <PlusIcon/>
+ </Button>
+ </Tooltip>
+ <ModalEditor property={property}
+ customCode={customCode}
+ showEditor={showEditor}
+ dark={dark}
+ dslLanguage={dslLanguage}
+ title="Java Class"
+ onClose={() => this.setState({showEditor: false})}
+ onSave={(fieldId, value1) => {
+ this.propertyChanged(fieldId, value);
+
KaravanInstance.getProps().onSaveCustomCode?.call(this, value, value1);
+ this.setState({showEditor: false});
+ }}/>
+ </InputGroup>)
+ }
+
getTextArea = (property: PropertyMeta, value: any) => {
const {dslLanguage, dark} = this.props;
- const showEditor = this.state.showEditor;
+ const {showEditor} = this.state;
return (
<InputGroup>
<TextArea
@@ -261,37 +306,17 @@ export class DslPropertyField extends
React.Component<Props, State> {
<EditorIcon/>
</Button>
</Tooltip>
- <Modal
- variant={ModalVariant.large}
- header={<React.Fragment>
- <Title id="modal-custom-header-label"
headingLevel="h1" size={TitleSizes['2xl']}>
- {`Expression (${dslLanguage?.[0]})`}
- </Title>
- <p className="pf-u-pt-sm">{dslLanguage?.[2]}</p>
- </React.Fragment>}
- isOpen={this.state.showEditor}
- onClose={() => this.setState({showEditor: false})}
- actions={[
- <Button key="cancel" variant="primary" isSmall
- onClick={e => this.setState({showEditor:
false})}>Close</Button>
- ]}
- onEscapePress={e => this.setState({showEditor: false})}>
- <Editor
- height="400px"
- width="100%"
- defaultLanguage={'java'}
- language={'java'}
- theme={dark ? 'vs-dark' : 'light'}
- options={{lineNumbers:"off", folding:false,
lineNumbersMinChars:10, showUnused:false, fontSize:12, minimap:{enabled:false}}}
- value={value?.toString()}
- className={'code-editor'}
- onChange={(value: any, ev: any) => {
- if (value) {
- this.propertyChanged(property.name, value)
- }
- }}
- />
- </Modal>
+ <ModalEditor property={property}
+ customCode={value}
+ showEditor={showEditor}
+ dark={dark}
+ dslLanguage={dslLanguage}
+ title={`Expression (${dslLanguage?.[0]})`}
+ onClose={() => this.setState({showEditor: false})}
+ onSave={(fieldId, value1) => {
+ this.propertyChanged(fieldId, value1);
+ this.setState({showEditor: false});
+ }}/>
</InputGroup>
)
}
@@ -433,6 +458,10 @@ export class DslPropertyField extends
React.Component<Props, State> {
}
}
+ javaTypeGenerated = (property: PropertyMeta): boolean => {
+ return property.javaType.length !== 0;
+ }
+
getInternalUriSelect = (property: PropertyMeta, value: any) => {
const selectOptions: JSX.Element[] = [];
const urls = CamelUi.getInternalRouteUris(this.props.integration,
"direct");
@@ -672,10 +701,13 @@ export class DslPropertyField extends
React.Component<Props, State> {
&& this.getInternalUriSelect(property, value)}
{this.canBeMediaType(property, this.props.element)
&& this.getMediaTypeSelect(property, value)}
+ {this.javaTypeGenerated(property)
+ && this.getJavaTypeGeneratedInput(property, value)}
{['string', 'duration', 'integer',
'number'].includes(property.type) && property.name !== 'expression' &&
!property.name.endsWith("Ref")
&& !property.isArray && !property.enumVals
&& !this.canBeInternalUri(property, this.props.element)
&& !this.canBeMediaType(property, this.props.element)
+ && !this.javaTypeGenerated(property)
&& this.getStringInput(property, value)}
{['string'].includes(property.type) &&
property.name.endsWith("Ref") && !property.isArray && !property.enumVals
&& this.getSelectBean(property, value)}
diff --git a/karavan-space/src/designer/route/property/ModalEditor.tsx
b/karavan-space/src/designer/route/property/ModalEditor.tsx
new file mode 100644
index 0000000..0d5568e
--- /dev/null
+++ b/karavan-space/src/designer/route/property/ModalEditor.tsx
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Modal,
+ ModalVariant, Title, TitleSizes
+} from '@patternfly/react-core';
+import '../../karavan.css';
+import "@patternfly/patternfly/patternfly.css";
+import {PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
+import Editor from "@monaco-editor/react";
+
+interface Props {
+ property: PropertyMeta,
+ customCode: any,
+ onSave: (fieldId: string, value: string | number | boolean | any) => void,
+ onClose: () => void,
+ title: string,
+ dslLanguage?: [string, string, string],
+ dark: boolean
+ showEditor: boolean
+}
+
+interface State {
+ customCode: any,
+}
+
+export class ModalEditor extends React.Component<Props, State> {
+
+ public state: State = {
+ customCode: this.props.customCode,
+ }
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevProps.showEditor !== this.props.showEditor) {
+ this.setState({customCode: this.props.customCode})
+ }
+ }
+
+ close(){
+ this.props.onClose?.call(this);
+ }
+
+ closeAndSave(){
+ this.props.onSave?.call(this, this.props.property.name,
this.state.customCode);
+ }
+
+ render() {
+ const {dark, dslLanguage, title, showEditor} = this.props;
+ const {customCode} = this.state;
+ return (
+ <Modal
+ aria-label={"expression"}
+ variant={ModalVariant.large}
+ header={<React.Fragment>
+ <Title id="modal-custom-header-label" headingLevel="h1"
size={TitleSizes['2xl']}>
+ {title}
+ </Title>
+ <p className="pf-u-pt-sm">{dslLanguage?.[2]}</p>
+ </React.Fragment>}
+ isOpen={showEditor}
+ onClose={() => this.close()}
+ actions={[
+ <Button key="save" variant="primary" isSmall
+ onClick={e => this.closeAndSave()}>Save</Button>,
+ <Button key="cancel" variant="secondary" isSmall
+ onClick={e => this.close()}>Close</Button>
+ ]}
+ onEscapePress={e => this.close()}>
+ <Editor
+ height="400px"
+ width="100%"
+ defaultLanguage={'java'}
+ language={'java'}
+ theme={dark ? 'vs-dark' : 'light'}
+ options={{lineNumbers: "off", folding: false,
lineNumbersMinChars: 10, showUnused: false, fontSize: 12, minimap: {enabled:
false}}}
+ value={customCode?.toString()}
+ className={'code-editor'}
+ onChange={(value: any, ev: any) =>
this.setState({customCode: value})}
+ />
+ </Modal>
+ )
+ }
+}
diff --git a/karavan-space/src/designer/utils/CamelUi.tsx
b/karavan-space/src/designer/utils/CamelUi.tsx
index 3083c36..51f8517 100644
--- a/karavan-space/src/designer/utils/CamelUi.tsx
+++ b/karavan-space/src/designer/utils/CamelUi.tsx
@@ -21,9 +21,9 @@ import {ComponentApi} from
"karavan-core/lib/api/ComponentApi";
import {CamelMetadataApi} from "karavan-core/lib/model/CamelMetadata";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
-import {NamedBeanDefinition, RouteDefinition, SagaDefinition, ToDefinition}
from "karavan-core/lib/model/CamelDefinition";
+import {ErrorHandlerDefinition, NamedBeanDefinition, RouteDefinition,
SagaDefinition, ToDefinition} from "karavan-core/lib/model/CamelDefinition";
import {CamelElement, Integration} from
"karavan-core/lib/model/IntegrationDefinition";
-import {AggregateIcon, ChoiceIcon, FilterIcon, SagaIcon, SortIcon, SplitIcon,
TransformIcon} from "./KaravanIcons";
+import {AggregateIcon, ChoiceIcon, FilterIcon, SagaIcon, SortIcon, SplitIcon}
from "./KaravanIcons";
import React from "react";
const StepElements: string[] = [
@@ -35,27 +35,34 @@ const StepElements: string[] = [
"ConvertBodyDefinition",
"DynamicRouterDefinition",
"EnrichDefinition",
- // "ErrorHandlerBuilderDeserializer",
// "ErrorHandlerDefinition",
"FilterDefinition",
+ "IdempotentConsumerDefinition",
"LogDefinition",
"LoopDefinition",
"MarshalDefinition",
"MulticastDefinition",
+ "PausableDefinition",
"PollEnrichDefinition",
"ProcessDefinition",
"RecipientListDefinition",
"RemoveHeaderDefinition",
"RemoveHeadersDefinition",
+ "RemovePropertiesDefinition",
"RemovePropertyDefinition",
+ "ResumableDefinition",
"ResequenceDefinition",
+ "RoutingSlipDefinition",
+ "SamplingDefinition",
"SagaDefinition",
"SetBodyDefinition",
"SetHeaderDefinition",
"SetPropertyDefinition",
"SortDefinition",
+ "ScriptDefinition",
"SplitDefinition",
"StepDefinition",
+ "StopDefinition",
"ThreadsDefinition",
"ThrottleDefinition",
"ThrowExceptionDefinition",
@@ -196,19 +203,6 @@ export class CamelUi {
return name.split("-").map(v => CamelUtil.capitalizeName(v)).join('');
}
- static titleFromName = (name?: string) => {
- name = name ? (name.substring(0, name.lastIndexOf('.')) || name) :
undefined;
- return name
- ? name
- .replace(".yaml", "")
- .split("-")
- .map((value) => CamelUtil.capitalizeName(value))
- .reduce(
- (previousValue, currentValue) => previousValue + " " +
currentValue
- )
- : name;
- }
-
static isActionKamelet = (element: CamelElement): boolean => {
const kamelet = CamelUtil.getKamelet(element);
if (kamelet) return kamelet.type() === 'action'
@@ -393,6 +387,8 @@ export class CamelUi {
return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpath d='m24,30l-20,0a2.0021,2.0021 0 0 1
-2,-2l0,-6a2.0021,2.0021 0 0 1 2,-2l20,0a2.0021,2.0021 0 0 1
2,2l0,6a2.0021,2.0021 0 0 1 -2,2zm-20,-8l-0.0015,0l0.0015,6l20,0l0,-6l-20,0z'
id='svg_1'/%3E%3Cpolygon id='svg_2' poi [...]
case "RemoveHeadersDefinition":
return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpolygon id='svg_2' points='32.12467002868652,6.015733242034912
32.12467002868652,4.021692276000977 27.047643661499023,4.021692276000977
27.047643661499023,-1.0553351640701294 25.05360221862793,-1.0553350448608398
25.053 [...]
+ case "RemovePropertiesDefinition":
+ return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpolygon id='svg_2' points='32.12467002868652,6.015733242034912
32.12467002868652,4.021692276000977 27.047643661499023,4.021692276000977
27.047643661499023,-1.0553351640701294 25.05360221862793,-1.0553350448608398
25.053 [...]
case "SetHeaderDefinition":
return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpath d='m24,30l-20,0a2.0021,2.0021 0 0 1
-2,-2l0,-6a2.0021,2.0021 0 0 1 2,-2l20,0a2.0021,2.0021 0 0 1
2,2l0,6a2.0021,2.0021 0 0 1 -2,2zm-20,-8l-0.0015,0l0.0015,6l20,0l0,-6l-20,0z'
id='svg_1'/%3E%3Cpolygon id='svg_2' poi [...]
case "SetPropertyDefinition":
@@ -408,7 +404,7 @@ export class CamelUi {
case "ConvertBodyDefinition":
return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpath d='m16,28l-8,0l0,-24l8,0l0,6a2.0058,2.0058 0 0 0
2,2l6,0l0,4l2,0l0,-6a0.9092,0.9092 0 0 0 -0.3,-0.7l-7,-7a0.9087,0.9087 0 0 0
-0.7,-0.3l-10,0a2.0058,2.0058 0 0 0 -2,2l0,24a2.0058,2.0058 0 0 0
2,2l8,0l0,-2zm2,-23.6l [...]
case "TransformDefinition":
- return "data:image/svg+xml,%0A%3Csvg width='32px'
height='32px' viewBox='0 0 32 32' id='icon'
xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:none;%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Escript%3C/title%3E%3Cpolygon
points='18.83 26 21.41 23.42 20 22 16 26 20 30 21.42 28.59 18.83
26'/%3E%3Cpolygon points='27.17 26 24.59 28.58 26 30 30 26 26 22 24.58 23.41
27.17 26'/%3E%3Cpath
d='M14,28H8V4h8v6a2.0058,2.0058,0,0,0,2,2h6v6h2V10a.9092.9092,0,0,0-.3-.7l-7
[...]
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+ZGF0YS1zaGFyZTwvdGl0bGU+PHBhdGggZD0iTTUsMjVWMTUuODI4MWwtMy41ODU5LDMuNTg2TDAsMThsNi02LDYsNi0xLjQxNDEsMS40MTQxTDcsMTUuODI4MVYyNUgxOXYySDdBMi4wMDI0LDIuMDAyNCwwLDAsMSw1LDI1WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwKSIvPjxwYXRoIGQ9Ik0yNCwyMmg0YTIuMDAyLD
[...]
case "EnrichDefinition":
return "data:image/svg+xml,%3Csvg width='32' height='32'
xmlns='http://www.w3.org/2000/svg'
xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1 %7B fill:
none; %7D%3C/style%3E%3C/defs%3E%3Cg class='layer'%3E%3Ctitle%3ELayer
1%3C/title%3E%3Cpolygon id='svg_1' points='4,20 4,22 8.586000442504883,22
2,28.586000442504883 3.4140000343322754,30 10,23.413999557495117 10,28 12,28
12,20 4,20 '/%3E%3Cpath d='m25.7,9.3l-7,-7a0.9087,0.9087 0 0 0
-0.7,-0.3l-10,0a2.005 [...]
case "PollEnrichDefinition":
@@ -439,6 +435,24 @@ export class CamelUi {
return "data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'
version='1.1' id='Layer_1' x='0px' y='0px' viewBox='0 0 305.001 305.001'
style='enable-background:new 0 0 305.001 305.001;' xml:space='preserve'%3E%3Cg
id='XMLID_7_'%3E%3Cpath id='XMLID_8_'
d='M150.99,56.513c-14.093,9.912-30.066,21.147-38.624,39.734c-14.865,32.426,30.418,67.798,32.353,69.288
c0.45,0.347,0.988,0.519,1.525,0.519c0.57,0,1.141-0.195,1.605-0.583c0.89 [...]
case "ProcessDefinition":
return "data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'
version='1.1' id='Capa_1' x='0px' y='0px' width='235.506px' height='235.506px'
viewBox='0 0 235.506 235.506' style='enable-background:new 0 0 235.506
235.506;' xml:space='preserve'%3E%3Cg%3E%3Cpath
d='M234.099,29.368c-3.025-4.861-10.303-7.123-22.915-7.123c-13.492,0-28.304,2.661-28.625,2.733
c-20.453,2.098-27.254,26.675-32.736,46.436c-1.924,6.969-3.755,13.549-5.8 [...]
+ case "ErrorHandlerDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+d2FybmluZzwvdGl0bGU+PHBhdGggZD0iTTE2LDJBMTQsMTQsMCwxLDAsMzAsMTYsMTQsMTQsMCwwLDAsMTYsMlptMCwyNkExMiwxMiwwLDEsMSwyOCwxNiwxMiwxMiwwLDAsMSwxNiwyOFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMCkiLz48cmVjdCB4PSIxNSIgeT0iOCIgd2lkdGg9IjIiIGhlaWdodD0iMTEiLz48cG
[...]
+ case "ScriptDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiBpZD0iRmxhdCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJNNDMuMTc1MjksMTI4YTI5Ljc4NTIsMjkuNzg1MiwwLDAsMSw4LjAyMywxMC4yNTk3N0M1NiwxNDguMTYzMDksNTYsMTYwLjI4MTI1LDU2LDE3MmMwLDI0LjMxMzQ4LDEuMDE5NTMsMzYsMjQsMzZhOCw4LDAsMCwxLDAsMTZjLTE3LjQ4MTQ1LDAtMjkuMzI0MjItNi4xNDM1NS0zNS4xOTgyNC0xOC4yNTk3N0M0MCwxOTUuODM2OTEsNDAsMTgzLjcxODc1LDQwLDE3MmMwLTI0LjMxMzQ4LT
[...]
+ case "PausableDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+cGF1c2UtLWZpbGxlZDwvdGl0bGU+PHBhdGggZD0iTTEyLDZIMTBBMiwyLDAsMCwwLDgsOFYyNGEyLDIsMCwwLDAsMiwyaDJhMiwyLDAsMCwwLDItMlY4YTIsMiwwLDAsMC0yLTJaIi8+PHBhdGggZD0iTTIyLDZIMjBhMiwyLDAsMCwwLTIsMlYyNGEyLDIsMCwwLDAsMiwyaDJhMiwyLDAsMCwwLDItMlY4YTIsMiwwLDAsMC
[...]
+ case "StopDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+c3RvcC0tZmlsbGVkPC90aXRsZT48cGF0aCBkPSJNMjQsNkg4QTIsMiwwLDAsMCw2LDhWMjRhMiwyLDAsMCwwLDIsMkgyNGEyLDIsMCwwLDAsMi0yVjhhMiwyLDAsMCwwLTItMloiLz48cmVjdCBpZD0iX1RyYW5zcGFyZW50X1JlY3RhbmdsZV8iIGRhdGEtbmFtZT0iJmx0O1RyYW5zcGFyZW50IFJlY3RhbmdsZSZndDsiIG
[...]
+ case "ResumableDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTVweCIgaGVpZ2h0PSIxNXB4IiB2aWV3Qm94PSIwIDAgMTUgMTUiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGgKICAgIGZpbGwtcnVsZT0iZXZlbm9kZCIKICAgIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgIGQ9Ik0zLjA0OTk1IDIuNzQ5OTVDMy4wNDk5NSAyLjQ0NjE5IDIuODAzNzEgMi4xOTk5NSAyLjQ5OTk1IDIuMTk5OTVDMi4xOTYxOSAyLjE5OTk1IDEuOTQ5OTUgMi40NDYxOSAxLjk0OTk1IDIuNzQ5OTVWMTIuMjVDMS45NDk5NSAxMi41NTM3IDIuMTk2MTkgMTIuOCAyLjQ5OTk1IDEyLjhDMi44MDM3MS
[...]
+ case "RoutingSlipDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+c2NoZW1hdGljczwvdGl0bGU+PHBhdGggZD0iTTI3LDE5LjAwMUE0LjAwNTYsNC4wMDU2LDAsMCwwLDIyLjk5OTEsMTVIOS4wMDExQTIuMDAzMSwyLjAwMzEsMCwwLDEsNywxMi45OTkxVjkuODU4QTMuOTk0OSwzLjk5NDksMCwwLDAsOS44NTgxLDdoMTIuMjg0YTQsNCwwLDEsMCwwLTJIOS44NTgxQTMuOTkxNiwzLjk5MT
[...]
+ case "ClaimCheckDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+Y2VydGlmaWNhdGUtLWNoZWNrPC90aXRsZT48cmVjdCB4PSI2IiB5PSIxNiIgd2lkdGg9IjYiIGhlaWdodD0iMiIvPjxyZWN0IHg9IjYiIHk9IjEyIiB3aWR0aD0iMTAiIGhlaWdodD0iMiIvPjxyZWN0IHg9IjYiIHk9IjgiIHdpZHRoPSIxMCIgaGVpZ2h0PSIyIi8+PHBhdGggZD0iTTE0LDI2SDRWNkgyOFYxNmgyVjZhMi
[...]
+ case "SamplingDefinition":
+ return
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MT
[...]
+ case "IdempotentConsumerDefinition":
+ return
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGlkPSJpY29uIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO308L3N0eWxlPjwvZGVmcz48dGl0bGU+cmVzZWFyY2gtLW1hdHJpeDwvdGl0bGU+PHBvbHlnb24gcG9pbnRzPSIxOCAxMyAxOCA0IDE2IDQgMTYgNiAxMyA2IDEzIDggMTYgOCAxNiAxMyAxMyAxMyAxMyAxNSAyMSAxNSAyMSAxMyAxOCAxMyIvPjxwYXRoIGQ9Ik0xNi41LDIwQTMuNSwzLjUsMCwxLDEsMTMsMjMuNSwzLjUsMy41LDAsMCwxLDE2LjUsMjBtMC0yQT
[...]
default:
return camelIcon;
}
@@ -473,7 +487,6 @@ export class CamelUi {
case 'ChoiceDefinition' :return <ChoiceIcon/>;
case 'SplitDefinition' :return <SplitIcon/>;
case 'SagaDefinition' :return <SagaIcon/>;
- case 'TransformDefinition' :return <TransformIcon/>;
case 'FilterDefinition' :return <FilterIcon/>;
case 'SortDefinition' :return <SortIcon/>;
default: return
this.getIconFromSource(CamelUi.getIconSrcForName(dslName))
@@ -499,6 +512,7 @@ export class CamelUi {
const result = new Map<string, number>();
result.set('routes', i.spec.flows?.filter((e: any) => e.dslName ===
'RouteDefinition').length || 0);
result.set('rest', i.spec.flows?.filter((e: any) => e.dslName ===
'RestDefinition').length || 0);
+ result.set('error', i.spec.flows?.filter((e: any) => e.dslName ===
'ErrorHandlerDefinition').length || 0);
const beans = i.spec.flows?.filter((e: any) => e.dslName === 'Beans');
if (beans && beans.length > 0 && beans[0].beans &&
beans[0].beans.length > 0){
result.set('beans', Array.from(beans[0].beans).length);
@@ -521,4 +535,9 @@ export class CamelUi {
}
return result;
}
+
+ static getErrorHandler = (integration: Integration):
ErrorHandlerDefinition | undefined => {
+ const errorHandler = integration.spec.flows?.filter((e: any) =>
e.dslName === 'ErrorHandlerDefinition').at(0);
+ return errorHandler;
+ }
}
\ No newline at end of file
diff --git a/karavan-space/src/eip/EipCard.tsx
b/karavan-space/src/eip/EipCard.tsx
index 0fab47e..bfb2f8d 100644
--- a/karavan-space/src/eip/EipCard.tsx
+++ b/karavan-space/src/eip/EipCard.tsx
@@ -51,7 +51,7 @@ export class EipCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconForDslName(component.className)}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardTitle>{component.title}</CardTitle>
<CardBody>{component.description}</CardBody>
<CardFooter>
<Badge isRead
className="labels">{component.labels}</Badge>
diff --git a/karavan-space/src/kamelets/KameletCard.tsx
b/karavan-space/src/kamelets/KameletCard.tsx
index 2bae9fc..5d4faaf 100644
--- a/karavan-space/src/kamelets/KameletCard.tsx
+++ b/karavan-space/src/kamelets/KameletCard.tsx
@@ -21,6 +21,7 @@ import {
import '../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
import {CamelUi} from "../designer/utils/CamelUi";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
interface Props {
kamelet: KameletModel,
@@ -44,19 +45,21 @@ export class KameletCard extends React.Component<Props,
State> {
render() {
const kamelet = this.state.kamelet;
+ const isCustom =
KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
return (
<Card isHoverable isCompact key={kamelet.metadata.name}
className="kamelet-card"
- onClick={event => this.click(event)}
+ onClick={event => this.click(event)}
>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
+ {isCustom && <Badge className="custom">custom</Badge>}
</CardHeader>
-
<CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardTitle>{kamelet.spec.definition.title}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
{/*<div style={{justifyContent: "space-between"}}>*/}
- <Badge isRead
className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- <Badge isRead
className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ <Badge isRead
className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead
className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
{/*</div>*/}
</CardFooter>
</Card>
diff --git a/karavan-space/src/kamelets/KameletsPage.tsx
b/karavan-space/src/kamelets/KameletsPage.tsx
index 0635917..1c500e4 100644
--- a/karavan-space/src/kamelets/KameletsPage.tsx
+++ b/karavan-space/src/kamelets/KameletsPage.tsx
@@ -21,7 +21,7 @@ import {
Gallery,
ToolbarItem,
TextInput,
- PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem,
Badge, Button
+ PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem,
Badge, Button, Switch
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {KameletCard} from "./KameletCard";
@@ -41,7 +41,8 @@ interface State {
repository: string,
path: string,
kamelets: KameletModel[],
- filter: string
+ filter: string,
+ customOnly: boolean
}
export class KameletsPage extends React.Component<Props, State> {
@@ -51,7 +52,8 @@ export class KameletsPage extends React.Component<Props,
State> {
repository: '',
path: '',
kamelets: [],
- filter: ''
+ filter: '',
+ customOnly: false
};
componentDidMount() {
@@ -63,26 +65,26 @@ export class KameletsPage extends React.Component<Props,
State> {
}
search(filter: string) {
- this.setState({
- filter: filter,
- isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet =>
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
- })
+ this.setState({ filter: filter, isModalOpen: false})
}
render() {
+ const {dark, onRefresh} = this.props;
+ const {kamelets, kamelet, isModalOpen, customOnly, filter} =
this.state;
+ let kameletList = kamelets.filter(kamelet =>
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
- <PageSection variant={this.props.dark ? PageSectionVariants.darker
: PageSectionVariants.light}
+ <PageSection variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{default: 'noPadding'}}
className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name +
this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen}
kamelet={this.state.kamelet}/>
+ <KameletModal key={kamelet?.metadata.name +
isModalOpen.toString()}
+ isOpen={isModalOpen} kamelet={kamelet}/>
<PageSection className="tools-section"
- variant={this.props.dark ?
PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default:
'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent className="header">
<Text component="h2">Kamelet Catalog</Text>
- <Badge isRead
className="labels">{this.state.kamelets.length}</Badge>
+ <Badge isRead
className="labels">{kamelets.length}</Badge>
</TextContent>
</FlexItem>
<FlexItem>
@@ -91,14 +93,21 @@ export class KameletsPage extends React.Component<Props,
State> {
<ToolbarItem>
<Button icon={<RefreshIcon/>}
variant="link"
onClick={e => {
-
this.props.onRefresh?.call(this).then(value => {
+
onRefresh?.call(this).then(value => {
this.setState({kamelets: KameletApi.getKamelets()});
})
}}/>
</ToolbarItem>
+ <ToolbarItem>
+ <Switch
+ label="Custom only"
+ isChecked={customOnly}
+ onChange={checked =>
this.setState({customOnly: checked})}
+ />
+ </ToolbarItem>
<ToolbarItem>
<TextInput className="text-field"
type="search" id="search" name="search"
- value={this.state.filter}
+ value={filter}
onChange={value =>
this.search(value)}
autoComplete="off"
placeholder="Search by
name"/>
@@ -109,9 +118,9 @@ export class KameletsPage extends React.Component<Props,
State> {
</Flex>
</PageSection>
<PageSection isFilled className="kamelets-page"
- variant={this.props.dark ?
PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
+ {kameletList.map(k => (
<KameletCard key={k.metadata.name} kamelet={k}
onClickCard={this.select}/>
))}
</Gallery>
diff --git a/karavan-space/src/space/SpacePage.tsx
b/karavan-space/src/space/SpacePage.tsx
index 9365489..4c0346f 100644
--- a/karavan-space/src/space/SpacePage.tsx
+++ b/karavan-space/src/space/SpacePage.tsx
@@ -19,7 +19,7 @@ import {
Toolbar,
ToolbarContent,
ToolbarItem,
- PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem,
Badge, Button, Tooltip, ToggleGroup, ToggleGroupItem
+ PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem,
Button, Tooltip, ToggleGroup, ToggleGroupItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
import DownloadIcon from
"@patternfly/react-icons/dist/esm/icons/download-icon";
@@ -96,7 +96,14 @@ export class SpacePage extends React.Component<Props, State>
{
ref={this.state.karavanDesignerRef}
filename={name}
yaml={yaml}
- onSave={(filename, yaml, propertyOnly) => this.save(filename,
yaml, propertyOnly)}/>
+ onSave={(filename, yaml, propertyOnly) => this.save(filename,
yaml, propertyOnly)}
+ onGetCustomCode={name => {
+ return new Promise<string | undefined>(resolve =>
resolve(undefined))
+ }}
+ onSaveCustomCode={(name1, code) => {
+ console.log(name1, code)
+ }}
+ />
)
}