Skip to content

GENIE-1307/bugfix/svg-black-screen-bug#97

Merged
MayaCrmi merged 6 commits intomainfrom
GENIE-1307/bugfix/svg-black-screen-bug
Feb 25, 2026
Merged

GENIE-1307/bugfix/svg-black-screen-bug#97
MayaCrmi merged 6 commits intomainfrom
GENIE-1307/bugfix/svg-black-screen-bug

Conversation

@MayaCrmi
Copy link
Collaborator

@MayaCrmi MayaCrmi commented Feb 22, 2026

Fix for the black screen bug!
After being able to replicate it, I found out that what happened is while we were in chat only display mode, the graph panel is set to width: 0 but GraphDisplay stays mounted (to preserve streaming node state, which we have actually opened a ticket to improve this logic and try and keep this without actually keeping the graph mounted behind the scenes). So when the run finishes, the state of isLiveRequest turns false, triggers a useEffect that calls applyNodeVisual on every element. Each el.attr() call makes JointJS recalculate, which requires computing SVG boxes using the function inverse... But in this particular case (the live streaming finishes while on the chat only mode), the SVG currently lives inside a container with width zero, so the transformation matrix is all zeros and cannot be inverted (some real-life CS degree issues lol). This error crashed the entire React component tree, which gave us the black screen.
The fix for this was in two parts. First, The el.attr() is now wrapped inside applyNodeVisual with a try-catch blick. Now, if this happens, the error is caught silently so the app doesn’t break. The node status state (nodeStatusMapRef) still updates correctly either way. But to fix it from the core of it, I added a ResizeObserver on the graph container, which watches for when the container goes from collapsed option back to big size like for example, when switching from chat-only back to graph mode. When that happens, it re-applies all the current node statuses from nodeStatusMapRef. That way, even if the visual updates failed while the panel was hidden, the graph refreshes well and shows the right DONE / PROGRESS / IDLE styles once it’s visible again.

You'll also see here tiny UI changes I also added על הדרך that were requested:

  • A2A card to be aligned with the primary color
  • Under inventory the list items wording changed to white to be clearer
  • Load workflow to be disabled until it's needed
  • When clicking back from graph canvas the page is stuck on Loading Graph

Summary by CodeRabbit

  • Bug Fixes

    • Prevented crashes and transient rendering errors when graph containers are collapsed by handling invalid SVG transforms and logging warnings.
  • New Features

    • Graph visuals now automatically re-sync when a previously hidden graph becomes visible.
    • Load Workflow button now shows "Select a workflow first" and is disabled until a workflow is chosen.
  • Style

    • Updated agent card and skill visuals to a unified primary color palette.
    • Sidebar selected-item text now uses white for improved visibility.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Adds explicit graph visibility prop, defensive try/catch logging around SVG matrix operations, and logic to reapply node visuals when a previously hidden graph becomes visible; also includes several UI styling/theme tweaks and button/tooltip logic updates.

Changes

Cohort / File(s) Summary
Graph resilience & visibility
ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx, ui/client/src/hooks/use-joint-graph.ts, ui/client/src/components/agentic-ai/ExecutionTab.tsx
Adds isGraphVisible?: boolean prop to GraphDisplay and passes it from ExecutionTab; wraps SVG matrix/attribute updates in try/catch with warnings; on visibility transition re-applies stored node visuals after a short delay instead of throwing; improves error logging in fit/resize logic.
Styling / theme adjustments
ui/client/src/components/agentic-ai/workspace/AgentCardVisualization.tsx, ui/client/src/components/agentic-ai/workspace/CategorySidebar.tsx
Switches many Tailwind color classes from blue/purple to primary tokens in AgentCardVisualization; adjusts selected item text color in CategorySidebar from text-secondary to text-white.
Workflows UX / button & tooltip logic
ui/client/src/pages/AgenticWorkflows.tsx
Back action now ignores saved blueprint and always resets selection; tooltip and Load button logic updated to handle “no workflow selected” state and expanded styling branches for disabled/valid/invalid/loading conditions.

Sequence Diagram(s)

