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 157c868 Clone for beans, REST and dependencies (#263)
157c868 is described below
commit 157c868f53cb0d4ca7e826dc4f302ab898481833
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Wed Mar 30 20:17:07 2022 -0400
Clone for beans, REST and dependencies (#263)
* Clone bean and dependency
* Rest clone
---
karavan-core/src/core/api/CamelDefinitionApiExt.ts | 54 ++++++++++++++++++----
karavan-designer/src/App.tsx | 2 +-
.../src/designer/beans/BeanProperties.tsx | 20 +++++++-
.../src/designer/beans/BeansDesigner.tsx | 3 +-
.../designer/dependencies/DependenciesDesigner.tsx | 4 +-
.../designer/dependencies/DependencyProperties.tsx | 24 +++++++++-
.../src/designer/rest/RestDesigner.tsx | 25 +++++++++-
.../src/designer/route/DslProperties.tsx | 33 ++++++++++++-
.../src/designer/route/RouteDesigner.tsx | 17 +++----
9 files changed, 158 insertions(+), 24 deletions(-)
diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 1c3e309..4936d27 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -201,7 +201,7 @@ export class CamelDefinitionApiExt {
flows.push(...integration.spec.flows?.filter(flow => flow.dslName
!== 'Beans') || []);
integration.spec.flows?.filter(flow => flow.dslName ===
'Beans').forEach(flow => {
const beans: NamedBeanDefinition[] = [];
- if ((flow as Beans).beans.filter(b => b.uuid ===
bean.uuid).length === 0){
+ if ((flow as Beans).beans.filter(b => b.uuid ===
bean.uuid).length === 0) {
beans.push(...(flow as Beans).beans.filter(b => b.uuid !==
bean.uuid));
beans.push(bean);
} else {
@@ -261,13 +261,25 @@ export class CamelDefinitionApiExt {
if (rest.uuid !== restUuid) {
flows.push(rest);
} else {
- switch (method.dslName){
- case 'GetDefinition': rest.get =
this.addRestMethodToRestMethods(rest.get, method); break;
- case 'PostDefinition': rest.post =
this.addRestMethodToRestMethods(rest.post, method); break;
- case 'PutDefinition': rest.put =
this.addRestMethodToRestMethods(rest.put, method); break;
- case 'PatchDefinition': rest.patch =
this.addRestMethodToRestMethods(rest.patch, method); break;
- case 'DeleteDefinition': rest.delete =
this.addRestMethodToRestMethods(rest.delete, method); break;
- case 'HeadDefinition': rest.head =
this.addRestMethodToRestMethods(rest.head, method); break;
+ switch (method.dslName) {
+ case 'GetDefinition':
+ rest.get = this.addRestMethodToRestMethods(rest.get,
method);
+ break;
+ case 'PostDefinition':
+ rest.post = this.addRestMethodToRestMethods(rest.post,
method);
+ break;
+ case 'PutDefinition':
+ rest.put = this.addRestMethodToRestMethods(rest.put,
method);
+ break;
+ case 'PatchDefinition':
+ rest.patch =
this.addRestMethodToRestMethods(rest.patch, method);
+ break;
+ case 'DeleteDefinition':
+ rest.delete =
this.addRestMethodToRestMethods(rest.delete, method);
+ break;
+ case 'HeadDefinition':
+ rest.head = this.addRestMethodToRestMethods(rest.head,
method);
+ break;
}
flows.push(rest);
}
@@ -286,6 +298,32 @@ export class CamelDefinitionApiExt {
return elements;
}
+ static findRestMethodParent = (integration: Integration, method:
CamelElement): string | undefined => {
+ const rests: RestDefinition[] = integration.spec.flows?.filter(flow =>
flow.dslName === 'RestDefinition') || [];
+ for (let rest of rests) {
+ switch (method.dslName) {
+ case 'GetDefinition':
+ if (rest.get?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ case 'PostDefinition':
+ if (rest.post?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ case 'PutDefinition':
+ if (rest.put?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ case 'PatchDefinition':
+ if (rest.patch?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ case 'DeleteDefinition':
+ if (rest.delete?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ case 'HeadDefinition':
+ if (rest.head?.find(m => m.uuid === method.uuid)) return
rest.uuid;
+ else break;
+ }
+ }
+ }
+
static deleteRestConfigurationFromIntegration = (integration:
Integration): Integration => {
const flows: any[] = [];
integration.spec.flows?.filter(flow => flow.dslName !==
'RestConfigurationDefinition').forEach(x => flows.push(x));
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 403b964..35f5a3a 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -98,7 +98,7 @@ class App extends React.Component<Props, State> {
save(filename: string, yaml: string, propertyOnly: boolean) {
// console.log(filename);
- // console.log(yaml);
+ console.log(yaml);
// console.log(propertyOnly);
}
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx
b/karavan-designer/src/designer/beans/BeanProperties.tsx
index a25320f..d0a9138 100644
--- a/karavan-designer/src/designer/beans/BeanProperties.tsx
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -18,7 +18,7 @@ import React from 'react';
import {
Form,
FormGroup,
- TextInput, Button,
+ TextInput, Button, Title, Tooltip, Text, TextVariants,
} from '@patternfly/react-core';
import '../karavan.css';
import "@patternfly/patternfly/patternfly.css";
@@ -31,12 +31,14 @@ import {v4 as uuidv4} from "uuid";
import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
import {IntegrationHeader} from "../utils/KaravanComponents";
+import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'
interface Props {
integration: Integration
bean?: NamedBeanDefinition
dark: boolean
onChange: (bean: NamedBeanDefinition) => void
+ onClone: (bean: NamedBeanDefinition) => void
}
interface State {
@@ -103,10 +105,26 @@ export class BeanProperties extends
React.Component<Props, State> {
})
}
+ cloneBean = () => {
+ if (this.state.bean) {
+ const bean = CamelUtil.cloneBean(this.state.bean);
+ bean.uuid = uuidv4();
+ this.props.onClone?.call(this, bean);
+ }
+ }
+
getBeanForm() {
const bean = this.state.bean;
return (
<>
+ <div className="headers">
+ <div className="top">
+ <Title headingLevel="h1" size="md">Bean</Title>
+ <Tooltip content="Clone bean" position="bottom">
+ <Button variant="link" onClick={() =>
this.cloneBean()} icon={<CloneIcon/>}/>
+ </Tooltip>
+ </div>
+ </div>
<FormGroup label="Name" fieldId="name" isRequired>
<TextInput className="text-field" isRequired type="text"
id="name" name="name" value={bean?.name}
onChange={e => this.beanChanged("name", e)}/>
diff --git a/karavan-designer/src/designer/beans/BeansDesigner.tsx
b/karavan-designer/src/designer/beans/BeansDesigner.tsx
index 30991b7..b61e8f6 100644
--- a/karavan-designer/src/designer/beans/BeansDesigner.tsx
+++ b/karavan-designer/src/designer/beans/BeansDesigner.tsx
@@ -123,7 +123,8 @@ export class BeansDesigner extends React.Component<Props,
State> {
<BeanProperties integration={this.props.integration}
bean={this.state.selectedBean}
dark={this.props.dark}
- onChange={this.changeBean}/>
+ onChange={this.changeBean}
+ onClone={this.changeBean}/>
</DrawerPanelContent>
)
}
diff --git
a/karavan-designer/src/designer/dependencies/DependenciesDesigner.tsx
b/karavan-designer/src/designer/dependencies/DependenciesDesigner.tsx
index ef1e16a..fc40f30 100644
--- a/karavan-designer/src/designer/dependencies/DependenciesDesigner.tsx
+++ b/karavan-designer/src/designer/dependencies/DependenciesDesigner.tsx
@@ -26,6 +26,7 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {Integration, Dependency} from
"karavan-core/lib/model/IntegrationDefinition";
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import {DependencyCard} from "./DependencyCard";
+import {NamedBeanDefinition} from
"../../../../karavan-core/lib/model/CamelDefinition";
interface Props {
onSave?: (integration: Integration, propertyOnly: boolean) => void
@@ -126,7 +127,8 @@ export class DependenciesDesigner extends
React.Component<Props, State> {
<DependencyProperties integration={this.props.integration}
dependency={this.state.selectedDep}
dark={this.props.dark}
- onChange={this.changeDep}/>
+ onChange={this.changeDep}
+ onClone={this.changeDep}/>
</DrawerPanelContent>
)
}
diff --git
a/karavan-designer/src/designer/dependencies/DependencyProperties.tsx
b/karavan-designer/src/designer/dependencies/DependencyProperties.tsx
index 5a31ea4..c629a55 100644
--- a/karavan-designer/src/designer/dependencies/DependencyProperties.tsx
+++ b/karavan-designer/src/designer/dependencies/DependencyProperties.tsx
@@ -16,21 +16,26 @@
*/
import React from 'react';
import {
+ Button,
Form,
FormGroup,
- TextInput,
+ TextInput, Title, Tooltip,
} from '@patternfly/react-core';
import '../karavan.css';
import "@patternfly/patternfly/patternfly.css";
import {Integration, Dependency} from
"karavan-core/lib/model/IntegrationDefinition";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {IntegrationHeader} from "../utils/KaravanComponents";
+import {NamedBeanDefinition} from
"../../../../karavan-core/lib/model/CamelDefinition";
+import {v4 as uuidv4} from "uuid";
+import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
interface Props {
integration: Integration
dependency?: Dependency
dark: boolean
onChange: (dependency: Dependency) => void
+ onClone: (dependency: Dependency) => void
}
interface State {
@@ -58,10 +63,27 @@ export class DependencyProperties extends
React.Component<Props, State> {
}
}
+
+ cloneDependency = () => {
+ if (this.state.dependency) {
+ const dependency =
CamelUtil.cloneDependency(this.state.dependency);
+ dependency.uuid = uuidv4();
+ this.props.onClone?.call(this, dependency);
+ }
+ }
+
getDependencyForm() {
const dependency = this.state.dependency;
return (
<>
+ <div className="headers">
+ <div className="top">
+ <Title headingLevel="h1" size="md">Dependency</Title>
+ <Tooltip content="Clone dependency" position="bottom">
+ <Button variant="link" onClick={() =>
this.cloneDependency()} icon={<CloneIcon/>}/>
+ </Tooltip>
+ </div>
+ </div>
<FormGroup label="Group" fieldId="group" isRequired>
<TextInput className="text-field" isRequired type="text"
id="group" name="group" value={dependency?.group}
onChange={e => this.dependencyChanged("group",
e)}/>
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx
b/karavan-designer/src/designer/rest/RestDesigner.tsx
index d7630a6..083717c 100644
--- a/karavan-designer/src/designer/rest/RestDesigner.tsx
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -32,6 +32,7 @@ import {RestMethodSelector} from "./RestMethodSelector";
import {DslMetaModel} from "../utils/DslMetaModel";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {RestConfigurationCard} from "./RestConfigurationCard";
+import {v4 as uuidv4} from "uuid";
interface Props {
onSave?: (integration: Integration, propertyOnly: boolean) => void
@@ -167,6 +168,27 @@ export class RestDesigner extends React.Component<Props,
State> {
}
}
+ cloneRest = (rest: CamelElement) => {
+ if (rest.dslName === 'RestDefinition'){
+ const cloneRest = CamelUtil.cloneStep(rest);
+ cloneRest.uuid = uuidv4();
+ const cloneIntegration =
CamelUtil.cloneIntegration(this.state.integration);
+ const i =
CamelDefinitionApiExt.addRestToIntegration(cloneIntegration, cloneRest);
+ this.setState({integration: i, propertyOnly: false, key:
Math.random().toString(), selectedStep: cloneRest});
+ } else if (rest.dslName === 'RestConfigurationDefinition') {
+ // could be only one RestConfigurationDefinition
+ } else if (this.state.selectedStep) {
+ const parentId =
CamelDefinitionApiExt.findRestMethodParent(this.state.integration, rest);
+ if (parentId){
+ const cloneRest = CamelUtil.cloneStep(rest);
+ cloneRest.uuid = uuidv4();
+ const cloneIntegration =
CamelUtil.cloneIntegration(this.state.integration);
+ const i =
CamelDefinitionApiExt.addRestMethodToIntegration(cloneIntegration, cloneRest,
parentId);
+ this.setState({integration: i, key: Math.random().toString(),
selectedStep: cloneRest, showSelector: false});
+ }
+ }
+ }
+
selectMethod = (element: CamelElement) => {
this.setState({selectedStep: element, showSelector: true})
}
@@ -219,7 +241,8 @@ export class RestDesigner extends React.Component<Props,
State> {
onIntegrationUpdate={this.onIntegrationUpdate}
onPropertyUpdate={this.onPropertyUpdate}
clipboardStep={undefined}
- onSaveClipboardStep={element => {}}
+ isRouteDesigner={false}
+ onClone={this.cloneRest}
/>
</DrawerPanelContent>
)
diff --git a/karavan-designer/src/designer/route/DslProperties.tsx
b/karavan-designer/src/designer/route/DslProperties.tsx
index 23ad9e9..d7540b5 100644
--- a/karavan-designer/src/designer/route/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -38,6 +38,7 @@ import {CamelMetadataApi, PropertyMeta} from
"karavan-core/lib/model/CamelMetada
import {IntegrationHeader} from "../utils/KaravanComponents";
import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon'
import PasteIcon from '@patternfly/react-icons/dist/esm/icons/paste-icon'
+import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
interface Props {
integration: Integration,
@@ -45,7 +46,9 @@ interface Props {
onIntegrationUpdate?: any,
onPropertyUpdate?: (element: CamelElement, updatedUuid: string, newRoute?:
RouteToCreate) => void
clipboardStep?: CamelElement
- onSaveClipboardStep: (element?: CamelElement) => void
+ onSaveClipboardStep?: (element?: CamelElement) => void
+ onClone?: (element: CamelElement) => void
+ isRouteDesigner: boolean
}
interface State {
@@ -111,6 +114,12 @@ export class DslProperties extends React.Component<Props,
State> {
}
}
+ cloneElement = () => {
+ if (this.state.step) {
+ this.props.onClone?.call(this, this.state.step);
+ }
+ }
+
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
if (prevProps.step !== this.props.step) {
this.setStep(this.props.step);
@@ -124,7 +133,7 @@ export class DslProperties extends React.Component<Props,
State> {
});
}
- getComponentHeader = (): JSX.Element => {
+ getRouteHeader= (): JSX.Element => {
const title = this.state.step && CamelUi.getTitle(this.state.step)
const kamelet = this.state.step && CamelUi.getKamelet(this.state.step)
const description = this.state.step && kamelet
@@ -142,11 +151,31 @@ export class DslProperties extends React.Component<Props,
State> {
</Tooltip>
</div>
<Text component={TextVariants.p}>{description}</Text>
+ </div>
+ )
+ }
+ getClonableElementHeader = (): JSX.Element => {
+ const title = this.state.step && CamelUi.getTitle(this.state.step)
+ const description = this.state.step?.dslName ?
CamelMetadataApi.getCamelModelMetadataByClassName(this.state.step?.dslName)?.description
: title;
+ return (
+ <div className="headers">
+ <div className="top">
+ <Title headingLevel="h1" size="md">{title}</Title>
+ <Tooltip content="Clone element" position="bottom">
+ <Button variant="link" onClick={() =>
this.cloneElement()} icon={<CloneIcon/>}/>
+ </Tooltip>
+ </div>
+ <Text component={TextVariants.p}>{description}</Text>
</div>
)
}
+ getComponentHeader = (): JSX.Element => {
+ if (this.props.isRouteDesigner) return this.getRouteHeader()
+ else return this.getClonableElementHeader();
+ }
+
getProperties = (): PropertyMeta[] => {
const dslName = this.state.step?.dslName;
return CamelDefinitionApiExt.getElementProperties(dslName)
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx
b/karavan-designer/src/designer/route/RouteDesigner.tsx
index 18e4f90..d493ba1 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -313,14 +313,15 @@ export class RouteDesigner extends React.Component<Props,
State> {
getPropertiesPanel() {
return (
<DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'}
maxSize={'800px'} minSize={'300px'}>
- <DslProperties ref={this.state.ref}
- integration={this.state.integration}
- step={this.state.selectedStep}
- onIntegrationUpdate={this.onIntegrationUpdate}
- onPropertyUpdate={this.onPropertyUpdate}
- clipboardStep={this.state.clipboardStep}
- onSaveClipboardStep={this.saveToClipboard}
- />
+ <DslProperties ref={this.state.ref}
+ integration={this.state.integration}
+ step={this.state.selectedStep}
+ onIntegrationUpdate={this.onIntegrationUpdate}
+ onPropertyUpdate={this.onPropertyUpdate}
+ clipboardStep={this.state.clipboardStep}
+ isRouteDesigner={true}
+ onSaveClipboardStep={this.saveToClipboard}
+ />
</DrawerPanelContent>
)
}