mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
Merge pull request #891 from fudiwei/dev
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -49,12 +48,11 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
return
|
||||
}
|
||||
|
||||
var settingsContent *domain.SettingsContentAsPersistence
|
||||
json.Unmarshal([]byte(settings.Content), &settingsContent)
|
||||
if settingsContent != nil && settingsContent.ExpiredCertificatesMaxDaysRetention != 0 {
|
||||
persistenceSettings, _ := settings.UnmarshalContentAsPersistence()
|
||||
if persistenceSettings != nil && persistenceSettings.ExpiredCertificatesMaxDaysRetention != 0 {
|
||||
ret, err := s.certificateRepo.DeleteWhere(
|
||||
context.Background(),
|
||||
dbx.NewExp(fmt.Sprintf("validityNotAfter<DATETIME('now', '-%d days')", settingsContent.ExpiredCertificatesMaxDaysRetention)),
|
||||
dbx.NewExp(fmt.Sprintf("validityNotAfter<DATETIME('now', '-%d days')", persistenceSettings.ExpiredCertificatesMaxDaysRetention)),
|
||||
)
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to delete expired certificates", "err", err)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package domain
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
const CollectionNameSettings = "settings"
|
||||
|
||||
type Settings struct {
|
||||
@@ -12,3 +14,11 @@ type SettingsContentAsPersistence struct {
|
||||
WorkflowRunsMaxDaysRetention int `json:"workflowRunsMaxDaysRetention"`
|
||||
ExpiredCertificatesMaxDaysRetention int `json:"expiredCertificatesMaxDaysRetention"`
|
||||
}
|
||||
|
||||
func (s *Settings) UnmarshalContentAsPersistence() (*SettingsContentAsPersistence, error) {
|
||||
var content *SettingsContentAsPersistence
|
||||
if err := json.Unmarshal([]byte(s.Content), &content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package workflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -59,14 +58,13 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
|
||||
return
|
||||
}
|
||||
|
||||
var settingsContent *domain.SettingsContentAsPersistence
|
||||
json.Unmarshal([]byte(settings.Content), &settingsContent)
|
||||
if settingsContent != nil && settingsContent.WorkflowRunsMaxDaysRetention != 0 {
|
||||
persistenceSettings, _ := settings.UnmarshalContentAsPersistence()
|
||||
if persistenceSettings != nil && persistenceSettings.WorkflowRunsMaxDaysRetention != 0 {
|
||||
ret, err := s.workflowRunRepo.DeleteWhere(
|
||||
context.Background(),
|
||||
dbx.NewExp(fmt.Sprintf("status!='%s'", string(domain.WorkflowRunStatusTypePending))),
|
||||
dbx.NewExp(fmt.Sprintf("status!='%s'", string(domain.WorkflowRunStatusTypeRunning))),
|
||||
dbx.NewExp(fmt.Sprintf("endedAt<DATETIME('now', '-%d days')", settingsContent.WorkflowRunsMaxDaysRetention)),
|
||||
dbx.NewExp(fmt.Sprintf("endedAt<DATETIME('now', '-%d days')", persistenceSettings.WorkflowRunsMaxDaysRetention)),
|
||||
)
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to delete workflow history runs", "err", err)
|
||||
|
||||
Vendored
Generated
+1577
-228
File diff suppressed because it is too large
Load Diff
+19
-16
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "ui",
|
||||
"name": "@certimate/webui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
@@ -10,17 +9,21 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.0.0",
|
||||
"@ant-design/pro-components": "^2.8.10",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
"@codemirror/lang-yaml": "^6.1.2",
|
||||
"@codemirror/language": "^6.11.2",
|
||||
"@codemirror/legacy-modes": "^6.5.1",
|
||||
"@flowgram.ai/document": "^0.3.4",
|
||||
"@flowgram.ai/fixed-layout-editor": "^0.3.4",
|
||||
"@flowgram.ai/minimap-plugin": "^0.3.4",
|
||||
"@tabler/icons-react": "^3.34.1",
|
||||
"@uiw/codemirror-extensions-basic-setup": "^4.24.1",
|
||||
"@uiw/codemirror-theme-vscode": "^4.24.1",
|
||||
"@uiw/react-codemirror": "^4.24.1",
|
||||
"@uiw/codemirror-extensions-basic-setup": "^4.24.2",
|
||||
"@uiw/codemirror-theme-vscode": "^4.24.2",
|
||||
"@uiw/react-codemirror": "^4.24.2",
|
||||
"ahooks": "^3.9.0",
|
||||
"antd": "^5.26.6",
|
||||
"antd": "^5.26.7",
|
||||
"antd-zod": "^7.0.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cron-parser": "^5.3.0",
|
||||
@@ -29,19 +32,19 @@
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"immer": "^10.1.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"pocketbase": "^0.26.1",
|
||||
"pocketbase": "^0.26.2",
|
||||
"radash": "^12.1.1",
|
||||
"react": "^18.3.1",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^15.6.1",
|
||||
"react-router-dom": "^7.7.0",
|
||||
"react-router-dom": "^7.8.0",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zod": "^4.0.5",
|
||||
"zustand": "^5.0.6"
|
||||
"zod": "^4.0.16",
|
||||
"zustand": "^5.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.31.0",
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
@@ -52,19 +55,19 @@
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@vitejs/plugin-legacy": "^6.1.1",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"eslint": "^9.31.0",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-better-tailwindcss": "^3.7.1",
|
||||
"eslint-plugin-better-tailwindcss": "^3.7.4",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-prettier": "^5.5.3",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"fs-extra": "^11.3.0",
|
||||
"fs-extra": "^11.3.1",
|
||||
"prettier": "^3.6.2",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"typescript-eslint": "^8.39.0",
|
||||
"vite": "^6.3.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@ const RootApp = () => {
|
||||
...antdTheme?.components?.Dropdown,
|
||||
paddingBlock: 9,
|
||||
},
|
||||
Form: {
|
||||
...antdTheme?.components?.Form,
|
||||
itemMarginBottom: 28,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -31,8 +31,10 @@ const AppVersionBadge = ({ className, style, children }: AppVersionBadgeProps) =
|
||||
<Badge
|
||||
className={className}
|
||||
style={style}
|
||||
styles={{ indicator: { transform: "scale(0.75) translate(50%, -50%)" } }}
|
||||
count={hasNewVersion ? "NEW" : undefined}
|
||||
styles={{
|
||||
indicator: { transform: "scale(0.75) translate(50%, -50%)" },
|
||||
}}
|
||||
count={hasNewVersion ? "NEW" : void 0}
|
||||
>
|
||||
{children}
|
||||
</Badge>
|
||||
|
||||
@@ -72,7 +72,7 @@ const CodeInput = ({ className, style, disabled, language, ...props }: CodeInput
|
||||
border: `1px solid ${isFocusWithin ? (themeToken.Input?.activeBorderColor ?? themeToken.colorPrimaryBorder) : themeToken.colorBorder}`,
|
||||
borderRadius: `${themeToken.borderRadius}px`,
|
||||
backgroundColor: disabled ? themeToken.colorBgContainerDisabled : themeToken.colorBgContainer,
|
||||
boxShadow: isFocusWithin ? themeToken.Input?.activeShadow : undefined,
|
||||
boxShadow: isFocusWithin ? themeToken.Input?.activeShadow : void 0,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Button, Drawer, type DrawerProps, Flex, Form, type FormProps, type ModalProps } from "antd";
|
||||
|
||||
@@ -66,13 +67,14 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
|
||||
});
|
||||
|
||||
const mergedFormProps: FormProps = {
|
||||
clearOnDestroy: drawerProps?.destroyOnHidden ? true : undefined,
|
||||
clearOnDestroy: drawerProps?.destroyOnHidden ? true : void 0,
|
||||
...formProps,
|
||||
...props,
|
||||
};
|
||||
|
||||
const mergedDrawerProps: DrawerProps = {
|
||||
...drawerProps,
|
||||
closeIcon: false,
|
||||
afterOpenChange: (open) => {
|
||||
if (!open && !mergedFormProps.preserve) {
|
||||
formInst.resetFields();
|
||||
@@ -109,7 +111,7 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
|
||||
<Drawer
|
||||
{...mergedDrawerProps}
|
||||
footer={
|
||||
<Flex justify="end" gap="small">
|
||||
<Flex className="px-2" justify="end" gap="small">
|
||||
<Button {...cancelButtonProps} onClick={handleCancelClick}>
|
||||
{cancelText ?? t("common.button.cancel")}
|
||||
</Button>
|
||||
@@ -120,7 +122,21 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
|
||||
}
|
||||
forceRender
|
||||
open={open}
|
||||
title={title}
|
||||
title={
|
||||
<Flex align="center" justify="space-between" gap="small">
|
||||
<div className="flex-1 truncate">{title}</div>
|
||||
{mergedDrawerProps.closeIcon !== false && (
|
||||
<Button
|
||||
className="ant-drawer-close"
|
||||
style={{ marginInline: 0 }}
|
||||
icon={mergedDrawerProps.closeIcon ?? <IconX size="1.25em" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={handleCancelClick}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
width={width}
|
||||
>
|
||||
<Form className={className} style={style} {...mergedFormProps} form={formInst}>
|
||||
|
||||
@@ -75,7 +75,7 @@ const ModalForm = <T extends NonNullable<unknown> = any>({
|
||||
});
|
||||
|
||||
const mergedFormProps: FormProps = {
|
||||
clearOnDestroy: modalProps?.destroyOnHidden ? true : undefined,
|
||||
clearOnDestroy: modalProps?.destroyOnHidden ? true : void 0,
|
||||
...formProps,
|
||||
...props,
|
||||
};
|
||||
|
||||
@@ -142,7 +142,7 @@ const MultipleInput = ({
|
||||
allowRemove={allowRemove}
|
||||
allowUp={allowUp}
|
||||
disabled={disabled}
|
||||
defaultValue={undefined}
|
||||
defaultValue={void 0}
|
||||
showSortButton={showSortButton}
|
||||
value={element}
|
||||
onBlur={() => handleInputBlur(index)}
|
||||
@@ -245,10 +245,10 @@ const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputIte
|
||||
<Input
|
||||
{...props}
|
||||
ref={inputRef}
|
||||
className={undefined}
|
||||
style={undefined}
|
||||
className={void 0}
|
||||
style={void 0}
|
||||
allowClear={allowClear}
|
||||
defaultValue={undefined}
|
||||
defaultValue={void 0}
|
||||
value={value}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { IconList } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Button, Form, Input, type InputProps, Space } from "antd";
|
||||
import { nanoid } from "nanoid";
|
||||
import { nanoid } from "nanoid/non-secure";
|
||||
|
||||
import { useAntdForm } from "@/hooks";
|
||||
import ModalForm from "./ModalForm";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IconFileImport } from "@tabler/icons-react";
|
||||
import { Button, type ButtonProps, Input, type UploadProps } from "antd";
|
||||
import { type TextAreaProps } from "antd/es/input/TextArea";
|
||||
|
||||
import { readFileContent } from "@/utils/file";
|
||||
import { readFileAsText } from "@/utils/file";
|
||||
|
||||
export interface TextFileInputProps extends Omit<TextAreaProps, "onChange"> {
|
||||
accept?: UploadProps["accept"];
|
||||
@@ -27,7 +27,7 @@ const TextFileInput = ({ className, style, accept, disabled, readOnly, uploadTex
|
||||
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { files } = e.target as HTMLInputElement;
|
||||
if (files?.length) {
|
||||
const value = await readFileContent(files[0]);
|
||||
const value = await readFileAsText(files[0]);
|
||||
onChange?.(value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IconBulb } from "@tabler/icons-react";
|
||||
import { Alert, Flex, Typography, theme } from "antd";
|
||||
|
||||
export interface TipsProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
message: React.ReactNode;
|
||||
}
|
||||
|
||||
const Tips = ({ className, style, message }: TipsProps) => {
|
||||
const { token: themeToken } = theme.useToken();
|
||||
|
||||
return (
|
||||
<Alert
|
||||
className={className}
|
||||
style={style}
|
||||
message={
|
||||
<Flex gap="small">
|
||||
<div>
|
||||
<IconBulb size="1.5em" color={themeToken.colorInfo} />
|
||||
</div>
|
||||
<Typography.Text>{message}</Typography.Text>
|
||||
</Flex>
|
||||
}
|
||||
type="info"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tips;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { App, Button, Drawer, Flex } from "antd";
|
||||
|
||||
@@ -99,11 +100,11 @@ const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ..
|
||||
|
||||
<Drawer
|
||||
afterOpenChange={setOpen}
|
||||
closable={!formPending}
|
||||
closeIcon={false}
|
||||
destroyOnHidden
|
||||
footer={
|
||||
footerShow ? (
|
||||
<Flex justify="end" gap="small">
|
||||
<Flex className="px-2" justify="end" gap="small">
|
||||
<Button onClick={handleCancelClick}>{t("common.button.cancel")}</Button>
|
||||
<Button loading={formPending} type="primary" onClick={handleOkClick}>
|
||||
{mode === "edit" ? t("common.button.save") : t("common.button.submit")}
|
||||
@@ -116,9 +117,23 @@ const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ..
|
||||
loading={loading}
|
||||
maskClosable={!formPending}
|
||||
open={open}
|
||||
title={t(`access.action.${mode}.modal.title`)}
|
||||
width={720}
|
||||
onClose={() => setOpen(false)}
|
||||
size="large"
|
||||
title={
|
||||
<Flex align="center" justify="space-between" gap="small">
|
||||
<div className="flex-1 truncate">
|
||||
{mode === "edit" && !!data ? t("access.action.edit.modal.title") + ` #${data.id}` : t(`access.action.${mode}.modal.title`)}
|
||||
</div>
|
||||
<Button
|
||||
className="ant-drawer-close"
|
||||
style={{ marginInline: 0 }}
|
||||
icon={<IconX size="1.25em" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={handleCancelClick}
|
||||
/>
|
||||
</Flex>
|
||||
}
|
||||
onClose={handleCancelClick}
|
||||
>
|
||||
<AccessForm ref={formRef} disabled={formPending} initialValues={data} mode={mode} usage={usage} onValuesChange={handleFormValuesChange} />
|
||||
</Drawer>
|
||||
@@ -134,7 +149,7 @@ const useProps = () => {
|
||||
setOpen(open);
|
||||
|
||||
if (!open) {
|
||||
setData(undefined);
|
||||
setData(void 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -138,16 +138,12 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
default:
|
||||
console.warn(`[certimate] unsupported provider usage: '${usage}'`);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}, [usage]);
|
||||
const providerTooltip = useMemo(() => {
|
||||
switch (usage) {
|
||||
case "dns-hosting":
|
||||
return <span dangerouslySetInnerHTML={{ __html: t("access.form.provider.tooltip") }}></span>;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}, [usage]);
|
||||
|
||||
const fieldProvider = Form.useWatch<z.infer<typeof formSchema>["provider"]>("provider", formInst);
|
||||
@@ -344,7 +340,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
getFieldsValue: () => {
|
||||
const values = formInst.getFieldsValue(true);
|
||||
values.config = nestedFormInst.getFieldsValue();
|
||||
values.reserve = usage === "ca" ? "ca" : usage === "notification" ? "notification" : undefined;
|
||||
values.reserve = usage === "ca" ? "ca" : usage === "notification" ? "notification" : void 0;
|
||||
return values;
|
||||
},
|
||||
resetFields: (fields) => {
|
||||
@@ -356,7 +352,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
},
|
||||
validateFields: (nameList, config) => {
|
||||
const t1 = formInst.validateFields(nameList, config);
|
||||
const t2 = nestedFormInst.validateFields(undefined, config);
|
||||
const t2 = nestedFormInst.validateFields(void 0, config);
|
||||
return Promise.all([t1, t2]).then(() => t1);
|
||||
},
|
||||
} as AccessFormInstance;
|
||||
|
||||
@@ -26,7 +26,7 @@ const AccessFormDiscordBotConfig = ({ form: formInst, formName, disabled, initia
|
||||
|
||||
const formSchema = z.object({
|
||||
botToken: z
|
||||
.string(t("access.form.discordbot_token.placeholder"))
|
||||
.string()
|
||||
.min(1, t("access.form.discordbot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
channelId: z.string().nullish(),
|
||||
|
||||
@@ -26,7 +26,7 @@ const AccessFormSlackBotConfig = ({ form: formInst, formName, disabled, initialV
|
||||
|
||||
const formSchema = z.object({
|
||||
botToken: z
|
||||
.string(t("access.form.slackbot_token.placeholder"))
|
||||
.string()
|
||||
.min(1, t("access.form.slackbot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
channelId: z.string().nullish(),
|
||||
|
||||
@@ -26,12 +26,12 @@ const AccessFormTelegramBotConfig = ({ form: formInst, formName, disabled, initi
|
||||
|
||||
const formSchema = z.object({
|
||||
botToken: z
|
||||
.string(t("access.form.telegrambot_token.placeholder"))
|
||||
.string()
|
||||
.min(1, t("access.form.telegrambot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
chatId: z
|
||||
.preprocess(
|
||||
(v) => (v == null || v === "" ? undefined : Number(v)),
|
||||
(v) => (v == null || v === "" ? void 0 : Number(v)),
|
||||
z.number().refine((v) => {
|
||||
return !Number.isNaN(+v!) && +v! !== 0;
|
||||
}, t("access.form.telegrambot_chat_id.placeholder"))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconChevronDown } from "@tabler/icons-react";
|
||||
import { Alert, Button, Dropdown, Form, type FormInstance, Input, Select, Switch } from "antd";
|
||||
import { Button, Dropdown, Form, type FormInstance, Input, Select, Switch } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import CodeInput from "@/components/CodeInput";
|
||||
import Show from "@/components/Show";
|
||||
import Tips from "@/components/Tips";
|
||||
import { type AccessConfigForWebhook } from "@/domain/access";
|
||||
|
||||
type AccessFormWebhookConfigFieldValues = Nullish<AccessConfigForWebhook>;
|
||||
@@ -330,7 +331,7 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Alert type="info" message={<span dangerouslySetInnerHTML={{ __html: t("access.form.webhook_data_for_deployment.guide") }}></span>} />
|
||||
<Tips message={<span dangerouslySetInnerHTML={{ __html: t("access.form.webhook_data_for_deployment.guide") }}></span>} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
@@ -373,7 +374,7 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Alert type="info" message={<span dangerouslySetInnerHTML={{ __html: t("access.form.webhook_data_for_notification.guide") }}></span>} />
|
||||
<Tips message={<span dangerouslySetInnerHTML={{ __html: t("access.form.webhook_data_for_notification.guide") }}></span>} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ const AccessSelect = ({ onFilter, ...props }: AccessTypeSelectProps) => {
|
||||
loading={!loadedAtOnce}
|
||||
options={options}
|
||||
optionFilterProp="label"
|
||||
optionLabelProp={undefined}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Drawer } from "antd";
|
||||
import { Button, Drawer, Flex } from "antd";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { type CertificateModel } from "@/domain/certificate";
|
||||
@@ -30,12 +31,25 @@ const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: Certifica
|
||||
|
||||
<Drawer
|
||||
afterOpenChange={setOpen}
|
||||
closeIcon={false}
|
||||
destroyOnHidden
|
||||
open={open}
|
||||
loading={loading}
|
||||
placement="right"
|
||||
title={`Certificate #${data?.id}`}
|
||||
width={720}
|
||||
size="large"
|
||||
title={
|
||||
<Flex align="center" justify="space-between" gap="small">
|
||||
<div className="flex-1 truncate">{data ? `Certificate #${data.id}` : "Certificate"}</div>
|
||||
<Button
|
||||
className="ant-drawer-close"
|
||||
style={{ marginInline: 0 }}
|
||||
icon={<IconX size="1.25em" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => setOpen(false)}
|
||||
/>
|
||||
</Flex>
|
||||
}
|
||||
onClose={() => setOpen(false)}
|
||||
>
|
||||
<Show when={!!data}>
|
||||
@@ -54,7 +68,7 @@ const useProps = () => {
|
||||
setOpen(open);
|
||||
|
||||
if (!open) {
|
||||
setData(undefined);
|
||||
setData(void 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ const ACMEDns01ProviderSelect = ({ onFilter, ...props }: ACMEDns01ProviderSelect
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{props.placeholder}</span>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionFilterProp={void 0}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -114,7 +114,7 @@ const AccessProviderPicker = ({ className, style, autoFocus, placeholder, showOp
|
||||
<Avatar className="bg-stone-100" icon={<img src={provider.icon} />} shape="square" size={28} />
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<div className={mergeCls("max-w-full", showOptionTagAnyhow ? "mb-1 truncate" : "line-clamp-2")}>
|
||||
<Typography.Text type={provider.builtin ? "secondary" : undefined}>{t(provider.name) || "\u00A0"}</Typography.Text>
|
||||
<Typography.Text type={provider.builtin ? "secondary" : void 0}>{t(provider.name) || "\u00A0"}</Typography.Text>
|
||||
</div>
|
||||
<Show when={showOptionTagAnyhow}>
|
||||
<div className="origin-left scale-80 whitespace-nowrap">
|
||||
|
||||
@@ -53,7 +53,7 @@ const AccessProviderSelect = ({ showOptionTags, onFilter, ...props }: AccessProv
|
||||
<div className="flex max-w-full items-center justify-between gap-4 overflow-hidden">
|
||||
<div className="flex items-center gap-2 truncate overflow-hidden">
|
||||
<Avatar shape="square" src={provider.icon} size="small" />
|
||||
<Typography.Text className="flex-1 truncate overflow-hidden" type={provider.builtin ? "secondary" : undefined} ellipsis>
|
||||
<Typography.Text className="flex-1 truncate overflow-hidden" type={provider.builtin ? "secondary" : void 0} ellipsis>
|
||||
{t(provider.name)}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
@@ -95,8 +95,8 @@ const AccessProviderSelect = ({ showOptionTags, onFilter, ...props }: AccessProv
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{props.placeholder}</span>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionFilterProp={void 0}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -77,8 +77,8 @@ const CAProviderSelect = ({ onFilter, ...props }: CAProviderSelectProps) => {
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{props.placeholder}</span>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionFilterProp={void 0}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -58,8 +58,8 @@ const DeploymentProviderSelect = ({ onFilter, ...props }: DeploymentProviderSele
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{props.placeholder}</span>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionFilterProp={void 0}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -58,8 +58,8 @@ const NotificationProviderSelect = ({ onFilter, ...props }: NotificationProvider
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{props.placeholder}</span>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionFilterProp={void 0}
|
||||
optionLabelProp={void 0}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -22,6 +22,10 @@ export interface WorkflowElementProps {
|
||||
branchIndex?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const WorkflowElement = ({ node, disabled, branchId, branchIndex }: WorkflowElementProps) => {
|
||||
const nodeEl = useMemo(() => {
|
||||
switch (node.type) {
|
||||
|
||||
@@ -11,6 +11,10 @@ export interface WorkflowElementsProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const WorkflowElements = ({ className, style, disabled }: WorkflowElementsProps) => {
|
||||
const { workflow } = useWorkflowStore(useZustandShallowSelector(["workflow"]));
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ export interface WorkflowElementsProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const WorkflowElementsContainer = ({ className, style, disabled }: WorkflowElementsProps) => {
|
||||
const [scale, setScale] = useState(1);
|
||||
|
||||
@@ -30,15 +34,19 @@ const WorkflowElementsContainer = ({ className, style, disabled }: WorkflowEleme
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute right-6 bottom-4 z-2">
|
||||
<Card className="rounded-lg p-2 shadow-lg" styles={{ body: { padding: 0 } }}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button icon={<IconMinus size="1.25em" />} disabled={scale <= MIN_SCALE} onClick={() => setScale((s) => Math.max(MIN_SCALE, s - STEP_SCALE))} />
|
||||
<Typography.Text className="min-w-12 text-center">{Math.round(scale * 100)}%</Typography.Text>
|
||||
<Button icon={<IconPlus size="1.25em" />} disabled={scale >= MAX_SCALE} onClick={() => setScale((s) => Math.min(MAX_SCALE, s + STEP_SCALE))} />
|
||||
<Button icon={<IconMaximize size="1.25em" />} onClick={() => setScale(1)} />
|
||||
<div className="absolute bottom-4 z-2 w-full px-4">
|
||||
<div className="container">
|
||||
<div className="flex justify-end">
|
||||
<Card className="rounded-lg p-2 shadow-lg" styles={{ body: { padding: 0 } }}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button icon={<IconMinus size="1.25em" />} disabled={scale <= MIN_SCALE} onClick={() => setScale((s) => Math.max(MIN_SCALE, s - STEP_SCALE))} />
|
||||
<Typography.Text className="min-w-12 text-center">{Math.round(scale * 100)}%</Typography.Text>
|
||||
<Button icon={<IconPlus size="1.25em" />} disabled={scale >= MAX_SCALE} onClick={() => setScale((s) => Math.min(MAX_SCALE, s + STEP_SCALE))} />
|
||||
<Button icon={<IconMaximize size="1.25em" />} onClick={() => setScale(1)} />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Drawer } from "antd";
|
||||
import { Button, Drawer, Flex } from "antd";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { type WorkflowRunModel } from "@/domain/workflowRun";
|
||||
@@ -31,12 +32,25 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
|
||||
|
||||
<Drawer
|
||||
afterOpenChange={setOpen}
|
||||
closeIcon={false}
|
||||
destroyOnHidden
|
||||
open={open}
|
||||
loading={loading}
|
||||
placement="right"
|
||||
title={`WorkflowRun #${data?.id}`}
|
||||
width={720}
|
||||
size="large"
|
||||
title={
|
||||
<Flex align="center" justify="space-between" gap="small">
|
||||
<div className="flex-1 truncate">{data ? `Workflow Run #${data.id}` : "Workflow Run"}</div>
|
||||
<Button
|
||||
className="ant-drawer-close"
|
||||
style={{ marginInline: 0 }}
|
||||
icon={<IconX size="1.25em" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => setOpen(false)}
|
||||
/>
|
||||
</Flex>
|
||||
}
|
||||
onClose={() => setOpen(false)}
|
||||
>
|
||||
<Show when={!!data}>
|
||||
|
||||
@@ -43,7 +43,7 @@ const WorkflowStatusTag = ({ className, style, status }: WorkflowStatusTagProps)
|
||||
);
|
||||
case WORKFLOW_RUN_STATUSES.CANCELED:
|
||||
return (
|
||||
<Tag className={className} style={style} color="var(--color-danger)" icon={Icon}>
|
||||
<Tag className={className} style={style} color="var(--color-warning)" icon={Icon}>
|
||||
{t("workflow_run.props.status.canceled")}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
|
||||
import {
|
||||
ConstantKeys,
|
||||
EditorRenderer,
|
||||
FixedLayoutEditorProvider,
|
||||
type FixedLayoutPluginContext,
|
||||
type FixedLayoutProps,
|
||||
type FlowDocumentJSON,
|
||||
type FlowNodeEntity,
|
||||
FlowTextKey,
|
||||
getNodeForm,
|
||||
} from "@flowgram.ai/fixed-layout-editor";
|
||||
import { createMinimapPlugin } from "@flowgram.ai/minimap-plugin";
|
||||
import "@flowgram.ai/fixed-layout-editor/index.css";
|
||||
import { theme } from "antd";
|
||||
|
||||
import { getFlowComponents } from "./components";
|
||||
import { EditorContextProvider } from "./EditorContext";
|
||||
import NodeRender from "./NodeRender";
|
||||
import { getFlowNodeRegistries } from "./nodes";
|
||||
import { BranchNode } from "./nodes/_shared";
|
||||
import "./flowgram.css";
|
||||
|
||||
export interface EditorProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
initialData?: FlowDocumentJSON;
|
||||
readonly?: boolean;
|
||||
onNodeClick?: (ctx: FixedLayoutPluginContext, node: FlowNodeEntity) => void;
|
||||
}
|
||||
|
||||
export interface EditorInstance extends FixedLayoutPluginContext {
|
||||
validateNode(node: string | FlowNodeEntity): Promise<boolean>;
|
||||
validateAllNodes(): Promise<boolean>;
|
||||
}
|
||||
|
||||
const Editor = forwardRef<EditorInstance, EditorProps>(({ className, style, children, initialData, readonly, onNodeClick }, ref) => {
|
||||
const { token: themeToken } = theme.useToken();
|
||||
|
||||
const flowgramEditorRef = useRef<FixedLayoutPluginContext>(null);
|
||||
const flowgramEditorProps = useMemo<FixedLayoutProps>(
|
||||
() => ({
|
||||
initialData: initialData,
|
||||
|
||||
constants: {
|
||||
[ConstantKeys.BASE_COLOR]: themeToken.colorBorder,
|
||||
[ConstantKeys.BASE_ACTIVATED_COLOR]: themeToken.colorPrimary,
|
||||
[ConstantKeys.NODE_SPACING]: 48,
|
||||
[ConstantKeys.BRANCH_SPACING]: 48,
|
||||
},
|
||||
|
||||
background: {
|
||||
backgroundColor: themeToken.colorBgContainer,
|
||||
dotSize: 0,
|
||||
},
|
||||
|
||||
playground: {
|
||||
autoFocus: true,
|
||||
autoResize: true,
|
||||
preventGlobalGesture: true,
|
||||
},
|
||||
|
||||
selectBox: {
|
||||
enable: false,
|
||||
},
|
||||
|
||||
scroll: {
|
||||
enableScrollLimit: true,
|
||||
},
|
||||
|
||||
readonly: readonly,
|
||||
|
||||
nodeEngine: {
|
||||
enable: true,
|
||||
},
|
||||
|
||||
variableEngine: {
|
||||
enable: true,
|
||||
},
|
||||
|
||||
materials: {
|
||||
components: getFlowComponents(),
|
||||
renderTexts: {
|
||||
[FlowTextKey.TRY_START_TEXT]: "Try",
|
||||
[FlowTextKey.TRY_END_TEXT]: "Finally",
|
||||
[FlowTextKey.CATCH_TEXT]: "Catch",
|
||||
},
|
||||
renderDefaultNode: NodeRender,
|
||||
},
|
||||
|
||||
nodeRegistries: getFlowNodeRegistries(),
|
||||
|
||||
getNodeDefaultRegistry(type) {
|
||||
return {
|
||||
type,
|
||||
meta: {
|
||||
defaultExpanded: true,
|
||||
},
|
||||
formMeta: {
|
||||
render: () => <BranchNode description={type} />,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
plugins: () => [
|
||||
createMinimapPlugin({
|
||||
disableLayer: true,
|
||||
enableDisplayAllNodes: true,
|
||||
canvasStyle: {
|
||||
canvasWidth: 160,
|
||||
canvasHeight: 160,
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
onAllLayersRendered: (ctx) => {
|
||||
// 画布初始化后向下滚动一点,露出可能被 Alert 遮挡的部分
|
||||
setTimeout(() => {
|
||||
ctx.playground.config.scroll({ scrollY: -80 });
|
||||
}, 1);
|
||||
},
|
||||
}),
|
||||
[themeToken, initialData, readonly]
|
||||
);
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
get container() {
|
||||
return flowgramEditorRef.current!.container;
|
||||
},
|
||||
get document() {
|
||||
return flowgramEditorRef.current!.document;
|
||||
},
|
||||
get playground() {
|
||||
return flowgramEditorRef.current!.playground;
|
||||
},
|
||||
get operation() {
|
||||
return flowgramEditorRef.current!.operation;
|
||||
},
|
||||
get clipboard() {
|
||||
return flowgramEditorRef.current!.clipboard;
|
||||
},
|
||||
get selection() {
|
||||
return flowgramEditorRef.current!.selection;
|
||||
},
|
||||
get history() {
|
||||
return flowgramEditorRef.current!.history;
|
||||
},
|
||||
|
||||
get(identifier) {
|
||||
return flowgramEditorRef.current!.get(identifier);
|
||||
},
|
||||
getAll(identifier) {
|
||||
return flowgramEditorRef.current!.getAll(identifier);
|
||||
},
|
||||
validateNode(node) {
|
||||
if (typeof node === "string") {
|
||||
node = flowgramEditorRef.current!.document.getNode(node)!;
|
||||
}
|
||||
|
||||
const form = getNodeForm(node);
|
||||
return form ? form.validate().then((res) => res && !form.state.invalid) : Promise.resolve(true);
|
||||
},
|
||||
validateAllNodes() {
|
||||
const nodes = flowgramEditorRef.current!.document.getAllNodes();
|
||||
const forms = nodes.map((node) => getNodeForm(node)).filter((form) => form != null);
|
||||
return Promise.allSettled(forms.map((form) => form.validate())).then((res) => forms.every((form, index) => res[index] && !form.state.invalid));
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<FixedLayoutEditorProvider ref={flowgramEditorRef} {...flowgramEditorProps}>
|
||||
<EditorContextProvider value={{ onNodeClick: (node) => onNodeClick?.(flowgramEditorRef.current!, node) }}>
|
||||
<EditorRenderer className={className} style={style} />
|
||||
{children}
|
||||
</EditorContextProvider>
|
||||
</FixedLayoutEditorProvider>
|
||||
);
|
||||
});
|
||||
|
||||
export default Editor;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createContext, useContext } from "react";
|
||||
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
export type NodeRenderContextType = {
|
||||
onNodeClick: (node: FlowNodeEntity) => void;
|
||||
};
|
||||
|
||||
export const EditorContext = createContext<NodeRenderContextType>({
|
||||
onNodeClick: () => {},
|
||||
});
|
||||
|
||||
export const EditorContextProvider = EditorContext.Provider;
|
||||
|
||||
export const useEditorContext = () => {
|
||||
const context = useContext(EditorContext);
|
||||
if (!context) {
|
||||
throw new Error("`EditorContext` must be used within a `EditorContextProvider`");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useService } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { FlowMinimapService, MinimapRender } from "@flowgram.ai/minimap-plugin";
|
||||
|
||||
export interface MinimapProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const Minimap = ({ className, style }: MinimapProps) => {
|
||||
const minimapService = useService(FlowMinimapService);
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<MinimapRender
|
||||
service={minimapService}
|
||||
panelStyles={{}}
|
||||
containerStyles={{
|
||||
pointerEvents: "auto",
|
||||
position: "relative",
|
||||
top: "unset",
|
||||
right: "unset",
|
||||
bottom: "unset",
|
||||
left: "unset",
|
||||
}}
|
||||
inactiveStyle={{
|
||||
opacity: 1,
|
||||
scale: 0.5,
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Minimap;
|
||||
@@ -0,0 +1,100 @@
|
||||
import { startTransition, useMemo, useState } from "react";
|
||||
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { useControllableValue } from "ahooks";
|
||||
|
||||
import { useTriggerElement } from "@/hooks";
|
||||
|
||||
import BizApplyNodeConfigDrawer from "./forms/BizApplyNodeConfigDrawer";
|
||||
import BizDeployNodeConfigDrawer from "./forms/BizDeployNodeConfigDrawer";
|
||||
import BizMonitorNodeConfigDrawer from "./forms/BizMonitorNodeConfigDrawer";
|
||||
import BizNotifyNodeConfigDrawer from "./forms/BizNotifyNodeConfigDrawer";
|
||||
import BizUploadNodeConfigDrawer from "./forms/BizUploadNodeConfigDrawer";
|
||||
import BranchBlockNodeConfigDrawer from "./forms/BranchBlockNodeConfigDrawer";
|
||||
import StartNodeConfigDrawer from "./forms/StartNodeConfigDrawer";
|
||||
import { NodeType } from "./nodes/typings";
|
||||
|
||||
export interface NodeDrawerProps {
|
||||
children?: React.ReactNode;
|
||||
loading?: boolean;
|
||||
node?: FlowNodeEntity;
|
||||
open?: boolean;
|
||||
trigger?: React.ReactNode;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const NodeDrawer = (_: NodeDrawerProps) => {
|
||||
const { node, trigger, ...props } = _;
|
||||
|
||||
const [open, setOpen] = useControllableValue<boolean>(props, {
|
||||
valuePropName: "open",
|
||||
defaultValuePropName: "defaultOpen",
|
||||
trigger: "onOpenChange",
|
||||
});
|
||||
|
||||
const triggerEl = useTriggerElement(trigger, { onClick: () => setOpen(true) });
|
||||
|
||||
const drawerProps = useMemo(
|
||||
() => ({
|
||||
...props,
|
||||
node: node!,
|
||||
open: open,
|
||||
onOpenChange: (open: boolean) => {
|
||||
setOpen(open);
|
||||
},
|
||||
}),
|
||||
[props, node, open]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{triggerEl}
|
||||
|
||||
{node?.flowNodeType === NodeType.Start ? (
|
||||
<StartNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BizApply ? (
|
||||
<BizApplyNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BizUpload ? (
|
||||
<BizUploadNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BizMonitor ? (
|
||||
<BizMonitorNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BizDeploy ? (
|
||||
<BizDeployNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BizNotify ? (
|
||||
<BizNotifyNodeConfigDrawer {...drawerProps} />
|
||||
) : node?.flowNodeType === NodeType.BranchBlock ? (
|
||||
<BranchBlockNodeConfigDrawer {...drawerProps} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const useProps = () => {
|
||||
const [node, setNode] = useState<NodeDrawerProps["node"]>();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
|
||||
const onOpenChange = (open: boolean) => {
|
||||
setOpen(open);
|
||||
|
||||
startTransition(() => {
|
||||
if (!open) {
|
||||
setNode(void 0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
node,
|
||||
open,
|
||||
setNode,
|
||||
setOpen,
|
||||
onOpenChange,
|
||||
};
|
||||
};
|
||||
|
||||
const _default = Object.assign(NodeDrawer, {
|
||||
useProps,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useEffect } from "react";
|
||||
import { type NodeRenderProps, useClientContext, useNodeRender, useRefresh } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
import { useEditorContext } from "./EditorContext";
|
||||
import { NodeRenderContextProvider } from "./NodeRenderContext";
|
||||
import { type NodeRegistry } from "./nodes/typings";
|
||||
|
||||
export interface NodeProps extends NodeRenderProps {}
|
||||
|
||||
const Node = (_: NodeProps) => {
|
||||
const ctx = useClientContext();
|
||||
|
||||
const refresh = useRefresh();
|
||||
|
||||
const nodeRender = useNodeRender();
|
||||
|
||||
useEffect(() => {
|
||||
const d = ctx.document.originTree.onTreeChange(() => refresh());
|
||||
return () => d.dispose();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const d1 = nodeRender.form?.onFormValuesChange?.(() => refresh());
|
||||
const d2 = nodeRender.form?.onValidate?.(() => refresh());
|
||||
return () => {
|
||||
d1?.dispose();
|
||||
d2?.dispose();
|
||||
};
|
||||
}, [nodeRender.form]);
|
||||
|
||||
const { onNodeClick } = useEditorContext();
|
||||
const handleNodeClick = () => {
|
||||
const node = nodeRender.node;
|
||||
if (node.getNodeRegistry<NodeRegistry>().meta?.clickable) {
|
||||
onNodeClick?.(node);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
opacity: nodeRender.dragging ? 0.3 : 1,
|
||||
...nodeRender.node.getNodeRegistry<NodeRegistry>().meta?.style,
|
||||
}}
|
||||
onMouseEnter={nodeRender.onMouseEnter}
|
||||
onMouseLeave={nodeRender.onMouseLeave}
|
||||
onMouseDown={(e) => {
|
||||
nodeRender.startDrag(e);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onClick={handleNodeClick}
|
||||
>
|
||||
<NodeRenderContextProvider value={nodeRender}>{nodeRender.form?.render()}</NodeRenderContextProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Node;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createContext, useContext } from "react";
|
||||
import { type NodeRenderReturnType } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
export type NodeRenderContextType = NodeRenderReturnType;
|
||||
|
||||
export const NodeRenderContext = createContext<NodeRenderContextType>({} as NodeRenderContextType);
|
||||
|
||||
export const NodeRenderContextProvider = NodeRenderContext.Provider;
|
||||
|
||||
export const useNodeRenderContext = () => {
|
||||
const context = useContext(NodeRenderContext);
|
||||
if (!context) {
|
||||
throw new Error("`NodeRenderContext` must be used within a `NodeRenderContextProvider`");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,114 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { EditorState, FlowLayoutDefault, useClientContext, usePlaygroundTools, useRefresh } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconHandStop, IconLayoutCards, IconMatrix, IconMaximize, IconMinus, IconPlus } from "@tabler/icons-react";
|
||||
import { Button, Dropdown, Tooltip } from "antd";
|
||||
|
||||
import { mergeCls } from "@/utils/css";
|
||||
|
||||
import Minimap from "./Minimap";
|
||||
|
||||
export interface ToolbarProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const Toolbar = ({ className, style }: ToolbarProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const ctx = useClientContext();
|
||||
const { playground } = ctx;
|
||||
|
||||
const tools = usePlaygroundTools({ minZoom: 0.1, maxZoom: 3, padding: 48 });
|
||||
|
||||
const refresh = useRefresh();
|
||||
|
||||
useEffect(() => {
|
||||
const d = playground.config.onReadonlyOrDisabledChange(() => refresh());
|
||||
return () => d.dispose();
|
||||
}, [playground]);
|
||||
|
||||
const [isMinimapVisible, setIsMinimapVisible] = useState(window.screen.availWidth >= 1024);
|
||||
|
||||
const [isMouseFriendly, setIsMouseFriendly] = useState(playground.editorState.is(EditorState.STATE_MOUSE_FRIENDLY_SELECT.id));
|
||||
|
||||
const handleToggleLayout = useCallback(() => {
|
||||
if (tools.isVertical) {
|
||||
tools.changeLayout(FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT);
|
||||
} else {
|
||||
tools.changeLayout(FlowLayoutDefault.VERTICAL_FIXED_LAYOUT);
|
||||
}
|
||||
}, [tools.isVertical]);
|
||||
|
||||
const handleToggleMinimap = useCallback(() => {
|
||||
setIsMinimapVisible((prev) => !prev);
|
||||
}, [isMinimapVisible]);
|
||||
|
||||
const handleToggleMouseFriendly = useCallback(() => {
|
||||
if (isMouseFriendly) {
|
||||
playground.editorState.changeState(EditorState.STATE_SELECT.id);
|
||||
setIsMouseFriendly(false);
|
||||
} else {
|
||||
playground.editorState.changeState(EditorState.STATE_MOUSE_FRIENDLY_SELECT.id);
|
||||
setIsMouseFriendly(true);
|
||||
}
|
||||
}, [isMouseFriendly]);
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Tooltip title={isMouseFriendly ? t("workflow.detail.design.toolbar.hand_mode") : t("workflow.detail.design.toolbar.pointer_mode")}>
|
||||
<Button
|
||||
ghost={isMouseFriendly}
|
||||
icon={<IconHandStop size="1.25em" />}
|
||||
type={isMouseFriendly ? "primary" : "default"}
|
||||
onClick={handleToggleMouseFriendly}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={t("workflow.detail.design.toolbar.zoomout")}>
|
||||
<Button icon={<IconMinus size="1.25em" />} onClick={() => tools.zoomout()} />
|
||||
</Tooltip>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: [
|
||||
...[200, 100, 75, 50, 25].map((zoom) => ({
|
||||
key: `${zoom}%`,
|
||||
label: `${zoom}%`,
|
||||
onClick: () => tools.updateZoom(zoom / 100),
|
||||
})),
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
key: "auto",
|
||||
label: t("workflow.detail.design.toolbar.auto_fit"),
|
||||
onClick: () => tools.fitView(),
|
||||
},
|
||||
],
|
||||
}}
|
||||
trigger={["click"]}
|
||||
>
|
||||
<Button className="w-16 text-center">{Math.round(tools.zoom * 100)}%</Button>
|
||||
</Dropdown>
|
||||
<Tooltip title={t("workflow.detail.design.toolbar.zoomin")}>
|
||||
<Button icon={<IconPlus size="1.25em" />} onClick={() => tools.zoomin()} />
|
||||
</Tooltip>
|
||||
<Tooltip title={t("workflow.detail.design.toolbar.auto_fit")}>
|
||||
<Button icon={<IconMaximize size="1.25em" />} onClick={() => tools.fitView()} />
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={tools.isVertical ? t("workflow.detail.design.toolbar.vertical_layout") : t("workflow.detail.design.toolbar.horizontal_layout")}>
|
||||
<Button icon={<IconLayoutCards className={mergeCls({ ["rotate-90"]: tools.isVertical })} size="1.25em" />} onClick={handleToggleLayout} />
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={t("workflow.detail.design.toolbar.minimap")}>
|
||||
<Button icon={<IconMatrix size="1.25em" />} ghost={isMinimapVisible} type={isMinimapVisible ? "primary" : "default"} onClick={handleToggleMinimap} />
|
||||
</Tooltip>
|
||||
{isMinimapVisible && <Minimap className="absolute right-0 bottom-[42px]" />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Toolbar;
|
||||
@@ -0,0 +1,60 @@
|
||||
import { type AdderProps as FlowgramAdderProps, useClientContext } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import { Button, Dropdown } from "antd";
|
||||
|
||||
import { getFlowNodeRegistries } from "../nodes";
|
||||
|
||||
export interface AdderProps extends FlowgramAdderProps {}
|
||||
|
||||
const Adder = ({ from, hoverActivated }: AdderProps) => {
|
||||
const ctx = useClientContext();
|
||||
const { operation, playground } = ctx;
|
||||
|
||||
const menuItems = getFlowNodeRegistries()
|
||||
.filter((registry) => {
|
||||
if (registry.meta?.addDisable != null) {
|
||||
return !registry.meta.addDisable;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.filter((registry) => {
|
||||
if (registry.canAdd != null) {
|
||||
return registry.canAdd(ctx, from);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((registry) => {
|
||||
const Icon = registry.meta?.icon;
|
||||
|
||||
return {
|
||||
key: registry.type,
|
||||
label: registry.meta?.labelText ?? registry.type,
|
||||
icon: <span className="anticon scale-125">{Icon && <Icon size="1em" />}</span>,
|
||||
onClick: () => {
|
||||
const block = operation.addFromNode(from, registry.onAdd!(ctx, from));
|
||||
|
||||
setTimeout(() => {
|
||||
playground.scrollToView({
|
||||
bounds: block.bounds,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}, 1);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return playground.config.readonlyOrDisabled ? null : (
|
||||
<div className="relative">
|
||||
<Dropdown menu={{ items: menuItems }} placement="bottomRight" trigger={["click"]}>
|
||||
{hoverActivated ? (
|
||||
<Button icon={<IconPlus size="1em" stroke={3} />} shape="circle" size="small" type="primary" />
|
||||
) : (
|
||||
<div className="size-2 rounded-full bg-primary opacity-75"></div>
|
||||
)}
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Adder;
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FlowNodeEntity, type AdderProps as FlowgramAdderProps, useClientContext } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { Button } from "antd";
|
||||
|
||||
import { BranchBlockNodeRegistry } from "../nodes/ConditionNode";
|
||||
import { CatchBlockNodeRegistry } from "../nodes/TryCatchNode";
|
||||
import { NodeType } from "../nodes/typings";
|
||||
|
||||
export interface BranchAdderProps extends FlowgramAdderProps {}
|
||||
|
||||
const BranchAdder = ({ node }: BranchAdderProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const ctx = useClientContext();
|
||||
const { operation, playground } = ctx;
|
||||
|
||||
const handleAddBranch = () => {
|
||||
let block: FlowNodeEntity;
|
||||
switch (node.flowNodeType) {
|
||||
case NodeType.Condition:
|
||||
block = operation.addBlock(node, BranchBlockNodeRegistry.onAdd!(ctx, node));
|
||||
break;
|
||||
|
||||
case NodeType.TryCatch:
|
||||
block = operation.addBlock(node, CatchBlockNodeRegistry.onAdd!(ctx, node));
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(`[certimate] unsupported node type for adding branch: '${node.flowNodeType}'`);
|
||||
break;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
playground.scrollToView({
|
||||
bounds: block.bounds,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}, 1);
|
||||
};
|
||||
|
||||
return playground.config.readonlyOrDisabled ? null : (
|
||||
<div
|
||||
className="relative"
|
||||
onMouseEnter={() => node.firstChild?.renderData?.toggleMouseEnter()}
|
||||
onMouseLeave={() => node.firstChild?.renderData?.toggleMouseLeave()}
|
||||
>
|
||||
<Button shape="round" size="small" onClick={handleAddBranch}>
|
||||
<span className="text-xs">{t("workflow.detail.design.editor.add_branch")}</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BranchAdder;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { type CollapseProps as FlowgramCollapseProps } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
export interface CollapseProps extends FlowgramCollapseProps {}
|
||||
|
||||
const Collapse = (_: CollapseProps) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Collapse;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { type DragNodeProps as FlowgramDragNodeProps } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconGradienter } from "@tabler/icons-react";
|
||||
|
||||
const DragHighlightAdder = (_: FlowgramDragNodeProps) => {
|
||||
return (
|
||||
<div className="size-4 animate-ping rounded-full bg-primary text-white shadow">
|
||||
<div className="flex size-full items-center justify-center">
|
||||
<IconGradienter size="1em" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DragHighlightAdder;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { type FlowNodeEntity, type DragNodeProps as FlowgramDragNodeProps, getNodeForm } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { Badge, Card } from "antd";
|
||||
|
||||
export interface DragNodeProps extends FlowgramDragNodeProps {
|
||||
dragStart: FlowNodeEntity;
|
||||
dragNodes: FlowNodeEntity[];
|
||||
}
|
||||
|
||||
const DragNode = ({ dragStart, dragNodes }: DragNodeProps) => {
|
||||
const count = (dragNodes || [])
|
||||
.map((n) => (n.allCollapsedChildren.length ? n.allCollapsedChildren.filter((_n) => !_n.hidden).length : 1))
|
||||
.reduce((acc, cur) => acc + cur, 0);
|
||||
return (
|
||||
<Badge count={count > 1 ? count : 0} size="small">
|
||||
<div className="relative w-[160px]">
|
||||
<Card className="bg-transparent shadow" styles={{ body: { padding: 0 } }}>
|
||||
<div className="overflow-hidden px-4 py-2 text-primary">
|
||||
<div className="truncate">{dragStart ? getNodeForm(dragStart)?.getValueIn("name") || `#${dragStart?.id}` : "\u00A0"}</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
||||
export default DragNode;
|
||||
@@ -0,0 +1,31 @@
|
||||
import { FlowDragLayer, type AdderProps as FlowgramAdderProps, usePlayground } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconChevronsDown } from "@tabler/icons-react";
|
||||
|
||||
export interface DraggingAdderProps extends FlowgramAdderProps {}
|
||||
|
||||
const DraggingAdder = ({ from }: DraggingAdderProps) => {
|
||||
const playground = usePlayground();
|
||||
|
||||
const layer = playground.getLayer(FlowDragLayer);
|
||||
if (!layer) return <></>;
|
||||
if (
|
||||
layer.options.canDrop &&
|
||||
!layer.options.canDrop({
|
||||
dragNodes: layer.dragEntities ?? [],
|
||||
dropNode: from,
|
||||
isBranch: false,
|
||||
})
|
||||
) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="size-4 animate-bounce rounded-full bg-primary text-white shadow">
|
||||
<div className="flex size-full items-center justify-center">
|
||||
<IconChevronsDown size="1em" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DraggingAdder;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
export interface NullProps {
|
||||
node: FlowNodeEntity;
|
||||
}
|
||||
|
||||
const Null = (_: NullProps) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Null;
|
||||
@@ -0,0 +1,62 @@
|
||||
import {
|
||||
type CustomLabelProps,
|
||||
FlowNodeRenderData,
|
||||
FlowNodeTransformData,
|
||||
FlowRendererRegistry,
|
||||
FlowTextKey,
|
||||
useBaseColor,
|
||||
} from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
export interface TryCatchCollapseProps extends CustomLabelProps {}
|
||||
|
||||
const TryCatchCollapse = ({ node, ...props }: TryCatchCollapseProps) => {
|
||||
const { baseColor, baseActivatedColor } = useBaseColor();
|
||||
|
||||
const nodeRenderData = node.getData(FlowNodeRenderData)!;
|
||||
const nodeTransformData = node.getData(FlowNodeTransformData)!;
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
nodeRenderData.activated = true;
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
nodeRenderData.activated = false;
|
||||
};
|
||||
|
||||
if (!nodeTransformData || !nodeTransformData.parent) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const width = nodeTransformData.inputPoint.x - nodeTransformData.parent.inputPoint.x;
|
||||
const height = 40;
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 6,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
data-label-id={props.labelId}
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: nodeRenderData.activated || nodeRenderData.lineActivated ? baseActivatedColor : baseColor,
|
||||
textAlign: "center",
|
||||
lineHeight: "20px",
|
||||
whiteSpace: "nowrap",
|
||||
backgroundColor: "var(--g-editor-background)",
|
||||
}}
|
||||
>
|
||||
{node.getService(FlowRendererRegistry).getText(FlowTextKey.CATCH_TEXT)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TryCatchCollapse;
|
||||
@@ -0,0 +1,30 @@
|
||||
import { FlowRendererKey } from "@flowgram.ai/fixed-layout-editor";
|
||||
|
||||
import Adder from "./Adder";
|
||||
import BranchAdder from "./BranchAdder";
|
||||
import Collapse from "./Collapse";
|
||||
import DraggingAdder from "./DraggingAdder";
|
||||
import DragHighlightAdder from "./DragHighlightAdder";
|
||||
import DragNode from "./DragNode";
|
||||
import Null from "./Null";
|
||||
import TryCatchCollapse from "./TryCatchCollapse";
|
||||
|
||||
export const getFlowComponents = () => {
|
||||
return {
|
||||
[FlowRendererKey.ADDER]: Adder,
|
||||
[FlowRendererKey.BRANCH_ADDER]: BranchAdder,
|
||||
[FlowRendererKey.SLOT_ADDER]: Null,
|
||||
|
||||
[FlowRendererKey.COLLAPSE]: Collapse,
|
||||
[FlowRendererKey.TRY_CATCH_COLLAPSE]: TryCatchCollapse,
|
||||
[FlowRendererKey.SLOT_COLLPASE]: Null,
|
||||
|
||||
[FlowRendererKey.DRAG_NODE]: DragNode,
|
||||
[FlowRendererKey.DRAG_HIGHLIGHT_ADDER]: DragHighlightAdder,
|
||||
[FlowRendererKey.DRAG_BRANCH_HIGHLIGHT_ADDER]: DragHighlightAdder,
|
||||
[FlowRendererKey.DRAGGABLE_ADDER]: DraggingAdder,
|
||||
|
||||
[FlowRendererKey.CONTEXT_MENU_POPOVER]: Null,
|
||||
[FlowRendererKey.SELECTOR_BOX_POPOVER]: Null,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/* 隐藏 flowgram 的标签背景 */
|
||||
/* flowgram 暂未提供相关配置项,这里需与 antd.colorBgContainer 保持一致 */
|
||||
:root {
|
||||
--g-editor-background: #fff;
|
||||
}
|
||||
.dark {
|
||||
--g-editor-background: #262c2d;
|
||||
}
|
||||
|
||||
/* 隐藏 flowgram 的折叠按钮 */
|
||||
.flow-canvas-collapse-adder > .flow-canvas-collapse {
|
||||
display: hidden !important;
|
||||
position: absolute !important;
|
||||
top: -99999px !important;
|
||||
left: -99999px !important;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
visibility: hidden !important;
|
||||
transform: scale(0) !important;
|
||||
}
|
||||
|
||||
/* 控制 flowgram 线条样式 */
|
||||
/* flowgram 暂未提供相关配置项 */
|
||||
.flow-lines-container {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { Form } from "antd";
|
||||
|
||||
import { NodeConfigDrawer } from "./_shared";
|
||||
import BizApplyNodeConfigForm from "./BizApplyNodeConfigForm";
|
||||
import { NodeType } from "../nodes/typings";
|
||||
|
||||
export interface BizApplyNodeConfigDrawerProps {
|
||||
loading?: boolean;
|
||||
node: FlowNodeEntity;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const BizApplyNodeConfigDrawer = (_: BizApplyNodeConfigDrawerProps) => {
|
||||
const { node, ...props } = _;
|
||||
if (node.flowNodeType !== NodeType.BizApply) {
|
||||
console.warn(`[certimate] current workflow node type is not: ${NodeType.BizApply}`);
|
||||
}
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const [formInst] = Form.useForm();
|
||||
|
||||
return (
|
||||
<NodeConfigDrawer
|
||||
anchor={{
|
||||
items: BizApplyNodeConfigForm.getAnchorItems({ i18n }),
|
||||
}}
|
||||
form={formInst}
|
||||
node={node}
|
||||
{...props}
|
||||
>
|
||||
<BizApplyNodeConfigForm form={formInst} node={node} />
|
||||
</NodeConfigDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default BizApplyNodeConfigDrawer;
|
||||
@@ -0,0 +1,652 @@
|
||||
import { memo, useEffect, useMemo, useState } from "react";
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router";
|
||||
import { QuestionCircleOutlined as IconQuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { type FlowNodeEntity, getNodeForm } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconChevronRight, IconCircleMinus, IconPlus } from "@tabler/icons-react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { type AnchorProps, AutoComplete, Button, Divider, Flex, Form, type FormInstance, Input, InputNumber, Select, Switch, Tooltip, Typography } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import AccessEditDrawer from "@/components/access/AccessEditDrawer";
|
||||
import AccessSelect from "@/components/access/AccessSelect";
|
||||
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
|
||||
import ACMEDns01ProviderSelect from "@/components/provider/ACMEDns01ProviderSelect";
|
||||
import CAProviderSelect from "@/components/provider/CAProviderSelect";
|
||||
import Show from "@/components/Show";
|
||||
import { ACCESS_USAGES, ACME_DNS01_PROVIDERS, accessProvidersMap, acmeDns01ProvidersMap, caProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowNodeConfigForApply, defaultNodeConfigForApply } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useAccessesStore } from "@/stores/access";
|
||||
import { useContactEmailsStore } from "@/stores/contact";
|
||||
import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators";
|
||||
|
||||
import { FormNestedFieldsContextProvider, NodeFormContextProvider } from "./_context";
|
||||
import BizApplyNodeConfigFormProviderAliyunESA from "./BizApplyNodeConfigFormProviderAliyunESA";
|
||||
import BizApplyNodeConfigFormProviderAWSRoute53 from "./BizApplyNodeConfigFormProviderAWSRoute53";
|
||||
import BizApplyNodeConfigFormProviderHuaweiCloudDNS from "./BizApplyNodeConfigFormProviderHuaweiCloudDNS";
|
||||
import BizApplyNodeConfigFormProviderJDCloudDNS from "./BizApplyNodeConfigFormProviderJDCloudDNS";
|
||||
import BizApplyNodeConfigFormProviderTencentCloudEO from "./BizApplyNodeConfigFormProviderTencentCloudEO";
|
||||
import { NodeType } from "../nodes/typings";
|
||||
|
||||
const MULTIPLE_INPUT_SEPARATOR = ";";
|
||||
|
||||
export interface BizApplyNodeConfigFormProps {
|
||||
form: FormInstance;
|
||||
node: FlowNodeEntity;
|
||||
}
|
||||
|
||||
const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps) => {
|
||||
if (node.flowNodeType !== NodeType.BizApply) {
|
||||
console.warn(`[certimate] current workflow node type is not: ${NodeType.BizApply}`);
|
||||
}
|
||||
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { accesses } = useAccessesStore(useZustandShallowSelector("accesses"));
|
||||
|
||||
const initialValues = useMemo(() => {
|
||||
return getNodeForm(node)?.getValueIn("config") as WorkflowNodeConfigForApply | undefined;
|
||||
}, [node]);
|
||||
|
||||
const formSchema = getSchema({ i18n });
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm({
|
||||
form: props.form,
|
||||
name: "workflowNodeBizApplyConfigForm",
|
||||
initialValues: initialValues ?? getInitialValues(),
|
||||
});
|
||||
|
||||
const fieldProvider = Form.useWatch<string>("provider", { form: formInst, preserve: true });
|
||||
const fieldProviderAccessId = Form.useWatch<string>("providerAccessId", { form: formInst, preserve: true });
|
||||
const fieldCAProvider = Form.useWatch<string>("caProvider", { form: formInst, preserve: true });
|
||||
|
||||
const NestedProviderConfigFields = useMemo(() => {
|
||||
/*
|
||||
注意:如果追加新的子组件,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new child component, please keep ASCII order.
|
||||
*/
|
||||
switch (fieldProvider) {
|
||||
case ACME_DNS01_PROVIDERS.ALIYUN_ESA:
|
||||
return BizApplyNodeConfigFormProviderAliyunESA;
|
||||
case ACME_DNS01_PROVIDERS.AWS:
|
||||
case ACME_DNS01_PROVIDERS.AWS_ROUTE53:
|
||||
return BizApplyNodeConfigFormProviderAWSRoute53;
|
||||
case ACME_DNS01_PROVIDERS.HUAWEICLOUD:
|
||||
case ACME_DNS01_PROVIDERS.HUAWEICLOUD_DNS:
|
||||
return BizApplyNodeConfigFormProviderHuaweiCloudDNS;
|
||||
case ACME_DNS01_PROVIDERS.JDCLOUD:
|
||||
case ACME_DNS01_PROVIDERS.JDCLOUD_DNS:
|
||||
return BizApplyNodeConfigFormProviderJDCloudDNS;
|
||||
case ACME_DNS01_PROVIDERS.TENCENTCLOUD_EO:
|
||||
return BizApplyNodeConfigFormProviderTencentCloudEO;
|
||||
}
|
||||
}, [fieldProvider]);
|
||||
|
||||
const [showProvider, setShowProvider] = useState(false);
|
||||
useEffect(() => {
|
||||
// 通常情况下每个授权信息只对应一个 DNS 提供商,此时无需显示 DNS 提供商字段;
|
||||
// 如果对应多个(如 AWS 的 Route53、Lightsail,阿里云的 DNS、ESA,腾讯云的 DNS、EdgeOne 等),则显示。
|
||||
if (fieldProviderAccessId) {
|
||||
const access = accesses.find((e) => e.id === fieldProviderAccessId);
|
||||
const providers = Array.from(acmeDns01ProvidersMap.values()).filter((e) => e.provider === access?.provider);
|
||||
setShowProvider(providers.length > 1);
|
||||
} else {
|
||||
setShowProvider(false);
|
||||
}
|
||||
}, [accesses, fieldProviderAccessId]);
|
||||
|
||||
const [showCAProviderAccess, setShowCAProviderAccess] = useState(false);
|
||||
useEffect(() => {
|
||||
// 内置的 CA 提供商(如 Let's Encrypt)无需显示授权信息字段
|
||||
if (fieldCAProvider) {
|
||||
const provider = caProvidersMap.get(fieldCAProvider);
|
||||
setShowCAProviderAccess(!provider?.builtin);
|
||||
} else {
|
||||
setShowCAProviderAccess(false);
|
||||
}
|
||||
}, [fieldCAProvider]);
|
||||
|
||||
const handleProviderSelect = (value: string) => {
|
||||
if (fieldProvider === value) return;
|
||||
|
||||
// 切换 DNS 提供商时联动授权信息
|
||||
if (initialValues?.provider === value) {
|
||||
formInst.setFieldValue("providerAccessId", initialValues?.providerAccessId);
|
||||
} else {
|
||||
if (acmeDns01ProvidersMap.get(fieldProvider)?.provider !== acmeDns01ProvidersMap.get(value)?.provider) {
|
||||
formInst.setFieldValue("providerAccessId", void 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleProviderAccessSelect = (value: string) => {
|
||||
// 切换授权信息时联动 DNS 提供商
|
||||
const access = accesses.find((access) => access.id === value);
|
||||
const provider = Array.from(acmeDns01ProvidersMap.values()).find((provider) => provider.provider === access?.provider);
|
||||
if (fieldProvider !== provider?.type) {
|
||||
formInst.setFieldValue("provider", provider?.type);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCAProviderSelect = (value?: string | undefined) => {
|
||||
// 切换 CA 提供商时联动授权信息
|
||||
if (value === "") {
|
||||
setTimeout(() => {
|
||||
formInst.setFieldValue("caProvider", void 0);
|
||||
formInst.setFieldValue("caProviderAccessId", void 0);
|
||||
}, 1);
|
||||
} else if (initialValues?.caProvider === value) {
|
||||
formInst.setFieldValue("caProviderAccessId", initialValues?.caProviderAccessId);
|
||||
} else {
|
||||
if (caProvidersMap.get(fieldCAProvider)?.provider !== caProvidersMap.get(value!)?.provider) {
|
||||
formInst.setFieldValue("caProviderAccessId", void 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeFormContextProvider value={{ node }}>
|
||||
<Form {...formProps} clearOnDestroy={true} form={formInst} layout="vertical" preserve={false} scrollToFirstError>
|
||||
<div id="parameters" data-anchor="parameters">
|
||||
<Form.Item
|
||||
name="domains"
|
||||
label={t("workflow_node.apply.form.domains.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.domains.tooltip") }}></span>}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.apply.form.domains.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.apply.form.domains.placeholder")}
|
||||
placeholderInModal={t("workflow_node.apply.form.domains.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="contactEmail"
|
||||
label={t("workflow_node.apply.form.contact_email.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.contact_email.tooltip") }}></span>}
|
||||
>
|
||||
<EmailInput placeholder={t("workflow_node.apply.form.contact_email.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="challengeType" label={t("workflow_node.apply.form.challenge_type.label")} rules={[formRule]} hidden>
|
||||
<Select
|
||||
options={["DNS-01"].map((e) => ({
|
||||
label: e,
|
||||
value: e.toLowerCase(),
|
||||
}))}
|
||||
placeholder={t("workflow_node.apply.form.challenge_type.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="provider" label={t("workflow_node.apply.form.provider.label")} hidden={!showProvider} rules={[formRule]}>
|
||||
<ACMEDns01ProviderSelect
|
||||
disabled={!showProvider}
|
||||
placeholder={t("workflow_node.apply.form.provider.placeholder")}
|
||||
showSearch
|
||||
onFilter={(_, option) => {
|
||||
if (fieldProviderAccessId) {
|
||||
return accesses.find((e) => e.id === fieldProviderAccessId)?.provider === option.provider;
|
||||
}
|
||||
|
||||
return true;
|
||||
}}
|
||||
onSelect={handleProviderSelect}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item noStyle>
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">
|
||||
<span>{t("workflow_node.apply.form.provider_access.label")}</span>
|
||||
<Tooltip title={t("workflow_node.apply.form.provider_access.tooltip")}>
|
||||
<Typography.Text className="ms-1" type="secondary">
|
||||
<IconQuestionCircleOutlined />
|
||||
</Typography.Text>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<AccessEditDrawer
|
||||
mode="create"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.apply.form.provider_access.button")}
|
||||
<IconPlus size="1.25em" />
|
||||
</Button>
|
||||
}
|
||||
usage="dns"
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.DNS)) {
|
||||
formInst.setFieldValue("providerAccessId", record.id);
|
||||
handleProviderAccessSelect(record.id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="providerAccessId" rules={[formRule]}>
|
||||
<AccessSelect
|
||||
placeholder={t("workflow_node.apply.form.provider_access.placeholder")}
|
||||
showSearch
|
||||
onChange={handleProviderAccessSelect}
|
||||
onFilter={(_, option) => {
|
||||
if (option.reserve) return false;
|
||||
|
||||
const provider = accessProvidersMap.get(option.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.DNS);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<FormNestedFieldsContextProvider value={{ parentNamePath: "providerConfig" }}>
|
||||
{NestedProviderConfigFields && <NestedProviderConfigFields />}
|
||||
</FormNestedFieldsContextProvider>
|
||||
</div>
|
||||
|
||||
<div id="certificate" data-anchor="certificate">
|
||||
<Divider size="small">
|
||||
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||
{t("workflow_node.apply.form_anchor.certificate.title")}
|
||||
</Typography.Text>
|
||||
</Divider>
|
||||
|
||||
<Form.Item noStyle>
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">
|
||||
<span>{t("workflow_node.apply.form.ca_provider.label")}</span>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<Show when={!fieldCAProvider}>
|
||||
<Link className="ant-typography" to="/settings/ssl-provider" target="_blank">
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.apply.form.ca_provider.button")}
|
||||
<IconChevronRight size="1.25em" />
|
||||
</Button>
|
||||
</Link>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="caProvider" rules={[formRule]}>
|
||||
<CAProviderSelect
|
||||
allowClear
|
||||
placeholder={t("workflow_node.apply.form.ca_provider.placeholder")}
|
||||
showSearch
|
||||
onSelect={handleCAProviderSelect}
|
||||
onClear={handleCAProviderSelect}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item hidden={!showCAProviderAccess} noStyle>
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">
|
||||
<span>{t("workflow_node.apply.form.ca_provider_access.label")}</span>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<AccessEditDrawer
|
||||
data={{ provider: caProvidersMap.get(fieldCAProvider!)?.provider }}
|
||||
mode="create"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.apply.form.ca_provider_access.button")}
|
||||
<IconChevronRight size="1.25em" />
|
||||
</Button>
|
||||
}
|
||||
usage="ca"
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.CA)) {
|
||||
formInst.setFieldValue("caProviderAccessId", record.id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="caProviderAccessId" rules={[formRule]}>
|
||||
<AccessSelect
|
||||
placeholder={t("workflow_node.apply.form.ca_provider_access.placeholder")}
|
||||
showSearch
|
||||
onFilter={(_, option) => {
|
||||
if (option.reserve !== "ca") return false;
|
||||
if (fieldCAProvider) return caProvidersMap.get(fieldCAProvider)?.provider === option.provider;
|
||||
|
||||
const provider = accessProvidersMap.get(option.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.CA);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="keyAlgorithm" label={t("workflow_node.apply.form.key_algorithm.label")} rules={[formRule]}>
|
||||
<Select
|
||||
options={["RSA2048", "RSA3072", "RSA4096", "RSA8192", "EC256", "EC384"].map((e) => ({
|
||||
label: e,
|
||||
value: e,
|
||||
}))}
|
||||
placeholder={t("workflow_node.apply.form.key_algorithm.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="acmeProfile"
|
||||
label={t("workflow_node.apply.form.acme_profile.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.acme_profile.tooltip") }}></span>}
|
||||
>
|
||||
<AutoComplete
|
||||
allowClear
|
||||
options={["classic", "tlsserver", "shortlived"].map((value) => ({ value }))}
|
||||
placeholder={t("workflow_node.apply.form.acme_profile.placeholder")}
|
||||
filterOption={(inputValue, option) => option!.value.toLowerCase().includes(inputValue.toLowerCase())}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div id="advanced" data-anchor="advanced">
|
||||
<Divider size="small">
|
||||
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||
{t("workflow_node.apply.form_anchor.advanced.title")}
|
||||
</Typography.Text>
|
||||
</Divider>
|
||||
|
||||
<Form.Item
|
||||
name="nameservers"
|
||||
label={t("workflow_node.apply.form.nameservers.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.nameservers.tooltip") }}></span>}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.apply.form.nameservers.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.apply.form.nameservers.placeholder")}
|
||||
placeholderInModal={t("workflow_node.apply.form.nameservers.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="dnsPropagationWait"
|
||||
label={t("workflow_node.apply.form.dns_propagation_wait.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.dns_propagation_wait.tooltip") }}></span>}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
allowClear
|
||||
min={0}
|
||||
max={3600}
|
||||
placeholder={t("workflow_node.apply.form.dns_propagation_wait.placeholder")}
|
||||
addonAfter={t("workflow_node.apply.form.dns_propagation_wait.unit")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="dnsPropagationTimeout"
|
||||
label={t("workflow_node.apply.form.dns_propagation_timeout.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.dns_propagation_timeout.tooltip") }}></span>}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
allowClear
|
||||
min={0}
|
||||
max={3600}
|
||||
placeholder={t("workflow_node.apply.form.dns_propagation_timeout.placeholder")}
|
||||
addonAfter={t("workflow_node.apply.form.dns_propagation_timeout.unit")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="dnsTTL"
|
||||
label={t("workflow_node.apply.form.dns_ttl.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.dns_ttl.tooltip") }}></span>}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
allowClear
|
||||
min={0}
|
||||
max={86400}
|
||||
placeholder={t("workflow_node.apply.form.dns_ttl.placeholder")}
|
||||
addonAfter={t("workflow_node.apply.form.dns_ttl.unit")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="disableFollowCNAME"
|
||||
label={t("workflow_node.apply.form.disable_follow_cname.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.disable_follow_cname.tooltip") }}></span>}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="disableARI"
|
||||
label={t("workflow_node.apply.form.disable_ari.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.disable_ari.tooltip") }}></span>}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div id="strategy" data-anchor="strategy">
|
||||
<Divider size="small">
|
||||
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||
{t("workflow_node.apply.form_anchor.strategy.title")}
|
||||
</Typography.Text>
|
||||
</Divider>
|
||||
|
||||
<Form.Item
|
||||
label={t("workflow_node.apply.form.skip_before_expiry_days.label")}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.skip_before_expiry_days.tooltip") }}></span>}
|
||||
>
|
||||
<Flex align="center" gap={8} wrap="wrap">
|
||||
<div>{t("workflow_node.apply.form.skip_before_expiry_days.prefix")}</div>
|
||||
<Form.Item name="skipBeforeExpiryDays" noStyle rules={[formRule]}>
|
||||
<InputNumber
|
||||
className="w-24"
|
||||
min={1}
|
||||
max={365}
|
||||
placeholder={t("workflow_node.apply.form.skip_before_expiry_days.placeholder")}
|
||||
addonAfter={t("workflow_node.apply.form.skip_before_expiry_days.unit")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<div>{t("workflow_node.apply.form.skip_before_expiry_days.suffix")}</div>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Form>
|
||||
</NodeFormContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const EmailInput = memo(
|
||||
({ disabled, placeholder, ...props }: { disabled?: boolean; placeholder?: string; value?: string; onChange?: (value: string) => void }) => {
|
||||
const { emails, fetchEmails, removeEmail } = useContactEmailsStore();
|
||||
useEffect(() => {
|
||||
fetchEmails();
|
||||
}, []);
|
||||
|
||||
const [value, setValue] = useControllableValue<string>(props, {
|
||||
valuePropName: "value",
|
||||
defaultValuePropName: "defaultValue",
|
||||
trigger: "onChange",
|
||||
});
|
||||
|
||||
const [inputValue, setInputValue] = useState<string>();
|
||||
|
||||
const renderOptionLabel = (email: string, removable: boolean = false) => (
|
||||
<div className="flex items-center gap-2 overflow-hidden">
|
||||
<span className="flex-1 truncate overflow-hidden">{email}</span>
|
||||
{removable && (
|
||||
<Button
|
||||
color="default"
|
||||
disabled={disabled}
|
||||
icon={<IconCircleMinus size="1.25em" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={(e) => {
|
||||
removeEmail(email);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const options = useMemo(() => {
|
||||
const temp = emails.map((email) => ({
|
||||
label: renderOptionLabel(email, true),
|
||||
value: email,
|
||||
}));
|
||||
|
||||
if (!!inputValue && temp.every((option) => option.value !== inputValue)) {
|
||||
temp.unshift({
|
||||
label: renderOptionLabel(inputValue),
|
||||
value: inputValue,
|
||||
});
|
||||
}
|
||||
|
||||
return temp;
|
||||
}, [emails, inputValue]);
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
setInputValue(value?.trim());
|
||||
};
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
backfill
|
||||
defaultValue={value}
|
||||
disabled={disabled}
|
||||
filterOption
|
||||
options={options}
|
||||
placeholder={placeholder}
|
||||
showSearch
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onSearch={handleSearch}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const getAnchorItems = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }): Required<AnchorProps>["items"] => {
|
||||
const { t } = i18n;
|
||||
|
||||
return ["parameters", "certificate", "advanced", "strategy"].map((key) => ({
|
||||
key: key,
|
||||
title: t(`workflow_node.apply.form_anchor.${key}.tab`),
|
||||
href: "#" + key,
|
||||
}));
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domains: "",
|
||||
provider: "",
|
||||
providerAccessId: "",
|
||||
...defaultNodeConfigForApply(),
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
domains: z.string().refine((v) => {
|
||||
if (!v) return false;
|
||||
return String(v)
|
||||
.split(MULTIPLE_INPUT_SEPARATOR)
|
||||
.every((e) => validDomainName(e, { allowWildcard: true }));
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
contactEmail: z.email(t("common.errmsg.email_invalid")),
|
||||
challengeType: z.string().nullish(),
|
||||
provider: z.string().nonempty(t("workflow_node.apply.form.provider.placeholder")),
|
||||
providerAccessId: z.string().nonempty(t("workflow_node.apply.form.provider_access.placeholder")),
|
||||
providerConfig: z.any().nullish(),
|
||||
caProvider: z.string().nullish(),
|
||||
caProviderAccessId: z.string().nullish(),
|
||||
caProviderConfig: z.any().nullish(),
|
||||
keyAlgorithm: z.string().nonempty(t("workflow_node.apply.form.key_algorithm.placeholder")),
|
||||
nameservers: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
|
||||
return String(v)
|
||||
.split(MULTIPLE_INPUT_SEPARATOR)
|
||||
.every((e) => validIPv4Address(e) || validIPv6Address(e) || validDomainName(e));
|
||||
}, t("common.errmsg.host_invalid")),
|
||||
dnsPropagationWait: z.preprocess(
|
||||
(v) => (v == null || v === "" ? void 0 : Number(v)),
|
||||
z
|
||||
.number()
|
||||
.int(t("workflow_node.apply.form.dns_propagation_wait.placeholder"))
|
||||
.gte(0, t("workflow_node.apply.form.dns_propagation_wait.placeholder"))
|
||||
.nullish()
|
||||
),
|
||||
dnsPropagationTimeout: z.preprocess(
|
||||
(v) => (v == null || v === "" ? void 0 : Number(v)),
|
||||
z
|
||||
.number()
|
||||
.int(t("workflow_node.apply.form.dns_propagation_timeout.placeholder"))
|
||||
.gte(1, t("workflow_node.apply.form.dns_propagation_timeout.placeholder"))
|
||||
.nullish()
|
||||
),
|
||||
dnsTTL: z.preprocess(
|
||||
(v) => (v == null || v === "" ? void 0 : Number(v)),
|
||||
z.number().int(t("workflow_node.apply.form.dns_ttl.placeholder")).gte(1, t("workflow_node.apply.form.dns_ttl.placeholder")).nullish()
|
||||
),
|
||||
acmeProfile: z.string().nullish(),
|
||||
disableFollowCNAME: z.boolean().nullish(),
|
||||
disableARI: z.boolean().nullish(),
|
||||
skipBeforeExpiryDays: z.preprocess(
|
||||
(v) => Number(v),
|
||||
z
|
||||
.number()
|
||||
.int(t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
|
||||
.gte(1, t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
|
||||
),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
if (values.caProvider) {
|
||||
const provider = caProvidersMap.get(values.caProvider);
|
||||
if (!provider?.builtin && !values.caProviderAccessId) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.apply.form.ca_provider_access.placeholder"),
|
||||
path: ["caProviderAccessId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigForm, {
|
||||
getAnchorItems,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizApplyNodeConfigFormProviderAWSRoute53 = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.apply.form.aws_route53_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.aws_route53_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.aws_route53_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "hostedZoneId"]}
|
||||
initialValue={initialValues.hostedZoneId}
|
||||
label={t("workflow_node.apply.form.aws_route53_hosted_zone_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.aws_route53_hosted_zone_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.aws_route53_hosted_zone_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "us-east-1",
|
||||
hostedZoneId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.apply.form.aws_route53_region.placeholder")),
|
||||
hostedZoneId: z.string().nonempty(t("workflow_node.apply.form.aws_route53_hosted_zone_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigFormProviderAWSRoute53, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizApplyNodeConfigFormProviderAliyunESA = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.apply.form.aliyun_esa_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.aliyun_esa_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.aliyun_esa_region.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "cn-hangzhou",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.apply.form.aliyun_esa_region.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigFormProviderAliyunESA, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizApplyNodeConfigFormProviderHuaweiCloudDNS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.apply.form.huaweicloud_dns_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.huaweicloud_dns_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.huaweicloud_dns_region.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "cn-north-1",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.apply.form.huaweicloud_dns_region.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigFormProviderHuaweiCloudDNS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizApplyNodeConfigFormProviderJDCloudDNS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "regionId"]}
|
||||
initialValue={initialValues.regionId}
|
||||
label={t("workflow_node.apply.form.jdcloud_dns_region_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.jdcloud_dns_region_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.jdcloud_dns_region_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
regionId: "cn-north-1",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
regionId: z.string().nonempty(t("workflow_node.apply.form.jdcloud_dns_region_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigFormProviderJDCloudDNS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizApplyNodeConfigFormProviderTencentCloudEO = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "zoneId"]}
|
||||
initialValue={initialValues.zoneId}
|
||||
label={t("workflow_node.apply.form.tencentcloud_eo_zone_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.tencentcloud_eo_zone_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.apply.form.tencentcloud_eo_zone_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
zoneId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
zoneId: z.string().nonempty(t("workflow_node.apply.form.tencentcloud_eo_zone_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizApplyNodeConfigFormProviderTencentCloudEO, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { Form } from "antd";
|
||||
|
||||
import { NodeConfigDrawer } from "./_shared";
|
||||
import BizDeployNodeConfigForm from "./BizDeployNodeConfigForm";
|
||||
import { NodeType } from "../nodes/typings";
|
||||
|
||||
export interface BizDeployNodeConfigDrawerProps {
|
||||
loading?: boolean;
|
||||
node: FlowNodeEntity;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const BizDeployNodeConfigDrawer = (_: BizDeployNodeConfigDrawerProps) => {
|
||||
const { node, ...props } = _;
|
||||
if (node.flowNodeType !== NodeType.BizDeploy) {
|
||||
console.warn(`[certimate] current workflow node type is not: ${NodeType.BizDeploy}`);
|
||||
}
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const [formInst] = Form.useForm();
|
||||
|
||||
const fieldProvider = Form.useWatch<string>("provider", { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<NodeConfigDrawer
|
||||
anchor={fieldProvider ? { items: BizDeployNodeConfigForm.getAnchorItems({ i18n }) } : false}
|
||||
footer={fieldProvider ? true : false}
|
||||
form={formInst}
|
||||
node={node}
|
||||
{...props}
|
||||
>
|
||||
<BizDeployNodeConfigForm form={formInst} node={node} />
|
||||
</NodeConfigDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default BizDeployNodeConfigDrawer;
|
||||
@@ -0,0 +1,576 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { QuestionCircleOutlined as IconQuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { type FlowNodeEntity, getNodeForm } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import { type AnchorProps, Button, Divider, Flex, Form, type FormInstance, Select, Switch, Tooltip, Typography, theme } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import AccessEditDrawer from "@/components/access/AccessEditDrawer";
|
||||
import AccessSelect from "@/components/access/AccessSelect";
|
||||
import DeploymentProviderPicker from "@/components/provider/DeploymentProviderPicker";
|
||||
import DeploymentProviderSelect from "@/components/provider/DeploymentProviderSelect";
|
||||
import Show from "@/components/Show";
|
||||
import { ACCESS_USAGES, DEPLOYMENT_PROVIDERS, accessProvidersMap, deploymentProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowNodeConfigForDeploy, WorkflowNodeType, defaultNodeConfigForDeploy } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
|
||||
import { FormNestedFieldsContextProvider, NodeFormContextProvider } from "./_context";
|
||||
import BizDeployNodeConfigFormProvider1PanelConsole from "./BizDeployNodeConfigFormProvider1PanelConsole";
|
||||
import BizDeployNodeConfigFormProvider1PanelSite from "./BizDeployNodeConfigFormProvider1PanelSite";
|
||||
import BizDeployNodeConfigFormProviderAliyunALB from "./BizDeployNodeConfigFormProviderAliyunALB";
|
||||
import BizDeployNodeConfigFormProviderAliyunAPIGW from "./BizDeployNodeConfigFormProviderAliyunAPIGW";
|
||||
import BizDeployNodeConfigFormProviderAliyunCAS from "./BizDeployNodeConfigFormProviderAliyunCAS";
|
||||
import BizDeployNodeConfigFormProviderAliyunCASDeploy from "./BizDeployNodeConfigFormProviderAliyunCASDeploy";
|
||||
import BizDeployNodeConfigFormProviderAliyunCDN from "./BizDeployNodeConfigFormProviderAliyunCDN";
|
||||
import BizDeployNodeConfigFormProviderAliyunCLB from "./BizDeployNodeConfigFormProviderAliyunCLB";
|
||||
import BizDeployNodeConfigFormProviderAliyunDCDN from "./BizDeployNodeConfigFormProviderAliyunDCDN";
|
||||
import BizDeployNodeConfigFormProviderAliyunDDoS from "./BizDeployNodeConfigFormProviderAliyunDDoS";
|
||||
import BizDeployNodeConfigFormProviderAliyunESA from "./BizDeployNodeConfigFormProviderAliyunESA";
|
||||
import BizDeployNodeConfigFormProviderAliyunFC from "./BizDeployNodeConfigFormProviderAliyunFC";
|
||||
import BizDeployNodeConfigFormProviderAliyunGA from "./BizDeployNodeConfigFormProviderAliyunGA";
|
||||
import BizDeployNodeConfigFormProviderAliyunLive from "./BizDeployNodeConfigFormProviderAliyunLive";
|
||||
import BizDeployNodeConfigFormProviderAliyunNLB from "./BizDeployNodeConfigFormProviderAliyunNLB";
|
||||
import BizDeployNodeConfigFormProviderAliyunOSS from "./BizDeployNodeConfigFormProviderAliyunOSS";
|
||||
import BizDeployNodeConfigFormProviderAliyunVOD from "./BizDeployNodeConfigFormProviderAliyunVOD";
|
||||
import BizDeployNodeConfigFormProviderAliyunWAF from "./BizDeployNodeConfigFormProviderAliyunWAF";
|
||||
import BizDeployNodeConfigFormProviderAPISIX from "./BizDeployNodeConfigFormProviderAPISIX";
|
||||
import BizDeployNodeConfigFormProviderAWSACM from "./BizDeployNodeConfigFormProviderAWSACM";
|
||||
import BizDeployNodeConfigFormProviderAWSCloudFront from "./BizDeployNodeConfigFormProviderAWSCloudFront";
|
||||
import BizDeployNodeConfigFormProviderAWSIAM from "./BizDeployNodeConfigFormProviderAWSIAM";
|
||||
import BizDeployNodeConfigFormProviderAzureKeyVault from "./BizDeployNodeConfigFormProviderAzureKeyVault";
|
||||
import BizDeployNodeConfigFormProviderBaiduCloudAppBLB from "./BizDeployNodeConfigFormProviderBaiduCloudAppBLB";
|
||||
import BizDeployNodeConfigFormProviderBaiduCloudBLB from "./BizDeployNodeConfigFormProviderBaiduCloudBLB";
|
||||
import BizDeployNodeConfigFormProviderBaiduCloudCDN from "./BizDeployNodeConfigFormProviderBaiduCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderBaishanCDN from "./BizDeployNodeConfigFormProviderBaishanCDN";
|
||||
import BizDeployNodeConfigFormProviderBaotaPanelConsole from "./BizDeployNodeConfigFormProviderBaotaPanelConsole";
|
||||
import BizDeployNodeConfigFormProviderBaotaPanelSite from "./BizDeployNodeConfigFormProviderBaotaPanelSite";
|
||||
import BizDeployNodeConfigFormProviderBaotaWAFSite from "./BizDeployNodeConfigFormProviderBaotaWAFSite";
|
||||
import BizDeployNodeConfigFormProviderBunnyCDN from "./BizDeployNodeConfigFormProviderBunnyCDN";
|
||||
import BizDeployNodeConfigFormProviderBytePlusCDN from "./BizDeployNodeConfigFormProviderBytePlusCDN";
|
||||
import BizDeployNodeConfigFormProviderCdnfly from "./BizDeployNodeConfigFormProviderCdnfly";
|
||||
import BizDeployNodeConfigFormProviderCTCCCloudAO from "./BizDeployNodeConfigFormProviderCTCCCloudAO";
|
||||
import BizDeployNodeConfigFormProviderCTCCCloudCDN from "./BizDeployNodeConfigFormProviderCTCCCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderCTCCCloudELB from "./BizDeployNodeConfigFormProviderCTCCCloudELB";
|
||||
import BizDeployNodeConfigFormProviderCTCCCloudICDN from "./BizDeployNodeConfigFormProviderCTCCCloudICDN";
|
||||
import BizDeployNodeConfigFormProviderCTCCCloudLVDN from "./BizDeployNodeConfigFormProviderCTCCCloudLVDN";
|
||||
import BizDeployNodeConfigFormProviderDogeCloudCDN from "./BizDeployNodeConfigFormProviderDogeCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderEdgioApplications from "./BizDeployNodeConfigFormProviderEdgioApplications";
|
||||
import BizDeployNodeConfigFormProviderFlexCDN from "./BizDeployNodeConfigFormProviderFlexCDN";
|
||||
import BizDeployNodeConfigFormProviderGcoreCDN from "./BizDeployNodeConfigFormProviderGcoreCDN";
|
||||
import BizDeployNodeConfigFormProviderGoEdge from "./BizDeployNodeConfigFormProviderGoEdge";
|
||||
import BizDeployNodeConfigFormProviderHuaweiCloudCDN from "./BizDeployNodeConfigFormProviderHuaweiCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderHuaweiCloudELB from "./BizDeployNodeConfigFormProviderHuaweiCloudELB";
|
||||
import BizDeployNodeConfigFormProviderHuaweiCloudWAF from "./BizDeployNodeConfigFormProviderHuaweiCloudWAF";
|
||||
import BizDeployNodeConfigFormProviderJDCloudALB from "./BizDeployNodeConfigFormProviderJDCloudALB";
|
||||
import BizDeployNodeConfigFormProviderJDCloudCDN from "./BizDeployNodeConfigFormProviderJDCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderJDCloudLive from "./BizDeployNodeConfigFormProviderJDCloudLive";
|
||||
import BizDeployNodeConfigFormProviderJDCloudVOD from "./BizDeployNodeConfigFormProviderJDCloudVOD";
|
||||
import BizDeployNodeConfigFormProviderKong from "./BizDeployNodeConfigFormProviderKong";
|
||||
import BizDeployNodeConfigFormProviderKubernetesSecret from "./BizDeployNodeConfigFormProviderKubernetesSecret";
|
||||
import BizDeployNodeConfigFormProviderLeCDN from "./BizDeployNodeConfigFormProviderLeCDN";
|
||||
import BizDeployNodeConfigFormProviderLocal from "./BizDeployNodeConfigFormProviderLocal";
|
||||
import BizDeployNodeConfigFormProviderNetlifySite from "./BizDeployNodeConfigFormProviderNetlifySite";
|
||||
import BizDeployNodeConfigFormProviderProxmoxVE from "./BizDeployNodeConfigFormProviderProxmoxVE";
|
||||
import BizDeployNodeConfigFormProviderQiniuCDN from "./BizDeployNodeConfigFormProviderQiniuCDN";
|
||||
import BizDeployNodeConfigFormProviderQiniuKodo from "./BizDeployNodeConfigFormProviderQiniuKodo";
|
||||
import BizDeployNodeConfigFormProviderQiniuPili from "./BizDeployNodeConfigFormProviderQiniuPili";
|
||||
import BizDeployNodeConfigFormProviderRainYunRCDN from "./BizDeployNodeConfigFormProviderRainYunRCDN";
|
||||
import BizDeployNodeConfigFormProviderRatPanelSite from "./BizDeployNodeConfigFormProviderRatPanelSite";
|
||||
import BizDeployNodeConfigFormProviderSafeLine from "./BizDeployNodeConfigFormProviderSafeLine";
|
||||
import BizDeployNodeConfigFormProviderSSH from "./BizDeployNodeConfigFormProviderSSH";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudCDN from "./BizDeployNodeConfigFormProviderTencentCloudCDN";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudCLB from "./BizDeployNodeConfigFormProviderTencentCloudCLB";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudCOS from "./BizDeployNodeConfigFormProviderTencentCloudCOS";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudCSS from "./BizDeployNodeConfigFormProviderTencentCloudCSS";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudECDN from "./BizDeployNodeConfigFormProviderTencentCloudECDN";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudEO from "./BizDeployNodeConfigFormProviderTencentCloudEO";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudGAAP from "./BizDeployNodeConfigFormProviderTencentCloudGAAP";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudSCF from "./BizDeployNodeConfigFormProviderTencentCloudSCF";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudSSL from "./BizDeployNodeConfigFormProviderTencentCloudSSL";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudSSLDeploy from "./BizDeployNodeConfigFormProviderTencentCloudSSLDeploy";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudSSLUpdate from "./BizDeployNodeConfigFormProviderTencentCloudSSLUpdate";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudVOD from "./BizDeployNodeConfigFormProviderTencentCloudVOD";
|
||||
import BizDeployNodeConfigFormProviderTencentCloudWAF from "./BizDeployNodeConfigFormProviderTencentCloudWAF";
|
||||
import BizDeployNodeConfigFormProviderUCloudUCDN from "./BizDeployNodeConfigFormProviderUCloudUCDN";
|
||||
import BizDeployNodeConfigFormProviderUCloudUS3 from "./BizDeployNodeConfigFormProviderUCloudUS3";
|
||||
import BizDeployNodeConfigFormProviderUniCloudWebHost from "./BizDeployNodeConfigFormProviderUniCloudWebHost";
|
||||
import BizDeployNodeConfigFormProviderUpyunCDN from "./BizDeployNodeConfigFormProviderUpyunCDN";
|
||||
import BizDeployNodeConfigFormProviderUpyunFile from "./BizDeployNodeConfigFormProviderUpyunFile";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineALB from "./BizDeployNodeConfigFormProviderVolcEngineALB";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineCDN from "./BizDeployNodeConfigFormProviderVolcEngineCDN";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineCertCenter from "./BizDeployNodeConfigFormProviderVolcEngineCertCenter";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineCLB from "./BizDeployNodeConfigFormProviderVolcEngineCLB";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineDCDN from "./BizDeployNodeConfigFormProviderVolcEngineDCDN";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineImageX from "./BizDeployNodeConfigFormProviderVolcEngineImageX";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineLive from "./BizDeployNodeConfigFormProviderVolcEngineLive";
|
||||
import BizDeployNodeConfigFormProviderVolcEngineTOS from "./BizDeployNodeConfigFormProviderVolcEngineTOS";
|
||||
import BizDeployNodeConfigFormProviderWangsuCDN from "./BizDeployNodeConfigFormProviderWangsuCDN";
|
||||
import BizDeployNodeConfigFormProviderWangsuCDNPro from "./BizDeployNodeConfigFormProviderWangsuCDNPro";
|
||||
import BizDeployNodeConfigFormProviderWangsuCertificate from "./BizDeployNodeConfigFormProviderWangsuCertificate";
|
||||
import BizDeployNodeConfigFormProviderWebhook from "./BizDeployNodeConfigFormProviderWebhook";
|
||||
import { NodeType } from "../nodes/typings";
|
||||
|
||||
export interface BizDeployNodeConfigFormProps {
|
||||
form: FormInstance;
|
||||
node: FlowNodeEntity;
|
||||
}
|
||||
|
||||
const BizDeployNodeConfigForm = ({ node, ...props }: BizDeployNodeConfigFormProps) => {
|
||||
if (node.flowNodeType !== NodeType.BizDeploy) {
|
||||
console.warn(`[certimate] current workflow node type is not: ${NodeType.BizDeploy}`);
|
||||
}
|
||||
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { token: themeToken } = theme.useToken();
|
||||
|
||||
const { getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
|
||||
|
||||
const initialValues = useMemo(() => {
|
||||
return getNodeForm(node)?.getValueIn("config") as WorkflowNodeConfigForDeploy | undefined;
|
||||
}, [node]);
|
||||
|
||||
const formSchema = getSchema({ i18n });
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm({
|
||||
form: props.form,
|
||||
name: "workflowNodeBizDeployConfigForm",
|
||||
initialValues: initialValues ?? getInitialValues(),
|
||||
});
|
||||
|
||||
const fieldProvider = Form.useWatch<string>("provider", { form: formInst, preserve: true });
|
||||
|
||||
const [showProviderAccess, setShowProviderAccess] = useState(false);
|
||||
useEffect(() => {
|
||||
// 内置的部署提供商(如本地部署)无需显示授权信息字段
|
||||
if (fieldProvider) {
|
||||
const provider = deploymentProvidersMap.get(fieldProvider);
|
||||
setShowProviderAccess(!provider?.builtin);
|
||||
} else {
|
||||
setShowProviderAccess(false);
|
||||
}
|
||||
}, [fieldProvider]);
|
||||
|
||||
// TODO: 适配 flowgram
|
||||
const certificateCandidates = useMemo(() => {
|
||||
const previousNodes = getWorkflowOuptutBeforeId(node.id, "certificate");
|
||||
return previousNodes
|
||||
.filter((node) => node.type === WorkflowNodeType.Apply || node.type === WorkflowNodeType.Upload)
|
||||
.map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
options: (item.outputs ?? [])?.map((output) => {
|
||||
return {
|
||||
label: output.label,
|
||||
value: `${item.id}#${output.name}`,
|
||||
};
|
||||
}),
|
||||
};
|
||||
})
|
||||
.filter((group) => group.options.length > 0);
|
||||
}, [node.id]);
|
||||
|
||||
const NestedProviderConfigFields = useMemo(() => {
|
||||
/*
|
||||
注意:如果追加新的子组件,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new child component, please keep ASCII order.
|
||||
*/
|
||||
switch (fieldProvider) {
|
||||
case DEPLOYMENT_PROVIDERS["1PANEL_CONSOLE"]:
|
||||
return BizDeployNodeConfigFormProvider1PanelConsole;
|
||||
case DEPLOYMENT_PROVIDERS["1PANEL_SITE"]:
|
||||
return BizDeployNodeConfigFormProvider1PanelSite;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_ALB:
|
||||
return BizDeployNodeConfigFormProviderAliyunALB;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_APIGW:
|
||||
return BizDeployNodeConfigFormProviderAliyunAPIGW;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_CAS:
|
||||
return BizDeployNodeConfigFormProviderAliyunCAS;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_CAS_DEPLOY:
|
||||
return BizDeployNodeConfigFormProviderAliyunCASDeploy;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_CLB:
|
||||
return BizDeployNodeConfigFormProviderAliyunCLB;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_CDN:
|
||||
return BizDeployNodeConfigFormProviderAliyunCDN;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_DCDN:
|
||||
return BizDeployNodeConfigFormProviderAliyunDCDN;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_DDOS:
|
||||
return BizDeployNodeConfigFormProviderAliyunDDoS;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_ESA:
|
||||
return BizDeployNodeConfigFormProviderAliyunESA;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_FC:
|
||||
return BizDeployNodeConfigFormProviderAliyunFC;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_GA:
|
||||
return BizDeployNodeConfigFormProviderAliyunGA;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_LIVE:
|
||||
return BizDeployNodeConfigFormProviderAliyunLive;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_NLB:
|
||||
return BizDeployNodeConfigFormProviderAliyunNLB;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_OSS:
|
||||
return BizDeployNodeConfigFormProviderAliyunOSS;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_VOD:
|
||||
return BizDeployNodeConfigFormProviderAliyunVOD;
|
||||
case DEPLOYMENT_PROVIDERS.ALIYUN_WAF:
|
||||
return BizDeployNodeConfigFormProviderAliyunWAF;
|
||||
case DEPLOYMENT_PROVIDERS.APISIX:
|
||||
return BizDeployNodeConfigFormProviderAPISIX;
|
||||
case DEPLOYMENT_PROVIDERS.AWS_ACM:
|
||||
return BizDeployNodeConfigFormProviderAWSACM;
|
||||
case DEPLOYMENT_PROVIDERS.AWS_CLOUDFRONT:
|
||||
return BizDeployNodeConfigFormProviderAWSCloudFront;
|
||||
case DEPLOYMENT_PROVIDERS.AWS_IAM:
|
||||
return BizDeployNodeConfigFormProviderAWSIAM;
|
||||
case DEPLOYMENT_PROVIDERS.AZURE_KEYVAULT:
|
||||
return BizDeployNodeConfigFormProviderAzureKeyVault;
|
||||
case DEPLOYMENT_PROVIDERS.BAIDUCLOUD_APPBLB:
|
||||
return BizDeployNodeConfigFormProviderBaiduCloudAppBLB;
|
||||
case DEPLOYMENT_PROVIDERS.BAIDUCLOUD_BLB:
|
||||
return BizDeployNodeConfigFormProviderBaiduCloudBLB;
|
||||
case DEPLOYMENT_PROVIDERS.BAIDUCLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderBaiduCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.BAISHAN_CDN:
|
||||
return BizDeployNodeConfigFormProviderBaishanCDN;
|
||||
case DEPLOYMENT_PROVIDERS.BAOTAPANEL_CONSOLE:
|
||||
return BizDeployNodeConfigFormProviderBaotaPanelConsole;
|
||||
case DEPLOYMENT_PROVIDERS.BAOTAPANEL_SITE:
|
||||
return BizDeployNodeConfigFormProviderBaotaPanelSite;
|
||||
case DEPLOYMENT_PROVIDERS.BAOTAWAF_SITE:
|
||||
return BizDeployNodeConfigFormProviderBaotaWAFSite;
|
||||
case DEPLOYMENT_PROVIDERS.BUNNY_CDN:
|
||||
return BizDeployNodeConfigFormProviderBunnyCDN;
|
||||
case DEPLOYMENT_PROVIDERS.BYTEPLUS_CDN:
|
||||
return BizDeployNodeConfigFormProviderBytePlusCDN;
|
||||
case DEPLOYMENT_PROVIDERS.CDNFLY:
|
||||
return BizDeployNodeConfigFormProviderCdnfly;
|
||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO:
|
||||
return BizDeployNodeConfigFormProviderCTCCCloudAO;
|
||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderCTCCCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_ELB:
|
||||
return BizDeployNodeConfigFormProviderCTCCCloudELB;
|
||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN:
|
||||
return BizDeployNodeConfigFormProviderCTCCCloudICDN;
|
||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_LVDN:
|
||||
return BizDeployNodeConfigFormProviderCTCCCloudLVDN;
|
||||
case DEPLOYMENT_PROVIDERS.DOGECLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderDogeCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.EDGIO_APPLICATIONS:
|
||||
return BizDeployNodeConfigFormProviderEdgioApplications;
|
||||
case DEPLOYMENT_PROVIDERS.FLEXCDN:
|
||||
return BizDeployNodeConfigFormProviderFlexCDN;
|
||||
case DEPLOYMENT_PROVIDERS.GCORE_CDN:
|
||||
return BizDeployNodeConfigFormProviderGcoreCDN;
|
||||
case DEPLOYMENT_PROVIDERS.GOEDGE:
|
||||
return BizDeployNodeConfigFormProviderGoEdge;
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderHuaweiCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_ELB:
|
||||
return BizDeployNodeConfigFormProviderHuaweiCloudELB;
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_WAF:
|
||||
return BizDeployNodeConfigFormProviderHuaweiCloudWAF;
|
||||
case DEPLOYMENT_PROVIDERS.JDCLOUD_ALB:
|
||||
return BizDeployNodeConfigFormProviderJDCloudALB;
|
||||
case DEPLOYMENT_PROVIDERS.JDCLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderJDCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.JDCLOUD_LIVE:
|
||||
return BizDeployNodeConfigFormProviderJDCloudLive;
|
||||
case DEPLOYMENT_PROVIDERS.JDCLOUD_VOD:
|
||||
return BizDeployNodeConfigFormProviderJDCloudVOD;
|
||||
case DEPLOYMENT_PROVIDERS.KONG:
|
||||
return BizDeployNodeConfigFormProviderKong;
|
||||
case DEPLOYMENT_PROVIDERS.KUBERNETES_SECRET:
|
||||
return BizDeployNodeConfigFormProviderKubernetesSecret;
|
||||
case DEPLOYMENT_PROVIDERS.LECDN:
|
||||
return BizDeployNodeConfigFormProviderLeCDN;
|
||||
case DEPLOYMENT_PROVIDERS.LOCAL:
|
||||
return BizDeployNodeConfigFormProviderLocal;
|
||||
case DEPLOYMENT_PROVIDERS.NETLIFY_SITE:
|
||||
return BizDeployNodeConfigFormProviderNetlifySite;
|
||||
case DEPLOYMENT_PROVIDERS.PROXMOXVE:
|
||||
return BizDeployNodeConfigFormProviderProxmoxVE;
|
||||
case DEPLOYMENT_PROVIDERS.QINIU_CDN:
|
||||
return BizDeployNodeConfigFormProviderQiniuCDN;
|
||||
case DEPLOYMENT_PROVIDERS.QINIU_KODO:
|
||||
return BizDeployNodeConfigFormProviderQiniuKodo;
|
||||
case DEPLOYMENT_PROVIDERS.QINIU_PILI:
|
||||
return BizDeployNodeConfigFormProviderQiniuPili;
|
||||
case DEPLOYMENT_PROVIDERS.RAINYUN_RCDN:
|
||||
return BizDeployNodeConfigFormProviderRainYunRCDN;
|
||||
case DEPLOYMENT_PROVIDERS.RATPANEL_SITE:
|
||||
return BizDeployNodeConfigFormProviderRatPanelSite;
|
||||
case DEPLOYMENT_PROVIDERS.SAFELINE:
|
||||
return BizDeployNodeConfigFormProviderSafeLine;
|
||||
case DEPLOYMENT_PROVIDERS.SSH:
|
||||
return BizDeployNodeConfigFormProviderSSH;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_CDN:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudCDN;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_CLB:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudCLB;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_COS:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudCOS;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_CSS:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudCSS;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_ECDN:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudECDN;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_EO:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudEO;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_GAAP:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudGAAP;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SCF:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudSCF;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudSSL;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudSSLDeploy;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_UPDATE:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudSSLUpdate;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_VOD:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudVOD;
|
||||
case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_WAF:
|
||||
return BizDeployNodeConfigFormProviderTencentCloudWAF;
|
||||
case DEPLOYMENT_PROVIDERS.UCLOUD_UCDN:
|
||||
return BizDeployNodeConfigFormProviderUCloudUCDN;
|
||||
case DEPLOYMENT_PROVIDERS.UCLOUD_US3:
|
||||
return BizDeployNodeConfigFormProviderUCloudUS3;
|
||||
case DEPLOYMENT_PROVIDERS.UNICLOUD_WEBHOST:
|
||||
return BizDeployNodeConfigFormProviderUniCloudWebHost;
|
||||
case DEPLOYMENT_PROVIDERS.UPYUN_CDN:
|
||||
return BizDeployNodeConfigFormProviderUpyunCDN;
|
||||
case DEPLOYMENT_PROVIDERS.UPYUN_FILE:
|
||||
return BizDeployNodeConfigFormProviderUpyunFile;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_ALB:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineALB;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_CDN:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineCDN;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_CERTCENTER:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineCertCenter;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_CLB:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineCLB;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_DCDN:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineDCDN;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_IMAGEX:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineImageX;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_LIVE:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineLive;
|
||||
case DEPLOYMENT_PROVIDERS.VOLCENGINE_TOS:
|
||||
return BizDeployNodeConfigFormProviderVolcEngineTOS;
|
||||
case DEPLOYMENT_PROVIDERS.WANGSU_CDN:
|
||||
return BizDeployNodeConfigFormProviderWangsuCDN;
|
||||
case DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO:
|
||||
return BizDeployNodeConfigFormProviderWangsuCDNPro;
|
||||
case DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE:
|
||||
return BizDeployNodeConfigFormProviderWangsuCertificate;
|
||||
case DEPLOYMENT_PROVIDERS.WEBHOOK:
|
||||
return BizDeployNodeConfigFormProviderWebhook;
|
||||
}
|
||||
}, [fieldProvider]);
|
||||
|
||||
const handleProviderPick = (value: string) => {
|
||||
formInst.setFieldValue("provider", value);
|
||||
console.log();
|
||||
};
|
||||
|
||||
const handleProviderSelect = (value?: string | undefined) => {
|
||||
// 切换部署目标时重置表单,避免其他部署目标的配置字段影响当前部署目标
|
||||
if (initialValues?.provider === value) {
|
||||
formInst.resetFields();
|
||||
} else {
|
||||
const oldValues = formInst.getFieldsValue();
|
||||
const newValues: Record<string, unknown> = {};
|
||||
for (const key in oldValues) {
|
||||
if (key === "provider" || key === "providerAccessId" || key === "certificate" || key === "skipOnLastSucceeded") {
|
||||
newValues[key] = oldValues[key];
|
||||
} else {
|
||||
delete newValues[key];
|
||||
}
|
||||
}
|
||||
formInst.setFieldsValue(newValues);
|
||||
|
||||
if (deploymentProvidersMap.get(fieldProvider)?.provider !== deploymentProvidersMap.get(value!)?.provider) {
|
||||
formInst.setFieldValue("providerAccessId", void 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeFormContextProvider value={{ node }}>
|
||||
<Form {...formProps} clearOnDestroy={true} form={formInst} layout="vertical" preserve={false} scrollToFirstError>
|
||||
<Show when={!fieldProvider}>
|
||||
<DeploymentProviderPicker autoFocus placeholder={t("workflow_node.deploy.form.provider.search.placeholder")} onSelect={handleProviderPick} />
|
||||
</Show>
|
||||
|
||||
<div style={{ display: fieldProvider ? "block" : "none" }}>
|
||||
<div id="parameters" data-anchor="parameters">
|
||||
<Form.Item name="provider" label={t("workflow_node.deploy.form.provider.label")} rules={[formRule]}>
|
||||
<DeploymentProviderSelect
|
||||
allowClear
|
||||
disabled={!!initialValues?.provider}
|
||||
placeholder={t("workflow_node.deploy.form.provider.placeholder")}
|
||||
showSearch
|
||||
onSelect={handleProviderSelect}
|
||||
onClear={handleProviderSelect}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item hidden={!showProviderAccess} noStyle>
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">
|
||||
<span>{t("workflow_node.deploy.form.provider_access.label")}</span>
|
||||
<Tooltip title={t("workflow_node.deploy.form.provider_access.tooltip")}>
|
||||
<Typography.Text className="ms-1" type="secondary">
|
||||
<IconQuestionCircleOutlined />
|
||||
</Typography.Text>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<AccessEditDrawer
|
||||
data={{ provider: deploymentProvidersMap.get(fieldProvider!)?.provider }}
|
||||
mode="create"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.deploy.form.provider_access.button")}
|
||||
<IconPlus size="1.25em" />
|
||||
</Button>
|
||||
}
|
||||
usage="hosting"
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.HOSTING)) {
|
||||
formInst.setFieldValue("providerAccessId", record.id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="providerAccessId" rules={[formRule]}>
|
||||
<AccessSelect
|
||||
placeholder={t("workflow_node.deploy.form.provider_access.placeholder")}
|
||||
showSearch
|
||||
onFilter={(_, option) => {
|
||||
if (option.reserve) return false;
|
||||
if (fieldProvider) return deploymentProvidersMap.get(fieldProvider)?.provider === option.provider;
|
||||
|
||||
const provider = accessProvidersMap.get(option.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.HOSTING);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="certificate"
|
||||
label={t("workflow_node.deploy.form.certificate.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.certificate.tooltip") }}></span>}
|
||||
>
|
||||
<Select
|
||||
labelRender={({ label, value }) => {
|
||||
if (value != null) {
|
||||
const group = certificateCandidates.find((group) => group.options.some((option) => option.value === value));
|
||||
return `${group?.label} - ${label}`;
|
||||
}
|
||||
|
||||
return <span style={{ color: themeToken.colorTextPlaceholder }}>{t("workflow_node.deploy.form.certificate.placeholder")}</span>;
|
||||
}}
|
||||
options={certificateCandidates}
|
||||
placeholder={t("workflow_node.deploy.form.certificate.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div id="deployment" data-anchor="deployment">
|
||||
<FormNestedFieldsContextProvider value={{ parentNamePath: "providerConfig" }}>
|
||||
{NestedProviderConfigFields && (
|
||||
<>
|
||||
<Divider size="small">
|
||||
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||
{t("workflow_node.deploy.form_anchor.deployment.title")}
|
||||
</Typography.Text>
|
||||
</Divider>
|
||||
|
||||
<NestedProviderConfigFields />
|
||||
</>
|
||||
)}
|
||||
</FormNestedFieldsContextProvider>
|
||||
</div>
|
||||
|
||||
<div id="strategy" data-anchor="strategy">
|
||||
<Divider size="small">
|
||||
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||
{t("workflow_node.deploy.form_anchor.strategy.title")}
|
||||
</Typography.Text>
|
||||
</Divider>
|
||||
|
||||
<Form.Item label={t("workflow_node.deploy.form.skip_on_last_succeeded.label")}>
|
||||
<Flex align="center" gap={8} wrap="wrap">
|
||||
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}</div>
|
||||
<Form.Item name="skipOnLastSucceeded" noStyle rules={[formRule]}>
|
||||
<Switch
|
||||
checkedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.switch.on")}
|
||||
unCheckedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.switch.off")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}</div>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</NodeFormContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const getAnchorItems = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }): Required<AnchorProps>["items"] => {
|
||||
const { t } = i18n;
|
||||
|
||||
return ["parameters", "deployment", "strategy"].map((key) => ({
|
||||
key: key,
|
||||
title: t(`workflow_node.deploy.form_anchor.${key}.tab`),
|
||||
href: "#" + key,
|
||||
}));
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
certificate: "",
|
||||
provider: "",
|
||||
...defaultNodeConfigForDeploy(),
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
certificate: z.string().nonempty(t("workflow_node.deploy.form.certificate.placeholder")),
|
||||
provider: z.string().nonempty(t("workflow_node.deploy.form.provider.placeholder")),
|
||||
providerAccessId: z.string().nullish(),
|
||||
providerConfig: z.any().nullish(),
|
||||
skipOnLastSucceeded: z.boolean().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
if (values.provider) {
|
||||
const provider = deploymentProvidersMap.get(values.provider);
|
||||
if (!provider?.builtin && !values.providerAccessId) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.provider_access.placeholder"),
|
||||
path: ["providerAccessId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigForm, {
|
||||
getAnchorItems,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Switch } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProvider1PanelConsole = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "autoRestart"]}
|
||||
initialValue={initialValues.autoRestart}
|
||||
label={t("workflow_node.deploy.form.1panel_console_auto_restart.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
autoRestart: true,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
autoRestart: z.boolean().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProvider1PanelConsole, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_WEBSITE = "website" as const;
|
||||
const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProvider1PanelSite = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "nodeName"]}
|
||||
initialValue={initialValues.nodeName}
|
||||
label={t("workflow_node.deploy.form.1panel_site_node_name.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.1panel_site_node_name.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.1panel_site_node_name.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.1panel_site_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.1panel_site_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_WEBSITE} value={RESOURCE_TYPE_WEBSITE}>
|
||||
{t("workflow_node.deploy.form.1panel_site_resource_type.option.website.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_CERTIFICATE} value={RESOURCE_TYPE_CERTIFICATE}>
|
||||
{t("workflow_node.deploy.form.1panel_site_resource_type.option.certificate.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_WEBSITE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "websiteId"]}
|
||||
initialValue={initialValues.websiteId}
|
||||
label={t("workflow_node.deploy.form.1panel_site_website_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.1panel_site_website_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" placeholder={t("workflow_node.deploy.form.1panel_site_website_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.1panel_site_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.1panel_site_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" placeholder={t("workflow_node.deploy.form.1panel_site_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
resourceType: RESOURCE_TYPE_WEBSITE,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
nodeName: z.string().nullish(),
|
||||
resourceType: z.literal([RESOURCE_TYPE_WEBSITE, RESOURCE_TYPE_CERTIFICATE], t("workflow_node.deploy.form.1panel_site_resource_type.placeholder")),
|
||||
websiteId: z.union([z.string(), z.number()]).nullish(),
|
||||
certificateId: z.union([z.string(), z.number()]).nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_WEBSITE:
|
||||
{
|
||||
const res = z.preprocess((v) => Number(v), z.number().int().positive()).safeParse(values.websiteId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.1panel_site_website_id.placeholder"),
|
||||
path: ["websiteId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
{
|
||||
const res = z.preprocess((v) => Number(v), z.number().int().positive()).safeParse(values.certificateId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.1panel_site_certificate_id.placeholder"),
|
||||
path: ["websiteId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProvider1PanelSite, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,91 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAPISIX = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.apisix_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.apisix_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_CERTIFICATE} value={RESOURCE_TYPE_CERTIFICATE}>
|
||||
{t("workflow_node.deploy.form.apisix_resource_type.option.certificate.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.apisix_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.apisix_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.apisix_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
resourceType: RESOURCE_TYPE_CERTIFICATE,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
resourceType: z.literal(RESOURCE_TYPE_CERTIFICATE, t("workflow_node.deploy.form.apisix_resource_type.placeholder")),
|
||||
certificateId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
{
|
||||
if (!values.certificateId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.apisix_certificate_id.placeholder"),
|
||||
path: ["certificateId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAPISIX, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,63 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAWSACM = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aws_acm_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_acm_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_acm_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateArn"]}
|
||||
initialValue={initialValues.certificateArn}
|
||||
label={t("workflow_node.deploy.form.aws_acm_certificate_arn.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_acm_certificate_arn.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aws_acm_certificate_arn.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aws_acm_region.placeholder")),
|
||||
certificateArn: z.string().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAWSACM, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAWSCloudFront = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aws_cloudfront_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_cloudfront_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_cloudfront_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "distributionId"]}
|
||||
initialValue={initialValues.distributionId}
|
||||
label={t("workflow_node.deploy.form.aws_cloudfront_distribution_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateSource"]}
|
||||
initialValue={initialValues.certificateSource}
|
||||
label={t("workflow_node.deploy.form.aws_cloudfront_certificate_source.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aws_cloudfront_certificate_source.placeholder")}>
|
||||
<Select.Option key="ACM" value="ACM">
|
||||
ACM
|
||||
</Select.Option>
|
||||
<Select.Option key="IAM" value="IAM">
|
||||
IAM
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
certificateSource: "ACM",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aws_cloudfront_region.placeholder")),
|
||||
distributionId: z.string().nonempty(t("workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder")),
|
||||
certificateSource: z.string().nonempty(t("workflow_node.deploy.form.aws_cloudfront_certificate_source.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAWSCloudFront, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,70 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAWSIAM = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aws_iam_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_iam_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_iam_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificatePath"]}
|
||||
initialValue={initialValues.certificatePath}
|
||||
label={t("workflow_node.deploy.form.aws_iam_certificate_path.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_iam_certificate_path.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aws_iam_certificate_path.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
certificatePath: "/",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aws_iam_region.placeholder")),
|
||||
certificatePath: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
return v.startsWith("/") && v.endsWith("/");
|
||||
}, t("workflow_node.deploy.form.aws_iam_certificate_path.errmsg.invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAWSIAM, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunALB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_alb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_alb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_alb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.aliyun_alb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_alb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.aliyun_alb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_alb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_alb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_alb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerId"]}
|
||||
initialValue={initialValues.listenerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_alb_listener_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_alb_listener_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_alb_listener_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_alb_snidomain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_alb_snidomain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aliyun_alb_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_alb_region.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.aliyun_alb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nullish(),
|
||||
listenerId: z.string().nullish(),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LOADBALANCER:
|
||||
{
|
||||
const res = z.string().nonempty().safeParse(values.loadbalancerId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_alb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
const res = z.string().nonempty().safeParse(values.listenerId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_alb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunALB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const SERVICE_TYPE_CLOUDNATIVE = "cloudnative" as const;
|
||||
const SERVICE_TYPE_TRADITIONAL = "traditional" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunAPIGW = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldServiceType = Form.useWatch([parentNamePath, "serviceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "serviceType"]}
|
||||
initialValue={initialValues.serviceType}
|
||||
label={t("workflow_node.deploy.form.aliyun_apigw_service_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_apigw_service_type.placeholder")}>
|
||||
<Select.Option key={SERVICE_TYPE_CLOUDNATIVE} value={SERVICE_TYPE_CLOUDNATIVE}>
|
||||
{t("workflow_node.deploy.form.aliyun_apigw_service_type.option.cloudnative.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={SERVICE_TYPE_TRADITIONAL} value={SERVICE_TYPE_TRADITIONAL}>
|
||||
{t("workflow_node.deploy.form.aliyun_apigw_service_type.option.traditional.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_apigw_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_apigw_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_apigw_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldServiceType === SERVICE_TYPE_CLOUDNATIVE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "gatewayId"]}
|
||||
initialValue={initialValues.gatewayId}
|
||||
label={t("workflow_node.deploy.form.aliyun_apigw_gateway_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_apigw_gateway_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_apigw_gateway_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldServiceType === SERVICE_TYPE_TRADITIONAL}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "groupId"]}
|
||||
initialValue={initialValues.groupId}
|
||||
label={t("workflow_node.deploy.form.aliyun_apigw_group_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_apigw_group_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_apigw_group_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_apigw_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_apigw_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_apigw_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
serviceType: z.literal([SERVICE_TYPE_CLOUDNATIVE, SERVICE_TYPE_TRADITIONAL], t("workflow_node.deploy.form.aliyun_apigw_service_type.placeholder")),
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_apigw_region.placeholder")),
|
||||
gatewayId: z.string().nullish(),
|
||||
groupId: z.string().nullish(),
|
||||
domain: z
|
||||
.string()
|
||||
.nonempty(t("workflow_node.deploy.form.aliyun_apigw_domain.placeholder"))
|
||||
.refine((v) => validDomainName(v!, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.serviceType) {
|
||||
case SERVICE_TYPE_CLOUDNATIVE:
|
||||
{
|
||||
if (!values.gatewayId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_apigw_gateway_id.placeholder"),
|
||||
path: ["gatewayId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SERVICE_TYPE_TRADITIONAL:
|
||||
{
|
||||
if (!values.groupId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_apigw_group_id.placeholder"),
|
||||
path: ["groupId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunAPIGW, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunCAS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_cas_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_cas_region.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_cas_region.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunCAS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Alert, Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const MULTIPLE_INPUT_SEPARATOR = ";";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunCASDeploy = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item>
|
||||
<Alert type="info" message={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy.guide") }}></span>} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_cas_deploy_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceIds"]}
|
||||
initialValue={initialValues.resourceIds}
|
||||
label={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.tooltip") }}></span>}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.placeholder")}
|
||||
placeholderInModal={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "contactIds"]}
|
||||
initialValue={initialValues.contactIds}
|
||||
label={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.tooltip") }}></span>}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.placeholder")}
|
||||
placeholderInModal={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceIds: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder")),
|
||||
resourceIds: z.string().refine((v) => {
|
||||
if (!v) return false;
|
||||
return String(v)
|
||||
.split(MULTIPLE_INPUT_SEPARATOR)
|
||||
.every((e) => /^[1-9]\d*$/.test(e));
|
||||
}, t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.errmsg.invalid")),
|
||||
contactIds: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
return String(v)
|
||||
.split(MULTIPLE_INPUT_SEPARATOR)
|
||||
.every((e) => /^[1-9]\d*$/.test(e));
|
||||
}, t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.errmsg.invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunCASDeploy, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName, validPortNumber } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunCLB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_clb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_clb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_clb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.aliyun_clb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_clb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.aliyun_clb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.aliyun_clb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerPort"]}
|
||||
initialValue={initialValues.listenerPort}
|
||||
label={t("workflow_node.deploy.form.aliyun_clb_listener_port.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_clb_listener_port.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" min={1} max={65535} placeholder={t("workflow_node.deploy.form.aliyun_clb_listener_port.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_clb_snidomain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_clb_snidomain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aliyun_clb_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
loadbalancerId: "",
|
||||
listenerPort: 443,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_clb_region.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.aliyun_clb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nonempty(t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder")),
|
||||
listenerPort: z.preprocess((v) => (v == null || v === "" ? undefined : Number(v)), z.number().nullish()),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!validPortNumber(values.listenerPort!)) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_clb_listener_port.placeholder"),
|
||||
path: ["listenerPort"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunCLB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunDCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_dcdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_dcdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_dcdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunDCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunDDoS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_ddos_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_ddos_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_ddos_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_ddos_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_ddos_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_ddos_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_ddos_region.placeholder")),
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunDDoS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunESA = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_esa_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_esa_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_esa_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteId"]}
|
||||
initialValue={initialValues.siteId}
|
||||
label={t("workflow_node.deploy.form.aliyun_esa_site_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_esa_site_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" placeholder={t("workflow_node.deploy.form.aliyun_esa_site_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
siteId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_esa_region.placeholder")),
|
||||
siteId: z.union([z.string(), z.number().int()]).refine((v) => {
|
||||
return /^\d+$/.test(v + "") && +v > 0;
|
||||
}, t("workflow_node.deploy.form.aliyun_esa_site_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunESA, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,84 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunFC = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_fc_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_fc_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_fc_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "serviceVersion"]}
|
||||
initialValue={initialValues.serviceVersion}
|
||||
label={t("workflow_node.deploy.form.aliyun_fc_service_version.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_fc_service_version.placeholder")}>
|
||||
<Select.Option key="2.0" value="2.0">
|
||||
2.0
|
||||
</Select.Option>
|
||||
<Select.Option key="3.0" value="3.0">
|
||||
3.0
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_fc_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_fc_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_fc_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
serviceVersion: "3.0",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_fc_region.placeholder")),
|
||||
serviceVersion: z.literal(["2.0", "3.0"], t("workflow_node.deploy.form.aliyun_fc_service_version.placeholder")),
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunFC, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_ACCELERATOR = "accelerator" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunGA = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.aliyun_ga_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_ga_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_ACCELERATOR} value={RESOURCE_TYPE_ACCELERATOR}>
|
||||
{t("workflow_node.deploy.form.aliyun_ga_resource_type.option.accelerator.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.aliyun_ga_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "acceleratorId"]}
|
||||
initialValue={initialValues.acceleratorId}
|
||||
label={t("workflow_node.deploy.form.aliyun_ga_accelerator_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_ga_accelerator_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_ga_accelerator_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerId"]}
|
||||
initialValue={initialValues.listenerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_ga_listener_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_ga_listener_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_ga_listener_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_ACCELERATOR || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_ga_snidomain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_ga_snidomain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aliyun_ga_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
acceleratorId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
resourceType: z.literal([RESOURCE_TYPE_ACCELERATOR, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.aliyun_ga_resource_type.placeholder")),
|
||||
acceleratorId: z.string().nonempty(t("workflow_node.deploy.form.aliyun_ga_accelerator_id.placeholder")),
|
||||
listenerId: z.string().nullish(),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!);
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!values.listenerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_ga_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunGA, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunLive = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_live_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_live_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_live_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_live_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_live_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_live_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_live_region.placeholder")),
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunLive, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunNLB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_nlb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_nlb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_nlb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.aliyun_nlb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.aliyun_nlb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.aliyun_nlb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerId"]}
|
||||
initialValue={initialValues.listenerId}
|
||||
label={t("workflow_node.deploy.form.aliyun_nlb_listener_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_nlb_listener_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_nlb_listener_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_nlb_region.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nullish(),
|
||||
listenerId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LOADBALANCER:
|
||||
{
|
||||
if (!values.loadbalancerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!values.listenerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.aliyun_nlb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunNLB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunOSS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_oss_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_oss_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_oss_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "bucket"]}
|
||||
initialValue={initialValues.bucket}
|
||||
label={t("workflow_node.deploy.form.aliyun_oss_bucket.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_oss_bucket.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_oss_bucket.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_oss_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_oss_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_oss_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
bucket: "",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_oss_region.placeholder")),
|
||||
bucket: z.string().nonempty(t("workflow_node.deploy.form.aliyun_oss_bucket.placeholder")),
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunOSS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunVOD = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_vod_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_vod_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_vod_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_vod_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_vod_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_vod_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_vod_region.placeholder")),
|
||||
domain: z.string().refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunVOD, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAliyunWAF = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.aliyun_waf_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_waf_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_waf_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "serviceVersion"]}
|
||||
initialValue={initialValues.serviceVersion}
|
||||
label={t("workflow_node.deploy.form.aliyun_waf_service_version.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.aliyun_waf_service_version.placeholder")}>
|
||||
<Select.Option key="3.0" value="3.0">
|
||||
3.0
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "instanceId"]}
|
||||
initialValue={initialValues.instanceId}
|
||||
label={t("workflow_node.deploy.form.aliyun_waf_instance_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_waf_instance_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.aliyun_waf_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_waf_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.aliyun_waf_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
serviceVersion: "3.0",
|
||||
instanceId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.aliyun_waf_region.placeholder")),
|
||||
serviceVersion: z.literal("3.0", t("workflow_node.deploy.form.aliyun_waf_service_version.placeholder")),
|
||||
instanceId: z.string().nonempty(t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder")),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAliyunWAF, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderAzureKeyVault = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "keyvaultName"]}
|
||||
initialValue={initialValues.keyvaultName}
|
||||
label={t("workflow_node.deploy.form.azure_keyvault_name.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.azure_keyvault_name.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.azure_keyvault_name.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateName"]}
|
||||
initialValue={initialValues.certificateName}
|
||||
label={t("workflow_node.deploy.form.azure_keyvault_certificate_name.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.azure_keyvault_certificate_name.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.azure_keyvault_certificate_name.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
keyvaultName: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
keyvaultName: z.string().nonempty(t("workflow_node.deploy.form.azure_keyvault_name.placeholder")),
|
||||
certificateName: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
return /^[a-zA-Z0-9-]{1,127}$/.test(v);
|
||||
}, t("workflow_node.deploy.form.azure_keyvault_certificate_name.errmsg.invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderAzureKeyVault, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName, validPortNumber } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaiduCloudAppBLB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.baiducloud_appblb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_appblb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baiducloud_appblb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.baiducloud_appblb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.baiducloud_appblb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.baiducloud_appblb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.baiducloud_appblb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.baiducloud_appblb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_appblb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baiducloud_appblb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerPort"]}
|
||||
initialValue={initialValues.listenerPort}
|
||||
label={t("workflow_node.deploy.form.baiducloud_appblb_listener_port.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_appblb_listener_port.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" min={1} max={65535} placeholder={t("workflow_node.deploy.form.baiducloud_appblb_listener_port.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.baiducloud_appblb_snidomain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_appblb_snidomain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.baiducloud_appblb_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
loadbalancerId: "",
|
||||
listenerPort: 443,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.baiducloud_appblb_region.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.baiducloud_appblb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nonempty(t("workflow_node.deploy.form.baiducloud_appblb_loadbalancer_id.placeholder")),
|
||||
listenerPort: z.preprocess((v) => (v == null || v === "" ? undefined : Number(v)), z.number().nullish()),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!validPortNumber(values.listenerPort!)) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.baiducloud_appblb_listener_port.placeholder"),
|
||||
path: ["listenerPort"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaiduCloudAppBLB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName, validPortNumber } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaiduCloudBLB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.baiducloud_blb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_blb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baiducloud_blb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.baiducloud_blb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.baiducloud_blb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.baiducloud_blb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.baiducloud_blb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.baiducloud_blb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_blb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baiducloud_blb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerPort"]}
|
||||
initialValue={initialValues.listenerPort}
|
||||
label={t("workflow_node.deploy.form.baiducloud_blb_listener_port.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_blb_listener_port.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" min={1} max={65535} placeholder={t("workflow_node.deploy.form.baiducloud_blb_listener_port.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.baiducloud_blb_snidomain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_blb_snidomain.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.baiducloud_blb_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
loadbalancerId: "",
|
||||
listenerPort: 443,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.baiducloud_blb_region.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.baiducloud_blb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nonempty(t("workflow_node.deploy.form.baiducloud_blb_loadbalancer_id.placeholder")),
|
||||
listenerPort: z.preprocess((v) => (v == null || v === "" ? undefined : Number(v)), z.number().nullish()),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!validPortNumber(values.listenerPort!)) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.baiducloud_blb_listener_port.placeholder"),
|
||||
path: ["listenerPort"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaiduCloudBLB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaiduCloudCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.baiducloud_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baiducloud_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baiducloud_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaiduCloudCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaishanCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.baishan_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baishan_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baishan_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.baishan_cdn_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baishan_cdn_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear type="number" placeholder={t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
certificateId: z
|
||||
.union([z.string(), z.number().int()])
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
return /^\d+$/.test(v + "") && +v > 0;
|
||||
}, t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaishanCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Switch } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaotaPanelConsole = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "autoRestart"]}
|
||||
initialValue={initialValues.autoRestart}
|
||||
label={t("workflow_node.deploy.form.baotapanel_console_auto_restart.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
autoRestart: true,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
autoRestart: z.boolean().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaotaPanelConsole, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const SITE_TYPE_PHP = "php";
|
||||
const SITE_TYPE_OTHER = "other";
|
||||
|
||||
const MULTIPLE_INPUT_SEPARATOR = ";";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaotaPanelSite = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldSiteType = Form.useWatch([parentNamePath, "siteType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteType"]}
|
||||
initialValue={initialValues.siteType}
|
||||
label={t("workflow_node.deploy.form.baotapanel_site_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.baotapanel_site_type.placeholder")}>
|
||||
<Select.Option key={SITE_TYPE_PHP} value={SITE_TYPE_PHP}>
|
||||
{t("workflow_node.deploy.form.baotapanel_site_type.option.php.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={SITE_TYPE_OTHER} value={SITE_TYPE_OTHER}>
|
||||
{t("workflow_node.deploy.form.baotapanel_site_type.option.other.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldSiteType === SITE_TYPE_PHP}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteName"]}
|
||||
initialValue={initialValues.siteName}
|
||||
label={t("workflow_node.deploy.form.baotapanel_site_name.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baotapanel_site_name.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baotapanel_site_name.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldSiteType === SITE_TYPE_OTHER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteNames"]}
|
||||
initialValue={initialValues.siteNames}
|
||||
label={t("workflow_node.deploy.form.baotapanel_site_names.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baotapanel_site_names.tooltip") }}></span>}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.deploy.form.baotapanel_site_names.placeholder")}
|
||||
placeholderInModal={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
siteType: SITE_TYPE_OTHER,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
siteType: z.literal([SITE_TYPE_PHP, SITE_TYPE_OTHER], t("workflow_node.deploy.form.baotapanel_site_type.placeholder")),
|
||||
siteName: z.string().nullish(),
|
||||
siteNames: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.siteType) {
|
||||
case SITE_TYPE_PHP:
|
||||
{
|
||||
if (!values.siteName?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.baotapanel_site_name.placeholder"),
|
||||
path: ["siteName"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SITE_TYPE_OTHER:
|
||||
{
|
||||
if (!values.siteNames?.trim() || !values.siteNames.split(MULTIPLE_INPUT_SEPARATOR).every((e) => !!e.trim())) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.baotapanel_site_names.placeholder"),
|
||||
path: ["siteNames"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaotaPanelSite, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, InputNumber } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validPortNumber } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBaotaWAFSite = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteName"]}
|
||||
initialValue={initialValues.siteName}
|
||||
label={t("workflow_node.deploy.form.baotawaf_site_name.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baotawaf_site_name.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baotawaf_site_name.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "sitePort"]}
|
||||
initialValue={initialValues.sitePort}
|
||||
label={t("workflow_node.deploy.form.baotawaf_site_port.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<InputNumber style={{ width: "100%" }} placeholder={t("access.form.ssh_port.placeholder")} min={1} max={65535} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
siteName: "",
|
||||
sitePort: 443,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
siteName: z.string().nonempty(t("workflow_node.deploy.form.baotawaf_site_name.placeholder")),
|
||||
sitePort: z.preprocess(
|
||||
(v) => Number(v),
|
||||
z
|
||||
.number()
|
||||
.int(t("workflow_node.deploy.form.baotawaf_site_port.placeholder"))
|
||||
.refine((v) => validPortNumber(v), t("common.errmsg.port_invalid"))
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBaotaWAFSite, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,72 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBunnyCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "pullZoneId"]}
|
||||
initialValue={initialValues.pullZoneId}
|
||||
label={t("workflow_node.deploy.form.bunny_cdn_pull_zone_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.bunny_cdn_pull_zone_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.bunny_cdn_pull_zone_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "hostname"]}
|
||||
initialValue={initialValues.hostname}
|
||||
label={t("workflow_node.deploy.form.bunny_cdn_hostname.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.bunny_cdn_hostname.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.bunny_cdn_hostname.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
pullZoneId: "",
|
||||
hostname: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
pullZoneId: z.union([z.string(), z.number().int()]).refine((v) => {
|
||||
return /^\d+$/.test(v + "") && +v! > 0;
|
||||
}, t("workflow_node.deploy.form.bunny_cdn_pull_zone_id.placeholder")),
|
||||
hostname: z
|
||||
.string()
|
||||
.nonempty(t("workflow_node.deploy.form.bunny_cdn_hostname.placeholder"))
|
||||
.refine((v) => {
|
||||
return validDomainName(v!, { allowWildcard: true });
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBunnyCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderBytePlusCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.byteplus_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.byteplus_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.byteplus_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderBytePlusCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderCTCCCloudAO = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_ao_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_ao_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_ao_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCTCCCloudAO, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderCTCCCloudCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCTCCCloudCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderCTCCCloudELB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "regionId"]}
|
||||
initialValue={initialValues.regionId}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_elb_region_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_region_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_elb_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||
{t("workflow_node.deploy.form.ctcccloud_elb_resource_type.option.loadbalancer.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||
{t("workflow_node.deploy.form.ctcccloud_elb_resource_type.option.listener.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerId"]}
|
||||
initialValue={initialValues.listenerId}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_elb_listener_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_listener_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
regionId: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
regionId: z.string().nonempty(t("workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder")),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder")),
|
||||
loadbalancerId: z.string().nullish(),
|
||||
listenerId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LOADBALANCER:
|
||||
{
|
||||
if (!values.loadbalancerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder"),
|
||||
path: ["loadbalancerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!values.listenerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCTCCCloudELB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderCTCCCloudICDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_icdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_icdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_icdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCTCCCloudICDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderCTCCCloudLVDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ctcccloud_lvdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_lvdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_lvdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCTCCCloudLVDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -0,0 +1,122 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_SITE = "site" as const;
|
||||
const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const BizDeployNodeConfigFormProviderCdnfly = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.cdnfly_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select placeholder={t("workflow_node.deploy.form.cdnfly_resource_type.placeholder")}>
|
||||
<Select.Option key={RESOURCE_TYPE_SITE} value={RESOURCE_TYPE_SITE}>
|
||||
{t("workflow_node.deploy.form.cdnfly_resource_type.option.site.label")}
|
||||
</Select.Option>
|
||||
<Select.Option key={RESOURCE_TYPE_CERTIFICATE} value={RESOURCE_TYPE_CERTIFICATE}>
|
||||
{t("workflow_node.deploy.form.cdnfly_resource_type.option.certificate.label")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_SITE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "siteId"]}
|
||||
initialValue={initialValues.siteId}
|
||||
label={t("workflow_node.deploy.form.cdnfly_site_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.cdnfly_site_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" placeholder={t("workflow_node.deploy.form.cdnfly_site_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.cdnfly_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.cdnfly_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input type="number" placeholder={t("workflow_node.deploy.form.cdnfly_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
resourceType: RESOURCE_TYPE_SITE,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
resourceType: z.literal([RESOURCE_TYPE_SITE, RESOURCE_TYPE_CERTIFICATE], t("workflow_node.deploy.form.cdnfly_resource_type.placeholder")),
|
||||
siteId: z.union([z.string(), z.number().int()]).nullish(),
|
||||
certificateId: z.union([z.string(), z.number().int()]).nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_SITE:
|
||||
{
|
||||
const res = z.preprocess((v) => Number(v), z.number().int().positive()).safeParse(values.siteId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.cdnfly_site_id.placeholder"),
|
||||
path: ["siteId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
{
|
||||
const res = z.preprocess((v) => Number(v), z.number().int().positive()).safeParse(values.certificateId);
|
||||
if (!res.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.cdnfly_certificate_id.placeholder"),
|
||||
path: ["certificateId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderCdnfly, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderDogeCloudCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.dogecloud_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.dogecloud_cdn_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.dogecloud_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
domain: z.string().refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderDogeCloudCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFormProviderEdgioApplications = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "environmentId"]}
|
||||
initialValue={initialValues.environmentId}
|
||||
label={t("workflow_node.deploy.form.edgio_applications_environment_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.edgio_applications_environment_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.edgio_applications_environment_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
environmentId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
environmentId: z.string().nonempty(t("workflow_node.deploy.form.edgio_applications_environment_id.placeholder")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFormProviderEdgioApplications, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user