Skip to content

Commit 1d41240

Browse files
authored
Merge pull request #500 from FalkorDB/merge-main-to-staging
Update dependencies and improve test configurations
2 parents 4200dbb + 998b2a3 commit 1d41240

28 files changed

Lines changed: 3754 additions & 2504 deletions

.github/workflows/nextjs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
- name: Setup Node
5454
uses: actions/setup-node@v4
5555
with:
56-
node-version: "20"
56+
node-version: "24"
5757
cache: ${{ steps.detect-package-manager.outputs.manager }}
5858
- name: Restore cache
5959
uses: actions/cache@v3

.github/workflows/playwright.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ jobs:
88
test:
99
timeout-minutes: 60
1010
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
shard: [1, 2]
1115
services:
1216
falkordb:
1317
image: falkordb/falkordb:latest
@@ -17,7 +21,7 @@ jobs:
1721
- uses: actions/checkout@v4
1822
- uses: actions/setup-node@v4
1923
with:
20-
node-version: lts/*
24+
node-version: 24
2125
- name: Install dependencies
2226
run: npm ci
2327
- name: Install Playwright Browsers
@@ -32,21 +36,21 @@ jobs:
3236
run: |
3337
npm install
3438
npm run build
35-
NEXTAUTH_SECRET=SECRET npm start & npx playwright test --reporter=dot,list
39+
NEXTAUTH_SECRET=SECRET npm start & npx playwright test --shard=${{ matrix.shard }}/2 --reporter=dot,list
3640
- name: Ensure required directories exist
3741
run: |
3842
mkdir -p playwright-report
3943
mkdir -p playwright-report/artifacts
4044
- uses: actions/upload-artifact@v4
4145
if: always()
4246
with:
43-
name: playwright-report
47+
name: playwright-report-shard-${{ matrix.shard }}
4448
path: playwright-report/
4549
retention-days: 30
4650
- name: Upload failed test screenshots
4751
if: always()
4852
uses: actions/upload-artifact@v4
4953
with:
50-
name: failed-test-screenshots
54+
name: failed-test-screenshots-shard-${{ matrix.shard }}
5155
path: playwright-report/artifacts/
5256
retention-days: 30

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Use a Node.js base image
2-
FROM node:22
2+
FROM node:24
33

44
# Set working directory
55
WORKDIR /app

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ curl -X POST http://127.0.0.1:5000/analyze_folder \
9292
-d '{"path": "<PATH_TO_LOCAL_REPO>", "ignore": ["./.github", "./sbin", "./.git", "./deps", "./bin", "./build"]}'
9393
```
9494

95-
**Note:** Currently, Code-Graph supports analyzing C and Python source files.
96-
Support for additional languages (e.g., JavaScript, Go, Java) is planned.
95+
Note: At the moment code-graph can analyze both the Java & Python source files.
96+
Support for additional languages e.g. C, JavaScript, Go is planned to be added
97+
in the future.
9798

9899
### 5. Access the Web Interface
99100

app/api/repo/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export async function GET() {
2222
return NextResponse.json({ result: repositories }, { status: 200 })
2323
} catch (err) {
2424
console.error(err)
25-
return NextResponse.json((err as Error).message, { status: 400 })
25+
return NextResponse.json(err instanceof Error ? err.message : String(err), { status: 400 })
2626
}
2727
}
2828

@@ -57,6 +57,6 @@ export async function POST(request: NextRequest) {
5757
return NextResponse.json({ message: "success" }, { status: 200 });
5858
} catch (err) {
5959
console.error(err)
60-
return NextResponse.json((err as Error).message, { status: 400 });
60+
return NextResponse.json(err instanceof Error ? err.message : String(err), { status: 400 });
6161
}
6262
}

app/components/ForceGraph.tsx

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
"use client"
2+
3+
import { useCallback, useEffect, useState } from "react"
4+
import type { Data, GraphLink, GraphNode } from "@falkordb/canvas"
5+
import { GraphRef, PATH_COLOR } from "@/lib/utils"
6+
import { GraphData, Link, Node } from "./model"
7+
8+
interface Props {
9+
id: "desktop" | "mobile"
10+
data: GraphData
11+
canvasRef: GraphRef
12+
onNodeClick: (node: Node, event: MouseEvent) => void
13+
onNodeHover: (node: Node | null) => void
14+
onNodeRightClick: (node: Node, event: MouseEvent) => void
15+
isNodeSelected: (node: GraphNode) => boolean
16+
onLinkClick: (link: Link, event: MouseEvent) => void
17+
onLinkHover: (link: Link | null) => void
18+
onLinkRightClick: (link: Link, event: MouseEvent) => void
19+
isLinkSelected: (link: GraphLink) => boolean
20+
onBackgroundClick: (event: MouseEvent) => void
21+
onBackgroundRightClick: (event: MouseEvent) => void
22+
nodeCanvasObject: (node: GraphNode, ctx: CanvasRenderingContext2D) => void
23+
nodePointerAreaPaint: (node: GraphNode, color: string, ctx: CanvasRenderingContext2D) => void
24+
linkLineDash: (link: any) => number[] | null
25+
onZoom: () => void
26+
onEngineStop: () => void
27+
cooldownTicks: number | undefined
28+
backgroundColor?: string
29+
foregroundColor?: string
30+
}
31+
32+
const convertToCanvasData = (graphData: GraphData): Data => ({
33+
nodes: graphData.nodes.filter(n => n.visible).map(({ id, category, color, visible, isPath, isPathSelected, data }) => ({
34+
id,
35+
labels: [category],
36+
color,
37+
visible,
38+
data: { ...data, isPath, isPathSelected }
39+
})),
40+
links: graphData.links.filter(l => l.visible).map(({ id, label, color, visible, source, target, isPath, isPathSelected, data }) => ({
41+
id,
42+
relationship: label,
43+
color: isPath ? PATH_COLOR : color,
44+
visible,
45+
source,
46+
target,
47+
data: { ...data, isPath, isPathSelected }
48+
}))
49+
});
50+
51+
export default function ForceGraph({
52+
id,
53+
data,
54+
canvasRef,
55+
onNodeClick,
56+
onNodeHover,
57+
onNodeRightClick,
58+
isNodeSelected,
59+
onLinkClick,
60+
onLinkHover,
61+
onLinkRightClick,
62+
isLinkSelected,
63+
onBackgroundClick,
64+
onBackgroundRightClick,
65+
onZoom,
66+
onEngineStop,
67+
nodeCanvasObject,
68+
nodePointerAreaPaint,
69+
linkLineDash,
70+
cooldownTicks,
71+
backgroundColor = "#FFFFFF",
72+
foregroundColor = "#000000"
73+
}: Props) {
74+
const [canvasLoaded, setCanvasLoaded] = useState(false)
75+
76+
// Load falkordb-canvas dynamically (client-only)
77+
useEffect(() => {
78+
import('@falkordb/canvas').then(() => {
79+
setCanvasLoaded(true)
80+
})
81+
}, [])
82+
83+
useEffect(() => {
84+
const canvas = canvasRef.current
85+
86+
if (!canvas) return
87+
88+
(window as any)[id === "desktop" ? "graphDesktop" : "graphMobile"] = () => canvas.getGraphData();
89+
}, [canvasRef, id])
90+
91+
// Update canvas colors
92+
useEffect(() => {
93+
if (!canvasRef.current || !canvasLoaded) return
94+
canvasRef.current.setBackgroundColor(backgroundColor)
95+
canvasRef.current.setForegroundColor(foregroundColor)
96+
}, [canvasRef, backgroundColor, foregroundColor, canvasLoaded])
97+
98+
// Update cooldown ticks
99+
useEffect(() => {
100+
if (!canvasRef.current || !canvasLoaded) return
101+
102+
canvasRef.current.setCooldownTicks(cooldownTicks === -1 ? undefined : cooldownTicks)
103+
}, [canvasRef, cooldownTicks, canvasLoaded])
104+
105+
// Map node click handler
106+
const handleNodeClick = useCallback((node: GraphNode, event: MouseEvent) => {
107+
const originalNode = data.nodes.find(n => n.id === node.id)
108+
if (originalNode) onNodeClick(originalNode, event)
109+
}, [onNodeClick, data.nodes])
110+
111+
// Map node hover handler
112+
const handleNodeHover = useCallback((node: GraphNode | null) => {
113+
if (!node) {
114+
onNodeHover(null)
115+
return
116+
}
117+
118+
const originalNode = data.nodes.find(n => n.id === node.id)
119+
120+
if (originalNode) onNodeHover(originalNode)
121+
}, [onNodeHover, data.nodes])
122+
123+
// Map node right click handler
124+
const handleNodeRightClick = useCallback((node: GraphNode, event: MouseEvent) => {
125+
const originalNode = data.nodes.find(n => n.id === node.id)
126+
if (originalNode) onNodeRightClick(originalNode, event)
127+
}, [onNodeRightClick, data.nodes])
128+
129+
// Map link click handler
130+
const handleLinkClick = useCallback((link: GraphLink, event: MouseEvent) => {
131+
const originalLink = data.links.find(l => l.id === link.id)
132+
if (originalLink) onLinkClick(originalLink, event)
133+
}, [onLinkClick, data.links])
134+
135+
// Map link hover handler
136+
const handleLinkHover = useCallback((link: GraphLink | null) => {
137+
if (!link) {
138+
onLinkHover(null)
139+
return
140+
}
141+
142+
const originalLink = data.links.find(l => l.id === link.id)
143+
144+
if (originalLink) onLinkHover(originalLink)
145+
}, [onLinkHover, data.links])
146+
147+
// Map link right click handler
148+
const handleLinkRightClick = useCallback((link: GraphLink, event: MouseEvent) => {
149+
const originalLink = data.links.find(l => l.id === link.id)
150+
if (originalLink) onLinkRightClick(originalLink, event)
151+
}, [onLinkRightClick, data.links])
152+
153+
// Handle engine stop and set window.graph
154+
const handleEngineStop = useCallback(() => {
155+
onEngineStop()
156+
}, [canvasRef, onEngineStop])
157+
158+
// Update event handlers
159+
useEffect(() => {
160+
if (!canvasRef.current || !canvasLoaded) return
161+
canvasRef.current.setConfig({
162+
autoStopOnSettle: false,
163+
// nodes will display node.data.captionsKeys in the canvas
164+
captionsKeys: ["name", "title"],
165+
onNodeClick: handleNodeClick,
166+
onNodeRightClick: handleNodeRightClick,
167+
onNodeHover: handleNodeHover,
168+
isNodeSelected: isNodeSelected,
169+
onLinkClick: handleLinkClick,
170+
onLinkRightClick: handleLinkRightClick,
171+
onLinkHover: handleLinkHover,
172+
isLinkSelected: isLinkSelected,
173+
onBackgroundClick,
174+
onBackgroundRightClick,
175+
onEngineStop: handleEngineStop,
176+
node: { nodeCanvasObject, nodePointerAreaPaint },
177+
linkLineDash,
178+
onZoom
179+
})
180+
}, [
181+
handleNodeClick,
182+
handleNodeRightClick,
183+
handleNodeHover,
184+
handleLinkClick,
185+
handleLinkRightClick,
186+
handleLinkHover,
187+
isNodeSelected,
188+
isLinkSelected,
189+
onBackgroundClick,
190+
onBackgroundRightClick,
191+
handleEngineStop,
192+
nodeCanvasObject,
193+
nodePointerAreaPaint,
194+
linkLineDash,
195+
onZoom,
196+
canvasRef,
197+
canvasLoaded
198+
])
199+
200+
// Update canvas data
201+
useEffect(() => {
202+
const canvas = canvasRef.current
203+
if (!canvas || !canvasLoaded) return
204+
205+
const canvasData = convertToCanvasData(data)
206+
canvas.setData(canvasData)
207+
}, [canvasRef, data, canvasLoaded])
208+
209+
return (
210+
<falkordb-canvas ref={canvasRef} node-mode="replace" />
211+
)
212+
}

0 commit comments

Comments
 (0)