@@ -16,12 +16,18 @@ import {
1616import { Input } from "@/components/ui/input" ;
1717import { api } from "@/utils/api" ;
1818
19+ const driverOptEntrySchema = z . object ( {
20+ key : z . string ( ) ,
21+ value : z . string ( ) ,
22+ } ) ;
23+
1924export 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 >
0 commit comments