Skip to content

feat: add xyflow#4170

Closed
jog1t wants to merge 1 commit into02-10-feat_add_ladlefrom
02-11-feat_add_xyflow
Closed

feat: add xyflow#4170
jog1t wants to merge 1 commit into02-10-feat_add_ladlefrom
02-11-feat_add_xyflow

Conversation

@jog1t
Copy link
Contributor

@jog1t jog1t commented Feb 10, 2026

Description

Added a workflow visualization component using XYFlow to render workflow history data as interactive node graphs. This implementation includes:

  • Custom node types for different workflow entry types (step, loop, sleep, message, etc.)
  • Support for nested structures like loops and parallel branches
  • Visual indicators for node status (completed, running, failed, retrying)
  • Duration display and timing gaps between nodes
  • Dark theme styling for all XYFlow components

The implementation includes example data for various workflow patterns (linear, loops, joins, races) and Ladle stories to showcase each node type and complete workflow examples.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Tested through Ladle stories that demonstrate:

  • Individual node types with different statuses
  • Simple linear workflows
  • Workflows with loops
  • Workflows with parallel branches (join)
  • Workflows with racing branches
  • Complex workflows with multiple patterns
  • In-progress, retrying, and failed workflows

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4170 February 10, 2026 23:01 Destroyed
@railway-app
Copy link

railway-app bot commented Feb 10, 2026

🚅 Deployed to the rivet-pr-4170 environment in rivet-frontend

Service Status Web Updated (UTC)
website 😴 Sleeping (View Logs) Web Feb 18, 2026 at 5:18 am
frontend-inspector ❌ Build Failed (View Logs) Web Feb 11, 2026 at 12:15 am
frontend-cloud ❌ Build Failed (View Logs) Web Feb 11, 2026 at 12:15 am
ladle ✅ Success (View Logs) Web Feb 11, 2026 at 12:15 am
mcp-hub ✅ Success (View Logs) Web Feb 10, 2026 at 11:02 pm

Copy link
Contributor Author

jog1t commented Feb 10, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@jog1t jog1t mentioned this pull request Feb 10, 2026
6 tasks
@jog1t jog1t self-assigned this Feb 10, 2026
@jog1t jog1t marked this pull request as ready for review February 10, 2026 23:04
@claude
Copy link

claude bot commented Feb 10, 2026

PR #4170 Review: feat: add xyflow

This PR replaces a custom SVG-based workflow visualizer (~1,882 lines) with an XYFlow (React Flow) implementation. The refactor is a solid improvement in interactivity and maintainability. Here are issues and observations worth addressing before merge.


Bugs

1. Branch name matching can produce false positives (workflow-to-xyflow.ts:336)

Using includes to filter branch child items is fragile. If branch names like "a" and "a-extra" coexist, items from a-extra would match the filter for a. Use startsWith with the full parent path instead:

// Current (fragile)
const branchItems = nested.filter((ni) => ni.key.includes(`/${name}/`));
// Better
const branchItems = nested.filter((ni) => ni.key.startsWith(`${item.key}/${name}/`));

2. sortByLocation unsafe cast (workflow-to-xyflow.ts:125)

The last location element can be a LoopIterationMarker object, not just a number. Casting it as number will silently produce NaN comparisons when sorting nested items. The function should guard against object-typed segments or only be called on arrays guaranteed to end with a number.

3. Dead regex in getDisplayName (workflow-to-xyflow.ts:54)

parts is already the result of key.split("/"), so the last element never contains /. The regex /^~\d+\// can never match and is dead code. This was carried over from the old implementation.

4. datacenter changed from undefined to "" in inspector mode (create-actor-dialog.tsx:44)

Passing an empty string is semantically different from undefined — the API may interpret "" as an invalid datacenter ID rather than "not specified". The PR description does not explain this change. If it fixes a bug, add a comment; if incidental, revert to undefined.


Code Quality

5. Type assertion workaround in makeChildNode (workflow-to-xyflow.ts:191)

(node as XYNode & { parentId: string }).parentId = parentId;
(node as XYNode & { extent: string }).extent = "parent";

Define a proper extended type or construct the full object literal at creation time rather than mutating through double type assertions.

6. MetaExtendedEntryType is re-declared in workflow-visualizer.tsx

This type is already defined (privately) in xyflow-nodes.tsx. Export it from there and import it in workflow-visualizer.tsx to avoid duplication and potential divergence.

7. Hard-coded hex colors mixed with CSS variables

