You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/01/25 15:30:17 UTC
[camel-karavan] branch main updated (504673cf -> e9177143)
This is an automated email from the ASF dual-hosted git repository.
marat pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
from 504673cf Copy/Paste Route
new 8392b52d Apply last changes to space
new 910e4379 Apply last changes to app
new e9177143 Fix #632
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../quarkus-kubernetes-application.properties | 2 +-
.../quarkus-openshift-application.properties | 2 +-
.../main/webui/src/designer/KaravanDesigner.tsx | 11 +-
.../main/webui/src/designer/route/DslElement.tsx | 36 +-
.../webui/src/designer/route/RouteDesigner.tsx | 354 +++-----------------
.../src/designer/route/RouteDesignerLogic.tsx | 0
.../src/main/webui/src/designer/utils/EventBus.ts | 14 +
karavan-demo/aggregator/application.properties | 2 +-
.../quarkus/application.properties | 2 +-
.../postman/project/application.properties | 2 +-
.../rest-service/quarkus/application.properties | 2 +-
karavan-space/src/designer/KaravanDesigner.tsx | 11 +-
karavan-space/src/designer/route/RouteDesigner.tsx | 370 ++-------------------
.../src/designer/route/RouteDesignerLogic.tsx | 0
karavan-space/src/designer/utils/EventBus.ts | 14 +
karavan-vscode/CHANGELOG.md | 2 +
karavan-vscode/package.json | 6 +-
17 files changed, 120 insertions(+), 710 deletions(-)
copy {karavan-designer => karavan-app/src/main/webui}/src/designer/route/RouteDesignerLogic.tsx (100%)
copy {karavan-designer => karavan-space}/src/designer/route/RouteDesignerLogic.tsx (100%)
[camel-karavan] 01/03: Apply last changes to space
Posted by ma...@apache.org.
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
commit 8392b52d10535ebde3c7ff84672a01466875a1cb
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Mon Jan 23 11:45:05 2023 -0500
Apply last changes to space
---
karavan-space/src/designer/KaravanDesigner.tsx | 11 +-
karavan-space/src/designer/route/RouteDesigner.tsx | 370 ++-------------------
.../{RouteDesigner.tsx => RouteDesignerLogic.tsx} | 346 ++++++-------------
karavan-space/src/designer/utils/EventBus.ts | 14 +
4 files changed, 142 insertions(+), 599 deletions(-)
diff --git a/karavan-space/src/designer/KaravanDesigner.tsx b/karavan-space/src/designer/KaravanDesigner.tsx
index e7f975b8..a2556b2a 100644
--- a/karavan-space/src/designer/KaravanDesigner.tsx
+++ b/karavan-space/src/designer/KaravanDesigner.tsx
@@ -44,7 +44,6 @@ interface State {
integration: Integration
key: string
propertyOnly: boolean
- routeDesignerRef?: any
}
export class KaravanInstance {
@@ -78,7 +77,6 @@ export class KaravanDesigner extends React.Component<Props, State> {
integration: this.getIntegration(this.props.yaml, this.props.filename),
key: "",
propertyOnly: false,
- routeDesignerRef: React.createRef(),
}
componentDidMount() {
@@ -117,12 +115,6 @@ export class KaravanDesigner extends React.Component<Props, State> {
)
}
- downloadImage(){
- if(this.state.routeDesignerRef){
- this.state.routeDesignerRef.current.integrationImageDownload();
- }
- }
-
render() {
const tab = this.state.tab;
return (
@@ -134,8 +126,7 @@ export class KaravanDesigner extends React.Component<Props, State> {
</Tabs>
{tab === 'routes' && <RouteDesigner integration={this.state.integration}
onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}
- ref={this.state.routeDesignerRef}/>}
+ dark={this.props.dark}/>}
{tab === 'rest' && <RestDesigner integration={this.state.integration}
onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
dark={this.props.dark}/>}
diff --git a/karavan-space/src/designer/route/RouteDesigner.tsx b/karavan-space/src/designer/route/RouteDesigner.tsx
index 67779963..dc0ab805 100644
--- a/karavan-space/src/designer/route/RouteDesigner.tsx
+++ b/karavan-space/src/designer/route/RouteDesigner.tsx
@@ -25,21 +25,14 @@ import {
} from '@patternfly/react-core';
import '../karavan.css';
import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "../utils/DslMetaModel";
import {DslProperties} from "./DslProperties";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {FromDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {DslConnections} from "./DslConnections";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {DslElement} from "./DslElement";
-import {EventBus} from "../utils/EventBus";
-import {CamelUi, RouteToCreate} from "../utils/CamelUi";
-import {findDOMNode} from "react-dom";
+import {CamelUi} from "../utils/CamelUi";
import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {toPng} from 'html-to-image';
+import {RouteDesignerLogic} from "./RouteDesignerLogic";
interface Props {
onSave?: (integration: Integration, propertyOnly: boolean) => void
@@ -47,7 +40,8 @@ interface Props {
dark: boolean
}
-interface State {
+export interface RouteDesignerState {
+ logic: RouteDesignerLogic
integration: Integration
selectedStep?: CamelElement
showSelector: boolean
@@ -71,9 +65,10 @@ interface State {
selectorTabIndex?: string | number
}
-export class RouteDesigner extends React.Component<Props, State> {
+export class RouteDesigner extends React.Component<Props, RouteDesignerState> {
- public state: State = {
+ public state: RouteDesignerState = {
+ logic: new RouteDesignerLogic(this),
integration: CamelDisplayUtil.setIntegrationVisibility(this.props.integration, undefined),
showSelector: false,
showDeleteConfirmation: false,
@@ -93,315 +88,41 @@ export class RouteDesigner extends React.Component<Props, State> {
};
componentDidMount() {
- window.addEventListener('resize', this.handleResize);
- window.addEventListener('keydown', this.handleKeyDown);
- window.addEventListener('keyup', this.handleKeyUp);
- const element = findDOMNode(this.state.ref.current)?.parentElement?.parentElement;
- const checkResize = (mutations: any) => {
- const el = mutations[0].target;
- const w = el.clientWidth;
- const isChange = mutations.map((m: any) => `${m.oldValue}`).some((prev: any) => prev.indexOf(`width: ${w}px`) === -1);
- if (isChange) this.setState({key: Math.random().toString()});
- }
- if (element) {
- const observer = new MutationObserver(checkResize);
- observer.observe(element, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
- }
+ this.state.logic.componentDidMount();
}
componentWillUnmount() {
- window.removeEventListener('resize', this.handleResize);
- window.removeEventListener('keydown', this.handleKeyDown);
- window.removeEventListener('keyup', this.handleKeyUp);
+ this.state.logic.componentWillUnmount();
}
handleResize = (event: any) => {
- this.setState({key: Math.random().toString()});
+ return this.state.logic.handleResize(event);
}
handleKeyDown = (event: KeyboardEvent) => {
- const {integration, selectedUuids, clipboardSteps} = this.state;
- if ((event.shiftKey)) {
- this.setState({shiftKeyPressed: true});
- }
- if (window.document.hasFocus() && window.document.activeElement) {
- if (['BODY', 'MAIN'].includes(window.document.activeElement.tagName)) {
- let charCode = String.fromCharCode(event.which).toLowerCase();
- if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
- const steps: CamelElement[] = []
- selectedUuids.forEach(selectedUuid => {
- const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
- if (selectedElement) {
- steps.push(selectedElement);
- }
- })
- this.saveToClipboard(steps);
- } else if ((event.ctrlKey || event.metaKey) && charCode === 'v') {
- if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
- const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
- const route = CamelDefinitionApi.createRouteDefinition({from: clone});
- this.addStep(route, '', 0)
- } else if (selectedUuids.length === 1) {
- const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
- clipboardSteps.reverse().forEach(clipboardStep => {
- if (clipboardStep && targetMeta.parentUuid) {
- const clone = CamelUtil.cloneStep(clipboardStep, true);
- this.addStep(clone, targetMeta.parentUuid, targetMeta.position);
- }
- })
- }
- }
- }
- } else {
- if (event.repeat) {
- window.dispatchEvent(event);
- }
- }
+ return this.state.logic.handleKeyDown(event);
}
handleKeyUp = (event: KeyboardEvent) => {
- this.setState({shiftKeyPressed: false});
- if (event.repeat) {
- window.dispatchEvent(event);
- }
+ return this.state.logic.handleKeyUp(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);
- }
- }
-
- saveToClipboard = (steps: CamelElement[]): void => {
- if (steps.length >0) {
- this.setState(prevState => ({
- key: Math.random().toString(),
- clipboardSteps: [...steps]
- }));
- }
- }
-
- onPropertyUpdate = (element: CamelElement, newRoute?: RouteToCreate) => {
- if (newRoute) {
- let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.state.integration, element);
- const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName + ":" + newRoute.name})
- const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
- i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
- const clone = CamelUtil.cloneIntegration(i);
- this.setState(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: element,
- propertyOnly: false,
- selectedUuids: [element.uuid]
- }));
- } else {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
- const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
- this.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
- }
- }
-
- showDeleteConfirmation = (id: string) => {
- let message: string;
- let ce: CamelElement;
- let isRouteConfiguration: boolean = false;
- ce = CamelDefinitionApiExt.findElementInIntegration(this.state.integration, id)!;
- if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this. Use its uuid.
- let flows = this.state.integration.spec.flows!;
- for (let i = 0; i < flows.length; i++) {
- if (flows[i].dslName === 'RouteDefinition') {
- let routeDefinition: RouteDefinition = flows[i];
- if (routeDefinition.from.uuid === id) {
- id = routeDefinition.uuid;
- break;
- }
- }
- }
- message = 'Deleting the first element will delete the entire route!';
- } else if (ce.dslName === 'RouteDefinition') {
- message = 'Delete route?';
- } else if (ce.dslName === 'RouteConfigurationDefinition') {
- message = 'Delete route configuration?';
- isRouteConfiguration = true;
- } else {
- message = 'Delete element from route?';
- }
- this.setState(prevState => ({
- showSelector: false,
- showDeleteConfirmation: true,
- deleteMessage: message,
- selectedUuids: [id],
- }));
- }
-
- deleteElement = () => {
- const id = this.state.selectedUuids.at(0);
- if (id) {
- const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id);
- this.setState(prevState => ({
- integration: i,
- showSelector: false,
- showDeleteConfirmation: false,
- deleteMessage: '',
- key: Math.random().toString(),
- selectedStep: undefined,
- propertyOnly: false,
- selectedUuids: [id],
- }));
- const el = new CamelElement("");
- el.uuid = id;
- EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0);
- }
- }
-
- selectElement = (element: CamelElement) => {
- const {shiftKeyPressed, selectedUuids, integration} = this.state;
- let canNotAdd: boolean = false;
- if (shiftKeyPressed) {
- const hasFrom = selectedUuids.map(e => CamelDefinitionApiExt.findElementInIntegration(integration, e)?.dslName === 'FromDefinition').filter(r => r).length > 0;
- canNotAdd = hasFrom || (selectedUuids.length > 0 && element.dslName === 'FromDefinition');
- }
- const add = shiftKeyPressed && !selectedUuids.includes(element.uuid);
- const remove = shiftKeyPressed && selectedUuids.includes(element.uuid);
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, element.uuid);
- this.setState((prevState: State) => {
- if (remove) {
- const index = prevState.selectedUuids.indexOf(element.uuid);
- prevState.selectedUuids.splice(index, 1);
- } else if (add && !canNotAdd) {
- prevState.selectedUuids.push(element.uuid);
- }
- const uuid: string = prevState.selectedUuids.includes(element.uuid) ? element.uuid : prevState.selectedUuids.at(0) || '';
- const selectedElement = shiftKeyPressed ? CamelDefinitionApiExt.findElementInIntegration(integration, uuid) : element;
- return {
- integration: i,
- selectedStep: selectedElement,
- showSelector: false,
- selectedUuids: shiftKeyPressed ? [...prevState.selectedUuids] : [element.uuid],
- }
- });
- }
-
- unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
- if ((evt.target as any).dataset.click === 'FLOWS') {
- evt.stopPropagation()
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, undefined);
- this.setState(prevState => ({
- integration: i,
- selectedStep: undefined,
- showSelector: false,
- selectedPosition: undefined,
- selectedUuids: [],
- }));
- }
- }
-
- openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
- this.setState({
- showSelector: true,
- parentId: parentId || '',
- parentDsl: parentDsl,
- showSteps: showSteps,
- selectedPosition: position,
- selectorTabIndex: selectorTabIndex
- })
- }
-
- closeDslSelector = () => {
- this.setState({showSelector: false})
- }
-
- onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
- switch (dsl.dsl) {
- case 'FromDefinition' :
- 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});
- this.addStep(to, parentId, position)
- break;
- case 'ToDynamicDefinition' :
- const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
- this.addStep(toD, parentId, position)
- break;
- case 'KameletDefinition' :
- const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: dsl.name});
- this.addStep(kamelet, parentId, position)
- break;
- default:
- const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
- this.addStep(step, parentId, position)
- break;
- }
- }
-
- createRouteConfiguration = () => {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
- const routeConfiguration = new RouteConfigurationDefinition();
- const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
- this.setState(prevState => ({
- integration: i,
- propertyOnly: false,
- key: Math.random().toString(),
- selectedStep: routeConfiguration,
- selectedUuids: [routeConfiguration.uuid],
- }));
- }
-
- 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(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: step,
- propertyOnly: false,
- selectedUuids: [step.uuid],
- }));
- }
-
- onIntegrationUpdate = (i: Integration) => {
- this.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
- }
-
- moveElement = (source: string, target: string, asChild: boolean) => {
- const i = CamelDefinitionApiExt.moveRouteElement(this.state.integration, source, target, asChild);
- const clone = CamelUtil.cloneIntegration(i);
- const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
- this.setState(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: selectedStep,
- propertyOnly: false,
- selectedUuids: [source],
- }));
- }
-
- onResizePage(el: HTMLDivElement | null) {
- const rect = el?.getBoundingClientRect();
- if (el && rect && (el.scrollWidth !== this.state.width || el.scrollHeight !== this.state.height || rect.top !== this.state.top || rect.left !== this.state.left)) {
- this.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
- }
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
+ return this.state.logic.componentDidUpdate(prevState, snapshot);
}
getSelectorModal() {
return (
<DslSelector
isOpen={this.state.showSelector}
- onClose={() => this.closeDslSelector()}
+ onClose={() => this.state.logic.closeDslSelector()}
dark={this.props.dark}
parentId={this.state.parentId}
parentDsl={this.state.parentDsl}
showSteps={this.state.showSteps}
position={this.state.selectedPosition}
tabIndex={this.state.selectorTabIndex}
- onDslSelect={this.onDslSelect}/>)
+ onDslSelect={this.state.logic.onDslSelect}/>)
}
getDeleteConfirmation() {
@@ -412,7 +133,7 @@ export class RouteDesigner extends React.Component<Props, State> {
isOpen={this.state.showDeleteConfirmation}
onClose={() => this.setState({showDeleteConfirmation: false})}
actions={[
- <Button key="confirm" variant="primary" onClick={e => this.deleteElement()}>Delete</Button>,
+ <Button key="confirm" variant="primary" onClick={e => this.state.logic.deleteElement()}>Delete</Button>,
<Button key="cancel" variant="link"
onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
]}
@@ -431,43 +152,14 @@ export class RouteDesigner extends React.Component<Props, State> {
<DslProperties ref={this.state.ref}
integration={this.state.integration}
step={this.state.selectedStep}
- onIntegrationUpdate={this.onIntegrationUpdate}
- onPropertyUpdate={this.onPropertyUpdate}
+ onIntegrationUpdate={this.state.logic.onIntegrationUpdate}
+ onPropertyUpdate={this.state.logic.onPropertyUpdate}
isRouteDesigner={true}
dark={this.props.dark}/>
</DrawerPanelContent>
)
}
- downloadIntegrationImage(dataUrl: string) {
- const a = document.createElement('a');
- a.setAttribute('download', 'karavan-routes.png');
- a.setAttribute('href', dataUrl);
- a.click();
- }
-
- integrationImageDownloadFilter = (node: HTMLElement) => {
- const exclusionClasses = ['add-flow'];
- return !exclusionClasses.some(classname => {
- return node.classList === undefined ? false : node.classList.contains(classname);
- });
- }
-
- integrationImageDownload() {
- 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);
- })
- }
-
getGraph() {
const {selectedUuids, integration, key, width, height, top, left} = this.state;
const routes = CamelUi.getRoutes(integration);
@@ -475,15 +167,15 @@ export class RouteDesigner extends React.Component<Props, State> {
return (
<div ref={this.state.printerRef} className="graph">
<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)}>
+ <div className="flows" data-click="FLOWS" onClick={event => this.state.logic.unselectElement(event)}
+ ref={el => this.state.logic.onResizePage(el)}>
{routeConfigurations?.map((routeConfiguration, index: number) => (
<DslElement key={routeConfiguration.uuid + key}
integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
+ openSelector={this.state.logic.openSelector}
+ deleteElement={this.state.logic.showDeleteConfirmation}
+ selectElement={this.state.logic.selectElement}
+ moveElement={this.state.logic.moveElement}
selectedUuid={selectedUuids}
inSteps={false}
position={index}
@@ -493,10 +185,10 @@ export class RouteDesigner extends React.Component<Props, State> {
{routes?.map((route: any, index: number) => (
<DslElement key={route.uuid + key}
integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
+ openSelector={this.state.logic.openSelector}
+ deleteElement={this.state.logic.showDeleteConfirmation}
+ selectElement={this.state.logic.selectElement}
+ moveElement={this.state.logic.moveElement}
selectedUuid={selectedUuids}
inSteps={false}
position={index}
@@ -507,12 +199,12 @@ export class RouteDesigner extends React.Component<Props, State> {
<Button
variant={routes.length === 0 ? "primary" : "secondary"}
icon={<PlusIcon/>}
- onClick={e => this.openSelector(undefined, undefined)}>Create route
+ onClick={e => this.state.logic.openSelector(undefined, undefined)}>Create route
</Button>
<Button
variant="secondary"
icon={<PlusIcon/>}
- onClick={e => this.createRouteConfiguration()}>Create configuration
+ onClick={e => this.state.logic.createRouteConfiguration()}>Create configuration
</Button>
</div>
</div>
diff --git a/karavan-space/src/designer/route/RouteDesigner.tsx b/karavan-space/src/designer/route/RouteDesignerLogic.tsx
similarity index 50%
copy from karavan-space/src/designer/route/RouteDesigner.tsx
copy to karavan-space/src/designer/route/RouteDesignerLogic.tsx
index 67779963..18b2ce3c 100644
--- a/karavan-space/src/designer/route/RouteDesigner.tsx
+++ b/karavan-space/src/designer/route/RouteDesignerLogic.tsx
@@ -15,141 +15,70 @@
* limitations under the License.
*/
import React from 'react';
-import {
- Drawer,
- DrawerPanelContent,
- DrawerContent,
- DrawerContentBody,
- Button, Modal,
- PageSection,
-} from '@patternfly/react-core';
import '../karavan.css';
-import {DslSelector} from "./DslSelector";
import {DslMetaModel} from "../utils/DslMetaModel";
-import {DslProperties} from "./DslProperties";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {FromDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
-import {DslConnections} from "./DslConnections";
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {DslElement} from "./DslElement";
-import {EventBus} from "../utils/EventBus";
-import {CamelUi, RouteToCreate} from "../utils/CamelUi";
-import {findDOMNode} from "react-dom";
+import {Command, EventBus} from "../utils/EventBus";
+import {RouteToCreate} from "../utils/CamelUi";
import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
import {toPng} from 'html-to-image';
+import {RouteDesigner, RouteDesignerState} from "./RouteDesigner";
+import {findDOMNode} from "react-dom";
+import {Subscription} from "rxjs";
-interface Props {
- onSave?: (integration: Integration, propertyOnly: boolean) => void
- integration: Integration
- dark: boolean
-}
-
-interface State {
- integration: Integration
- selectedStep?: CamelElement
- showSelector: boolean
- showDeleteConfirmation: boolean
- deleteMessage: string
- parentId: string
- parentDsl?: string
- selectedPosition?: number
- showSteps: boolean
- selectedUuids: string []
- key: string
- width: number
- height: number
- top: number
- left: number
- clipboardSteps: CamelElement[]
- shiftKeyPressed?: boolean
- ref?: any
- printerRef?: any
- propertyOnly: boolean
- selectorTabIndex?: string | number
-}
+export class RouteDesignerLogic {
-export class RouteDesigner extends React.Component<Props, State> {
+ routeDesigner: RouteDesigner
+ commandSub?: Subscription
- public state: State = {
- integration: CamelDisplayUtil.setIntegrationVisibility(this.props.integration, undefined),
- showSelector: false,
- showDeleteConfirmation: false,
- deleteMessage: '',
- parentId: '',
- showSteps: true,
- selectedUuids: [],
- clipboardSteps: [],
- key: "",
- width: 1000,
- height: 1000,
- top: 0,
- left: 0,
- ref: React.createRef(),
- printerRef: React.createRef(),
- propertyOnly: false,
- };
+ constructor(routeDesigner: RouteDesigner) {
+ this.routeDesigner = routeDesigner;
+ }
componentDidMount() {
- window.addEventListener('resize', this.handleResize);
- window.addEventListener('keydown', this.handleKeyDown);
- window.addEventListener('keyup', this.handleKeyUp);
- const element = findDOMNode(this.state.ref.current)?.parentElement?.parentElement;
+ window.addEventListener('resize', this.routeDesigner.handleResize);
+ window.addEventListener('keydown', this.routeDesigner.handleKeyDown);
+ window.addEventListener('keyup', this.routeDesigner.handleKeyUp);
+ const element = findDOMNode(this.routeDesigner.state.ref.current)?.parentElement?.parentElement;
const checkResize = (mutations: any) => {
const el = mutations[0].target;
const w = el.clientWidth;
const isChange = mutations.map((m: any) => `${m.oldValue}`).some((prev: any) => prev.indexOf(`width: ${w}px`) === -1);
- if (isChange) this.setState({key: Math.random().toString()});
+ if (isChange) this.routeDesigner.setState({key: Math.random().toString()});
}
if (element) {
const observer = new MutationObserver(checkResize);
observer.observe(element, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
}
+ this.commandSub = EventBus.onCommand()?.subscribe((command: Command) => this.onCommand(command));
}
componentWillUnmount() {
- window.removeEventListener('resize', this.handleResize);
- window.removeEventListener('keydown', this.handleKeyDown);
- window.removeEventListener('keyup', this.handleKeyUp);
+ window.removeEventListener('resize', this.routeDesigner.handleResize);
+ window.removeEventListener('keydown', this.routeDesigner.handleKeyDown);
+ window.removeEventListener('keyup', this.routeDesigner.handleKeyUp);
+ this.commandSub?.unsubscribe();
}
handleResize = (event: any) => {
- this.setState({key: Math.random().toString()});
+ this.routeDesigner.setState({key: Math.random().toString()});
}
handleKeyDown = (event: KeyboardEvent) => {
- const {integration, selectedUuids, clipboardSteps} = this.state;
if ((event.shiftKey)) {
- this.setState({shiftKeyPressed: true});
+ this.routeDesigner.setState({shiftKeyPressed: true});
}
if (window.document.hasFocus() && window.document.activeElement) {
if (['BODY', 'MAIN'].includes(window.document.activeElement.tagName)) {
let charCode = String.fromCharCode(event.which).toLowerCase();
if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
- const steps: CamelElement[] = []
- selectedUuids.forEach(selectedUuid => {
- const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
- if (selectedElement) {
- steps.push(selectedElement);
- }
- })
- this.saveToClipboard(steps);
+ this.copyToClipboard();
} else if ((event.ctrlKey || event.metaKey) && charCode === 'v') {
- if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
- const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
- const route = CamelDefinitionApi.createRouteDefinition({from: clone});
- this.addStep(route, '', 0)
- } else if (selectedUuids.length === 1) {
- const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
- clipboardSteps.reverse().forEach(clipboardStep => {
- if (clipboardStep && targetMeta.parentUuid) {
- const clone = CamelUtil.cloneStep(clipboardStep, true);
- this.addStep(clone, targetMeta.parentUuid, targetMeta.position);
- }
- })
- }
+ this.pasteFromClipboard();
}
}
} else {
@@ -160,35 +89,68 @@ export class RouteDesigner extends React.Component<Props, State> {
}
handleKeyUp = (event: KeyboardEvent) => {
- this.setState({shiftKeyPressed: false});
+ this.routeDesigner.setState({shiftKeyPressed: false});
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);
+ componentDidUpdate = (prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
+ if (prevState.key !== this.routeDesigner.state.key) {
+ this.routeDesigner.props.onSave?.call(this, this.routeDesigner.state.integration, this.routeDesigner.state.propertyOnly);
}
}
- saveToClipboard = (steps: CamelElement[]): void => {
+ copyToClipboard = (): void => {
+ const {integration, selectedUuids} = this.routeDesigner.state;
+ const steps: CamelElement[] = []
+ selectedUuids.forEach(selectedUuid => {
+ const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
+ if (selectedElement) {
+ steps.push(selectedElement);
+ }
+ })
if (steps.length >0) {
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
key: Math.random().toString(),
clipboardSteps: [...steps]
}));
}
}
+ pasteFromClipboard = (): void => {
+ const {integration, selectedUuids, clipboardSteps} = this.routeDesigner.state;
+ if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
+ const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+ const route = CamelDefinitionApi.createRouteDefinition({from: clone});
+ this.addStep(route, '', 0)
+ } else if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'RouteDefinition') {
+ const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+ this.addStep(clone, '', 0)
+ } else if (selectedUuids.length === 1) {
+ const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
+ clipboardSteps.reverse().forEach(clipboardStep => {
+ if (clipboardStep && targetMeta.parentUuid) {
+ const clone = CamelUtil.cloneStep(clipboardStep, true);
+ this.addStep(clone, targetMeta.parentUuid, targetMeta.position);
+ }
+ })
+ }
+ }
+
+ onCommand = (command: Command) => {
+ switch (command.command){
+ case "downloadImage": this.integrationImageDownload()
+ }
+ }
onPropertyUpdate = (element: CamelElement, newRoute?: RouteToCreate) => {
if (newRoute) {
- let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.state.integration, element);
+ let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.routeDesigner.state.integration, element);
const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName + ":" + newRoute.name})
const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
const clone = CamelUtil.cloneIntegration(i);
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
integration: clone,
key: Math.random().toString(),
showSelector: false,
@@ -197,9 +159,9 @@ export class RouteDesigner extends React.Component<Props, State> {
selectedUuids: [element.uuid]
}));
} else {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
+ const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
- this.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
+ this.routeDesigner.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
}
}
@@ -207,9 +169,9 @@ export class RouteDesigner extends React.Component<Props, State> {
let message: string;
let ce: CamelElement;
let isRouteConfiguration: boolean = false;
- ce = CamelDefinitionApiExt.findElementInIntegration(this.state.integration, id)!;
- if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this. Use its uuid.
- let flows = this.state.integration.spec.flows!;
+ ce = CamelDefinitionApiExt.findElementInIntegration(this.routeDesigner.state.integration, id)!;
+ if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this.routeDesigner. Use its uuid.
+ let flows = this.routeDesigner.state.integration.spec.flows!;
for (let i = 0; i < flows.length; i++) {
if (flows[i].dslName === 'RouteDefinition') {
let routeDefinition: RouteDefinition = flows[i];
@@ -228,7 +190,7 @@ export class RouteDesigner extends React.Component<Props, State> {
} else {
message = 'Delete element from route?';
}
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
showSelector: false,
showDeleteConfirmation: true,
deleteMessage: message,
@@ -237,10 +199,10 @@ export class RouteDesigner extends React.Component<Props, State> {
}
deleteElement = () => {
- const id = this.state.selectedUuids.at(0);
+ const id = this.routeDesigner.state.selectedUuids.at(0);
if (id) {
- const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id);
- this.setState(prevState => ({
+ const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.routeDesigner.state.integration, id);
+ this.routeDesigner.setState(prevState => ({
integration: i,
showSelector: false,
showDeleteConfirmation: false,
@@ -257,7 +219,7 @@ export class RouteDesigner extends React.Component<Props, State> {
}
selectElement = (element: CamelElement) => {
- const {shiftKeyPressed, selectedUuids, integration} = this.state;
+ const {shiftKeyPressed, selectedUuids, integration} = this.routeDesigner.state;
let canNotAdd: boolean = false;
if (shiftKeyPressed) {
const hasFrom = selectedUuids.map(e => CamelDefinitionApiExt.findElementInIntegration(integration, e)?.dslName === 'FromDefinition').filter(r => r).length > 0;
@@ -265,8 +227,8 @@ export class RouteDesigner extends React.Component<Props, State> {
}
const add = shiftKeyPressed && !selectedUuids.includes(element.uuid);
const remove = shiftKeyPressed && selectedUuids.includes(element.uuid);
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, element.uuid);
- this.setState((prevState: State) => {
+ const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, element.uuid);
+ this.routeDesigner.setState((prevState: RouteDesignerState) => {
if (remove) {
const index = prevState.selectedUuids.indexOf(element.uuid);
prevState.selectedUuids.splice(index, 1);
@@ -287,8 +249,8 @@ export class RouteDesigner extends React.Component<Props, State> {
unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if ((evt.target as any).dataset.click === 'FLOWS') {
evt.stopPropagation()
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, undefined);
- this.setState(prevState => ({
+ const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, undefined);
+ this.routeDesigner.setState(prevState => ({
integration: i,
selectedStep: undefined,
showSelector: false,
@@ -299,7 +261,7 @@ export class RouteDesigner extends React.Component<Props, State> {
}
openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
- this.setState({
+ this.routeDesigner.setState({
showSelector: true,
parentId: parentId || '',
parentDsl: parentDsl,
@@ -310,7 +272,7 @@ export class RouteDesigner extends React.Component<Props, State> {
}
closeDslSelector = () => {
- this.setState({showSelector: false})
+ this.routeDesigner.setState({showSelector: false})
}
onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
@@ -339,10 +301,10 @@ export class RouteDesigner extends React.Component<Props, State> {
}
createRouteConfiguration = () => {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
+ const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
const routeConfiguration = new RouteConfigurationDefinition();
const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
integration: i,
propertyOnly: false,
key: Math.random().toString(),
@@ -352,10 +314,10 @@ 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 i = CamelDefinitionApiExt.addStepToIntegration(this.routeDesigner.state.integration, step, parentId, position);
const clone = CamelUtil.cloneIntegration(i);
EventBus.sendPosition("clean", step, undefined, new DOMRect(), new DOMRect(), 0);
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
integration: clone,
key: Math.random().toString(),
showSelector: false,
@@ -366,14 +328,14 @@ export class RouteDesigner extends React.Component<Props, State> {
}
onIntegrationUpdate = (i: Integration) => {
- this.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
+ this.routeDesigner.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
}
moveElement = (source: string, target: string, asChild: boolean) => {
- const i = CamelDefinitionApiExt.moveRouteElement(this.state.integration, source, target, asChild);
+ const i = CamelDefinitionApiExt.moveRouteElement(this.routeDesigner.state.integration, source, target, asChild);
const clone = CamelUtil.cloneIntegration(i);
const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
- this.setState(prevState => ({
+ this.routeDesigner.setState(prevState => ({
integration: clone,
key: Math.random().toString(),
showSelector: false,
@@ -385,60 +347,11 @@ export class RouteDesigner extends React.Component<Props, State> {
onResizePage(el: HTMLDivElement | null) {
const rect = el?.getBoundingClientRect();
- if (el && rect && (el.scrollWidth !== this.state.width || el.scrollHeight !== this.state.height || rect.top !== this.state.top || rect.left !== this.state.left)) {
- this.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
+ if (el && rect && (el.scrollWidth !== this.routeDesigner.state.width || el.scrollHeight !== this.routeDesigner.state.height || rect.top !== this.routeDesigner.state.top || rect.left !== this.routeDesigner.state.left)) {
+ this.routeDesigner.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
}
}
- getSelectorModal() {
- return (
- <DslSelector
- isOpen={this.state.showSelector}
- onClose={() => this.closeDslSelector()}
- dark={this.props.dark}
- parentId={this.state.parentId}
- parentDsl={this.state.parentDsl}
- showSteps={this.state.showSteps}
- position={this.state.selectedPosition}
- tabIndex={this.state.selectorTabIndex}
- onDslSelect={this.onDslSelect}/>)
- }
-
- getDeleteConfirmation() {
- let htmlContent: string = this.state.deleteMessage;
- 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.deleteElement()}>Delete</Button>,
- <Button key="cancel" variant="link"
- onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
- ]}
- onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
- <div>
- {htmlContent}
- </div>
- </Modal>)
- }
-
- getPropertiesPanel() {
- return (
- <DrawerPanelContent onResize={width => this.setState({key: Math.random().toString(1)})}
- style={{transform: "initial"}} 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}
- isRouteDesigner={true}
- dark={this.props.dark}/>
- </DrawerPanelContent>
- )
- }
-
downloadIntegrationImage(dataUrl: string) {
const a = document.createElement('a');
a.setAttribute('download', 'karavan-routes.png');
@@ -454,84 +367,17 @@ export class RouteDesigner extends React.Component<Props, State> {
}
integrationImageDownload() {
- if (this.state.printerRef.current === null) {
+ if (this.routeDesigner.state.printerRef.current === null) {
return
}
- toPng(this.state.printerRef.current, {
+ toPng(this.routeDesigner.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"
+ height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
}).then(v => {
- toPng(this.state.printerRef.current, {
+ toPng(this.routeDesigner.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"
+ height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
}).then(this.downloadIntegrationImage);
})
}
-
- getGraph() {
- const {selectedUuids, integration, key, width, height, top, left} = this.state;
- const routes = CamelUi.getRoutes(integration);
- const routeConfigurations = CamelUi.getRouteConfigurations(integration);
- return (
- <div ref={this.state.printerRef} className="graph">
- <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) => (
- <DslElement key={routeConfiguration.uuid + key}
- integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
- selectedUuid={selectedUuids}
- inSteps={false}
- position={index}
- step={routeConfiguration}
- parent={undefined}/>
- ))}
- {routes?.map((route: any, index: number) => (
- <DslElement key={route.uuid + key}
- integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
- selectedUuid={selectedUuids}
- inSteps={false}
- position={index}
- step={route}
- parent={undefined}/>
- ))}
- <div className="add-flow">
- <Button
- variant={routes.length === 0 ? "primary" : "secondary"}
- icon={<PlusIcon/>}
- onClick={e => this.openSelector(undefined, undefined)}>Create route
- </Button>
- <Button
- variant="secondary"
- icon={<PlusIcon/>}
- onClick={e => this.createRouteConfiguration()}>Create configuration
- </Button>
- </div>
- </div>
- </div>)
- }
-
- render() {
- return (
- <PageSection className="dsl-page" isFilled padding={{default: 'noPadding'}}>
- <div className="dsl-page-columns">
- <Drawer isExpanded isInline>
- <DrawerContent panelContent={this.getPropertiesPanel()}>
- <DrawerContentBody>{this.getGraph()}</DrawerContentBody>
- </DrawerContent>
- </Drawer>
- </div>
- {this.getSelectorModal()}
- {this.getDeleteConfirmation()}
- </PageSection>
- );
- }
}
\ No newline at end of file
diff --git a/karavan-space/src/designer/utils/EventBus.ts b/karavan-space/src/designer/utils/EventBus.ts
index 2df867f4..aeae6ff7 100644
--- a/karavan-space/src/designer/utils/EventBus.ts
+++ b/karavan-space/src/designer/utils/EventBus.ts
@@ -48,6 +48,17 @@ export class DslPosition {
}
}
+const commands = new Subject<Command>();
+export class Command {
+ command: string;
+ data: any;
+
+ constructor(command: string, data: any) {
+ this.command = command;
+ this.data = data;
+ }
+}
+
export const EventBus = {
sendPosition: (command: "add" | "delete" | "clean",
step: CamelElement,
@@ -58,4 +69,7 @@ export const EventBus = {
inSteps: boolean = false,
isSelected: boolean = false) => positions.next(new DslPosition(command, step, parent, rect, headerRect, position, inSteps, isSelected)),
onPosition: () => positions.asObservable(),
+
+ sendCommand: (command: string, data?: any) => commands.next(new Command(command, data)),
+ onCommand: () => commands.asObservable(),
}
[camel-karavan] 03/03: Fix #632
Posted by ma...@apache.org.
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
commit e9177143f6216a0c33f58277f0a3e6b21e2038d9
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Jan 25 10:30:08 2023 -0500
Fix #632
---
.../resources/snippets/quarkus-kubernetes-application.properties | 2 +-
.../resources/snippets/quarkus-openshift-application.properties | 2 +-
karavan-demo/aggregator/application.properties | 2 +-
karavan-demo/expose-pod-service/quarkus/application.properties | 2 +-
karavan-demo/postman/project/application.properties | 2 +-
karavan-demo/rest-service/quarkus/application.properties | 2 +-
karavan-vscode/CHANGELOG.md | 2 ++
karavan-vscode/package.json | 6 +++---
8 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/karavan-app/src/main/resources/snippets/quarkus-kubernetes-application.properties b/karavan-app/src/main/resources/snippets/quarkus-kubernetes-application.properties
index eb73f218..c3fdc3a8 100644
--- a/karavan-app/src/main/resources/snippets/quarkus-kubernetes-application.properties
+++ b/karavan-app/src/main/resources/snippets/quarkus-kubernetes-application.properties
@@ -3,7 +3,7 @@ camel.karavan.project-name={projectName}
camel.karavan.project-description={projectDescription}
camel.jbang.gav=org.camel.karavan.demo:{projectId}:1
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.13.5.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-kubernetes,mvn:io.quarkus:quarkus-container-image-jib
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-app/src/main/resources/snippets/quarkus-openshift-application.properties b/karavan-app/src/main/resources/snippets/quarkus-openshift-application.properties
index 31de7653..f3fac222 100644
--- a/karavan-app/src/main/resources/snippets/quarkus-openshift-application.properties
+++ b/karavan-app/src/main/resources/snippets/quarkus-openshift-application.properties
@@ -3,7 +3,7 @@ camel.karavan.project-name={projectName}
camel.karavan.project-description={projectDescription}
camel.jbang.gav=org.camel.karavan.demo:{projectId}:1
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.13.5.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-openshift,mvn:io.quarkus:quarkus-container-image-jib
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-demo/aggregator/application.properties b/karavan-demo/aggregator/application.properties
index 397a47f5..4222006a 100644
--- a/karavan-demo/aggregator/application.properties
+++ b/karavan-demo/aggregator/application.properties
@@ -4,7 +4,7 @@ camel.jbang.project-name=Aggregator
camel.jbang.project-description=Aggregator
camel.jbang.gav=org.camel.karavan.demo:aggregator:1.0.0
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.12.2.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=mvn:io.quarkus:quarkus-container-image-jib,mvn:org.apache.camel.quarkus:camel-quarkus-microprofile-health,camel:file
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-demo/expose-pod-service/quarkus/application.properties b/karavan-demo/expose-pod-service/quarkus/application.properties
index 5a72a54c..057e9f40 100644
--- a/karavan-demo/expose-pod-service/quarkus/application.properties
+++ b/karavan-demo/expose-pod-service/quarkus/application.properties
@@ -3,7 +3,7 @@ camel.karavan.project-name=NodePortExpose
camel.karavan.project-description=Example to show the way to expose POD port via NodePort service
camel.jbang.gav=org.camel.karavan.demo:nodeportexpose:1
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.13.5.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-kubernetes,mvn:io.quarkus:quarkus-container-image-jib
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-demo/postman/project/application.properties b/karavan-demo/postman/project/application.properties
index 35ba31fb..d0ba2d28 100644
--- a/karavan-demo/postman/project/application.properties
+++ b/karavan-demo/postman/project/application.properties
@@ -3,7 +3,7 @@ camel.jbang.project-name=postman
camel.jbang.project-description=Postman Demo
camel.jbang.gav=org.camel.karavan.demo:postman:1.0.0
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.12.2.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-container-image-jib,mvn:io.quarkus:quarkus-openshift
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-demo/rest-service/quarkus/application.properties b/karavan-demo/rest-service/quarkus/application.properties
index 340eeef9..6e396053 100644
--- a/karavan-demo/rest-service/quarkus/application.properties
+++ b/karavan-demo/rest-service/quarkus/application.properties
@@ -3,7 +3,7 @@ camel.karavan.project-name=OpenApi
camel.karavan.project-description=Example to show Openapi usage
camel.jbang.gav=org.camel.karavan.demo:openapi:1
camel.jbang.runtime=quarkus
-camel.jbang.quarkusVersion=2.13.5.Final
+camel.jbang.quarkusVersion=2.16.0.Final
camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-kubernetes,mvn:io.quarkus:quarkus-container-image-jib
camel.health.enabled=true
camel.health.exposure-level=full
diff --git a/karavan-vscode/CHANGELOG.md b/karavan-vscode/CHANGELOG.md
index 99cd77a3..163cc15c 100644
--- a/karavan-vscode/CHANGELOG.md
+++ b/karavan-vscode/CHANGELOG.md
@@ -7,6 +7,8 @@
3. Quarkus and Spring Boot in cloud-native mode
4. Kamelets 3.20.0
5. Route Configuration DSL
+6. Quarkus 2.16.0.Final
+7. Spring Boot 2.7.7
## 3.18.5
1. First preview of Karavan Operator
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 35547b24..e82b0085 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -196,7 +196,7 @@
"camel.karavan.project-description=$NAME",
"camel.karavan.target=$TARGET",
"camel.jbang.gav=$GAV",
- "camel.jbang.quarkusVersion=2.15.3.Final",
+ "camel.jbang.quarkusVersion=2.16.0.Final",
"camel.jbang.runtime=$RUNTIME",
"camel.jbang.exportDir=.export"
],
@@ -237,7 +237,7 @@
"type": "string"
},
"default": [
- "camel.jbang.quarkusVersion=2.15.3.Final",
+ "camel.jbang.quarkusVersion=2.16.0.Final",
"camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-openshift,mvn:io.quarkus:quarkus-container-image-jib",
"# image build properties",
"quarkus.container-image.build=true",
@@ -275,7 +275,7 @@
"type": "string"
},
"default": [
- "camel.jbang.quarkusVersion=2.15.3.Final",
+ "camel.jbang.quarkusVersion=2.16.0.Final",
"camel.jbang.dependencies=camel:microprofile-health,mvn:io.quarkus:quarkus-container-image-jib,mvn:io.quarkus:quarkus-kubernetes",
"# image build properties",
"quarkus.container-image.build=true",
[camel-karavan] 02/03: Apply last changes to app
Posted by ma...@apache.org.
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
commit 910e43799a1c9ac67e843f6cf116e495a75cb732
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Mon Jan 23 11:47:04 2023 -0500
Apply last changes to app
---
.../main/webui/src/designer/KaravanDesigner.tsx | 11 +-
.../main/webui/src/designer/route/DslElement.tsx | 36 +-
.../webui/src/designer/route/RouteDesigner.tsx | 354 ++-----------------
.../src/designer/route/RouteDesignerLogic.tsx | 383 +++++++++++++++++++++
.../src/main/webui/src/designer/utils/EventBus.ts | 14 +
5 files changed, 446 insertions(+), 352 deletions(-)
diff --git a/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx b/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
index e7f975b8..a2556b2a 100644
--- a/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
+++ b/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
@@ -44,7 +44,6 @@ interface State {
integration: Integration
key: string
propertyOnly: boolean
- routeDesignerRef?: any
}
export class KaravanInstance {
@@ -78,7 +77,6 @@ export class KaravanDesigner extends React.Component<Props, State> {
integration: this.getIntegration(this.props.yaml, this.props.filename),
key: "",
propertyOnly: false,
- routeDesignerRef: React.createRef(),
}
componentDidMount() {
@@ -117,12 +115,6 @@ export class KaravanDesigner extends React.Component<Props, State> {
)
}
- downloadImage(){
- if(this.state.routeDesignerRef){
- this.state.routeDesignerRef.current.integrationImageDownload();
- }
- }
-
render() {
const tab = this.state.tab;
return (
@@ -134,8 +126,7 @@ export class KaravanDesigner extends React.Component<Props, State> {
</Tabs>
{tab === 'routes' && <RouteDesigner integration={this.state.integration}
onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
- dark={this.props.dark}
- ref={this.state.routeDesignerRef}/>}
+ dark={this.props.dark}/>}
{tab === 'rest' && <RestDesigner integration={this.state.integration}
onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
dark={this.props.dark}/>}
diff --git a/karavan-app/src/main/webui/src/designer/route/DslElement.tsx b/karavan-app/src/main/webui/src/designer/route/DslElement.tsx
index 07222d84..f9cd9498 100644
--- a/karavan-app/src/main/webui/src/designer/route/DslElement.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/DslElement.tsx
@@ -41,7 +41,7 @@ interface Props {
selectElement: any
openSelector: (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean, position?: number | undefined) => void
moveElement: (source: string, target: string, asChild: boolean) => void
- selectedUuid: string
+ selectedUuid: string []
inSteps: boolean
position: number
}
@@ -51,7 +51,6 @@ interface State {
showMoveConfirmation: boolean
moveElements: [string | undefined, string | undefined]
tabIndex: string | number
- selectedUuid: string
isDragging: boolean
isDraggedOver: boolean
}
@@ -63,29 +62,16 @@ export class DslElement extends React.Component<Props, State> {
showMoveConfirmation: false,
moveElements: [undefined, undefined],
tabIndex: 0,
- selectedUuid: this.props.selectedUuid,
isDragging: 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});
- }
- }
+ //
+ // componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
+ // if (prevState.selectedUuid !== this.props.selectedUuid) {
+ // this.setState({selectedUuid: this.props.selectedUuid});
+ // }
+ // }
openSelector = (evt: React.MouseEvent, showSteps: boolean = true, isInsert: boolean = false) => {
evt.stopPropagation();
@@ -139,7 +125,7 @@ export class DslElement extends React.Component<Props, State> {
}
isSelected = (): boolean => {
- return this.state.selectedUuid === this.props.step.uuid
+ return this.props.selectedUuid.includes(this.props.step.uuid);
}
hasBorder = (): boolean => {
@@ -365,7 +351,7 @@ export class DslElement extends React.Component<Props, State> {
deleteElement={this.props.deleteElement}
selectElement={this.props.selectElement}
moveElement={this.props.moveElement}
- selectedUuid={this.state.selectedUuid}
+ selectedUuid={this.props.selectedUuid}
inSteps={child.name === 'steps'}
position={index}
step={element}
@@ -386,7 +372,7 @@ export class DslElement extends React.Component<Props, State> {
getAddStepButton() {
const {integration, step, selectedUuid} = this.props;
- const hideAddButton = step.dslName === 'StepDefinition' && !CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, selectedUuid);
+ const hideAddButton = step.dslName === 'StepDefinition' && !CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, selectedUuid.at(0));
if (hideAddButton) return (<></>)
else return (
<Tooltip position={"bottom"}
@@ -497,8 +483,6 @@ 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-app/src/main/webui/src/designer/route/RouteDesigner.tsx b/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx
index 87584dc1..dc0ab805 100644
--- a/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx
@@ -25,21 +25,14 @@ import {
} from '@patternfly/react-core';
import '../karavan.css';
import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "../utils/DslMetaModel";
import {DslProperties} from "./DslProperties";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {FromDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {DslConnections} from "./DslConnections";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {DslElement} from "./DslElement";
-import {EventBus} from "../utils/EventBus";
-import {CamelUi, RouteToCreate} from "../utils/CamelUi";
-import {findDOMNode} from "react-dom";
+import {CamelUi} from "../utils/CamelUi";
import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {toPng} from 'html-to-image';
+import {RouteDesignerLogic} from "./RouteDesignerLogic";
interface Props {
onSave?: (integration: Integration, propertyOnly: boolean) => void
@@ -47,7 +40,8 @@ interface Props {
dark: boolean
}
-interface State {
+export interface RouteDesignerState {
+ logic: RouteDesignerLogic
integration: Integration
selectedStep?: CamelElement
showSelector: boolean
@@ -57,13 +51,13 @@ interface State {
parentDsl?: string
selectedPosition?: number
showSteps: boolean
- selectedUuid: string []
+ selectedUuids: string []
key: string
width: number
height: number
top: number
left: number
- clipboardStep?: CamelElement
+ clipboardSteps: CamelElement[]
shiftKeyPressed?: boolean
ref?: any
printerRef?: any
@@ -71,16 +65,18 @@ interface State {
selectorTabIndex?: string | number
}
-export class RouteDesigner extends React.Component<Props, State> {
+export class RouteDesigner extends React.Component<Props, RouteDesignerState> {
- public state: State = {
+ public state: RouteDesignerState = {
+ logic: new RouteDesignerLogic(this),
integration: CamelDisplayUtil.setIntegrationVisibility(this.props.integration, undefined),
showSelector: false,
showDeleteConfirmation: false,
deleteMessage: '',
parentId: '',
showSteps: true,
- selectedUuid: [],
+ selectedUuids: [],
+ clipboardSteps: [],
key: "",
width: 1000,
height: 1000,
@@ -92,286 +88,41 @@ export class RouteDesigner extends React.Component<Props, State> {
};
componentDidMount() {
- window.addEventListener('resize', this.handleResize);
- window.addEventListener('keydown', this.handleKeyDown);
- window.addEventListener('keyup', this.handleKeyUp);
- const element = findDOMNode(this.state.ref.current)?.parentElement?.parentElement;
- const checkResize = (mutations: any) => {
- const el = mutations[0].target;
- const w = el.clientWidth;
- const isChange = mutations.map((m: any) => `${m.oldValue}`).some((prev: any) => prev.indexOf(`width: ${w}px`) === -1);
- if (isChange) this.setState({key: Math.random().toString()});
- }
- if (element) {
- const observer = new MutationObserver(checkResize);
- observer.observe(element, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
- }
+ this.state.logic.componentDidMount();
}
componentWillUnmount() {
- window.removeEventListener('resize', this.handleResize);
- window.removeEventListener('keydown', this.handleKeyDown);
- window.removeEventListener('keyup', this.handleKeyUp);
+ this.state.logic.componentWillUnmount();
}
handleResize = (event: any) => {
- this.setState({key: Math.random().toString()});
+ return this.state.logic.handleResize(event);
}
handleKeyDown = (event: KeyboardEvent) => {
- const {integration, selectedUuid, clipboardStep} = this.state;
- const selectedUUID = selectedUuid.at(0);
- if ((event.shiftKey)) {
- this.setState({shiftKeyPressed: true});
- }
- if (window.document.hasFocus() && window.document.activeElement && 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);
- }
- }
+ return this.state.logic.handleKeyDown(event);
}
handleKeyUp = (event: KeyboardEvent) => {
- this.setState({shiftKeyPressed: false});
- if (event.repeat) {
- window.dispatchEvent(event);
- }
+ return this.state.logic.handleKeyUp(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);
- }
- }
-
- saveToClipboard = (step?: CamelElement): void => {
- this.setState({clipboardStep: step, key: Math.random().toString()});
- }
-
- onPropertyUpdate = (element: CamelElement, newRoute?: RouteToCreate) => {
- if (newRoute) {
- let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.state.integration, element);
- const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName + ":" + newRoute.name})
- const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
- i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
- const clone = CamelUtil.cloneIntegration(i);
- this.setState(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: element,
- propertyOnly: false,
- selectedUuid: [element.uuid],
- }));
- } else {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
- const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
- this.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
- }
- }
-
- showDeleteConfirmation = (id: string) => {
- let message: string;
- let ce: CamelElement;
- let isRouteConfiguration: boolean = false;
- ce = CamelDefinitionApiExt.findElementInIntegration(this.state.integration, id)!;
- if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this. Use its uuid.
- let flows = this.state.integration.spec.flows!;
- for (let i = 0; i < flows.length; i++) {
- if (flows[i].dslName === 'RouteDefinition') {
- let routeDefinition: RouteDefinition = flows[i];
- if (routeDefinition.from.uuid === id) {
- id = routeDefinition.uuid;
- break;
- }
- }
- }
- message = 'Deleting the first element will delete the entire route!';
- } else if (ce.dslName === 'RouteDefinition') {
- message = 'Delete route?';
- } else if (ce.dslName === 'RouteConfigurationDefinition') {
- message = 'Delete route configuration?';
- isRouteConfiguration = true;
- } else {
- message = 'Delete element from route?';
- }
- this.setState(prevState => ({
- showSelector: false,
- showDeleteConfirmation: true,
- deleteMessage: message,
- selectedUuid: [id],
- }));
- }
-
- deleteElement = () => {
- const id = this.state.selectedUuid.at(0);
- if (id) {
- const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id);
- this.setState(prevState => ({
- integration: i,
- showSelector: false,
- showDeleteConfirmation: false,
- deleteMessage: '',
- key: Math.random().toString(),
- selectedStep: undefined,
- propertyOnly: false,
- selectedUuid: [id],
- }));
- const el = new CamelElement("");
- el.uuid = id;
- EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0);
- }
- }
-
- selectElement = (element: CamelElement) => {
- console.log(this.state.shiftKeyPressed, element);
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, element.uuid);
- this.setState(prevState => ({
- integration: i,
- selectedStep: element,
- showSelector: false,
- selectedUuid: [element.uuid],
- }));
- }
-
- unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
- if ((evt.target as any).dataset.click === 'FLOWS') {
- evt.stopPropagation()
- const i = CamelDisplayUtil.setIntegrationVisibility(this.state.integration, undefined);
- this.setState(prevState => ({
- integration: i,
- selectedStep: undefined,
- showSelector: false,
- selectedPosition: undefined,
- selectedUuid: [],
- }));
- }
- }
-
- openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
- this.setState({
- showSelector: true,
- parentId: parentId || '',
- parentDsl: parentDsl,
- showSteps: showSteps,
- selectedPosition: position,
- selectorTabIndex: selectorTabIndex
- })
- }
-
- closeDslSelector = () => {
- this.setState({showSelector: false})
- }
-
- onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
- switch (dsl.dsl) {
- case 'FromDefinition' :
- 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});
- this.addStep(to, parentId, position)
- break;
- case 'ToDynamicDefinition' :
- const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
- this.addStep(toD, parentId, position)
- break;
- case 'KameletDefinition' :
- const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: dsl.name});
- this.addStep(kamelet, parentId, position)
- break;
- default:
- const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
- this.addStep(step, parentId, position)
- break;
- }
- }
-
- createRouteConfiguration = () => {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
- const routeConfiguration = new RouteConfigurationDefinition();
- const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
- this.setState(prevState => ({
- integration: i,
- propertyOnly: false,
- key: Math.random().toString(),
- selectedStep: routeConfiguration,
- selectedUuid: [routeConfiguration.uuid],
- }));
- }
-
- 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(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: step,
- propertyOnly: false,
- selectedUuid: [step.uuid],
- }));
- }
-
- onIntegrationUpdate = (i: Integration) => {
- this.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
- }
-
- moveElement = (source: string, target: string, asChild: boolean) => {
- const i = CamelDefinitionApiExt.moveRouteElement(this.state.integration, source, target, asChild);
- const clone = CamelUtil.cloneIntegration(i);
- const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
- this.setState(prevState => ({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: selectedStep,
- propertyOnly: false,
- selectedUuid: [source],
- }));
- }
-
- onResizePage(el: HTMLDivElement | null) {
- const rect = el?.getBoundingClientRect();
- if (el && rect && (el.scrollWidth !== this.state.width || el.scrollHeight !== this.state.height || rect.top !== this.state.top || rect.left !== this.state.left)) {
- this.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
- }
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
+ return this.state.logic.componentDidUpdate(prevState, snapshot);
}
getSelectorModal() {
return (
<DslSelector
isOpen={this.state.showSelector}
- onClose={() => this.closeDslSelector()}
+ onClose={() => this.state.logic.closeDslSelector()}
dark={this.props.dark}
parentId={this.state.parentId}
parentDsl={this.state.parentDsl}
showSteps={this.state.showSteps}
position={this.state.selectedPosition}
tabIndex={this.state.selectorTabIndex}
- onDslSelect={this.onDslSelect}/>)
+ onDslSelect={this.state.logic.onDslSelect}/>)
}
getDeleteConfirmation() {
@@ -382,7 +133,7 @@ export class RouteDesigner extends React.Component<Props, State> {
isOpen={this.state.showDeleteConfirmation}
onClose={() => this.setState({showDeleteConfirmation: false})}
actions={[
- <Button key="confirm" variant="primary" onClick={e => this.deleteElement()}>Delete</Button>,
+ <Button key="confirm" variant="primary" onClick={e => this.state.logic.deleteElement()}>Delete</Button>,
<Button key="cancel" variant="link"
onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
]}
@@ -401,60 +152,31 @@ export class RouteDesigner extends React.Component<Props, State> {
<DslProperties ref={this.state.ref}
integration={this.state.integration}
step={this.state.selectedStep}
- onIntegrationUpdate={this.onIntegrationUpdate}
- onPropertyUpdate={this.onPropertyUpdate}
+ onIntegrationUpdate={this.state.logic.onIntegrationUpdate}
+ onPropertyUpdate={this.state.logic.onPropertyUpdate}
isRouteDesigner={true}
dark={this.props.dark}/>
</DrawerPanelContent>
)
}
- downloadIntegrationImage(dataUrl: string) {
- const a = document.createElement('a');
- a.setAttribute('download', 'karavan-routes.png');
- a.setAttribute('href', dataUrl);
- a.click();
- }
-
- integrationImageDownloadFilter = (node: HTMLElement) => {
- const exclusionClasses = ['add-flow'];
- return !exclusionClasses.some(classname => {
- return node.classList === undefined ? false : node.classList.contains(classname);
- });
- }
-
- integrationImageDownload() {
- 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);
- })
- }
-
getGraph() {
- const {selectedUuid, integration, key, width, height, top, left} = this.state;
+ const {selectedUuids, integration, key, width, height, top, left} = this.state;
const routes = CamelUi.getRoutes(integration);
const routeConfigurations = CamelUi.getRouteConfigurations(integration);
return (
<div ref={this.state.printerRef} className="graph">
<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)}>
+ <div className="flows" data-click="FLOWS" onClick={event => this.state.logic.unselectElement(event)}
+ ref={el => this.state.logic.onResizePage(el)}>
{routeConfigurations?.map((routeConfiguration, index: number) => (
<DslElement key={routeConfiguration.uuid + key}
integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
- selectedUuid={selectedUuid.at(0) || ''}
+ openSelector={this.state.logic.openSelector}
+ deleteElement={this.state.logic.showDeleteConfirmation}
+ selectElement={this.state.logic.selectElement}
+ moveElement={this.state.logic.moveElement}
+ selectedUuid={selectedUuids}
inSteps={false}
position={index}
step={routeConfiguration}
@@ -463,11 +185,11 @@ export class RouteDesigner extends React.Component<Props, State> {
{routes?.map((route: any, index: number) => (
<DslElement key={route.uuid + key}
integration={integration}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
- selectedUuid={selectedUuid.at(0) || ''}
+ openSelector={this.state.logic.openSelector}
+ deleteElement={this.state.logic.showDeleteConfirmation}
+ selectElement={this.state.logic.selectElement}
+ moveElement={this.state.logic.moveElement}
+ selectedUuid={selectedUuids}
inSteps={false}
position={index}
step={route}
@@ -477,12 +199,12 @@ export class RouteDesigner extends React.Component<Props, State> {
<Button
variant={routes.length === 0 ? "primary" : "secondary"}
icon={<PlusIcon/>}
- onClick={e => this.openSelector(undefined, undefined)}>Create route
+ onClick={e => this.state.logic.openSelector(undefined, undefined)}>Create route
</Button>
<Button
variant="secondary"
icon={<PlusIcon/>}
- onClick={e => this.createRouteConfiguration()}>Create configuration
+ onClick={e => this.state.logic.createRouteConfiguration()}>Create configuration
</Button>
</div>
</div>
diff --git a/karavan-app/src/main/webui/src/designer/route/RouteDesignerLogic.tsx b/karavan-app/src/main/webui/src/designer/route/RouteDesignerLogic.tsx
new file mode 100644
index 00000000..18b2ce3c
--- /dev/null
+++ b/karavan-app/src/main/webui/src/designer/route/RouteDesignerLogic.tsx
@@ -0,0 +1,383 @@
+/*
+ * 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 '../karavan.css';
+import {DslMetaModel} from "../utils/DslMetaModel";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {FromDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
+import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
+import {Command, EventBus} from "../utils/EventBus";
+import {RouteToCreate} from "../utils/CamelUi";
+import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
+import {toPng} from 'html-to-image';
+import {RouteDesigner, RouteDesignerState} from "./RouteDesigner";
+import {findDOMNode} from "react-dom";
+import {Subscription} from "rxjs";
+
+export class RouteDesignerLogic {
+
+ routeDesigner: RouteDesigner
+ commandSub?: Subscription
+
+ constructor(routeDesigner: RouteDesigner) {
+ this.routeDesigner = routeDesigner;
+ }
+
+ componentDidMount() {
+ window.addEventListener('resize', this.routeDesigner.handleResize);
+ window.addEventListener('keydown', this.routeDesigner.handleKeyDown);
+ window.addEventListener('keyup', this.routeDesigner.handleKeyUp);
+ const element = findDOMNode(this.routeDesigner.state.ref.current)?.parentElement?.parentElement;
+ const checkResize = (mutations: any) => {
+ const el = mutations[0].target;
+ const w = el.clientWidth;
+ const isChange = mutations.map((m: any) => `${m.oldValue}`).some((prev: any) => prev.indexOf(`width: ${w}px`) === -1);
+ if (isChange) this.routeDesigner.setState({key: Math.random().toString()});
+ }
+ if (element) {
+ const observer = new MutationObserver(checkResize);
+ observer.observe(element, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
+ }
+ this.commandSub = EventBus.onCommand()?.subscribe((command: Command) => this.onCommand(command));
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.routeDesigner.handleResize);
+ window.removeEventListener('keydown', this.routeDesigner.handleKeyDown);
+ window.removeEventListener('keyup', this.routeDesigner.handleKeyUp);
+ this.commandSub?.unsubscribe();
+ }
+
+ handleResize = (event: any) => {
+ this.routeDesigner.setState({key: Math.random().toString()});
+ }
+
+ handleKeyDown = (event: KeyboardEvent) => {
+ if ((event.shiftKey)) {
+ this.routeDesigner.setState({shiftKeyPressed: true});
+ }
+ if (window.document.hasFocus() && window.document.activeElement) {
+ if (['BODY', 'MAIN'].includes(window.document.activeElement.tagName)) {
+ let charCode = String.fromCharCode(event.which).toLowerCase();
+ if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
+ this.copyToClipboard();
+ } else if ((event.ctrlKey || event.metaKey) && charCode === 'v') {
+ this.pasteFromClipboard();
+ }
+ }
+ } else {
+ if (event.repeat) {
+ window.dispatchEvent(event);
+ }
+ }
+ }
+
+ handleKeyUp = (event: KeyboardEvent) => {
+ this.routeDesigner.setState({shiftKeyPressed: false});
+ if (event.repeat) {
+ window.dispatchEvent(event);
+ }
+ }
+
+ componentDidUpdate = (prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
+ if (prevState.key !== this.routeDesigner.state.key) {
+ this.routeDesigner.props.onSave?.call(this, this.routeDesigner.state.integration, this.routeDesigner.state.propertyOnly);
+ }
+ }
+
+ copyToClipboard = (): void => {
+ const {integration, selectedUuids} = this.routeDesigner.state;
+ const steps: CamelElement[] = []
+ selectedUuids.forEach(selectedUuid => {
+ const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
+ if (selectedElement) {
+ steps.push(selectedElement);
+ }
+ })
+ if (steps.length >0) {
+ this.routeDesigner.setState(prevState => ({
+ key: Math.random().toString(),
+ clipboardSteps: [...steps]
+ }));
+ }
+ }
+ pasteFromClipboard = (): void => {
+ const {integration, selectedUuids, clipboardSteps} = this.routeDesigner.state;
+ if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
+ const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+ const route = CamelDefinitionApi.createRouteDefinition({from: clone});
+ this.addStep(route, '', 0)
+ } else if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'RouteDefinition') {
+ const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+ this.addStep(clone, '', 0)
+ } else if (selectedUuids.length === 1) {
+ const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
+ clipboardSteps.reverse().forEach(clipboardStep => {
+ if (clipboardStep && targetMeta.parentUuid) {
+ const clone = CamelUtil.cloneStep(clipboardStep, true);
+ this.addStep(clone, targetMeta.parentUuid, targetMeta.position);
+ }
+ })
+ }
+ }
+
+ onCommand = (command: Command) => {
+ switch (command.command){
+ case "downloadImage": this.integrationImageDownload()
+ }
+ }
+
+ onPropertyUpdate = (element: CamelElement, newRoute?: RouteToCreate) => {
+ if (newRoute) {
+ let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.routeDesigner.state.integration, element);
+ const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName + ":" + newRoute.name})
+ const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
+ i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
+ const clone = CamelUtil.cloneIntegration(i);
+ this.routeDesigner.setState(prevState => ({
+ integration: clone,
+ key: Math.random().toString(),
+ showSelector: false,
+ selectedStep: element,
+ propertyOnly: false,
+ selectedUuids: [element.uuid]
+ }));
+ } else {
+ const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
+ const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
+ this.routeDesigner.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
+ }
+ }
+
+ showDeleteConfirmation = (id: string) => {
+ let message: string;
+ let ce: CamelElement;
+ let isRouteConfiguration: boolean = false;
+ ce = CamelDefinitionApiExt.findElementInIntegration(this.routeDesigner.state.integration, id)!;
+ if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this.routeDesigner. Use its uuid.
+ let flows = this.routeDesigner.state.integration.spec.flows!;
+ for (let i = 0; i < flows.length; i++) {
+ if (flows[i].dslName === 'RouteDefinition') {
+ let routeDefinition: RouteDefinition = flows[i];
+ if (routeDefinition.from.uuid === id) {
+ id = routeDefinition.uuid;
+ break;
+ }
+ }
+ }
+ message = 'Deleting the first element will delete the entire route!';
+ } else if (ce.dslName === 'RouteDefinition') {
+ message = 'Delete route?';
+ } else if (ce.dslName === 'RouteConfigurationDefinition') {
+ message = 'Delete route configuration?';
+ isRouteConfiguration = true;
+ } else {
+ message = 'Delete element from route?';
+ }
+ this.routeDesigner.setState(prevState => ({
+ showSelector: false,
+ showDeleteConfirmation: true,
+ deleteMessage: message,
+ selectedUuids: [id],
+ }));
+ }
+
+ deleteElement = () => {
+ const id = this.routeDesigner.state.selectedUuids.at(0);
+ if (id) {
+ const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.routeDesigner.state.integration, id);
+ this.routeDesigner.setState(prevState => ({
+ integration: i,
+ showSelector: false,
+ showDeleteConfirmation: false,
+ deleteMessage: '',
+ key: Math.random().toString(),
+ selectedStep: undefined,
+ propertyOnly: false,
+ selectedUuids: [id],
+ }));
+ const el = new CamelElement("");
+ el.uuid = id;
+ EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0);
+ }
+ }
+
+ selectElement = (element: CamelElement) => {
+ const {shiftKeyPressed, selectedUuids, integration} = this.routeDesigner.state;
+ let canNotAdd: boolean = false;
+ if (shiftKeyPressed) {
+ const hasFrom = selectedUuids.map(e => CamelDefinitionApiExt.findElementInIntegration(integration, e)?.dslName === 'FromDefinition').filter(r => r).length > 0;
+ canNotAdd = hasFrom || (selectedUuids.length > 0 && element.dslName === 'FromDefinition');
+ }
+ const add = shiftKeyPressed && !selectedUuids.includes(element.uuid);
+ const remove = shiftKeyPressed && selectedUuids.includes(element.uuid);
+ const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, element.uuid);
+ this.routeDesigner.setState((prevState: RouteDesignerState) => {
+ if (remove) {
+ const index = prevState.selectedUuids.indexOf(element.uuid);
+ prevState.selectedUuids.splice(index, 1);
+ } else if (add && !canNotAdd) {
+ prevState.selectedUuids.push(element.uuid);
+ }
+ const uuid: string = prevState.selectedUuids.includes(element.uuid) ? element.uuid : prevState.selectedUuids.at(0) || '';
+ const selectedElement = shiftKeyPressed ? CamelDefinitionApiExt.findElementInIntegration(integration, uuid) : element;
+ return {
+ integration: i,
+ selectedStep: selectedElement,
+ showSelector: false,
+ selectedUuids: shiftKeyPressed ? [...prevState.selectedUuids] : [element.uuid],
+ }
+ });
+ }
+
+ unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
+ if ((evt.target as any).dataset.click === 'FLOWS') {
+ evt.stopPropagation()
+ const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, undefined);
+ this.routeDesigner.setState(prevState => ({
+ integration: i,
+ selectedStep: undefined,
+ showSelector: false,
+ selectedPosition: undefined,
+ selectedUuids: [],
+ }));
+ }
+ }
+
+ openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
+ this.routeDesigner.setState({
+ showSelector: true,
+ parentId: parentId || '',
+ parentDsl: parentDsl,
+ showSteps: showSteps,
+ selectedPosition: position,
+ selectorTabIndex: selectorTabIndex
+ })
+ }
+
+ closeDslSelector = () => {
+ this.routeDesigner.setState({showSelector: false})
+ }
+
+ onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
+ switch (dsl.dsl) {
+ case 'FromDefinition' :
+ 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});
+ this.addStep(to, parentId, position)
+ break;
+ case 'ToDynamicDefinition' :
+ const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
+ this.addStep(toD, parentId, position)
+ break;
+ case 'KameletDefinition' :
+ const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: dsl.name});
+ this.addStep(kamelet, parentId, position)
+ break;
+ default:
+ const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
+ this.addStep(step, parentId, position)
+ break;
+ }
+ }
+
+ createRouteConfiguration = () => {
+ const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
+ const routeConfiguration = new RouteConfigurationDefinition();
+ const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
+ this.routeDesigner.setState(prevState => ({
+ integration: i,
+ propertyOnly: false,
+ key: Math.random().toString(),
+ selectedStep: routeConfiguration,
+ selectedUuids: [routeConfiguration.uuid],
+ }));
+ }
+
+ addStep = (step: CamelElement, parentId: string, position?: number | undefined) => {
+ const i = CamelDefinitionApiExt.addStepToIntegration(this.routeDesigner.state.integration, step, parentId, position);
+ const clone = CamelUtil.cloneIntegration(i);
+ EventBus.sendPosition("clean", step, undefined, new DOMRect(), new DOMRect(), 0);
+ this.routeDesigner.setState(prevState => ({
+ integration: clone,
+ key: Math.random().toString(),
+ showSelector: false,
+ selectedStep: step,
+ propertyOnly: false,
+ selectedUuids: [step.uuid],
+ }));
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.routeDesigner.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
+ }
+
+ moveElement = (source: string, target: string, asChild: boolean) => {
+ const i = CamelDefinitionApiExt.moveRouteElement(this.routeDesigner.state.integration, source, target, asChild);
+ const clone = CamelUtil.cloneIntegration(i);
+ const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
+ this.routeDesigner.setState(prevState => ({
+ integration: clone,
+ key: Math.random().toString(),
+ showSelector: false,
+ selectedStep: selectedStep,
+ propertyOnly: false,
+ selectedUuids: [source],
+ }));
+ }
+
+ onResizePage(el: HTMLDivElement | null) {
+ const rect = el?.getBoundingClientRect();
+ if (el && rect && (el.scrollWidth !== this.routeDesigner.state.width || el.scrollHeight !== this.routeDesigner.state.height || rect.top !== this.routeDesigner.state.top || rect.left !== this.routeDesigner.state.left)) {
+ this.routeDesigner.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
+ }
+ }
+
+ downloadIntegrationImage(dataUrl: string) {
+ const a = document.createElement('a');
+ a.setAttribute('download', 'karavan-routes.png');
+ a.setAttribute('href', dataUrl);
+ a.click();
+ }
+
+ integrationImageDownloadFilter = (node: HTMLElement) => {
+ const exclusionClasses = ['add-flow'];
+ return !exclusionClasses.some(classname => {
+ return node.classList === undefined ? false : node.classList.contains(classname);
+ });
+ }
+
+ integrationImageDownload() {
+ if (this.routeDesigner.state.printerRef.current === null) {
+ return
+ }
+ toPng(this.routeDesigner.state.printerRef.current, {
+ style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter,
+ height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
+ }).then(v => {
+ toPng(this.routeDesigner.state.printerRef.current, {
+ style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter,
+ height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
+ }).then(this.downloadIntegrationImage);
+ })
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/designer/utils/EventBus.ts b/karavan-app/src/main/webui/src/designer/utils/EventBus.ts
index 2df867f4..aeae6ff7 100644
--- a/karavan-app/src/main/webui/src/designer/utils/EventBus.ts
+++ b/karavan-app/src/main/webui/src/designer/utils/EventBus.ts
@@ -48,6 +48,17 @@ export class DslPosition {
}
}
+const commands = new Subject<Command>();
+export class Command {
+ command: string;
+ data: any;
+
+ constructor(command: string, data: any) {
+ this.command = command;
+ this.data = data;
+ }
+}
+
export const EventBus = {
sendPosition: (command: "add" | "delete" | "clean",
step: CamelElement,
@@ -58,4 +69,7 @@ export const EventBus = {
inSteps: boolean = false,
isSelected: boolean = false) => positions.next(new DslPosition(command, step, parent, rect, headerRect, position, inSteps, isSelected)),
onPosition: () => positions.asObservable(),
+
+ sendCommand: (command: string, data?: any) => commands.next(new Command(command, data)),
+ onCommand: () => commands.asObservable(),
}