Skip to content

feat: add stacking to network#5316

Open
ogzhanolguncu wants to merge 6 commits intomainfrom
add-stacking-to-network-view
Open

feat: add stacking to network#5316
ogzhanolguncu wants to merge 6 commits intomainfrom
add-stacking-to-network-view

Conversation

@ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented Mar 13, 2026

What does this PR do?

  • Add collapsible stacking for instance nodes in the network view, sentinels with more than 3 instances auto-collapse into a layered card stack on initial load
  • Users can toggle visibility via a pill-style button on each sentinel node
  • Stacked instances skip individual RPS polling queries to avoid N concurrent requests for hidden nodes
Screen.Recording.2026-03-16.at.12.30.58.mov

@vercel
Copy link

vercel bot commented Mar 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard Ready Ready Preview, Comment Mar 17, 2026 7:11am

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

Adds client-side collapsing for sentinel nodes with auto-collapse on initial load, memoized visible-tree computation, unified node renderer, expanded node component props to support collapse and stacked views, and exports/constants for node sizing and collapse threshold.

Changes

Cohort / File(s) Summary
Deployment view
web/apps/dashboard/.../deployments/[deploymentId]/network/deployment-network-view.tsx
Adds collapsedSentinelIds state, hasAutoCollapsed ref, toggleSentinel and auto-collapse logic, computes visibleTree & sentinelChildrenMap with useMemo, replaces per-file renderer with renderDeploymentNode, and adds showNodeDetails prop.
Node exports & types
web/apps/dashboard/.../nodes/index.ts, web/apps/dashboard/.../nodes/types.ts
Exports COLLAPSE_THRESHOLD, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, and InstanceNode type; introduces DEFAULT_NODE_HEIGHT and COLLAPSE_THRESHOLD and updates NODE_SIZES to use constants.
Instance & wrapper nodes
web/apps/dashboard/.../nodes/instance-node.tsx, web/apps/dashboard/.../nodes/node-wrapper/node-wrapper.tsx
Adds stacked?: boolean to InstanceNode (disables RPS query when stacked), introduces showBanner?: boolean to NodeWrapper, and conditionally shows HealthBanner.
Sentinel node UI
web/apps/dashboard/.../nodes/sentinel-node.tsx
Adds isCollapsed?: boolean and onToggleCollapse?: () => void props, reads instances from node.metadata, and renders collapse toggle when instances exceed COLLAPSE_THRESHOLD.
Styling adjustments
web/apps/dashboard/.../nodes/node-wrapper/health-banner.tsx, web/apps/dashboard/.../nodes/skeleton-node/skeleton-node.tsx
HealthBanner uses full-width layout and adjusted margins; SkeletonNode uses inline styles for width/height with DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT instead of Tailwind utility sizing.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as DeploymentNetworkView
    participant State as React State
    participant Layout as TreeLayout
    participant Sentinel as SentinelNode

    User->>UI: click collapse toggle
    UI->>State: toggleSentinel(sentinelId)
    State->>State: update collapsedSentinelIds
    State-->>UI: re-render
    UI->>UI: compute visibleTree & sentinelChildrenMap (useMemo)
    UI->>Layout: render with visibleTree & renderDeploymentNode
    Layout->>Sentinel: render with isCollapsed & onToggleCollapse
    Sentinel->>UI: emit onToggleCollapse when toggled
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains what the PR does but is missing required sections like issue reference, type of change, testing instructions, and the mandatory checklist. Add a reference to the related issue, mark the type of change, provide testing instructions, and complete the required checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: adding stacking functionality to the network view for collapsible instance nodes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-stacking-to-network-view
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx:
- Around line 116-123: The collapsed Sentinel render changes the DOM footprint
(sentinel-node.tsx adds a pill and the collapsed wrapper grows by frontOffset)
which mismatches TreeLayout's fixed NODE_SIZES and causes connector drift;
update the layout footprint rather than only the DOM by either (A) updating
NODE_SIZES in components/nodes/types.ts to include the collapsed frontOffset for
the sentinel node type or (B) ensure the collapsed SentinelNode render (used
where isSentinelNode(...) returns true and controlled by
collapsedSentinelIds/toggleSentinel) keeps the same bounding box as the expanded
state (for example by reserving the extra frontOffset space in the collapsed
wrapper via padding/margin or an invisible spacer) so TreeLayout sees a
consistent size for both collapsed and expanded states.
- Around line 94-98: The sentinel remains collapsed after scaling below the
collapse threshold because the collapse check only uses collapsedSentinelIds;
update the collapse condition in deployment-network-view.tsx so that you only
slice children when both collapsedSentinelIds.has(node.id) AND
node.metadata.instances > COLLAPSE_THRESHOLD (or alternatively remove node.id
from collapsedSentinelIds when instances <= COLLAPSE_THRESHOLD). Locate the
logic around isSentinelNode, map.set and the ternary returning { ...node,
children: node.children?.slice(0, 1) } and change it to include the
instance-count check (or perform the cleanup of collapsedSentinelIds) to ensure
sentinels auto-expand when instances drop below COLLAPSE_THRESHOLD; the toggle
in sentinel-node.tsx will then behave correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: add124e5-ddd1-478c-8aeb-d8b672103a33

