Skip to content

Staging#358

Open
gkorland wants to merge 258 commits intomainfrom
staging
Open

Staging#358
gkorland wants to merge 258 commits intomainfrom
staging

Conversation

@gkorland
Copy link
Contributor

@gkorland gkorland commented Jan 22, 2025

Summary by CodeRabbit

  • New Features
    • Responsive desktop/mobile layout with a tips carousel and slide-out chat/options drawer; improved toolbar with image download and enhanced search & chat flows.
  • Bug Fixes
    • Fixed interaction issues (click/right-click/double-click), context menu behaviors, and naming/display inconsistencies.
  • Performance Improvements
    • Smoother graph rendering, improved zoom-to-fit, selective element updates, and more reliable canvas animations.
  • Documentation / Dev Ops
    • Updated README and added a docker-compose for local setup.
  • Testing
    • Expanded and stabilized end-to-end tests covering chat, search, canvas, and tooltips.

@vercel
Copy link

vercel bot commented Jan 22, 2025

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

Project Deployment Actions Updated (UTC)
code-graph Ready Ready Preview, Comment Feb 28, 2026 8:54pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2025

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

Chat, graph, UI, tests, and infra were refactored to centralize graph state via GraphRef, expose messaging/path types and state as props, replace legacy ForceGraph2D with a new ForceGraph/canvas integration, add mobile/desktop refs and UI components (carousel/drawer), expand E2E helpers/tests, add docker-compose, and bump dependencies.

Changes

