From 1aec98fe1afd6f1dcb6ddafc068ca9b63d2cbd73 Mon Sep 17 00:00:00 2001 From: Jenny <32821331+jenny-s51@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:27:03 -0400 Subject: [PATCH 1/5] add terminal types conditionally render terminal types use directional connectors address PR feedback from Jeff revert utils.ts --- .../demos/pipelineGroupsDemo/DemoTaskEdge.tsx | 24 +++++ .../createDemoPipelineGroupsNodes.ts | 99 ++++++++++++++----- .../pipelineGroupsComponentFactory.tsx | 7 +- .../pipelinesDemo/DemoFinallyTaskEdge.tsx | 13 +++ .../src/demos/pipelinesDemo/DemoTaskEdge.tsx | 24 +++++ .../pipelinesDemo/PipelineDemoContext.tsx | 28 ++++-- .../pipelinesDemo/PipelineLayoutDemo.tsx | 20 ++-- .../pipelinesDemo/PipelineOptionsBar.tsx | 8 ++ .../demos/pipelinesDemo/PipelineTasksDemo.tsx | 2 +- .../pipelineComponentFactory.tsx | 8 +- .../pipelinesDemo/useDemoPipelineNodes.tsx | 14 +-- .../src/components/edges/DefaultEdge.tsx | 2 +- .../terminals/DefaultConnectorTerminal.tsx | 7 +- .../pipelines/components/edges/TaskEdge.tsx | 86 ++++++++++++---- packages/module/src/pipelines/const.ts | 1 + 15 files changed, 267 insertions(+), 76 deletions(-) create mode 100644 packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskEdge.tsx create mode 100644 packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx create mode 100644 packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskEdge.tsx diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskEdge.tsx b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskEdge.tsx new file mode 100644 index 00000000..095cf4a1 --- /dev/null +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskEdge.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { Edge, EdgeTerminalType, GraphElement, TaskEdge } from '@patternfly/react-topology'; + +interface DemoTaskEdgeProps { + element: GraphElement; +} + +const DemoTaskEdge: React.FunctionComponent = ({ element, ...props }) => { + + const isDependency = (element as Edge).getTarget().getData()?.isDependency; + + return ( + + ); +}; + +export default observer(DemoTaskEdge); diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts index 383c99cd..a9c9f664 100644 --- a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts @@ -1,8 +1,5 @@ /* eslint-disable camelcase */ -import { - PipelineNodeModel, - RunStatus, -} from '@patternfly/react-topology'; +import { PipelineNodeModel, RunStatus } from '@patternfly/react-topology'; export const NODE_PADDING_VERTICAL = 15; export const NODE_PADDING_HORIZONTAL = 15; @@ -27,10 +24,11 @@ export const createExecution2 = (): [string, PipelineNodeModel[]] => { runAfterTasks: [], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_2_1: PipelineNodeModel = { + const task_2_1: PipelineNodeModel = { id: 'task_2_1', label: 'Task 2-1', type: 'Task', @@ -42,10 +40,11 @@ export const createExecution2 = (): [string, PipelineNodeModel[]] => { runAfterTasks: [], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_2_2: PipelineNodeModel = { + const task_2_2: PipelineNodeModel = { id: 'task_2_2', label: 'Task 2-2', type: 'Task', @@ -57,10 +56,11 @@ export const createExecution2 = (): [string, PipelineNodeModel[]] => { runAfterTasks: ['task_2_1'], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_2_3: PipelineNodeModel = { + const task_2_3: PipelineNodeModel = { id: 'task_2_3', label: 'Task 2-3', type: 'Task', @@ -72,10 +72,11 @@ export const createExecution2 = (): [string, PipelineNodeModel[]] => { runAfterTasks: ['task_2_1'], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_2_4: PipelineNodeModel = { + const task_2_4: PipelineNodeModel = { id: 'task_2_4', label: 'Task 2-4', type: 'Task', @@ -87,14 +88,15 @@ export const createExecution2 = (): [string, PipelineNodeModel[]] => { runAfterTasks: ['task_2_1'], data: { status: RunStatus.Succeeded, + isDependency: true } }; execution2.children = [task_2_1.id, task_2_2.id, task_2_3.id, task_2_4.id]; - const nodes:PipelineNodeModel[] = [execution2, task_2_1, task_2_2, task_2_3, task_2_4]; + const nodes: PipelineNodeModel[] = [execution2, task_2_1, task_2_2, task_2_3, task_2_4]; - return ['execution-2', nodes] -} + return ['execution-2', nodes]; +}; export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[]] => { const execution3: PipelineNodeModel = { @@ -110,6 +112,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: runAfter ? [runAfter] : [], data: { status: RunStatus.Succeeded, + isDependency: true } }; @@ -125,6 +128,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_2: PipelineNodeModel = { @@ -139,6 +143,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_3: PipelineNodeModel = { @@ -154,6 +159,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_4: PipelineNodeModel = { @@ -168,6 +174,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_5: PipelineNodeModel = { @@ -182,6 +189,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_4.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_6: PipelineNodeModel = { @@ -196,6 +204,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_4.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_7: PipelineNodeModel = { @@ -210,6 +219,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_5.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_8: PipelineNodeModel = { @@ -224,6 +234,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_2.id, task_3_7.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; @@ -238,6 +249,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ }, data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_3_2: PipelineNodeModel = { @@ -252,6 +264,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ }, data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_3_3: PipelineNodeModel = { @@ -266,6 +279,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ runAfterTasks: [task_3_3_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; const task_3_3_4: PipelineNodeModel = { @@ -280,19 +294,43 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ }, data: { status: RunStatus.Succeeded, + isDependency: true } }; task_3_3.children = [task_3_3_1.id, task_3_3_2.id, task_3_3_3.id, task_3_3_4.id]; - execution3.children = [task_3_1.id, task_3_2.id, task_3_3.id, task_3_4.id, task_3_5.id, task_3_6.id, task_3_7.id, task_3_8.id]; + execution3.children = [ + task_3_1.id, + task_3_2.id, + task_3_3.id, + task_3_4.id, + task_3_5.id, + task_3_6.id, + task_3_7.id, + task_3_8.id + ]; - const nodes:PipelineNodeModel[] = [execution3, task_3_1, task_3_2, task_3_3, task_3_4, task_3_5, task_3_6, task_3_7, task_3_8, task_3_3_1, task_3_3_2, task_3_3_3, task_3_3_4]; + const nodes: PipelineNodeModel[] = [ + execution3, + task_3_1, + task_3_2, + task_3_3, + task_3_4, + task_3_5, + task_3_6, + task_3_7, + task_3_8, + task_3_3_1, + task_3_3_2, + task_3_3_3, + task_3_3_4 + ]; - return ['execution-3', nodes] + return ['execution-3', nodes]; }; export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { - const nodes:PipelineNodeModel[] = []; + const nodes: PipelineNodeModel[] = []; const execution1: PipelineNodeModel = { id: 'execution-1', @@ -308,6 +346,7 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [], data: { status: RunStatus.Succeeded, + isDependency: true } }; nodes.push(execution1); @@ -316,7 +355,7 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { execution1.children.push(execution2Id); nodes.push(...execution2Nodes); - const task_1_1: PipelineNodeModel = { + const task_1_1: PipelineNodeModel = { id: 'task_1_1', label: 'Task 1-1', type: 'Task', @@ -328,9 +367,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [execution2Id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_1_2: PipelineNodeModel = { + const task_1_2: PipelineNodeModel = { id: 'task_1_2', label: 'Task 1-2', type: 'Task', @@ -342,9 +382,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_1_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_1_3: PipelineNodeModel = { + const task_1_3: PipelineNodeModel = { id: 'task_1_3', label: 'Task 1-3', type: 'Task', @@ -356,9 +397,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_1_1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_1_4: PipelineNodeModel = { + const task_1_4: PipelineNodeModel = { id: 'task_1_4', label: 'Task 1-4', type: 'Task', @@ -370,6 +412,7 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_1_3.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; nodes.push(task_1_1, task_1_2, task_1_3, task_1_4); @@ -379,7 +422,7 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { execution1.children.push(execution3Id); nodes.push(...execution3Nodes); - const task_1: PipelineNodeModel = { + const task_1: PipelineNodeModel = { id: 'task_1', label: 'Task 1', type: 'Task', @@ -391,9 +434,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [execution1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_2: PipelineNodeModel = { + const task_2: PipelineNodeModel = { id: 'task_2', label: 'Task 2', type: 'Task', @@ -405,9 +449,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [execution1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_3: PipelineNodeModel = { + const task_3: PipelineNodeModel = { id: 'task_3', label: 'Task 3', type: 'Task', @@ -419,9 +464,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [execution1.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_4: PipelineNodeModel = { + const task_4: PipelineNodeModel = { id: 'task_4', label: 'Task 4', type: 'Task', @@ -433,9 +479,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_3.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_5: PipelineNodeModel = { + const task_5: PipelineNodeModel = { id: 'task_5', label: 'Task 5', type: 'Task', @@ -447,9 +494,10 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_3.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; - const task_6: PipelineNodeModel = { + const task_6: PipelineNodeModel = { id: 'task_6', label: 'Task 6', type: 'Task', @@ -461,6 +509,7 @@ export const createDemoPipelineGroupsNodes = (): PipelineNodeModel[] => { runAfterTasks: [task_4.id], data: { status: RunStatus.Succeeded, + isDependency: true } }; nodes.push(task_1, task_2, task_3, task_4, task_5, task_6); diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/pipelineGroupsComponentFactory.tsx b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/pipelineGroupsComponentFactory.tsx index edc7b214..4acb646e 100644 --- a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/pipelineGroupsComponentFactory.tsx +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/pipelineGroupsComponentFactory.tsx @@ -7,11 +7,11 @@ import { DEFAULT_SPACER_NODE_TYPE, withSelection, withPanZoom, - GraphComponent, - TaskEdge + GraphComponent } from '@patternfly/react-topology'; import DemoTaskNode from './DemoTaskNode'; import DemoTaskGroup from './DemoTaskGroup'; +import DemoTaskEdge from './DemoTaskEdge'; const pipelineGroupsComponentFactory: ComponentFactory = ( kind: ModelKind, @@ -28,7 +28,8 @@ const pipelineGroupsComponentFactory: ComponentFactory = ( case DEFAULT_SPACER_NODE_TYPE: return SpacerNode; case 'edge': - return TaskEdge; + // draw arrow terminal when isDependency is set on data + return DemoTaskEdge; default: return undefined; } diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx new file mode 100644 index 00000000..46f40bf2 --- /dev/null +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { EdgeTerminalType, GraphElement, TaskEdge } from '@patternfly/react-topology'; + +interface DemoFinallyTaskEdgeProps { + element: GraphElement; +} + +const DemoFinallyTaskEdge: React.FunctionComponent = (props) => ( + +); + +export default observer(DemoFinallyTaskEdge); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskEdge.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskEdge.tsx new file mode 100644 index 00000000..03972dac --- /dev/null +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskEdge.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { Edge, EdgeTerminalType, GraphElement, TaskEdge } from '@patternfly/react-topology'; +import { PipelineDemoContext } from './PipelineDemoContext'; + +interface DemoTaskEdgeProps { + element: GraphElement; +} + +const DemoTaskEdge: React.FunctionComponent = ({ element, ...props }) => { + const pipelineOptions = React.useContext(PipelineDemoContext); + + return ( + + ); +}; + +export default observer(DemoTaskEdge); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineDemoContext.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineDemoContext.tsx index 25819ebc..2bbffc75 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineDemoContext.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineDemoContext.tsx @@ -7,6 +7,7 @@ export class PipelineDemoModel { protected showBadgeTooltipsP: boolean = false; protected showContextMenusP: boolean = false; protected showGroupsP: boolean = false; + protected showTerminalTypeP: boolean = false; protected verticalLayoutP: boolean = false; constructor() { @@ -17,20 +18,23 @@ export class PipelineDemoModel { | 'showBadgeTooltipsP' | 'showContextMenusP' | 'showGroupsP' + | 'showTerminalTypeP' | 'verticalLayoutP' - >(this, { + >(this, { showIconsP: observable, showBadgesP: observable, showBadgeTooltipsP: observable, showContextMenusP: observable, showGroupsP: observable, + showTerminalTypeP: observable, verticalLayoutP: observable, setShowIcons: action, setShowBadges: action, setShowBadgeTooltips: action, setShowContextMenus: action, setShowGroups: action, - setVerticalLayout: action, + setShowTerminalType: action, + setVerticalLayout: action }); } @@ -39,42 +43,50 @@ export class PipelineDemoModel { } public setShowIcons = (show: boolean): void => { this.showIconsP = show; - } + }; public get showBadges(): boolean { return this.showBadgesP; } public setShowBadges = (show: boolean): void => { this.showBadgesP = show; - } + }; public get showBadgeTooltips(): boolean { return this.showBadgeTooltipsP; } public setShowBadgeTooltips = (show: boolean): void => { this.showBadgeTooltipsP = show; - } + }; public get showContextMenus(): boolean { return this.showContextMenusP; } public setShowContextMenus = (show: boolean): void => { this.showContextMenusP = show; + }; + + public get showTerminalType(): boolean { + return this.showTerminalTypeP; } + public setShowTerminalType = (show: boolean): void => { + this.showTerminalTypeP = show; + }; + public get showGroups(): boolean { return this.showGroupsP; } public setShowGroups = (show: boolean): void => { this.showGroupsP = show; - } + }; public get verticalLayout(): boolean { return this.verticalLayoutP; } public setVerticalLayout = (show: boolean): void => { this.verticalLayoutP = show; - } + }; } -export const PipelineDemoContext = React.createContext(new PipelineDemoModel()); \ No newline at end of file +export const PipelineDemoContext = React.createContext(new PipelineDemoModel()); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx index f27670c3..8bcf6855 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx @@ -15,12 +15,13 @@ import { GRAPH_LAYOUT_END_EVENT, getSpacerNodes, getEdgesFromNodes, - DEFAULT_EDGE_TYPE, DEFAULT_SPACER_NODE_TYPE, DEFAULT_FINALLY_NODE_TYPE, TOP_TO_BOTTOM, LEFT_TO_RIGHT, - observer + observer, + DEFAULT_EDGE_TYPE, + DEFAULT_FINALLY_EDGE_TYPE } from '@patternfly/react-topology'; import pipelineComponentFactory, { GROUPED_EDGE_TYPE } from './pipelineComponentFactory'; import { useDemoPipelineNodes } from './useDemoPipelineNodes'; @@ -54,12 +55,12 @@ const TopologyPipelineLayout: React.FC = observer(() => { const nodes = [...pipelineNodes, ...spacerNodes]; const edgeType = pipelineOptions.showGroups ? GROUPED_EDGE_TYPE : DEFAULT_EDGE_TYPE; const edges = getEdgesFromNodes( - nodes.filter(n => !n.group), + nodes.filter((n) => !n.group), DEFAULT_SPACER_NODE_TYPE, edgeType, edgeType, [DEFAULT_FINALLY_NODE_TYPE], - edgeType + DEFAULT_FINALLY_EDGE_TYPE ); controller.fromModel( @@ -69,7 +70,9 @@ const TopologyPipelineLayout: React.FC = observer(() => { type: 'graph', x: 25, y: 25, - layout: `${pipelineOptions.showGroups ? GROUP_PREFIX : ''}${PIPELINE_LAYOUT}${pipelineOptions.verticalLayout ? VERTICAL_SUFFIX : ''}` + layout: `${pipelineOptions.showGroups ? GROUP_PREFIX : ''}${PIPELINE_LAYOUT}${ + pipelineOptions.verticalLayout ? VERTICAL_SUFFIX : '' + }` }, nodes, edges @@ -79,7 +82,7 @@ const TopologyPipelineLayout: React.FC = observer(() => { controller.getGraph().layout(); }, [controller, pipelineNodes, pipelineOptions.showGroups, pipelineOptions.verticalLayout]); - useEventListener(SELECTION_EVENT, ids => { + useEventListener(SELECTION_EVENT, (ids) => { setSelectedIds(ids); }); @@ -101,8 +104,9 @@ export const PipelineLayoutDemo = React.memo(() => { new PipelineDagreLayout(graph, { nodesep: PIPELINE_NODE_SEPARATION_VERTICAL, rankdir: type.endsWith(VERTICAL_SUFFIX) ? TOP_TO_BOTTOM : LEFT_TO_RIGHT, - ranksep: - type.startsWith(GROUP_PREFIX) ? GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL : NODE_SEPARATION_HORIZONTAL, + ranksep: type.startsWith(GROUP_PREFIX) + ? GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL + : NODE_SEPARATION_HORIZONTAL, ignoreGroups: true }) ); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineOptionsBar.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineOptionsBar.tsx index 7fddc6bf..d1b1ce51 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineOptionsBar.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineOptionsBar.tsx @@ -40,6 +40,14 @@ const PipelineOptionsBar: React.FC<{ isLayout?: boolean }> = observer(({ isLayou label="Context menus" /> + + pipelineOptions.setShowTerminalType(checked)} + label="Directional edges" + /> + {isLayout ? ( <> diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineTasksDemo.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineTasksDemo.tsx index 549f3cc0..94e858e9 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineTasksDemo.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineTasksDemo.tsx @@ -43,7 +43,7 @@ export const PipelineTasks: React.FC = observer(() => { ); }, [controller, pipelineNodes]); - useEventListener(SELECTION_EVENT, ids => { + useEventListener(SELECTION_EVENT, (ids) => { setSelectedIds(ids); }); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx index a33ef892..90dca5e7 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx @@ -15,11 +15,13 @@ import { withSelection, withPanZoom, GraphComponent, - TaskEdge + DEFAULT_FINALLY_EDGE_TYPE } from '@patternfly/react-topology'; import DemoTaskNode from './DemoTaskNode'; import DemoFinallyNode from './DemoFinallyNode'; import DemoTaskGroupEdge from './DemoTaskGroupEdge'; +import DemoFinallyTaskEdge from './DemoFinallyTaskEdge'; +import DemoTaskEdge from './DemoTaskEdge'; export const GROUPED_EDGE_TYPE = 'GROUPED_EDGE'; @@ -59,7 +61,9 @@ const pipelineComponentFactory: ComponentFactory = ( return SpacerNode; case 'finally-spacer-edge': case DEFAULT_EDGE_TYPE: - return TaskEdge; + return DemoTaskEdge; + case DEFAULT_FINALLY_EDGE_TYPE: + return DemoFinallyTaskEdge; case GROUPED_EDGE_TYPE: return DemoTaskGroupEdge; default: diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/useDemoPipelineNodes.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/useDemoPipelineNodes.tsx index ef18f00a..8daa5109 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/useDemoPipelineNodes.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/useDemoPipelineNodes.tsx @@ -6,7 +6,7 @@ import { DEFAULT_WHEN_SIZE, PipelineNodeModel, RunStatus, - WhenStatus, + WhenStatus } from '@patternfly/react-topology'; export const NODE_PADDING_VERTICAL = 45; @@ -147,7 +147,7 @@ export const useDemoPipelineNodes = ( tasks.push({ id: `group-parallels`, type: 'task-group', - children: parallelTasks.map(t => t.id), + children: parallelTasks.map((t) => t.id), group: true, label: 'Parallel tasks' }); @@ -176,7 +176,7 @@ export const useDemoPipelineNodes = ( const finallyGroup = { id: 'finally-group', type: 'finally-group', - children: finallyNodes.map(n => n.id), + children: finallyNodes.map((n) => n.id), group: true }; @@ -221,8 +221,8 @@ export const useDemoPipelineNodes = ( taskProgress: '3/4', taskType: 'java', taskTopic: 'Environment', - columnGroup: TASK_STATUSES.length % STATUS_PER_ROW + 1, - taskJobType: 'cubes', + columnGroup: (TASK_STATUSES.length % STATUS_PER_ROW) + 1, + taskJobType: 'cubes' }; if (!layout) { @@ -250,8 +250,8 @@ export const useDemoPipelineNodes = ( taskProgress: '3/4', taskType: 'java', taskTopic: 'Environment', - columnGroup: TASK_STATUSES.length % STATUS_PER_ROW + 1, - taskJobType: 'link', + columnGroup: (TASK_STATUSES.length % STATUS_PER_ROW) + 1, + taskJobType: 'link' }; if (!layout) { diff --git a/packages/module/src/components/edges/DefaultEdge.tsx b/packages/module/src/components/edges/DefaultEdge.tsx index 84bcee69..84171a82 100644 --- a/packages/module/src/components/edges/DefaultEdge.tsx +++ b/packages/module/src/components/edges/DefaultEdge.tsx @@ -101,7 +101,7 @@ const DefaultEdgeInner: React.FunctionComponent = observe className, selected, onSelect, - onContextMenu + onContextMenu, }) => { const [hover, hoverRef] = useHover(); const startPoint = element.getStartPoint(); diff --git a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx index 0c22d67e..87c6a46c 100644 --- a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx +++ b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx @@ -10,6 +10,7 @@ import ConnectorSquare from './ConnectorSquare'; import ConnectorCircle from './ConnectorCircle'; import ConnectorArrowAlt from './ConnectorArrowAlt'; import { StatusModifier } from '../../../utils'; +import Point from '../../../geom/Point'; interface EdgeConnectorArrowProps { edge: Edge; @@ -20,6 +21,8 @@ interface EdgeConnectorArrowProps { terminalType?: EdgeTerminalType; size?: number; dragRef?: ConnectDragSource; + startPoint?: Point; + endPoint?: Point; } const DefaultConnectorTerminal: React.FunctionComponent = ({ @@ -54,7 +57,9 @@ const DefaultConnectorTerminal: React.FunctionComponent return null; } const bendPoints = edge.getBendpoints(); - const startPoint = isTarget ? bendPoints[bendPoints.length - 1] || edge.getStartPoint() : bendPoints[0] || edge.getEndPoint(); + const startPoint = isTarget + ? edge.getBendpoints[bendPoints.length - 1] || edge.getStartPoint() + : bendPoints[0] || edge.getEndPoint(); const endPoint = isTarget ? edge.getEndPoint() : edge.getStartPoint(); const classes = css(styles.topologyEdge, className, StatusModifier[status]); diff --git a/packages/module/src/pipelines/components/edges/TaskEdge.tsx b/packages/module/src/pipelines/components/edges/TaskEdge.tsx index f40700cb..c6d1726b 100644 --- a/packages/module/src/pipelines/components/edges/TaskEdge.tsx +++ b/packages/module/src/pipelines/components/edges/TaskEdge.tsx @@ -2,9 +2,10 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { css } from '@patternfly/react-styles'; import styles from '../../../css/topology-components'; -import { Edge, GraphElement, isEdge } from '../../../types'; +import { Edge, EdgeTerminalType, GraphElement, NodeStatus, isEdge } from '../../../types'; import { integralShapePath } from '../../utils'; import { DagreLayoutOptions, TOP_TO_BOTTOM } from '../../../layouts'; +import { DefaultConnectorTerminal } from '../../../components'; interface TaskEdgeProps { /** The graph edge element to represent */ @@ -13,30 +14,75 @@ interface TaskEdgeProps { className?: string; /** Offset for integral shape path */ nodeSeparation?: number; + /** The terminal type to use for the edge start */ + startTerminalType?: EdgeTerminalType; + /** Additional classes added to the start terminal */ + startTerminalClass?: string; + /** The status to indicate on the start terminal */ + startTerminalStatus?: NodeStatus; + /** The size of the start terminal */ + startTerminalSize?: number; + /** The terminal type to use for the edge end */ + endTerminalType?: EdgeTerminalType; + /** Additional classes added to the end terminal */ + endTerminalClass?: string; + /** The status to indicate on the end terminal */ + endTerminalStatus?: NodeStatus; + /** The size of the end terminal */ + endTerminalSize?: number; } type TaskEdgeInnerProps = Omit & { element: Edge }; -const TaskEdgeInner: React.FunctionComponent = observer(({ - element, - className, - nodeSeparation }) => { - const startPoint = element.getStartPoint(); - const endPoint = element.getEndPoint(); - const groupClassName = css(styles.topologyEdge, className); - const startIndent: number = element.getData()?.indent || 0; - const verticalLayout = (element.getGraph().getLayoutOptions?.() as DagreLayoutOptions)?.rankdir === TOP_TO_BOTTOM; +const TaskEdgeInner: React.FunctionComponent = observer( + ({ + element, + startTerminalType = EdgeTerminalType.none, + startTerminalClass, + startTerminalStatus, + startTerminalSize = 14, + endTerminalType = EdgeTerminalType.none, + endTerminalClass, + endTerminalStatus, + endTerminalSize = 14, + className, + nodeSeparation + }) => { + const startPoint = element.getStartPoint(); + const endPoint = element.getEndPoint(); + const groupClassName = css(styles.topologyEdge, className); + const startIndent: number = element.getData()?.indent || 0; + const verticalLayout = (element.getGraph().getLayoutOptions?.() as DagreLayoutOptions)?.rankdir === TOP_TO_BOTTOM; - return ( - - - - ); -}); + return ( + + + + + + ); + } +); const TaskEdge: React.FunctionComponent = ({ element, ...rest }: TaskEdgeProps) => { if (!isEdge(element)) { diff --git a/packages/module/src/pipelines/const.ts b/packages/module/src/pipelines/const.ts index a987c4fd..1e8e8a21 100644 --- a/packages/module/src/pipelines/const.ts +++ b/packages/module/src/pipelines/const.ts @@ -10,3 +10,4 @@ export const DEFAULT_TASK_NODE_TYPE = 'DEFAULT_TASK_NODE'; export const DEFAULT_SPACER_NODE_TYPE = 'DEFAULT_SPACER_NODE'; export const DEFAULT_EDGE_TYPE = 'DEFAULT_EDGE'; export const DEFAULT_FINALLY_NODE_TYPE = 'DEFAULT_FINALLY_NODE'; +export const DEFAULT_FINALLY_EDGE_TYPE = 'DEFAULT_FINALLY_EDGE'; From 6480e465683bc48c083f00bd8efe766e2eb19e13 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Date: Tue, 19 Mar 2024 08:30:01 -0400 Subject: [PATCH 2/5] Fixes for arrow alignments --- .../src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx | 13 ------------- .../src/demos/pipelinesDemo/DemoTaskNode.tsx | 5 ++--- .../src/demos/pipelinesDemo/PipelineLayoutDemo.tsx | 9 +++++---- .../pipelinesDemo/pipelineComponentFactory.tsx | 11 ++++++----- .../components/anchors/TaskNodeTargetAnchor.ts | 4 ++-- packages/module/src/pipelines/utils/utils.ts | 2 +- 6 files changed, 16 insertions(+), 28 deletions(-) delete mode 100644 packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx deleted file mode 100644 index 46f40bf2..00000000 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoFinallyTaskEdge.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { EdgeTerminalType, GraphElement, TaskEdge } from '@patternfly/react-topology'; - -interface DemoFinallyTaskEdgeProps { - element: GraphElement; -} - -const DemoFinallyTaskEdge: React.FunctionComponent = (props) => ( - -); - -export default observer(DemoFinallyTaskEdge); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskNode.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskNode.tsx index b65815df..cadf46c7 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskNode.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskNode.tsx @@ -82,9 +82,8 @@ const DemoTaskNode: React.FunctionComponent = ({ badge={pipelineOptions.showBadges ? data.taskProgress : undefined} badgePopoverParams={pipelineOptions.showBadgeTooltips ? undefined : badgePopoverParams} badgeTooltip={pipelineOptions.showBadgeTooltips ? DEMO_TIP_TEXT : undefined} - hasWhenExpression={!!data.whenStatus} - whenOffset={DEFAULT_WHEN_OFFSET} - whenSize={DEFAULT_WHEN_SIZE} + whenOffset={data.whenStatus ? DEFAULT_WHEN_OFFSET : 0} + whenSize={data.whenStatus ? DEFAULT_WHEN_SIZE : 0} {...rest} > {whenDecorator} diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx index 8bcf6855..31ba093e 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/PipelineLayoutDemo.tsx @@ -23,7 +23,10 @@ import { DEFAULT_EDGE_TYPE, DEFAULT_FINALLY_EDGE_TYPE } from '@patternfly/react-topology'; -import pipelineComponentFactory, { GROUPED_EDGE_TYPE } from './pipelineComponentFactory'; +import pipelineComponentFactory, { + GROUPED_EDGE_TYPE, + SPACER_EDGE_TYPE +} from './pipelineComponentFactory'; import { useDemoPipelineNodes } from './useDemoPipelineNodes'; import { GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL } from './DemoTaskGroupEdge'; import { PipelineDemoContext, PipelineDemoModel } from './PipelineDemoContext'; @@ -31,8 +34,6 @@ import PipelineOptionsBar from './PipelineOptionsBar'; export const PIPELINE_NODE_SEPARATION_VERTICAL = 65; -export const LAYOUT_TITLE = 'Layout'; - const GROUP_PREFIX = 'Grouped_'; const VERTICAL_SUFFIX = '_Vertical'; const PIPELINE_LAYOUT = 'PipelineLayout'; @@ -58,7 +59,7 @@ const TopologyPipelineLayout: React.FC = observer(() => { nodes.filter((n) => !n.group), DEFAULT_SPACER_NODE_TYPE, edgeType, - edgeType, + SPACER_EDGE_TYPE, [DEFAULT_FINALLY_NODE_TYPE], DEFAULT_FINALLY_EDGE_TYPE ); diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx index 90dca5e7..970dca11 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/pipelineComponentFactory.tsx @@ -15,15 +15,16 @@ import { withSelection, withPanZoom, GraphComponent, - DEFAULT_FINALLY_EDGE_TYPE + DEFAULT_FINALLY_EDGE_TYPE, + TaskEdge } from '@patternfly/react-topology'; import DemoTaskNode from './DemoTaskNode'; import DemoFinallyNode from './DemoFinallyNode'; import DemoTaskGroupEdge from './DemoTaskGroupEdge'; -import DemoFinallyTaskEdge from './DemoFinallyTaskEdge'; import DemoTaskEdge from './DemoTaskEdge'; export const GROUPED_EDGE_TYPE = 'GROUPED_EDGE'; +export const SPACER_EDGE_TYPE = 'spacer-edge'; const contextMenuItem = (label: string, i: number): React.ReactElement => { if (label === '-') { @@ -59,11 +60,11 @@ const pipelineComponentFactory: ComponentFactory = ( return DefaultTaskGroup; case DEFAULT_SPACER_NODE_TYPE: return SpacerNode; - case 'finally-spacer-edge': + case SPACER_EDGE_TYPE: + return TaskEdge; + case DEFAULT_FINALLY_EDGE_TYPE: case DEFAULT_EDGE_TYPE: return DemoTaskEdge; - case DEFAULT_FINALLY_EDGE_TYPE: - return DemoFinallyTaskEdge; case GROUPED_EDGE_TYPE: return DemoTaskGroupEdge; default: diff --git a/packages/module/src/pipelines/components/anchors/TaskNodeTargetAnchor.ts b/packages/module/src/pipelines/components/anchors/TaskNodeTargetAnchor.ts index 3894b65f..3a585a84 100644 --- a/packages/module/src/pipelines/components/anchors/TaskNodeTargetAnchor.ts +++ b/packages/module/src/pipelines/components/anchors/TaskNodeTargetAnchor.ts @@ -28,8 +28,8 @@ export default class TaskNodeTargetAnchor extends Abstrac const scale = this.owner.getGraph().getScale(); return new Point(bounds.x + (this.lowDetailsStatusIconSize / 2 + 2) * (1 / scale), bounds.y); } - return new Point(bounds.x + bounds.width / 2, bounds.y); + return new Point(bounds.x + bounds.width / 2, bounds.y - this.whenOffset); } - return new Point(bounds.x + this.whenOffset, bounds.y + bounds.height / 2); + return new Point(bounds.x, bounds.y + bounds.height / 2); } } diff --git a/packages/module/src/pipelines/utils/utils.ts b/packages/module/src/pipelines/utils/utils.ts index d7a96ff8..4c60fb34 100644 --- a/packages/module/src/pipelines/utils/utils.ts +++ b/packages/module/src/pipelines/utils/utils.ts @@ -185,7 +185,7 @@ export const getEdgesFromNodes = ( finallyNodes.forEach(finallyNode => { edges.push({ id: `${finallyId}-${finallyNode.id}`, - type: spacerEdgeType, + type: finallyEdgeType, source: finallyId, target: finallyNode.id }); From afcc835f31fbdcb2a9c319bbe86e18fc601375d2 Mon Sep 17 00:00:00 2001 From: Jenny <32821331+jenny-s51@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:51:15 -0400 Subject: [PATCH 3/5] fix issue where arrow terminals didnt render with groups --- .../demos/pipelinesDemo/DemoTaskGroupEdge.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskGroupEdge.tsx b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskGroupEdge.tsx index bcc94f92..04496f46 100644 --- a/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskGroupEdge.tsx +++ b/packages/demo-app-ts/src/demos/pipelinesDemo/DemoTaskGroupEdge.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { GraphElement, TaskEdge } from '@patternfly/react-topology'; +import { Edge, EdgeTerminalType, GraphElement, TaskEdge } from '@patternfly/react-topology'; +import { PipelineDemoContext } from './PipelineDemoContext'; export const GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL = 200; @@ -8,8 +9,16 @@ interface DemoTaskEdgeProps { element: GraphElement; } -const DemoTaskGroupEdge: React.FunctionComponent = props => ( - -); +const DemoTaskGroupEdge: React.FunctionComponent = ({ element, ...props }) => { + const pipelineOptions = React.useContext(PipelineDemoContext); + return ( + + ); +}; export default observer(DemoTaskGroupEdge); From e7a40b4b16d207c4928153e0761a4a45e3b689c0 Mon Sep 17 00:00:00 2001 From: Jenny <32821331+jenny-s51@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:54:28 -0400 Subject: [PATCH 4/5] remove unused props add startpoint to fix build --- .../src/components/edges/terminals/DefaultConnectorTerminal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx index 87c6a46c..69e33495 100644 --- a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx +++ b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx @@ -22,7 +22,6 @@ interface EdgeConnectorArrowProps { size?: number; dragRef?: ConnectDragSource; startPoint?: Point; - endPoint?: Point; } const DefaultConnectorTerminal: React.FunctionComponent = ({ From bb805aebe4062e45388897727336061a0125dec5 Mon Sep 17 00:00:00 2001 From: Jenny <32821331+jenny-s51@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:23:24 -0400 Subject: [PATCH 5/5] update per Jeff feedback, use default start and endpoints if not passed into DefaultConnectorTerminal --- .../terminals/DefaultConnectorTerminal.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx index 69e33495..8fecc9d4 100644 --- a/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx +++ b/packages/module/src/components/edges/terminals/DefaultConnectorTerminal.tsx @@ -22,6 +22,7 @@ interface EdgeConnectorArrowProps { size?: number; dragRef?: ConnectDragSource; startPoint?: Point; + endPoint?: Point; } const DefaultConnectorTerminal: React.FunctionComponent = ({ @@ -30,6 +31,8 @@ const DefaultConnectorTerminal: React.FunctionComponent isTarget = true, terminalType, status, + startPoint, + endPoint, ...others }) => { let Terminal; @@ -56,13 +59,21 @@ const DefaultConnectorTerminal: React.FunctionComponent return null; } const bendPoints = edge.getBendpoints(); - const startPoint = isTarget - ? edge.getBendpoints[bendPoints.length - 1] || edge.getStartPoint() - : bendPoints[0] || edge.getEndPoint(); - const endPoint = isTarget ? edge.getEndPoint() : edge.getStartPoint(); + const defaultStartPoint = isTarget + ? edge.getBendpoints[bendPoints.length - 1] || edge.getStartPoint() + : bendPoints[0] || edge.getEndPoint(); + const defaultEndPoint = isTarget ? edge.getEndPoint() : edge.getStartPoint(); const classes = css(styles.topologyEdge, className, StatusModifier[status]); - return ; + return ( + + ); }; export default observer(DefaultConnectorTerminal);