chore: remove unused code

This commit is contained in:
Fu Diwei 2024-12-26 00:42:23 +08:00
parent 4008c2bfd5
commit a980904e38
10 changed files with 107 additions and 652 deletions

176
ui/package-lock.json generated
View File

@ -11,7 +11,6 @@
"@ant-design/pro-components": "^2.8.2",
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-slot": "^1.1.0",
@ -23,7 +22,6 @@
"cron-parser": "^4.9.0",
"i18next": "^24.2.0",
"i18next-browser-languagedetector": "^8.0.2",
"i18next-http-backend": "^3.0.1",
"immer": "^10.1.1",
"jszip": "^3.10.1",
"lucide-react": "^0.469.0",
@ -3051,34 +3049,6 @@
}
}
},
"node_modules/@radix-ui/react-dropdown-menu": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz",
"integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-menu": "2.1.1",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
@ -3156,45 +3126,6 @@
}
}
},
"node_modules/@radix-ui/react-menu": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-menu/-/react-menu-2.1.1.tgz",
"integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-collection": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-dismissable-layer": "1.1.0",
"@radix-ui/react-focus-guards": "1.1.0",
"@radix-ui/react-focus-scope": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-popper": "1.2.0",
"@radix-ui/react-portal": "1.1.1",
"@radix-ui/react-presence": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-roving-focus": "1.1.0",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.7"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
@ -3249,29 +3180,6 @@
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
"integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
@ -3294,36 +3202,6 @@
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",
"integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-collection": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-select": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@radix-ui/react-select/-/react-select-2.1.1.tgz",
@ -4837,14 +4715,6 @@
"node": ">=12.0.0"
}
},
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-4.0.0.tgz",
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
"dependencies": {
"node-fetch": "^2.6.12"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -5667,14 +5537,6 @@
"@babel/runtime": "^7.23.2"
}
},
"node_modules/i18next-http-backend": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/i18next-http-backend/-/i18next-http-backend-3.0.1.tgz",
"integrity": "sha512-XT2lYSkbAtDE55c6m7CtKxxrsfuRQO3rUfHzj8ZyRtY9CkIX3aRGwXGTkUhpGWce+J8n7sfu3J0f2wTzo7Lw0A==",
"dependencies": {
"cross-fetch": "4.0.0"
}
},
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.1.tgz",
@ -6187,25 +6049,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-releases": {
"version": "2.0.19",
"resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz",
@ -8176,11 +8019,6 @@
"resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-api-utils": {
"version": "1.4.3",
"resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
@ -8481,20 +8319,6 @@
"loose-envify": "^1.0.0"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",

View File

@ -13,7 +13,6 @@
"@ant-design/pro-components": "^2.8.2",
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-slot": "^1.1.0",
@ -25,7 +24,6 @@
"cron-parser": "^4.9.0",
"i18next": "^24.2.0",
"i18next-browser-languagedetector": "^8.0.2",
"i18next-http-backend": "^3.0.1",
"immer": "^10.1.1",
"jszip": "^3.10.1",
"lucide-react": "^0.469.0",

View File

@ -1,30 +1,17 @@
import { Plus } from "lucide-react";
import { BrandNodeProps, NodeProps } from "./types";
import { newWorkflowNode, workflowNodeDropdownList, WorkflowNodeType } from "@/domain/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import { Dropdown } from "antd";
import DropdownMenuItemIcon from "./DropdownMenuItemIcon";
import Show from "../Show";
import { useTranslation } from "react-i18next";
const AddNode = ({ data }: NodeProps | BrandNodeProps) => {
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
const { t } = useTranslation();
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
const handleTypeSelected = (type: WorkflowNodeType, provider?: string) => {
const node = newWorkflowNode(type, {
providerType: provider,
@ -35,57 +22,43 @@ const AddNode = ({ data }: NodeProps | BrandNodeProps) => {
return (
<div className="before:content-[''] before:w-[2px] before:bg-stone-200 before:absolute before:h-full before:left-[50%] before:-translate-x-[50%] before:top-0 pt-6 pb-9 relative flex flex-col items-center">
<DropdownMenu>
<DropdownMenuTrigger className="">
<div className="bg-stone-400 hover:bg-stone-500 rounded-full z-10 relative outline-none">
<Plus size={18} className="text-white" />
</div>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>{t("workflow.node.selectNodeType.label")}</DropdownMenuLabel>
<DropdownMenuSeparator />
{workflowNodeDropdownList.map((item) => (
<Show
key={item.type}
when={!!item.leaf}
fallback={
<DropdownMenuSub>
<DropdownMenuSubTrigger className="flex space-x-2">
<DropdownMenuItemIcon type={item.icon.type} name={item.icon.name} /> <div>{item.name}</div>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
{item.children?.map((subItem) => {
return (
<DropdownMenuItem
key={subItem.providerType}
className="flex space-x-2"
onClick={() => {
handleTypeSelected(item.type, subItem.providerType);
}}
>
<DropdownMenuItemIcon type={subItem.icon.type} name={subItem.icon.name} /> <div>{subItem.name}</div>
</DropdownMenuItem>
);
})}
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
}
>
<DropdownMenuItem
key={item.type}
className="flex space-x-2"
onClick={() => {
handleTypeSelected(item.type, item.providerType);
}}
>
<DropdownMenuItemIcon type={item.icon.type} name={item.icon.name} /> <div>{item.name}</div>
</DropdownMenuItem>
</Show>
))}
</DropdownMenuContent>
</DropdownMenu>
<Dropdown
menu={{
items: workflowNodeDropdownList.map((item) => {
if (item.leaf) {
return {
key: item.type,
label: <div className="ml-2">{item.name}</div>,
icon: <DropdownMenuItemIcon type={item.icon.type} name={item.icon.name} />,
onClick: () => {
handleTypeSelected(item.type);
},
};
}
return {
key: item.type,
label: <div className="ml-2">{item.name}</div>,
icon: <DropdownMenuItemIcon type={item.icon.type} name={item.icon.name} />,
children: item.children?.map((subItem) => {
return {
key: subItem.providerType,
label: <div className="ml-2">{subItem.name}</div>,
icon: <DropdownMenuItemIcon type={subItem.icon.type} name={subItem.icon.name} />,
onClick: () => {
handleTypeSelected(item.type, subItem.providerType);
},
};
}),
};
}),
}}
trigger={["click"]}
>
<div className="bg-stone-400 hover:bg-stone-500 rounded-full z-10 relative outline-none">
<Plus size={18} className="text-white" />
</div>
</Dropdown>
</div>
);
};

View File

@ -2,7 +2,7 @@ import { useWorkflowStore } from "@/stores/workflow";
import AddNode from "./AddNode";
import { NodeProps } from "./types";
import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Dropdown } from "antd";
import { Ellipsis, Trash2 } from "lucide-react";
const ConditionNode = ({ data, branchId, branchIndex }: NodeProps) => {
@ -13,21 +13,26 @@ const ConditionNode = ({ data, branchId, branchIndex }: NodeProps) => {
return (
<>
<div className="rounded-md shadow-md w-[261px] mt-10 relative z-10">
<DropdownMenu>
<DropdownMenuTrigger className="absolute right-2 top-1">
<Dropdown
menu={{
items: [
{
key: "delete",
label: "删除分支",
icon: <Trash2 size={16} />,
danger: true,
onClick: () => {
removeBranch(branchId ?? "", branchIndex ?? 0);
},
},
],
}}
trigger={["click"]}
>
<div className="absolute right-2 top-1 cursor-pointer">
<Ellipsis size={17} className="text-stone-600" />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
className="flex space-x-2 text-red-600"
onClick={() => {
removeBranch(branchId ?? "", branchIndex ?? 0);
}}
>
<Trash2 size={16} /> <div></div>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</Dropdown>
<div className="w-[261px] flex flex-col justify-center text-foreground rounded-md bg-white px-5 py-5">
<div contentEditable suppressContentEditableWarning onBlur={handleNameBlur} className="text-center outline-slate-200 dark:text-stone-600">

View File

@ -14,7 +14,7 @@ import { useEffect, useState } from "react";
import i18n from "@/i18n";
import { WorkflowNode } from "@/domain/workflow";
import { Textarea } from "../ui/textarea";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Dropdown } from "antd";
import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
@ -432,22 +432,30 @@ Remove-Item -Path "$pfxPath" -Force
<FormItem>
<FormLabel className="flex justify-between items-center">
<div>{t("domain.deployment.form.shell_command.label")}</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<a className="text-xs text-blue-500 cursor-pointer">{t("domain.deployment.form.shell_preset_scripts.trigger")}</a>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => handleUsePresetScript("reload_nginx")}>
{t("domain.deployment.form.shell_preset_scripts.option.reload_nginx.label")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleUsePresetScript("binding_iis")}>
{t("domain.deployment.form.shell_preset_scripts.option.binding_iis.label")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleUsePresetScript("binding_netsh")}>
{t("domain.deployment.form.shell_preset_scripts.option.binding_netsh.label")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<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)} />

View File

@ -13,7 +13,7 @@ const DropdownMenuItemIcon = ({ type, name }: WorkflowNodeDropdwonItemIcon) => {
if (type === WorkflowNodeDropdwonItemIconType.Icon) {
return icons.get(name);
} else {
return <img src={name} className="w-4" />;
return <img src={name} className="inline-block size-4" />;
}
};

View File

@ -2,7 +2,7 @@ import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
import AddNode from "./AddNode";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Dropdown } from "antd";
import { Ellipsis, Trash2 } from "lucide-react";
import { usePanel } from "./PanelProvider";
import PanelBody from "./PanelBody";
@ -84,21 +84,26 @@ const Node = ({ data }: NodeProps) => {
<div className="rounded-md shadow-md w-[260px] relative">
{data.type != WorkflowNodeType.Start && (
<>
<DropdownMenu>
<DropdownMenuTrigger className="absolute right-2 top-1">
<Dropdown
menu={{
items: [
{
key: "delete",
label: t(`${i18nPrefix}.delete.label`),
icon: <Trash2 size={16} />,
danger: true,
onClick: () => {
removeNode(data.id);
},
},
],
}}
trigger={["click"]}
>
<div className="absolute right-2 top-1 cursor-pointer">
<Ellipsis className="text-white" size={17} />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
className="flex space-x-2 text-red-600"
onClick={() => {
removeNode(data.id);
}}
>
<Trash2 size={16} /> <div>{t(`${i18nPrefix}.delete.label`)}</div>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</Dropdown>
</>
)}

View File

@ -1,356 +0,0 @@
import { memo, useEffect } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Collapse, Divider, Switch, Tooltip, Typography } from "antd";
import z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { ChevronsUpDown as ChevronsUpDownIcon, Plus as PlusIcon, CircleHelp as CircleHelpIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import AccessEditModal from "@/components/access/AccessEditModal";
import EmailsEdit from "@/components/certimate/EmailsEdit";
import StringList from "@/components/certimate/StringList";
import { accessProvidersMap } from "@/domain/access";
import { useZustandShallowSelector } from "@/hooks";
import { useAccessStore } from "@/stores/access";
import { useContactStore } from "@/stores/contact";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore } from "@/stores/workflow";
import { usePanel } from "../PanelProvider";
type ApplyFormProps = {
data: WorkflowNode;
};
const ApplyForm = ({ data }: ApplyFormProps) => {
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { accesses } = useAccessStore();
const { emails, fetchEmails } = useContactStore();
useEffect(() => {
fetchEmails();
}, []);
const { t } = useTranslation();
const { hidePanel } = usePanel();
const formSchema = z.object({
domain: z.string().min(1, {
message: "common.errmsg.domain_invalid",
}),
email: z.string().email("common.errmsg.email_invalid").optional(),
access: z.string().regex(/^[a-zA-Z0-9]+$/, {
message: "domain.application.form.access.placeholder",
}),
keyAlgorithm: z.string().optional(),
nameservers: z.string().optional(),
timeout: z.number().optional(),
disableFollowCNAME: z.boolean().optional(),
});
let config: WorkflowNodeConfig = {
domain: "",
email: "",
access: "",
keyAlgorithm: "RSA2048",
nameservers: "",
timeout: 60,
disableFollowCNAME: true,
};
if (data) config = data.config ?? config;
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
domain: config.domain as string,
email: config.email as string,
access: config.access as string,
keyAlgorithm: config.keyAlgorithm as string,
nameservers: config.nameservers as string,
timeout: config.timeout as number,
disableFollowCNAME: config.disableFollowCNAME as boolean,
},
});
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 dark:text-stone-200">
{/* 域名 */}
<FormField
control={form.control}
name="domain"
render={({ field }) => (
<FormItem>
<>
<StringList
value={field.value}
valueType="domain"
onValueChange={(domain: string) => {
form.setValue("domain", domain);
}}
/>
</>
<FormMessage />
</FormItem>
)}
/>
{/* 邮箱 */}
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel className="flex justify-between w-full">
<div>{t("domain.application.form.email.label") + " " + t("domain.application.form.email.tips")}</div>
<EmailsEdit
trigger={
<div className="flex items-center font-normal cursor-pointer text-primary hover:underline">
<PlusIcon size={14} />
{t("common.button.add")}
</div>
}
/>
</FormLabel>
<FormControl>
<Select
{...field}
value={field.value}
onValueChange={(value) => {
form.setValue("email", value);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.application.form.email.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>{t("domain.application.form.email.list")}</SelectLabel>
{emails.map((item) => (
<SelectItem key={item} value={item}>
<div>{item}</div>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* DNS 服务商授权 */}
<FormField
control={form.control}
name="access"
render={({ field }) => (
<FormItem>
<FormLabel className="flex justify-between w-full">
<div>{t("domain.application.form.access.label")}</div>
<AccessEditModal
preset="add"
trigger={
<div className="flex items-center font-normal cursor-pointer text-primary hover:underline">
<PlusIcon size={14} />
{t("common.button.add")}
</div>
}
/>
</FormLabel>
<FormControl>
<Select
{...field}
value={field.value}
onValueChange={(value) => {
form.setValue("access", value);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.application.form.access.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>{t("domain.application.form.access.list")}</SelectLabel>
{accesses
.filter((item) => item.usage != "deploy")
.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>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Divider />
<Collapse
bordered={false}
ghost={true}
items={[
{
key: "advanced",
styles: {
header: { paddingLeft: 0, paddingRight: 0 },
body: { paddingLeft: 0, paddingRight: 0 },
},
label: <Typography.Text type="secondary">{t("domain.application.form.advanced_settings.label")}</Typography.Text>,
children: (
<div className="flex flex-col space-y-8">
{/* 证书算法 */}
<FormField
control={form.control}
name="keyAlgorithm"
render={({ field }) => (
<FormItem>
<FormLabel>{t("domain.application.form.key_algorithm.label")}</FormLabel>
<Select
{...field}
value={field.value}
onValueChange={(value) => {
form.setValue("keyAlgorithm", value);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.application.form.key_algorithm.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="RSA2048">RSA2048</SelectItem>
<SelectItem value="RSA3072">RSA3072</SelectItem>
<SelectItem value="RSA4096">RSA4096</SelectItem>
<SelectItem value="RSA8192">RSA8192</SelectItem>
<SelectItem value="EC256">EC256</SelectItem>
<SelectItem value="EC384">EC384</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormItem>
)}
/>
{/* DNS */}
<FormField
control={form.control}
name="nameservers"
render={({ field }) => (
<FormItem>
<StringList
value={field.value ?? ""}
onValueChange={(val: string) => {
form.setValue("nameservers", val);
}}
valueType="dns"
></StringList>
<FormMessage />
</FormItem>
)}
/>
{/* DNS 超时时间 */}
<FormField
control={form.control}
name="timeout"
render={({ field }) => (
<FormItem>
<FormLabel>{t("domain.application.form.timeout.label")}</FormLabel>
<FormControl>
<Input
type="number"
placeholder={t("domain.application.form.timeout.placeholder")}
{...field}
value={field.value}
onChange={(e) => {
form.setValue("timeout", parseInt(e.target.value));
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* 禁用 CNAME 跟随 */}
<FormField
control={form.control}
name="disableFollowCNAME"
render={({ field }) => (
<FormItem>
<FormLabel>
<div className="flex">
<span className="mr-1">{t("domain.application.form.disable_follow_cname.label")} </span>
<Tooltip
title={
<p>
{t("domain.application.form.disable_follow_cname.tips")}
<a
className="text-primary"
target="_blank"
href="https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme/#the-advantages-of-a-cname"
>
{t("domain.application.form.disable_follow_cname.tips_link")}
</a>
</p>
}
>
<CircleHelpIcon size={14} />
</Tooltip>
</div>
</FormLabel>
<FormControl>
<div>
<Switch
defaultChecked={field.value}
onChange={(value) => {
form.setValue(field.name, value);
}}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
),
extra: <ChevronsUpDownIcon size={14} />,
forceRender: true,
showArrow: false,
},
]}
/>
<div className="flex justify-end">
<Button type="submit">{t("common.button.save")}</Button>
</div>
</form>
</Form>
</>
);
};
export default memo(ApplyForm);

View File

@ -14,9 +14,6 @@ i18n
interpolation: {
escapeValue: false,
},
backend: {
loadPath: "/locales/{{lng}}.json",
},
detection: {
lookupLocalStorage: "certimate-ui-lang",
},

View File

@ -143,6 +143,7 @@ const WorkflowDetail = () => {
},
],
}}
trigger={["click"]}
>
<Button icon={<EllipsisIcon size={14} />} />
</Dropdown>