Cohort / File(s) Summary
Chat & Input
app/components/chat.tsx, app/components/Input.tsx
Chat component now receives external state (messages, setMessages, query, setQuery, selectedPath, setSelectedPath, setChatOpen, paths, setPaths) and canvasRef: GraphRef; internal state removed. Input no longer accepts value prop and uses node?.name.
Graph UI & Toolbar
app/components/code-graph.tsx, app/components/graphView.tsx, app/components/toolbar.tsx, app/components/elementMenu.tsx, app/components/dataPanel.tsx, app/components/ForceGraph.tsx
Unified canvas API: canvasRef: GraphRef across components, Node/Link unions for selections, new handlers (handleExpand, handleRemove updated), zoom/zoomedNodes integration, download image hook, JSONTree/SyntaxHighlighter for data panel, and a new ForceGraph wrapper that wires events to the Falkordb canvas.
Model / Types / Utils
app/components/model.ts, lib/utils.ts, app/components/model.ts
Graph model changed: Label type, labelsMap, Link/Node reshaped (numeric source/target), path flags added. New shared types: PathData, Message, MessageTypes, GraphRef, PATH_COLOR in lib/utils.
Page & New UI components
app/page.tsx, components/ui/carousel.tsx, components/ui/drawer.tsx, components/ui/switch.tsx, app/components/combobox.tsx
Split desktop/mobile chart refs, new UI state (messages/query/paths/selectedPath/etc.), mobile Drawer and Carousel added, Switch component added, combobox styling tweak, and Chat/CodeGraph wired with expanded props.
Styling & Config
app/globals.css, tailwind.config.js, components.json, app/layout.tsx
New chart CSS variables and .control-button, Tailwind chart palette added, new import aliases and iconLibrary in components.json, removed GoogleAnalytics import.
E2E tests & utils
e2e/logic/POM/codeGraph.ts, e2e/logic/utils.ts, e2e/config/constants.ts, e2e/config/testData.ts, e2e/tests/*.spec.ts, e2e/infra/*
POM scoped locators and mobile-aware flows, new wait helpers (waitForStableText, waitForElementToBeVisible, interactWhenVisible), canvas helpers (download, right-click, hover), constants updated (GRAPHRAG_SDK, FLASK_GRAPH), and tests updated/added for download, tooltips, and chat consistency.
Playwright & CI
.github/workflows/playwright.yml, playwright.config.ts, .github/workflows/nextjs.yml
CI Playwright changes: node version bumps, ensure report dirs, upload failed screenshots artifact, adjusted reporter and workers.
Docker & README & package
docker-compose.yml, README.md, package.json, Dockerfile
Added docker-compose (falkordb + backend), README restructure, large dependency additions/bumps (e.g., @falkordb/canvas, embla, html2canvas, react-json-tree, vaul), and base image Node update to 24.
API
app/api/repo/route.ts
Added POST handler that proxies to analyze_folder or analyze_repo based on repo_url (uses NextRequest).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ChatUI as Chat component
    participant API as /api/chat
    participant Graph as ForceGraph (via GraphRef)

    User->>ChatUI: submit question / select path
    ChatUI->>API: fetch response / paths
    API-->>ChatUI: returns messages and path data
    ChatUI->>Graph: update path flags & call canvasRef.zoomToFit()
    Graph-->>ChatUI: zoom complete / engine stop event
    ChatUI-->>User: render messages and focused graph
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • AviAvni

Poem

🐰 I hopped through props and typed each name,
I nudged the graph to zoom — then called its frame.
Drawers, carousels, and tests in tow,
Paths marked bright in PATH_COLOR's glow.
A carrot for CI — the repo's game! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Staging' is vague and generic, using a non-descriptive term that does not convey meaningful information about the changeset's primary objective. Replace 'Staging' with a specific, descriptive title that summarizes the main change, such as 'Refactor chat and graph components to use external state management and integrate ForceGraph canvas'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 staging

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.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

Hi! Looks like you've reached your API usage limit. You can increase it from your account settings page here: app.greptile.com/settings/billing/code-review

💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!

9 file(s) reviewed, no comment(s)
Edit PR Review Bot Settings | Greptile

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

🔭 Outside diff range comments (2)
app/components/graphView.tsx (1)

Line range hint 105-166: Improve double-click detection implementation.

The current implementation has potential issues:

  1. The double-click detection uses a fixed 1000ms threshold which might not match the system's double-click speed setting.
  2. The implementation doesn't handle the case where a user clicks different nodes within the threshold.

Consider this improved implementation:

-const lastClick = useRef<{ date: Date, name: string }>({ date: new Date(), name: "" })
+const lastClick = useRef<{ time: number, id: number }>({ time: 0, id: 0 })

-const isDoubleClick = now.getTime() - date.getTime() < 1000 && name === node.name
+const isDoubleClick = (now.getTime() - lastClick.current.time < 500) && (lastClick.current.id === node.id)
+lastClick.current = { time: now.getTime(), id: node.id }
app/components/chat.tsx (1)

Line range hint 157-215: Improve zoom functionality implementation.

Several improvements can be made to the zoom functionality:

  1. The setTimeout with 0ms delay is unnecessary
  2. Magic numbers should be constants
  3. Add proper error handling for undefined chart

Apply these changes:

+const ZOOM_DURATION = 1000;
+const ZOOM_PADDING = 150;

 const handleSetSelectedPath = (p: PathData) => {
   const chart = chartRef.current
   
-  if (!chart) return
+  if (!chart) {
+    console.warn('Chart reference is not available');
+    return;
+  }
   
   // ... rest of the function ...
   
-  setTimeout(() => {
-    chart.zoomToFit(1000, 150, (n: NodeObject<Node>) => p.nodes.some(node => node.id === n.id));
-  }, 0)
+  chart.zoomToFit(ZOOM_DURATION, ZOOM_PADDING, (n: NodeObject<Node>) => p.nodes.some(node => node.id === n.id));
 }
🧰 Tools
🪛 Biome (1.9.4)

[error] 163-163: Comparing to itself is potentially pointless.

(lint/suspicious/noSelfCompare)

🧹 Nitpick comments (5)
e2e/tests/chat.spec.ts (1)

113-113: Remove unnecessary empty line within the loop.

The empty line within the loop affects readability without adding value.

    for (let i = 0; i < 3; i++) {
      await chat.sendMessage(Node_Question);
      const result = await chat.getTextInLastChatElement();
      const number = result.match(/\d+/g)?.[0]!;
      responses.push(number);
-      
    }
app/components/model.ts (2)

179-215: Add error handling for edge cases.

While the node creation logic is sound, it would benefit from additional error handling for edge cases.

      let source = this.nodesMap.get(edgeData.src_node)
      let target = this.nodesMap.get(edgeData.dest_node)

+     if (edgeData.src_node === undefined || edgeData.dest_node === undefined) {
+       console.warn('Invalid edge data: Missing source or destination node ID');
+       return;
+     }

      if (!source) {

229-253: Add documentation for curve calculation logic.

The curve calculation logic is complex and would benefit from documentation explaining the mathematical reasoning.

Add a comment block explaining the curve calculation:

+    // Calculate curve values for graph edges:
+    // - For self-loops (start === end):
+    //   - Even indices: negative values starting from -3
+    //   - Odd indices: positive values starting from 2
+    // - For regular edges:
+    //   - Even indices: negative values starting from 0
+    //   - Odd indices: positive values starting from 1
+    // The final curve value is scaled by 0.1 to create subtle curves
     newElements.links.forEach(link => {
e2e/logic/POM/codeGraph.ts (1)

284-285: Consider removing redundant delay.

The code waits for the loading image to be hidden and then adds an additional 2-second delay, which might be unnecessary.

Consider removing the redundant delay:

 async getTextInLastChatElement(): Promise<string>{
     await this.page.waitForSelector('img[alt="Waiting for response"]', { state: 'hidden' });
-    await delay(2000);
     return (await this.lastElementInChat.textContent())!;
 }
app/components/chat.tsx (1)

Line range hint 272-313: Extract common zoom functionality.

The zoom logic is duplicated between handleSetSelectedPath and handleSubmit. Consider extracting it into a reusable function.

Apply these changes:

+const ZOOM_DURATION = 1000;
+const ZOOM_PADDING = 150;
+
+const zoomToNodes = (chart: ForceGraphMethods, nodes: any[]) => {
+  if (!chart) {
+    console.warn('Chart reference is not available');
+    return;
+  }
+  chart.zoomToFit(ZOOM_DURATION, ZOOM_PADDING, (n: NodeObject<Node>) => 
+    nodes.some(node => node.id === n.id)
+  );
+};

 const handleSubmit = async () => {
   const chart = chartRef.current
   
   if (!chart) return
   
   // ... rest of the function ...
   
-  setTimeout(() => {
-    chart.zoomToFit(1000, 150, (n: NodeObject<Node>) => 
-      formattedPaths.some(p => p.nodes.some(node => node.id === n.id))
-    );
-  }, 0)
+  zoomToNodes(chart, formattedPaths.flatMap(p => p.nodes));
 }

 const handleSetSelectedPath = (p: PathData) => {
   // ... rest of the function ...
-  setTimeout(() => {
-    chart.zoomToFit(1000, 150, (n: NodeObject<Node>) => 
-      p.nodes.some(node => node.id === n.id)
-    );
-  }, 0)
+  zoomToNodes(chart, p.nodes);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f419fe6 and d47f502.

📒 Files selected for processing (9)
  • app/components/chat.tsx (9 hunks)
  • app/components/code-graph.tsx (5 hunks)
  • app/components/elementMenu.tsx (3 hunks)
  • app/components/graphView.tsx (5 hunks)
  • app/components/model.ts (3 hunks)
  • app/page.tsx (1 hunks)
  • e2e/logic/POM/codeGraph.ts (4 hunks)
  • e2e/tests/canvas.spec.ts (1 hunks)
  • e2e/tests/chat.spec.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (11)
e2e/tests/chat.spec.ts (1)

120-121: LGTM! Good test isolation.

Moving the API calls inside the test scope improves test isolation and follows testing best practices.

app/components/elementMenu.tsx (1)

17-17: LGTM! Consistent function naming.

The typo fix from handelExpand to handleExpand is applied consistently across the component.

Also applies to: 22-22, 71-71, 77-77, 117-117, 123-123

app/components/model.ts (1)

55-55: LGTM! Safe default parameter.

Adding a default value of 0 ensures the function always returns a valid color.

app/page.tsx (1)

284-284: LGTM! Enhanced graph interaction.

Adding the chartRef prop to the Chat component enables improved graph visualization capabilities.

e2e/tests/canvas.spec.ts (1)

46-46: LGTM! Good improvement to test reliability.

Adding clickCenter() before zoom operations ensures consistent test behavior by establishing a known starting position.

app/components/graphView.tsx (2)

64-87: Good implementation of responsive graph sizing.

The resize observer implementation properly handles both window resizing and parent container changes. The cleanup in the useEffect hook correctly removes event listeners and disconnects the observer.


173-174: LGTM! Proper usage of dynamic dimensions.

Using state-managed dimensions ensures the graph properly responds to container size changes.

app/components/code-graph.tsx (1)

Line range hint 244-357: LGTM! Good cleanup of handler names.

The renaming from 'handel*' to 'handle*' improves code consistency and fixes typos.

e2e/logic/POM/codeGraph.ts (2)

155-157: LGTM! Good addition of loading state locator.

The new locator helps track loading states consistently across tests.


426-426: Verify the impact of changing to right-click.

The change from left-click to right-click for node selection might affect other tests that depend on this behavior.

Let's verify the impact:

✅ Verification successful

Right-click change appears safe to implement

The tests use the nodeClick() abstraction method rather than direct click events, focusing on outcomes rather than the click mechanism. The change from left to right click is an implementation detail that won't affect the test behavior as long as the nodeClick() method maintains its core functionality of node selection.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for tests that might be affected by the click behavior change
rg -l "nodeClick" "e2e/tests"

Length of output: 87


Script:

#!/bin/bash
# Check the content of test files for click-related code
echo "=== canvas.spec.ts ==="
rg -A 5 -B 5 "click" "e2e/tests/canvas.spec.ts"
echo -e "\n=== nodeDetailsPanel.spec.ts ==="
rg -A 5 -B 5 "click" "e2e/tests/nodeDetailsPanel.spec.ts"

Length of output: 8469

app/components/chat.tsx (1)

110-110: LGTM!

The function signature has been correctly updated to include the new chartRef prop.

… handling and neighbor deletion logic. Updated deleteNeighbors function to handle expanded nodes correctly and replaced direct calls with handleExpand in GraphView for better clarity and maintainability.
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

🔭 Outside diff range comments (1)
app/components/Input.tsx (1)

Line range hint 201-201: Warning: Dynamic Tailwind class names may not work in production.

The dynamic class name bg-${colorName} might not survive Tailwind's purge in production. Consider using style objects or safelist these color classes in your Tailwind config.

Example safelist configuration in tailwind.config.js:

module.exports = {
  safelist: [
    {
      pattern: /bg-(red|blue|green|yellow|purple|pink|indigo|gray)-/,
      variants: ['hover', 'focus', 'active']
    }
  ]
}
🧹 Nitpick comments (1)
app/components/Input.tsx (1)

Line range hint 147-160: Consider extracting input validation logic.

While the validation works correctly, consider extracting it into a reusable function for better maintainability.

+const INVALID_CHARS_PATTERN = /[%*()\-\[\]{};:"|~]/;
+const getInvalidCharacterMessage = (char: string) => 
+  `The character "${char}" is not allowed in this field.`;
+
+const validateInput = (value: string): { isValid: boolean; message: string } => {
+  const match = value.match(INVALID_CHARS_PATTERN);
+  return match 
+    ? { isValid: false, message: getInvalidCharacterMessage(match[0]) }
+    : { isValid: true, message: '' };
+};
+
 onChange={(e) => {
     const newVal = e.target.value
-    const invalidChars = /[%*()\-\[\]{};:"|~]/;
-
-    if (invalidChars.test(newVal)) {
-        e.target.setCustomValidity(`The character "${newVal.match(invalidChars)?.[0]}" is not allowed in this field.`);
+    const { isValid, message } = validateInput(newVal);
+    if (!isValid) {
+        e.target.setCustomValidity(message);
         e.target.reportValidity();
         return;
     }
     e.target.setCustomValidity('');
     onValueChange({ name: newVal })
 }}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d47f502 and 43c94c7.

📒 Files selected for processing (1)
  • app/components/Input.tsx (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (2)
app/components/Input.tsx (2)

18-18: LGTM! Good architectural improvement.

The removal of the value prop in favor of using node?.name makes the component more focused and reduces prop drilling.


Line range hint 48-79: LGTM! Well-implemented search functionality.

The implementation includes:

  • Proper debouncing with timeout
  • Clean error handling with user feedback
  • Appropriate cleanup in useEffect

Anchel123 and others added 28 commits February 24, 2026 11:49
…t handlers for improved link and node interactions
Update dependencies and improve test configurations
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: 17

🧹 Nitpick comments (9)
.github/dependabot.yml (1)

13-16: Group name suggests minor updates but only patches are included.

The group is named npm-minor-patch but only includes "patch" in update-types. This naming could be confusing. Consider either:

  1. Renaming to npm-patch if only patch updates are intended, or
  2. Adding "minor" to update-types if minor updates should also be grouped.
💡 Option 1: Rename to match behavior
     groups:
-      npm-minor-patch:
+      npm-patch:
         update-types:
           - "patch"
💡 Option 2: Include minor updates
     groups:
       npm-minor-patch:
         update-types:
+          - "minor"
           - "patch"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/dependabot.yml around lines 13 - 16, The dependabot group name
npm-minor-patch does not match its update-types (only "patch"); either rename
the group to npm-patch or add "minor" to update-types to match intent—update the
groups -> npm-minor-patch name or modify the update-types array (the keys
involved are groups, npm-minor-patch and update-types) accordingly so the config
and naming are consistent.
e2e/logic/utils.ts (2)

52-54: Consider adding type annotations for improved type safety.

The function signature uses any[] and returns any, which reduces type safety. If the node structure is known, consider using a more specific type or generic.

💡 Optional: Type-safe alternative
-export function findNodeByName(nodes: any[], nodeName: string): any {
+export function findNodeByName<T extends { name?: string; data?: { name?: string } }>(
+  nodes: T[], 
+  nodeName: string
+): T | undefined {
     return nodes.find((node) => node.name === nodeName || node.data?.name === nodeName);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/logic/utils.ts` around lines 52 - 54, The findNodeByName function
currently uses any[] and any; replace these with a type-safe signature by
introducing a Node-like shape or a generic: define or use an interface with
optional fields name?: string and data?: { name?: string } and change
findNodeByName to accept nodes of that type (or a generic T extends that shape)
and return T | undefined instead of any; update any callsites if necessary to
satisfy the new return type.

16-35: Consider edge case: function returns potentially unstable text.

The function returns stableText at the end even if the text never stabilized (i.e., it kept changing until timeout). This might be the intended behavior, but consider throwing an error or logging a warning when timeout is reached without stabilization to help debug flaky tests.

💡 Optional: Add timeout warning
     for (let i = 0; i < maxChecks; i++) {
         stableText = await locator.textContent() ?? "";
         if (stableText === previousText && stableText.trim().length > 0) {
             return stableText;
         }
         previousText = stableText;
         await locator.page().waitForTimeout(pollingInterval);
     }
 
+    console.warn(`Text did not stabilize within ${timeout}ms, returning last value`);
     return stableText;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/logic/utils.ts` around lines 16 - 35, waitForStableText currently returns
the last-read stableText even if the loop timed out without stabilization;
update the end of waitForStableText to treat timeout as a failure: throw an
Error (or at minimum log a warning) indicating the text never stabilized,
include contextual info (the last observed stableText, locator description or
string, and the timeout value) so tests can fail fast and debugging is easier;
locate this logic in the waitForStableText function and replace the final return
stableText with a thrown error or a process/test logger call as appropriate for
the test runner.
package.json (1)

29-29: Add @types/d3 to devDependencies for TypeScript support.

While d3@^7.9.0 does not include built-in TypeScript declarations, d3 is not currently imported in the codebase. However, since the library is now a dependency, adding types ahead of time will prevent TypeScript compilation issues when it's used. Install via DefinitelyTyped:

"@types/d3": "^7.4.3"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 29, Add the DefinitelyTyped declarations for D3 by
adding "@types/d3": "^7.4.3" to devDependencies in package.json so TypeScript
has typings when d3 is imported; update the package.json devDependencies block
(referencing the existing "d3" dependency) and run npm/yarn install to persist
the change.
lib/utils.ts (3)

2-2: Unused import: GraphNode.

GraphNode is imported from @falkordb/canvas but is not used anywhere in this file.

♻️ Proposed fix
-import FalkorDBCanvas, { GraphNode } from "@falkordb/canvas"
+import FalkorDBCanvas from "@falkordb/canvas"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils.ts` at line 2, The import includes an unused symbol GraphNode from
`@falkordb/canvas`; remove GraphNode from the import statement (leave
FalkorDBCanvas) to eliminate the unused import warning and keep imports minimal.

7-10: Consider stronger typing instead of any[].

Using any[] for nodes and links reduces type safety. Consider using the imported Node and Link types for better compile-time checks.

♻️ Proposed fix
+import { Link, Node } from "@/app/components/model"
+
 export type PathData = {
-  nodes: any[]
-  links: any[]
+  nodes: Node[]
+  links: Link[]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils.ts` around lines 7 - 10, The PathData type currently uses any[] for
nodes and links which reduces type safety; update the PathData definition in
lib/utils.ts to use the specific imported Node and Link types (i.e., nodes:
Node[] and links: Link[]), add/import those types if they are not already
imported, and adjust any call sites or tests that relied on any[] to satisfy the
stronger types.

31-36: Consider stronger typing for paths property.

The paths property uses any[] for both nodes and links. This could leverage the PathData type defined above for consistency and type safety.

♻️ Proposed fix
 export interface Message {
   type: MessageTypes;
   text?: string;
-  paths?: { nodes: any[], links: any[] }[];
+  paths?: PathData[];
   graphName?: string;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils.ts` around lines 31 - 36, The Message interface's paths property is
weakly typed using any[]; replace it with the existing PathData type for
stronger typing: change paths?: { nodes: any[], links: any[] }[] to paths?:
PathData[] (or Array<PathData>) in the Message interface so it uses the PathData
definition above and preserves optionality. Ensure PathData is visible in the
same module (or imported) so the Message type compiles.
app/components/toolbar.tsx (1)

64-64: Inconsistent title casing.

The title attribute uses camelCase "downloadImage" while other buttons use title case like "Zoom In", "Zoom Out", and "Center". Consider using consistent casing for accessibility and consistency.

♻️ Proposed fix
             <button
                 className="hidden md:block control-button"
-                title="downloadImage"
+                title="Download Image"
                 onClick={handleDownloadImage}
             >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/toolbar.tsx` at line 64, The title attribute for the download
button ("downloadImage") is using camelCase while other buttons use Title Case,
causing inconsistent accessibility labels; update the title attribute in the
toolbar component (the element with title="downloadImage") to use Title Case
e.g. "Download Image" to match "Zoom In"/"Zoom Out"/"Center" and ensure
consistency across the toolbar UI.
app/api/repo/route.ts (1)

45-45: Hardcoded ignore list may not be appropriate for all repositories.

The ignore array is hardcoded with specific directory patterns. This may not apply universally to all repositories being analyzed. Consider making this configurable via environment variables or request parameters.

♻️ Proposed configuration approach
+const DEFAULT_IGNORE = ["./.github", "./sbin", "./.git", "./deps", "./bin", "./build"];
+
 export async function POST(request: NextRequest) {
   const repo_url = request.nextUrl.searchParams.get('url');
+  const customIgnore = request.nextUrl.searchParams.get('ignore');
+  const ignore = customIgnore ? JSON.parse(customIgnore) : DEFAULT_IGNORE;
   // ...
   const result = await fetch(`${url}/${isLocal ? "analyze_folder" : "analyze_repo"}`, {
     method: 'POST',
-    body: JSON.stringify({ repo_url, ignore: ["./.github", "./sbin", "./.git", "./deps", "./bin", "./build"] }),
+    body: JSON.stringify({ repo_url, ignore }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/repo/route.ts` at line 45, The hardcoded ignore array in the request
body (body: JSON.stringify({ repo_url, ignore: [...] })) should be made
configurable: update the handler in app/api/repo/route.ts (the function that
constructs this body) to accept an optional ignore list from the incoming
request payload (e.g., request.body.ignore) and/or read a fallback from an
environment variable (e.g., REPO_IGNORE_LIST as JSON or comma-separated); if
neither is provided, fall back to the current default array. Validate/parses the
env or request value into an array before including it in JSON.stringify so
existing behavior remains unchanged when no config is supplied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/chat.tsx`:
- Line 100: The overlap check uses the same identifier for both elements so e.id
=== e.id is always true; update the inner some() callback to use a different
variable name (e.g., prevElem) and compare e.id === prevElem.id so you're
comparing an element from the current path (paths.some path -> e) against
elements from the previous selection ([...prev.nodes, ...prev.links] ->
prevElem). Locate the lambda in the paths.some(... every(... some(...)))
expression in chat.tsx and rename the inner callback parameter and its
comparison to fix the logic.

In `@app/components/code-graph.tsx`:
- Around line 106-110: The Delete-key guard in handleKeyDown is inverted: it
currently returns early when selectedObj exists and selectedObjects is empty,
preventing single-selection deletion; update the condition so it only returns
early when there is neither a single selectedObj nor any selectedObjects (i.e.,
if (!selectedObj && selectedObjects.length === 0) return), then call
handleRemove with the combined ids computed from selectedObjects.map(obj =>
obj.id) and selectedObj?.id filtered for undefined, ensuring you still pass
"nodes" as the second arg.

In `@app/components/dataPanel.tsx`:
- Around line 21-26: The excludedProperties array in dataPanel.tsx contains a
duplicate entry "isPathSelected"; remove the redundant "isPathSelected" so that
excludedProperties only lists each property once (locate the array named
excludedProperties in app/components/dataPanel.tsx and delete the duplicate
string entry).
- Around line 95-112: The valueRenderer is declared with parameters
(valueAsString, value, keyPath) but react-json-tree passes keyPath as rest
parameters; update the valueRenderer implementation (the prop named
valueRenderer) to accept rest parameters (e.g., (...keyPath)) and then check the
first element keyPath[0] === "src" to decide when to render the
SyntaxHighlighter in the DataPanel component; ensure the fallback still returns
the span with className "text-white".

In `@app/components/graphView.tsx`:
- Around line 167-168: The current checks use "!node.x || !node.y" which
incorrectly treats 0 as missing; update both occurrences where that check
appears (the conditional guarding rendering/hit-testing of a node) to explicitly
test for null/undefined instead, e.g. use "node.x == null || node.y == null" or
"node.x === undefined || node.y === undefined" (or prefer
Number.isFinite(node.x) && Number.isFinite(node.y) if you want to ensure numeric
coordinates) so nodes at x=0 or y=0 are not skipped.

In `@app/components/model.ts`:
- Around line 197-230: When synthesizing missing endpoint nodes (the local
variables source and target created from edgeData.src_node / edgeData.dest_node)
you currently only set them in this.nodesMap; also append the newly created node
objects to the exported element lists (e.g. this.elements.nodes and, if present
in context, newElements.nodes) so links reference actual exported nodes; update
the blocks that create source and target to push the created node into
this.elements.nodes (and newElements.nodes when used) immediately after
this.nodesMap.set(...) to keep maps and element arrays in sync.

In `@app/page.tsx`:
- Around line 371-388: External links rendered with the Link components (e.g.,
the Link instances that render the FalkorDB logo, "Main Website", "Github",
"Discord" etc. in app/page.tsx) use target='_blank' but lack rel='noopener
noreferrer'; update each external Link element that opens in a new tab to
include rel="noopener noreferrer" alongside target='_blank' to prevent
tabnabbing and improve security—ensure every Link with target='_blank' (all
occurrences around the header block and lines ~537-560) is amended accordingly.
- Line 617: The mobile CodeGraph is calling onCategoryClick with the desktop
canvas ref (desktopChartRef) so mobile category toggles target the wrong canvas;
update the mobile CodeGraph invocation to pass the mobile canvas ref (e.g.,
mobileChartRef or the ref used by the mobile CodeGraph instance) into
onCategoryClick instead of desktopChartRef, ensuring the onCategoryClick(name,
show, ...) call for the mobile component uses the mobile ref; search for the
CodeGraph mobile render and replace the passed desktopChartRef with the
mobileChartRef symbol (or the precise ref variable name used for mobile).

In `@e2e/logic/POM/codeGraph.ts`:
- Line 152: The XPath in locateNodeInLastChatPath is invalid because ${node} is
injected unquoted; wrap the node string in quotes and escape any internal quotes
— e.g., interpolate a properly quoted JS string using JSON.stringify(node) so
the XPath becomes contains(text(), ${JSON.stringify(node)}); update the locator
returned by locateNodeInLastChatPath accordingly to ensure safe, valid XPath.
- Around line 595-605: The function always calls window.graphDesktop() which
returns the wrong instance in mobile tests; update the accessor selection so
that both the waitForFunction check and the final page.evaluate call use
window.graphMobile() when running in mobile mode and window.graphDesktop()
otherwise—detect mobile via the Playwright context/page mode available in this
class (e.g., this.page.isMobile or other environment flag) and replace the
hardcoded graphDesktop references (graphDesktop, graphMobile, page.evaluate,
page.waitForFunction) so the code conditionally invokes the correct window graph
accessor before awaiting canvas animation and returning the graph data.

In `@e2e/tests/canvas.spec.ts`:
- Around line 222-225: Replace unsafe non-null assertions on firstNodeRes and
secondNodeRes when calling api.showPath and in expectations: after asserting
firstNodeRes and secondNodeRes are defined (using expect(...).toBeDefined()),
extract their ids with a guard (e.g., throw or return if undefined) or use
optional chaining when accessing .id, and use those guarded ids in the
api.showPath call and subsequent checks for callsRelationObject (from
response.result.paths[0].find). Also guard callsRelationObject before asserting
src_node/dest_node to avoid runtime errors if the relation is missing.

In `@e2e/tests/chat.spec.ts`:
- Around line 85-87: The test uses a non-null assertion on const number =
uiResponse.match(/\d+/g)?.[0]! which can throw if the regex doesn't match and
also directly compares to apiResponse.result.response.match(...), so update the
assertion to avoid the trailing "!" and first capture both matches into
temporaries (e.g., uiMatch and apiMatch), assert each is defined (or fail with a
clear message) and then compare them; reference the variables uiResponse,
apiResponse, and the extracted value currently named number to locate the lines
to change and ensure robust null/undefined handling before calling
expect(...).toEqual(...).
- Line 69: The line "const number = result.match(/\d+/g)?.[0]!" uses a non-null
assertion after optional chaining which is unsafe; change it to explicitly
handle the possible null/undefined match: call result.match(/\d+/g) into a local
variable (e.g., const match = result.match(/\d+/g)), assert or throw if match is
null or match[0] is falsy (or use an expect(...) assertion in the test), then
assign const number = match[0]; this removes the "!.", ensures deterministic
failures with a clear error message, and references the existing identifiers
"number" and the result.match(...) expression in chat.spec.ts.

In `@package.json`:
- Line 33: package.json pins Next.js to "next": "^15.5.8" which has security
advisories and may require React 19 for App Router; update the "next" dependency
to a patched release (>=15.5.9) and, if your app uses the App Router, bump
"react" and "react-dom" to React 19-compatible versions (replace current "react"
and "react-dom" entries) and run install and test to resolve peer dependency
warnings and verify the app and App Router behavior.

In `@playwright.config.ts`:
- Around line 22-23: The comment above the workers setting is stale: update the
comment to accurately describe the current behavior of the workers property
(workers: process.env.CI ? 3 : undefined) — e.g., change the comment to
something like "Use a fixed 3 workers on CI (otherwise default)" or similar so
it no longer says we opt out of parallel tests; ensure you edit the comment
immediately above the workers property that references the workers setting.

In `@README.md`:
- Line 109: Update the GitHub Issues link in the README: replace the current URL
"https://github.com/FalkorDB/GraphRAG-SDK/issues" referenced by the "[GitHub
Issues]" list item with "https://github.com/FalkorDB/code-graph/issues" so the
repo's README points to the correct issue tracker for code-graph.
- Line 9: Remove the stray lone "-" character present in the README (the stray
hyphen on its own line) so the file has no extraneous characters; simply delete
that line containing only "-" and save the README to restore clean formatting.

---

Nitpick comments:
In @.github/dependabot.yml:
- Around line 13-16: The dependabot group name npm-minor-patch does not match
its update-types (only "patch"); either rename the group to npm-patch or add
"minor" to update-types to match intent—update the groups -> npm-minor-patch
name or modify the update-types array (the keys involved are groups,
npm-minor-patch and update-types) accordingly so the config and naming are
consistent.

In `@app/api/repo/route.ts`:
- Line 45: The hardcoded ignore array in the request body (body:
JSON.stringify({ repo_url, ignore: [...] })) should be made configurable: update
the handler in app/api/repo/route.ts (the function that constructs this body) to
accept an optional ignore list from the incoming request payload (e.g.,
request.body.ignore) and/or read a fallback from an environment variable (e.g.,
REPO_IGNORE_LIST as JSON or comma-separated); if neither is provided, fall back
to the current default array. Validate/parses the env or request value into an
array before including it in JSON.stringify so existing behavior remains
unchanged when no config is supplied.

In `@app/components/toolbar.tsx`:
- Line 64: The title attribute for the download button ("downloadImage") is
using camelCase while other buttons use Title Case, causing inconsistent
accessibility labels; update the title attribute in the toolbar component (the
element with title="downloadImage") to use Title Case e.g. "Download Image" to
match "Zoom In"/"Zoom Out"/"Center" and ensure consistency across the toolbar
UI.

In `@e2e/logic/utils.ts`:
- Around line 52-54: The findNodeByName function currently uses any[] and any;
replace these with a type-safe signature by introducing a Node-like shape or a
generic: define or use an interface with optional fields name?: string and
data?: { name?: string } and change findNodeByName to accept nodes of that type
(or a generic T extends that shape) and return T | undefined instead of any;
update any callsites if necessary to satisfy the new return type.
- Around line 16-35: waitForStableText currently returns the last-read
stableText even if the loop timed out without stabilization; update the end of
waitForStableText to treat timeout as a failure: throw an Error (or at minimum
log a warning) indicating the text never stabilized, include contextual info
(the last observed stableText, locator description or string, and the timeout
value) so tests can fail fast and debugging is easier; locate this logic in the
waitForStableText function and replace the final return stableText with a thrown
error or a process/test logger call as appropriate for the test runner.

In `@lib/utils.ts`:
- Line 2: The import includes an unused symbol GraphNode from `@falkordb/canvas`;
remove GraphNode from the import statement (leave FalkorDBCanvas) to eliminate
the unused import warning and keep imports minimal.
- Around line 7-10: The PathData type currently uses any[] for nodes and links
which reduces type safety; update the PathData definition in lib/utils.ts to use
the specific imported Node and Link types (i.e., nodes: Node[] and links:
Link[]), add/import those types if they are not already imported, and adjust any
call sites or tests that relied on any[] to satisfy the stronger types.
- Around line 31-36: The Message interface's paths property is weakly typed
using any[]; replace it with the existing PathData type for stronger typing:
change paths?: { nodes: any[], links: any[] }[] to paths?: PathData[] (or
Array<PathData>) in the Message interface so it uses the PathData definition
above and preserves optionality. Ensure PathData is visible in the same module
(or imported) so the Message type compiles.

In `@package.json`:
- Line 29: Add the DefinitelyTyped declarations for D3 by adding "@types/d3":
"^7.4.3" to devDependencies in package.json so TypeScript has typings when d3 is
imported; update the package.json devDependencies block (referencing the
existing "d3" dependency) and run npm/yarn install to persist the change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fea017b and 1d41240.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (28)
  • .github/dependabot.yml
  • .github/workflows/nextjs.yml
  • .github/workflows/playwright.yml
  • Dockerfile
  • README.md
  • app/api/repo/route.ts
  • app/components/ForceGraph.tsx
  • app/components/chat.tsx
  • app/components/code-graph.tsx
  • app/components/dataPanel.tsx
  • app/components/elementMenu.tsx
  • app/components/graphView.tsx
  • app/components/model.ts
  • app/components/toolbar.tsx
  • app/page.tsx
  • components/ui/switch.tsx
  • e2e/config/testData.ts
  • e2e/infra/ui/basePage.ts
  • e2e/infra/ui/browserWrapper.ts
  • e2e/logic/POM/codeGraph.ts
  • e2e/logic/utils.ts
  • e2e/tests/canvas.spec.ts
  • e2e/tests/chat.spec.ts
  • e2e/tests/nodeDetailsPanel.spec.ts
  • e2e/tests/searchBar.spec.ts
  • lib/utils.ts
  • package.json
  • playwright.config.ts
✅ Files skipped from review due to trivial changes (1)
  • e2e/infra/ui/browserWrapper.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/playwright.yml
  • app/components/elementMenu.tsx
  • e2e/tests/nodeDetailsPanel.spec.ts

if (!canvas) return
setSelectedPath(prev => {
if (prev) {
if (isPathResponse && paths.some((path) => [...path.nodes, ...path.links].every((e: any) => [...prev.nodes, ...prev.links].some((e: any) => e.id === e.id)))) {
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 | 🟠 Major

Fix always-true path-overlap comparison.

Line 100 compares e.id === e.id, which is always true. This makes the overlap condition unreliable and can mark/unmark path selection incorrectly.

Proposed fix
-                if (isPathResponse && paths.some((path) => [...path.nodes, ...path.links].every((e: any) => [...prev.nodes, ...prev.links].some((e: any) => e.id === e.id)))) {
+                if (isPathResponse && paths.some((path) =>
+                    [...path.nodes, ...path.links].every((pathEl: any) =>
+                        [...prev.nodes, ...prev.links].some((prevEl: any) => prevEl.id === pathEl.id)
+                    )
+                )) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isPathResponse && paths.some((path) => [...path.nodes, ...path.links].every((e: any) => [...prev.nodes, ...prev.links].some((e: any) => e.id === e.id)))) {
if (isPathResponse && paths.some((path) =>
[...path.nodes, ...path.links].every((pathEl: any) =>
[...prev.nodes, ...prev.links].some((prevEl: any) => prevEl.id === pathEl.id)
)
)) {
🧰 Tools
🪛 Biome (2.4.4)

[error] 100-100: Comparing to itself is potentially pointless.

(lint/suspicious/noSelfCompare)

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

In `@app/components/chat.tsx` at line 100, The overlap check uses the same
identifier for both elements so e.id === e.id is always true; update the inner
some() callback to use a different variable name (e.g., prevElem) and compare
e.id === prevElem.id so you're comparing an element from the current path
(paths.some path -> e) against elements from the previous selection
([...prev.nodes, ...prev.links] -> prevElem). Locate the lambda in the
paths.some(... every(... some(...))) expression in chat.tsx and rename the inner
callback parameter and its comparison to fix the logic.

Comment on lines 106 to 110
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Delete') {
if (selectedObj && selectedObjects.length === 0) return
handelRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined));
handleRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined), "nodes");
}
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 | 🟠 Major

Fix inverted Delete-key guard for single selection.

Line 108 returns early when selectedObj exists and selectedObjects is empty, which blocks deleting a single selected item via keyboard.

Proposed fix
         const handleKeyDown = (event: KeyboardEvent) => {
             if (event.key === 'Delete') {
-                if (selectedObj && selectedObjects.length === 0) return
+                if (!selectedObj && selectedObjects.length === 0) return
                 handleRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined), "nodes");
             }
         };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Delete') {
if (selectedObj && selectedObjects.length === 0) return
handelRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined));
handleRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined), "nodes");
}
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Delete') {
if (!selectedObj && selectedObjects.length === 0) return
handleRemove([...selectedObjects.map(obj => obj.id), selectedObj?.id].filter(id => id !== undefined), "nodes");
}
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/code-graph.tsx` around lines 106 - 110, The Delete-key guard
in handleKeyDown is inverted: it currently returns early when selectedObj exists
and selectedObjects is empty, preventing single-selection deletion; update the
condition so it only returns early when there is neither a single selectedObj
nor any selectedObjects (i.e., if (!selectedObj && selectedObjects.length === 0)
return), then call handleRemove with the combined ids computed from
selectedObjects.map(obj => obj.id) and selectedObj?.id filtered for undefined,
ensuring you still pass "nodes" as the second arg.

Comment on lines +21 to +26
"isPathSelected",
"visible",
"index",
"curve",
"__indexColor",
"isPathSelected",
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

Duplicate entry in excludedProperties array.

"isPathSelected" appears twice in the array (lines 21 and 26). This is redundant and should be removed.

💡 Proposed fix
     "isPath",
     "isPathSelected",
     "visible",
     "index",
     "curve",
     "__indexColor",
-    "isPathSelected",
     "__controlPoints",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"isPathSelected",
"visible",
"index",
"curve",
"__indexColor",
"isPathSelected",
"isPath",
"isPathSelected",
"visible",
"index",
"curve",
"__indexColor",
"__controlPoints",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/dataPanel.tsx` around lines 21 - 26, The excludedProperties
array in dataPanel.tsx contains a duplicate entry "isPathSelected"; remove the
redundant "isPathSelected" so that excludedProperties only lists each property
once (locate the array named excludedProperties in app/components/dataPanel.tsx
and delete the duplicate string entry).

Comment on lines +95 to +112
valueRenderer={(valueAsString, value, keyPath) => {
if (keyPath === "src") {
return <SyntaxHighlighter
language="python"
style={{
...dark,
hljs: {
...dark.hljs,
maxHeight: `9rem`,
background: '#343434',
padding: 2,
}
}}
>
{value as string}
</SyntaxHighlighter>
}
return <span className="text-white">{value as string}</span>
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 | 🟠 Major

🧩 Analysis chain

🌐 Web query:

react-json-tree valueRenderer keyPath parameter type documentation

💡 Result:

In react-json-tree, the valueRenderer prop uses this (TypeScript) function type:

type KeyPath = readonly (string | number)[];

type ValueRenderer = (
  valueAsString: unknown,
  value: unknown,
  ...keyPath: KeyPath
) => React.ReactNode;

So:

  • valueAsString: the library’s preformatted “display string” for the value (passed as unknown). [1][2]
  • value: the original raw value (passed as unknown). [1][2]
  • keyPath: a path made of object keys (string) and array indices (number). In the signature it’s a rest parameter (...keyPath), so in your implementation you typically write (...keyPath) to receive it as an array. Its element type is (string | number)[] / KeyPath. [1][2]

Related docs also show the public signatures as:

  • labelRenderer(keyPath, nodeType, expanded, expandable)
  • valueRenderer(valueAsString, value, ...keyPath) [3]

And examples often treat the first element of keyPath as the “current key” (e.g. labelRenderer={([key]) => ...}), implying keyPath[0] is the current property name / index. [3]

Sources: [1] [2] [3]


Use rest parameters to properly access the full keyPath array.

The valueRenderer callback should receive keyPath as rest parameters: (...keyPath). In react-json-tree, keyPath is an array of keys representing the path to the value, not a single string. The current implementation (valueAsString, value, keyPath) will only capture the first path element. To check if a value is at the "src" key, compare the first element: keyPath[0] === "src".

Suggested fix
valueRenderer={(...keyPath) => {
    if (keyPath[0] === "src") {
        // render syntax highlighter
    }
    // fallback
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/dataPanel.tsx` around lines 95 - 112, The valueRenderer is
declared with parameters (valueAsString, value, keyPath) but react-json-tree
passes keyPath as rest parameters; update the valueRenderer implementation (the
prop named valueRenderer) to accept rest parameters (e.g., (...keyPath)) and
then check the first element keyPath[0] === "src" to decide when to render the
SyntaxHighlighter in the DataPanel component; ensure the fallback still returns
the span with className "text-white".

Comment on lines +167 to +168
if (!node.x || !node.y) return

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

Avoid falsy coordinate checks that drop valid (0, y) / (x, 0) nodes.

Line 167 and Line 234 use !node.x || !node.y; coordinates at 0 are valid and should still render/hit-test.

Proposed fix
-        if (!node.x || !node.y) return
+        if (node.x == null || node.y == null) return
@@
-        if (!node.x || !node.y) return
+        if (node.x == null || node.y == null) return

Also applies to: 234-235

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

In `@app/components/graphView.tsx` around lines 167 - 168, The current checks use
"!node.x || !node.y" which incorrectly treats 0 as missing; update both
occurrences where that check appears (the conditional guarding
rendering/hit-testing of a node) to explicitly test for null/undefined instead,
e.g. use "node.x == null || node.y == null" or "node.x === undefined || node.y
=== undefined" (or prefer Number.isFinite(node.x) && Number.isFinite(node.y) if
you want to ensure numeric coordinates) so nodes at x=0 or y=0 are not skipped.

Comment on lines +85 to +87
const number = uiResponse.match(/\d+/g)?.[0]!;

expect(number).toEqual(apiResponse.result.response.match(/\d+/g)?.[0]);
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

Same non-null assertion issue after optional chaining.

This has the same problem as line 69. Additionally, the API response comparison could fail if either side doesn't match the expected pattern.

💡 Proposed fix
     const uiResponse = await chat.getTextInLastChatElement();
-    const number = uiResponse.match(/\d+/g)?.[0]!;
-    
-    expect(number).toEqual(apiResponse.result.response.match(/\d+/g)?.[0]);
+    const uiMatch = uiResponse.match(/\d+/g);
+    const apiMatch = apiResponse.result.response.match(/\d+/g);
+    expect(uiMatch).toBeTruthy();
+    expect(apiMatch).toBeTruthy();
+    expect(uiMatch![0]).toEqual(apiMatch![0]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const number = uiResponse.match(/\d+/g)?.[0]!;
expect(number).toEqual(apiResponse.result.response.match(/\d+/g)?.[0]);
const uiMatch = uiResponse.match(/\d+/g);
const apiMatch = apiResponse.result.response.match(/\d+/g);
expect(uiMatch).toBeTruthy();
expect(apiMatch).toBeTruthy();
expect(uiMatch![0]).toEqual(apiMatch![0]);
🧰 Tools
🪛 Biome (2.4.4)

[error] 85-85: Forbidden non-null assertion after optional chaining.

(lint/suspicious/noNonNullAssertedOptionalChain)

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

In `@e2e/tests/chat.spec.ts` around lines 85 - 87, The test uses a non-null
assertion on const number = uiResponse.match(/\d+/g)?.[0]! which can throw if
the regex doesn't match and also directly compares to
apiResponse.result.response.match(...), so update the assertion to avoid the
trailing "!" and first capture both matches into temporaries (e.g., uiMatch and
apiMatch), assert each is defined (or fail with a clear message) and then
compare them; reference the variables uiResponse, apiResponse, and the extracted
value currently named number to locate the lines to change and ensure robust
null/undefined handling before calling expect(...).toEqual(...).

"embla-carousel-react": "^8.5.2",
"html2canvas": "^1.4.1",
"lucide-react": "^0.486.0",
"next": "^15.5.8",
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 | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Next.js 15.5.8 release date stability React 18 compatibility

💡 Result:

  • Next.js 15.5.8 release date: December 11, 2025 (tag v15.5.8 in vercel/next.js). [1]
  • Stability (15.5.8 / 15.x line): Next.js 15.x is in Maintenance LTS (limited to critical fixes/security updates), which generally implies low-risk patch/minor updates—but 15.5.8 specifically has known security advisories in common scanners (e.g., issues fixed in 15.5.9 and 15.5.10+), so for production you should prefer upgrading beyond 15.5.8. [2][3]
  • React 18 compatibility:
    • Pages Router: Next.js 15 maintains backward compatibility with React 18 (so you can run React 18 there). [4]
    • App Router: Next.js 15’s App Router is aligned with React 19 (React 19 RC in the original 15 release notes); mixing/forcing React 18 with App Router is not the intended/supported path. [4]
    • Next.js 15’s dependency ranges also reflect this split (react/react-dom: ^18.2.0 || 19.0.0-rc...). [5]

Sources: [1] GitHub release tag v15.5.8, [2] Next.js Support Policy, [3] Snyk entry for next@15.5.8, [4] Next.js 15 blog (React 19 + React 18 Pages Router compatibility), [5] vercel/next.js discussion #72795.


🌐 Web query:

Next.js 15 latest version React 18.3.1 peer dependencies

💡 Result:

  • Next.js 15 react / react-dom peer dependency range (from next package):
    ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 (same for both react and react-dom). [1]

  • Does react@18.3.1 satisfy that peer range?
    Yes — 18.3.1 matches ^18.2.0. [1]

  • Note on “latest” guidance: Next.js’s v15 upgrade guide says the minimum react / react-dom is now 19 (and suggests upgrading React accordingly), even though the published next peer range still allows React 18. [2]

Sources
[1] next@15.4.5 package.json on UNPKG (peerDependencies) (app.unpkg.com)
[2] Next.js “Upgrading: Version 15” (React 19 minimum note) (nextjs.org)

Citations:


Upgrade Next.js 15.5.8 to a patched version and consider upgrading React to 19.

Next.js 15.5.8 has known security advisories; upgrade to 15.5.9 or later. While React 18.3.1 technically satisfies the peer dependency range, Next.js 15's App Router is aligned with React 19. If using App Router (the recommended modern approach), React 19 is the intended minimum version. React 18 is only fully supported for the Pages Router.

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

In `@package.json` at line 33, package.json pins Next.js to "next": "^15.5.8"
which has security advisories and may require React 19 for App Router; update
the "next" dependency to a patched release (>=15.5.9) and, if your app uses the
App Router, bump "react" and "react-dom" to React 19-compatible versions
(replace current "react" and "react-dom" entries) and run install and test to
resolve peer dependency warnings and verify the app and App Router behavior.

Comment on lines 22 to +23
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 2 : undefined,
workers: process.env.CI ? 3 : undefined,
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

Update the stale CI parallelism comment.

Line 22 says CI opts out of parallel tests, but Line 23 sets workers to 3 on CI. This is misleading for future maintainers.

Suggested fix
-  /* Opt out of parallel tests on CI. */
+  /* Limit parallelism on CI to reduce flakiness while keeping runtime reasonable. */
   workers: process.env.CI ? 3 : undefined,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 2 : undefined,
