This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push: new aed9731c Implement #622 aed9731c is described below commit aed9731c0fa71bea2f96a4fc13ceb9bb3fc394f7 Author: Marat Gubaidullin <marat.gubaidul...@gmail.com> AuthorDate: Fri Jan 20 17:30:53 2023 -0500 Implement #622 --- .../src/main/resources/application.properties | 2 +- karavan-app/src/main/webui/package-lock.json | 43 +++-- .../configuration/RouteConfigurationCard.tsx | 58 ------- .../configuration/RouteConfigurationDesigner.tsx | 174 --------------------- .../main/webui/src/designer/rest/RestDesigner.tsx | 1 - .../webui/src/designer/route/DslConnections.tsx | 8 +- .../main/webui/src/designer/route/DslElement.tsx | 17 +- .../webui/src/designer/route/DslProperties.tsx | 19 --- .../webui/src/designer/route/RouteDesigner.tsx | 163 +++++++++++++------ .../src/main/webui/src/designer/utils/EventBus.ts | 6 +- .../main/webui/src/projects/CreateFileModal.tsx | 2 - 11 files changed, 175 insertions(+), 318 deletions(-) diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties index d3413d23..d5bf15b9 100644 --- a/karavan-app/src/main/resources/application.properties +++ b/karavan-app/src/main/resources/application.properties @@ -92,7 +92,7 @@ quarkus.kubernetes-client.request-timeout=10000 quarkus.swagger-ui.always-include=true quarkus.quinoa.frozen-lockfile=false -quarkus.quinoa.package-manager-install=true +quarkus.quinoa.package-manager-install=false quarkus.quinoa.package-manager-install.node-version=18.12.1 quarkus.quinoa.dev-server.port=3000 quarkus.quinoa.dev-server.check-timeout=60000 \ No newline at end of file diff --git a/karavan-app/src/main/webui/package-lock.json b/karavan-app/src/main/webui/package-lock.json index 4122dfc4..65dcddc8 100644 --- a/karavan-app/src/main/webui/package-lock.json +++ b/karavan-app/src/main/webui/package-lock.json @@ -39,6 +39,27 @@ "monaco-editor": "0.29.1" } }, + "../../../../karavan-core": { + "version": "3.18.6", + "license": "Apache-2.0", + "dependencies": { + "@types/js-yaml": "^4.0.5", + "@types/uuid": "^8.3.4", + "typescript": "^4.9.4", + "uuid": "8.3.2" + }, + "devDependencies": { + "@types/chai": "^4.3.0", + "@types/dagre": "^0.7.47", + "@types/mocha": "^9.1.0", + "@types/node": "^18.11.18", + "chai": "^4.3.4", + "cross-env": "^7.0.3", + "fs": "^0.0.1-security", + "mocha": "^9.2.0", + "ts-node": "^10.4.0" + } + }, "../karavan-core": { "extraneous": true }, @@ -10837,15 +10858,8 @@ } }, "node_modules/karavan-core": { - "version": "3.18.6", - "resolved": "file:../../../../karavan-core", - "license": "Apache-2.0", - "dependencies": { - "@types/js-yaml": "^4.0.5", - "@types/uuid": "^8.3.4", - "typescript": "^4.9.4", - "uuid": "8.3.2" - } + "resolved": "../../../../karavan-core", + "link": true }, "node_modules/keycloak-js": { "version": "19.0.1", @@ -24308,10 +24322,19 @@ } }, "karavan-core": { - "version": "3.18.6", + "version": "file:../../../../karavan-core", "requires": { + "@types/chai": "^4.3.0", + "@types/dagre": "^0.7.47", "@types/js-yaml": "^4.0.5", + "@types/mocha": "^9.1.0", + "@types/node": "^18.11.18", "@types/uuid": "^8.3.4", + "chai": "^4.3.4", + "cross-env": "^7.0.3", + "fs": "^0.0.1-security", + "mocha": "^9.2.0", + "ts-node": "^10.4.0", "typescript": "^4.9.4", "uuid": "8.3.2" } diff --git a/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationCard.tsx b/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationCard.tsx deleted file mode 100644 index 7b069e3c..00000000 --- a/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationCard.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { - Button -} from '@patternfly/react-core'; -import '../karavan.css'; -import {RouteConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition"; -import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon"; -import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; - -interface Props { - routeConfiguration: RouteConfigurationDefinition - selectedStep?: CamelElement - deleteElement: (element: RouteConfigurationDefinition) => void - selectElement: (element: RouteConfigurationDefinition) => void -} - -export class RouteConfigurationCard extends React.Component<Props, any> { - - selectElement = (evt: React.MouseEvent) => { - evt.stopPropagation(); - this.props.selectElement.call(this, this.props.routeConfiguration); - } - - delete = (evt: React.MouseEvent) => { - evt.stopPropagation(); - this.props.deleteElement.call(this, this.props.routeConfiguration); - } - - render() { - const {selectedStep, routeConfiguration} = this.props; - return ( - <div className={selectedStep?.uuid === routeConfiguration.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"} - onClick={e => this.selectElement(e)}> - <div className="header"> - <div className="title">Route Configuration</div> - <div className="description">Route Configuration</div> - <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button> - </div> - </div> - ); - } -} diff --git a/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationDesigner.tsx b/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationDesigner.tsx deleted file mode 100644 index d7fdb61a..00000000 --- a/karavan-app/src/main/webui/src/designer/configuration/RouteConfigurationDesigner.tsx +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { - Button, Drawer, DrawerContent, DrawerContentBody, DrawerPanelContent, Modal, PageSection -} from '@patternfly/react-core'; -import '../karavan.css'; -import {RouteConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition"; -import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition"; -import {CamelUi} from "../utils/CamelUi"; -import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon"; -import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; -import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; -import {RouteConfigurationCard} from "./RouteConfigurationCard"; -import {DslProperties} from "../route/DslProperties"; - -interface Props { - onSave?: (integration: Integration, propertyOnly: boolean) => void - integration: Integration - dark: boolean -} - -interface State { - integration: Integration - showDeleteConfirmation: boolean - routeConfigurations: RouteConfigurationDefinition[] - selectedRouteConfiguration?: RouteConfigurationDefinition - key: string - propertyOnly: boolean -} - -export class RouteConfigurationDesigner extends React.Component<Props, State> { - - public state: State = { - integration: this.props.integration, - routeConfigurations: [], - showDeleteConfirmation: false, - key: "", - propertyOnly: false - } - - componentDidMount() { - this.setState({key: Math.random().toString()}) - } - - componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => { - if (prevState.key !== this.state.key) { - this.props.onSave?.call(this, this.state.integration, this.state.propertyOnly); - } - } - - showDeleteConfirmation = (routeConfiguration: RouteConfigurationDefinition) => { - this.setState({selectedRouteConfiguration: routeConfiguration, showDeleteConfirmation: true}); - } - - onIntegrationUpdate = (i: Integration) => { - this.setState({integration: i, propertyOnly: false, showDeleteConfirmation: false, key: Math.random().toString()}); - } - - deleteRouteConfiguration = () => { - const {selectedRouteConfiguration} = this.state; - if (selectedRouteConfiguration) { - const i = CamelDefinitionApiExt.deleteRouteConfigurationFromIntegration(this.state.integration, selectedRouteConfiguration); - this.setState({ - integration: i, - showDeleteConfirmation: false, - key: Math.random().toString(), - selectedRouteConfiguration: undefined, - propertyOnly: false - }); - } - } - - getDeleteConfirmation() { - return (<Modal - className="modal-delete" - title="Confirmation" - isOpen={this.state.showDeleteConfirmation} - onClose={() => this.setState({showDeleteConfirmation: false})} - actions={[ - <Button key="confirm" variant="primary" onClick={e => this.deleteRouteConfiguration()}>Delete</Button>, - <Button key="cancel" variant="link" - onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button> - ]} - onEscapePress={e => this.setState({showDeleteConfirmation: false})}> - <div> - Delete Route Configuration from integration? - </div> - </Modal>) - } - - createRouteConfiguration = () => { - const clone = CamelUtil.cloneIntegration(this.state.integration); - const routeConfiguration = new RouteConfigurationDefinition(); - const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration); - this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), selectedRouteConfiguration: routeConfiguration}); - } - - selectRouteConfiguration = (element: RouteConfigurationDefinition) => { - this.setState({selectedRouteConfiguration: element}) - } - - onPropertyUpdate = (element: CamelElement) => { - const clone = CamelUtil.cloneIntegration(this.state.integration); - const i = CamelDefinitionApiExt.updateRouteConfigurationToIntegration(clone, element); - this.setState({integration: i, propertyOnly: true, key: Math.random().toString()}); - } - - getPropertiesPanel() { - return ( - <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'} maxSize={'800px'} minSize={'300px'}> - <DslProperties - integration={this.props.integration} - step={this.state.selectedRouteConfiguration} - onIntegrationUpdate={this.onIntegrationUpdate} - onPropertyUpdate={this.onPropertyUpdate} - clipboardStep={undefined} - isRouteDesigner={false} - onClone={element => {}} - dark={this.props.dark}/> - </DrawerPanelContent> - ) - } - - render() { - const routeConfigurations = CamelUi.getRouteConfigurations(this.state.integration); - return ( - <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}> - <div className="rest-page-columns"> - <Drawer isExpanded isInline> - <DrawerContent panelContent={this.getPropertiesPanel()}> - <DrawerContentBody> - <div className="graph" data-click="REST"> - <div className="flows"> - {routeConfigurations?.map(routeConfiguration => - <RouteConfigurationCard key={routeConfiguration.uuid + this.state.key} - routeConfiguration={routeConfiguration} - selectedStep={this.state.selectedRouteConfiguration} - selectElement={this.selectRouteConfiguration} - deleteElement={this.showDeleteConfirmation}/> - )} - <div className="add-rest"> - <Button - variant="primary" - data-click="ADD_REST" - icon={<PlusIcon/>} - onClick={e => this.createRouteConfiguration()}>Create new configuration - </Button> - </div> - </div> - </div> - </DrawerContentBody> - </DrawerContent> - </Drawer> - </div> - {this.getDeleteConfirmation()} - </PageSection> - ) - } -} diff --git a/karavan-app/src/main/webui/src/designer/rest/RestDesigner.tsx b/karavan-app/src/main/webui/src/designer/rest/RestDesigner.tsx index f91c5129..d13d07e6 100644 --- a/karavan-app/src/main/webui/src/designer/rest/RestDesigner.tsx +++ b/karavan-app/src/main/webui/src/designer/rest/RestDesigner.tsx @@ -240,7 +240,6 @@ export class RestDesigner extends React.Component<Props, State> { step={this.state.selectedStep} onIntegrationUpdate={this.onIntegrationUpdate} onPropertyUpdate={this.onPropertyUpdate} - clipboardStep={undefined} isRouteDesigner={false} onClone={this.cloneRest} dark={this.props.dark}/> diff --git a/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx b/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx index 0806761e..6dc1ced3 100644 --- a/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx +++ b/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx @@ -57,12 +57,18 @@ export class DslConnections extends React.Component<Props, State> { } setPosition(evt: DslPosition) { - if (evt.command === "add") this.setState(prevState => ({steps: prevState.steps.set(evt.step.uuid, evt)})); + if (evt.command === "add") { + this.setState(prevState => ({steps: prevState.steps.set(evt.step.uuid, evt)})); + } else if (evt.command === "delete") this.setState(prevState => { // prevState.steps.clear(); prevState.steps.delete(evt.step.uuid); return {steps: prevState.steps}; }); + else if (evt.command === "clean") this.setState(prevState => { + prevState.steps.clear(); + return {steps: prevState.steps}; + }); } getIncomings() { diff --git a/karavan-app/src/main/webui/src/designer/route/DslElement.tsx b/karavan-app/src/main/webui/src/designer/route/DslElement.tsx index 868f3e2c..07222d84 100644 --- a/karavan-app/src/main/webui/src/designer/route/DslElement.tsx +++ b/karavan-app/src/main/webui/src/designer/route/DslElement.tsx @@ -65,9 +65,22 @@ export class DslElement extends React.Component<Props, State> { tabIndex: 0, selectedUuid: this.props.selectedUuid, isDragging: false, - isDraggedOver: false + isDraggedOver: false, }; + handleKeyDown = (event: React.KeyboardEvent) =>{ + // event.preventDefault(); + // console.log(event); + // let charCode = String.fromCharCode(event.which).toLowerCase(); + // if((event.ctrlKey || event.metaKey) && charCode === 's') { + // alert("CTRL+S Pressed"); + // }else if((event.ctrlKey || event.metaKey) && charCode === 'c') { + // alert("CTRL+C Pressed"); + // }else if((event.ctrlKey || event.metaKey) && charCode === 'v') { + // alert("CTRL+V Pressed"); + // } + } + componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => { if (prevState.selectedUuid !== this.props.selectedUuid) { this.setState({selectedUuid: this.props.selectedUuid}); @@ -484,6 +497,8 @@ export class DslElement extends React.Component<Props, State> { }} onDrop={event => this.dragElement(event, element)} draggable={!this.isNotDraggable()} + // tabIndex={0} + onKeyDown={this.handleKeyDown} > {this.getElementHeader()} {this.getChildElements()} diff --git a/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx b/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx index 0359bb36..f0000bc1 100644 --- a/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx +++ b/karavan-app/src/main/webui/src/designer/route/DslProperties.tsx @@ -36,8 +36,6 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; import {CamelUi, RouteToCreate} from "../utils/CamelUi"; import {CamelMetadataApi, PropertyMeta} from "karavan-core/lib/model/CamelMetadata"; import {IntegrationHeader} from "../utils/KaravanComponents"; -import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon' -import PasteIcon from '@patternfly/react-icons/dist/esm/icons/paste-icon' import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon"; interface Props { @@ -45,8 +43,6 @@ interface Props { step?: CamelElement, onIntegrationUpdate?: any, onPropertyUpdate?: (element: CamelElement, newRoute?: RouteToCreate) => void - clipboardStep?: CamelElement - onSaveClipboardStep?: (element?: CamelElement) => void onClone?: (element: CamelElement) => void isRouteDesigner: boolean dark: boolean @@ -76,15 +72,6 @@ export class DslProperties extends React.Component<Props, State> { } } - pasteClipboardStep = () => { - if (this.props.clipboardStep && this.state.step) { - const clone = CamelUtil.cloneStep(this.props.clipboardStep); - clone.uuid = this.state.step.uuid; - this.setStep(clone) - this.props.onPropertyUpdate?.call(this, clone); - } - } - dataFormatChanged = (value: DataFormatDefinition) => { value.uuid = this.state.step?.uuid ? this.state.step?.uuid : value.uuid; this.setStep(value); @@ -144,12 +131,6 @@ export class DslProperties extends React.Component<Props, State> { <div className="headers"> <div className="top"> <Title headingLevel="h1" size="md">{title}</Title> - <Tooltip content="Copy step" position="bottom"> - <Button variant="link" onClick={() => this.props.onSaveClipboardStep?.call(this, this.state.step)} icon={<CopyIcon/>}/> - </Tooltip> - <Tooltip content="Paste step" position="bottom"> - <Button variant="link" onClick={() => this.pasteClipboardStep()} icon={<PasteIcon/>}/> - </Tooltip> </div> <Text component={TextVariants.p}>{descriptionLines.at(0)}</Text> {descriptionLines.length > 1 && <ExpandableSection toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'} diff --git a/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx b/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx index 949295ea..87584dc1 100644 --- a/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx +++ b/karavan-app/src/main/webui/src/designer/route/RouteDesigner.tsx @@ -57,13 +57,14 @@ interface State { parentDsl?: string selectedPosition?: number showSteps: boolean - selectedUuid: string + selectedUuid: string [] key: string width: number height: number top: number left: number clipboardStep?: CamelElement + shiftKeyPressed?: boolean ref?: any printerRef?: any propertyOnly: boolean @@ -79,7 +80,7 @@ export class RouteDesigner extends React.Component<Props, State> { deleteMessage: '', parentId: '', showSteps: true, - selectedUuid: '', + selectedUuid: [], key: "", width: 1000, height: 1000, @@ -92,6 +93,8 @@ 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; @@ -107,12 +110,54 @@ export class RouteDesigner extends React.Component<Props, State> { componentWillUnmount() { window.removeEventListener('resize', this.handleResize); + window.removeEventListener('keydown', this.handleKeyDown); + window.removeEventListener('keyup', this.handleKeyUp); } handleResize = (event: any) => { this.setState({key: Math.random().toString()}); } + 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); + } + } + } + + handleKeyUp = (event: KeyboardEvent) => { + this.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); @@ -130,14 +175,14 @@ export class RouteDesigner extends React.Component<Props, State> { const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name}) i = CamelDefinitionApiExt.addStepToIntegration(i, r, ''); const clone = CamelUtil.cloneIntegration(i); - this.setState({ + this.setState(prevState => ({ integration: clone, key: Math.random().toString(), showSelector: false, selectedStep: element, - selectedUuid: element.uuid, - propertyOnly: false - }); + propertyOnly: false, + selectedUuid: [element.uuid], + })); } else { const clone = CamelUtil.cloneIntegration(this.state.integration); const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element); @@ -170,37 +215,56 @@ export class RouteDesigner extends React.Component<Props, State> { } else { message = 'Delete element from route?'; } - this.setState({selectedUuid: id, showSelector: false, showDeleteConfirmation: true, deleteMessage: message}); + this.setState(prevState => ({ + showSelector: false, + showDeleteConfirmation: true, + deleteMessage: message, + selectedUuid: [id], + })); } deleteElement = () => { - const id = this.state.selectedUuid; - const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id); - this.setState({ - integration: i, - showSelector: false, - showDeleteConfirmation: false, - deleteMessage: '', - key: Math.random().toString(), - selectedStep: undefined, - selectedUuid: '', - propertyOnly: false - }); - const el = new CamelElement(""); - el.uuid = id; - EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0); + 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({integration: i, selectedStep: element, selectedUuid: element.uuid, showSelector: false}) + 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({integration: i, selectedStep: undefined, selectedUuid: '', showSelector: false, selectedPosition: undefined}) + this.setState(prevState => ({ + integration: i, + selectedStep: undefined, + showSelector: false, + selectedPosition: undefined, + selectedUuid: [], + })); } } @@ -222,8 +286,8 @@ export class RouteDesigner extends React.Component<Props, State> { onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => { switch (dsl.dsl) { case 'FromDefinition' : - const from = CamelDefinitionApi.createRouteDefinition({from: new FromDefinition({uri: dsl.uri})}); - this.addStep(from, parentId, position) + const route = CamelDefinitionApi.createRouteDefinition({from: new FromDefinition({uri: dsl.uri})}); + this.addStep(route, parentId, position) break; case 'ToDefinition' : const to = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri}); @@ -248,26 +312,27 @@ export class RouteDesigner extends React.Component<Props, State> { const clone = CamelUtil.cloneIntegration(this.state.integration); const routeConfiguration = new RouteConfigurationDefinition(); const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration); - this.setState({ + this.setState(prevState => ({ integration: i, propertyOnly: false, key: Math.random().toString(), selectedStep: routeConfiguration, - selectedUuid: routeConfiguration.uuid, - }); + 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); - this.setState({ + EventBus.sendPosition("clean", step, undefined, new DOMRect(), new DOMRect(), 0); + this.setState(prevState => ({ integration: clone, key: Math.random().toString(), showSelector: false, selectedStep: step, - selectedUuid: step.uuid, - propertyOnly: false - }); + propertyOnly: false, + selectedUuid: [step.uuid], + })); } onIntegrationUpdate = (i: Integration) => { @@ -278,14 +343,14 @@ export class RouteDesigner extends React.Component<Props, State> { const i = CamelDefinitionApiExt.moveRouteElement(this.state.integration, source, target, asChild); const clone = CamelUtil.cloneIntegration(i); const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source); - this.setState({ + this.setState(prevState => ({ integration: clone, key: Math.random().toString(), showSelector: false, selectedStep: selectedStep, - selectedUuid: source, - propertyOnly: false - }); + propertyOnly: false, + selectedUuid: [source], + })); } onResizePage(el: HTMLDivElement | null) { @@ -338,9 +403,7 @@ export class RouteDesigner extends React.Component<Props, State> { step={this.state.selectedStep} onIntegrationUpdate={this.onIntegrationUpdate} onPropertyUpdate={this.onPropertyUpdate} - clipboardStep={this.state.clipboardStep} isRouteDesigner={true} - onSaveClipboardStep={this.saveToClipboard} dark={this.props.dark}/> </DrawerPanelContent> ) @@ -356,7 +419,7 @@ export class RouteDesigner extends React.Component<Props, State> { integrationImageDownloadFilter = (node: HTMLElement) => { const exclusionClasses = ['add-flow']; return !exclusionClasses.some(classname => { - return node.classList === undefined ? false: node.classList.contains(classname); + return node.classList === undefined ? false : node.classList.contains(classname); }); } @@ -364,11 +427,15 @@ export class RouteDesigner extends React.Component<Props, State> { if (this.state.printerRef.current === null) { return } - toPng(this.state.printerRef.current, { style:{overflow:'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter, - height:this.state.height,width:this.state.width, backgroundColor: this.props.dark?"black":"white" }).then(v => { - toPng(this.state.printerRef.current, { style:{overflow:'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter, - height:this.state.height,width:this.state.width, backgroundColor: this.props.dark?"black":"white" }).then(this.downloadIntegrationImage); - }) + toPng(this.state.printerRef.current, { + style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter, + height: this.state.height, width: this.state.width, backgroundColor: this.props.dark ? "black" : "white" + }).then(v => { + toPng(this.state.printerRef.current, { + style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter, + height: this.state.height, width: this.state.width, backgroundColor: this.props.dark ? "black" : "white" + }).then(this.downloadIntegrationImage); + }) } getGraph() { @@ -380,14 +447,14 @@ export class RouteDesigner extends React.Component<Props, State> { <DslConnections height={height} width={width} top={top} left={left} integration={integration}/> <div className="flows" data-click="FLOWS" onClick={event => this.unselectElement(event)} ref={el => this.onResizePage(el)}> - {routeConfigurations?.map((routeConfiguration , index: number) => ( + {routeConfigurations?.map((routeConfiguration, index: number) => ( <DslElement key={routeConfiguration.uuid + key} integration={integration} openSelector={this.openSelector} deleteElement={this.showDeleteConfirmation} selectElement={this.selectElement} moveElement={this.moveElement} - selectedUuid={selectedUuid} + selectedUuid={selectedUuid.at(0) || ''} inSteps={false} position={index} step={routeConfiguration} @@ -400,7 +467,7 @@ export class RouteDesigner extends React.Component<Props, State> { deleteElement={this.showDeleteConfirmation} selectElement={this.selectElement} moveElement={this.moveElement} - selectedUuid={selectedUuid} + selectedUuid={selectedUuid.at(0) || ''} inSteps={false} position={index} step={route} 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 98e573d7..2df867f4 100644 --- a/karavan-app/src/main/webui/src/designer/utils/EventBus.ts +++ b/karavan-app/src/main/webui/src/designer/utils/EventBus.ts @@ -27,9 +27,9 @@ export class DslPosition { position: number = 0; rect: DOMRect = new DOMRect(); headerRect: DOMRect = new DOMRect(); - command: "add" | "delete" = "add"; + command: "add" | "delete" | "clean" = "add"; - constructor(command: "add" | "delete", + constructor(command: "add" | "delete" | "clean", step: CamelElement, parent:CamelElement | undefined, rect: DOMRect, @@ -49,7 +49,7 @@ export class DslPosition { } export const EventBus = { - sendPosition: (command: "add" | "delete", + sendPosition: (command: "add" | "delete" | "clean", step: CamelElement, parent: CamelElement | undefined, rect: DOMRect, diff --git a/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx b/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx index 9101d9ac..90183a0f 100644 --- a/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx +++ b/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx @@ -61,8 +61,6 @@ export class CreateFileModal extends React.Component<Props, State> { render() { const {fileType} = this.state; const {types} = this.props; - console.log(fileType) - console.log(types) const extension = ProjectFileTypes.filter(value => value.name === fileType)[0].extension; const filename = (extension !== 'java') ? CamelUi.nameFromTitle(this.state.name)