📥 Commits

Reviewing files that changed from the base of the PR and between b965f3f and 705786a.

📒 Files selected for processing (8)
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/index.ts
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/instance-node.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/node-wrapper/health-banner.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/node-wrapper/node-wrapper.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/sentinel-node.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/skeleton-node/skeleton-node.tsx
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/types.ts

Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

The rabbit issue about if instances scale down below threshold for collapse while collapsed is legit and should be fixed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx:
- Around line 66-85: The auto-collapse uses the live child nodes count via
isInstanceNode and COLLAPSE_THRESHOLD but the collapse logic compares
node.metadata.instances, causing divergence; update the collapse routine (the
function that currently reads node.metadata.instances) to compute the instance
count the same way as the useEffect—e.g., derive instanceChildrenCount from
(node.children ?? []).filter(isInstanceNode).length or extract into a shared
helper like getInstanceCount(node) and use that from both the useEffect and the
collapse function, then compare against COLLAPSE_THRESHOLD and call
setCollapsedSentinelIds as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b2ecdc86-efc7-41ac-aebe-ee99179147c2

📥 Commits

Reviewing files that changed from the base of the PR and between 705786a and 33d47c0.

📒 Files selected for processing (1)
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx

Comment on lines +66 to +85
useEffect(() => {
if (hasAutoCollapsed.current || !defaultTree) {
return;
}
hasAutoCollapsed.current = true;
const toCollapse = new Set<string>();
if (isOriginNode(defaultTree)) {
for (const child of defaultTree.children ?? []) {
if (
isSentinelNode(child) &&
(child.children ?? []).filter(isInstanceNode).length > COLLAPSE_THRESHOLD
) {
toCollapse.add(child.id);
}
}
}
if (toCollapse.size > 0) {
setCollapsedSentinelIds(toCollapse);
}
}, [defaultTree]);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor inconsistency in threshold check between auto-collapse and collapse logic.

Line 76 counts actual instance children via filter(isInstanceNode).length, but line 98 in the collapse function uses node.metadata.instances. If these values ever diverge (e.g., partially loaded children), behavior could be inconsistent—a sentinel might auto-collapse but not stay collapsed, or vice versa.

Consider using the same source of truth in both places for predictability.

💡 Suggested alignment

Use instanceChildren.length instead of node.metadata.instances in the collapse function (line 98):

-        return collapsedSentinelIds.has(node.id) && node.metadata.instances > COLLAPSE_THRESHOLD
+        return collapsedSentinelIds.has(node.id) && instanceChildren.length > COLLAPSE_THRESHOLD
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx
around lines 66 - 85, The auto-collapse uses the live child nodes count via
isInstanceNode and COLLAPSE_THRESHOLD but the collapse logic compares
node.metadata.instances, causing divergence; update the collapse routine (the
function that currently reads node.metadata.instances) to compute the instance
count the same way as the useEffect—e.g., derive instanceChildrenCount from
(node.children ?? []).filter(isInstanceNode).length or extract into a shared
helper like getInstanceCount(node) and use that from both the useEffect and the
collapse function, then compare against COLLAPSE_THRESHOLD and call
setCollapsedSentinelIds as before.

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.

2 participants