Skip to content

Commit e4c440b

Browse files
authored
Merge pull request #3627 from Dokploy/3583-dokploy-traefik-config-editor-does-not-allow-valid-traefik-config-to-be-saved
feat(traefik): add option to skip YAML validation for Go templating
2 parents 5b48e45 + e39f0fe commit e4c440b

2 files changed

Lines changed: 78 additions & 23 deletions

File tree

apps/dokploy/components/dashboard/application/advanced/traefik/update-traefik-config.tsx

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
FormLabel,
2525
FormMessage,
2626
} from "@/components/ui/form";
27+
import { Checkbox } from "@/components/ui/checkbox";
28+
import { Label } from "@/components/ui/label";
2729
import { api } from "@/utils/api";
2830

2931
const UpdateTraefikConfigSchema = z.object({
@@ -59,6 +61,7 @@ export const validateAndFormatYAML = (yamlText: string) => {
5961

6062
export const UpdateTraefikConfig = ({ applicationId }: Props) => {
6163
const [open, setOpen] = useState(false);
64+
const [skipYamlValidation, setSkipYamlValidation] = useState(false);
6265
const { data, refetch } = api.application.readTraefikConfig.useQuery(
6366
{
6467
applicationId,
@@ -85,13 +88,15 @@ export const UpdateTraefikConfig = ({ applicationId }: Props) => {
8588
}, [data]);
8689

8790
const onSubmit = async (data: UpdateTraefikConfig) => {
88-
const { valid, error } = validateAndFormatYAML(data.traefikConfig);
89-
if (!valid) {
90-
form.setError("traefikConfig", {
91-
type: "manual",
92-
message: (error as string) || "Invalid YAML",
93-
});
94-
return;
91+
if (!skipYamlValidation) {
92+
const { valid, error } = validateAndFormatYAML(data.traefikConfig);
93+
if (!valid) {
94+
form.setError("traefikConfig", {
95+
type: "manual",
96+
message: (error as string) || "Invalid YAML",
97+
});
98+
return;
99+
}
95100
}
96101
form.clearErrors("traefikConfig");
97102
await mutateAsync({
@@ -116,6 +121,7 @@ export const UpdateTraefikConfig = ({ applicationId }: Props) => {
116121
setOpen(open);
117122
if (!open) {
118123
form.reset();
124+
setSkipYamlValidation(false);
119125
}
120126
}}
121127
>
@@ -169,7 +175,28 @@ routers:
169175
</div>
170176
</form>
171177

172-
<DialogFooter>
178+
<DialogFooter className="flex-col sm:flex-row gap-4">
179+
<div className="flex flex-col gap-1 w-full sm:w-auto sm:mr-auto">
180+
<div className="flex items-center space-x-2">
181+
<Checkbox
182+
id="skip-yaml-validation-app"
183+
checked={skipYamlValidation}
184+
onCheckedChange={(checked) =>
185+
setSkipYamlValidation(checked === true)
186+
}
187+
/>
188+
<Label
189+
htmlFor="skip-yaml-validation-app"
190+
className="text-sm font-normal cursor-pointer"
191+
>
192+
Skip YAML validation (for Go templating)
193+
</Label>
194+
</div>
195+
<p className="text-sm text-muted-foreground">
196+
Check to save configs with Go templating (e.g.{" "}
197+
<code className="text-xs">{"{{range}}"}</code>).
198+
</p>
199+
</div>
173200
<Button
174201
isLoading={isLoading}
175202
form="hook-form-update-traefik-config"

apps/dokploy/components/dashboard/file-system/show-traefik-file.tsx

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { z } from "zod";
77
import { AlertBlock } from "@/components/shared/alert-block";
88
import { CodeEditor } from "@/components/shared/code-editor";
99
import { Button } from "@/components/ui/button";
10+
import { Checkbox } from "@/components/ui/checkbox";
1011
import {
1112
Form,
1213
FormControl,
@@ -16,6 +17,7 @@ import {
1617
FormLabel,
1718
FormMessage,
1819
} from "@/components/ui/form";
20+
import { Label } from "@/components/ui/label";
1921
import { api } from "@/utils/api";
2022
import { validateAndFormatYAML } from "../application/advanced/traefik/update-traefik-config";
2123

@@ -47,6 +49,7 @@ export const ShowTraefikFile = ({ path, serverId }: Props) => {
4749
},
4850
);
4951
const [canEdit, setCanEdit] = useState(true);
52+
const [skipYamlValidation, setSkipYamlValidation] = useState(false);
5053

5154
const { mutateAsync, isLoading, error, isError } =
5255
api.settings.updateTraefikFile.useMutation();
@@ -66,13 +69,15 @@ export const ShowTraefikFile = ({ path, serverId }: Props) => {
6669
}, [form, form.reset, data]);
6770

6871
const onSubmit = async (data: UpdateServerMiddlewareConfig) => {
69-
const { valid, error } = validateAndFormatYAML(data.traefikConfig);
70-
if (!valid) {
71-
form.setError("traefikConfig", {
72-
type: "manual",
73-
message: error || "Invalid YAML",
74-
});
75-
return;
72+
if (!skipYamlValidation) {
73+
const { valid, error } = validateAndFormatYAML(data.traefikConfig);
74+
if (!valid) {
75+
form.setError("traefikConfig", {
76+
type: "manual",
77+
message: error || "Invalid YAML",
78+
});
79+
return;
80+
}
7681
}
7782
form.clearErrors("traefikConfig");
7883
await mutateAsync({
@@ -153,14 +158,37 @@ routers:
153158
/>
154159
)}
155160
</div>
156-
<div className="flex justify-end">
157-
<Button
158-
isLoading={isLoading}
159-
disabled={canEdit || isLoading}
160-
type="submit"
161-
>
162-
Update
163-
</Button>
161+
<div className="flex flex-col gap-4">
162+
<div className="flex items-center space-x-2">
163+
<Checkbox
164+
id="skip-yaml-validation"
165+
checked={skipYamlValidation}
166+
onCheckedChange={(checked) =>
167+
setSkipYamlValidation(checked === true)
168+
}
169+
/>
170+
<Label
171+
htmlFor="skip-yaml-validation"
172+
className="text-sm font-normal cursor-pointer"
173+
>
174+
Skip YAML validation (for Go templating)
175+
</Label>
176+
</div>
177+
<p className="text-sm text-muted-foreground -mt-2">
178+
Traefik supports Go templating in dynamic configs (e.g.{" "}
179+
<code className="text-xs">{"{{range}}"}</code>). Configs using
180+
templates will fail standard YAML validation. Check this to save
181+
without validation.
182+
</p>
183+
<div className="flex justify-end">
184+
<Button
185+
isLoading={isLoading}
186+
disabled={canEdit || isLoading}
187+
type="submit"
188+
>
189+
Update
190+
</Button>
191+
</div>
164192
</div>
165193
</form>
166194
</Form>

0 commit comments

Comments
 (0)