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 ee454172 Implement #622
ee454172 is described below

commit ee454172d18c94a85e96638c4a0cac8dccf19921
Author: Marat Gubaidullin <marat.gubaidul...@gmail.com>
AuthorDate: Fri Jan 20 16:40:41 2023 -0500

    Implement #622
---
 karavan-core/src/core/api/CamelUtil.ts             | 11 ++++-
 .../src/designer/rest/RestDesigner.tsx             |  1 -
 .../src/designer/route/DslConnections.tsx          |  8 +++-
 karavan-designer/src/designer/route/DslElement.tsx | 17 ++++++-
 .../src/designer/route/DslProperties.tsx           | 19 --------
 .../src/designer/route/RouteDesigner.tsx           | 56 +++++++++++++++++-----
 karavan-designer/src/designer/utils/EventBus.ts    |  6 +--
 7 files changed, 80 insertions(+), 38 deletions(-)

diff --git a/karavan-core/src/core/api/CamelUtil.ts 
b/karavan-core/src/core/api/CamelUtil.ts
index dca89363..170d267a 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -26,6 +26,7 @@ import {ComponentProperty} from "../model/ComponentModels";
 import {ComponentApi} from "./ComponentApi";
 import {CamelMetadataApi} from "../model/CamelMetadata";
 import {CamelDefinitionApiExt} from "./CamelDefinitionApiExt";
