feat: support specified format on deployment to local/ssh

This commit is contained in:
Fu Diwei
2024-10-26 23:49:26 +08:00
parent e7870e2b05
commit adad5d86ba
13 changed files with 329 additions and 76 deletions

View File

@@ -102,7 +102,7 @@ const DeployToHuaweiCloudCDN = () => {
onValueChange={(value) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.resourceType = value?.trim();
draft.config.resourceType = value;
});
setDeploy(newData);
}}

View File

@@ -6,6 +6,7 @@ import { produce } from "immer";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { useDeployEditContext } from "./DeployEdit";
import { cn } from "@/lib/utils";
@@ -20,8 +21,10 @@ const DeployToLocal = () => {
setDeploy({
...data,
config: {
format: "pem",
certPath: "/etc/nginx/ssl/nginx.crt",
keyPath: "/etc/nginx/ssl/nginx.key",
pfxPassword: "",
shell: "sh",
preCommand: "",
command: "sudo service nginx reload",
@@ -34,15 +37,34 @@ const DeployToLocal = () => {
setError({});
}, []);
const formSchema = z.object({
certPath: z.string().min(1, t("domain.deployment.form.file_cert_path.placeholder")),
keyPath: z.string().min(1, t("domain.deployment.form.file_key_path.placeholder")),
shell: z.union([z.literal("sh"), z.literal("cmd"), z.literal("powershell")], {
message: t("domain.deployment.form.shell.placeholder"),
}),
preCommand: z.string().optional(),
command: z.string().optional(),
});
const formSchema = z
.object({
format: z.union([z.literal("pem"), z.literal("pfx")], {
message: t("domain.deployment.form.file_format.placeholder"),
}),
certPath: z
.string()
.min(1, t("domain.deployment.form.file_cert_path.placeholder"))
.max(255, t("common.errmsg.string_max", { max: 255 })),
keyPath: z
.string()
.min(0, t("domain.deployment.form.file_key_path.placeholder"))
.max(255, t("common.errmsg.string_max", { max: 255 })),
pfxPassword: z.string().optional(),
shell: z.union([z.literal("sh"), z.literal("cmd"), z.literal("powershell")], {
message: t("domain.deployment.form.shell.placeholder"),
}),
preCommand: z.string().optional(),
command: z.string().optional(),
})
.refine((data) => (data.format === "pem" ? !!data.keyPath?.trim() : true), {
message: t("domain.deployment.form.file_key_path.placeholder"),
path: ["keyPath"],
})
.refine((data) => (data.format === "pfx" ? !!data.pfxPassword?.trim() : true), {
message: t("domain.deployment.form.file_pfx_password.placeholder"),
path: ["pfxPassword"],
});
useEffect(() => {
const res = formSchema.safeParse(data.config);
@@ -67,6 +89,26 @@ const DeployToLocal = () => {
}
}, [data]);
useEffect(() => {
if (data.config?.format === "pem") {
if (data.config.certPath && data.config.certPath.endsWith(".pfx")) {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.certPath = data.config!.certPath.replace(/.pfx$/, ".crt");
});
setDeploy(newData);
}
} else if (data.config?.format === "pfx") {
if (data.config.certPath && data.config.certPath.endsWith(".crt")) {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.certPath = data.config!.certPath.replace(/.crt$/, ".pfx");
});
setDeploy(newData);
}
}
}, [data.config?.format]);
const getOptionCls = (val: string) => {
if (data.config?.shell === val) {
return "border-primary dark:border-primary";
@@ -78,6 +120,31 @@ const DeployToLocal = () => {
return (
<>
<div className="flex flex-col space-y-8">
<div>
<Label>{t("domain.deployment.form.file_format.label")}</Label>
<Select
value={data?.config?.format}
onValueChange={(value) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.format = value;
});
setDeploy(newData);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.deployment.form.file_format.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="pem">PEM</SelectItem>
<SelectItem value="pfx">PFX</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="text-red-600 text-sm mt-1">{error?.format}</div>
</div>
<div>
<Label>{t("domain.deployment.form.file_cert_path.label")}</Label>
<Input
@@ -95,22 +162,47 @@ const DeployToLocal = () => {
<div className="text-red-600 text-sm mt-1">{error?.certPath}</div>
</div>
<div>
<Label>{t("domain.deployment.form.file_key_path.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.keyPath = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.keyPath}</div>
</div>
{data.config?.format === "pem" ? (
<div>
<Label>{t("domain.deployment.form.file_key_path.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.keyPath = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.keyPath}</div>
</div>
) : (
<></>
)}
{data.config?.format === "pfx" ? (
<div>
<Label>{t("domain.deployment.form.file_pfx_password.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_pfx_password.placeholder")}
className="w-full mt-1"
value={data?.config?.pfxPassword}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.pfxPassword = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.pfxPassword}</div>
</div>
) : (
<></>
)}
<div>
<Label>{t("domain.deployment.form.shell.label")}</Label>

View File

@@ -5,6 +5,7 @@ import { produce } from "immer";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { useDeployEditContext } from "./DeployEdit";
@@ -18,8 +19,10 @@ const DeployToSSH = () => {
setDeploy({
...data,
config: {
format: "pem",
certPath: "/etc/nginx/ssl/nginx.crt",
keyPath: "/etc/nginx/ssl/nginx.key",
pfxPassword: "",
preCommand: "",
command: "sudo service nginx reload",
},
@@ -31,12 +34,31 @@ const DeployToSSH = () => {
setError({});
}, []);
const formSchema = z.object({
certPath: z.string().min(1, t("domain.deployment.form.file_cert_path.placeholder")),
keyPath: z.string().min(1, t("domain.deployment.form.file_key_path.placeholder")),
preCommand: z.string().optional(),
command: z.string().optional(),
});
const formSchema = z
.object({
format: z.union([z.literal("pem"), z.literal("pfx")], {
message: t("domain.deployment.form.file_format.placeholder"),
}),
certPath: z
.string()
.min(1, t("domain.deployment.form.file_cert_path.placeholder"))
.max(255, t("common.errmsg.string_max", { max: 255 })),
keyPath: z
.string()
.min(0, t("domain.deployment.form.file_key_path.placeholder"))
.max(255, t("common.errmsg.string_max", { max: 255 })),
pfxPassword: z.string().optional(),
preCommand: z.string().optional(),
command: z.string().optional(),
})
.refine((data) => (data.format === "pem" ? !!data.keyPath?.trim() : true), {
message: t("domain.deployment.form.file_key_path.placeholder"),
path: ["keyPath"],
})
.refine((data) => (data.format === "pfx" ? !!data.pfxPassword?.trim() : true), {
message: t("domain.deployment.form.file_pfx_password.placeholder"),
path: ["pfxPassword"],
});
useEffect(() => {
const res = formSchema.safeParse(data.config);
@@ -59,9 +81,54 @@ const DeployToSSH = () => {
}
}, [data]);
useEffect(() => {
if (data.config?.format === "pem") {
if (data.config.certPath && data.config.certPath.endsWith(".pfx")) {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.certPath = data.config!.certPath.replace(/.pfx$/, ".crt");
});
setDeploy(newData);
}
} else if (data.config?.format === "pfx") {
if (data.config.certPath && data.config.certPath.endsWith(".crt")) {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.certPath = data.config!.certPath.replace(/.crt$/, ".pfx");
});
setDeploy(newData);
}
}
}, [data.config?.format]);
return (
<>
<div className="flex flex-col space-y-8">
<div>
<Label>{t("domain.deployment.form.file_format.label")}</Label>
<Select
value={data?.config?.format}
onValueChange={(value) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.format = value;
});
setDeploy(newData);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.deployment.form.file_format.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="pem">PEM</SelectItem>
<SelectItem value="pfx">PFX</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="text-red-600 text-sm mt-1">{error?.format}</div>
</div>
<div>
<Label>{t("domain.deployment.form.file_cert_path.label")}</Label>
<Input
@@ -79,22 +146,47 @@ const DeployToSSH = () => {
<div className="text-red-600 text-sm mt-1">{error?.certPath}</div>
</div>
<div>
<Label>{t("domain.deployment.form.file_key_path.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.keyPath = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.keyPath}</div>
</div>
{data.config?.format === "pem" ? (
<div>
<Label>{t("domain.deployment.form.file_key_path.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.keyPath = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.keyPath}</div>
</div>
) : (
<></>
)}
{data.config?.format === "pfx" ? (
<div>
<Label>{t("domain.deployment.form.file_pfx_password.label")}</Label>
<Input
placeholder={t("domain.deployment.form.file_pfx_password.placeholder")}
className="w-full mt-1"
value={data?.config?.pfxPassword}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.pfxPassword = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.pfxPassword}</div>
</div>
) : (
<></>
)}
<div>
<Label>{t("domain.deployment.form.shell_pre_command.label")}</Label>