sequenceDiagram
    participant Exec as ExecutionTab (UI)
    participant Graph as GraphDisplay
    participant NodeStore as nodeStatusMapRef
    participant Joint as JointJS Graph
    Exec->>Graph: render with isGraphVisible (true/false)
    note right of Graph: GraphDisplay monitors visibility
    Graph->>Graph: detect transition hidden -> visible
    Graph->>NodeStore: iterate stored node visuals
    NodeStore-->>Graph: provide visuals per node
    Graph->>Joint: applyNodeVisual(node, visual)
    alt SVG matrix invertible
        Joint-->>Graph: attributes updated
    else non-invertible
        Joint-->>Graph: throws -> caught, warn logged
    end
    Graph->>Graph: schedule/confirm reapply complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • odaiodeh
  • yhabushi79
  • Nirsisr

Poem

🐰
I nibble errors, gentle and spry,
When hidden graphs unfold to the sky.
I reapply paint with a patient hop,
Warn if matrices twist and stop.
Hop—now every node's colors fly! 🎨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly references a specific bug (SVG black screen bug) with a ticket ID (GENIE-1307), clearly summarizing the main fix in this changeset.

✏️ 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
  • Post copyable unit tests in a comment
  • Commit unit tests in branch GENIE-1307/bugfix/svg-black-screen-bug

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

🔍 Summary

This Pull Request addresses critical runtime errors in the JointJS graph visualization (GraphDisplay and useJointGraph) that occur when the graph container is collapsed (zero dimensions), typically during chat/carousel transitions. It introduces defensive error handling and a ResizeObserver to restore visuals when the graph becomes visible again. Additionally, it includes a minor styling update to the CategorySidebar.

The changes align with the Agentic AI System architecture, specifically the read-only / view-mode workflow display strategy using JointJS.

🧩 File-by-file feedback

[DOMAIN: UI] ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx

  • Defensive Programming: The try/catch block around el.attr is a necessary safeguard against SVG matrix inversion errors in JointJS when the container has 0 width/height.
  • Race Condition / Magic Number: The 60ms timeout relies on an implicit knowledge of a 10ms debounce in use-joint-graph.ts. This creates a fragile coupling.
    • Reference: ui/ARCHITECTURE.md - Code Conventions: While not explicitly forbidden, magic numbers coupled across files violate robust component structure principles.
  • Performance: The ResizeObserver is instantiated inside useEffect. Ensure observer.disconnect() is reliably called (it appears correct in the cleanup return).

[DOMAIN: UI] ui/client/src/hooks/use-joint-graph.ts

  • Error Handling: The try/catch implementation here mirrors the fix in GraphDisplay and correctly handles the getLinks() iteration.
  • Documentation: The comment explaining the "SVGMatrix non-invertible" issue is excellent and helpful for future maintainers.

[DOMAIN: UI] ui/client/src/components/agentic-ai/workspace/CategorySidebar.tsx

  • Styling Violation: The change to text-white hardcodes a specific color value instead of using the project's semantic design tokens.
    • Reference: ui/ARCHITECTURE.md - Styling Conventions: "Design tokens (CSS variables)... text-foreground, text-primary-foreground".
    • Risk: If the application runs in Light Mode, bg-primary with bg-opacity-20 results in a light background. text-white on top of this will likely have insufficient contrast and be unreadable.

🛠 Suggested Improvements

1. Decouple Timing Logic (GraphDisplay.tsx)
Instead of a magic number 60ms, consider defining these timing constants in a shared config or passing a "ready" state from the hook. If that is too large a refactor, at least extract the constant.

// Define at top of file or imported from constants
const GRAPH_RESIZE_DEBOUNCE_MS = 10;
const VISUAL_UPDATE_BUFFER_MS = 50; // Buffer to ensure resize completes
const RESTORE_VISUALS_DELAY = GRAPH_RESIZE_DEBOUNCE_MS + VISUAL_UPDATE_BUFFER_MS;

// ... inside useEffect
pendingTimer = setTimeout(() => {
   // logic
}, RESTORE_VISUALS_DELAY);

2. Use Semantic Tokens for Styling (CategorySidebar.tsx)
Replace hardcoded text-white with a theme-aware token to ensure accessibility across Light/Dark modes.

