Skip to content

Commit c650263

Browse files
committed
feat(network-form): add DriverOptsEntries to network form schema and UI
- Introduced DriverOptsEntries to the network form schema, allowing users to specify driver options for networks. - Updated the form UI to support adding, editing, and removing driver options dynamically. - Adjusted the backend schema to accept driver options as a record of key-value pairs.
1 parent 8872dc1 commit c650263

2 files changed

Lines changed: 115 additions & 8 deletions

File tree

  • apps/dokploy/components/dashboard/application/advanced/cluster/swarm-forms
  • packages/server/src/db/schema

apps/dokploy/components/dashboard/application/advanced/cluster/swarm-forms/network-form.tsx

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@ import {
1616
import { Input } from "@/components/ui/input";
1717
import { api } from "@/utils/api";
1818

19+
const driverOptEntrySchema = z.object({
20+
key: z.string(),
21+
value: z.string(),
22+
});
23+
1924
export const networkFormSchema = z.object({
2025
networks: z
2126
.array(
2227
z.object({
2328
Target: z.string().optional(),
2429
Aliases: z.string().optional(),
30+
DriverOptsEntries: z.array(driverOptEntrySchema).optional(),
2531
}),
2632
)
2733
.optional(),
@@ -80,6 +86,12 @@ export const NetworkForm = ({ id, type }: NetworkFormProps) => {
8086
const networkEntries = data.networkSwarm.map((network) => ({
8187
Target: network.Target || "",
8288
Aliases: network.Aliases?.join(", ") || "",
89+
DriverOptsEntries: network.DriverOpts
90+
? Object.entries(network.DriverOpts).map(([key, value]) => ({
91+
key,
92+
value: value ?? "",
93+
}))
94+
: [],
8395
}));
8496
form.reset({ networks: networkEntries });
8597
}
@@ -91,12 +103,25 @@ export const NetworkForm = ({ id, type }: NetworkFormProps) => {
91103
const networksArray =
92104
formData.networks
93105
?.filter((network) => network.Target)
94-
.map((network) => ({
95-
Target: network.Target,
96-
Aliases: network.Aliases
97-
? network.Aliases.split(",").map((alias) => alias.trim())
98-
: undefined,
99-
})) || [];
106+
.map((network) => {
107+
const entries =
108+
(network.DriverOptsEntries ?? []).filter(
109+
(e) => e.key.trim() !== "",
110+
);
111+
const driverOpts =
112+
entries.length > 0
113+
? Object.fromEntries(
114+
entries.map((e) => [e.key.trim(), e.value]),
115+
)
116+
: undefined;
117+
return {
118+
Target: network.Target,
119+
Aliases: network.Aliases
120+
? network.Aliases.split(",").map((alias) => alias.trim())
121+
: undefined,
122+
DriverOpts: driverOpts,
123+
};
124+
}) || [];
100125

101126
// If no networks, send null to clear the database
102127
const networksToSend = networksArray.length > 0 ? networksArray : null;
@@ -166,6 +191,82 @@ export const NetworkForm = ({ id, type }: NetworkFormProps) => {
166191
</FormItem>
167192
)}
168193
/>
194+
<div className="space-y-2">
195+
<FormLabel>Driver options (optional)</FormLabel>
196+
<FormDescription>
197+
e.g. com.docker.network.driver.mtu, com.docker.network.driver.host_binding
198+
</FormDescription>
199+
{(form.watch(`networks.${index}.DriverOptsEntries`) ?? []).map(
200+
(_, optIndex) => (
201+
<div
202+
key={optIndex}
203+
className="flex gap-2 items-end flex-wrap"
204+
>
205+
<FormField
206+
control={form.control}
207+
name={`networks.${index}.DriverOptsEntries.${optIndex}.key`}
208+
render={({ field }) => (
209+
<FormItem className="flex-1 min-w-[140px]">
210+
<FormControl>
211+
<Input
212+
{...field}
213+
placeholder="com.docker.network.driver.mtu"
214+
/>
215+
</FormControl>
216+
<FormMessage />
217+
</FormItem>
218+
)}
219+
/>
220+
<FormField
221+
control={form.control}
222+
name={`networks.${index}.DriverOptsEntries.${optIndex}.value`}
223+
render={({ field }) => (
224+
<FormItem className="flex-1 min-w-[100px]">
225+
<FormControl>
226+
<Input {...field} placeholder="1500" />
227+
</FormControl>
228+
<FormMessage />
229+
</FormItem>
230+
)}
231+
/>
232+
<Button
233+
type="button"
234+
variant="ghost"
235+
size="sm"
236+
onClick={() => {
237+
const entries =
238+
form.getValues(
239+
`networks.${index}.DriverOptsEntries`,
240+
) ?? [];
241+
form.setValue(
242+
`networks.${index}.DriverOptsEntries`,
243+
entries.filter((_, i) => i !== optIndex),
244+
);
245+
}}
246+
>
247+
Remove
248+
</Button>
249+
</div>
250+
),
251+
)}
252+
<Button
253+
type="button"
254+
variant="outline"
255+
size="sm"
256+
onClick={() => {
257+
const entries =
258+
form.getValues(
259+
`networks.${index}.DriverOptsEntries`,
260+
) ?? [];
261+
form.setValue(
262+
`networks.${index}.DriverOptsEntries`,
263+
[...entries, { key: "", value: "" }],
264+
);
265+
}}
266+
>
267+
Add driver option
268+
</Button>
269+
</div>
169270
<Button
170271
type="button"
171272
variant="destructive"
@@ -180,7 +281,13 @@ export const NetworkForm = ({ id, type }: NetworkFormProps) => {
180281
type="button"
181282
variant="outline"
182283
size="sm"
183-
onClick={() => append({ Target: "", Aliases: "" })}
284+
onClick={() =>
285+
append({
286+
Target: "",
287+
Aliases: "",
288+
DriverOptsEntries: [],
289+
})
290+
}
184291
>
185292
Add Network
186293
</Button>

packages/server/src/db/schema/shared.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export const NetworkSwarmSchema = z.array(
167167
.object({
168168
Target: z.string().optional(),
169169
Aliases: z.array(z.string()).optional(),
170-
DriverOpts: z.object({}).optional(),
170+
DriverOpts: z.record(z.string()).optional(),
171171
})
172172
.strict(),
173173
);

0 commit comments

Comments
 (0)