blob: 57c488de59bdf9fbed563d0dcd7b88b52210c727 [file] [log] [blame]
gio5f2f1002025-03-20 18:38:48 +04001import { NodeRect } from './node-rect';
2import { nodeIsConnectable, nodeLabel, useStateStore, VolumeNode } from '@/lib/state';
3import { useEffect, useMemo } from 'react';
4import { z } from "zod";
5import { DeepPartial, EventType, useForm } from 'react-hook-form';
6import { zodResolver } from '@hookform/resolvers/zod';
7import { Form, FormControl, FormField, FormItem, FormMessage } from './ui/form';
8import { Input } from './ui/input';
9import { Handle, Position } from "@xyflow/react";
10import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
11
12export function NodeVolume(node: VolumeNode) {
13 const { id, data, selected } = node;
14 const isConnectable = useMemo(() => nodeIsConnectable(node, "volume"), [node]);
15 return (
16 <NodeRect id={id} selected={selected} type={node.type}>
17 <div style={{ padding: '10px 20px' }}>
18 <div>{nodeLabel(node)}</div>
19 <div>{data.type && `${data.type}`}</div>
20 <div>{data.size && `${data.size}`}</div>
21 <Handle
22 id="volume"
23 type={"source"}
24 position={Position.Top}
25 isConnectableStart={isConnectable}
26 isConnectableEnd={isConnectable}
27 isConnectable={isConnectable}
28 />
29 </div>
30 </NodeRect>
31 );
32}
33
34const volumeTypes = ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"] as const;
35
36const schema = z.object({
37 name: z.string().min(1),
38 type: z.enum(volumeTypes),
39 size: z.string().min(1).default("1Gi"),
40});
41
42export function NodeVolumeDetails({ id, data }: VolumeNode) {
43 const store = useStateStore();
44 const form = useForm<z.infer<typeof schema>>({
45 resolver: zodResolver(schema),
46 mode: "onChange",
47 defaultValues: {
48 name: "",
49 type: undefined,
50 size: "",
51 }
52 });
53 useEffect(() => {
54 const sub = form.watch((value: DeepPartial<z.infer<typeof schema>>, { name, type }: { name?: keyof z.infer<typeof schema> | undefined, type?: EventType | undefined }) => {
55 if (type !== "change") {
56 return
57 }
58 console.log({ name, type, value });
59 store.updateNodeData<"volume">(id, {
60 label: value.name,
61 type: value.type,
62 size: value.size,
63 });
64 });
65 return () => sub.unsubscribe();
66 }, [form, store]);
67 useEffect(() => {
68 form.reset({
69 name: data.label,
70 type: data.type,
71 size: data.size,
72 });
73 }, [form, data])
74 return (
75 <>
76 <Form {...form}>
77 <form className="space-y-2">
78 <FormField
79 control={form.control}
80 name="name"
81 render={({ field }) => (
82 <FormItem>
83 <FormControl>
84 <Input placeholder="name" className="border border-black" {...field} />
85 </FormControl>
86 <FormMessage />
87 </FormItem>
88 )}
89 />
90 <FormField
91 control={form.control}
92 name="type"
93 render={({ field }) => (
94 <FormItem>
95 <Select onValueChange={field.onChange} defaultValue={field.value}>
96 <FormControl>
97 <SelectTrigger>
98 <SelectValue placeholder="Volume Type" />
99 </SelectTrigger>
100 </FormControl>
101 <SelectContent>
102 {volumeTypes.map((t) => (
103 <SelectItem key={t} value={t}>{t}</SelectItem>
104 ))}
105 </SelectContent>
106 </Select>
107 <FormMessage />
108 </FormItem>
109 )}
110 />
111 <FormField
112 control={form.control}
113 name="size"
114 render={({ field }) => (
115 <FormItem>
116 <FormControl>
117 <Input placeholder="size" className="border border-black" {...field} />
118 </FormControl>
119 <FormMessage />
120 </FormItem>
121 )}
122 />
123 </form>
124 </Form>
125 </>);
126}