From 280ca91f1db1ae594a5ff5a5605deff71c40e436 Mon Sep 17 00:00:00 2001 From: Jeff Phillips Date: Fri, 7 Jun 2024 15:42:55 -0400 Subject: [PATCH] feat(group labels): Add ability to show group labels on hover (#214) --- .../pipelineGroupsDemo/DemoTaskGroup.tsx | 43 ++++----- .../demos/topologyPackageDemo/DemoGroup.tsx | 1 + .../src/components/groups/DefaultGroup.tsx | 2 + .../groups/DefaultGroupExpanded.tsx | 80 +++++++++-------- .../components/groups/DefaultTaskGroup.tsx | 2 + .../groups/DefaultTaskGroupExpanded.tsx | 89 +++++++++++-------- 6 files changed, 119 insertions(+), 98 deletions(-) diff --git a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx index 348f182..330e7f5 100644 --- a/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx +++ b/packages/demo-app-ts/src/demos/pipelineGroupsDemo/DemoTaskGroup.tsx @@ -12,10 +12,6 @@ import { EdgeCreationTypes, useHover, ScaleDetailsLevel, - DEFAULT_LAYER, - Layer, - TOP_LAYER, - GROUPS_LAYER, RunStatus } from '@patternfly/react-topology'; import { DEFAULT_TASK_HEIGHT, GROUP_TASK_WIDTH } from './createDemoPipelineGroupsNodes'; @@ -38,29 +34,26 @@ const DemoTaskGroup: React.FunctionComponent = ({ element, . if (!isNode(element)) { return null; } - const groupLayer = element.isCollapsed() ? DEFAULT_LAYER : GROUPS_LAYER; return ( - - - - - + + + ); }; diff --git a/packages/demo-app-ts/src/demos/topologyPackageDemo/DemoGroup.tsx b/packages/demo-app-ts/src/demos/topologyPackageDemo/DemoGroup.tsx index bc6b0db..7116ccc 100644 --- a/packages/demo-app-ts/src/demos/topologyPackageDemo/DemoGroup.tsx +++ b/packages/demo-app-ts/src/demos/topologyPackageDemo/DemoGroup.tsx @@ -58,6 +58,7 @@ const DemoGroup: React.FunctionComponent = ({ element, onContext collapsedHeight={DEFAULT_NODE_SIZE} showLabel={detailsLevel === ScaleDetailsLevel.high} hulledOutline={options.hulledOutline} + showLabelOnHover > {groupElement.isCollapsed() ? renderIcon() : null} diff --git a/packages/module/src/components/groups/DefaultGroup.tsx b/packages/module/src/components/groups/DefaultGroup.tsx index 0108e91..c0633ca 100644 --- a/packages/module/src/components/groups/DefaultGroup.tsx +++ b/packages/module/src/components/groups/DefaultGroup.tsx @@ -32,6 +32,8 @@ interface DefaultGroupProps { secondaryLabel?: string; /** Flag to show the label */ showLabel?: boolean; // Defaults to true + /** Flag to show the label when hovering (effects expanded only) */ + showLabelOnHover?: boolean; /** Position of the label, top or bottom. Defaults to element.getLabelPosition() or bottom */ labelPosition?: LabelPosition; /** The maximum length of the label before truncation */ diff --git a/packages/module/src/components/groups/DefaultGroupExpanded.tsx b/packages/module/src/components/groups/DefaultGroupExpanded.tsx index ce4e4c0..39e7d2a 100644 --- a/packages/module/src/components/groups/DefaultGroupExpanded.tsx +++ b/packages/module/src/components/groups/DefaultGroupExpanded.tsx @@ -31,6 +31,7 @@ type DefaultGroupExpandedProps = { label?: string; // Defaults to element.getLabel() secondaryLabel?: string; showLabel?: boolean; // Defaults to true + showLabelOnHover?: boolean; truncateLength?: number; // Defaults to 13 badge?: string; badgeColor?: string; @@ -119,6 +120,7 @@ const DefaultGroupExpanded: React.FunctionComponent = label, secondaryLabel, showLabel = true, + showLabelOnHover, truncateLength, dndDropRef, droppable, @@ -141,11 +143,11 @@ const DefaultGroupExpanded: React.FunctionComponent = onCollapseChange, hulledOutline = true }) => { - const [hovered, hoverRef] = useHover(); - const [labelHover, labelHoverRef] = useHover(); + const [hovered, hoverRef] = useHover(200, 500); + const [labelHover, labelHoverRef] = useHover(0); const dragLabelRef = useDragNode()[1]; const refs = useCombineRefs(hoverRef, dragNodeRef); - const isHover = hover !== undefined ? hover : hovered; + const isHover = hover !== undefined ? hover : hovered || labelHover; const anchorRef = useSvgAnchor(); const outlineRef = useCombineRefs(dndDropRef, anchorRef); const labelLocation = React.useRef(); @@ -239,8 +241,46 @@ const DefaultGroupExpanded: React.FunctionComponent = ? labelLocation.current[1] - outlinePadding - labelGap * 2 : labelLocation.current[1] + outlinePadding + labelGap; + const scale = element.getGraph().getScale(); + const medScale = element.getGraph().getDetailsLevelThresholds().medium; + const labelScale = !showLabel && showLabelOnHover && isHover ? Math.min(1 / scale, 1 / medScale) : 1; + const labelPositionScale = 1 / labelScale; + + const groupLabel = + (showLabel || (showLabelOnHover && isHover)) && (label || element.getLabel()) ? ( + + : undefined} + onActionIconClick={() => onCollapseChange(element, true)} + > + {label || element.getLabel()} + + + ) : null; + return ( - + {hulledOutline ? ( @@ -256,38 +296,8 @@ const DefaultGroupExpanded: React.FunctionComponent = /> )} + {groupLabel && isHover ? {groupLabel} : groupLabel} - {showLabel && (label || element.getLabel()) && ( - - : undefined} - onActionIconClick={() => onCollapseChange(element, true)} - > - {label || element.getLabel()} - - - )} ); }; diff --git a/packages/module/src/pipelines/components/groups/DefaultTaskGroup.tsx b/packages/module/src/pipelines/components/groups/DefaultTaskGroup.tsx index 41f323f..d55647c 100644 --- a/packages/module/src/pipelines/components/groups/DefaultTaskGroup.tsx +++ b/packages/module/src/pipelines/components/groups/DefaultTaskGroup.tsx @@ -46,6 +46,8 @@ export interface DefaultTaskGroupProps { scaleNode?: boolean; /** Flag to hide details at medium scale */ hideDetailsAtMedium?: boolean; + /** Flag to show the label when hovering and details are hidden (effects expanded only) */ + showLabelOnHover?: boolean; /** Flag if the user is hovering on the node */ hover?: boolean; /** Label for the node. Defaults to element.getLabel() */ diff --git a/packages/module/src/pipelines/components/groups/DefaultTaskGroupExpanded.tsx b/packages/module/src/pipelines/components/groups/DefaultTaskGroupExpanded.tsx index 45baefd..5fbc37a 100644 --- a/packages/module/src/pipelines/components/groups/DefaultTaskGroupExpanded.tsx +++ b/packages/module/src/pipelines/components/groups/DefaultTaskGroupExpanded.tsx @@ -7,7 +7,7 @@ import NodeLabel from '../../../components/nodes/labels/NodeLabel'; import { Layer } from '../../../components/layers'; import { GROUPS_LAYER, TOP_LAYER } from '../../../const'; import { maxPadding, useCombineRefs, useHover } from '../../../utils'; -import { AnchorEnd, isGraph, LabelPosition, Node, NodeStyle } from '../../../types'; +import { AnchorEnd, isGraph, LabelPosition, Node, NodeStyle, ScaleDetailsLevel } from '../../../types'; import { useAnchor, useDragNode } from '../../../behavior'; import { DagreLayoutOptions, TOP_TO_BOTTOM } from '../../../layouts'; import TaskGroupSourceAnchor from '../anchors/TaskGroupSourceAnchor'; @@ -26,6 +26,8 @@ const DefaultTaskGroupExpanded: React.FunctionComponent { - const [hovered, hoverRef] = useHover(); - const [labelHover, labelHoverRef] = useHover(); + const [hovered, hoverRef] = useHover(200, 500); + const [labelHover, labelHoverRef] = useHover(0); const dragLabelRef = useDragNode()[1]; const refs = useCombineRefs(hoverRef, dragNodeRef); - const isHover = hover !== undefined ? hover : hovered; + const isHover = hover !== undefined ? hover : hovered || labelHover; const verticalLayout = (element.getGraph().getLayoutOptions?.() as DagreLayoutOptions)?.rankdir === TOP_TO_BOTTOM; const groupLabelPosition = labelPosition ?? element.getLabelPosition() ?? LabelPosition.bottom; let parent = element.getParent(); + const detailsLevel = element.getGraph().getDetailsLevel(); let altGroup = false; while (!isGraph(parent)) { altGroup = !altGroup; @@ -121,12 +124,53 @@ const DefaultTaskGroupExpanded: React.FunctionComponent + : undefined} + onActionIconClick={() => onCollapseChange(element, true)} + > + {label || element.getLabel()} + + + ) : null; + return ( - + + {groupLabel && isHover ? {groupLabel} : groupLabel} - {showLabel && (label || element.getLabel()) && ( - - : undefined} - onActionIconClick={() => onCollapseChange(element, true)} - > - {label || element.getLabel()} - - - )} ); }