// Recommended change using semantic tokens
className={cn(
  "w-full justify-start px-4 py-2 rounded-none text-xs",
  selectedElementType?.type === elementType.type && 
  selectedElementType?.category === elementType.category
    ? "bg-primary/20 border-r-2 border-primary text-primary" // text-primary ensures contrast on primary/20
    : "text-muted-foreground hover:text-foreground"
)}

Note: bg-primary/20 is the Tailwind 3 syntax preferred over bg-opacity-20.

✅ What's Good

  • Crash Prevention: The try/catch blocks effectively prevent the entire application from crashing during layout resizing/collapsing, which is a significant stability improvement.
  • Context Awareness: The ResizeObserver logic correctly identifies the transition from "collapsed" to "visible" before attempting to repaint, preventing wasted cycles.
  • Comments: Code comments explain why the hacky try/catch blocks are needed (JointJS internal limitations), which is crucial for maintenance.

✍️ Suggested Commit Message

fix(ui): handle JointJS render errors in collapsed containers

- Wrap JointJS attribute updates in try/catch to handle non-invertible matrix errors
- Add ResizeObserver to GraphDisplay to restore visuals after container expansion
- Update sidebar active item styling for better visibility

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.

🧹 Nitpick comments (3)
ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx (2)

343-343: graphRef and containerRef are stable refs — remove them from the dep array.

Both graphRef and containerRef are useRef objects whose identity never changes across renders. Listing them as deps implies the effect re-runs when they "change" — which never happens — misleading future readers.

♻️ Suggested fix
-  }, [graphRef, containerRef, applyNodeVisual]);
+  }, [applyNodeVisual]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx` at line 343, The
effect's dependency array includes stable refs graphRef and containerRef which
never change; remove graphRef and containerRef from the deps and only include
real changing dependencies (e.g., applyNodeVisual) so the effect runs correctly;
update the useEffect dependency list in the component containing the effect that
references graphRef, containerRef, and applyNodeVisual to remove the two refs,
and if ESLint warns, add a focused comment explaining that graphRef/containerRef
are stable refs and intentionally omitted.

325-333: The 60ms delay is implicitly coupled to the 10ms debounce in use-joint-graph.ts.

The value 60 exists solely to outlast the 10ms debounce in the sibling file's ResizeObserver (line 541 of use-joint-graph.ts). There is no shared constant tying them together, so changing the debounce in use-joint-graph.ts silently breaks the timing assumption here.

Consider extracting a shared constant (e.g. RESIZE_DEBOUNCE_MS = 10) and deriving the delay from it, or at minimum adding a cross-file reference in the comment.

♻️ Suggested approach (shared constant)

In use-joint-graph.ts (or a shared constants file):

+export const RESIZE_DEBOUNCE_MS = 10;

In use-joint-graph.ts ResizeObserver:

-      }, 10);
+      }, RESIZE_DEBOUNCE_MS);

In GraphDisplay.tsx:

+import { RESIZE_DEBOUNCE_MS } from "@/hooks/use-joint-graph";
 ...
-        }, 60);
+        // Wait for use-joint-graph ResizeObserver (RESIZE_DEBOUNCE_MS + render budget)
+        }, RESIZE_DEBOUNCE_MS + 50);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx` around lines 325
- 333, The 60ms timeout in GraphDisplay (pendingTimer setTimeout) is implicitly
tied to the 10ms debounce in use-joint-graph.ts's ResizeObserver and should be
decoupled; introduce a shared constant (e.g. RESIZE_DEBOUNCE_MS) exported from
use-joint-graph.ts or a shared constants module and use a derived delay (e.g.
RESIZE_DEBOUNCE_MS * N or RESIZE_DEBOUNCE_MS + buffer) when scheduling
pendingTimer in GraphDisplay instead of the hard-coded 60, and update the
comment to reference the shared constant so applyNodeVisual, graphRef.current
and nodeStatusMapRef.current behavior remains correct if the debounce changes.
ui/client/src/hooks/use-joint-graph.ts (1)

509-521: Try-catch wraps the entire loop — first throw skips remaining links.

