Canvas: Fix linter errors
Change-Id: I602c1562d4ab2d948bb4dcf6caf66f185585d720
diff --git a/apps/canvas/front/eslint.config.js b/apps/canvas/front/eslint.config.js
index 092408a..545cef9 100644
--- a/apps/canvas/front/eslint.config.js
+++ b/apps/canvas/front/eslint.config.js
@@ -23,6 +23,14 @@
'warn',
{ allowConstantExport: true },
],
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ "argsIgnorePattern": "^_$",
+ "varsIgnorePattern": "^_$",
+ "caughtErrorsIgnorePattern": "^_$",
+ }
+ ]
},
},
)
diff --git a/apps/canvas/front/package-lock.json b/apps/canvas/front/package-lock.json
index 39c0823..86e3762 100644
--- a/apps/canvas/front/package-lock.json
+++ b/apps/canvas/front/package-lock.json
@@ -21,7 +21,7 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.1",
- "@radix-ui/react-toast": "^1.2.2",
+ "@radix-ui/react-toast": "^1.2.13",
"@radix-ui/react-tooltip": "^1.1.4",
"@xyflow/react": "^12.3.3",
"class-variance-authority": "^0.7.0",
@@ -1868,22 +1868,276 @@
}
},
"node_modules/@radix-ui/react-toast": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.2.tgz",
- "integrity": "sha512-Z6pqSzmAP/bFJoqMAston4eSNa+ud44NSZTiZUmUen+IOZ5nBY8kzuU5WDBVyFXPtcW6yUalOHsxM/BP6Sv8ww==",
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.13.tgz",
+ "integrity": "sha512-e/e43mQAwgYs8BY4y9l99xTK6ig1bK2uXsFLOMn9IZ16lAgulSTsotcPHVT2ZlSb/ye6Sllq7IgyDB8dGhpeXQ==",
"dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-collection": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.1",
- "@radix-ui/react-dismissable-layer": "1.1.1",
- "@radix-ui/react-portal": "1.1.2",
- "@radix-ui/react-presence": "1.1.1",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "@radix-ui/react-use-controllable-state": "1.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.0",
- "@radix-ui/react-visually-hidden": "1.1.0"
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-collection": "1.1.6",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.9",
+ "@radix-ui/react-portal": "1.1.8",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/primitive": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
+ "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.6.tgz",
+ "integrity": "sha512-PbhRFK4lIEw9ADonj48tiYWzkllz81TM7KVYyyMMw2cwHO7D5h4XKEblL8NlaRisTK3QTe6tBEhDccFUryxHBQ==",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.2",
+ "@radix-ui/react-slot": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.9.tgz",
+ "integrity": "sha512-way197PiTvNp+WBP7svMJasHl+vibhWGQDb6Mgf5mhEWJkgb85z7Lfl9TUdkqpWsf8GRNmoopx9ZxCyDzmgRMQ==",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.8.tgz",
+ "integrity": "sha512-hQsTUIn7p7fxCPvao/q6wpbxmCwgLrlz+nOrJgC+RwfZqWY/WN+UMqkXzrtKbPrF82P43eCTl3ekeKuyAQbFeg==",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
+ "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz",
+ "integrity": "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz",
+ "integrity": "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "dependencies": {
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.2.tgz",
+ "integrity": "sha512-ORCmRUbNiZIv6uV5mhFrhsIKw4UX/N3syZtyqvry61tbGm4JlgQuSn0hk5TwCARsCjkcnuRkSdCE3xfb+ADHew==",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.2"
},
"peerDependencies": {
"@types/react": "*",
diff --git a/apps/canvas/front/package.json b/apps/canvas/front/package.json
index 4c9ba0c..6bfe3cb 100644
--- a/apps/canvas/front/package.json
+++ b/apps/canvas/front/package.json
@@ -27,7 +27,7 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.1",
- "@radix-ui/react-toast": "^1.2.2",
+ "@radix-ui/react-toast": "^1.2.13",
"@radix-ui/react-tooltip": "^1.1.4",
"@xyflow/react": "^12.3.3",
"class-variance-authority": "^0.7.0",
diff --git a/apps/canvas/front/src/Header.tsx b/apps/canvas/front/src/Header.tsx
index 2d6d68d..83c658c 100644
--- a/apps/canvas/front/src/Header.tsx
+++ b/apps/canvas/front/src/Header.tsx
@@ -11,10 +11,6 @@
const { toast } = useToast();
const store = useStateStore();
const [projects, setProjects] = useState<Project[]>([]);
- // TODO(gio): sth fishy is here
- useEffect(() => {
- store.setProjects(projects);
- }, [projects]);
const refreshProjects = useCallback(async () => {
try {
const resp = await fetch("/api/project");
@@ -87,7 +83,7 @@
title: `Failed to create project: ${name}`,
});
});
- }, [name, setCreateNewOpen, toast]); // store
+ }, [name, setCreateNewOpen, toast, store, refreshProjects]);
return (
<div className="flex flex-row h-9">
<Select onValueChange={onSelect} value={project}>
@@ -109,7 +105,7 @@
</SelectItem>
</SelectContent>
</Select>
-
+
</div>
);
}
\ No newline at end of file
diff --git a/apps/canvas/front/src/Integrations.tsx b/apps/canvas/front/src/Integrations.tsx
index a566c22..00fe9f1 100644
--- a/apps/canvas/front/src/Integrations.tsx
+++ b/apps/canvas/front/src/Integrations.tsx
@@ -87,7 +87,7 @@
</Button>
)}
- {(!!!githubService || isEditing) && (
+ {(!githubService || isEditing) && (
<Form {...form}>
<form className="space-y-4" onSubmit={form.handleSubmit(onSubmit)}>
<FormField
diff --git a/apps/canvas/front/src/Messages.tsx b/apps/canvas/front/src/Messages.tsx
index 94cd42e..ecf7777 100644
--- a/apps/canvas/front/src/Messages.tsx
+++ b/apps/canvas/front/src/Messages.tsx
@@ -8,7 +8,7 @@
export function Messages() {
const store = useStateStore();
const nodes = useNodes<AppNode>();
- const [nodeMap, setNodeMap] = useState<Map<string, AppNode>>();
+ const [nodeMap, setNodeMap] = useState<Map<string, AppNode>>(new Map());
useEffect(() => {
setNodeMap(new Map(nodes.map((n) => [n.id, n])));
}, [nodes, setNodeMap]);
@@ -37,22 +37,22 @@
setOpen([...grouped.keys()]);
}, [grouped, setOpen]);
return (
- <Accordion type="multiple" value={open} onValueChange={(v) => setOpen(v)}>
- {[...grouped.entries()].map(([id, messages]) => (
- <AccordionItem key={id} value={id}>
- <AccordionTrigger className="flex flex-row-reverse !space-x-4 !justify-end">
- <Badge>{messages.length}</Badge>
- <div>{id === "global" ? "Global" : nodeLabel(nodeMap?.get(id)!)}</div>
- </AccordionTrigger>
- <AccordionContent>
- <div className="flex flex-col space-y-1">
- {messages.map((m) => (
- <Button key={m.id} variant="ghost" style={{ justifyContent: "flex-start" }} onMouseOver={onClick(m.onHighlight)} onMouseLeave={onClick(m.onLooseHighlight)} onClick={onClick(m.onClick)}>{m.message}</Button>
- ))}
- </div>
- </AccordionContent>
- </AccordionItem>
- ))}
- </Accordion>
+ <Accordion type="multiple" value={open} onValueChange={(v) => setOpen(v)}>
+ {[...grouped.entries()].map(([id, messages]) => (
+ <AccordionItem key={id} value={id}>
+ <AccordionTrigger className="flex flex-row-reverse !space-x-4 !justify-end">
+ <Badge>{messages.length}</Badge>
+ <div>{id === "global" ? "Global" : nodeLabel(nodeMap.get(id)!)}</div>
+ </AccordionTrigger>
+ <AccordionContent>
+ <div className="flex flex-col space-y-1">
+ {messages.map((m) => (
+ <Button key={m.id} variant="ghost" style={{ justifyContent: "flex-start" }} onMouseOver={onClick(m.onHighlight)} onMouseLeave={onClick(m.onLooseHighlight)} onClick={onClick(m.onClick)}>{m.message}</Button>
+ ))}
+ </div>
+ </AccordionContent>
+ </AccordionItem>
+ ))}
+ </Accordion>
)
}
\ No newline at end of file
diff --git a/apps/canvas/front/src/components/actions.tsx b/apps/canvas/front/src/components/actions.tsx
index 0f39e4e..54449c4 100644
--- a/apps/canvas/front/src/components/actions.tsx
+++ b/apps/canvas/front/src/components/actions.tsx
@@ -57,7 +57,7 @@
}
};
setTimeout(m, 100);
- }, [projectId, nodes]);
+ }, [projectId, nodes, store]);
const deploy = useCallback(async () => {
if (projectId == null) {
return;
@@ -99,8 +99,7 @@
} finally {
setLoading(false);
}
- }, [projectId, instance, nodes, env, setLoading]);
- const [st, setSt] = useState<string>();
+ }, [projectId, instance, nodes, env, setLoading, toast, monitor]);
const save = useCallback(async () => {
if (projectId == null) {
return;
@@ -123,7 +122,7 @@
description: await resp.text(),
});
}
- }, [projectId, instance, setSt]);
+ }, [projectId, instance, toast]);
const restoreSaved = useCallback(async () => {
if (projectId == null) {
return;
@@ -136,12 +135,12 @@
store.setNodes(inst.nodes || []);
store.setEdges(inst.edges || []);
instance.setViewport({ x, y, zoom });
- }, [projectId, instance, st]);
+ }, [projectId, instance, store]);
const clear = useCallback(() => {
store.setEdges([]);
store.setNodes([]);
instance.setViewport({ x: 0, y: 0, zoom: 1 });
- }, [store]);
+ }, [store, instance]);
// TODO(gio): Update store
const deleteProject = useCallback(async () => {
if (projectId == null) {
@@ -163,7 +162,7 @@
description: await resp.text(),
});
}
- }, [store, clear]);
+ }, [store, clear, projectId, toast]);
const [props, setProps] = useState({});
useEffect(() => {
if (loading) {
diff --git a/apps/canvas/front/src/components/details.tsx b/apps/canvas/front/src/components/details.tsx
index ffac03f..d498771 100644
--- a/apps/canvas/front/src/components/details.tsx
+++ b/apps/canvas/front/src/components/details.tsx
@@ -3,7 +3,7 @@
import { NodeDetails } from "@/components/node-details";
import { Accordion, AccordionContent, AccordionTrigger } from "./ui/accordion";
import { AccordionItem } from "@radix-ui/react-accordion";
-import { useCallback, useMemo, useState } from "react";
+import { useMemo, useState } from "react";
import { Icon } from "./icon";
function unique<T>(v: T, i: number, a: T[]) {
@@ -21,23 +21,22 @@
["gateway-https", 8],
]);
+function cmpNodes(x: AppNode, y: AppNode): number {
+ if (x.type === y.type) {
+ if (nodeLabel(x) < nodeLabel(y)) {
+ return -1;
+ } else if (nodeLabel(x) > nodeLabel(y)) {
+ return 1;
+ }
+ return 0;
+ }
+ // TODO(gio): why !
+ return (nodeTypeIndex.get(x.type!) || 0) - (nodeTypeIndex.get(y.type!) || 0);
+}
+
export function Details() {
const nodes = useNodes<AppNode>();
- const cmpNodes = useCallback(() => {
- return (x: AppNode, y: AppNode): number => {
- if (x.type === y.type) {
- if (nodeLabel(x) < nodeLabel(y)) {
- return -1;
- } else if (nodeLabel(x) > nodeLabel(y)) {
- return 1;
- }
- return 0;
- }
- // TODO(gio): why !
- return (nodeTypeIndex.get(x.type!) || 0) - (nodeTypeIndex.get(y.type!) || 0);
- };
- }, [nodes]);
- const sorted = useMemo(() => nodes.filter((n) => n.type !== "network").sort(cmpNodes()), [nodes, cmpNodes]);
+ const sorted = useMemo(() => nodes.filter((n) => n.type !== "network").sort(cmpNodes), [nodes]);
const [open, setOpen] = useState<string[]>([]);
const selected = useMemo(() => nodes.filter((n) => n.selected).map((n) => n.id), [nodes]);
const all = useMemo(() => open.concat(selected).filter(unique), [open, selected]);
diff --git a/apps/canvas/front/src/components/node-app.tsx b/apps/canvas/front/src/components/node-app.tsx
index 5b4b3fa..3027f27 100644
--- a/apps/canvas/front/src/components/node-app.tsx
+++ b/apps/canvas/front/src/components/node-app.tsx
@@ -1,9 +1,9 @@
import { v4 as uuidv4 } from "uuid";
import { NodeRect } from './node-rect';
-import { useStateStore, ServiceNode, ServiceTypes, nodeLabel, BoundEnvVar, AppState, nodeIsConnectable, GatewayTCPNode, GatewayHttpsNode } from '@/lib/state';
+import { useStateStore, ServiceNode, ServiceTypes, nodeLabel, BoundEnvVar, AppState, nodeIsConnectable, GatewayTCPNode, GatewayHttpsNode, AppNode } from '@/lib/state';
import { KeyboardEvent, FocusEvent, useCallback, useEffect, useMemo, useState } from 'react';
import { z } from "zod";
-import { DeepPartial, EventType, useForm } from 'react-hook-form';
+import { DeepPartial, EventType, useForm, ControllerRenderProps, FieldPath } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Form, FormControl, FormField, FormItem, FormMessage } from './ui/form';
import { Input } from './ui/input';
@@ -69,7 +69,7 @@
export function NodeAppDetails({ id, data }: ServiceNode) {
const store = useStateStore();
- const nodes = useNodes();
+ const nodes = useNodes<AppNode>();
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
mode: "onChange",
@@ -102,7 +102,7 @@
}),
});
portForm.reset();
- }, [data, portForm]);
+ }, [id, data, portForm, store]);
useEffect(() => {
const sub = form.watch((value: DeepPartial<z.infer<typeof schema>>, { name, type }: { name?: keyof z.infer<typeof schema> | undefined, type?: EventType | undefined }) => {
console.log({ name, type });
@@ -129,8 +129,8 @@
}
});
return () => sub.unsubscribe();
- }, [form, store]);
- const focus = useCallback((field: any, name: string) => {
+ }, [id, form, store]);
+ const focus = useCallback((field: ControllerRenderProps<z.infer<typeof schema>, FieldPath<z.infer<typeof schema>>>, name: string) => {
return (e: HTMLElement | null) => {
field.ref(e);
if (e != null && name === data.activeField) {
@@ -141,7 +141,7 @@
});
}
}
- }, [data, store]);
+ }, [id, data, store]);
const [typeProps, setTypeProps] = useState({});
useEffect(() => {
if (data.activeField === "type") {
@@ -152,7 +152,7 @@
} else {
setTypeProps({});
}
- }, [store, data, setTypeProps]);
+ }, [id, data, store, setTypeProps]);
const editAlias = useCallback((e: BoundEnvVar) => {
return () => {
store.updateNodeData(id, {
@@ -168,7 +168,7 @@
});
};
}, [id, data, store]);
- const saveAlias = (e: BoundEnvVar, value: string, store: AppState) => {
+ const saveAlias = useCallback((e: BoundEnvVar, value: string, store: AppState) => {
store.updateNodeData(id, {
...data,
envVars: data.envVars!.map((o) => {
@@ -184,7 +184,7 @@
}
console.log(o);
if ("alias" in o) {
- const { alias: tmp, ...rest } = o;
+ const { alias: _, ...rest } = o;
console.log(rest);
return {
...rest,
@@ -197,7 +197,7 @@
};
}),
});
- };
+ }, [id, data]);
const saveAliasOnEnter = useCallback((e: BoundEnvVar) => {
return (event: KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter") {
@@ -205,12 +205,12 @@
saveAlias(e, event.currentTarget.value, store);
}
}
- }, [id, data, store]);
+ }, [store, saveAlias]);
const saveAliasOnBlur = useCallback((e: BoundEnvVar) => {
return (event: FocusEvent<HTMLInputElement>) => {
saveAlias(e, event.currentTarget.value, store);
}
- }, [id, data, store]);
+ }, [store, saveAlias]);
const removePort = useCallback((portId: string) => {
// TODO(gio): this is ugly
const tcpRemoved = new Set<string>();
@@ -394,7 +394,7 @@
</SelectTrigger>
</FormControl>
<SelectContent>
- {nodes.filter((n) => n.type === "github" && n.data.repository?.id !== undefined).map((n) => (
+ {(nodes.filter((n) => n.type === "github" && n.data.repository?.id !== undefined) as GithubNode[]).map((n) => (
<SelectItem key={n.id} value={n.id}>{`${n.data.repository?.sshURL}`}</SelectItem>
))}
</SelectContent>
diff --git a/apps/canvas/front/src/components/node-gateway-https.tsx b/apps/canvas/front/src/components/node-gateway-https.tsx
index e618943..6effb26 100644
--- a/apps/canvas/front/src/components/node-gateway-https.tsx
+++ b/apps/canvas/front/src/components/node-gateway-https.tsx
@@ -125,7 +125,7 @@
return nodes.find((n) => n.id === https.serviceId)! as ServiceNode;
}
return null;
- }, [data]);
+ }, [data, nodes]);
const selectable = useMemo(() => {
return nodes.filter((n) => {
if (n.id === id) {
@@ -139,14 +139,14 @@
}
return n.data && n.data.ports && n.data.ports.length > 0;
})
- }, [nodes, selected]);
+ }, [id, nodes, selected]);
useEffect(() => {
const sub = connectedToForm.watch((value: DeepPartial<z.infer<typeof connectedToSchema>>, { name, type }: { name?: keyof z.infer<typeof connectedToSchema> | undefined, type?: EventType | undefined }) => {
if (type !== "change") {
return;
}
switch (name) {
- case "id":
+ case "id": {
if (!value.id) {
break;
}
@@ -159,6 +159,7 @@
targetHandle: "https",
}, cid);
break;
+ }
case "portId":
store.updateNodeData<"gateway-https">(id, {
https: {
@@ -170,7 +171,7 @@
}
});
return () => sub.unsubscribe();
- }, [connectedToForm, store, selectable]);
+ }, [id, connectedToForm, store, selectable]);
const authEnabledForm = useForm<z.infer<typeof authEnabledSchema>>({
resolver: zodResolver(authEnabledSchema),
mode: "onChange",
@@ -224,7 +225,7 @@
},
});
authGroupForm.reset();
- }, [id, data, store]);
+ }, [id, data, store, authGroupForm]);
const removeNoAuthPathPattern = useCallback((path: string) => {
const noAuthPathPatterns = data?.auth?.noAuthPathPatterns || [];
store.updateNodeData<"gateway-https">(id, {
@@ -245,7 +246,7 @@
},
});
authNoAuthPatternFrom.reset();
- }, [id, data, store]);
+ }, [id, data, store, authNoAuthPatternFrom]);
return (
<>
<Form {...form}>
diff --git a/apps/canvas/front/src/components/node-gateway-tcp.tsx b/apps/canvas/front/src/components/node-gateway-tcp.tsx
index 3588502..e16fdd2 100644
--- a/apps/canvas/front/src/components/node-gateway-tcp.tsx
+++ b/apps/canvas/front/src/components/node-gateway-tcp.tsx
@@ -104,7 +104,7 @@
portId: data.selected?.portId,
});
console.log(connectedToForm.getValues());
- }, [connectedToForm, data]);
+ }, [id, connectedToForm, data]);
const nodes = useNodes<AppNode>();
const [selected, setSelected] = useState<AppNode | undefined>(undefined);
useEffect(() => {
@@ -114,7 +114,7 @@
const serviceId = data.selected.serviceId;
setSelected(nodes.find((n) => n.id === serviceId));
}
- }, [data, setSelected]);
+ }, [id, data, setSelected, nodes]);
const selectable = useMemo(() => {
console.log(selected);
return nodes.filter((n) => {
@@ -129,7 +129,7 @@
}
return false;
})
- }, [nodes, selected]);
+ }, [id, nodes, selected]);
useEffect(() => {
const sub = connectedToForm.watch((value: DeepPartial<z.infer<typeof connectedToSchema>>, { name, type }: { name?: keyof z.infer<typeof connectedToSchema> | undefined, type?: EventType | undefined }) => {
if (type !== "change") {
@@ -160,7 +160,7 @@
}
});
return () => sub.unsubscribe();
- }, [connectedToForm, store]);
+ }, [id, connectedToForm, store]);
const [nodeLabels, setNodeLabels] = useState(new Map<string, string>());
const [portLabels, setPortLabels] = useState(new Map<string, string>());
useEffect(() => {
@@ -184,7 +184,7 @@
target: id,
targetHandle: "tcp",
}))));
- }, [id, data, connectedToForm, store, setNodeLabels, setPortLabels]);
+ }, [id, data, store]);
return (
<>
<Form {...form}>
diff --git a/apps/canvas/front/src/components/node-github.tsx b/apps/canvas/front/src/components/node-github.tsx
index 3ae779e..6ece1b0 100644
--- a/apps/canvas/front/src/components/node-github.tsx
+++ b/apps/canvas/front/src/components/node-github.tsx
@@ -100,7 +100,7 @@
useEffect(() => {
const fetchRepositories = async () => {
- if (!!!githubService) return;
+ if (!githubService) return;
setLoading(true);
setError(null);
@@ -129,11 +129,11 @@
<Select
onValueChange={(value) => field.onChange(Number(value))}
value={field.value?.toString()}
- disabled={loading || !projectId || !!!githubService}
+ disabled={loading || !projectId || !githubService}
>
<FormControl>
<SelectTrigger>
- <SelectValue placeholder={!!githubService ? "Select a repository" : "GitHub not configured"} />
+ <SelectValue placeholder={githubService ? "Select a repository" : "GitHub not configured"} />
</SelectTrigger>
</FormControl>
<SelectContent>
@@ -148,7 +148,7 @@
<FormMessage />
{error && <p className="text-sm text-red-500">{error}</p>}
{loading && <p className="text-sm text-gray-500">Loading repositories...</p>}
- {!!!githubService && (
+ {!githubService && (
<Alert variant="destructive" className="mt-2">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
diff --git a/apps/canvas/front/src/components/node-mongodb.tsx b/apps/canvas/front/src/components/node-mongodb.tsx
index 40c9748..9ead671 100644
--- a/apps/canvas/front/src/components/node-mongodb.tsx
+++ b/apps/canvas/front/src/components/node-mongodb.tsx
@@ -21,7 +21,7 @@
isConnectableStart={true}
isConnectableEnd={true}
isConnectable={true}
- />
+ />
</div>
</NodeRect>
);
@@ -50,7 +50,7 @@
});
});
return () => sub.unsubscribe();
- }, [form, store]);
+ }, [id, form, store]);
return (
<>
<Form {...form}>
diff --git a/apps/canvas/front/src/components/node-postgresql.tsx b/apps/canvas/front/src/components/node-postgresql.tsx
index 4213645..a0bd558 100644
--- a/apps/canvas/front/src/components/node-postgresql.tsx
+++ b/apps/canvas/front/src/components/node-postgresql.tsx
@@ -50,7 +50,7 @@
});
});
return () => sub.unsubscribe();
- }, [form, store]);
+ }, [id, form, store]);
return (
<>
<Form {...form}>
diff --git a/apps/canvas/front/src/components/node-rect.tsx b/apps/canvas/front/src/components/node-rect.tsx
index 06f3307..615f7a1 100644
--- a/apps/canvas/front/src/components/node-rect.tsx
+++ b/apps/canvas/front/src/components/node-rect.tsx
@@ -5,7 +5,7 @@
export type Props = {
id: string;
selected?: boolean;
- children: any;
+ children: React.ReactNode;
type: NodeType;
state: string | null;
};
@@ -32,7 +32,7 @@
classes.push("border");
}
setClasses(classes);
- let stateClasses: string[] = [];
+ const stateClasses: string[] = [];
if (state === "processing") {
stateClasses.push("bg-yellow-500");
stateClasses.push("animate-pulse");
diff --git a/apps/canvas/front/src/components/node-volume.tsx b/apps/canvas/front/src/components/node-volume.tsx
index 430d1e9..cb42241 100644
--- a/apps/canvas/front/src/components/node-volume.tsx
+++ b/apps/canvas/front/src/components/node-volume.tsx
@@ -25,7 +25,7 @@
isConnectableStart={isConnectable}
isConnectableEnd={isConnectable}
isConnectable={isConnectable}
- />
+ />
</div>
</NodeRect>
);
@@ -63,7 +63,7 @@
});
});
return () => sub.unsubscribe();
- }, [form, store]);
+ }, [id, form, store]);
useEffect(() => {
form.reset({
name: data.label,
@@ -75,7 +75,7 @@
<>
<Form {...form}>
<form className="space-y-2">
- <FormField
+ <FormField
control={form.control}
name="name"
render={({ field }) => (
@@ -87,7 +87,7 @@
</FormItem>
)}
/>
- <FormField
+ <FormField
control={form.control}
name="type"
render={({ field }) => (
@@ -108,7 +108,7 @@
</FormItem>
)}
/>
- <FormField
+ <FormField
control={form.control}
name="size"
render={({ field }) => (
diff --git a/apps/canvas/front/src/components/resources.tsx b/apps/canvas/front/src/components/resources.tsx
index 7471c1f..085301c 100644
--- a/apps/canvas/front/src/components/resources.tsx
+++ b/apps/canvas/front/src/components/resources.tsx
@@ -22,9 +22,9 @@
}
export function Resources() {
- let flow = useReactFlow();
+ const flow = useReactFlow();
const categories = useCategories();
- let onResourceAdd = useCallback((item: CategoryItem) => {
+ const onResourceAdd = useCallback((item: CategoryItem) => {
return () => addResource(item, flow);
}, [flow]);
const [open, setOpen] = useState<string[]>(categories.map((c) => c.title));
diff --git a/apps/canvas/front/src/hooks/use-toast.ts b/apps/canvas/front/src/hooks/use-toast.ts
index 02e111d..55ec184 100644
--- a/apps/canvas/front/src/hooks/use-toast.ts
+++ b/apps/canvas/front/src/hooks/use-toast.ts
@@ -36,21 +36,21 @@
type Action =
| {
- type: ActionType["ADD_TOAST"]
- toast: ToasterToast
- }
+ type: ActionType["ADD_TOAST"]
+ toast: ToasterToast
+ }
| {
- type: ActionType["UPDATE_TOAST"]
- toast: Partial<ToasterToast>
- }
+ type: ActionType["UPDATE_TOAST"]
+ toast: Partial<ToasterToast>
+ }
| {
- type: ActionType["DISMISS_TOAST"]
- toastId?: ToasterToast["id"]
- }
+ type: ActionType["DISMISS_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
| {
- type: ActionType["REMOVE_TOAST"]
- toastId?: ToasterToast["id"]
- }
+ type: ActionType["REMOVE_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
interface State {
toasts: ToasterToast[]
@@ -108,9 +108,9 @@
toasts: state.toasts.map((t) =>
t.id === toastId || toastId === undefined
? {
- ...t,
- open: false,
- }
+ ...t,
+ open: false,
+ }
: t
),
}
diff --git a/apps/canvas/front/src/lib/categories.ts b/apps/canvas/front/src/lib/categories.ts
index e45c4fd..6330536 100644
--- a/apps/canvas/front/src/lib/categories.ts
+++ b/apps/canvas/front/src/lib/categories.ts
@@ -1,6 +1,6 @@
import { NodeType, InitData } from "@/lib/state";
-export interface CategoryItem<T extends NodeType = any> {
+export interface CategoryItem<T extends NodeType> {
title: string;
init: InitData;
type: T;
@@ -8,7 +8,7 @@
export type Category = {
title: string;
- items: CategoryItem[];
+ items: CategoryItem<NodeType>[];
active?: boolean;
};
diff --git a/apps/canvas/front/src/lib/state.ts b/apps/canvas/front/src/lib/state.ts
index a3cd755..2492642 100644
--- a/apps/canvas/front/src/lib/state.ts
+++ b/apps/canvas/front/src/lib/state.ts
@@ -335,7 +335,6 @@
setNodes: (nodes: AppNode[]) => void;
setEdges: (edges: Edge[]) => void;
setProject: (projectId: string | undefined) => void;
- setProjects: (projects: Project[]) => void;
updateNode: <T extends NodeType>(id: string, node: NodeUpdate<T>) => void;
updateNodeData: <T extends NodeType>(id: string, data: NodeDataUpdate<T>) => void;
replaceEdge: (c: Connection, id?: string) => void;
@@ -670,6 +669,5 @@
get().refreshEnv();
}
},
- setProjects: (projects) => set({ projects }),
};
});