chore: remove unused code
This commit is contained in:
@@ -52,9 +52,9 @@ const AccessEditForm = forwardRef<AccessEditFormInstance, AccessEditFormProps>((
|
||||
const formSchema = z.object({
|
||||
name: z
|
||||
.string({ message: t("access.form.name.placeholder") })
|
||||
.trim()
|
||||
.min(1, t("access.form.name.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
configType: z.nativeEnum(ACCESS_PROVIDERS, { message: t("access.form.type.placeholder") }),
|
||||
config: z.any(),
|
||||
});
|
||||
|
||||
@@ -28,18 +28,16 @@ const AccessEditFormACMEHttpReqConfig = ({ form, formName, disabled, initialValu
|
||||
|
||||
const formSchema = z.object({
|
||||
endpoint: z.string().url(t("common.errmsg.url_invalid")),
|
||||
mode: z.string().min(0, t("access.form.acmehttpreq_mode.placeholder")).nullish(),
|
||||
mode: z.string().nullish(),
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.acmehttpreq_username.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
password: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.acmehttpreq_password.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
@@ -31,27 +31,25 @@ const AccessEditFormAWSConfig = ({ form, formName, disabled, initialValues, onVa
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aws_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aws_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
region: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.aws_region.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
hostedZoneId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.aws_hosted_zone_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormAliyunConfig = ({ form, formName, disabled, initialValues, o
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aliyun_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
accessKeySecret: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aliyun_access_key_secret.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -34,9 +34,9 @@ const AccessEditFormBaiduCloudConfig = ({ form, formName, disabled, initialValue
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.baiducloud_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -34,9 +34,9 @@ const AccessEditFormBytePlusConfig = ({ form, formName, disabled, initialValues,
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.byteplus_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -28,9 +28,9 @@ const AccessEditFormCloudflareConfig = ({ form, formName, disabled, initialValue
|
||||
const formSchema = z.object({
|
||||
dnsApiToken: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.cloudflare_dns_api_token.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormDogeCloudConfig = ({ form, formName, disabled, initialValues
|
||||
const formSchema = z.object({
|
||||
accessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.dogecloud_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.dogecloud_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormGoDaddyConfig = ({ form, formName, disabled, initialValues,
|
||||
const formSchema = z.object({
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.godaddy_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
apiSecret: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.godaddy_api_secret.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -30,20 +30,19 @@ const AccessEditFormHuaweiCloudConfig = ({ form, formName, disabled, initialValu
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.huaweicloud_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.huaweicloud_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
region: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.huaweicloud_region.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
@@ -32,7 +32,6 @@ const AccessEditFormKubernetesConfig = ({ form, formName, disabled, initialValue
|
||||
kubeConfig: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.k8s_kubeconfig.placeholder"))
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
|
||||
.nullish(),
|
||||
});
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormNameDotComConfig = ({ form, formName, disabled, initialValue
|
||||
const formSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.namedotcom_username.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
apiToken: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.namedotcom_api_token.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -28,9 +28,9 @@ const AccessEditFormNameSiloConfig = ({ form, formName, disabled, initialValues,
|
||||
const formSchema = z.object({
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.namesilo_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -30,9 +30,9 @@ const AccessEditFormPowerDNSConfig = ({ form, formName, disabled, initialValues,
|
||||
apiUrl: z.string().url(t("common.errmsg.url_invalid")),
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.powerdns_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormQiniuConfig = ({ form, formName, disabled, initialValues, on
|
||||
const formSchema = z.object({
|
||||
accessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.qiniu_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.qiniu_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -34,12 +34,7 @@ const AccessEditFormSSHConfig = ({ form, formName, disabled, initialValues, onVa
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
host: z.string().refine(
|
||||
(str) => {
|
||||
return validDomainName(str) || validIPv4Address(str) || validIPv6Address(str);
|
||||
},
|
||||
{ message: t("common.errmsg.host_invalid") }
|
||||
),
|
||||
host: z.string().refine((v) => validDomainName(v) || validIPv4Address(v) || validIPv6Address(v), t("common.errmsg.host_invalid")),
|
||||
port: z.number().int().gte(1, t("common.errmsg.port_invalid")).lte(65535, t("common.errmsg.port_invalid")),
|
||||
username: z
|
||||
.string()
|
||||
@@ -47,20 +42,17 @@ const AccessEditFormSSHConfig = ({ form, formName, disabled, initialValues, onVa
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
password: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_password.placeholder")
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.nullish(),
|
||||
key: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_key.placeholder")
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
|
||||
.nullish(),
|
||||
keyPassphrase: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_key_passphrase.placeholder")
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
|
||||
.nullish()
|
||||
.and(z.string().refine((v) => !v || form.getFieldValue("key"), { message: t("access.form.ssh_key.placeholder") })),
|
||||
.refine((v) => !v || form.getFieldValue("key"), t("access.form.ssh_key.placeholder")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -29,14 +29,14 @@ const AccessEditFormTencentCloudConfig = ({ form, formName, disabled, initialVal
|
||||
const formSchema = z.object({
|
||||
secretId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.tencentcloud_secret_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.tencentcloud_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -34,9 +34,9 @@ const AccessEditFormVolcEngineConfig = ({ form, formName, disabled, initialValue
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.volcengine_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -26,10 +26,7 @@ const AccessEditFormWebhookConfig = ({ form, formName, disabled, initialValues,
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
url: z
|
||||
.string()
|
||||
.min(1, { message: t("access.form.webhook_url.placeholder") })
|
||||
.url({ message: t("common.errmsg.url_invalid") }),
|
||||
url: z.string({ message: t("access.form.webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm<z.infer<typeof formSchema>>({
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Avatar, Select, Space, Typography, type SelectProps } from "antd";
|
||||
|
||||
import { accessProvidersMap, type AccessModel } from "@/domain/access";
|
||||
import { type AccessModel } from "@/domain/access";
|
||||
import { accessProvidersMap } from "@/domain/provider";
|
||||
import { useAccessStore } from "@/stores/access";
|
||||
|
||||
export type AccessTypeSelectProps = Omit<
|
||||
|
||||
@@ -2,7 +2,8 @@ import { memo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar, Select, Space, Tag, Typography, type SelectProps } from "antd";
|
||||
|
||||
import { ACCESS_USAGES, accessProvidersMap } from "@/domain/access";
|
||||
import { ACCESS_USAGES } from "@/domain/access";
|
||||
import { accessProvidersMap } from "@/domain/provider";
|
||||
|
||||
export type AccessTypeSelectProps = Omit<
|
||||
SelectProps,
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { produce } from "immer";
|
||||
import { Edit, Plus, Trash2 } from "lucide-react";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { KVType } from "@/domain/domain";
|
||||
|
||||
type KVListProps = {
|
||||
variables?: KVType[];
|
||||
onValueChange?: (variables: KVType[]) => void;
|
||||
};
|
||||
|
||||
const KVList = ({ variables, onValueChange }: KVListProps) => {
|
||||
const [locVariables, setLocVariables] = useState<KVType[]>([]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (variables) {
|
||||
setLocVariables(variables);
|
||||
}
|
||||
}, [variables]);
|
||||
|
||||
const handleAddClick = (variable: KVType) => {
|
||||
// 查看是否存在key,存在则更新,不存在则添加
|
||||
const index = locVariables.findIndex((item) => {
|
||||
return item.key === variable.key;
|
||||
});
|
||||
|
||||
const newList = produce(locVariables, (draft) => {
|
||||
if (index === -1) {
|
||||
draft.push(variable);
|
||||
} else {
|
||||
draft[index] = variable;
|
||||
}
|
||||
});
|
||||
|
||||
setLocVariables(newList);
|
||||
|
||||
onValueChange?.(newList);
|
||||
};
|
||||
|
||||
const handleDeleteClick = (index: number) => {
|
||||
const newList = [...locVariables];
|
||||
newList.splice(index, 1);
|
||||
setLocVariables(newList);
|
||||
|
||||
onValueChange?.(newList);
|
||||
};
|
||||
|
||||
const handleEditClick = (index: number, variable: KVType) => {
|
||||
const newList = [...locVariables];
|
||||
newList[index] = variable;
|
||||
setLocVariables(newList);
|
||||
|
||||
onValueChange?.(newList);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex justify-between dark:text-stone-200">
|
||||
<Label>{t("domain.deployment.form.variables.label")}</Label>
|
||||
<Show when={!!locVariables?.length}>
|
||||
<KVEdit
|
||||
variable={{
|
||||
key: "",
|
||||
value: "",
|
||||
}}
|
||||
trigger={
|
||||
<div className="flex items-center text-primary">
|
||||
<Plus size={16} className="cursor-pointer " />
|
||||
|
||||
<div className="text-sm ">{t("common.button.add")}</div>
|
||||
</div>
|
||||
}
|
||||
onSave={(variable) => {
|
||||
handleAddClick(variable);
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Show
|
||||
when={!!locVariables?.length}
|
||||
fallback={
|
||||
<div className="border rounded-md p-3 text-sm flex flex-col items-center">
|
||||
<div className="text-muted-foreground">{t("domain.deployment.form.variables.empty")}</div>
|
||||
|
||||
<KVEdit
|
||||
trigger={
|
||||
<div className="flex items-center text-primary">
|
||||
<Plus size={16} className="cursor-pointer " />
|
||||
|
||||
<div className="text-sm ">{t("common.button.add")}</div>
|
||||
</div>
|
||||
}
|
||||
variable={{
|
||||
key: "",
|
||||
value: "",
|
||||
}}
|
||||
onSave={(variable) => {
|
||||
handleAddClick(variable);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="border p-3 rounded-md text-stone-700 text-sm dark:text-stone-200">
|
||||
{locVariables?.map((item, index) => (
|
||||
<div key={index} className="flex justify-between items-center">
|
||||
<div>
|
||||
{item.key}={item.value}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<KVEdit
|
||||
trigger={<Edit size={16} className="cursor-pointer" />}
|
||||
variable={item}
|
||||
onSave={(variable) => {
|
||||
handleEditClick(index, variable);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Trash2
|
||||
size={16}
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
handleDeleteClick(index);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type KVEditProps = {
|
||||
variable?: KVType;
|
||||
trigger: React.ReactNode;
|
||||
onSave: (variable: KVType) => void;
|
||||
};
|
||||
|
||||
const KVEdit = ({ variable, trigger, onSave }: KVEditProps) => {
|
||||
const [locVariable, setLocVariable] = useState<KVType>({
|
||||
key: "",
|
||||
value: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (variable) setLocVariable(variable!);
|
||||
}, [variable]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
|
||||
const [err, setErr] = useState<Record<string, string>>({});
|
||||
|
||||
const handleSaveClick = () => {
|
||||
if (!locVariable.key) {
|
||||
setErr({
|
||||
key: t("domain.deployment.form.variables.key.required"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!locVariable.value) {
|
||||
setErr({
|
||||
value: t("domain.deployment.form.variables.value.required"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
onSave?.(locVariable);
|
||||
|
||||
setOpen(false);
|
||||
|
||||
setErr({});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={() => {
|
||||
setOpen(!open);
|
||||
}}
|
||||
>
|
||||
<DialogTrigger>{trigger}</DialogTrigger>
|
||||
<DialogContent className="dark:text-stone-200">
|
||||
<DialogHeader className="flex flex-col">
|
||||
<DialogTitle>{t("domain.deployment.form.variables.label")}</DialogTitle>
|
||||
|
||||
<div className="pt-5 flex flex-col items-start">
|
||||
<Label>{t("domain.deployment.form.variables.key")}</Label>
|
||||
<Input
|
||||
placeholder={t("domain.deployment.form.variables.key.placeholder")}
|
||||
value={locVariable?.key}
|
||||
onChange={(e) => {
|
||||
setLocVariable({ ...locVariable, key: e.target.value });
|
||||
}}
|
||||
className="w-full mt-1"
|
||||
/>
|
||||
<div className="text-red-500 text-sm mt-1">{err?.key}</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-2 flex flex-col items-start">
|
||||
<Label>{t("domain.deployment.form.variables.value")}</Label>
|
||||
<Input
|
||||
placeholder={t("domain.deployment.form.variables.value.placeholder")}
|
||||
value={locVariable?.value}
|
||||
onChange={(e) => {
|
||||
setLocVariable({ ...locVariable, value: e.target.value });
|
||||
}}
|
||||
className="w-full mt-1"
|
||||
/>
|
||||
|
||||
<div className="text-red-500 text-sm mt-1">{err?.value}</div>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleSaveClick();
|
||||
}}
|
||||
>
|
||||
{t("common.button.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default KVList;
|
||||
@@ -9,7 +9,7 @@ const NotifyChannelEditFormBarkFields = () => {
|
||||
const formSchema = z.object({
|
||||
serverUrl: z
|
||||
.string({ message: t("settings.notification.channel.form.bark_server_url.placeholder") })
|
||||
.url({ message: t("common.errmsg.url_invalid") })
|
||||
.url(t("common.errmsg.url_invalid"))
|
||||
.nullish(),
|
||||
deviceKey: z
|
||||
.string({ message: t("settings.notification.channel.form.bark_device_key.placeholder") })
|
||||
|
||||
@@ -25,23 +25,17 @@ const NotifyChannelEditFormEmailFields = () => {
|
||||
.string({ message: t("settings.notification.channel.form.email_password.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.email_password.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
senderAddress: z
|
||||
.string({ message: t("settings.notification.channel.form.email_sender_address.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.email_sender_address.placeholder"))
|
||||
.email({ message: t("common.errmsg.email_invalid") }),
|
||||
receiverAddress: z
|
||||
.string({ message: t("settings.notification.channel.form.email_receiver_address.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.email_receiver_address.placeholder"))
|
||||
.email({ message: t("common.errmsg.email_invalid") }),
|
||||
senderAddress: z.string({ message: t("settings.notification.channel.form.email_sender_address.placeholder") }).email(t("common.errmsg.email_invalid")),
|
||||
receiverAddress: z.string({ message: t("settings.notification.channel.form.email_receiver_address.placeholder") }).email(t("common.errmsg.email_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const form = Form.useFormInstance<z.infer<typeof formSchema>>();
|
||||
const formInst = Form.useFormInstance<z.infer<typeof formSchema>>();
|
||||
|
||||
const handleTLSSwitchChange = (checked: boolean) => {
|
||||
const oldPort = form.getFieldValue("smtpPort");
|
||||
const oldPort = formInst.getFieldValue("smtpPort");
|
||||
const newPort = checked && (oldPort == null || oldPort === 25) ? 465 : !checked && (oldPort == null || oldPort === 465) ? 25 : oldPort;
|
||||
if (newPort !== oldPort) {
|
||||
form.setFieldValue("smtpPort", newPort);
|
||||
formInst.setFieldValue("smtpPort", newPort);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ const NotifyChannelEditFormLarkFields = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
webhookUrl: z
|
||||
.string({ message: t("settings.notification.channel.form.lark_webhook_url.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.lark_webhook_url.placeholder"))
|
||||
.url({ message: t("common.errmsg.url_invalid") }),
|
||||
webhookUrl: z.string({ message: t("settings.notification.channel.form.lark_webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ const NotifyChannelEditFormServerChanFields = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
url: z
|
||||
.string({ message: t("settings.notification.channel.form.serverchan_url.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.serverchan_url.placeholder"))
|
||||
.url({ message: t("common.errmsg.url_invalid") }),
|
||||
url: z.string({ message: t("settings.notification.channel.form.serverchan_url.placeholder") }).url(t("common.errmsg.url_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ const NotifyChannelEditFormWebhookFields = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
url: z
|
||||
.string({ message: t("settings.notification.channel.form.webhook_url.placeholder") })
|
||||
.min(1, t("settings.notification.channel.form.webhook_url.placeholder"))
|
||||
.url({ message: t("common.errmsg.url_invalid") }),
|
||||
url: z.string({ message: t("settings.notification.channel.form.webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
|
||||
@@ -26,14 +26,14 @@ const NotifyTemplateForm = ({ className, style }: NotifyTemplateFormProps) => {
|
||||
const formSchema = z.object({
|
||||
subject: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("settings.notification.template.form.subject.placeholder"))
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 }))
|
||||
.trim(),
|
||||
message: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("settings.notification.template.form.message.placeholder"))
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, loading, asChild = false, children, ...props }, ref) => {
|
||||
if (asChild) {
|
||||
return (
|
||||
<Slot ref={ref} {...props}>
|
||||
<>
|
||||
{React.Children.map(children as React.ReactElement, (child: React.ReactElement) => {
|
||||
return React.cloneElement(child, {
|
||||
className: cn(buttonVariants({ variant, size }), className),
|
||||
children: (
|
||||
<>
|
||||
{loading && <Loader2 className={cn("h-4 w-4 animate-spin", children && "mr-2")} />}
|
||||
{child.props.children}
|
||||
</>
|
||||
),
|
||||
});
|
||||
})}
|
||||
</>
|
||||
</Slot>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button className={cn(buttonVariants({ variant, size, className }))} disabled={loading} ref={ref} {...props}>
|
||||
<>
|
||||
{loading && <Loader2 className={cn("h-4 w-4 animate-spin", children && "mr-2")} />}
|
||||
{children}
|
||||
</>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants };
|
||||
@@ -1,75 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal;
|
||||
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>>(
|
||||
({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
)
|
||||
);
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...props} />
|
||||
);
|
||||
DialogHeader.displayName = "DialogHeader";
|
||||
|
||||
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
|
||||
);
|
||||
DialogFooter.displayName = "DialogFooter";
|
||||
|
||||
const DialogTitle = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Title>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
|
||||
)
|
||||
);
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => <DialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />);
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };
|
||||
@@ -1,173 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
));
|
||||
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
));
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
));
|
||||
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
));
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)} {...props} />
|
||||
));
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => <DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />);
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||
|
||||
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />;
|
||||
};
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
};
|
||||
@@ -1,117 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
|
||||
import { cn } from "./utils";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
const Form = FormProvider;
|
||||
|
||||
type FormFieldContextValue<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
|
||||
name: TName;
|
||||
};
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
|
||||
|
||||
const FormField = <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext);
|
||||
const itemContext = React.useContext(FormItemContext);
|
||||
const { getFieldState, formState } = useFormContext();
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState);
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error("useFormField should be used within <FormField>");
|
||||
}
|
||||
|
||||
const { id } = itemContext;
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
};
|
||||
};
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
|
||||
|
||||
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => {
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
});
|
||||
FormItem.displayName = "FormItem";
|
||||
|
||||
const FormLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>>(
|
||||
({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField();
|
||||
|
||||
return <Label ref={ref} className={cn(error && "text-destructive", className)} htmlFor={formItemId} {...props} />;
|
||||
}
|
||||
);
|
||||
FormLabel.displayName = "FormLabel";
|
||||
|
||||
const FormControl = React.forwardRef<React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
FormControl.displayName = "FormControl";
|
||||
|
||||
const FormDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField();
|
||||
|
||||
return <p ref={ref} id={formDescriptionId} className={cn("text-sm text-muted-foreground", className)} {...props} />;
|
||||
});
|
||||
FormDescription.displayName = "FormDescription";
|
||||
|
||||
const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const body = error ? t(String(error?.message)) : children;
|
||||
|
||||
if (!body) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<p ref={ref} id={formMessageId} className={cn("text-sm font-medium text-destructive", className)} {...props}>
|
||||
{body}
|
||||
</p>
|
||||
);
|
||||
});
|
||||
FormMessage.displayName = "FormMessage";
|
||||
|
||||
export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField };
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
||||
@@ -1,15 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />);
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
export { Label };
|
||||
@@ -1,122 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
const Select = SelectPrimitive.Root;
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group;
|
||||
|
||||
const SelectValue = SelectPrimitive.Value;
|
||||
|
||||
const SelectTrigger = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Trigger>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>>(
|
||||
({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
);
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
|
||||
const SelectScrollUpButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton ref={ref} className={cn("flex cursor-default items-center justify-center py-1", className)} {...props}>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
));
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||
|
||||
const SelectScrollDownButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton ref={ref} className={cn("flex cursor-default items-center justify-center py-1", className)} {...props}>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
));
|
||||
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
||||
|
||||
const SelectContent = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Content>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>>(
|
||||
({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn("p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]")}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
);
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||
|
||||
const SelectLabel = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Label>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>>(
|
||||
({ className, ...props }, ref) => <SelectPrimitive.Label ref={ref} className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)} {...props} />
|
||||
);
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||
|
||||
const SelectItem = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Item>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>>(
|
||||
({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
);
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||
|
||||
const SelectSeparator = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Separator>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>>(
|
||||
({ className, ...props }, ref) => <SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
|
||||
);
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Textarea.displayName = "Textarea";
|
||||
|
||||
export { Textarea };
|
||||
@@ -1,6 +0,0 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { accessProvidersMap, deployProvidersMap } from "@/domain/provider";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAccessStore } from "@/stores/access";
|
||||
|
||||
type AccessSelectProps = {
|
||||
providerType: string;
|
||||
value: string;
|
||||
onValueChange: (val: string) => void;
|
||||
};
|
||||
const AccessSelect = ({ value, onValueChange, providerType }: AccessSelectProps) => {
|
||||
const [localValue, setLocalValue] = React.useState<string>("");
|
||||
const { t } = useTranslation();
|
||||
const { accesses, fetchAccesses } = useAccessStore();
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccesses();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(value);
|
||||
}, [value]);
|
||||
|
||||
const targetAccesses = accesses.filter((item) => {
|
||||
return item.configType === deployProvidersMap.get(providerType)?.provider;
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
value={localValue}
|
||||
onValueChange={(val: string) => {
|
||||
setLocalValue(val);
|
||||
onValueChange(val);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="mt-2">
|
||||
<SelectValue placeholder={t("domain.deployment.form.access.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t("domain.deployment.form.access.list")}</SelectLabel>
|
||||
{targetAccesses.map((item) => (
|
||||
<SelectItem key={item.id} value={item.id}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<img className="w-6" src={accessProvidersMap.get(item.configType)?.icon} />
|
||||
<div>{item.name}</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessSelect;
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Dropdown } from "antd";
|
||||
import { PlusOutlined as PlusOutlinedIcon } from "@ant-design/icons";
|
||||
|
||||
@@ -9,8 +8,6 @@ import { type BrandNodeProps, type NodeProps } from "./types";
|
||||
import DropdownMenuItemIcon from "./DropdownMenuItemIcon";
|
||||
|
||||
const AddNode = ({ data }: NodeProps | BrandNodeProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
|
||||
|
||||
const handleTypeSelected = (type: WorkflowNodeType, provider?: string) => {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import AddNode from "./AddNode";
|
||||
import { WorkflowBranchNode, WorkflowNode } from "@/domain/workflow";
|
||||
import NodeRender from "./NodeRender";
|
||||
import { memo } from "react";
|
||||
import { BrandNodeProps } from "./types";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "antd";
|
||||
|
||||
import AddNode from "./AddNode";
|
||||
import NodeRender from "./NodeRender";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { type WorkflowBranchNode, type WorkflowNode } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { type BrandNodeProps } from "./types";
|
||||
|
||||
const BranchNode = memo(({ data }: BrandNodeProps) => {
|
||||
const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"]));
|
||||
@@ -27,12 +28,12 @@ const BranchNode = memo(({ data }: BrandNodeProps) => {
|
||||
<>
|
||||
<div className="border-t-[2px] border-b-[2px] relative flex gap-x-16 border-stone-200 bg-background">
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
addBranch(data.id);
|
||||
}}
|
||||
size={"sm"}
|
||||
variant={"outline"}
|
||||
className="text-xs px-2 h-6 rounded-full absolute -top-3 left-[50%] -translate-x-1/2 z-[1] dark:text-stone-200"
|
||||
className="text-xs px-2 h-6 rounded-full absolute -top-3 left-[50%] -translate-x-1/2 z-[1] dark:text-stone-200"
|
||||
>
|
||||
{t("workflow.node.addBranch.label")}
|
||||
</Button>
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { memo } from "react";
|
||||
|
||||
import { type WorkflowNode } from "@/domain/workflow";
|
||||
import DeployToAliyunALB from "./DeployToAliyunALB";
|
||||
import DeployToAliyunCDN from "./DeployToAliyunCDN";
|
||||
import DeployToAliyunCLB from "./DeployToAliyunCLB";
|
||||
import DeployToAliyunNLB from "./DeployToAliyunNLB";
|
||||
import DeployToAliyunOSS from "./DeployToAliyunOss";
|
||||
import DeployToBaiduCloudCDN from "./DeployToBaiduCloudCDN";
|
||||
import DeployToBytePlusCDN from "./DeployToByteplusCDN";
|
||||
import DeployToDogeCloudCDN from "./DeployToDogeCloudCDN";
|
||||
import DeployToHuaweiCloudCDN from "./DeployToHuaweiCloudCDN";
|
||||
import DeployToHuaweiCloudELB from "./DeployToHuaweiCloudELB";
|
||||
import DeployToKubernetesSecret from "./DeployToKubernetesSecret";
|
||||
import DeployToLocal from "./DeployToLocal";
|
||||
import DeployToQiniuCDN from "./DeployToQiniuCDN";
|
||||
import DeployToSSH from "./DeployToSSH";
|
||||
import DeployToTencentCDN from "./DeployToTencentCDN";
|
||||
import DeployToTencentCLB from "./DeployToTencentCLB";
|
||||
import DeployToTencentCOS from "./DeployToTencentCOS";
|
||||
import DeployToTencentEO from "./DeployToTencentTEO";
|
||||
import DeployToVolcEngineCDN from "./DeployToVolcengineCDN";
|
||||
import DeployToVolcEngineLive from "./DeployToVolcengineLive";
|
||||
import DeployToWebhook from "./DeployToWebhook";
|
||||
|
||||
export type DeployFormProps = {
|
||||
data: WorkflowNode;
|
||||
defaultProivder?: string;
|
||||
};
|
||||
|
||||
const DeployForm = ({ data, defaultProivder }: DeployFormProps) => {
|
||||
return <div className="dark:text-stone-200">{getForm(data, defaultProivder)}</div>;
|
||||
};
|
||||
|
||||
export default memo(DeployForm);
|
||||
|
||||
const getForm = (data: WorkflowNode, defaultProivder?: string) => {
|
||||
const provider = defaultProivder || data.config?.providerType;
|
||||
switch (provider) {
|
||||
case "aliyun-oss":
|
||||
return <DeployToAliyunOSS data={data} />;
|
||||
case "aliyun-alb":
|
||||
return <DeployToAliyunALB data={data} />;
|
||||
case "aliyun-cdn":
|
||||
case "aliyun-dcdn":
|
||||
return <DeployToAliyunCDN data={data} />;
|
||||
case "aliyun-clb":
|
||||
return <DeployToAliyunCLB data={data} />;
|
||||
case "aliyun-nlb":
|
||||
return <DeployToAliyunNLB data={data} />;
|
||||
case "baiducloud-cdn":
|
||||
return <DeployToBaiduCloudCDN data={data} />;
|
||||
case "dogecloud-cdn":
|
||||
return <DeployToDogeCloudCDN data={data} />;
|
||||
case "huaweicloud-cdn":
|
||||
return <DeployToHuaweiCloudCDN data={data} />;
|
||||
case "huaweicloud-elb":
|
||||
return <DeployToHuaweiCloudELB data={data} />;
|
||||
case "k8s-secret":
|
||||
return <DeployToKubernetesSecret data={data} />;
|
||||
case "qiniu-cdn":
|
||||
return <DeployToQiniuCDN data={data} />;
|
||||
case "webhook":
|
||||
return <DeployToWebhook data={data} />;
|
||||
case "tencentcloud-cdn":
|
||||
case "tencentcloud-ecdn":
|
||||
return <DeployToTencentCDN data={data} />;
|
||||
case "tencentcloud-clb":
|
||||
return <DeployToTencentCLB data={data} />;
|
||||
case "tencentcloud-cos":
|
||||
return <DeployToTencentCOS data={data} />;
|
||||
case "tencentcloud-eo":
|
||||
return <DeployToTencentEO data={data} />;
|
||||
case "ssh":
|
||||
return <DeployToSSH data={data} />;
|
||||
case "local":
|
||||
return <DeployToLocal data={data} />;
|
||||
case "byteplus-cdn":
|
||||
return <DeployToBytePlusCDN data={data} />;
|
||||
case "volcengine-cdn":
|
||||
return <DeployToVolcEngineCDN data={data} />;
|
||||
case "volcengine-live":
|
||||
return <DeployToVolcEngineLive data={data} />;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
@@ -1,257 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToAliyunALB = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.aliyun_alb_region.placeholder")),
|
||||
resourceType: z.union([z.literal("loadbalancer"), z.literal("listener")], {
|
||||
message: t("domain.deployment.form.aliyun_alb_resource_type.placeholder"),
|
||||
}),
|
||||
loadbalancerId: z.string().optional(),
|
||||
listenerId: z.string().optional(),
|
||||
})
|
||||
.refine((data) => (data.resourceType === "loadbalancer" ? !!data.loadbalancerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
})
|
||||
.refine((data) => (data.resourceType === "listener" ? !!data.listenerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.aliyun_alb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
region: "",
|
||||
resourceType: "",
|
||||
loadbalancerId: "",
|
||||
listenerId: "",
|
||||
access: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "aliyun-alb",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
resourceType: config.resourceType as "loadbalancer" | "listener",
|
||||
loadbalancerId: config.loadbalancerId as string,
|
||||
listenerId: config.listenerId as string,
|
||||
},
|
||||
});
|
||||
|
||||
const resourceType = form.watch("resourceType");
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="aliyun-alb"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_alb_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_alb_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="resourceType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_alb_resource_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("resourceType", value as "loadbalancer" | "listener");
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.aliyun_alb_resource_type.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="loadbalancer">{t("domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label")}</SelectItem>
|
||||
<SelectItem value="listener">{t("domain.deployment.form.aliyun_alb_resource_type.option.listener.label")}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{resourceType === "loadbalancer" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loadbalancerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_alb_loadbalancer_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "listener" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="listenerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_alb_listener_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_alb_listener_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToAliyunALB;
|
||||
@@ -1,177 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToAliyunCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "aliyun-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="aliyun-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToAliyunCDN;
|
||||
@@ -1,257 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToAliyunCLB = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.aliyun_clb_region.placeholder")),
|
||||
resourceType: z.union([z.literal("certificate"), z.literal("loadbalancer"), z.literal("listener")], {
|
||||
message: t("domain.deployment.form.aliyun_clb_resource_type.placeholder"),
|
||||
}),
|
||||
loadbalancerId: z.string().optional(),
|
||||
listenerPort: z.string().optional(),
|
||||
})
|
||||
.refine((data) => (data.resourceType === "loadbalancer" || data.resourceType === "listener" ? !!data.loadbalancerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.aliyun_clb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
})
|
||||
.refine((data) => (data.resourceType === "listener" ? +data.listenerPort! > 0 && +data.listenerPort! < 65535 : true), {
|
||||
message: t("domain.deployment.form.aliyun_clb_listener_port.placeholder"),
|
||||
path: ["listenerPort"],
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
region: "",
|
||||
resourceType: "",
|
||||
loadbalancerId: "",
|
||||
listenerPort: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "aliyun-clb",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
resourceType: config.resourceType as "loadbalancer" | "listener",
|
||||
loadbalancerId: config.loadbalancerId as string,
|
||||
listenerPort: config.listenerPort as string,
|
||||
},
|
||||
});
|
||||
|
||||
const resouceType = form.watch("resourceType");
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="aliyun-clb"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_clb_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_clb_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="resourceType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_clb_resource_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("resourceType", value as "loadbalancer" | "listener");
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.aliyun_clb_resource_type.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="loadbalancer">{t("domain.deployment.form.aliyun_clb_resource_type.option.loadbalancer.label")}</SelectItem>
|
||||
<SelectItem value="listener">{t("domain.deployment.form.aliyun_clb_resource_type.option.listener.label")}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loadbalancerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_clb_loadbalancer_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_clb_loadbalancer_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{resouceType === "listener" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="listenerPort"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_clb_listener_port.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_clb_listener_port.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToAliyunCLB;
|
||||
@@ -1,219 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
const DeployToAliyunNLB = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.aliyun_nlb_region.placeholder")),
|
||||
resourceType: z.union([z.literal("loadbalancer"), z.literal("listener")], {
|
||||
message: t("domain.deployment.form.aliyun_nlb_resource_type.placeholder"),
|
||||
}),
|
||||
loadbalancerId: z.string().optional(),
|
||||
listenerId: z.string().optional(),
|
||||
})
|
||||
.refine((data) => (data.resourceType === "loadbalancer" ? !!data.loadbalancerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.aliyun_nlb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
})
|
||||
.refine((data) => (data.resourceType === "listener" ? !!data.listenerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.aliyun_nlb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
region: "",
|
||||
resourceType: "",
|
||||
loadbalancerId: "",
|
||||
listenerId: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "aliyun-nlb",
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
resourceType: config.resourceType as "loadbalancer" | "listener",
|
||||
loadbalancerId: config.loadbalancerId as string,
|
||||
listenerId: config.listenerId as string,
|
||||
},
|
||||
});
|
||||
|
||||
const resourceType = form.watch("resourceType");
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_nlb_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_nlb_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="resourceType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_nlb_resource_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("resourceType", value as "loadbalancer" | "listener");
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.aliyun_nlb_resource_type.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="loadbalancer">{t("domain.deployment.form.aliyun_nlb_resource_type.option.loadbalancer.label")}</SelectItem>
|
||||
<SelectItem value="listener">{t("domain.deployment.form.aliyun_nlb_resource_type.option.listener.label")}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{resourceType === "loadbalancer" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loadbalancerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_nlb_loadbalancer_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_nlb_loadbalancer_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "listener" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="listenerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_nlb_listener_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_nlb_listener_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToAliyunNLB;
|
||||
@@ -1,214 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToAliyunOSS = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
endpoint: z.string().min(1, {
|
||||
message: t("domain.deployment.form.aliyun_oss_endpoint.placeholder"),
|
||||
}),
|
||||
bucket: z.string().min(1, {
|
||||
message: t("domain.deployment.form.aliyun_oss_bucket.placeholder"),
|
||||
}),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
endpoint: "",
|
||||
bucket: "",
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "aliyun-oss",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
endpoint: config.endpoint as string,
|
||||
bucket: config.bucket as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="aliyun-oss"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="endpoint"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_oss_endpoint.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_oss_endpoint.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bucket"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.aliyun_oss_bucket.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.aliyun_oss_bucket.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToAliyunOSS;
|
||||
@@ -1,176 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToBaiduCloudCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "baiducloud-cdn",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "baiducloud-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "baiducloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="baiducloud-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToBaiduCloudCDN;
|
||||
@@ -1,176 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToByteplusCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "byteplus-cdn",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "byteplus-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "byteplus" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="byteplus-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToByteplusCDN;
|
||||
@@ -1,177 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
|
||||
const DeployToDogeCloudCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "dogecloud-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "dogecloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="dogecloud-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToDogeCloudCDN;
|
||||
@@ -1,198 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToHuaweiCloudCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, {
|
||||
message: t("domain.deployment.form.huaweicloud_cdn_region.placeholder"),
|
||||
}),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
region: "",
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "huaweicloud-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "huaweicloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="huaweicloud-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_cdn_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_cdn_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToHuaweiCloudCDN;
|
||||
@@ -1,289 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
|
||||
const DeployToHuaweiCloudELB = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [resourceType, setResourceType] = useState<"certificate" | "loadbalancer" | "listener">();
|
||||
|
||||
useEffect(() => {
|
||||
setResourceType(data.config?.resourceType as "certificate" | "loadbalancer" | "listener");
|
||||
}, [data]);
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.huaweicloud_elb_region.placeholder")),
|
||||
resourceType: z.union([z.literal("certificate"), z.literal("loadbalancer"), z.literal("listener")], {
|
||||
message: t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder"),
|
||||
}),
|
||||
certificateId: z.string().optional(),
|
||||
loadbalancerId: z.string().optional(),
|
||||
listenerId: z.string().optional(),
|
||||
})
|
||||
.refine((data) => (data.resourceType === "certificate" ? !!data.certificateId?.trim() : true), {
|
||||
message: t("domain.deployment.form.huaweicloud_elb_certificate_id.placeholder"),
|
||||
path: ["certificateId"],
|
||||
})
|
||||
.refine((data) => (data.resourceType === "loadbalancer" ? !!data.loadbalancerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
})
|
||||
.refine((data) => (data.resourceType === "listener" ? !!data.listenerId?.trim() : true), {
|
||||
message: t("domain.deployment.form.huaweicloud_elb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
resouceType: "",
|
||||
certificateId: "",
|
||||
loadbalancerId: "",
|
||||
listenerId: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "huaweicloud-elb",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
resourceType: config.resourceType as "certificate" | "loadbalancer" | "listener",
|
||||
certificateId: config.certificateId as string,
|
||||
loadbalancerId: config.loadbalancerId as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "huaweicloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="huaweicloud-elb"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_cdn_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_cdn_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="resourceType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_elb_resource_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
setResourceType(value as "certificate" | "loadbalancer" | "listener");
|
||||
form.setValue("resourceType", value as "loadbalancer" | "certificate" | "listener");
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="certificate">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label")}</SelectItem>
|
||||
<SelectItem value="loadbalancer">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label")}</SelectItem>
|
||||
<SelectItem value="listener">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label")}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{resourceType === "certificate" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificateId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_elb_certificate_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_elb_certificate_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "loadbalancer" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loadbalancerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "listener" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="listenerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_elb_listener_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_elb_listener_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToHuaweiCloudELB;
|
||||
@@ -1,233 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
|
||||
const DeployToKubernetesSecret = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
namespace: z.string().min(1, {
|
||||
message: t("domain.deployment.form.k8s_namespace.placeholder"),
|
||||
}),
|
||||
secretName: z.string().min(1, {
|
||||
message: t("domain.deployment.form.k8s_secret_name.placeholder"),
|
||||
}),
|
||||
secretDataKeyForCrt: z.string().min(1, {
|
||||
message: t("domain.deployment.form.k8s_secret_data_key_for_crt.placeholder"),
|
||||
}),
|
||||
secretDataKeyForKey: z.string().min(1, {
|
||||
message: t("domain.deployment.form.k8s_secret_data_key_for_key.placeholder"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
namespace: "",
|
||||
secretName: "",
|
||||
secretDataKeyForCrt: "",
|
||||
secretDataKeyForKey: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "k8s-secret",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
namespace: config.namespace as string,
|
||||
secretName: config.secretName as string,
|
||||
secretDataKeyForCrt: config.secretDataKeyForCrt as string,
|
||||
secretDataKeyForKey: config.secretDataKeyForKey as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "k8s" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="k8s-secret"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="namespace"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.k8s_namespace.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder={t("domain.deployment.form.k8s_namespace.label")} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="secretName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.k8s_secret_name.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder={t("domain.deployment.form.k8s_secret_name.label")} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="secretDataKeyForCrt"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.k8s_secret_data_key_for_crt.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder={t("domain.deployment.form.k8s_secret_data_key_for_crt.label")} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="secretDataKeyForKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.k8s_secret_data_key_for_key.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder={t("domain.deployment.form.k8s_secret_data_key_for_key.label")} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToKubernetesSecret;
|
||||
@@ -1,476 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { Button } from "../ui/button";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { useEffect, useState } from "react";
|
||||
import i18n from "@/i18n";
|
||||
import { WorkflowNode } from "@/domain/workflow";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Dropdown } from "antd";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const t = i18n.t;
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
format: z.union([z.literal("pem"), z.literal("pfx"), z.literal("jks")], {
|
||||
message: t("domain.deployment.form.file_format.placeholder"),
|
||||
}),
|
||||
certPath: z
|
||||
.string()
|
||||
.min(1, t("domain.deployment.form.file_cert_path.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
keyPath: z
|
||||
.string()
|
||||
.min(0, t("domain.deployment.form.file_key_path.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.nullish(),
|
||||
pfxPassword: z.string().nullish(),
|
||||
jksAlias: z.string().nullish(),
|
||||
jksKeypass: z.string().nullish(),
|
||||
jksStorepass: z.string().nullish(),
|
||||
preCommand: z.string().nullish(),
|
||||
postCommand: z.string().nullish(),
|
||||
shell: z.union([z.literal("sh"), z.literal("cmd"), z.literal("powershell")], {
|
||||
message: t("domain.deployment.form.shell.placeholder"),
|
||||
}),
|
||||
})
|
||||
.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"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksAlias?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_alias.placeholder"),
|
||||
path: ["jksAlias"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksKeypass?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_keypass.placeholder"),
|
||||
path: ["jksKeypass"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksStorepass?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_storepass.placeholder"),
|
||||
path: ["jksStorepass"],
|
||||
});
|
||||
|
||||
const DeployToLocal = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "local",
|
||||
access: data.config?.access as string,
|
||||
certificate: data.config?.certificate as string,
|
||||
format: (data.config?.format as "pem" | "pfx" | "jks") || "pem",
|
||||
certPath: (data.config?.certPath as string) || "/etc/ssl/certs/cert.crt",
|
||||
keyPath: (data.config?.keyPath as string) || "/etc/ssl/private/cert.key",
|
||||
pfxPassword: (data.config?.pfxPassword as string) || "",
|
||||
jksAlias: (data.config?.jksAlias as string) || "",
|
||||
jksKeypass: (data.config?.jksKeypass as string) || "",
|
||||
jksStorepass: (data.config?.jksStorepass as string) || "",
|
||||
shell: (data.config?.shell as "sh" | "cmd" | "powershell") || "sh",
|
||||
preCommand: (data.config?.preCommand as string) || "",
|
||||
postCommand: (data.config?.postCommand as string) || "service nginx reload",
|
||||
},
|
||||
});
|
||||
|
||||
const format = form.watch("format");
|
||||
const certPath = form.watch("certPath");
|
||||
|
||||
useEffect(() => {
|
||||
if (format === "pem" && /(.pfx|.jks)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.pfx|.jks)$/, ".crt"));
|
||||
} else if (format === "pfx" && /(.crt|.jks)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.crt|.jks)$/, ".pfx"));
|
||||
} else if (format === "jks" && /(.crt|.pfx)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.crt|.pfx)$/, ".jks"));
|
||||
}
|
||||
}, [format]);
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
const handleUsePresetScript = (key: string) => {
|
||||
switch (key) {
|
||||
case "reload_nginx":
|
||||
{
|
||||
form.setValue("shell", "sh");
|
||||
form.setValue("postCommand", "sudo service nginx reload");
|
||||
}
|
||||
break;
|
||||
|
||||
case "binding_iis":
|
||||
{
|
||||
form.setValue("shell", "powershell");
|
||||
form.setValue(
|
||||
"postCommand",
|
||||
`# 请将以下变量替换为实际值
|
||||
$pfxPath = "<your-pfx-path>" # PFX 文件路径
|
||||
$pfxPassword = "<your-pfx-password>" # PFX 密码
|
||||
$siteName = "<your-site-name>" # IIS 网站名称
|
||||
$domain = "<your-domain-name>" # 域名
|
||||
$ipaddr = "<your-binding-ip>" # 绑定 IP,“*”表示所有 IP 绑定
|
||||
$port = "<your-binding-port>" # 绑定端口
|
||||
|
||||
|
||||
# 导入证书到本地计算机的个人存储区
|
||||
$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
|
||||
# 获取 Thumbprint
|
||||
$thumbprint = $cert.Thumbprint
|
||||
# 导入 WebAdministration 模块
|
||||
Import-Module WebAdministration
|
||||
# 检查是否已存在 HTTPS 绑定
|
||||
$existingBinding = Get-WebBinding -Name "$siteName" -Protocol "https" -Port $port -HostHeader "$domain" -ErrorAction SilentlyContinue
|
||||
if (!$existingBinding) {
|
||||
# 添加新的 HTTPS 绑定
|
||||
New-WebBinding -Name "$siteName" -Protocol "https" -Port $port -IPAddress "$ipaddr" -HostHeader "$domain"
|
||||
}
|
||||
# 获取绑定对象
|
||||
$binding = Get-WebBinding -Name "$siteName" -Protocol "https" -Port $port -IPAddress "$ipaddr" -HostHeader "$domain"
|
||||
# 绑定 SSL 证书
|
||||
$binding.AddSslCertificate($thumbprint, "My")
|
||||
# 删除目录下的证书文件
|
||||
Remove-Item -Path "$pfxPath" -Force
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "binding_netsh":
|
||||
{
|
||||
form.setValue("shell", "powershell");
|
||||
form.setValue(
|
||||
"postCommand",
|
||||
`# 请将以下变量替换为实际值
|
||||
$pfxPath = "<your-pfx-path>" # PFX 文件路径
|
||||
$pfxPassword = "<your-pfx-password>" # PFX 密码
|
||||
$ipaddr = "<your-binding-ip>" # 绑定 IP,“0.0.0.0”表示所有 IP 绑定,可填入域名。
|
||||
$port = "<your-binding-port>" # 绑定端口
|
||||
|
||||
$addr = $ipaddr + ":" + $port
|
||||
|
||||
# 导入证书到本地计算机的个人存储区
|
||||
$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
|
||||
# 获取 Thumbprint
|
||||
$thumbprint = $cert.Thumbprint
|
||||
# 检测端口是否绑定证书,如绑定则删除绑定
|
||||
$isExist = netsh http show sslcert ipport=$addr
|
||||
if ($isExist -like "*$addr*"){ netsh http delete sslcert ipport=$addr }
|
||||
# 绑定到端口
|
||||
netsh http add sslcert ipport=$addr certhash=$thumbprint
|
||||
# 删除目录下的证书文件
|
||||
Remove-Item -Path "$pfxPath" -Force
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "local" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="local"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="format"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.file_format.label")}</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.file_format.placeholder")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="pem">PEM</SelectItem>
|
||||
<SelectItem value="pfx">PFX</SelectItem>
|
||||
<SelectItem value="jks">JKS</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certPath"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.file_cert_path.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.file_cert_path.label")} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="keyPath"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>密钥路径</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入密钥路径" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{format === "pfx" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pfxPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>PFX 密码</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 PFX 密码" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{format === "jks" && (
|
||||
<>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksAlias"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS 别名</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入 JKS 别名" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksKeypass"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS Keypass</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 JKS Keypass" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksStorepass"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS Storepass</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 JKS Storepass" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shell"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.shell.label")}</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.shell.placeholder")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="sh">POSIX Bash (Linux)</SelectItem>
|
||||
<SelectItem value="cmd">CMD (Windows)</SelectItem>
|
||||
<SelectItem value="powershell">PowerShell (Windows)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="preCommand"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.shell_pre_command.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea placeholder={t("domain.deployment.form.shell_pre_command.placeholder")} {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="postCommand"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between items-center">
|
||||
<div>{t("domain.deployment.form.shell_command.label")}</div>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
key: "reload_nginx",
|
||||
label: t("domain.deployment.form.shell_preset_scripts.option.reload_nginx.label"),
|
||||
onClick: () => handleUsePresetScript("reload_nginx"),
|
||||
},
|
||||
{
|
||||
key: "binding_iis",
|
||||
label: t("domain.deployment.form.shell_preset_scripts.option.binding_iis.label"),
|
||||
onClick: () => handleUsePresetScript("binding_iis"),
|
||||
},
|
||||
{
|
||||
key: "binding_netsh",
|
||||
label: t("domain.deployment.form.shell_preset_scripts.option.binding_netsh.label"),
|
||||
onClick: () => handleUsePresetScript("binding_netsh"),
|
||||
},
|
||||
],
|
||||
}}
|
||||
trigger={["click"]}
|
||||
>
|
||||
<a className="text-xs text-blue-500 cursor-pointer">{t("domain.deployment.form.shell_preset_scripts.trigger")}</a>
|
||||
</Dropdown>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea placeholder={t("domain.deployment.form.shell_command.placeholder")} {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToLocal;
|
||||
@@ -1,178 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToQiniuCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "qiniu-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "qiniu" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="qiniu-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToQiniuCDN;
|
||||
@@ -1,345 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { Button } from "../ui/button";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { useEffect, useState } from "react";
|
||||
import i18n from "@/i18n";
|
||||
import { WorkflowNode } from "@/domain/workflow";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const t = i18n.t;
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
format: z.union([z.literal("pem"), z.literal("pfx"), z.literal("jks")], {
|
||||
message: t("domain.deployment.form.file_format.placeholder"),
|
||||
}),
|
||||
certPath: z
|
||||
.string()
|
||||
.min(1, t("domain.deployment.form.file_cert_path.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
keyPath: z
|
||||
.string()
|
||||
.min(0, t("domain.deployment.form.file_key_path.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.nullish(),
|
||||
pfxPassword: z.string().nullish(),
|
||||
jksAlias: z.string().nullish(),
|
||||
jksKeypass: z.string().nullish(),
|
||||
jksStorepass: z.string().nullish(),
|
||||
preCommand: z.string().nullish(),
|
||||
postCommand: z.string().nullish(),
|
||||
})
|
||||
.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"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksAlias?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_alias.placeholder"),
|
||||
path: ["jksAlias"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksKeypass?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_keypass.placeholder"),
|
||||
path: ["jksKeypass"],
|
||||
})
|
||||
.refine((data) => (data.format === "jks" ? !!data.jksStorepass?.trim() : true), {
|
||||
message: t("domain.deployment.form.file_jks_storepass.placeholder"),
|
||||
path: ["jksStorepass"],
|
||||
});
|
||||
|
||||
const DeployToSSH = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "ssh",
|
||||
access: data.config?.access as string,
|
||||
certificate: data.config?.certificate as string,
|
||||
format: (data.config?.format as "pem" | "pfx" | "jks") || "pem",
|
||||
certPath: (data.config?.certPath as string) || "/etc/ssl/certs/cert.crt",
|
||||
keyPath: (data.config?.keyPath as string) || "/etc/ssl/private/cert.key",
|
||||
pfxPassword: (data.config?.pfxPassword as string) || "",
|
||||
jksAlias: (data.config?.jksAlias as string) || "",
|
||||
jksKeypass: (data.config?.jksKeypass as string) || "",
|
||||
jksStorepass: (data.config?.jksStorepass as string) || "",
|
||||
preCommand: (data.config?.preCommand as string) || "",
|
||||
postCommand: (data.config?.postCommand as string) || "",
|
||||
},
|
||||
});
|
||||
|
||||
const format = form.watch("format");
|
||||
const certPath = form.watch("certPath");
|
||||
|
||||
useEffect(() => {
|
||||
if (format === "pem" && /(.pfx|.jks)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.pfx|.jks)$/, ".crt"));
|
||||
} else if (format === "pfx" && /(.crt|.jks)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.crt|.jks)$/, ".pfx"));
|
||||
} else if (format === "jks" && /(.crt|.pfx)$/.test(certPath)) {
|
||||
form.setValue("certPath", certPath.replace(/(.crt|.pfx)$/, ".jks"));
|
||||
}
|
||||
}, [format]);
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "ssh" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="ssh"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="format"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.file_format.label")}</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.file_format.placeholder")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="pem">PEM</SelectItem>
|
||||
<SelectItem value="pfx">PFX</SelectItem>
|
||||
<SelectItem value="jks">JKS</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certPath"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.file_cert_path.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.file_cert_path.label")} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="keyPath"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>密钥路径</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入密钥路径" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{format === "pfx" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pfxPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>PFX 密码</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 PFX 密码" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{format === "jks" && (
|
||||
<>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksAlias"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS 别名</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="输入 JKS 别名" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksKeypass"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS Keypass</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 JKS Keypass" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="jksStorepass"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>JKS Storepass</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="输入 JKS Storepass" {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="preCommand"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.shell_pre_command.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea placeholder={t("domain.deployment.form.shell_pre_command.placeholder")} {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="postCommand"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.shell_command.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea placeholder={t("domain.deployment.form.shell_command.placeholder")} {...(field as any)} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToSSH;
|
||||
@@ -1,176 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToTencentCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "tencentcloud-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="tencentcloud-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToTencentCDN;
|
||||
@@ -1,316 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
type TencentResourceType = "ssl-deploy" | "loadbalancer" | "listener" | "ruledomain";
|
||||
|
||||
const DeployToTencentCLB = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [resourceType, setResourceType] = useState<TencentResourceType>();
|
||||
|
||||
useEffect(() => {
|
||||
setResourceType(data.config?.resourceType as TencentResourceType);
|
||||
}, [data]);
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.tencent_clb_region.placeholder")),
|
||||
resourceType: z.union([z.literal("ssl-deploy"), z.literal("loadbalancer"), z.literal("listener"), z.literal("ruledomain")], {
|
||||
message: t("domain.deployment.form.tencent_clb_resource_type.placeholder"),
|
||||
}),
|
||||
loadbalancerId: z.string().min(1, t("domain.deployment.form.tencent_clb_loadbalancer_id.placeholder")),
|
||||
listenerId: z.string().optional(),
|
||||
domain: z.string().regex(/^$|^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
switch (data.resourceType) {
|
||||
case "ssl-deploy":
|
||||
case "listener":
|
||||
case "ruledomain":
|
||||
return !!data.listenerId?.trim();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: t("domain.deployment.form.tencent_clb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
}
|
||||
)
|
||||
.refine((data) => (data.resourceType === "ruledomain" ? !!data.domain?.trim() : true), {
|
||||
message: t("domain.deployment.form.tencent_clb_ruledomain.placeholder"),
|
||||
path: ["domain"],
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
resouceType: "",
|
||||
domain: "",
|
||||
loadbalancerId: "",
|
||||
listenerId: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "tencentcloud-clb",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
resourceType: config.resourceType as TencentResourceType,
|
||||
domain: config.certificateId as string,
|
||||
loadbalancerId: config.loadbalancerId as string,
|
||||
listenerId: config.listenerId as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="tencentcloud-clb"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.huaweicloud_cdn_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.huaweicloud_cdn_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="resourceType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_clb_resource_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
setResourceType(value as TencentResourceType);
|
||||
form.setValue("resourceType", value as TencentResourceType);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("domain.deployment.form.tencent_clb_resource_type.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="ssl-deploy">{t("domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label")}</SelectItem>
|
||||
<SelectItem value="loadbalancer">{t("domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label")}</SelectItem>
|
||||
<SelectItem value="listener">{t("domain.deployment.form.tencent_clb_resource_type.option.listener.label")}</SelectItem>
|
||||
<SelectItem value="ruledomain">{t("domain.deployment.form.tencent_clb_resource_type.option.ruledomain.label")}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loadbalancerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_clb_loadbalancer_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_clb_loadbalancer_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{(resourceType === "ssl-deploy" || resourceType === "listener" || resourceType === "ruledomain") && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="listenerId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_clb_listener_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_clb_listener_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "ssl-deploy" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_clb_domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_clb_domain.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{resourceType === "ruledomain" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_clb_ruledomain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_clb_ruledomain.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToTencentCLB;
|
||||
@@ -1,212 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToTencentCOS = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
region: z.string().min(1, t("domain.deployment.form.tencent_cos_region.placeholder")),
|
||||
bucket: z.string().min(1, t("domain.deployment.form.tencent_cos_bucket.placeholder")),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
region: "",
|
||||
bucket: "",
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "tencentcloud-cos",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
region: config.region as string,
|
||||
bucket: config.bucket as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="tencentcloud-cos"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_cos_region.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_cos_region.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bucket"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_cos_bucket.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_cos_bucket.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToTencentCOS;
|
||||
@@ -1,194 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToTencentTEO = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
console.log(rs);
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
zoneId: z.string().min(1, t("domain.deployment.form.tencent_teo_zone_id.placeholder")),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
zoneId: "",
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "tencentcloud-eo",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
zoneId: config.zoneId as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="tencentcloud-eo"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="zoneId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.tencent_teo_zone_id.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.tencent_teo_zone_id.placeholder")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToTencentTEO;
|
||||
@@ -1,176 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToVolcengineCDN = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "volcengine-cdn",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "volcengine-cdn",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "volcengine" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="volcengine-cdn"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToVolcengineCDN;
|
||||
@@ -1,176 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const DeployToVolcengineLive = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("common.errmsg.domain_invalid"),
|
||||
}),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "volcengine-live",
|
||||
access: "",
|
||||
|
||||
domain: "",
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "volcengine-live",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
domain: config.domain as string,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "volcengine" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="volcengine-live"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("domain.deployment.form.domain.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("domain.deployment.form.domain.label")} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToVolcengineLive;
|
||||
@@ -1,179 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { DeployFormProps } from "./DeployForm";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { usePanel } from "./PanelProvider";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import KVList from "../certimate/KVList";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const KVTypeSchema = z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
});
|
||||
const DeployToWebhook = ({ data }: DeployFormProps) => {
|
||||
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
const { hidePanel } = usePanel();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [beforeOutput, setBeforeOutput] = useState<WorkflowNode[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
|
||||
setBeforeOutput(rs);
|
||||
}, [data]);
|
||||
|
||||
const formSchema = z.object({
|
||||
providerType: z.string(),
|
||||
access: z.string().min(1, t("domain.deployment.form.access.placeholder")),
|
||||
certificate: z.string().min(1),
|
||||
variables: z.array(KVTypeSchema).optional(),
|
||||
});
|
||||
|
||||
let config: WorkflowNodeConfig = {
|
||||
certificate: "",
|
||||
providerType: "",
|
||||
access: "",
|
||||
|
||||
variables: [],
|
||||
};
|
||||
if (data) config = data.config ?? config;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: "webhook",
|
||||
access: config.access as string,
|
||||
certificate: config.certificate as string,
|
||||
variables: config.variables as { key: string; value: string }[],
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (config: z.infer<typeof formSchema>) => {
|
||||
console.log(config);
|
||||
updateNode({ ...data, config: { ...config }, validated: true });
|
||||
hidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="access"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditModal
|
||||
data={{ configType: "webhook" }}
|
||||
preset="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<AccessSelect
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("access", value);
|
||||
}}
|
||||
providerType="webhook"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certificate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("workflow.common.certificate.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("certificate", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("workflow.common.certificate.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{beforeOutput.map((item) => (
|
||||
<>
|
||||
<SelectGroup key={item.id}>
|
||||
<SelectLabel>{item.name}</SelectLabel>
|
||||
{item.output?.map((output) => (
|
||||
<SelectItem key={output.name} value={`${item.id}#${output.name}`}>
|
||||
<div>
|
||||
{item.name}-{output.label}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="variables"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<KVList
|
||||
{...field}
|
||||
variables={field.value}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("variables", value);
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.button.save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployToWebhook;
|
||||
@@ -19,7 +19,7 @@ const DeployNodeFormLocalFields = () => {
|
||||
|
||||
const formSchema = z.object({
|
||||
format: z.union([z.literal(FORMAT_PEM), z.literal(FORMAT_PFX), z.literal(FORMAT_JKS)], {
|
||||
message: t("domain.deployment.form.local_format.placeholder"),
|
||||
message: t("workflow_node.deploy.form.local_format.placeholder"),
|
||||
}),
|
||||
certPath: z
|
||||
.string()
|
||||
|
||||
@@ -15,7 +15,7 @@ const DeployNodeFormSSHFields = () => {
|
||||
|
||||
const formSchema = z.object({
|
||||
format: z.union([z.literal(FORMAT_PEM), z.literal(FORMAT_PFX), z.literal(FORMAT_JKS)], {
|
||||
message: t("domain.deployment.form.ssh_format.placeholder"),
|
||||
message: t("workflow_node.deploy.form.ssh_format.placeholder"),
|
||||
}),
|
||||
certPath: z
|
||||
.string()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cloneElement, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Alert, Drawer } from "antd";
|
||||
|
||||
Reference in New Issue
Block a user