diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx index f751e262e..985e130f2 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx @@ -42,9 +42,7 @@ const AddRegistrySchema = z.object({ username: z.string().min(1, { message: "Username is required", }), - password: z.string().min(1, { - message: "Password is required", - }), + password: z.string(), registryUrl: z .string() .optional() @@ -75,6 +73,7 @@ const AddRegistrySchema = z.object({ ), imagePrefix: z.string(), serverId: z.string().optional(), + isEditing: z.boolean().optional(), }); type AddRegistry = z.infer; @@ -108,6 +107,12 @@ export const HandleRegistry = ({ registryId }: Props) => { error: testRegistryError, isError: testRegistryIsError, } = api.registry.testRegistry.useMutation(); + const { + mutateAsync: testRegistryById, + isLoading: isLoadingById, + error: testRegistryByIdError, + isError: testRegistryByIdIsError, + } = api.registry.testRegistryById.useMutation(); const form = useForm({ defaultValues: { username: "", @@ -116,8 +121,26 @@ export const HandleRegistry = ({ registryId }: Props) => { imagePrefix: "", registryName: "", serverId: "", + isEditing: !!registryId, }, - resolver: zodResolver(AddRegistrySchema), + resolver: zodResolver( + AddRegistrySchema.refine( + (data) => { + // When creating a new registry, password is required + if ( + !data.isEditing && + (!data.password || data.password.length === 0) + ) { + return false; + } + return true; + }, + { + message: "Password is required", + path: ["password"], + }, + ), + ), }); const password = form.watch("password"); @@ -138,6 +161,7 @@ export const HandleRegistry = ({ registryId }: Props) => { registryUrl: registry.registryUrl, imagePrefix: registry.imagePrefix || "", registryName: registry.registryName, + isEditing: true, }); } else { form.reset({ @@ -146,13 +170,13 @@ export const HandleRegistry = ({ registryId }: Props) => { registryUrl: "", imagePrefix: "", serverId: "", + isEditing: false, }); } }, [form, form.reset, form.formState.isSubmitSuccessful, registry]); const onSubmit = async (data: AddRegistry) => { - await mutateAsync({ - password: data.password, + const payload: any = { registryName: data.registryName, username: data.username, registryUrl: data.registryUrl || "", @@ -160,7 +184,15 @@ export const HandleRegistry = ({ registryId }: Props) => { imagePrefix: data.imagePrefix, serverId: data.serverId, registryId: registryId || "", - }) + }; + + // Only include password if it's been provided (not empty) + // When editing, empty password means "keep the existing password" + if (data.password && data.password.length > 0) { + payload.password = data.password; + } + + await mutateAsync(payload) .then(async (_data) => { await utils.registry.all.invalidate(); toast.success(registryId ? "Registry updated" : "Registry added"); @@ -198,11 +230,14 @@ export const HandleRegistry = ({ registryId }: Props) => { Fill the next fields to add a external registry. - {(isError || testRegistryIsError) && ( + {(isError || testRegistryIsError || testRegistryByIdIsError) && (
- {testRegistryError?.message || error?.message || ""} + {testRegistryError?.message || + testRegistryByIdError?.message || + error?.message || + ""}
)} @@ -253,10 +288,20 @@ export const HandleRegistry = ({ registryId }: Props) => { name="password" render={({ field }) => ( - Password + Password{registryId && " (Optional)"} + {registryId && ( + + Leave blank to keep existing password. Enter new + password to test or update it. + + )} {