Skip to content

Commit cd60faf

Browse files
committed
refactor(web): Conditional validation for Docker Compose image and build fields
- Ensure the image field is required only when the build option is disabled in Docker Compose. - When the build option is enabled, make the build-related fields required and allow the image field to be optional. - Prevent sending empty strings to the server; send null instead.
1 parent 89e2035 commit cd60faf

2 files changed

Lines changed: 56 additions & 30 deletions

File tree

web/src/pages/docker-compose/docker-compose.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ const DockerCompose: FC = () => {
5757
},
5858
],
5959
},
60-
command: '',
61-
container_name: '',
60+
command: null,
61+
container_name: null,
6262
environment: [
6363
{
6464
key: '',
@@ -124,8 +124,8 @@ const DockerCompose: FC = () => {
124124
dockerfile: '',
125125
},
126126
name: '',
127-
command: '',
128-
container_name: '',
127+
command: null,
128+
container_name: null,
129129
image: '',
130130
environment: [
131131
{
@@ -228,6 +228,7 @@ const DockerCompose: FC = () => {
228228
) {
229229
item.build.args = null;
230230
}
231+
231232
return item;
232233
});
233234

@@ -240,13 +241,11 @@ const DockerCompose: FC = () => {
240241
await dockerComposeMutate(requestBody);
241242
await download();
242243
} catch (error) {
243-
console.log(error);
244244
if (isAxiosError<DockerComposeValidationError>(error)) {
245245
toast.error(
246246
`${error.response?.data.detail[0].loc[error.response?.data.detail[0].loc.length - 1]} ${error.response?.data.detail[0].msg}`,
247247
);
248248
} else {
249-
console.log(error);
250249
toast.error('Something went wrong');
251250
}
252251
}
@@ -256,19 +255,19 @@ const DockerCompose: FC = () => {
256255
<div className="flex h-[calc(100%-56px)] w-full justify-center overflow-y-auto p-4 text-black-1 scrollbar-thin dark:text-white">
257256
<div className="h-full w-full max-w-[768px]">
258257
<FormWrapper methods={methods} onSubmit={handleSubmit}>
259-
<div className="flex flex-col w-full mb-4">
258+
<div className="mb-4 flex w-full flex-col">
260259
<FormInput label="Version" name="version" placeholder="3" />
261260
</div>
262-
<div className="flex flex-col w-full mb-4">
261+
<div className="mb-4 flex w-full flex-col">
263262
<NetworkFields />
264263
</div>
265264

266-
<div className="flex items-center mb-4">
265+
<div className="mb-4 flex items-center">
267266
<h1 className="text-2xl font-bold">Services</h1>
268267
<button
269268
type="button"
270269
onClick={handleAddService}
271-
className="ml-4 btn btn-xs"
270+
className="btn btn-xs ml-4"
272271
>
273272
Add <Plus className="size-3" />
274273
</button>
@@ -278,7 +277,7 @@ const DockerCompose: FC = () => {
278277
{services.map((service, index) => (
279278
<div
280279
key={service.id}
281-
className="w-full p-5 border border-gray-500 rounded-md"
280+
className="w-full rounded-md border border-gray-500 p-5"
282281
>
283282
<div
284283
className={cn(
@@ -316,31 +315,31 @@ const DockerCompose: FC = () => {
316315
},
317316
)}
318317
>
319-
<div className="flex flex-col mb-4">
318+
<div className="mb-4 flex flex-col">
320319
<FormInput
321320
id="service_name"
322321
name={`services.${index}.name`}
323322
label="Name"
324323
placeholder="service name"
325324
/>
326325
</div>
327-
<div className="flex flex-col mb-4">
326+
<div className="mb-4 flex flex-col">
328327
<FormInput
329328
id="image"
330329
name={`services.${index}.image`}
331330
label="Image"
332331
placeholder="image"
333332
/>
334333
</div>
335-
<div className="flex flex-col mb-4">
334+
<div className="mb-4 flex flex-col">
336335
<FormInput
337336
id="container_name"
338337
name={`services.${index}.container_name`}
339338
label="Container Name"
340339
placeholder="container_name"
341340
/>
342341
</div>
343-
<div className="flex flex-col mb-4">
342+
<div className="mb-4 flex flex-col">
344343
<FormInput
345344
id="command"
346345
name={`services.${index}.command`}
@@ -361,7 +360,7 @@ const DockerCompose: FC = () => {
361360
<button
362361
type="submit"
363362
disabled={dockerComposePending}
364-
className="w-full mt-3 text-white btn bg-orange-base hover:bg-orange-base/70 disabled:bg-orange-base/50 disabled:text-white/70"
363+
className="btn mt-3 w-full bg-orange-base text-white hover:bg-orange-base/70 disabled:bg-orange-base/50 disabled:text-white/70"
365364
>
366365
{dockerComposePending
367366
? 'Generating...'

web/src/pages/docker-compose/docker-compose.type.ts

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,22 +66,49 @@ const KV_Schema = zod.array(
6666
export const BuildSchema = zod.object({
6767
enabled: zod.boolean(),
6868
args: KV_Schema,
69-
context: zod.string(),
70-
dockerfile: zod.string(),
69+
context: zod.string().optional(),
70+
dockerfile: zod.string().optional(),
7171
});
7272

73-
export const ServiceSchema = zod.object({
74-
name: zod.string(),
75-
build: BuildSchema,
76-
image: zod.string(),
77-
environment: KV_Schema,
78-
container_name: zod.string(),
79-
ports: zod.array(zod.object({ value: zod.string() })).nullable(),
80-
command: zod.string().optional().nullable(),
81-
volumes: zod.array(zod.object({ value: zod.string() })).nullable(),
82-
networks: zod.array(zod.object({ value: zod.string() })).nullable(),
83-
depends_on: zod.array(zod.object({ value: zod.string() })).nullable(),
84-
});
73+
export const ServiceSchema = zod
74+
.object({
75+
name: zod.string().min(1, 'Name is required!'),
76+
build: BuildSchema,
77+
image: zod.string().nullable(),
78+
environment: KV_Schema,
79+
container_name: zod.string().nullable(),
80+
ports: zod.array(zod.object({ value: zod.string() })).nullable(),
81+
command: zod.string().optional().nullable(),
82+
volumes: zod.array(zod.object({ value: zod.string() })).nullable(),
83+
networks: zod.array(zod.object({ value: zod.string() })).nullable(),
84+
depends_on: zod.array(zod.object({ value: zod.string() })).nullable(),
85+
})
86+
.superRefine((data, ctx) => {
87+
if (!data.build.enabled && !data.image) {
88+
ctx.addIssue({
89+
path: ['image'],
90+
message: 'Image is required.',
91+
code: zod.ZodIssueCode.custom,
92+
});
93+
}
94+
95+
if (data.build.enabled) {
96+
if (!data.build.context) {
97+
ctx.addIssue({
98+
path: ['build', 'context'],
99+
message: 'Context is required.',
100+
code: zod.ZodIssueCode.custom,
101+
});
102+
}
103+
if (!data.build.dockerfile) {
104+
ctx.addIssue({
105+
path: ['build', 'dockerfile'],
106+
message: 'Dockerfile is required.',
107+
code: zod.ZodIssueCode.custom,
108+
});
109+
}
110+
}
111+
});
85112

86113
const labelValueSchema = zod.object({
87114
label: zod.string(),

0 commit comments

Comments
 (0)