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 9d503ba51812e6b5e702172fd08b355005326749 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Wed Dec 6 20:35:19 2023 -0500 Preview fixes of new Designer --- karavan-designer/public/example/demo.camel.yaml | 26 +++- karavan-designer/src/designer/DesignerStore.ts | 31 ++-- .../src/designer/route/DslConnections.tsx | 170 ++++++++++++--------- .../src/designer/route/RouteDesigner.tsx | 6 +- .../src/designer/route/element/DslElement.css | 19 +-- .../src/designer/route/element/DslElement.tsx | 55 ++----- .../designer/route/element/DslElementHeader.tsx | 42 +---- .../src/designer/route/useRouteDesignerHook.tsx | 2 +- karavan-designer/src/designer/utils/EventBus.ts | 11 +- 9 files changed, 175 insertions(+), 187 deletions(-) diff --git a/karavan-designer/public/example/demo.camel.yaml b/karavan-designer/public/example/demo.camel.yaml index ccd98241..1bc2b8ae 100644 --- a/karavan-designer/public/example/demo.camel.yaml +++ b/karavan-designer/public/example/demo.camel.yaml @@ -25,6 +25,15 @@ - to: uri: amqp id: to-fbfe + - choice: + when: + - expression: + simple: + id: simple-e78b + id: when-b7d0 + otherwise: + id: otherwise-40d0 + id: choice-8f6b otherwise: id: otherwise-382c steps: @@ -38,12 +47,6 @@ - to: uri: kamelet:azure-cosmosdb-sink id: to-1394 -- route: - nodePrefixId: route-d10 - id: route-3ad9 - from: - uri: kamelet:azure-storage-datalake-source - id: from-1516 - route: nodePrefixId: route-171 id: route-99f9 @@ -85,6 +88,15 @@ - log: message: ${body} id: log-77df + - choice: + when: + - expression: + simple: + id: simple-c7db + id: when-f058 + otherwise: + id: otherwise-1e11 + id: choice-8374 - wireTap: id: wireTap-a25e doFinally: @@ -113,5 +125,7 @@ simple: id: simple-f0dc id: setBody-3c0c + - process: + id: process-6d06 - circuitBreaker: id: circuitBreaker-4af8 diff --git a/karavan-designer/src/designer/DesignerStore.ts b/karavan-designer/src/designer/DesignerStore.ts index f9bc38d1..815f0f68 100644 --- a/karavan-designer/src/designer/DesignerStore.ts +++ b/karavan-designer/src/designer/DesignerStore.ts @@ -120,9 +120,9 @@ interface ConnectionsState { deleteStep: (uuid: string) => void; clearSteps: () => void; setSteps: (steps: Map<string, DslPosition>) => void; - buttons: ButtonPosition[]; - addButton: (button: ButtonPosition) => void; - deleteButton: (button: ButtonPosition) => void; + buttons: Map<string, ButtonPosition>; + addButton: (uuid: string, button: ButtonPosition) => void; + deleteButton: (uuid: string) => void; clearButtons: () => void; } @@ -152,27 +152,24 @@ export const useConnectionsStore = createWithEqualityFn<ConnectionsState>((set) setSteps: (steps: Map<string, DslPosition>) => { set({steps: steps}) }, - buttons: [], - addButton: (button: ButtonPosition) => { - set((state: ConnectionsState) => { - const index = state.buttons.findIndex(b => b.uuid === button.uuid); - if (index !== -1) { - state.buttons.splice(index, 1); - } - state.buttons.push(button); - return state; - }) + buttons: new Map<string, ButtonPosition>(), + addButton: (uuid: string, button: ButtonPosition) => { + set(state => ({ + buttons: new Map(state.buttons).set(uuid, button), + })) }, clearButtons: () => { set((state: ConnectionsState) => { - state.buttons.length = 0; + state.buttons.clear(); return state; }) }, - deleteButton: (button: ButtonPosition) => { + deleteButton: (uuid: string) => { set((state: ConnectionsState) => { - const index = state.buttons.findIndex(b => b.uuid === button.uuid); - state.buttons.splice(index, 1); + Array.from(state.buttons.entries()) + .filter(value => value[1].uuid !== uuid) + .forEach(value => state.buttons.set(value[0], value[1])); + state.buttons.delete(uuid) return state; }) }, diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx index a4eef251..934fd89c 100644 --- a/karavan-designer/src/designer/route/DslConnections.tsx +++ b/karavan-designer/src/designer/route/DslConnections.tsx @@ -14,15 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {useEffect} from 'react'; +import React, {JSX, useEffect} from 'react'; import '../karavan.css'; -import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; import {ButtonPosition, DslPosition, EventBus} from "../utils/EventBus"; import {CamelUi} from "../utils/CamelUi"; import {useConnectionsStore, useDesignerStore, useIntegrationStore} from "../DesignerStore"; import {shallow} from "zustand/shallow"; import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; +import {CamelElement} from "../../../../karavan-core/lib/model/IntegrationDefinition"; const overlapGap: number = 40; @@ -45,15 +45,17 @@ export function DslConnections() { }); useEffect(() => { - const toDelete: string[] = Array.from(steps.keys()).filter(k => CamelDefinitionApiExt.findElementInIntegration(integration, k) === undefined); - toDelete.forEach(key => deleteStep(key)); + const toDelete1: string[] = Array.from(steps.keys()).filter(k => CamelDefinitionApiExt.findElementInIntegration(integration, k) === undefined); + toDelete1.forEach(key => deleteStep(key)); + const toDelete2: string[] = Array.from(buttons.keys()).filter(k => CamelDefinitionApiExt.findElementInIntegration(integration, k) === undefined); + toDelete2.forEach(key => deleteButton(key)); }, [integration]); function setButtonPosition(btn: ButtonPosition) { if (btn.command === "add") { - addButton(btn); + addButton(btn.uuid, btn); } else if (btn.command === "delete") { - deleteButton(btn); + deleteButton(btn.uuid); } else if (btn.command === "clean") { clearButtons(); } @@ -103,8 +105,6 @@ export function DslConnections() { return ( <g key={pos.step.uuid + "-incoming"}> <circle cx={incomingX} cy={fromY} r={r} className="circle-incoming"/> - {/*<image x={imageX} y={imageY} href={CamelUi.getConnectionIconString(pos.step)} className="icon"/>*/} - {/*<text x={imageX - 5} y={imageY + 40} className="caption" textAnchor="start">{CamelUi.getTitle(pos.step)}</text>*/} <path d={`M ${lineX1},${lineY1} C ${lineX1},${lineY2} ${lineX2},${lineY1} ${lineX2},${lineY2}`} className="path-incoming" markerEnd="url(#arrowhead)"/> </g> @@ -189,8 +189,6 @@ export function DslConnections() { return ( <g key={pos.step.uuid + "-outgoing"}> <circle cx={outgoingX} cy={outgoingY} r={r} className="circle-outgoing"/> - {/*<image x={imageX} y={imageY} href={image} className="icon"/>*/} - {/*<text x={imageX + 25} y={imageY + 40} className="caption" textAnchor="end">{CamelUi.getOutgoingTitle(pos.step)}</text>*/} <path d={`M ${lineX1},${lineY1} C ${lineXi - 20}, ${lineY1} ${lineX1 - 15},${lineYi} ${lineXi},${lineYi} L ${lineX2},${lineY2}`} className="path-incoming" markerEnd="url(#arrowhead)"/> @@ -226,79 +224,105 @@ export function DslConnections() { ) } - function hasSteps(step: CamelElement): boolean { - return (step.hasSteps() && !['FromDefinition'].includes(step.dslName)) - || ['RouteDefinition', 'TryDefinition', 'ChoiceDefinition', 'SwitchDefinition'].includes(step.dslName); + function getNext(pos: DslPosition): CamelElement | undefined { + if (pos.nextstep) { + return pos.nextstep; + } else if (pos.parent) { + const parent = steps.get(pos.parent.uuid); + if (parent) return getNext(parent); + } + } + + function isSpecial(pos: DslPosition): boolean { + return ['ChoiceDefinition', 'MulticastDefinition', 'TryDefinition'].includes(pos.step.dslName); } - function getPreviousStep(pos: DslPosition) { - return Array.from(steps.values()) - .filter(p => pos.parent?.uuid === p.parent?.uuid) - .filter(p => p.inSteps) - .filter(p => p.position === pos.position - 1)[0]; + function addArrowToList(list: JSX.Element[], from?: DslPosition, to?: DslPosition, fromHeader?: boolean, toHeader?: boolean): JSX.Element[] { + const result: JSX.Element[] = [...list]; + if (from && to) { + const rect1 = fromHeader === true ? from.headerRect : from.rect; + const rect2 = toHeader === true ? to.headerRect : to.rect; + result.push(getComplexArrow(from.step.uuid + "->" + to.step.uuid, rect1, rect2, toHeader === true)); + } + return result; } - function getArrow(pos: DslPosition) { - const endX = pos.headerRect.x + pos.headerRect.width / 2 - left; - const endY = pos.headerRect.y - 9 - top; - if (pos.parent) { + function getArrow(pos: DslPosition): JSX.Element[] { + const list: JSX.Element[] = []; + + if (pos.parent && pos.parent.dslName === 'FromDefinition' && pos.position === 0) { + // const parent = steps.get(pos.parent.uuid); + // list.push(...addArrowToList(list, parent, pos, true, false)) + } else if (pos.parent && pos.parent.dslName === 'TryDefinition' && pos.position === 0) { + const parent = steps.get(pos.parent.uuid); + list.push(...addArrowToList(list, parent, pos, true, false)) + } else if (pos.parent && ['CatchDefinition', 'FinallyDefinition'].includes(pos.parent.dslName) && pos.position === 0) { + const parent = steps.get(pos.parent.uuid); + list.push(...addArrowToList(list, parent, pos, true, true)) + } else if (pos.parent && pos.parent.dslName === 'MulticastDefinition') { + const parent = steps.get(pos.parent.uuid); + list.push(...addArrowToList(list, parent, pos, true, false)) + if (parent?.nextstep) { + const to = steps.get(parent.nextstep.uuid); + list.push(...addArrowToList(list, pos, to, true, true)) + } + } else if (pos.parent && pos.parent.dslName === 'ChoiceDefinition') { const parent = steps.get(pos.parent.uuid); - const showArrow = pos.prevStep !== undefined && !['TryDefinition', 'ChoiceDefinition'].includes(pos.prevStep.dslName); - const name = pos.prevStep?.dslName; - if (parent && showArrow) { - if ((!pos.inSteps || (pos.inSteps && pos.position === 0)) && parent.step.dslName !== 'MulticastDefinition') { - return getArrows(pos); - } else if (parent.step.dslName === 'MulticastDefinition' && pos.inSteps) { - return getArrows(pos) - } else if (pos.inSteps && pos.position > 0 && !hasSteps(pos.step)) { - const prev = getPreviousStep(pos); - if (prev) { - const r = hasSteps(prev.step) ? prev.rect : prev.headerRect; - const prevX = r.x + r.width / 2 - left; - const prevY = r.y + r.height - top; - return ( - <line name={name} x1={prevX} y1={prevY} x2={endX} y2={endY} className="path" - key={pos.step.uuid} markerEnd="url(#arrowhead)"/> - ) - } - } else if (pos.inSteps && pos.position > 0 && hasSteps(pos.step)) { - const prev = getPreviousStep(pos); - if (prev) { - const r = hasSteps(prev.step) ? prev.rect : prev.headerRect; - const prevX = r.x + r.width / 2 - left; - const prevY = r.y + r.height - top; - return ( - <line name={name} x1={prevX} y1={prevY} x2={endX} y2={endY} className="path" - key={pos.step.uuid} markerEnd="url(#arrowhead)"/> - ) - } + list.push(...addArrowToList(list, parent, pos, true, false)) + } else if (pos.parent && ['WhenDefinition', 'OtherwiseDefinition', 'CatchDefinition', 'FinallyDefinition'].includes(pos.parent.dslName)) { + if (pos.position === 0) { + const parent = steps.get(pos.parent.uuid); + list.push(...addArrowToList(list, parent, pos, true, false)) + } + if (pos.position === (pos.inStepsLength - 1) && !isSpecial(pos)) { + const nextElement = getNext(pos); + if (nextElement) { + const next = steps.get(nextElement.uuid); + list.push(...addArrowToList(list, pos, next, true, true)) } } + } else if (pos.step && !isSpecial(pos)) { + if (pos.nextstep) { + const next = steps.get(pos.nextstep.uuid); + const fromHeader = !pos.step.hasSteps(); + list.push(...addArrowToList(list, pos, next, fromHeader, true)) + } + if (pos.step.hasSteps() && (pos.step as any).steps.length > 0) { + const firstStep = (pos.step as any).steps[0]; + const next = steps.get(firstStep.uuid); + list.push(...addArrowToList(list, pos, next, true, true)) + } } - } - function getArrows(pos: DslPosition) { - if (pos.parent) { - const parent = steps.get(pos?.parent.uuid); - if (parent) { - const rect1 = parent.headerRect; - const rect2 = pos.headerRect; - return getComplexArrow(pos.step.uuid + ":" + pos.parent.uuid, rect1, rect2); + if (['WhenDefinition', 'OtherwiseDefinition'].includes(pos.step.dslName) && pos.step.hasSteps() && (pos.step as any).steps.length === 0) { + if (pos.nextstep) { + const to = steps.get(pos.nextstep.uuid); + list.push(...addArrowToList(list, pos, to, true, true)) + } else { + const next = getNext(pos); + if (next) { + const to = steps.get(next.uuid); + list.push(...addArrowToList(list, pos, to, true, true)) + } } } - } - function getButtonArrow(btn: ButtonPosition) { - const rect1 = btn.rect; - const uuid = btn.nextstep.uuid; - const nextStep = steps.get(uuid); - const rect2 = nextStep?.rect; - if (rect1 && rect2) { - return getComplexArrow(uuid + "-" + btn.nextstep.uuid, rect1, rect2); + if (pos.parent?.dslName === 'TryDefinition' && pos.inSteps && pos.position === (pos.inStepsLength - 1)) { + const parent = steps.get(pos.parent.uuid); + if (parent && parent.nextstep) { + const to = steps.get(parent.nextstep.uuid); + list.push(...addArrowToList(list, pos, to, true, true)) + } } + + if (!isSpecial(pos) && pos.inSteps && pos.nextstep && !pos.step.hasSteps() && pos.parent?.dslName !== 'MulticastDefinition') { + const to = steps.get(pos.nextstep.uuid); + list.push(...addArrowToList(list, pos, to, true, true)) + } + return list; } - function getComplexArrow(key: string, rect1: DOMRect, rect2: DOMRect) { + function getComplexArrow(key: string, rect1: DOMRect, rect2: DOMRect, toHeader: boolean) { const startX = rect1.x + rect1.width / 2 - left; const startY = rect1.y + rect1.height - top - 2; const endX = rect2.x + rect2.width / 2 - left; @@ -309,7 +333,7 @@ export function DslConnections() { const radX = gapX > 30 ? 20 : gapX/2; const radY = gapY > 30 ? 20 : gapY/2; - const endY = rect2.y - top - 9 - radY; + const endY = rect2.y - top - radY - (toHeader ? 9 : 6); const iRadX = startX > endX ? -1 * radX : radX; const iRadY = startY > endY ? -1 * radY : radY; @@ -336,7 +360,7 @@ export function DslConnections() { + ` L ${LX2} ${LY2}` + ` Q ${Q2_X1} ${Q2_Y1} ${Q2_X2} ${Q2_Y2}` return ( - <path key={key} d={path} className="path" markerEnd="url(#arrowhead)"/> + <path key={key} name={key} d={path} className="path" markerEnd="url(#arrowhead)"/> ) } @@ -353,11 +377,11 @@ export function DslConnections() { </marker> </defs> {stepsArray.map(pos => getCircle(pos))} - {stepsArray.map(pos => getArrow(pos))} - {buttons.map(btn => getButtonArrow(btn)).filter(b => b !== undefined)} + <g> + {stepsArray.map(pos => getArrow(pos)).flat(1)} + </g> {getIncomings().map(p => getIncoming(p))} {getOutgoings().map(p => getOutgoing(p))} - {/*{getInternals().map((p) => getInternalLines(p)).flat()}*/} </svg> ) } diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx b/karavan-designer/src/designer/route/RouteDesigner.tsx index b6b1c942..b02ed20b 100644 --- a/karavan-designer/src/designer/route/RouteDesigner.tsx +++ b/karavan-designer/src/designer/route/RouteDesigner.tsx @@ -147,16 +147,17 @@ export function RouteDesigner() { data-click="FLOWS" onClick={event => {unselectElement(event)}} ref={flowRef}> - {routeConfigurations?.map((routeConfiguration, index: number) => ( + {routeConfigurations?.map((routeConfiguration, index: number, array) => ( <DslElement key={routeConfiguration.uuid} inSteps={false} position={index} step={routeConfiguration} nextStep={undefined} prevStep={undefined} + inStepsLength={array.length} parent={undefined}/> ))} - {routes?.map((route: any, index: number) => { + {routes?.map((route: any, index: number, array) => { return ( <DslElement key={route.uuid} inSteps={false} @@ -164,6 +165,7 @@ export function RouteDesigner() { step={route} nextStep={undefined} prevStep={undefined} + inStepsLength={array.length} parent={undefined}/> ) })} diff --git a/karavan-designer/src/designer/route/element/DslElement.css b/karavan-designer/src/designer/route/element/DslElement.css index 7af5bd51..61cc5af3 100644 --- a/karavan-designer/src/designer/route/element/DslElement.css +++ b/karavan-designer/src/designer/route/element/DslElement.css @@ -18,14 +18,19 @@ .karavan .dsl-page .flows .step-element .header-route { display: block; background: transparent; - padding: 10px; + border-radius: 42px; + padding: 20px; margin: 0; z-index: 101; min-width: 260px; } -.karavan .dsl-page .flows .step-element .header-bottom-line { - border-bottom: 1px dashed; +.karavan .dsl-page .flows .step-element .header-bottom-selected { + border-bottom: 1px dashed var(--step-border-color-selected); +} + +.karavan .dsl-page .flows .step-element .header-bottom-not-selected { + border-bottom: 1px dashed var(--pf-v5-global--Color--200); } .karavan .dsl-page .flows .step-element .header-route:hover { @@ -48,7 +53,7 @@ .karavan .step-element .header .delete-button, .element-builder .header .delete-button { position: absolute; - top: -7px; + top: -11px; line-height: 1; border: 0; padding: 0; @@ -72,10 +77,6 @@ height: 50px; } -.karavan .step-element-selected { - background-color: rgba(var(--pf-v5-global--palette--blue-50), 1); -} - .karavan .step-element .selected .header-icon { border-color: var(--pf-v5-global--primary-color--100); background-color: var(--pf-v5-global--palette--blue-50); @@ -152,7 +153,7 @@ .karavan .step-element .insert-element-button { position: absolute; - top: -7px; + top: -11px; line-height: 1; border: 0; padding: 0; diff --git a/karavan-designer/src/designer/route/element/DslElement.tsx b/karavan-designer/src/designer/route/element/DslElement.tsx index a1b63a98..8f89a0f9 100644 --- a/karavan-designer/src/designer/route/element/DslElement.tsx +++ b/karavan-designer/src/designer/route/element/DslElement.tsx @@ -27,6 +27,7 @@ import {shallow} from "zustand/shallow"; import {useRouteDesignerHook} from "../useRouteDesignerHook"; import {AddElementIcon} from "./DslElementIcons"; import {DslElementHeader} from "./DslElementHeader"; +import {TryDefinition} from "karavan-core/lib/model/CamelDefinition"; interface Props { step: CamelElement, @@ -35,12 +36,12 @@ interface Props { prevStep: CamelElement | undefined, inSteps: boolean position: number + inStepsLength: number } export function DslElement(props: Props) { const headerRef = React.useRef<HTMLDivElement>(null); - const addButtonRef = React.useRef<HTMLDivElement>(null); const { selectElement, moveElement, @@ -94,10 +95,6 @@ export function DslElement(props: Props) { return selectedUuids.includes(props.step.uuid); } - function isElementHidden(): boolean { - return props.step.dslName === 'LogDefinition' && hideLogDSL; - } - function hasBorder(): boolean { const step = props.step; if (['FilterDefinition', 'RouteDefinition', 'RouteConfigurationDefinition'].includes(step.dslName)) { @@ -106,6 +103,7 @@ export function DslElement(props: Props) { if ([ 'FromDefinition', 'TryDefinition', + 'MulticastDefinition', 'CatchDefinition', 'FinallyDefinition', 'ChoiceDefinition', 'SwitchDefinition', 'WhenDefinition', 'OtherwiseDefinition' @@ -119,10 +117,6 @@ export function DslElement(props: Props) { return ['FromDefinition', 'RouteConfigurationDefinition', 'RouteDefinition', 'WhenDefinition', 'OtherwiseDefinition'].includes(props.step.dslName); } - function isRoute(): boolean { - return ['RouteDefinition'].includes(props.step.dslName); - } - function isAddStepButtonLeft(): boolean { return ['MulticastDefinition'] .includes(props.step.dslName); @@ -139,28 +133,10 @@ export function DslElement(props: Props) { return children.filter((c: ChildElement) => c.name === 'steps' || c.multiple).length > 0 && props.inSteps; } - function sendButtonPosition(el: HTMLButtonElement | null) { - const {nextStep, step, parent} = props; - let needArrow = !hasBorder() && !['ChoiceDefinition', 'MulticastDefinition', 'TryDefinition'].includes(step.dslName); - - if (parent - && ['TryDefinition'].includes(parent.dslName) - && !['CatchDefinition', 'FinallyDefinition'].includes(step.dslName)) { - needArrow = true; - } - - if (el && nextStep && needArrow) { - const rect = headerRef.current?.getBoundingClientRect(); - - if (rect) - EventBus.sendButtonPosition("add", step.uuid, nextStep, rect); - } - } function sendPosition(el: HTMLDivElement | null) { - const {step, prevStep, parent} = props; + const {step, prevStep, nextStep, parent, inSteps, inStepsLength} = props; const isSelected = isElementSelected(); - const isHidden = isElementHidden(); if (el) { const header = Array.from(el.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0]; if (header) { @@ -168,13 +144,9 @@ export function DslElement(props: Props) { const headerRect = headerIcon.getBoundingClientRect(); const rect = el.getBoundingClientRect(); if (step.showChildren) { - if (isHidden) { - EventBus.sendPosition("add", step, prevStep, parent, rect, headerRect, props.position, props.inSteps, isSelected); - } else { - EventBus.sendPosition("add", step, prevStep, parent, rect, headerRect, props.position, props.inSteps, isSelected); - } + EventBus.sendPosition("add", step, prevStep, nextStep, parent, rect, headerRect, props.position, inStepsLength, inSteps, isSelected); } else { - EventBus.sendPosition("delete", step, prevStep, parent, new DOMRect(), new DOMRect(), 0); + EventBus.sendPosition("delete", step, prevStep, nextStep, parent, new DOMRect(), new DOMRect(), 0, 0); } } } @@ -190,7 +162,6 @@ export function DslElement(props: Props) { function getChildrenElementsStyle(child: ChildElement, notOnlySteps: boolean) { const style: CSSProperties = { - // borderStyle: isBorder ? "dotted" : "none", borderColor: "var(--step-border-color)", borderWidth: "1px", borderRadius: "16px", @@ -229,10 +200,12 @@ export function DslElement(props: Props) { return ( <div className={child.name + " has-child"} style={getChildrenElementsStyle(child, notOnlySteps)} key={step.uuid + "-child-" + index}> - {children.map((element, index) => { + {children.map((element, index, array) => { let prevStep = children.at(index - 1); let nextStep: CamelElement | undefined = undefined; - if (['TryDefinition', 'ChoiceDefinition'].includes(step.dslName)) { + if ('ChoiceDefinition' === step.dslName) { + nextStep = props.nextStep; + } else if ('TryDefinition' === step.dslName && ['CatchDefinition', 'FinallyDefinition'].includes(element.dslName)) { nextStep = props.nextStep; } else { nextStep = children.at(index + 1); @@ -244,6 +217,7 @@ export function DslElement(props: Props) { step={element} nextStep={nextStep} prevStep={prevStep} + inStepsLength={array.length} parent={step}/> </div>) } @@ -266,12 +240,10 @@ export function DslElement(props: Props) { const hideAddButton = step.dslName === 'StepDefinition' && !CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, selectedUuids.at(0)); if (hideAddButton) return (<></>) else return ( - <div ref={addButtonRef}> - <Tooltip position={"bottom"} + <Tooltip position={"left"} content={<div>{"Add step to " + CamelDisplayUtil.getTitle(step)}</div>} > <button type="button" - ref={el => sendButtonPosition(el)} aria-label="Add" onClick={e => onOpenSelector(e)} className={isAddStepButtonLeft() ? "add-button add-button-left" : "add-button add-button-bottom"}> @@ -279,13 +251,12 @@ export function DslElement(props: Props) { </button> </Tooltip> - </div> ) } const element: CamelElement = props.step; const className = "step-element" - + (isElementSelected() ? " step-element-selected" : "") + (!props.step.showChildren ? " hidden-step" : "") + + (!props.step.showChildren ? " hidden-step" : "") + ((element as any).disabled ? " disabled " : ""); return ( <div key={"root" + element.uuid} diff --git a/karavan-designer/src/designer/route/element/DslElementHeader.tsx b/karavan-designer/src/designer/route/element/DslElementHeader.tsx index 9ac4ab99..d201d105 100644 --- a/karavan-designer/src/designer/route/element/DslElementHeader.tsx +++ b/karavan-designer/src/designer/route/element/DslElementHeader.tsx @@ -20,7 +20,6 @@ import '../../karavan.css'; import './DslElement.css'; import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; import {CamelUi} from "../../utils/CamelUi"; -import {EventBus} from "../../utils/EventBus"; import {ChildElement, CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil"; @@ -28,11 +27,7 @@ import {useDesignerStore} from "../../DesignerStore"; import {shallow} from "zustand/shallow"; import {useRouteDesignerHook} from "../useRouteDesignerHook"; import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from "./DslElementIcons"; -import { - InterceptDefinition, - InterceptFromDefinition, - InterceptSendToEndpointDefinition, OnCompletionDefinition, OnExceptionDefinition, RouteConfigurationDefinition -} from "karavan-core/lib/model/CamelDefinition"; +import { RouteConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition"; interface Props { headerRef: React.RefObject<HTMLDivElement> @@ -79,12 +74,8 @@ export function DslElementHeader(props: Props) { return selectedUuids.includes(props.step.uuid); } - function isElementHidden(): boolean { - return props.step.dslName === 'LogDefinition' && hideLogDSL; - } - function isWide(): boolean { - return ['RouteConfigurationDefinition', 'RouteDefinition', 'ChoiceDefinition', 'SwitchDefinition', 'MulticastDefinition', 'TryDefinition', 'CircuitBreakerDefinition'] + return ['RouteConfigurationDefinition', 'RouteDefinition', 'ChoiceDefinition', 'MulticastDefinition', 'TryDefinition', 'CircuitBreakerDefinition'] .includes(props.step.dslName); } @@ -129,29 +120,6 @@ export function DslElementHeader(props: Props) { return style; } - function sendPosition(el: HTMLDivElement | null) { - const {step, prevStep, parent} = props; - const isSelected = isElementSelected(); - const isHidden = isElementHidden(); - if (el) { - const header = Array.from(el.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0]; - if (header) { - const headerIcon: any = Array.from(header.childNodes.values()).filter((n: any) => n.classList.contains("header-icon"))[0]; - const headerRect = headerIcon.getBoundingClientRect(); - const rect = el.getBoundingClientRect(); - if (step.showChildren) { - if (isHidden) { - EventBus.sendPosition("add", step, prevStep, parent, rect, headerRect, props.position, props.inSteps, isSelected); - } else { - EventBus.sendPosition("add", step, prevStep, parent, rect, headerRect, props.position, props.inSteps, isSelected); - } - } else { - EventBus.sendPosition("delete", step, prevStep, parent, new DOMRect(), new DOMRect(), 0); - } - } - } - } - function getAvailableModels() { // TODO: make static list-of-values instead const step: CamelElement = props.step return CamelUi.getSelectorModelsForParent(step.dslName, false); @@ -174,10 +142,13 @@ export function DslElementHeader(props: Props) { const classes: string[] = []; const step: CamelElement = props.step; if (step.dslName === 'RouteDefinition') { - classes.push(...'header-route', 'header-bottom-line') + classes.push('header-route') + classes.push('header-bottom-line') + classes.push(isElementSelected() ? 'header-bottom-selected' : 'header-bottom-not-selected') } else if (step.dslName === 'RouteConfigurationDefinition') { classes.push('header-route') if (hasElements(step)) classes.push('header-bottom-line') + classes.push(isElementSelected() ? 'header-bottom-selected' : 'header-bottom-not-selected') } else { classes.push('header') } @@ -200,7 +171,6 @@ export function DslElementHeader(props: Props) { <div className={"dsl-element " + headerClasses} style={getHeaderStyle()} ref={props.headerRef}> {!['RouteConfigurationDefinition', 'RouteDefinition'].includes(props.step.dslName) && <div - ref={el => sendPosition(el)} className={"header-icon"} style={isWide() ? {width: ""} : {}}> {CamelUi.getIconForElement(step)} diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx index b65966a0..0f90bb10 100644 --- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx +++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx @@ -105,7 +105,7 @@ export function useRouteDesignerHook () { } const deleteElement = () => { - EventBus.sendPosition("clean", new CamelElement(""), undefined, undefined, new DOMRect(), new DOMRect(), 0); + EventBus.sendPosition("clean", new CamelElement(""), undefined,undefined, undefined, new DOMRect(), new DOMRect(), 0, 0); EventBus.sendButtonPosition("clean", '', new CamelElement(""), new DOMRect()); let i = integration; selectedUuids.forEach(uuidToDelete => { diff --git a/karavan-designer/src/designer/utils/EventBus.ts b/karavan-designer/src/designer/utils/EventBus.ts index 55906f0f..2d075b00 100644 --- a/karavan-designer/src/designer/utils/EventBus.ts +++ b/karavan-designer/src/designer/utils/EventBus.ts @@ -38,10 +38,12 @@ export class ButtonPosition { export class DslPosition { step: CamelElement = new CamelElement(""); prevStep: CamelElement | undefined; + nextstep: CamelElement | undefined; parent: CamelElement | undefined; inSteps: boolean = false; isSelected: boolean = false; position: number = 0; + inStepsLength: number = 0; rect: DOMRect = new DOMRect(); headerRect: DOMRect = new DOMRect(); command: "add" | "delete" | "clean" = "add"; @@ -49,20 +51,24 @@ export class DslPosition { constructor(command: "add" | "delete" | "clean", step: CamelElement, prevStep: CamelElement | undefined, + nextstep: CamelElement | undefined, parent:CamelElement | undefined, rect: DOMRect, headerRect:DOMRect, position: number, + inStepsLength: number, inSteps: boolean = false, isSelected: boolean = false) { this.command = command; this.step = step; + this.nextstep = nextstep; this.prevStep = prevStep; this.parent = parent; this.rect = rect; this.headerRect = headerRect; this.inSteps = inSteps; this.position = position; + this.inStepsLength = inStepsLength; this.isSelected = isSelected; } } @@ -110,12 +116,15 @@ export const EventBus = { sendPosition: (command: "add" | "delete" | "clean", step: CamelElement, prevStep: CamelElement | undefined, + nextstep: CamelElement | undefined, parent: CamelElement | undefined, rect: DOMRect, headerRect: DOMRect, position: number, + inStepsLength: number, inSteps: boolean = false, - isSelected: boolean = false) => dslPositions.next(new DslPosition(command, step, prevStep, parent, rect, headerRect, position, inSteps, isSelected)), + isSelected: boolean = false) => dslPositions.next( + new DslPosition(command, step, prevStep, nextstep, parent, rect, headerRect, position, inStepsLength, inSteps, isSelected)), onPosition: () => dslPositions.asObservable(), sendButtonPosition: (command: "add" | "delete" | "clean", uuid: string,