Skip to content

feat: add stacking to network#5316

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

feat: add stacking to network#5316
ogzhanolguncu wants to merge 13 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 23, 2026 5:04pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds client-side sentinel collapse state with one-time auto-collapse, memoized visible-tree and sentinelChildrenMap, stacked-instance rendering for collapsed sentinels, a unified renderDeploymentNode callback, and new node sizing/collapse constants plus updated node component APIs.

Changes

Cohort / File(s) Summary
Deployment view
web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx
Introduces collapsedSentinelIds state, hasAutoCollapsed ref, toggleSentinel, one-time auto-collapse (computeAutoCollapsedSentinels), visibleTree and sentinelChildrenMap memoization, and replaces the previous render helper with a useCallback renderDeploymentNode.
Node exports & types
web/apps/dashboard/.../network/unkey-flow/components/nodes/index.ts, web/apps/dashboard/.../nodes/types.ts
Exports added: COLLAPSE_THRESHOLD, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, and type exports InstanceNode/OriginNode. Replaced hard-coded node heights with DEFAULT_NODE_HEIGHT and exposed collapse threshold.
Instance node
web/apps/dashboard/.../nodes/instance-node.tsx
InstanceNode props now include optional stacked?: boolean; RPS query is disabled when stacked is true, and showBanner is passed as !stacked.
Node wrapper & health banner
web/apps/dashboard/.../nodes/node-wrapper/node-wrapper.tsx, web/apps/dashboard/.../nodes/node-wrapper/health-banner.tsx
NodeWrapper gains optional showBanner?: boolean (defaults true) and conditionally renders HealthBanner. HealthBanner layout adjusted to full-width with updated margins (removed dependence on DEFAULT_NODE_WIDTH for container classes).
Sentinel node
web/apps/dashboard/.../nodes/sentinel-node.tsx
SentinelNode props now accept isCollapsed?: boolean and onToggleCollapse?: () => void; reads instances from node.metadata and renders a collapse toggle when instance count > COLLAPSE_THRESHOLD.
Skeleton node
web/apps/dashboard/.../nodes/skeleton-node/skeleton-node.tsx
Skeleton node now uses inline styles driven by DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT instead of fixed Tailwind width/height utility classes.

Sequence Diagram(s)

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

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

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete and does not follow the required template. It lacks the structured format with issue reference, type of change checkboxes, testing instructions, and required checklist items. Complete the PR description using the required template: add issue reference, select change type, describe testing procedure, and complete all 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 clearly and concisely summarizes the main change: adding stacking functionality to the network view feature.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-stacking-to-network-view

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

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.

♻️ Duplicate comments (1)
web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx (1)

123-124: ⚠️ Potential issue | 🟠 Major

Keep collapsed-state checks consistent across sentinel and instance render paths.

Line 98 correctly gates collapse by threshold, but Lines 123 and 133 still use ID-only collapse state. If a sentinel was collapsed at 4 instances and later drops to 3, this can still force stacked rendering for each visible instance node.

💡 Minimal fix
       if (isSentinelNode(node)) {
+        const instanceCount = sentinelChildrenMap.get(node.id)?.length ?? 0;
+        const isCollapsed =
+          collapsedSentinelIds.has(node.id) && instanceCount > COLLAPSE_THRESHOLD;
         return (
           <SentinelNode
             node={node}
             deploymentId={deployment.id}
-            isCollapsed={collapsedSentinelIds.has(node.id)}
+            isCollapsed={isCollapsed}
             onToggleCollapse={isShowingSkeleton ? undefined : () => toggleSentinel(node.id)}
           />
         );
       }

       if (isInstanceNode(node)) {
         if (!parent || !isSentinelNode(parent)) {
           throw new Error("Instance node requires parent sentinel");
         }
-        if (collapsedSentinelIds.has(parent.id)) {
-          const instances = sentinelChildrenMap.get(parent.id) ?? [];
+        const instances = sentinelChildrenMap.get(parent.id) ?? [];
+        const isParentCollapsed =
+          collapsedSentinelIds.has(parent.id) && instances.length > COLLAPSE_THRESHOLD;
+        if (isParentCollapsed) {
           const totalLayers = instances.length;
           const step = 10;

Also applies to: 133-137

🤖 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 123 - 124, The sentinel render is using
collapsedSentinelIds.has(node.id) directly for isCollapsed/onToggleCollapse,
causing inconsistent behavior vs. the threshold-gated check used earlier; update
the sentinel and instance render paths (the places setting isCollapsed and
onToggleCollapse where you currently call collapsedSentinelIds.has(node.id)) to
use the same collapse gating logic as line 98 (i.e., combine
collapsedSentinelIds.has(node.id) with the collapse threshold check used there),
and keep the onToggleCollapse hook as isShowingSkeleton ? undefined : () =>
toggleSentinel(node.id) so toggling remains disabled during skeleton view.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx:
- Around line 123-124: The sentinel render is using
collapsedSentinelIds.has(node.id) directly for isCollapsed/onToggleCollapse,
causing inconsistent behavior vs. the threshold-gated check used earlier; update
the sentinel and instance render paths (the places setting isCollapsed and
onToggleCollapse where you currently call collapsedSentinelIds.has(node.id)) to
use the same collapse gating logic as line 98 (i.e., combine
collapsedSentinelIds.has(node.id) with the collapse threshold check used there),
and keep the onToggleCollapse hook as isShowingSkeleton ? undefined : () =>
toggleSentinel(node.id) so toggling remains disabled during skeleton view.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bd57f60a-6a69-447a-aa5f-03ac55fefaeb

📥 Commits

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

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

@mcstepp
Copy link
Collaborator

mcstepp commented Mar 17, 2026

I didn't see the issue resolved or the changes?

@ogzhanolguncu
Copy link
Contributor Author

fix: coderabbit

7d75c24

This should prevent it I guess

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 63-74: The effect defined in useEffect reads defaultTree but lists
currentTree in its dependency array, which is misleading and brittle; update the
dependency array to include defaultTree (or replace currentTree with
defaultTree) so the effect re-runs when defaultTree changes, and ensure
hasAutoCollapsed, computeAutoCollapsedSentinels, and setCollapsedSentinelIds
usage remains unchanged.
- Line 79: The code unsafely casts currentTree to OriginNodeType using "as
OriginNodeType", which breaks the guideline; replace the cast with a runtime
type guard that checks whether currentTree is an OriginNodeType (and not
SKELETON_TREE / SkeletonNode) before assigning to originNode: implement or call
an isOriginNode(obj): obj is OriginNodeType predicate (or inline checks for
distinguishing properties) and branch accordingly (e.g., handle skeleton case or
return early) so originNode is only set when the guard passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 70c1d1ca-c1a0-4041-bd5c-4a8e4571fa29

📥 Commits

Reviewing files that changed from the base of the PR and between ac68712 and 4f1417a.

📒 Files selected for processing (2)
  • 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
✅ Files skipped from review due to trivial changes (1)
  • web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/unkey-flow/components/nodes/index.ts

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.

3 participants