From 57b04bdfd56f731d61d146db70a7118527290993 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Date: Wed, 5 Jun 2024 08:41:53 -0400 Subject: [PATCH] feat(group label): Add ability to center the group's label on the edge --- .eslintignore | 2 +- .../pipelineGroupsDemo/DemoTaskGroup.tsx | 1 + .../createDemoPipelineGroupsNodes.ts | 12 +- .../module/src/components/ElementWrapper.tsx | 11 +- .../src/components/nodes/labels/NodeLabel.tsx | 22 ++-- .../anchors/TaskGroupSourceAnchor.ts | 8 +- .../anchors/TaskGroupTargetAnchor.ts | 8 +- .../components/groups/DefaultTaskGroup.tsx | 2 + .../groups/DefaultTaskGroupExpanded.tsx | 118 +++++++++++------- .../pipelines/components/nodes/TaskNode.tsx | 1 - 10 files changed, 116 insertions(+), 69 deletions(-) diff --git a/.eslintignore b/.eslintignore index 9dc2eded..f1667eff 100644 --- a/.eslintignore +++ b/.eslintignore @@ -11,7 +11,7 @@ coverage .eslintcache generated *.d.ts -*/css/*.js +**/css/*.js # package managers yarn-error.log diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx index 330e7f50..f7c5100e 100644 --- a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx @@ -43,6 +43,7 @@ const DemoTaskGroup: React.FunctionComponent = ({ element, . collapsedWidth={GROUP_TASK_WIDTH} collapsedHeight={DEFAULT_TASK_HEIGHT} element={element as Node} + centerLabelOnEdge recreateLayoutOnCollapseChange getEdgeCreationTypes={getEdgeCreationTypes} scaleNode={hover && detailsLevel !== ScaleDetailsLevel.high} diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts index e4fdb067..582f0a54 100644 --- a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/createDemoPipelineGroupsNodes.ts @@ -155,7 +155,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[ height: DEFAULT_TASK_HEIGHT, group: true, style: { - padding: [NODE_PADDING_VERTICAL, NODE_PADDING_HORIZONTAL] + padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, runAfterTasks: [task_3_1.id], data: { @@ -386,7 +386,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [ 'metadata', 'training-configurator-and-validator' ], - style: { padding: [15, 15] }, + style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, data: {} }, { @@ -420,7 +420,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [ 'model', 'model-upload' ], - style: { padding: [15, 15] }, + style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, data: {} }, { @@ -519,7 +519,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [ 'model-evaluation-import', 'table-to-uri' ], - style: { padding: [15, 15] }, + style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, data: {} }, { @@ -748,7 +748,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [ 'get-prediction-image-uri-2', 'model-upload-2' ], - style: { padding: [15, 15] }, + style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, data: {} }, { @@ -797,7 +797,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [ 'model-evaluation-import-2', 'table-to-uri-2' ], - style: { padding: [15, 15] }, + style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] }, data: {} }, { diff --git a/packages/module/src/components/ElementWrapper.tsx b/packages/module/src/components/ElementWrapper.tsx index c693f7d4..e93002e1 100644 --- a/packages/module/src/components/ElementWrapper.tsx +++ b/packages/module/src/components/ElementWrapper.tsx @@ -9,6 +9,7 @@ import { useDndManager } from '../behavior/useDndManager'; interface ElementWrapperProps { element: Graph | Edge | Node; + level?: number; // used for groups to set z-index keeping child groups drawn on top of their parent. } const NodeElementComponent: React.FunctionComponent<{ element: Node }> = observer(({ element }) => { @@ -44,7 +45,7 @@ const ElementComponent: React.FunctionComponent = observer( return null; }); -const ElementChildren: React.FunctionComponent = observer(({ element }) => ( +const ElementChildren: React.FunctionComponent = observer(({ element, level }) => ( <> {element .getChildren() @@ -56,12 +57,12 @@ const ElementChildren: React.FunctionComponent = observer(( .getChildren() .filter(isNode) .map((e) => ( - + ))} )); -const ElementWrapper: React.FunctionComponent = observer(({ element }) => { +const ElementWrapper: React.FunctionComponent = observer(({ element, level = 0 }) => { if (!element.isVisible()) { if (!isNode(element) || element.isDimensionsInitialized()) { return null; @@ -116,9 +117,9 @@ const ElementWrapper: React.FunctionComponent = observer(({ ); } return ( - + - + ); }); diff --git a/packages/module/src/components/nodes/labels/NodeLabel.tsx b/packages/module/src/components/nodes/labels/NodeLabel.tsx index 6ded2743..c464e686 100644 --- a/packages/module/src/components/nodes/labels/NodeLabel.tsx +++ b/packages/module/src/components/nodes/labels/NodeLabel.tsx @@ -19,6 +19,8 @@ type NodeLabelProps = { x?: number; y?: number; position?: LabelPosition; + centerLabelOnEdge?: boolean; + boxRef?: React.Ref; cornerRadius?: number; status?: NodeStatus; secondaryLabel?: string; @@ -54,6 +56,7 @@ const NodeLabel: React.FunctionComponent = ({ x = 0, y = 0, position = LabelPosition.bottom, + centerLabelOnEdge, secondaryLabel, status, badge, @@ -76,6 +79,7 @@ const NodeLabel: React.FunctionComponent = ({ actionIcon, actionIconClassName, onActionIconClick, + boxRef, ...other }) => { const [labelHover, labelHoverRef] = useHover(); @@ -123,26 +127,26 @@ const NodeLabel: React.FunctionComponent = ({ const primaryWidth = iconSpace + badgeSpace + paddingX + textSize.width + actionSpace + contextSpace + paddingX; const secondaryWidth = secondaryLabel && secondaryTextSize ? secondaryTextSize.width + 2 * paddingX : 0; const width = Math.max(primaryWidth, secondaryWidth); + const backgroundHeight = + height + (secondaryLabel && secondaryTextSize ? secondaryTextSize.height + paddingY * 2 : 0); let startX: number; let startY: number; if (position === LabelPosition.top) { startX = x - width / 2; - startY = -y - height - paddingY; + startY = -y - height - (centerLabelOnEdge ? -backgroundHeight / 2 : paddingY); } else if (position === LabelPosition.right) { - startX = x + iconSpace; + startX = x + iconSpace - (centerLabelOnEdge ? width / 2 : 0); startY = y - height / 2; } else if (position === LabelPosition.left) { - startX = -width - paddingX; - startY = y - height / 2 + paddingY; + startX = centerLabelOnEdge ? x - width / 2 : -width - paddingX; + startY = y - height / 2; } else { startX = x - width / 2 + iconSpace / 2; - startY = y; + startY = y - (centerLabelOnEdge ? backgroundHeight / 2 : 0); } const actionStartX = iconSpace + badgeSpace + paddingX + textSize.width + paddingX; const contextStartX = actionStartX + actionSpace; - const backgroundHeight = - height + (secondaryLabel && secondaryTextSize ? secondaryTextSize.height + paddingY * 2 : 0); let badgeStartX = 0; let badgeStartY = 0; if (badgeSize) { @@ -183,6 +187,7 @@ const NodeLabel: React.FunctionComponent = ({ contextSize, secondaryLabel, secondaryTextSize, + centerLabelOnEdge, position, x, y @@ -200,8 +205,9 @@ const NodeLabel: React.FunctionComponent = ({ {textSize && ( (hoverRef, dragNodeRef); const isHover = hover !== undefined ? hover : hovered || labelHover; const verticalLayout = (element.getGraph().getLayoutOptions?.() as DagreLayoutOptions)?.rankdir === TOP_TO_BOTTOM; @@ -62,13 +64,44 @@ const DefaultTaskGroupExpanded: React.FunctionComponent new TaskGroupSourceAnchor(node, verticalLayout), [verticalLayout]), + React.useCallback( + (node: Node) => + new TaskGroupSourceAnchor( + node, + verticalLayout, + labelShown && + ((centerLabelOnEdge && labelPosition === LabelPosition.bottom && verticalLayout) || + (labelPosition === LabelPosition.right && !verticalLayout)) && + labelSize + ? anchorOffset + : 0 + ), + [labelShown, anchorOffset, centerLabelOnEdge, labelPosition, labelSize, verticalLayout] + ), AnchorEnd.source ); useAnchor( - React.useCallback((node: Node) => new TaskGroupTargetAnchor(node, verticalLayout), [verticalLayout]), + React.useCallback( + (node: Node) => + new TaskGroupTargetAnchor( + node, + verticalLayout, + labelShown && + ((centerLabelOnEdge && labelPosition === LabelPosition.top && verticalLayout) || + (labelPosition === LabelPosition.left && !verticalLayout)) && + labelSize + ? anchorOffset + : 0 + ), + [labelShown, anchorOffset, centerLabelOnEdge, labelPosition, labelSize, verticalLayout] + ), AnchorEnd.target ); @@ -96,14 +129,16 @@ const DefaultTaskGroupExpanded: React.FunctionComponent - : undefined} - onActionIconClick={() => onCollapseChange(element, true)} - > - {label || element.getLabel()} - - - ) : null; + const groupLabel = labelShown ? ( + + : undefined} + onActionIconClick={() => onCollapseChange(element, true)} + > + {label || element.getLabel()} + + + ) : null; return ( diff --git a/packages/module/src/pipelines/components/nodes/TaskNode.tsx b/packages/module/src/pipelines/components/nodes/TaskNode.tsx index f84be8cb..1f484268 100644 --- a/packages/module/src/pipelines/components/nodes/TaskNode.tsx +++ b/packages/module/src/pipelines/components/nodes/TaskNode.tsx @@ -299,7 +299,6 @@ const TaskNodeInner: React.FC = observer( showStatusState, leadSize, leadIcon, - customStatusIcon, statusSize, badgeSize, badge,