+import {v4 as uuidv4} from 'uuid';
 
 export class CamelUtil {
 
@@ -50,8 +51,14 @@ export class CamelUtil {
         return int;
     }
 
-    static cloneStep = (step: CamelElement): CamelElement => {
-        const clone = JSON.parse(JSON.stringify(step));
+    static cloneStep = (step: CamelElement, generateUuids: boolean = false): 
CamelElement => {
+        const clone = JSON.parse(JSON.stringify(step, (key, value) => {
+            if (generateUuids && key === 'uuid'){
+                return uuidv4();
+            } else {
+                return value;
+            }
+        }));
         return CamelDefinitionApi.createStep(step.dslName, clone, true);
     }
 
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx 
b/karavan-designer/src/designer/rest/RestDesigner.tsx
index f91c5129..d13d07e6 100644
--- a/karavan-designer/src/designer/rest/RestDesigner.tsx
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -240,7 +240,6 @@ export class RestDesigner extends React.Component<Props, 
State> {
                     step={this.state.selectedStep}
                     onIntegrationUpdate={this.onIntegrationUpdate}
                     onPropertyUpdate={this.onPropertyUpdate}
-                    clipboardStep={undefined}
                     isRouteDesigner={false}
                     onClone={this.cloneRest}
                     dark={this.props.dark}/>
diff --git a/karavan-designer/src/designer/route/DslConnections.tsx 
b/karavan-designer/src/designer/route/DslConnections.tsx
index 0806761e..6dc1ced3 100644
--- a/karavan-designer/src/designer/route/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -57,12 +57,18 @@ export class DslConnections extends React.Component<Props, 
State> {
     }
 
     setPosition(evt: DslPosition) {
-        if (evt.command === "add") this.setState(prevState => ({steps: 
prevState.steps.set(evt.step.uuid, evt)}));
+        if (evt.command === "add") {
+            this.setState(prevState => ({steps: 
prevState.steps.set(evt.step.uuid, evt)}));
+        }
         else if (evt.command === "delete") this.setState(prevState => {
             // prevState.steps.clear();
             prevState.steps.delete(evt.step.uuid);
             return {steps: prevState.steps};
         });
+        else if (evt.command === "clean") this.setState(prevState => {
+            prevState.steps.clear();
+            return {steps: prevState.steps};
+        });
     }
 
     getIncomings() {
diff --git a/karavan-designer/src/designer/route/DslElement.tsx 
b/karavan-designer/src/designer/route/DslElement.tsx
index 868f3e2c..07222d84 100644
--- a/karavan-designer/src/designer/route/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -65,9 +65,22 @@ export class DslElement extends React.Component<Props, 
State> {
         tabIndex: 0,
         selectedUuid: this.props.selectedUuid,
         isDragging: false,
-        isDraggedOver: false
+        isDraggedOver: false,
     };
 
+    handleKeyDown = (event: React.KeyboardEvent) =>{
+        // event.preventDefault();
+        // console.log(event);
+        // let charCode = String.fromCharCode(event.which).toLowerCase();
+        // if((event.ctrlKey || event.metaKey) && charCode === 's') {
+        //     alert("CTRL+S Pressed");
+        // }else if((event.ctrlKey || event.metaKey) && charCode === 'c') {
+        //     alert("CTRL+C Pressed");
+        // }else if((event.ctrlKey || event.metaKey) && charCode === 'v') {
+        //     alert("CTRL+V Pressed");
+        // }
+    }
+
     componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
         if (prevState.selectedUuid !== this.props.selectedUuid) {
             this.setState({selectedUuid: this.props.selectedUuid});
@@ -484,6 +497,8 @@ export class DslElement extends React.Component<Props, 
State> {
                  }}
                  onDrop={event => this.dragElement(event, element)}
                  draggable={!this.isNotDraggable()}
+                 // tabIndex={0}
+                 onKeyDown={this.handleKeyDown}
             >
                 {this.getElementHeader()}
                 {this.getChildElements()}
diff --git a/karavan-designer/src/designer/route/DslProperties.tsx 
b/karavan-designer/src/designer/route/DslProperties.tsx
index 0359bb36..f0000bc1 100644
--- a/karavan-designer/src/designer/route/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -36,8 +36,6 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelUi, RouteToCreate} from "../utils/CamelUi";
 import {CamelMetadataApi, PropertyMeta} from 
"karavan-core/lib/model/CamelMetadata";
 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 {
@@ -45,8 +43,6 @@ interface Props {
     step?: CamelElement,
     onIntegrationUpdate?: any,
     onPropertyUpdate?: (element: CamelElement, newRoute?: RouteToCreate) => 
void
-    clipboardStep?: CamelElement
-    onSaveClipboardStep?: (element?: CamelElement) => void
     onClone?: (element: CamelElement) => void
     isRouteDesigner: boolean
     dark: boolean
@@ -76,15 +72,6 @@ export class DslProperties extends React.Component<Props, 
State> {
         }
     }
 
-    pasteClipboardStep = () => {
-        if (this.props.clipboardStep && this.state.step) {
-            const clone = CamelUtil.cloneStep(this.props.clipboardStep);
-            clone.uuid = this.state.step.uuid;
-            this.setStep(clone)
-            this.props.onPropertyUpdate?.call(this, clone);
-        }
-    }
-
     dataFormatChanged = (value: DataFormatDefinition) => {
         value.uuid = this.state.step?.uuid ? this.state.step?.uuid : 
value.uuid;
         this.setStep(value);
@@ -144,12 +131,6 @@ export class DslProperties extends React.Component<Props, 
State> {
             <div className="headers">
                 <div className="top">
                     <Title headingLevel="h1" size="md">{title}</Title>
-                    <Tooltip content="Copy step" position="bottom">
-                        <Button variant="link" onClick={() => 
this.props.onSaveClipboardStep?.call(this, this.state.step)} 
icon={<CopyIcon/>}/>
-                    </Tooltip>
-                    <Tooltip content="Paste step" position="bottom">
-                        <Button variant="link" onClick={() => 
this.pasteClipboardStep()} icon={<PasteIcon/>}/>
-                    </Tooltip>
                 </div>
                 <Text 
component={TextVariants.p}>{descriptionLines.at(0)}</Text>
                 {descriptionLines.length > 1 && <ExpandableSection 
toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'}
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx 
b/karavan-designer/src/designer/route/RouteDesigner.tsx
index 949295ea..10a44ca6 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -92,6 +92,7 @@ export class RouteDesigner extends React.Component<Props, 
State> {
 
     componentDidMount() {
         window.addEventListener('resize', this.handleResize);
+        window.addEventListener('keydown', this.handleKeyDown);
         const element = 
findDOMNode(this.state.ref.current)?.parentElement?.parentElement;
         const checkResize = (mutations: any) => {
             const el = mutations[0].target;
@@ -107,12 +108,42 @@ export class RouteDesigner extends React.Component<Props, 
State> {
 
     componentWillUnmount() {
         window.removeEventListener('resize', this.handleResize);
+        window.removeEventListener('keydown', this.handleKeyDown);
     }
 
     handleResize = (event: any) => {
         this.setState({key: Math.random().toString()});
     }
 
+    handleKeyDown = (event: KeyboardEvent) => {
+        const {integration, selectedUuid, clipboardStep} = this.state;
+        if (window.document.hasFocus() && window.document.activeElement && 
selectedUuid && selectedUuid !== '') {
+            if (['BODY', 
'MAIN'].includes(window.document.activeElement.tagName)) {
+                let charCode = String.fromCharCode(event.which).toLowerCase();
+                if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
+                    const selectedElement = 
CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
+                    this.saveToClipboard(selectedElement);
+                } else if ((event.ctrlKey || event.metaKey) && charCode === 
'v') {
+                    if (clipboardStep?.dslName === 'FromDefinition') {
+                        const clone = CamelUtil.cloneStep(clipboardStep, true);
+                        const route = 
CamelDefinitionApi.createRouteDefinition({from: clone});
+                        this.addStep(route, '', 0)
+                    } else {
+                        const meta = 
CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuid);
+                        if (clipboardStep && meta.parentUuid) {
+                            const clone = CamelUtil.cloneStep(clipboardStep, 
true);
+                            this.addStep(clone, meta.parentUuid, 
meta.position);
+                        }
+                    }
+                }
+            }
+        } else {
+            if (event.repeat) {
+                window.dispatchEvent(event);
+            }
+        }
+    }
+
     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);
@@ -222,8 +253,8 @@ export class RouteDesigner extends React.Component<Props, 
State> {
     onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | 
undefined) => {
         switch (dsl.dsl) {
             case 'FromDefinition' :
-                const from = CamelDefinitionApi.createRouteDefinition({from: 
new FromDefinition({uri: dsl.uri})});
-                this.addStep(from, parentId, position)
+                const route = CamelDefinitionApi.createRouteDefinition({from: 
new FromDefinition({uri: dsl.uri})});
+                this.addStep(route, parentId, position)
                 break;
             case 'ToDefinition' :
                 const to = CamelDefinitionApi.createStep(dsl.dsl, {uri: 
dsl.uri});
@@ -260,6 +291,7 @@ export class RouteDesigner extends React.Component<Props, 
State> {
     addStep = (step: CamelElement, parentId: string, position?: number | 
undefined) => {
         const i = 
CamelDefinitionApiExt.addStepToIntegration(this.state.integration, step, 
parentId, position);
         const clone = CamelUtil.cloneIntegration(i);
+        EventBus.sendPosition("clean", step, undefined, new DOMRect(), new 
DOMRect(), 0);
         this.setState({
             integration: clone,
             key: Math.random().toString(),
@@ -338,9 +370,7 @@ export class RouteDesigner extends React.Component<Props, 
State> {
                                step={this.state.selectedStep}
                                onIntegrationUpdate={this.onIntegrationUpdate}
                                onPropertyUpdate={this.onPropertyUpdate}
-                               clipboardStep={this.state.clipboardStep}
                                isRouteDesigner={true}
-                               onSaveClipboardStep={this.saveToClipboard}
                                dark={this.props.dark}/>
             </DrawerPanelContent>
         )
@@ -356,7 +386,7 @@ export class RouteDesigner extends React.Component<Props, 
State> {
     integrationImageDownloadFilter = (node: HTMLElement) => {
         const exclusionClasses = ['add-flow'];
         return !exclusionClasses.some(classname => {
-            return node.classList === undefined ? false: 
node.classList.contains(classname);
+            return node.classList === undefined ? false : 
node.classList.contains(classname);
         });
     }
 
@@ -364,11 +394,15 @@ export class RouteDesigner extends React.Component<Props, 
State> {
         if (this.state.printerRef.current === null) {
             return
         }
-        toPng(this.state.printerRef.current, { style:{overflow:'hidden'}, 
cacheBust: true, filter: this.integrationImageDownloadFilter,
-                height:this.state.height,width:this.state.width,  
backgroundColor: this.props.dark?"black":"white" }).then(v => {
-                    toPng(this.state.printerRef.current, { 
style:{overflow:'hidden'}, cacheBust: true, filter: 
this.integrationImageDownloadFilter,
-                    height:this.state.height,width:this.state.width,  
backgroundColor: this.props.dark?"black":"white" 
}).then(this.downloadIntegrationImage);
-            })
+        toPng(this.state.printerRef.current, {
+            style: {overflow: 'hidden'}, cacheBust: true, filter: 
this.integrationImageDownloadFilter,
+            height: this.state.height, width: this.state.width, 
backgroundColor: this.props.dark ? "black" : "white"
+        }).then(v => {
+            toPng(this.state.printerRef.current, {
+                style: {overflow: 'hidden'}, cacheBust: true, filter: 
this.integrationImageDownloadFilter,
+                height: this.state.height, width: this.state.width, 
backgroundColor: this.props.dark ? "black" : "white"
+            }).then(this.downloadIntegrationImage);
+        })
     }
 
     getGraph() {
@@ -380,7 +414,7 @@ export class RouteDesigner extends React.Component<Props, 
State> {
                 <DslConnections height={height} width={width} top={top} 
left={left} integration={integration}/>
                 <div className="flows" data-click="FLOWS" onClick={event => 
this.unselectElement(event)}
                      ref={el => this.onResizePage(el)}>
-                    {routeConfigurations?.map((routeConfiguration , index: 
number) => (
+                    {routeConfigurations?.map((routeConfiguration, index: 
number) => (
                         <DslElement key={routeConfiguration.uuid + key}
                                     integration={integration}
                                     openSelector={this.openSelector}
diff --git a/karavan-designer/src/designer/utils/EventBus.ts 
b/karavan-designer/src/designer/utils/EventBus.ts
index 98e573d7..2df867f4 100644
--- a/karavan-designer/src/designer/utils/EventBus.ts
+++ b/karavan-designer/src/designer/utils/EventBus.ts
@@ -27,9 +27,9 @@ export class DslPosition {
     position: number = 0;
     rect: DOMRect = new DOMRect();
     headerRect: DOMRect = new DOMRect();
-    command: "add" | "delete" = "add";
+    command: "add" | "delete" | "clean" = "add";
 
-    constructor(command: "add" | "delete",
+    constructor(command: "add" | "delete" | "clean",
                 step: CamelElement,
                 parent:CamelElement | undefined,
                 rect: DOMRect,
@@ -49,7 +49,7 @@ export class DslPosition {
 }
 
 export const EventBus = {
-    sendPosition: (command: "add" | "delete",
+    sendPosition: (command: "add" | "delete" | "clean",
                    step: CamelElement,
                    parent: CamelElement | undefined,
                    rect: DOMRect,

Reply via email to