workers: process.env.CI ? 3 : undefined,
/* Limit parallelism on CI to reduce flakiness while keeping runtime reasonable. */
workers: process.env.CI ? 3 : undefined,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright.config.ts` around lines 22 - 23, The comment above the workers
setting is stale: update the comment to accurately describe the current behavior
of the workers property (workers: process.env.CI ? 3 : undefined) — e.g., change
the comment to something like "Use a fixed 3 workers on CI (otherwise default)"
or similar so it no longer says we opt out of parallel tests; ensure you edit
the comment immediately above the workers property that references the workers
setting.

[![Dockerhub](https://img.shields.io/docker/pulls/falkordb/falkordb?label=Docker)](https://hub.docker.com/r/falkordb/falkordb/)
[![Discord](https://img.shields.io/discord/1146782921294884966?style=flat-square)](https://discord.com/invite/6M4QwDXn2w)
[![Workflow](https://github.com/FalkorDB/code-graph/actions/workflows/nextjs.yml/badge.svg?branch=main)](https://github.com/FalkorDB/code-graph/actions/workflows/nextjs.yml)
-
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

Remove stray character.

Line 9 contains a lone - which appears to be a leftover from editing. This should be removed.

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

In `@README.md` at line 9, Remove the stray lone "-" character present in the
README (the stray hyphen on its own line) so the file has no extraneous
characters; simply delete that line containing only "-" and save the README to
restore clean formatting.


Have questions or feedback? Reach out via:

* [GitHub Issues](https://github.com/FalkorDB/GraphRAG-SDK/issues)
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

Verify the GitHub Issues link.

The issues link points to https://github.com/FalkorDB/GraphRAG-SDK/issues, but this README is for the code-graph repository. Should this link to https://github.com/FalkorDB/code-graph/issues instead?

🔧 Proposed fix
-* [GitHub Issues](https://github.com/FalkorDB/GraphRAG-SDK/issues)
+* [GitHub Issues](https://github.com/FalkorDB/code-graph/issues)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* [GitHub Issues](https://github.com/FalkorDB/GraphRAG-SDK/issues)
* [GitHub Issues](https://github.com/FalkorDB/code-graph/issues)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 109, Update the GitHub Issues link in the README: replace
the current URL "https://github.com/FalkorDB/GraphRAG-SDK/issues" referenced by
the "[GitHub Issues]" list item with
"https://github.com/FalkorDB/code-graph/issues" so the repo's README points to
the correct issue tracker for code-graph.

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.

6 participants