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 502d0747 Fix #1302
502d0747 is described below
commit 502d07470aabff1565b4607eb8127e7ad3f71520
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Thu Feb 13 19:00:20 2025 -0500
Fix #1302
---
.../src/designer/route/element/DslElement.css | 14 +++++++++++
.../designer/route/element/DslElementHeader.tsx | 28 ++++++++++++++++++----
.../src/designer/route/useRouteDesignerHook.tsx | 10 +++++++-
.../main/webui/src/designer/utils/ElementIcon.css | 7 ++++++
.../main/webui/src/designer/utils/ElementIcons.tsx | 21 ++++++++++++++++
karavan-designer/public/example/demo.camel.yaml | 9 ++++---
karavan-designer/src/App.tsx | 4 ++--
.../src/designer/route/element/DslElement.css | 14 +++++++++++
.../designer/route/element/DslElementHeader.tsx | 28 ++++++++++++++++++----
.../src/designer/route/useRouteDesignerHook.tsx | 10 +++++++-
.../src/designer/utils/ElementIcon.css | 7 ++++++
.../src/designer/utils/ElementIcons.tsx | 21 ++++++++++++++++
.../src/designer/route/element/DslElement.css | 14 +++++++++++
.../designer/route/element/DslElementHeader.tsx | 28 ++++++++++++++++++----
.../src/designer/route/useRouteDesignerHook.tsx | 10 +++++++-
karavan-space/src/designer/utils/ElementIcon.css | 7 ++++++
karavan-space/src/designer/utils/ElementIcons.tsx | 21 ++++++++++++++++
17 files changed, 233 insertions(+), 20 deletions(-)
diff --git
a/karavan-app/src/main/webui/src/designer/route/element/DslElement.css
b/karavan-app/src/main/webui/src/designer/route/element/DslElement.css
index 791acdb3..5ab8ecfd 100644
--- a/karavan-app/src/main/webui/src/designer/route/element/DslElement.css
+++ b/karavan-app/src/main/webui/src/designer/route/element/DslElement.css
@@ -235,6 +235,20 @@
z-index: 100;
}
+.karavan .step-element .copy-element-button {
+ position: absolute;
+ bottom: 9px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0 0 0 -30px;
+ background: transparent;
+ color: var(--pf-v5-global--primary-color--100);
+ visibility: hidden;
+ z-index: 100;
+}
+
+.karavan .step-element .header:hover .copy-element-button,
.karavan .step-element .header:hover .insert-element-button {
visibility: visible;
}
diff --git
a/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
b/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
index db181cff..90eb5985 100644
--- a/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
@@ -26,7 +26,7 @@ import {CamelDisplayUtil} from
"karavan-core/lib/api/CamelDisplayUtil";
import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "../useRouteDesignerHook";
-import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from
"../../utils/ElementIcons";
+import {AddElementIcon, DeleteElementIcon, InsertElementIcon, CopyElementIcon}
from "../../utils/ElementIcons";
import { RouteConfigurationDefinition} from
"karavan-core/lib/model/CamelDefinition";
import {AutoStartupIcon, ErrorHandlerIcon} from "../../icons/OtherIcons";
@@ -50,7 +50,8 @@ export function DslElementHeader(props: Props) {
openSelector,
isKamelet,
isSourceKamelet,
- isActionKamelet
+ isActionKamelet,
+ copyPasteStep
} = useRouteDesignerHook();
const [integration] = useIntegrationStore((s) => [s.integration], shallow)
@@ -217,6 +218,7 @@ export function DslElementHeader(props: Props) {
!['FromDefinition', 'RouteConfigurationDefinition',
'RouteTemplateDefinition', 'RouteDefinition', 'CatchDefinition',
'FinallyDefinition', 'WhenDefinition',
'OtherwiseDefinition'].includes(step.dslName)
&& !inRouteConfiguration;
const showDeleteButton = !('RouteDefinition' === step.dslName &&
'RouteTemplateDefinition' === parent?.dslName);
+ const showCopyButton = ['ToDefinition', 'ToDynamicDefinition',
'PollDefinition'].includes(step.dslName);
const headerClasses = getHeaderClasses();
const childrenInfo = getChildrenInfo(step) || [];
const hasWideChildrenElement = getHasWideChildrenElement(childrenInfo)
@@ -250,6 +252,7 @@ export function DslElementHeader(props: Props) {
{!isDebugging && showInsertButton && getInsertElementButton()}
{!isDebugging && showDeleteButton && getDeleteButton()}
{!isDebugging && showAddButton && getAddElementButton()}
+ {!isDebugging && showCopyButton && getCopyElementButton()}
</div>
)
}
@@ -313,8 +316,7 @@ export function DslElementHeader(props: Props) {
function getAddElementButton() {
return (
- <Tooltip position={"bottom"}
- content={<div>{"Add DSL element to " +
CamelDisplayUtil.getTitle(step)}</div>}>
+ <Tooltip position={"bottom"} content={<div>{"Add DSL element to "
+ CamelDisplayUtil.getTitle(step)}</div>}>
<button
type="button"
aria-label="Add"
@@ -325,6 +327,24 @@ export function DslElementHeader(props: Props) {
</Tooltip>
)
}
+ function getCopyElementButton() {
+ return (
+ <Tooltip position={"left"} content={"Copy element"}>
+ <button
+ type="button"
+ aria-label="Copy"
+ onClick={e => {
+ e.stopPropagation();
+ if (props.parent) {
+ copyPasteStep(step, props.parent?.uuid,
props.position)
+ }
+ }}
+ className={"copy-element-button"}>
+ <CopyElementIcon/>
+ </button>
+ </Tooltip>
+ )
+ }
function getInsertElementButton() {
return (
diff --git
a/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
b/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
index 62cda4bb..ac92bfe5 100644
--- a/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
@@ -182,6 +182,14 @@ export function useRouteDesignerHook() {
}
}
+ function copyPasteStep(step: CamelElement, parentUuid: string, position:
number): void {
+ if (step) {
+ const clone = CamelUtil.cloneStep(step, true);
+ (clone as any).id = (clone as any).stepName + "-" +
clone.uuid.substring(0,4);
+ addStep(clone, parentUuid, position + 1);
+ }
+ }
+
function copyToClipboard(): void {
const steps: CamelElement[] = []
selectedUuids.forEach(selectedUuid => {
@@ -397,6 +405,6 @@ export function useRouteDesignerHook() {
return {
deleteElement, selectElement, moveElement, onShowDeleteConfirmation,
onDslSelect, openSelector,
createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp,
unselectElement, isKamelet, isSourceKamelet,
- isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate
+ isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate, copyPasteStep
}
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/designer/utils/ElementIcon.css
b/karavan-app/src/main/webui/src/designer/utils/ElementIcon.css
index f89c962b..ee7d87dc 100644
--- a/karavan-app/src/main/webui/src/designer/utils/ElementIcon.css
+++ b/karavan-app/src/main/webui/src/designer/utils/ElementIcon.css
@@ -24,6 +24,13 @@
vertical-align: text-bottom;
}
+.copy-button-icon {
+ width: 20px;
+ height: 20px;
+ background: transparent;
+ vertical-align: text-bottom;
+}
+
.delete-button-icon {
fill: var(--pf-v5-global--danger-color--100);
width: 20px;
diff --git a/karavan-app/src/main/webui/src/designer/utils/ElementIcons.tsx
b/karavan-app/src/main/webui/src/designer/utils/ElementIcons.tsx
index 2d44bc5e..63c3ee43 100644
--- a/karavan-app/src/main/webui/src/designer/utils/ElementIcons.tsx
+++ b/karavan-app/src/main/webui/src/designer/utils/ElementIcons.tsx
@@ -18,6 +18,27 @@
import "./ElementIcon.css"
import React from 'react'
+export function CopyElementIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ className="copy-button-icon"
+ fill="none"
+ viewBox="0 0 27 27"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={2}
+ style={{
+ stroke: "var(--pf-v5-global--primary-color--100)",
+ }}
+ d="M9.41 2.34a9.996 9.996 0 0 1 9.661 2.589c3.905 3.905 3.905
10.237 0 14.142-3.905 3.905-10.237 3.905-14.142 0a9.996 9.996 0 0
1-2.59-9.66M15 9v6m0 0H9m6 0L5 5"
+ />
+ </svg>
+ )
+}
+
export function DeleteElementIcon() {
return (
<svg
diff --git a/karavan-designer/public/example/demo.camel.yaml
b/karavan-designer/public/example/demo.camel.yaml
index cf7b8ed0..d3d24002 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -6,6 +6,12 @@
parameters:
name: getUser
steps:
+ - to:
+ id: to-a36b
+ uri: amqp
+ parameters:
+ destinationName: hello
+ clientId: world
- to:
id: to-6d55
uri: bean
@@ -26,7 +32,4 @@
constant:
id: constant-9d21
expression: 404
-#- beans:
-# - name: userService
-# type: org.apache.camel.example.rest.UserService
- routeConfiguration: {}
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 3a5b5fdd..466b9924 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -72,8 +72,8 @@ export function App() {
fetch("metadata/spiBeans.json"),
fetch("snippets/org.apache.camel.AggregationStrategy"),
fetch("snippets/org.apache.camel.Processor"),
- // fetch("example/demo.camel.yaml"),
- fetch("example/avro-serialize-action.kamelet.yaml"),
+ fetch("example/demo.camel.yaml"),
+ // fetch("example/avro-serialize-action.kamelet.yaml"),
// fetch("components/blocked-components.properties"),
// fetch("kamelets/blocked-kamelets.properties")
// fetch("example/plc4x-ads-source.kamelet.yaml")
diff --git a/karavan-designer/src/designer/route/element/DslElement.css
b/karavan-designer/src/designer/route/element/DslElement.css
index 791acdb3..5ab8ecfd 100644
--- a/karavan-designer/src/designer/route/element/DslElement.css
+++ b/karavan-designer/src/designer/route/element/DslElement.css
@@ -235,6 +235,20 @@
z-index: 100;
}
+.karavan .step-element .copy-element-button {
+ position: absolute;
+ bottom: 9px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0 0 0 -30px;
+ background: transparent;
+ color: var(--pf-v5-global--primary-color--100);
+ visibility: hidden;
+ z-index: 100;
+}
+
+.karavan .step-element .header:hover .copy-element-button,
.karavan .step-element .header:hover .insert-element-button {
visibility: visible;
}
diff --git a/karavan-designer/src/designer/route/element/DslElementHeader.tsx
b/karavan-designer/src/designer/route/element/DslElementHeader.tsx
index db181cff..90eb5985 100644
--- a/karavan-designer/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-designer/src/designer/route/element/DslElementHeader.tsx
@@ -26,7 +26,7 @@ import {CamelDisplayUtil} from
"karavan-core/lib/api/CamelDisplayUtil";
import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "../useRouteDesignerHook";
-import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from
"../../utils/ElementIcons";
+import {AddElementIcon, DeleteElementIcon, InsertElementIcon, CopyElementIcon}
from "../../utils/ElementIcons";
import { RouteConfigurationDefinition} from
"karavan-core/lib/model/CamelDefinition";
import {AutoStartupIcon, ErrorHandlerIcon} from "../../icons/OtherIcons";
@@ -50,7 +50,8 @@ export function DslElementHeader(props: Props) {
openSelector,
isKamelet,
isSourceKamelet,
- isActionKamelet
+ isActionKamelet,
+ copyPasteStep
} = useRouteDesignerHook();
const [integration] = useIntegrationStore((s) => [s.integration], shallow)
@@ -217,6 +218,7 @@ export function DslElementHeader(props: Props) {
!['FromDefinition', 'RouteConfigurationDefinition',
'RouteTemplateDefinition', 'RouteDefinition', 'CatchDefinition',
'FinallyDefinition', 'WhenDefinition',
'OtherwiseDefinition'].includes(step.dslName)
&& !inRouteConfiguration;
const showDeleteButton = !('RouteDefinition' === step.dslName &&
'RouteTemplateDefinition' === parent?.dslName);
+ const showCopyButton = ['ToDefinition', 'ToDynamicDefinition',
'PollDefinition'].includes(step.dslName);
const headerClasses = getHeaderClasses();
const childrenInfo = getChildrenInfo(step) || [];
const hasWideChildrenElement = getHasWideChildrenElement(childrenInfo)
@@ -250,6 +252,7 @@ export function DslElementHeader(props: Props) {
{!isDebugging && showInsertButton && getInsertElementButton()}
{!isDebugging && showDeleteButton && getDeleteButton()}
{!isDebugging && showAddButton && getAddElementButton()}
+ {!isDebugging && showCopyButton && getCopyElementButton()}
</div>
)
}
@@ -313,8 +316,7 @@ export function DslElementHeader(props: Props) {
function getAddElementButton() {
return (
- <Tooltip position={"bottom"}
- content={<div>{"Add DSL element to " +
CamelDisplayUtil.getTitle(step)}</div>}>
+ <Tooltip position={"bottom"} content={<div>{"Add DSL element to "
+ CamelDisplayUtil.getTitle(step)}</div>}>
<button
type="button"
aria-label="Add"
@@ -325,6 +327,24 @@ export function DslElementHeader(props: Props) {
</Tooltip>
)
}
+ function getCopyElementButton() {
+ return (
+ <Tooltip position={"left"} content={"Copy element"}>
+ <button
+ type="button"
+ aria-label="Copy"
+ onClick={e => {
+ e.stopPropagation();
+ if (props.parent) {
+ copyPasteStep(step, props.parent?.uuid,
props.position)
+ }
+ }}
+ className={"copy-element-button"}>
+ <CopyElementIcon/>
+ </button>
+ </Tooltip>
+ )
+ }
function getInsertElementButton() {
return (
diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
index 62cda4bb..ac92bfe5 100644
--- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
@@ -182,6 +182,14 @@ export function useRouteDesignerHook() {
}
}
+ function copyPasteStep(step: CamelElement, parentUuid: string, position:
number): void {
+ if (step) {
+ const clone = CamelUtil.cloneStep(step, true);
+ (clone as any).id = (clone as any).stepName + "-" +
clone.uuid.substring(0,4);
+ addStep(clone, parentUuid, position + 1);
+ }
+ }
+
function copyToClipboard(): void {
const steps: CamelElement[] = []
selectedUuids.forEach(selectedUuid => {
@@ -397,6 +405,6 @@ export function useRouteDesignerHook() {
return {
deleteElement, selectElement, moveElement, onShowDeleteConfirmation,
onDslSelect, openSelector,
createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp,
unselectElement, isKamelet, isSourceKamelet,
- isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate
+ isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate, copyPasteStep
}
}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/utils/ElementIcon.css
b/karavan-designer/src/designer/utils/ElementIcon.css
index f89c962b..ee7d87dc 100644
--- a/karavan-designer/src/designer/utils/ElementIcon.css
+++ b/karavan-designer/src/designer/utils/ElementIcon.css
@@ -24,6 +24,13 @@
vertical-align: text-bottom;
}
+.copy-button-icon {
+ width: 20px;
+ height: 20px;
+ background: transparent;
+ vertical-align: text-bottom;
+}
+
.delete-button-icon {
fill: var(--pf-v5-global--danger-color--100);
width: 20px;
diff --git a/karavan-designer/src/designer/utils/ElementIcons.tsx
b/karavan-designer/src/designer/utils/ElementIcons.tsx
index 2d44bc5e..63c3ee43 100644
--- a/karavan-designer/src/designer/utils/ElementIcons.tsx
+++ b/karavan-designer/src/designer/utils/ElementIcons.tsx
@@ -18,6 +18,27 @@
import "./ElementIcon.css"
import React from 'react'
+export function CopyElementIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ className="copy-button-icon"
+ fill="none"
+ viewBox="0 0 27 27"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={2}
+ style={{
+ stroke: "var(--pf-v5-global--primary-color--100)",
+ }}
+ d="M9.41 2.34a9.996 9.996 0 0 1 9.661 2.589c3.905 3.905 3.905
10.237 0 14.142-3.905 3.905-10.237 3.905-14.142 0a9.996 9.996 0 0
1-2.59-9.66M15 9v6m0 0H9m6 0L5 5"
+ />
+ </svg>
+ )
+}
+
export function DeleteElementIcon() {
return (
<svg
diff --git a/karavan-space/src/designer/route/element/DslElement.css
b/karavan-space/src/designer/route/element/DslElement.css
index 791acdb3..5ab8ecfd 100644
--- a/karavan-space/src/designer/route/element/DslElement.css
+++ b/karavan-space/src/designer/route/element/DslElement.css
@@ -235,6 +235,20 @@
z-index: 100;
}
+.karavan .step-element .copy-element-button {
+ position: absolute;
+ bottom: 9px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0 0 0 -30px;
+ background: transparent;
+ color: var(--pf-v5-global--primary-color--100);
+ visibility: hidden;
+ z-index: 100;
+}
+
+.karavan .step-element .header:hover .copy-element-button,
.karavan .step-element .header:hover .insert-element-button {
visibility: visible;
}
diff --git a/karavan-space/src/designer/route/element/DslElementHeader.tsx
b/karavan-space/src/designer/route/element/DslElementHeader.tsx
index db181cff..90eb5985 100644
--- a/karavan-space/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-space/src/designer/route/element/DslElementHeader.tsx
@@ -26,7 +26,7 @@ import {CamelDisplayUtil} from
"karavan-core/lib/api/CamelDisplayUtil";
import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "../useRouteDesignerHook";
-import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from
"../../utils/ElementIcons";
+import {AddElementIcon, DeleteElementIcon, InsertElementIcon, CopyElementIcon}
from "../../utils/ElementIcons";
import { RouteConfigurationDefinition} from
"karavan-core/lib/model/CamelDefinition";
import {AutoStartupIcon, ErrorHandlerIcon} from "../../icons/OtherIcons";
@@ -50,7 +50,8 @@ export function DslElementHeader(props: Props) {
openSelector,
isKamelet,
isSourceKamelet,
- isActionKamelet
+ isActionKamelet,
+ copyPasteStep
} = useRouteDesignerHook();
const [integration] = useIntegrationStore((s) => [s.integration], shallow)
@@ -217,6 +218,7 @@ export function DslElementHeader(props: Props) {
!['FromDefinition', 'RouteConfigurationDefinition',
'RouteTemplateDefinition', 'RouteDefinition', 'CatchDefinition',
'FinallyDefinition', 'WhenDefinition',
'OtherwiseDefinition'].includes(step.dslName)
&& !inRouteConfiguration;
const showDeleteButton = !('RouteDefinition' === step.dslName &&
'RouteTemplateDefinition' === parent?.dslName);
+ const showCopyButton = ['ToDefinition', 'ToDynamicDefinition',
'PollDefinition'].includes(step.dslName);
const headerClasses = getHeaderClasses();
const childrenInfo = getChildrenInfo(step) || [];
const hasWideChildrenElement = getHasWideChildrenElement(childrenInfo)
@@ -250,6 +252,7 @@ export function DslElementHeader(props: Props) {
{!isDebugging && showInsertButton && getInsertElementButton()}
{!isDebugging && showDeleteButton && getDeleteButton()}
{!isDebugging && showAddButton && getAddElementButton()}
+ {!isDebugging && showCopyButton && getCopyElementButton()}
</div>
)
}
@@ -313,8 +316,7 @@ export function DslElementHeader(props: Props) {
function getAddElementButton() {
return (
- <Tooltip position={"bottom"}
- content={<div>{"Add DSL element to " +
CamelDisplayUtil.getTitle(step)}</div>}>
+ <Tooltip position={"bottom"} content={<div>{"Add DSL element to "
+ CamelDisplayUtil.getTitle(step)}</div>}>
<button
type="button"
aria-label="Add"
@@ -325,6 +327,24 @@ export function DslElementHeader(props: Props) {
</Tooltip>
)
}
+ function getCopyElementButton() {
+ return (
+ <Tooltip position={"left"} content={"Copy element"}>
+ <button
+ type="button"
+ aria-label="Copy"
+ onClick={e => {
+ e.stopPropagation();
+ if (props.parent) {
+ copyPasteStep(step, props.parent?.uuid,
props.position)
+ }
+ }}
+ className={"copy-element-button"}>
+ <CopyElementIcon/>
+ </button>
+ </Tooltip>
+ )
+ }
function getInsertElementButton() {
return (
diff --git a/karavan-space/src/designer/route/useRouteDesignerHook.tsx
b/karavan-space/src/designer/route/useRouteDesignerHook.tsx
index 62cda4bb..ac92bfe5 100644
--- a/karavan-space/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-space/src/designer/route/useRouteDesignerHook.tsx
@@ -182,6 +182,14 @@ export function useRouteDesignerHook() {
}
}
+ function copyPasteStep(step: CamelElement, parentUuid: string, position:
number): void {
+ if (step) {
+ const clone = CamelUtil.cloneStep(step, true);
+ (clone as any).id = (clone as any).stepName + "-" +
clone.uuid.substring(0,4);
+ addStep(clone, parentUuid, position + 1);
+ }
+ }
+
function copyToClipboard(): void {
const steps: CamelElement[] = []
selectedUuids.forEach(selectedUuid => {
@@ -397,6 +405,6 @@ export function useRouteDesignerHook() {
return {
deleteElement, selectElement, moveElement, onShowDeleteConfirmation,
onDslSelect, openSelector,
createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp,
unselectElement, isKamelet, isSourceKamelet,
- isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate
+ isActionKamelet, isSinkKamelet, openSelectorToReplaceFrom,
createRouteTemplate, copyPasteStep
}
}
\ No newline at end of file
diff --git a/karavan-space/src/designer/utils/ElementIcon.css
b/karavan-space/src/designer/utils/ElementIcon.css
index f89c962b..ee7d87dc 100644
--- a/karavan-space/src/designer/utils/ElementIcon.css
+++ b/karavan-space/src/designer/utils/ElementIcon.css
@@ -24,6 +24,13 @@
vertical-align: text-bottom;
}
+.copy-button-icon {
+ width: 20px;
+ height: 20px;
+ background: transparent;
+ vertical-align: text-bottom;
+}
+
.delete-button-icon {
fill: var(--pf-v5-global--danger-color--100);
width: 20px;
diff --git a/karavan-space/src/designer/utils/ElementIcons.tsx
b/karavan-space/src/designer/utils/ElementIcons.tsx
index 2d44bc5e..63c3ee43 100644
--- a/karavan-space/src/designer/utils/ElementIcons.tsx
+++ b/karavan-space/src/designer/utils/ElementIcons.tsx
@@ -18,6 +18,27 @@
import "./ElementIcon.css"
import React from 'react'
+export function CopyElementIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ className="copy-button-icon"
+ fill="none"
+ viewBox="0 0 27 27"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={2}
+ style={{
+ stroke: "var(--pf-v5-global--primary-color--100)",
+ }}
+ d="M9.41 2.34a9.996 9.996 0 0 1 9.661 2.589c3.905 3.905 3.905
10.237 0 14.142-3.905 3.905-10.237 3.905-14.142 0a9.996 9.996 0 0
1-2.59-9.66M15 9v6m0 0H9m6 0L5 5"
+ />
+ </svg>
+ )
+}
+
export function DeleteElementIcon() {
return (
<svg