From cd11ffaa9aa77dadba009e942e42d2771cea1fe1 Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 17 Jul 2026 09:00:36 -0400 Subject: [PATCH 1/5] feat(apollo-react): don't change node shape when collapsed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolveDisplay squared a rectangle node whenever it was collapsed (getCollapsedShape). Agents were the only collapsible nodes, and design wants them to keep their footprint when collapsed — only hide artifacts and show the stacked affordance. Collapsing now never changes a node's shape. Removes getCollapsedShape and the shape-squaring branch in resolveDisplay; isStacked and artifact-handle hiding are unaffected. --- packages/apollo-react/src/canvas/utils/collapse.ts | 8 -------- .../src/canvas/utils/manifest-resolver.test.ts | 6 +++--- .../src/canvas/utils/manifest-resolver.ts | 11 ++++------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/packages/apollo-react/src/canvas/utils/collapse.ts b/packages/apollo-react/src/canvas/utils/collapse.ts index faf759193..e4fd2fc72 100644 --- a/packages/apollo-react/src/canvas/utils/collapse.ts +++ b/packages/apollo-react/src/canvas/utils/collapse.ts @@ -18,14 +18,6 @@ export const COLLAPSED_NODE_SIZE = 96; */ export const EXPANDED_RECTANGLE_WIDTH = 288; -/** - * Transform a shape to its collapsed form. - * Rectangle nodes collapse to square, other shapes remain unchanged. - */ -export const getCollapsedShape = (originalShape?: NodeShape): NodeShape | undefined => { - return originalShape === 'rectangle' ? 'square' : originalShape; -}; - /** * Transform a collapsed shape back to its expanded form. * Square nodes expand to rectangle (since rectangle → square when collapsing). diff --git a/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts b/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts index 9ccb6dfa6..badc840a8 100644 --- a/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts +++ b/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts @@ -43,15 +43,15 @@ describe('resolveDisplay', () => { expect(result.shape).toBe('square'); }); - it('collapses rectangle to square when isCollapsed is true', () => { + it('keeps a rectangle shape when collapsed (collapse never squares the node)', () => { const result = resolveDisplay( { label: 'Agent', icon: 'bot', shape: 'rectangle' }, { isCollapsed: true } ); - expect(result.shape).toBe('square'); + expect(result.shape).toBe('rectangle'); }); - it('preserves non-rectangle shapes when collapsed', () => { + it('keeps non-rectangle shapes when collapsed', () => { const result = resolveDisplay( { label: 'Node', icon: 'box', shape: 'circle' }, { isCollapsed: true } diff --git a/packages/apollo-react/src/canvas/utils/manifest-resolver.ts b/packages/apollo-react/src/canvas/utils/manifest-resolver.ts index 7c19ceab0..f06a018f7 100644 --- a/packages/apollo-react/src/canvas/utils/manifest-resolver.ts +++ b/packages/apollo-react/src/canvas/utils/manifest-resolver.ts @@ -14,7 +14,6 @@ import type { HandleActionEvent, HandleMouseEvent } from '../components/ButtonHa import type { HandleGroupManifest, HandleManifest } from '../schema/node-definition/handle'; import type { NodeDisplayManifest } from '../schema/node-definition/node-manifest'; import type { InstanceDisplayConfig } from '../schema/node-instance'; -import { getCollapsedShape } from './collapse'; /** * Context object passed to resolution functions @@ -110,11 +109,9 @@ export function resolveDisplay( } as ResolvedDisplay; } - const isCollapsed = context?.isCollapsed ?? false; - const shape = context?.display?.shape ?? manifestDisplay.shape; - - const collapsedShape = getCollapsedShape(shape); - const expandedShape = manifestDisplay.shape; + // Collapsing a node hides its artifacts and shows the stacked affordance, but + // never changes its shape — the node keeps its footprint whether expanded or + // collapsed. // Resolve the canvas chip label. // @@ -140,7 +137,7 @@ export function resolveDisplay( label: resolvedLabel, canvasLabel: context?.display?.canvasLabel ?? manifestDisplay.canvasLabel, icon: context?.display?.icon ?? manifestDisplay.icon ?? '', - shape: isCollapsed ? collapsedShape : expandedShape, + shape: manifestDisplay.shape, }; } From 945523aa37037217a1863242f15cc9471737082d Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 17 Jul 2026 09:00:37 -0400 Subject: [PATCH 2/5] docs(apollo-react): demo a collapsed rectangle keeping its shape in the Stacked Treatment story --- .../components/BaseNode/BaseNode.stories.tsx | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx b/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx index 28a76c7c4..2d3274023 100644 --- a/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx +++ b/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx @@ -1967,6 +1967,30 @@ const stackedManifest: { nodes: NodeManifest[]; categories: CategoryManifest[] } }, ], }, + { + // A collapsed rectangle keeps its shape: it stays a wide pill AND shows the + // stacked layer, rather than shrinking to a square (collapse never squares). + nodeType: 'uipath.agent.rectangle', + version: '1.0.0', + category: 'agents', + tags: ['agent'], + sortOrder: 1, + display: { + label: 'Rectangle Agent', + icon: 'agent', + shape: 'rectangle', + }, + handleConfiguration: [ + { + position: 'left', + handles: [{ id: 'input', type: 'target', handleType: 'input' }], + }, + { + position: 'right', + handles: [{ id: 'output', type: 'source', handleType: 'output' }], + }, + ], + }, ], }; @@ -2004,6 +2028,17 @@ function StackedTreatmentStory() { isCollapsed: true, }, }), + createNode({ + id: 'collapsed-rectangle', + type: 'uipath.agent.rectangle', + position: { x: 768, y: 200 }, + data: { + nodeType: 'uipath.agent.rectangle', + version: '1.0.0', + display: { label: 'Collapsed Rectangle', subLabel: 'stays a pill', shape: 'rectangle' }, + isCollapsed: true, + }, + }), ], [] ); @@ -2016,7 +2051,7 @@ function StackedTreatmentStory() { ); From 6bd41e9115e5bf1b28c31e7e630c8faa97c64198 Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 17 Jul 2026 10:36:32 -0400 Subject: [PATCH 3/5] fix(apollo-react): honor instance display.shape override in resolveDisplay Addresses review: the shape was pinned to manifestDisplay.shape, dropping instance/node-data display.shape overrides. Resolve it from context.display.shape ?? manifestDisplay.shape (collapse still never changes it). Also drops spaced em dashes from the Stacked Treatment story copy. --- .../src/canvas/components/BaseNode/BaseNode.stories.tsx | 2 +- .../src/canvas/utils/manifest-resolver.test.ts | 8 ++++++++ .../apollo-react/src/canvas/utils/manifest-resolver.ts | 9 +++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx b/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx index 2d3274023..2e0552406 100644 --- a/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx +++ b/packages/apollo-react/src/canvas/components/BaseNode/BaseNode.stories.tsx @@ -2051,7 +2051,7 @@ function StackedTreatmentStory() { ); diff --git a/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts b/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts index badc840a8..b9ca59f81 100644 --- a/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts +++ b/packages/apollo-react/src/canvas/utils/manifest-resolver.test.ts @@ -59,6 +59,14 @@ describe('resolveDisplay', () => { expect(result.shape).toBe('circle'); }); + it('honors an instance display.shape override', () => { + const result = resolveDisplay( + { label: 'Node', icon: 'box', shape: 'square' }, + { display: { shape: 'circle' } } + ); + expect(result.shape).toBe('circle'); + }); + it('uses manifest canvasLabel for canvas label when no instance override', () => { const result = resolveDisplay({ label: 'Send Outlook Email', diff --git a/packages/apollo-react/src/canvas/utils/manifest-resolver.ts b/packages/apollo-react/src/canvas/utils/manifest-resolver.ts index f06a018f7..784995e33 100644 --- a/packages/apollo-react/src/canvas/utils/manifest-resolver.ts +++ b/packages/apollo-react/src/canvas/utils/manifest-resolver.ts @@ -109,9 +109,10 @@ export function resolveDisplay( } as ResolvedDisplay; } - // Collapsing a node hides its artifacts and shows the stacked affordance, but - // never changes its shape — the node keeps its footprint whether expanded or - // collapsed. + // Shape comes from the instance override (if any) or the manifest. Collapsing + // never changes it: a collapsed node hides its artifacts and shows the stacked + // affordance but keeps its footprint. + const shape = context?.display?.shape ?? manifestDisplay.shape; // Resolve the canvas chip label. // @@ -137,7 +138,7 @@ export function resolveDisplay( label: resolvedLabel, canvasLabel: context?.display?.canvasLabel ?? manifestDisplay.canvasLabel, icon: context?.display?.icon ?? manifestDisplay.icon ?? '', - shape: manifestDisplay.shape, + shape, }; } From 5fb1d029502accde96a0f8725cc646ee1944617a Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 17 Jul 2026 11:30:49 -0400 Subject: [PATCH 4/5] refactor(apollo-react): remove unused getCollapsedSize and getExpandedShape With collapse no longer tied to shape, these helpers are dead in apollo. collapse.ts now holds only the node default-sizing helper (getExpandedSize) and its size constants. --- .../apollo-react/src/canvas/utils/collapse.ts | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/packages/apollo-react/src/canvas/utils/collapse.ts b/packages/apollo-react/src/canvas/utils/collapse.ts index e4fd2fc72..a691c621a 100644 --- a/packages/apollo-react/src/canvas/utils/collapse.ts +++ b/packages/apollo-react/src/canvas/utils/collapse.ts @@ -1,47 +1,25 @@ /** - * Collapse/Expand Transformation Helpers + * Node sizing helpers. * - * Utilities for transforming node dimensions and shapes between collapsed and expanded states. - * These helpers ensure consistent behavior across the codebase. + * Default pixel dimensions for a node based on its shape, used when a node has + * no measured size yet (creation, layout). */ import type { NodeShape } from '../schema/node-definition'; import { DEFAULT_CONTAINER_HEIGHT, DEFAULT_CONTAINER_WIDTH } from './container'; /** - * Default dimension for collapsed nodes when no measured dimensions are available. + * Default square dimension for a node with no explicit size. */ export const COLLAPSED_NODE_SIZE = 96; /** - * Default width for expanded rectangle nodes. + * Default width for a rectangle (pill) node. */ export const EXPANDED_RECTANGLE_WIDTH = 288; /** - * Transform a collapsed shape back to its expanded form. - * Square nodes expand to rectangle (since rectangle → square when collapsing). - * Other shapes remain unchanged. - */ -export const getExpandedShape = (collapsedShape?: NodeShape): NodeShape | undefined => { - return collapsedShape === 'square' ? 'rectangle' : (collapsedShape ?? undefined); -}; - -/** - * Calculate the collapsed size (square) from original dimensions. - * Uses height as the basis for the square dimension. - */ -export const getCollapsedSize = (): { width: number; height: number } => { - return { - width: COLLAPSED_NODE_SIZE, - height: COLLAPSED_NODE_SIZE, - }; -}; - -/** - * Calculate the expanded size from original dimensions stored in ui.size. - * This is the inverse of getCollapsedSize - it restores the original dimensions - * when expanding a collapsed node. + * Default size for a node of the given shape. */ export const getExpandedSize = (shape?: NodeShape): { width: number; height: number } => { if (shape === 'container') { From d97bbed3b08ccaa462d544d04e6c2eddd25b18da Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 17 Jul 2026 13:07:59 -0400 Subject: [PATCH 5/5] refactor(apollo-react): rename collapse.ts to node-size.ts The file only holds the shape to default-size helper now (getExpandedSize), not collapse logic. Renamed for clarity; export names kept so consumers (flow-workbench) don't break. BREAKING CHANGE: getCollapsedShape, getCollapsedSize, and getExpandedShape are removed from the public canvas/utils API. They only supported the removed collapse-to-shape tying (collapse no longer changes a node's shape). getExpandedSize and the size constants are unaffected. --- .../components/AddNodePanel/AddNodeManager.helpers.test.ts | 2 +- .../canvas/components/AddNodePanel/AddNodeManager.helpers.ts | 2 +- packages/apollo-react/src/canvas/hooks/useCanvasNodeLayout.ts | 2 +- packages/apollo-react/src/canvas/utils/index.ts | 2 +- .../apollo-react/src/canvas/utils/{collapse.ts => node-size.ts} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename packages/apollo-react/src/canvas/utils/{collapse.ts => node-size.ts} (100%) diff --git a/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.test.ts b/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.test.ts index a92f827ca..07d0ad4f2 100644 --- a/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.test.ts +++ b/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.test.ts @@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'; import { PREVIEW_NODE_ID } from '../../constants'; import type { NodeLayout } from '../../hooks/useCanvasNodeLayout'; import type { NodeShape } from '../../schema/node-definition'; -import { getExpandedSize } from '../../utils/collapse'; +import { getExpandedSize } from '../../utils/node-size'; import { getContainerFitGeometry, getNodeDimensions } from '../../utils/container'; import { placeAddedNode } from './AddNodeManager.helpers'; diff --git a/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.ts b/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.ts index bdab36b8b..4ca4e6abb 100644 --- a/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.ts +++ b/packages/apollo-react/src/canvas/components/AddNodePanel/AddNodeManager.helpers.ts @@ -5,7 +5,7 @@ import type { NodeLayout } from '../../hooks/useCanvasNodeLayout'; import type { PreviewNodeConnectionInfo } from '../../hooks/usePreviewNode'; import type { NodeManifest } from '../../schema'; import { resolveCollisions } from '../../utils'; -import { getExpandedSize } from '../../utils/collapse'; +import { getExpandedSize } from '../../utils/node-size'; import { CONTAINER_SEQUENCE_GAP_PX, collectLinearDownstreamSiblings, diff --git a/packages/apollo-react/src/canvas/hooks/useCanvasNodeLayout.ts b/packages/apollo-react/src/canvas/hooks/useCanvasNodeLayout.ts index a5208f262..c31e6ff1f 100644 --- a/packages/apollo-react/src/canvas/hooks/useCanvasNodeLayout.ts +++ b/packages/apollo-react/src/canvas/hooks/useCanvasNodeLayout.ts @@ -2,7 +2,7 @@ import type { Node } from '@uipath/apollo-react/canvas/xyflow/react'; import { useCallback, useMemo } from 'react'; import { useOptionalNodeTypeRegistry } from '../core'; import type { NodeManifest } from '../schema/node-definition'; -import { getExpandedSize } from '../utils/collapse'; +import { getExpandedSize } from '../utils/node-size'; import { type ContainerFitGeometry, getContainerFitGeometry as getDefaultContainerFitGeometry, diff --git a/packages/apollo-react/src/canvas/utils/index.ts b/packages/apollo-react/src/canvas/utils/index.ts index 978251d7f..b565838e7 100644 --- a/packages/apollo-react/src/canvas/utils/index.ts +++ b/packages/apollo-react/src/canvas/utils/index.ts @@ -4,7 +4,7 @@ export * from './CanvasEventBus'; export * from './CssUtil'; export * from './coded-agents/d3-layout'; export * from './coded-agents/mermaid-parser'; -export * from './collapse'; +export * from './node-size'; export * from './constraint-validator'; export * from './container'; export * from './createPreviewGraph'; diff --git a/packages/apollo-react/src/canvas/utils/collapse.ts b/packages/apollo-react/src/canvas/utils/node-size.ts similarity index 100% rename from packages/apollo-react/src/canvas/utils/collapse.ts rename to packages/apollo-react/src/canvas/utils/node-size.ts