TYPE_COLORS and statusColor in xyflow-nodes.tsx mix CSS custom property references (hsl(var(--card))) with raw hex values (#3b82f6, #ef4444). The hex values will not respond to theme changes. Consider using CSS variables throughout.


Architecture / Design

8. proOptions={{ hideAttribution: true }} (workflow-visualizer.tsx, xyflow-nodes.stories.tsx)

XYFlow requires an active Pro license to suppress attribution. Using this prop without a license violates XYFlow's terms of service. If the project does not have a Pro subscription, remove this prop.

9. workflow-example-data.ts lives in the production code tree

This 1,269-line file contains only fixture data for Ladle stories. It should live alongside the stories or in a fixtures/ subdirectory rather than as a peer of production modules.

10. No error handling around workflowHistoryToXYFlow

If the layout function throws on malformed history data, the entire WorkflowVisualizer will crash. A try/catch in the useMemo or a React error boundary would improve resilience in production.


CSS / Styling

11. XYFlow dark-theme CSS is duplicated

The .react-flow__controls, .react-flow__minimap, and .react-flow__edge-path overrides are copy-pasted identically into both frontend/.ladle/ladle.css and frontend/src/index.css. Extract them into a shared CSS file or at minimum add a comment that both files must be kept in sync.

12. !important in minimap style

.react-flow__minimap { background: hsl(var(--card)) !important; } — avoid !important unless truly necessary.


Minor Notes

  • The maskColor in MiniMap uses a raw HSL string ("hsl(20 14.3% 4.1% / 0.7)") rather than a CSS variable reference, which will break if the background color changes.
  • panOnDrag={[1, 2]} (middle-click + right-click panning) is a non-obvious choice. A brief comment explaining the intent would help future maintainers.

Overall the XYFlow rewrite is a substantial improvement over the previous SVG renderer. The main concerns worth resolving before merge are the branch-name matching bug (#1), the unexplained datacenter change (#4), and the Pro license attribution issue (#8).

Comment on lines 1 to 26
import { useState } from "react";
import {
Handle,
NodeToolbar,
Position,
type NodeProps,
type Node,
} from "@xyflow/react";
import {
faArrowDown,
faArrowUp,
faBolt,
faCircleCheck,
faCircleExclamation,
faCircleXmark,
faClock,
faCodeMerge,
faEnvelope,
faFlag,
faPlay,
faRefresh,
faSpinnerThird,
faTrash,
Icon,
} from "@rivet-gg/icons";
import { cn } from "@/components";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports need to be sorted according to the project's conventions. Consider organizing them in groups: React imports first, then third-party libraries, then local imports, each group sorted alphabetically.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment on lines 1 to 27
import type { Edge, Node } from "@xyflow/react";
import {
NODE_HEIGHT,
NODE_WIDTH,
LOOP_HEADER_HEIGHT,
LOOP_PADDING_X,
LOOP_PADDING_BOTTOM,
type WorkflowNodeData,
type LoopGroupNodeData,
type BranchGroupNodeData,
formatDuration,
} from "./xyflow-nodes";
import type {
EntryKindType,
EntryStatus,
ExtendedEntryType,
HistoryItem,
JoinEntry,
LoopEntry,
LoopIterationMarker,
MessageEntry,
RaceEntry,
RemovedEntry,
SleepEntry,
StepEntry,
WorkflowHistory,
} from "./workflow-types";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports need to be sorted according to the project's conventions. Consider organizing them in groups: third-party libraries first, then local imports, each group sorted alphabetically.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment on lines 264 to 273
{/* Icon box */}
<div
className="ml-2.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg"
style={{
backgroundColor: colors.iconBg,
border: `1px solid ${colors.icon}4d`,
}}
>
<TypeIcon type={data.entryType} size={14} />
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This icon container should have an aria-hidden="true" attribute if it's decorative, or an appropriate aria-label if it conveys meaning that's not available to screen readers.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@jog1t jog1t mentioned this pull request Feb 10, 2026
11 tasks
@jog1t jog1t force-pushed the 02-11-feat_add_xyflow branch from 0716e7c to 9b4d46a Compare February 10, 2026 23:35
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4170 February 10, 2026 23:35 Destroyed
@jog1t jog1t force-pushed the 02-11-feat_add_xyflow branch from 9b4d46a to 8bf01e3 Compare February 11, 2026 00:11
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4170 February 11, 2026 00:12 Destroyed
@jog1t jog1t force-pushed the 02-10-feat_add_ladle branch from aa5df64 to 995ac00 Compare February 16, 2026 16:39
@jog1t jog1t force-pushed the 02-11-feat_add_xyflow branch from 8bf01e3 to 95291ff Compare February 16, 2026 16:42
@jog1t jog1t force-pushed the 02-10-feat_add_ladle branch from 995ac00 to e03420d Compare February 16, 2026 19:13
@jog1t jog1t force-pushed the 02-11-feat_add_xyflow branch from 95291ff to 7b2929d Compare February 16, 2026 19:13
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 16, 2026

More templates

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4170

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4170

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4170

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4170

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4170

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4170

@rivetkit/sqlite-vfs

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sqlite-vfs@4170

@rivetkit/traces

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/traces@4170

@rivetkit/workflow-engine

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/workflow-engine@4170

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4170

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4170

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4170

commit: 7b2929d

@graphite-app
Copy link
Contributor

graphite-app bot commented Feb 19, 2026

Merge activity

  • Feb 19, 11:17 PM UTC: NathanFlurry added this pull request to the Graphite merge queue.
  • Feb 19, 11:18 PM UTC: CI is running for this pull request on a draft pull request (#4244) due to your merge queue CI optimization settings.
  • Feb 19, 11:19 PM UTC: Merged by the Graphite merge queue via draft PR: #4244.

graphite-app bot pushed a commit that referenced this pull request Feb 19, 2026
# Description

Added a workflow visualization component using XYFlow to render workflow history data as interactive node graphs. This implementation includes:

- Custom node types for different workflow entry types (step, loop, sleep, message, etc.)
- Support for nested structures like loops and parallel branches
- Visual indicators for node status (completed, running, failed, retrying)
- Duration display and timing gaps between nodes
- Dark theme styling for all XYFlow components

The implementation includes example data for various workflow patterns (linear, loops, joins, races) and Ladle stories to showcase each node type and complete workflow examples.

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Tested through Ladle stories that demonstrate:
- Individual node types with different statuses
- Simple linear workflows
- Workflows with loops
- Workflows with parallel branches (join)
- Workflows with racing branches
- Complex workflows with multiple patterns
- In-progress, retrying, and failed workflows

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
@graphite-app graphite-app bot closed this Feb 19, 2026
@graphite-app graphite-app bot deleted the 02-11-feat_add_xyflow branch February 19, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant