Canvas: build application infrastructure with drag and drop
Change-Id: I5cfd12e67794f3376c5c025af29470d52d77cf16
diff --git a/apps/canvas/src/components/node-postgresql.tsx b/apps/canvas/src/components/node-postgresql.tsx
new file mode 100644
index 0000000..232fe9f
--- /dev/null
+++ b/apps/canvas/src/components/node-postgresql.tsx
@@ -0,0 +1,74 @@
+import { NodeRect } from './node-rect';
+import { nodeLabel, PostgreSQLNode, useStateStore } from '@/lib/state';
+import { useEffect } from 'react';
+import { Handle, Position } from "@xyflow/react";
+import { z } from "zod";
+import { DeepPartial, EventType, useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { Form, FormControl, FormField, FormItem, FormMessage } from './ui/form';
+import { Input } from './ui/input';
+
+export function NodePostgreSQL(node: PostgreSQLNode) {
+ const { id, selected } = node;
+ return (
+ <NodeRect id={id} selected={selected} type={node.type}>
+ <div style={{ padding: '10px 20px' }}>
+ {nodeLabel(node)}
+ <Handle
+ id="env_var"
+ type={"source"}
+ position={Position.Top}
+ isConnectableStart={true}
+ isConnectableEnd={true}
+ isConnectable={true}
+ />
+ </div>
+ </NodeRect>
+ );
+}
+
+const schema = z.object({
+ name: z.string().min(1, "required"),
+});
+
+export function NodePostgreSQLDetails(node: PostgreSQLNode) {
+ const { id } = node;
+ const store = useStateStore();
+ const form = useForm<z.infer<typeof schema>>({
+ resolver: zodResolver(schema),
+ mode: "onChange",
+ defaultValues: {
+ name: "",
+ }
+ });
+ useEffect(() => {
+ const sub = form.watch((value: DeepPartial<z.infer<typeof schema>>, { type }: { name?: keyof z.infer<typeof schema> | undefined, type?: EventType | undefined }) => {
+ if (type !== "change") {
+ return;
+ }
+ store.updateNodeData<"postgresql">(id, {
+ label: value.name,
+ });
+ });
+ return () => sub.unsubscribe();
+ }, [form, store]);
+ return (
+ <>
+ <Form {...form}>
+ <form className="space-y-2">
+ <FormField
+ control={form.control}
+ name="name"
+ render={({ field }) => (
+ <FormItem>
+ <FormControl>
+ <Input placeholder="name" className="border border-black" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </form>
+ </Form>
+ </>);
+}
\ No newline at end of file