If any link.attr() throws, the remaining links in the iteration won't be updated (partial or zero update depending on which link throws first). Because all links share the same paper SVG context they'll typically all fail or all succeed, so the practical impact is low — but moving the guard inside the loop is more defensive and consistent with the applyNodeVisual pattern in GraphDisplay.tsx.

♻️ Suggested refactor
-    try {
-      for (const link of graph.getLinks()) {
-        if (conditionalLinkIdsRef.current.has(link.id as string)) continue;
-        link.attr("line/stroke", linkColor);
-        link.attr("line/sourceMarker/fill", linkColor);
-        link.attr("line/targetMarker/fill", linkColor);
-      }
-    } catch {
-      // SVGMatrix non-invertible when the container is collapsed to zero
-      // width (e.g. carousel chat mode).  The ResizeObserver will re-fit
-      // the paper once the container becomes visible; link colors are
-      // cosmetic and will be correct on next full rebuild.
-    }
+    for (const link of graph.getLinks()) {
+      if (conditionalLinkIdsRef.current.has(link.id as string)) continue;
+      try {
+        link.attr("line/stroke", linkColor);
+        link.attr("line/sourceMarker/fill", linkColor);
+        link.attr("line/targetMarker/fill", linkColor);
+      } catch {
+        // SVGMatrix non-invertible — container is collapsed (e.g. carousel
+        // chat mode). Colors will be correct on next full rebuild once the
+        // ResizeObserver re-fits the paper.
+      }
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/hooks/use-joint-graph.ts` around lines 509 - 521, The current
try-catch around the whole loop means a single link.attr() exception aborts
updating remaining links; change it to catch per-link so other links still get
updated: iterate over graph.getLinks(), skip when
conditionalLinkIdsRef.current.has(link.id as string) as before, then wrap the
link.attr(...) calls for each link in a try-catch (mirroring applyNodeVisual in
GraphDisplay.tsx) so SVGMatrix errors only skip that one link and do not prevent
processing of subsequent links.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx`:
- Line 343: The effect's dependency array includes stable refs graphRef and
containerRef which never change; remove graphRef and containerRef from the deps
and only include real changing dependencies (e.g., applyNodeVisual) so the
effect runs correctly; update the useEffect dependency list in the component
containing the effect that references graphRef, containerRef, and
applyNodeVisual to remove the two refs, and if ESLint warns, add a focused
comment explaining that graphRef/containerRef are stable refs and intentionally
omitted.
- Around line 325-333: The 60ms timeout in GraphDisplay (pendingTimer
setTimeout) is implicitly tied to the 10ms debounce in use-joint-graph.ts's
ResizeObserver and should be decoupled; introduce a shared constant (e.g.
RESIZE_DEBOUNCE_MS) exported from use-joint-graph.ts or a shared constants
module and use a derived delay (e.g. RESIZE_DEBOUNCE_MS * N or
RESIZE_DEBOUNCE_MS + buffer) when scheduling pendingTimer in GraphDisplay
instead of the hard-coded 60, and update the comment to reference the shared
constant so applyNodeVisual, graphRef.current and nodeStatusMapRef.current
behavior remains correct if the debounce changes.

In `@ui/client/src/hooks/use-joint-graph.ts`:
- Around line 509-521: The current try-catch around the whole loop means a
single link.attr() exception aborts updating remaining links; change it to catch
per-link so other links still get updated: iterate over graph.getLinks(), skip
when conditionalLinkIdsRef.current.has(link.id as string) as before, then wrap
the link.attr(...) calls for each link in a try-catch (mirroring applyNodeVisual
in GraphDisplay.tsx) so SVGMatrix errors only skip that one link and do not
prevent processing of subsequent links.

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/client/src/pages/AgenticWorkflows.tsx (1)

145-155: ⚠️ Potential issue | 🔴 Critical

Tooltip on disabled button will not display to users.

The new !selectedFlow branch returns <p>Select a workflow first</p>, but the Button component applies disabled:pointer-events-none when disabled. Since the button is disabled exactly when !selectedFlow is true, pointer events will not fire and the tooltip will be invisible.

SimpleTooltip uses asChild on the TooltipTrigger, which means trigger behavior is applied directly to the Button element. When that Button has pointer-events: none, the Radix UI tooltip cannot detect hover events.

This issue applies equally to the pre-existing tooltip branches (!isFlowValid and isValidatingFlow), but this PR introduces a new user-facing message that will silently fail to display.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/pages/AgenticWorkflows.tsx` around lines 145 - 155, The tooltip
never appears when the Button is disabled because the Button gets
disabled:pointer-events-none and SimpleTooltip uses asChild (so the trigger is
the Button); update the JSX around SimpleTooltip and the Button in
AgenticWorkflows.tsx to wrap the Button with a non-disabled wrapper element
(e.g., a <span className="inline-block">) and make the tooltip trigger target
that wrapper instead of the Button (or remove asChild and render the
TooltipTrigger around the wrapper), so pointer events are received even when the
Button is disabled; keep the same conditional content logic for the tooltip.
🧹 Nitpick comments (1)
ui/client/src/pages/AgenticWorkflows.tsx (1)

60-65: handleLoadFlow lacks a guard for !selectedFlow.

The button's disabled prop prevents normal invocation, but handleLoadFlow still silently creates a random session (random graph-${Date.now()} ID, random name) when selectedFlow is null. Adding an early return keeps the function self-consistent with the new UI constraint.

🛡️ Proposed defensive guard
 const handleLoadFlow = async () => {
   if (isLoadingFlow) return; // Prevent multiple calls
+  if (!selectedFlow) return;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/pages/AgenticWorkflows.tsx` around lines 60 - 65,
handleLoadFlow currently creates a random session when selectedFlow is null; add
a defensive early-return at the start of handleLoadFlow to exit immediately if
!selectedFlow (and ensure isLoadingFlow state is cleared by not setting it to
true or by calling setIsLoadingFlow(false) before returning) so the function
respects the UI disabled state; reference handleLoadFlow, selectedFlow,
isLoadingFlow and setIsLoadingFlow when making the change.
ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae84ac3 and 5d9619c.

📒 Files selected for processing (2)
  • ui/client/src/components/agentic-ai/workspace/AgentCardVisualization.tsx
  • ui/client/src/pages/AgenticWorkflows.tsx
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@ui/client/src/pages/AgenticWorkflows.tsx`:
- Around line 145-155: The tooltip never appears when the Button is disabled
because the Button gets disabled:pointer-events-none and SimpleTooltip uses
asChild (so the trigger is the Button); update the JSX around SimpleTooltip and
the Button in AgenticWorkflows.tsx to wrap the Button with a non-disabled
wrapper element (e.g., a <span className="inline-block">) and make the tooltip
trigger target that wrapper instead of the Button (or remove asChild and render
the TooltipTrigger around the wrapper), so pointer events are received even when
the Button is disabled; keep the same conditional content logic for the tooltip.

---

Nitpick comments:
In `@ui/client/src/pages/AgenticWorkflows.tsx`:
- Around line 60-65: handleLoadFlow currently creates a random session when
selectedFlow is null; add a defensive early-return at the start of
handleLoadFlow to exit immediately if !selectedFlow (and ensure isLoadingFlow
state is cleared by not setting it to true or by calling setIsLoadingFlow(false)
before returning) so the function respects the UI disabled state; reference
handleLoadFlow, selectedFlow, isLoadingFlow and setIsLoadingFlow when making the
change.

sfiresht
sfiresht previously approved these changes Feb 24, 2026
MayaCrmi added 2 commits February 24, 2026 03:54
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)
ui/client/src/components/agentic-ai/ExecutionTab.tsx (1)

1016-1016: ⚠️ Potential issue | 🟠 Major

isGraphVisible should reflect effective graph width, not only carousel mode.

With Line 202 allowing maxChatInterface = 100, users can collapse graph width to 0 while still in normal mode. In that state this prop remains true, so the hidden→visible replay path won’t run when width comes back, leaving stale node visuals possible.

Proposed fix
-                  isGraphVisible={carouselMode !== 'chat'}
+                  isGraphVisible={
+                    !isChatOnlyMode &&
+                    carouselMode !== 'chat' &&
+                    blueprintGraphWidth > 0
+                  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/components/agentic-ai/ExecutionTab.tsx` at line 1016, The
isGraphVisible prop should be driven by the effective graph width, not just
carouselMode; update the prop assignment in ExecutionTab.tsx to compute the
graph width (e.g., graphWidth = 100 - maxChatInterface or from the existing chat
width state) and set isGraphVisible to (carouselMode !== 'chat' && graphWidth >
0) so the replay/visibility path runs correctly when width is restored; change
the single-line prop where isGraphVisible is set to use this combined condition
(referencing carouselMode and maxChatInterface/chat width variable).
🧹 Nitpick comments (1)
ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx (1)

208-214: Avoid repeated exception/log churn while the panel is collapsed.

This catch can run on every node update tick when the container is zero-width. Consider short-circuiting visual writes while hidden (or logging once) to reduce hot-path overhead.

Suggested refinement
+  const collapsedVisualWarnedRef = useRef(false);
+
   const applyNodeVisual = useCallback(
     (el: dia.Element, status: NodeStatus | undefined) => {
       const s = STATUS_STYLES[status ?? "IDLE"];
       try {
         el.attr("body/stroke", s.stroke);
         el.attr("body/strokeWidth", s.strokeWidth);
         el.attr("body/filter", s.filter);
+        collapsedVisualWarnedRef.current = false;
       } catch (e) {
-        console.warn("[GraphDisplay] applyNodeVisual: SVGMatrix non-invertible (container likely collapsed to zero width)", e);
+        if (!collapsedVisualWarnedRef.current) {
+          console.warn("[GraphDisplay] applyNodeVisual: SVGMatrix non-invertible (container likely collapsed to zero width)", e);
+          collapsedVisualWarnedRef.current = true;
+        }
       }
     },
     [],
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx` around lines 208
- 214, The catch in applyNodeVisual is hitting repeatedly when the SVG container
is collapsed; short-circuit the visual updates instead of repeatedly calling
el.attr or spamming console.warn: detect container visibility/size (e.g., check
containerRef or graph root boundingClientRect width/height or a CSS visibility
flag) before performing the three el.attr calls, and only attempt the visual
writes when size > 0; alternatively, if a one-time log is preferred, add a
module-level flag (e.g., hasLoggedNonInvertible) and only call console.warn once
from the catch in applyNodeVisual to avoid hot-path churn.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@ui/client/src/components/agentic-ai/ExecutionTab.tsx`:
- Line 1016: The isGraphVisible prop should be driven by the effective graph
width, not just carouselMode; update the prop assignment in ExecutionTab.tsx to
compute the graph width (e.g., graphWidth = 100 - maxChatInterface or from the
existing chat width state) and set isGraphVisible to (carouselMode !== 'chat' &&
graphWidth > 0) so the replay/visibility path runs correctly when width is
restored; change the single-line prop where isGraphVisible is set to use this
combined condition (referencing carouselMode and maxChatInterface/chat width
variable).

---

Nitpick comments:
In `@ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx`:
- Around line 208-214: The catch in applyNodeVisual is hitting repeatedly when
the SVG container is collapsed; short-circuit the visual updates instead of
repeatedly calling el.attr or spamming console.warn: detect container
visibility/size (e.g., check containerRef or graph root boundingClientRect
width/height or a CSS visibility flag) before performing the three el.attr
calls, and only attempt the visual writes when size > 0; alternatively, if a
one-time log is preferred, add a module-level flag (e.g.,
hasLoggedNonInvertible) and only call console.warn once from the catch in
applyNodeVisual to avoid hot-path churn.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 778144a and 816c96c.

📒 Files selected for processing (3)
  • ui/client/src/components/agentic-ai/ExecutionTab.tsx
  • ui/client/src/components/agentic-ai/graphs/GraphDisplay.tsx
  • ui/client/src/hooks/use-joint-graph.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • ui/client/src/hooks/use-joint-graph.ts

@MayaCrmi MayaCrmi merged commit b75a29e into main Feb 25, 2026
1 check passed
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.

5 participants