Skip to content

Commit 37825fa

Browse files
committed
fix node issues in flow chart
1 parent ae7b7a4 commit 37825fa

File tree

1 file changed

+129
-16
lines changed

1 file changed

+129
-16
lines changed

apps/web/src/app/(home)/_components/CustomizableStack.tsx

Lines changed: 129 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import {
44
Background,
5+
type Connection,
56
ReactFlow,
67
useEdgesState,
78
useNodesState,
@@ -16,8 +17,8 @@ import { TechNodeComponent } from "./TechNodeComponent";
1617
const initialEdges = [
1718
{ id: "bun-hono", source: "bun", target: "hono", animated: true },
1819
{ id: "bun-tanstack", source: "bun", target: "tanstack", animated: true },
19-
{ id: "hono-libsql", source: "hono", target: "libsql", animated: true },
20-
{ id: "libsql-drizzle", source: "libsql", target: "drizzle", animated: true },
20+
{ id: "hono-libsql", source: "hono", target: "sqlite", animated: true },
21+
{ id: "libsql-drizzle", source: "sqlite", target: "drizzle", animated: true },
2122
{
2223
id: "hono-better-auth",
2324
source: "hono",
@@ -47,6 +48,29 @@ const CustomizableStack = () => {
4748
auth: "better-auth",
4849
});
4950

51+
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
52+
const cleanupConnectionsByCategory = useCallback((category: string) => {
53+
setEdges((eds) =>
54+
eds.filter((edge) => {
55+
if (category === "database") {
56+
return !(
57+
["postgres", "sqlite"].includes(edge.target) ||
58+
["postgres", "sqlite"].includes(edge.source) ||
59+
edge.target === "drizzle" ||
60+
edge.target === "prisma"
61+
);
62+
}
63+
if (category === "orm") {
64+
return !(edge.target === "drizzle" || edge.target === "prisma");
65+
}
66+
if (category === "auth") {
67+
return !["better-auth", "no-auth"].includes(edge.target);
68+
}
69+
return true;
70+
}),
71+
);
72+
}, []);
73+
5074
const handleTechSelect = useCallback(
5175
(category: string, techId: string) => {
5276
setActiveNodes((prev) => ({ ...prev, [category]: techId }));
@@ -64,16 +88,8 @@ const CustomizableStack = () => {
6488
},
6589
})),
6690
);
67-
setEdges((eds) =>
68-
eds.filter((edge) => {
69-
const targetNode = nodes.find((n) => n.id === edge.target);
70-
const sourceNode = nodes.find((n) => n.id === edge.source);
71-
return !(
72-
targetNode?.data.category === category ||
73-
sourceNode?.data.category === category
74-
);
75-
}),
76-
);
91+
92+
cleanupConnectionsByCategory(category);
7793

7894
if (category === "database") {
7995
const honoNode = nodes.find((n) => n.id === "hono");
@@ -125,12 +141,105 @@ const CustomizableStack = () => {
125141
}
126142
}
127143
},
128-
[nodes, setNodes, setEdges],
144+
[nodes, setNodes, setEdges, cleanupConnectionsByCategory],
129145
);
130146

131-
const onConnect = useCallback(() => {
132-
return;
133-
}, []);
147+
const isValidConnection = useCallback(
148+
(connection: Connection) => {
149+
const sourceNode = nodes.find((n) => n.id === connection.source);
150+
const targetNode = nodes.find((n) => n.id === connection.target);
151+
152+
if (!sourceNode || !targetNode) return false;
153+
154+
if (sourceNode.id === "hono" && targetNode.data.category === "database") {
155+
return ["postgres", "sqlite"].includes(targetNode.id);
156+
}
157+
158+
if (sourceNode.id === "hono" && targetNode.data.category === "auth") {
159+
return ["better-auth", "no-auth"].includes(targetNode.id);
160+
}
161+
162+
if (
163+
["postgres", "sqlite"].includes(sourceNode.id) &&
164+
targetNode.data.category === "orm"
165+
) {
166+
return true;
167+
}
168+
169+
return false;
170+
},
171+
[nodes],
172+
);
173+
174+
const cleanupPreviousConnections = useCallback(
175+
(connection: Connection) => {
176+
const sourceNode = nodes.find((n) => n.id === connection.source);
177+
const targetNode = nodes.find((n) => n.id === connection.target);
178+
if (!targetNode || !sourceNode) return;
179+
180+
cleanupConnectionsByCategory(targetNode.data.category);
181+
},
182+
[nodes, cleanupConnectionsByCategory],
183+
);
184+
185+
const onConnect = useCallback(
186+
(connection: Connection) => {
187+
if (!isValidConnection(connection)) return;
188+
cleanupPreviousConnections(connection);
189+
const targetNode = nodes.find((n) => n.id === connection.target);
190+
if (!targetNode) return;
191+
192+
setEdges((eds) => {
193+
const newEdges = [
194+
...eds,
195+
{
196+
id: `${connection.source}-${connection.target}`,
197+
source: connection.source,
198+
target: connection.target,
199+
animated: true,
200+
},
201+
];
202+
203+
if (targetNode.data.category === "database") {
204+
const activeOrm = nodes.find(
205+
(n) => n.data.category === "orm" && n.data.isActive,
206+
);
207+
if (activeOrm) {
208+
newEdges.push({
209+
id: `${connection.target}-${activeOrm.id}`,
210+
source: connection.target,
211+
target: activeOrm.id,
212+
animated: true,
213+
});
214+
}
215+
}
216+
217+
return newEdges;
218+
});
219+
220+
if (targetNode.data.category) {
221+
setActiveNodes((prev) => ({
222+
...prev,
223+
[targetNode.data.category]: connection.target,
224+
}));
225+
226+
setNodes((nds) =>
227+
nds.map((node) => ({
228+
...node,
229+
data: {
230+
...node.data,
231+
isActive: node.data.isStatic
232+
? true
233+
: node.data.category === targetNode.data.category
234+
? node.id === connection.target
235+
: node.data.isActive,
236+
},
237+
})),
238+
);
239+
}
240+
},
241+
[nodes, setEdges, setNodes, cleanupPreviousConnections, isValidConnection],
242+
);
134243

135244
const generateCommand = useCallback(() => {
136245
const flags: string[] = ["-y"];
@@ -178,6 +287,10 @@ const CustomizableStack = () => {
178287
zoomOnPinch={false}
179288
preventScrolling={false}
180289
nodesConnectable={true}
290+
nodesDraggable={false}
291+
connectOnClick={true}
292+
deleteKeyCode="Delete"
293+
selectionKeyCode="Shift"
181294
>
182295
<Background
183296
className="bg-gray-950/5"

0 commit comments

Comments
 (0)