[WIP POC] Add Phase 2 case-management node manifests and LoopNode header UI#938
[WIP POC] Add Phase 2 case-management node manifests and LoopNode header UI#938kittyyueli wants to merge 13 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Dependency License Review
License distribution
Excluded packages
|
There was a problem hiding this comment.
Pull request overview
Extends the canvas “case management” visual language by adding Phase 2 node manifests (stages, tasks, rules, lifecycle nodes) and enhances LoopNode to render a richer header (description + rule chips) for stage-like loop containers.
Changes:
- Added Phase 2 case-flow manifests + categories, along with schema-validation tests.
- Enhanced
LoopNodeheader to support a secondary row with instance-supplied description text and rule summary chips. - Added a Storybook canvas story demonstrating an end-to-end case-flow graph using the new node types.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/apollo-react/src/canvas/components/LoopNode/LoopNodeHeaderChips.tsx | New chip renderer for loop headers (rule counts + status pills). |
| packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts | Adds headerChips config prop for LoopNode. |
| packages/apollo-react/src/canvas/components/LoopNode/LoopNode.tsx | Renders optional description + chips beneath the title in the loop header. |
| packages/apollo-react/src/canvas/components/LoopNode/LoopNode.test.tsx | Adds tests covering header chips/description rendering and precedence behavior. |
| packages/apollo-react/src/canvas/components/LoopNode/index.ts | Exports the new header chips component. |
| packages/apollo-react/src/canvas/components/CaseFlow/index.ts | Re-exports new manifests and sizing constants for case-flow consumers. |
| packages/apollo-react/src/canvas/components/CaseFlow/CaseFlowCanvas.stories.tsx | New Storybook story showcasing a complete case flow with Phase 2 nodes. |
| packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts | Adds Phase 2 node/category manifests and sizing constants. |
| packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.test.ts | New tests validating manifests against schemas and key invariants. |
| packages/apollo-react/src/canvas/components/BaseNode/BaseNode.types.ts | Extends display data shape with description for canvas rendering. |
| export interface LoopNodeConfig { | ||
| toolbarConfig?: NodeToolbarConfig | null; | ||
| adornments?: NodeAdornments; | ||
| executionStatusOverride?: ElementStatusValues; | ||
| suggestionType?: SuggestionType; | ||
| iterationPillState?: LoopNodeExecutionCountState; | ||
| /** | ||
| * Rule chips rendered in a wrapping row under the header title (entry / exit / | ||
| * completion counts, Optional / Ends case pills). Same chip model as StageNode's | ||
| * `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`; | ||
| * this prop wins when both are set. | ||
| */ | ||
| headerChips?: StageHeaderChip[]; | ||
| } |
| const testId = `loop-header-chip-${chip.type}`; | ||
| const ariaLabel = | ||
| (typeof chip.tooltip === 'string' ? chip.tooltip : undefined) ?? label ?? chip.type; | ||
|
|
📊 Coverage + size by packagePer-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.
"Coverage" is each package's own |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:38
- The PR description mentions a
headerDescriptionprop onLoopNode, but the code only supports instance-supplied descriptions viadata.display.description(and there is noheaderDescriptionprop inLoopNodeConfig). Either add the prop (with the same precedence behavior asheaderChips) or update the PR description to match the implemented API.
/**
* Rule chips rendered in a wrapping row under the header title (entry / exit /
* completion counts, Optional / Ends case pills). Same chip model as StageNode's
* `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`;
* this prop wins when both are set.
*/
headerChips?: StageHeaderChip[];
| // ============================================================================ | ||
| // Header Chips — rule chips, wrapped titles, and description text in the | ||
| // loop header (the case-management "stage" flavor of the loop container). |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.stories.tsx:1519
- This Storybook file uses an em dash (
—) in the section header comment. The repo guideline for Storybook content avoids em dashes; please replace with a period/colon for consistency.
// ============================================================================
// Header Chips — rule chips, wrapped titles, and description text in the
// loop header (the case-management "stage" flavor of the loop container).
// ============================================================================
| const rendered = chip.onClick ? ( | ||
| <button | ||
| type="button" | ||
| data-testid={testId} | ||
| aria-label={ariaLabel} | ||
| className={className} | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| chip.onClick?.(); | ||
| }} | ||
| > | ||
| {content} | ||
| </button> | ||
| ) : ( | ||
| <span data-testid={testId} role="img" aria-label={ariaLabel} className={className}> | ||
| {content} | ||
| </span> | ||
| ); |
| showButton: true, | ||
| constraints: { | ||
| forbiddenTargetCategories: ['case-management-trigger'], | ||
| }, | ||
| }, |
| showButton: true, | ||
| constraints: { | ||
| forbiddenTargetCategories: ['case-management-trigger'], | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/LoopNode/LoopNodeHeaderChips.tsx:96
- The non-interactive chip renders as a even though it contains text (label/count).
role="img"is intended for images and can make screen reader output confusing; a plain with an aria-label is sufficient here.
<span data-testid={testId} role="img" aria-label={ariaLabel} className={className}>
{content}
</span>
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:38
- The PR description mentions a
headerDescriptionprop onLoopNode, but the implementation only sources description text fromdata.display.description(and there is noheaderDescriptionconfig prop). Either add the missing prop/override or update the PR description to match the actual API surface.
/**
* Rule chips rendered in a wrapping row under the header title (entry / exit /
* completion counts, Optional / Ends case pills). Same chip model as StageNode's
* `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`;
* this prop wins when both are set.
*/
headerChips?: StageHeaderChip[];
| import type { StageHeaderChip } from '../StageNode/StageNode.types'; | ||
| import type { NodeToolbarConfig } from '../Toolbar'; | ||
|
|
||
| export type LoopNodeData = BaseNodeData; |
| * Longer descriptive text for the node. Container/loop nodes render it as a | ||
| * muted secondary line under the header title; other nodes may surface it in | ||
| * tooltips or panels. |
| /** | ||
| * Default diameter for the small rule / event / adhoc marker circles. | ||
| * 64px is the smallest square BaseNode supports for a node with one handle per | ||
| * side: its minimum-height rule reserves a 2-grid lane per left/right handle | ||
| * plus 2 grid spaces of padding ((1 * 2 + 2) * 16px). Anything smaller gets its | ||
| * height forced back up, which renders as an oval instead of a circle. | ||
| */ | ||
| export const CASE_MARKER_NODE_SIZE = 64; |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (3)
packages/apollo-react/src/canvas/components/LoopNode/LoopNodeHeaderChips.tsx:96
- Non-clickable chips render as a , which is not an appropriate role for a text/count chip, and it also can’t receive keyboard focus. When a tooltip is provided, keyboard users won’t be able to discover it. Consider removing role="img" and making the span focusable when chip.tooltip is present (and prevent drag/pan for tooltip interactions).
<span data-testid={testId} role="img" aria-label={ariaLabel} className={className}>
{content}
</span>
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:38
- PR description mentions a LoopNode
headerDescriptionprop for canvas-level customization, but LoopNodeConfig currently only exposesheaderChips. IfheaderDescriptionis intended, it should be added to the public props and documented precedence should mirrorheaderChips(prop wins over node data).
headerChips?: StageHeaderChip[];
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:40
- PR description mentions 48px marker circles, but CASE_MARKER_NODE_SIZE is 64 (with a rationale in the comment explaining BaseNode’s minimum sizing). Please align the PR description, or change the implementation only if 48px is a hard requirement.
export const CASE_MARKER_NODE_SIZE = 64;
| iterationPillState: iterationPillStateProp, | ||
| headerChips: headerChipsProp, | ||
| } = props; |
| // Only instance-supplied descriptions render on the canvas. Manifest-level | ||
| // `display.description` stays add-panel/tooltip copy so existing loop nodes | ||
| // keep their compact single-row header. | ||
| const headerDescription = (resolvedData.display as { description?: string } | undefined) | ||
| ?.description; |
| * Phase 2 (POC): stage (container/loop-based), tasks (sequential square, event and | ||
| * adhoc circle markers), and case complete / case exit lifecycle circles. Every | ||
| * case rule is representable as a handle, a node, or an edge: |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.stories.tsx:1518
- This story file introduces an em dash (
—) in the section header comment.CLAUDE.mdforbids using—in.stories.tsxfiles (often enforced via a simple text scan), so this may fail repo checks even though it's in a comment.
Replace the em dash with a colon/period.
// Header Chips — rule chips, wrapped titles, and description text in the
// loop header (the case-management "stage" flavor of the loop container).
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.tsx:261
- PR description mentions a
headerDescriptionprop onLoopNodefor canvas-level customization, but the implementation only derivesdescriptionfromdata.display.description(and passes it toHeader). If consumers need a prop-level override (similar toheaderChips), it should be added toLoopNodeConfigand take precedence overdata.display.description.
Alternatively, update the PR description to match the implemented API.
const headerChips =
headerChipsProp ??
(Array.isArray(resolvedData.headerChips)
? (resolvedData.headerChips as StageHeaderChip[])
: undefined);
// Only instance-supplied descriptions render on the canvas. Manifest-level
// `display.description` stays add-panel/tooltip copy so existing loop nodes
// keep their compact single-row header.
const headerDescription = (resolvedData.display as { description?: string } | undefined)
?.description;
| /** Default diameter for the big lifecycle circles (trigger, case complete/exit). */ | ||
| export const CASE_LIFECYCLE_NODE_SIZE = 96; | ||
| /** | ||
| * Diameter for the event / adhoc task marker circles. The regular BaseNode | ||
| * size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry | ||
| * is the only way it reliably renders as a true circle, because BaseNode owns | ||
| * its own minimum-height math and fights any smaller explicit size. | ||
| */ | ||
| export const CASE_MARKER_NODE_SIZE = 96; |
| it('has no dedicated stage-level rule nodes: rules are edges', () => { | ||
| const ruleNodes = caseFlowManifest.nodes.filter((n) => | ||
| n.nodeType.startsWith('uipath.case.rule.') | ||
| ); | ||
| expect(ruleNodes).toHaveLength(0); | ||
| }); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.stories.tsx:1517
- Storybook guidance in this repo avoids using an em dash with spaces (
—). This comment header introduces one; please replace it with punctuation (e.g., a colon) to keep story documentation consistent.
// Header Chips — rule chips, wrapped titles, and description text in the
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:39
- PR description mentions marker circles as 48px, but
CASE_MARKER_NODE_SIZEis set to 96 (same as lifecycle circles) and the comment explains why smaller explicit sizes don't render correctly. Please align the PR description and code so consumers know the intended size contract (either update the PR description or change the implementation if 48px is truly required).
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the event / adhoc task marker circles. The regular BaseNode
* size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry
* is the only way it reliably renders as a true circle, because BaseNode owns
* its own minimum-height math and fights any smaller explicit size.
*/
export const CASE_MARKER_NODE_SIZE = 96;
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:643
- PR description lists additional Phase 2 manifests (e.g., entry/complete/exit rule condition node manifests), but the combined
caseFlowManifest.nodesonly includes trigger, stage, task, event/adhoc markers, and case complete/exit. If those rule node manifests are intentionally out of scope, please update the PR description; otherwise they appear to be missing from this manifest bundle.
export const caseFlowManifest = {
version: '1.0.0',
categories: caseFlowCategories,
nodes: [
caseManagementTriggerManifest,
caseStageManifest,
caseTaskManifest,
caseEventMarkerManifest,
caseAdhocMarkerManifest,
caseCompleteManifest,
caseExitManifest,
],
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (4)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:38
- The PR description mentions a
headerDescriptionprop onLoopNode, but the config type only exposesheaderChips. If consumers need canvas-level control (and consistent precedence rules), addheaderDescription?: stringand document that it overridesdata.display.descriptionwhen both are set.
* completion counts, Optional / Ends case pills). Same chip model as StageNode's
* `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`;
* this prop wins when both are set.
*/
headerChips?: StageHeaderChip[];
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.tsx:198
- If
headerDescriptionis meant to be supported (per PR description), it needs to be plumbed from props inLoopNodeComponentso it can override the instance data description when desired.
suggestionType: suggestionTypeProp,
iterationPillState: iterationPillStateProp,
headerChips: headerChipsProp,
} = props;
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.tsx:261
headerDescriptionis currently derived only fromdata.display.description. To match the intended API and precedence model (prop wins when both are set), computeheaderDescriptionusing the prop first.
// Only instance-supplied descriptions render on the canvas. Manifest-level
// `display.description` stays add-panel/tooltip copy so existing loop nodes
// keep their compact single-row header.
const headerDescription = (resolvedData.display as { description?: string } | undefined)
?.description;
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.test.ts:40
- The PR description calls out dedicated stage-level rule manifests (e.g. entry/complete/exit rule nodes), but this test asserts there are no
uipath.case.rule.*node types and that stage-level rules are edges. Please align the PR description with the implementation direction (or drop this assertion if rule nodes are intended after all).
it('has no dedicated stage-level rule nodes: rules are edges', () => {
const ruleNodes = caseFlowManifest.nodes.filter((n) =>
n.nodeType.startsWith('uipath.case.rule.')
);
expect(ruleNodes).toHaveLength(0);
| import type { CategoryManifest, NodeManifest } from '../../schema/node-definition'; | ||
|
|
||
| /** Default diameter for the big lifecycle circles (trigger, case complete/exit). */ | ||
| export const CASE_LIFECYCLE_NODE_SIZE = 96; | ||
| /** | ||
| * Diameter for the event / adhoc task marker circles. The regular BaseNode | ||
| * size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry | ||
| * is the only way it reliably renders as a true circle, because BaseNode owns | ||
| * its own minimum-height math and fights any smaller explicit size. | ||
| */ | ||
| export const CASE_MARKER_NODE_SIZE = 96; |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:39
- PR description mentions a
headerDescriptionprop on LoopNode, but LoopNodeConfig only introducesheaderChips. Currently the description is sourced fromdata.display.description(instance data) rather than a prop. Please align either the implementation (addheaderDescription?: stringand wire it similarly toheaderChips) or update the PR description to match the actual API.
export interface LoopNodeConfig {
toolbarConfig?: NodeToolbarConfig | null;
adornments?: NodeAdornments;
executionStatusOverride?: ElementStatusValues;
suggestionType?: SuggestionType;
iterationPillState?: LoopNodeExecutionCountState;
/**
* Rule chips rendered in a wrapping row under the header title (entry / exit /
* completion counts, Optional / Ends case pills). Same chip model as StageNode's
* `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`;
* this prop wins when both are set.
*/
headerChips?: StageHeaderChip[];
}
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:39
- PR description says marker circles are 48px, but CASE_MARKER_NODE_SIZE is set to 96 (and the comment explains why). Please align the PR description with the implementation, or (if 48px is required) revisit the BaseNode sizing constraint and update both the constant and rendering approach.
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the event / adhoc task marker circles. The regular BaseNode
* size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry
* is the only way it reliably renders as a true circle, because BaseNode owns
* its own minimum-height math and fights any smaller explicit size.
*/
export const CASE_MARKER_NODE_SIZE = 96;
| /** | ||
| * Container nodes only: walls this handle's label pill may be dragged along | ||
| * (grid-snapped, kept clear of corners). Omit to keep the handle fixed. | ||
| * The drag writes per-node offsets into `data.handleOffsets`. | ||
| */ |
| /** | ||
| * Minimum distance from the container top for handles on the side walls, so a | ||
| * dragged handle never collides with the header area. | ||
| */ | ||
| export const HANDLE_DRAG_TOP_MARGIN_PX = 112; |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:12
- PR description lists dedicated stage-level rule node manifests (e.g.
caseEntryRuleManifest,caseCompleteRuleManifest,caseExitRuleManifest), but this implementation explicitly models stage-level rules as edges/handles (andcase-flow.manifest.test.tsasserts there are nouipath.case.rule.*nodes). Please align the PR description with the implemented approach to avoid confusing reviewers/consumers.
* Phase 2 (POC): stage (container/loop-based), tasks (sequential square, event and
* adhoc circle markers), and case complete / case exit lifecycle circles. Every
* case rule is representable as a handle, a node, or an edge:
* - the stage's INNER handles carry the labeled lifecycle, Enter / Complete /
* Exit, mapping 1:1 onto the loop node's start / continue / break; the outer
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:35
- PR description mentions exporting size constants with 48px marker circles, but
CASE_MARKER_NODE_SIZEis set to 96 here (and the comment explains why smaller sizes break the circle rendering). Please sync the PR description with the actual constant value/behavior, or adjust the implementation if 48px markers are required.
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the event / adhoc task marker circles. The regular BaseNode
* size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry
| window.addEventListener('pointermove', onPointerMove); | ||
| window.addEventListener('pointerup', onPointerUp); | ||
| pillDragCleanupRef.current = () => { | ||
| window.removeEventListener('pointermove', onPointerMove); | ||
| window.removeEventListener('pointerup', onPointerUp); | ||
| pillDragCleanupRef.current = null; | ||
| }; |
…ader Adds a Tailwind chip row (reusing the StageNode StageHeaderChip model: entry/exit/completion/return-to-origin icon chips plus Optional and Ends case status pills) under the LoopNode title, accepted via the new headerChips config prop or per-node data.headerChips. The title now wraps to two lines instead of hard-truncating, and an instance-supplied display.description renders as a muted secondary line. This lets the loop container double as the case-management stage visual. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
Extends the CaseFlow module beyond the phase 1 trigger with the full case-management node set, all manifest-driven: - uipath.case.stage: loop container stage. Outer handles map loop semantics to the stage lifecycle (enter = loop start, complete = loop end, exit = loop break); inner handles (onEnter, entryRules, completeRules, exitRules) receive the sequential task chain and rule circles. - uipath.case.task: square task node; incoming edges are sequential run rules. - uipath.case.task.event / uipath.case.task.adhoc: small circle markers (event icon / play icon) that start event-based and manual tasks. - uipath.case.rule.entry|complete|exit: small circle rule conditions constrained to the stage's matching inner handle. - uipath.case.complete / uipath.case.exit: big lifecycle circles fed by stage complete/exit handles. Each node carries a FormSchema so properties panels render flow-config style. Adds schema validation tests and an InsuranceClaim storybook story demonstrating the whole visual language, and documents the new display.description field on BaseNodeData. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
Focused story for the new LoopNode header API: rule chips with counts and tooltips, Optional and Ends case status pills, two-line wrapped titles, and the instance-supplied description line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…arker circle size Design revision from POC review: - Rule circles no longer live inside the stage wired to dedicated inner rule handles. They sit OUTSIDE on the transitions: entry rules feed the stage's enter handle; complete/exit rules are fed by the stage's complete/exit handles and gate the next stage or the case lifecycle. A rule circle on the edge between two stages is the cross-stage dependency rule. Inside the stage only tasks and task-level event / adhoc markers remain. - Stage inner handles reduce to the loop pair: onEnter starts the sequential task chain, onComplete terminates it. - Trigger output may feed entry rule circles. - CASE_MARKER_NODE_SIZE bumped 48 -> 64: BaseNode's minimum-height rule reserves (handles * 2 + 2) grid spaces, so 48px markers were forced taller and rendered as ovals; 64px is the smallest true circle. - InsuranceClaim story and manifest tests updated to the new grammar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
The stage's INNER handles now carry the labeled lifecycle, matching the loop node's start / continue / break one to one: Enter (starts the sequential task chain), Complete (tasks that finish the stage), and a new Exit handle (tasks that abandon the stage). The outer enter / complete / exit handles keep their ids for edge wiring and rule circle constraints but drop their labels, so the outer boundary reads like a regular loop container. The InsuranceClaim story wires Escalate to expert into the inner Exit handle to demonstrate the loop-break path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…nner lifecycle handles Three POC design refinements: - Dedicated stage-level rule circle nodes (uipath.case.rule.entry / complete / exit) are removed: drawn as nodes they read as out-of-place work items. The transitions themselves carry the rules (edge into enter = entry rule, edges leaving complete/exit = complete/exit rules), summarized by the header chips and configured via edge/stage properties. The one exception: event-based complete/exit rules are event circles (uipath.case.task.event) INSIDE the stage wired into the inner Complete / Exit handles. - The stage's inner Exit handle moves to the bottom inner wall, so the inner lifecycle reads Enter (left) -> Complete (right) / Exit (bottom), mapping onto loop start / continue / break. - New alwaysVisible flag on handle group manifests: LoopNode renders such groups (and their labels) at all times instead of only on hover / selection. The stage's three inner lifecycle handles use it. InsuranceClaim story, manifest tests, and LoopNode tests updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…marker circles - New alwaysVisible flag on handle group manifests: LoopNode renders such groups (and their labels) at all times instead of only on hover / selection / while connecting. The stage's inner lifecycle groups use it, so Enter / Complete / Exit labels are permanently visible. - Inner handles line up with the outer ones: Enter (single, left inner wall) faces the outer enter handle; Complete and Exit share one right inner group so their vertical positions mirror the outer complete / exit pair (handle distribution is count-based, so equal counts per side align). - Event / adhoc marker circles use the regular 96px BaseNode size. Smaller explicit sizes fight BaseNode's own minimum-height math and render as ovals; standard geometry guarantees true circles. Manifest tests assert the alignment invariant; LoopNode tests cover the alwaysVisible behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…stages New display.showModePill flag on node manifests (default true). When false, LoopNode omits the Sequential / Parallel iteration-mode pill from the header. The case stage manifest sets it: stages have no iteration mode, so the pill was noise in the top-right corner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…r with Complete New slotCount option on handle group manifests: the group lays out as if it had that many handle slots, with handles filling slots from the first. This lets a group with fewer handles align with a fuller group on the opposite wall. The case stage uses slotCount 2 on both left groups, so the single enter / Enter handles sit level with complete / Complete (the first slot of the right wall pair) at any stage size. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
Prototype of user-movable stage lifecycle handles: - New per-handle manifest fields: draggableWalls (walls the handle's label pill may be dragged along) and dragMirrors (id of the sibling handle, typically the outer counterpart, that follows the dragged wall + offset so the inner/outer pair stays glued). - The inward label pill becomes the drag grip (nodrag/nopan, grab cursor). The drag projects the pointer onto the nearest allowed wall, snaps to the 16px grid, and keeps 48px clear of every corner (112px from the top on side walls, clearing the header). - Dragged positions persist per node in data.handleOffsets and are applied by re-bucketing the resolved handle groups: a moved handle renders in a synthetic single-handle group on its wall with an explicit offsetPx that bypasses the slot distribution. Edges follow automatically via the existing updateNodeInternals refresh. - Case stage wiring: Enter drags along the left wall only; Complete and Exit roam the right and bottom walls, each mirroring its outer handle. Covered by drag-math and re-bucketing unit tests, LoopNode grip tests, and manifest constraint tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
…eparation The side-wall top clamp for dragged lifecycle pills now derives from the measured header height, so the pill keeps the same clearance from the dashed body frame's top edge as the corner margin gives it from the bottom edge, even when a description or chips grow the header. Pills on the same wall now keep a minimum 32px center-to-center separation: a drag onto an occupied slot settles on the nearest free grid slot, and sibling positions (dragged offsets or default slot distribution) are collected via the new collectOccupiedWallOffsets helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
ef80445 to
0974a20
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.types.ts:38
- The PR description mentions a
headerDescriptionprop onLoopNode, but the publicLoopNodeConfigtype only exposesheaderChipsand the implementation reads the description only fromdata.display.description. Either add theheaderDescription?: stringprop (and make it override node data, similar toheaderChips) or update the PR description to match the implemented API.
adornments?: NodeAdornments;
executionStatusOverride?: ElementStatusValues;
suggestionType?: SuggestionType;
iterationPillState?: LoopNodeExecutionCountState;
/**
* Rule chips rendered in a wrapping row under the header title (entry / exit /
* completion counts, Optional / Ends case pills). Same chip model as StageNode's
* `stageDetails.headerChips`. Can also be supplied per-node via `data.headerChips`;
* this prop wins when both are set.
*/
headerChips?: StageHeaderChip[];
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:39
- The PR description says marker circles are 48px, but
CASE_MARKER_NODE_SIZEis set to 96 (same as lifecycle circles). If 96 is intentional (as the comment suggests), the PR description should be updated; otherwise, adjust the constant (and any dependent layout) to match 48.
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the event / adhoc task marker circles. The regular BaseNode
* size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry
* is the only way it reliably renders as a true circle, because BaseNode owns
* its own minimum-height math and fights any smaller explicit size.
*/
export const CASE_MARKER_NODE_SIZE = 96;
| */ | ||
| export type LoopNodeHeaderChip = StageHeaderChip; | ||
|
|
||
| const CHIP_ICONS: Partial<Record<StageHeaderChipType, React.ReactElement>> = { |
…o 64px The header-derived side-wall top clamp now sits one grid step higher (bottom clearance minus 16px), letting the pill reach closer to the dashed frame's top edge. The same-wall minimum separation grows from 32px to 64px center-to-center so the pills themselves never overlap, including on the bottom wall where they sit side by side along their wider horizontal axis. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
packages/apollo-react/src/canvas/components/LoopNode/LoopNode.stories.tsx:1519
- Avoid using an em dash with spaces (
—) in Storybook story files. Replace it with a period (or colon) to match the repository guideline for story copy/comments.
// ============================================================================
// Header Chips — rule chips, wrapped titles, and description text in the
// loop header (the case-management "stage" flavor of the loop container).
// ============================================================================
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:39
- PR description mentions exporting size constants with marker circles at 48px, but CASE_MARKER_NODE_SIZE is set to 96 here (same as lifecycle). Please reconcile which is intended (update PR description or change the constant + any rendering logic so 48px markers remain circular).
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the event / adhoc task marker circles. The regular BaseNode
* size (96px, DEFAULT_NODE_SIZE): letting the node use its standard geometry
* is the only way it reliably renders as a true circle, because BaseNode owns
* its own minimum-height math and fights any smaller explicit size.
*/
export const CASE_MARKER_NODE_SIZE = 96;
…me handles Adds a 'marker' handle variant to the canvas handle schema and ButtonHandle: a small circular icon badge on the node boundary, with an optional label and no inline add button. useButtonHandles now honors group-level alwaysVisible so markers render without hover, matching the LoopNode container behavior. The case task's event / manual (adhoc) start rules move onto the task itself as data-driven marker handles (zap / play on the top wall, toggled by inputs.eventTrigger / inputs.manualTrigger, labeled from inputs.triggerLabel) instead of separate circle nodes. The adhoc marker node type is removed and the event circle is narrowed to stage-level complete / exit rules only. Story, manifest tests and ButtonHandle tests updated to the new shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
packages/apollo-react/src/canvas/components/LoopNode/LoopNodeHeaderChips.tsx:61
aria-labelis currently derived from tooltip/label/type and does not includechip.count. Because the chip setsaria-label(and the non-interactive variant also usesrole="img"), screen readers will not announce the count, so users can’t perceive the rule totals via assistive tech. Consider folding the count into the accessible name when present (unless a string tooltip already supplies it).
const testId = `loop-header-chip-${chip.type}`;
const ariaLabel =
(typeof chip.tooltip === 'string' ? chip.tooltip : undefined) ?? label ?? chip.type;
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:660
- The PR description lists additional Phase 2 manifests (e.g. adhoc marker, entry/complete/exit rule condition circles), but this combined manifest only includes stage/task/event marker/complete/exit. Either add the missing manifests or update the PR description to match what’s actually shipped in this PR.
nodes: [
caseManagementTriggerManifest,
caseStageManifest,
caseTaskManifest,
caseEventMarkerManifest,
caseCompleteManifest,
caseExitManifest,
],
packages/apollo-react/src/canvas/components/CaseFlow/case-flow.manifest.ts:41
- The PR description mentions marker circles being 48px, but
CASE_MARKER_NODE_SIZEis exported as 96 here. If 96 is intentional (per comment), the PR description should be updated; otherwise adjust the constant and any consumers accordingly.
/** Default diameter for the big lifecycle circles (trigger, case complete/exit). */
export const CASE_LIFECYCLE_NODE_SIZE = 96;
/**
* Diameter for the stage-rule event circles. The regular BaseNode size (96px,
* DEFAULT_NODE_SIZE): letting the node use its standard geometry is the only
* way it reliably renders as a true circle, because BaseNode owns its own
* minimum-height math and fights any smaller explicit size.
*/
export const CASE_MARKER_NODE_SIZE = 96;
Summary
Extends the case-management visual language with Phase 2 node types and UI enhancements. Adds manifests for stages (loop containers), tasks, rule conditions, and case lifecycle nodes. Introduces header chips and description text rendering in LoopNode to surface rule summaries and stage metadata on the canvas.
Key Changes
New node manifests for case-management Phase 2:
caseStageManifest: Loop container with outer lifecycle handles (enter/complete/exit) and inner rule/task handlescaseTaskManifest: Sequential work units with input/output handlescaseEventMarkerManifest&caseAdhocMarkerManifest: Small circle markers for event-based and manual task entrycaseEntryRuleManifest,caseCompleteRuleManifest,caseExitRuleManifest: Rule condition circles targeting stage inner handlescaseCompleteManifest&caseExitManifest: Big lifecycle circles for case completion/exit rulesNew categories for stages, tasks, rules, and case lifecycle with distinct colors and icons
LoopNode header enhancements:
LoopNodeHeaderChipscomponent renders rule summary chips (entry/completion/exit counts) with iconsdescriptiontext in node data, rendered below the titleheaderChipsandheaderDescriptionon LoopNode for canvas-level customizationSize constants exported for consistent node sizing (96px for lifecycle circles, 48px for marker circles)
Comprehensive test coverage for manifest validation and LoopNode header rendering
Storybook story demonstrating a complete insurance claim case flow with all node types, handle connections, and rule dependencies
Implementation Details
StageHeaderChip/StageHeaderChipTypemodel for consistency with existing stage-style consumersdisplay.descriptionremains for add-panel/tooltip copy; only instance-supplied descriptions render on canvas to keep existing loop nodes compacthttps://claude.ai/code/session_01JFSpmppW6EZYWUDQVS1SKr