From 554bc1a5d0b177695e938e7b83fd0fd6894270f4 Mon Sep 17 00:00:00 2001 From: "Ricardo M." Date: Mon, 12 Feb 2024 14:09:27 +0100 Subject: [PATCH] feat(canvas): Add additional node's interactions Currently, all canvas' nodes have the possibility to be replaced and removed. This leads to an inconsistent situation in which empty containers suggests that can be replaced or removed. The fix for this situation is to offer the possibility to select whether a node can be replaced or removed, this way, we have a broad range of node interactions. fix: https://github.com/KaotoIO/kaoto-next/issues/561 --- .../Visualization/Custom/ItemRemoveNode.tsx | 7 ++++--- .../Visualization/Custom/ItemReplaceNode.tsx | 7 ++++--- .../src/models/visualization/base-visual-entity.ts | 2 ++ .../flows/abstract-camel-visual-entity.ts | 2 ++ .../flows/camel-on-exception-visual-entity.ts | 13 +++++++++---- .../visualization/flows/pipe-visual-entity.ts | 2 ++ .../flows/support/camel-component-schema.service.ts | 2 +- .../src/models/visualization/visualization-node.ts | 2 ++ 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/packages/ui/src/components/Visualization/Custom/ItemRemoveNode.tsx b/packages/ui/src/components/Visualization/Custom/ItemRemoveNode.tsx index 7a15e839f..5b807cade 100644 --- a/packages/ui/src/components/Visualization/Custom/ItemRemoveNode.tsx +++ b/packages/ui/src/components/Visualization/Custom/ItemRemoveNode.tsx @@ -1,6 +1,6 @@ import { MinusIcon } from '@patternfly/react-icons'; import { ContextMenuItem, ElementContext, ElementModel, GraphElement } from '@patternfly/react-topology'; -import { FunctionComponent, useCallback, useContext } from 'react'; +import { FunctionComponent, useCallback, useContext, useMemo } from 'react'; import { IDataTestID } from '../../../models'; import { EntitiesContext } from '../../../providers/entities.provider'; import { CanvasNode } from '../Canvas/canvas.models'; @@ -9,15 +9,16 @@ export const ItemRemoveNode: FunctionComponent = (props) => { const entitiesContext = useContext(EntitiesContext); const element: GraphElement = useContext(ElementContext); const vizNode = element.getData()?.vizNode; + const shouldRender = useMemo(() => vizNode?.getNodeInteraction()?.canRemoveStep ?? false, [vizNode]); const onRemoveNode = useCallback(() => { vizNode?.removeChild(); entitiesContext?.updateEntitiesFromCamelResource(); }, [entitiesContext, vizNode]); - return ( + return shouldRender ? ( Remove {vizNode?.id} node - ); + ) : null; }; diff --git a/packages/ui/src/components/Visualization/Custom/ItemReplaceNode.tsx b/packages/ui/src/components/Visualization/Custom/ItemReplaceNode.tsx index e4324360f..ea94bfe78 100644 --- a/packages/ui/src/components/Visualization/Custom/ItemReplaceNode.tsx +++ b/packages/ui/src/components/Visualization/Custom/ItemReplaceNode.tsx @@ -1,6 +1,6 @@ import { AngleRightIcon } from '@patternfly/react-icons'; import { ContextMenuItem, ElementContext, ElementModel, GraphElement } from '@patternfly/react-topology'; -import { FunctionComponent, useCallback, useContext } from 'react'; +import { FunctionComponent, useCallback, useContext, useMemo } from 'react'; import { IDataTestID } from '../../../models'; import { AddStepMode } from '../../../models/visualization/base-visual-entity'; import { CatalogModalContext } from '../../../providers/catalog-modal.provider'; @@ -12,6 +12,7 @@ export const ItemReplaceNode: FunctionComponent = (props) => { const catalogModalContext = useContext(CatalogModalContext); const element: GraphElement = useContext(ElementContext); const vizNode = element.getData()?.vizNode; + const shouldRender = useMemo(() => vizNode?.getNodeInteraction()?.canReplaceStep ?? false, [vizNode]); const onReplaceNode = useCallback(async () => { if (!vizNode || !entitiesContext) return; @@ -30,9 +31,9 @@ export const ItemReplaceNode: FunctionComponent = (props) => { entitiesContext.updateEntitiesFromCamelResource(); }, [catalogModalContext, entitiesContext, vizNode]); - return ( + return shouldRender ? ( Replace {vizNode?.id} node - ); + ) : null; }; diff --git a/packages/ui/src/models/visualization/base-visual-entity.ts b/packages/ui/src/models/visualization/base-visual-entity.ts index 317e72566..0b1a3d9d9 100644 --- a/packages/ui/src/models/visualization/base-visual-entity.ts +++ b/packages/ui/src/models/visualization/base-visual-entity.ts @@ -150,4 +150,6 @@ export interface NodeInteraction { canHaveNextStep: boolean; canHaveChildren: boolean; canHaveSpecialChildren: boolean; + canReplaceStep: boolean; + canRemoveStep: boolean; } diff --git a/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts b/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts index 88dc5d05b..ff1c991ab 100644 --- a/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts @@ -207,6 +207,8 @@ export abstract class AbstractCamelVisualEntity implements BaseVisualCamelEntity canHaveNextStep: canHavePreviousStep, canHaveChildren, canHaveSpecialChildren, + canReplaceStep: true, + canRemoveStep: true, }; } diff --git a/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts index 90da5b952..e916a05cd 100644 --- a/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts @@ -21,9 +21,10 @@ import { CamelComponentDefaultService } from './support/camel-component-default. export class CamelOnExceptionVisualEntity implements BaseVisualCamelEntity { id: string; readonly type = EntityType.ErrorHandler; + private static readonly ROOT_PATH = 'onException'; constructor(public onExceptionDef: { onException: OnException }) { - const id = onExceptionDef.onException.id ?? getCamelRandomId('onException'); + const id = onExceptionDef.onException.id ?? getCamelRandomId(CamelOnExceptionVisualEntity.ROOT_PATH); this.id = id; onExceptionDef.onException.id = id; } @@ -36,7 +37,7 @@ export class CamelOnExceptionVisualEntity implements BaseVisualCamelEntity { const objectKeys = Object.keys(onExceptionDef!); return ( - objectKeys.length === 1 && 'onException' in onExceptionDef! && typeof onExceptionDef.onException === 'object' + objectKeys.length === 1 && this.ROOT_PATH in onExceptionDef! && typeof onExceptionDef.onException === 'object' ); } @@ -209,12 +210,16 @@ export class CamelOnExceptionVisualEntity implements BaseVisualCamelEntity { ); const canHaveChildren = stepsProperties.find((property) => property.type === 'branch') !== undefined; const canHaveSpecialChildren = Object.keys(stepsProperties).length > 1; + const canReplaceStep = data.path !== CamelOnExceptionVisualEntity.ROOT_PATH; + const canRemoveStep = data.path !== CamelOnExceptionVisualEntity.ROOT_PATH; return { canHavePreviousStep, canHaveNextStep: canHavePreviousStep, canHaveChildren, canHaveSpecialChildren, + canReplaceStep, + canRemoveStep, }; } @@ -227,8 +232,8 @@ export class CamelOnExceptionVisualEntity implements BaseVisualCamelEntity { toVizNode(): IVisualizationNode { const onExceptionGroupNode = CamelStepsService.getVizNodeFromProcessor( - 'onException', - { processorName: 'onException' as keyof ProcessorDefinition }, + CamelOnExceptionVisualEntity.ROOT_PATH, + { processorName: CamelOnExceptionVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.onExceptionDef, ); onExceptionGroupNode.data.entity = this; diff --git a/packages/ui/src/models/visualization/flows/pipe-visual-entity.ts b/packages/ui/src/models/visualization/flows/pipe-visual-entity.ts index f807f6a3c..e1c61ccd5 100644 --- a/packages/ui/src/models/visualization/flows/pipe-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/pipe-visual-entity.ts @@ -158,6 +158,8 @@ export class PipeVisualEntity implements BaseVisualCamelEntity { canHaveNextStep: data.path !== 'sink', canHaveChildren: false, canHaveSpecialChildren: false, + canReplaceStep: true, + canRemoveStep: true, }; } diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts index 34ca626fd..4661e7114 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts @@ -10,7 +10,7 @@ import { IKameletDefinition } from '../../../kamelets-catalog'; import { ICamelComponentDefinition } from '../../../camel-components-catalog'; export class CamelComponentSchemaService { - static DISABLED_SIBLING_STEPS = ['from', 'onWhen', 'when', 'otherwise', 'doCatch', 'doFinally']; + static DISABLED_SIBLING_STEPS = ['from', 'onWhen', 'when', 'otherwise', 'doCatch', 'doFinally', 'onException']; // eslint-disable-next-line @typescript-eslint/no-explicit-any static getVisualComponentSchema(path: string, definition: any): VisualComponentSchema | undefined { diff --git a/packages/ui/src/models/visualization/visualization-node.ts b/packages/ui/src/models/visualization/visualization-node.ts index 6310240a3..892bd9cd2 100644 --- a/packages/ui/src/models/visualization/visualization-node.ts +++ b/packages/ui/src/models/visualization/visualization-node.ts @@ -53,6 +53,8 @@ class VisualizationNode