This commit is contained in:
RHQYZ
2025-07-22 22:22:08 +08:00
committed by GitHub
329 changed files with 6515 additions and 6770 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
{
"recommendations": [
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode"
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
]
}
+2 -2
View File
@@ -5,7 +5,7 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
"go.useLanguageServer": true,
"gopls": {
@@ -18,4 +18,4 @@
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
}
+21 -21
View File
@@ -1,53 +1,53 @@
{
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
"url": "https://tailwindcss.com/docs/functions-and-directives#variant-directive"
}
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"name": "@source",
"description": "Use the `@source` directive to explicitly specify source files that aren't picked up by Tailwind's automatic content detection.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
"url": "https://tailwindcss.com/docs/functions-and-directives#source-directive"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"name": "@theme",
"description": "Use the `@theme` directive to define your project's custom design tokens, like fonts, colors, and breakpoints.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
"url": "https://tailwindcss.com/docs/functions-and-directives#theme-directive"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"name": "@utility",
"description": "Use the `@utility` directive to add custom utilities to your project that work with variants like `hover`, `focus` and `lg`.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
"url": "https://tailwindcss.com/docs/functions-and-directives#utility-directive"
}
]
},
{
"name": "@variant",
"description": "Use the `@variant` directive to apply a Tailwind variant to styles in your CSS",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variant-directive"
}
]
}
+2 -2
View File
@@ -21,7 +21,7 @@
### 要求
- Go 1.24+(用于修改后端代码)
- Node.js 22.0+(用于修改前端代码)
- Node.js 22.12+(用于修改前端代码)
### 后端代码
@@ -74,7 +74,7 @@ npm run build
**在向主仓库提交 PR 之前,你应该:**
- 使用 [ESLint](https://github.com/eslint/eslint) 格式化你的代码。推荐使用 VSCode,并安装 ESLint+Prettier 插件,以便在保存时自动格式化。
- 使用 [ESLint](https://github.com/eslint/eslint) 格式化你的代码。推荐使用 VSCode,并安装 ESLint 插件,以便在保存时自动格式化。
## 提交 PR
+1 -1
View File
@@ -21,7 +21,7 @@ Index:
### Prerequisites
- Go 1.24+ (for backend code changes)
- Node.js 22.0+ (for frontend code changes)
- Node.js 22.12+ (for frontend code changes)
### Backend Code
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:20-alpine3.19 AS webui-builder
FROM node:22-alpine AS webui-builder
WORKDIR /app
COPY . /app/
RUN \
-112
View File
@@ -1,112 +0,0 @@
/**
* @type {import("eslint").Linter.Config}
*/
module.exports = {
root: true,
env: {
browser: true,
node: true,
es2020: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:prettier/recommended",
"plugin:react-hooks/recommended",
"plugin:tailwindcss/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-empty-object-type": [
"error",
{
allowInterfaces: "with-single-extends",
},
],
"@typescript-eslint/no-explicit-any": [
"warn",
{
ignoreRestArgs: true,
},
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
},
],
"import/no-named-as-default-member": "off",
"import/no-unresolved": "off",
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", ["parent", "sibling"], "index"],
pathGroups: [
{
pattern: "react*",
group: "external",
position: "before",
},
{
pattern: "react/**",
group: "external",
position: "before",
},
{
pattern: "react-*",
group: "external",
position: "before",
},
{
pattern: "react-*/**",
group: "external",
position: "before",
},
{
pattern: "~/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["builtin"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
"react-refresh/only-export-components": [
"warn",
{
allowConstantExport: true,
},
],
"sort-imports": [
"error",
{
ignoreDeclarationSort: true,
},
],
"tailwindcss/no-custom-classname": "off",
},
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
},
},
};
-17
View File
@@ -1,17 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/global.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/components/ui/utils"
}
}
+153
View File
@@ -0,0 +1,153 @@
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tailwindcssPlugin from "eslint-plugin-better-tailwindcss";
import importPlugin from "eslint-plugin-import";
import prettierPluginConfig from "eslint-plugin-prettier/recommended";
import reactHooksPlugin from "eslint-plugin-react-hooks";
import reactRefreshPlugin from "eslint-plugin-react-refresh";
import typescriptPlugin from "typescript-eslint";
/**
* @type {import("eslint").Linter.Config[]}
*/
export default defineConfig(
// Basic
eslint.configs["recommended"],
{
name: "eslint/import",
extends: [importPlugin.flatConfigs["recommended"], importPlugin.flatConfigs["typescript"]],
rules: {
"import/no-named-as-default-member": "off",
"import/no-unresolved": "off",
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", ["parent", "sibling"], "index"],
pathGroups: [
{
pattern: "react*",
group: "external",
position: "before",
},
{
pattern: "react/**",
group: "external",
position: "before",
},
{
pattern: "react-*",
group: "external",
position: "before",
},
{
pattern: "react-*/**",
group: "external",
position: "before",
},
{
pattern: "~/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["builtin"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
"sort-imports": [
"error",
{
ignoreDeclarationSort: true,
},
],
},
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
},
// Typescript
{
name: "typescript",
extends: [typescriptPlugin.configs["recommended"]],
rules: {
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-empty-object-type": [
"error",
{
allowInterfaces: "with-single-extends",
},
],
"@typescript-eslint/no-explicit-any": [
"warn",
{
ignoreRestArgs: true,
},
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
},
],
},
},
// Pretter
{
name: "prettier",
extends: [prettierPluginConfig],
},
// React
{
name: "react",
extends: [reactHooksPlugin.configs["recommended-latest"], reactRefreshPlugin.configs["vite"]],
rules: {
"react-refresh/only-export-components": [
"warn",
{
allowConstantExport: true,
},
],
},
},
// TailwindCSS
{
name: "tailwindcss",
plugins: {
"better-tailwindcss": tailwindcssPlugin,
},
rules: {
...tailwindcssPlugin.configs["recommended-warn"].rules,
...tailwindcssPlugin.configs["recommended-error"].rules,
"better-tailwindcss/enforce-consistent-line-wrapping": "off",
"better-tailwindcss/no-unregistered-classes": "off",
},
settings: {
"better-tailwindcss": {
entryPoint: "src/global.css",
},
},
}
);
+1700 -1713
View File
File diff suppressed because it is too large Load Diff
+29 -31
View File
@@ -10,63 +10,61 @@
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons": "^6.0.0",
"@ant-design/pro-components": "^2.8.9",
"@ant-design/pro-components": "^2.8.10",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/language": "^6.11.1",
"@codemirror/language": "^6.11.2",
"@codemirror/legacy-modes": "^6.5.1",
"@uiw/codemirror-extensions-basic-setup": "^4.23.13",
"@uiw/codemirror-theme-vscode": "^4.23.13",
"@uiw/react-codemirror": "^4.23.13",
"ahooks": "^3.8.5",
"antd": "^5.26.1",
"@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",
"ahooks": "^3.9.0",
"antd": "^5.26.6",
"antd-zod": "^7.0.0",
"clsx": "^2.1.1",
"cron-parser": "^5.3.0",
"file-saver": "^2.0.5",
"i18next": "^25.2.1",
"i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0",
"immer": "^10.1.1",
"lucide-react": "^0.522.0",
"nanoid": "^5.1.5",
"pocketbase": "^0.26.1",
"radash": "^12.1.1",
"react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.3.1",
"react-i18next": "^15.5.3",
"react-router-dom": "^7.6.2",
"tailwind-merge": "^2.6.0",
"zod": "^3.25.67",
"zustand": "^5.0.5"
"react-i18next": "^15.6.0",
"react-router-dom": "^7.7.0",
"tailwind-merge": "^3.3.1",
"zod": "^4.0.5",
"zustand": "^5.0.6"
},
"devDependencies": {
"@eslint/js": "^9.31.0",
"@tailwindcss/postcss": "^4.1.11",
"@tailwindcss/vite": "^4.1.11",
"@types/file-saver": "^2.0.7",
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.15.17",
"@types/react": "^18.3.12",
"@types/node": "^22.16.5",
"@types/react": "^18.3.19",
"@types/react-copy-to-clipboard": "^5.0.7",
"@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.34.1",
"@typescript-eslint/parser": "^8.34.1",
"@types/react-dom": "^18.3.7",
"@vitejs/plugin-legacy": "^6.1.1",
"@vitejs/plugin-react": "^4.6.0",
"autoprefixer": "^10.4.21",
"eslint": "^8.57.0",
"eslint-config-prettier": "^10.1.5",
"eslint-import-resolver-typescript": "^3.8.3",
"@vitejs/plugin-react": "^4.7.0",
"eslint": "^9.31.0",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-better-tailwindcss": "^3.7.0",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.0",
"eslint-plugin-prettier": "^5.5.3",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"eslint-plugin-tailwindcss": "^3.18.0",
"fs-extra": "^11.3.0",
"postcss": "^8.5.6",
"prettier": "^3.6.0",
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"prettier": "^3.6.2",
"tailwindcss": "^4.1.11",
"typescript": "^5.8.3",
"typescript-eslint": "^8.37.0",
"vite": "^6.3.5"
}
}
-6
View File
@@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
@@ -1,7 +1,7 @@
/**
* @type {import("prettier").Config}
*/
module.exports = {
export default {
arrowParens: "always",
bracketSpacing: true,
editorconfig: true,
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

+58 -22
View File
@@ -1,4 +1,4 @@
import { useEffect, useLayoutEffect, useMemo, useState } from "react";
import { useEffect, useLayoutEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { RouterProvider } from "react-router-dom";
import { App, ConfigProvider, type ThemeConfig, theme } from "antd";
@@ -10,25 +10,30 @@ import "dayjs/locale/zh-cn";
import { useBrowserTheme } from "@/hooks";
import { localeNames } from "@/i18n";
import { router } from "@/router.tsx";
import { router } from "@/routers";
const antdLocalesMap: Record<string, Locale> = {
[localeNames.ZH]: AntdLocaleZhCN,
[localeNames.EN]: AntdLocaleEnUs,
};
const antdThemesMap: Record<string, ThemeConfig> = {
["light"]: { algorithm: theme.defaultAlgorithm },
["dark"]: { algorithm: theme.darkAlgorithm },
};
const RootApp = () => {
const { i18n } = useTranslation();
const { theme: browserTheme } = useBrowserTheme();
const antdLocalesMap: Record<string, Locale> = useMemo(
() => ({
[localeNames.ZH]: AntdLocaleZhCN,
[localeNames.EN]: AntdLocaleEnUs,
}),
[]
);
const [antdLocale, setAntdLocale] = useState(antdLocalesMap[i18n.language]);
const [antdTheme, setAntdTheme] = useState(antdThemesMap[browserTheme]);
const handleLanguageChanged = () => {
setAntdLocale(antdLocalesMap[i18n.language]);
dayjs.locale(i18n.language);
};
i18n.on("languageChanged", handleLanguageChanged);
useLayoutEffect(() => {
handleLanguageChanged();
@@ -36,23 +41,15 @@ const RootApp = () => {
return () => {
i18n.off("languageChanged", handleLanguageChanged);
};
}, [antdLocalesMap, i18n]);
}, [i18n]);
const antdThemesMap: Record<string, ThemeConfig> = useMemo(
() => ({
["light"]: { algorithm: theme.defaultAlgorithm },
["dark"]: { algorithm: theme.darkAlgorithm },
}),
[]
);
const [antdTheme, setAntdTheme] = useState(antdThemesMap[browserTheme]);
useEffect(() => {
setAntdTheme(antdThemesMap[browserTheme]);
const root = window.document.documentElement;
root.classList.remove("light", "dark");
root.classList.add(browserTheme);
}, [antdThemesMap, browserTheme]);
}, [browserTheme]);
return (
<ConfigProvider
@@ -60,9 +57,48 @@ const RootApp = () => {
theme={{
...antdTheme,
token: {
/* @see tailwind.config.js */
colorPrimary: browserTheme === "dark" ? "hsl(20.5 90.2% 48.2%)" : "hsl(24.6 95% 53.1%)",
colorLink: browserTheme === "dark" ? "hsl(20.5 90.2% 48.2%)" : "hsl(24.6 95% 53.1%)",
/* @see global.css, YOU MUST MODIFY BOTH DEFINITIONS AT THE SAME TIME! */
colorBgBase: browserTheme === "dark" ? "#17191c" : "#ffffff",
colorTextBase: browserTheme === "dark" ? "#fafaf9" : "#141414",
colorPrimary: browserTheme === "dark" ? "#f97316" : "#ea580c",
colorLink: browserTheme === "dark" ? "#f97316" : "#ea580c",
colorInfo: browserTheme === "dark" ? "#478be6" : "#0969da",
colorSuccess: browserTheme === "dark" ? "#57ab5a" : "#1a7f37",
colorWarning: browserTheme === "dark" ? "#daaa3f" : "#eac54f",
colorError: browserTheme === "dark" ? "#e5534b" : "#d1242f",
/* @see https://tailwindcss.com/docs/responsive-design#overview */
screenXS: 30 * 16,
screenXSMin: 30 * 16,
screenXSMax: 40 * 16 - 1,
screenSM: 40 * 16,
screenSMMin: 40 * 16,
screenSMMax: 48 * 16 - 1,
screenMD: 48 * 16,
screenMDMin: 48 * 16,
screenMDMax: 64 * 16 - 1,
screenLG: 64 * 16,
screenLGMin: 64 * 16,
screenLGMax: 80 * 16 - 1,
screenXL: 80 * 16,
screenXLMin: 80 * 16,
screenXLMax: 96 * 16 - 1,
screenXXL: 96 * 16,
screenXXLMin: 96 * 16,
padding: 16,
paddingXS: 8,
paddingXXS: 6,
},
components: {
Layout: {
...antdTheme?.components?.Layout,
bodyBg: "transparent",
siderBg: "transparent",
},
Dropdown: {
...antdTheme?.components?.Dropdown,
paddingBlock: 9,
},
},
}}
>
+38
View File
@@ -0,0 +1,38 @@
import { useTranslation } from "react-i18next";
import { IconBook } from "@tabler/icons-react";
import { Typography } from "antd";
import { APP_DOCUMENT_URL } from "@/domain/app";
export interface AppDocumentLinkButtonProps {
className?: string;
style?: React.CSSProperties;
showIcon?: boolean;
}
const AppDocumentLinkButton = (props: AppDocumentLinkButtonProps) => {
const { className, style, showIcon = true } = props;
const { i18n, t } = useTranslation();
const handleDocumentClick = () => {
if (i18n.language.startsWith("en")) {
window.open(APP_DOCUMENT_URL + "/en/", "_blank");
} else {
window.open(APP_DOCUMENT_URL, "_blank");
}
};
return (
<Typography.Link className={className} style={style} type="secondary" onClick={handleDocumentClick}>
<div className="flex items-center justify-center space-x-1">
{showIcon ? <IconBook size="1em" /> : <></>}
<span>{t("common.menu.document")}</span>
</div>
</Typography.Link>
);
};
export default {
LinkButton: AppDocumentLinkButton,
};
+87
View File
@@ -0,0 +1,87 @@
import { useTranslation } from "react-i18next";
import { IconLanguage, type IconProps } from "@tabler/icons-react";
import { Dropdown, type DropdownProps, Typography } from "antd";
import { IconLanguageEnZh, IconLanguageZhEn } from "@/components/icons";
import { localeNames, localeResources } from "@/i18n";
import { mergeCls } from "@/utils/css";
export const useAppLocaleMenuItems = () => {
const { i18n } = useTranslation();
const items = Object.keys(i18n.store.data).map((key) => {
return {
key: key as string,
label: i18n.store.data[key].name as string,
onClick: () => {
if (key !== i18n.language) {
i18n.changeLanguage(key);
window.location.reload();
}
},
};
});
return items;
};
export interface AppLocaleDropdownProps {
children?: React.ReactNode;
trigger?: DropdownProps["trigger"];
}
const AppLocaleDropdown = (props: AppLocaleDropdownProps) => {
const { children, trigger = ["click"] } = props;
const items = useAppLocaleMenuItems();
return (
<Dropdown menu={{ items }} trigger={trigger}>
{children}
</Dropdown>
);
};
export interface AppLocaleIconProps extends IconProps {}
const AppLocaleIcon = (props: AppLocaleIconProps) => {
const { i18n } = useTranslation();
return i18n.language === localeNames.EN ? (
<IconLanguageEnZh {...props} />
) : i18n.language === localeNames.ZH ? (
<IconLanguageZhEn {...props} />
) : (
<IconLanguage {...props} />
);
};
export interface AppLocaleLinkButtonProps {
className?: string;
style?: React.CSSProperties;
showIcon?: boolean;
}
const AppLocaleLinkButton = (props: AppLocaleLinkButtonProps) => {
const { className, style, showIcon = true } = props;
const { t } = useTranslation();
const { i18n } = useTranslation();
return (
<AppLocaleDropdown trigger={["click", "hover"]}>
<Typography.Text className={mergeCls("cursor-pointer", className)} style={style} type="secondary">
<div className="flex items-center justify-center space-x-1">
{showIcon ? <AppLocaleIcon size="1em" /> : <></>}
<span>{String(localeResources[i18n.language]?.name ?? t("common.menu.locale"))}</span>
</div>
</Typography.Text>
</AppLocaleDropdown>
);
};
export default {
Dropdown: AppLocaleDropdown,
Icon: AppLocaleIcon,
LinkButton: AppLocaleLinkButton,
};
+91
View File
@@ -0,0 +1,91 @@
import { useTranslation } from "react-i18next";
import { IconMoon, type IconProps, IconSun, IconSunMoon } from "@tabler/icons-react";
import { Dropdown, type DropdownProps, Typography } from "antd";
import { useBrowserTheme } from "@/hooks";
import { mergeCls } from "@/utils/css";
export const useAppThemeMenuItems = () => {
const { t } = useTranslation();
const { themeMode, setThemeMode } = useBrowserTheme();
const items = (
[
["light", "common.theme.light", <IconSun size="1em" />],
["dark", "common.theme.dark", <IconMoon size="1em" />],
["system", "common.theme.system", <IconSunMoon size="1em" />],
] satisfies Array<[string, string, React.ReactNode]>
).map(([key, label, icon]) => {
return {
key: key,
label: t(label),
icon: icon,
onClick: () => {
if (key !== themeMode) {
setThemeMode(key as Parameters<typeof setThemeMode>[0]);
window.location.reload();
}
},
};
});
return items;
};
export interface AppThemeDropdownProps {
children?: React.ReactNode;
trigger?: DropdownProps["trigger"];
}
const AppThemeDropdown = (props: AppThemeDropdownProps) => {
const { children, trigger = ["click"] } = props;
const items = useAppThemeMenuItems();
return (
<Dropdown menu={{ items }} trigger={trigger}>
{children}
</Dropdown>
);
};
export interface AppThemeIconProps extends IconProps {}
const AppThemeIcon = (props: AppThemeIconProps) => {
const { theme } = useBrowserTheme();
return theme === "dark" ? <IconMoon {...props} /> : <IconSun {...props} />;
};
export interface AppThemeLinkButtonProps {
className?: string;
style?: React.CSSProperties;
showIcon?: boolean;
}
const AppThemeLinkButton = (props: AppThemeLinkButtonProps) => {
const { className, style, showIcon = true } = props;
const { t } = useTranslation();
const { themeMode } = useBrowserTheme();
return (
<AppThemeDropdown trigger={["click", "hover"]}>
<Typography.Text className={mergeCls("cursor-pointer", className)} style={style} type="secondary">
<div className="flex items-center justify-center space-x-1">
{showIcon ? <AppThemeIcon size="1em" /> : <></>}
<span>{t(`common.theme.${themeMode}`)}</span>
</div>
</Typography.Text>
</AppThemeDropdown>
);
};
export default {
Dropdown: AppThemeDropdown,
Icon: AppThemeIcon,
LinkButton: AppThemeLinkButton,
};
+45
View File
@@ -0,0 +1,45 @@
import { Badge, Typography } from "antd";
import { APP_DOWNLOAD_URL, APP_VERSION } from "@/domain/app";
import { useVersionChecker } from "@/hooks";
export interface AppVersionLinkButtonProps {
className?: string;
style?: React.CSSProperties;
}
const AppVersionLinkButton = ({ className, style }: AppVersionLinkButtonProps) => {
return (
<AppVersionBadge>
<Typography.Link className={className} style={style} type="secondary" href={APP_DOWNLOAD_URL} target="_blank">
{APP_VERSION}
</Typography.Link>
</AppVersionBadge>
);
};
export interface AppVersionBadgeProps {
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}
const AppVersionBadge = ({ className, style, children }: AppVersionBadgeProps) => {
const { hasNewVersion } = useVersionChecker();
return (
<Badge
className={className}
style={style}
styles={{ indicator: { transform: "scale(0.75) translate(50%, -50%)" } }}
count={hasNewVersion ? "NEW" : undefined}
>
{children}
</Badge>
);
};
export default {
LinkButton: AppVersionLinkButton,
Badge: AppVersionBadge,
};
+3 -3
View File
@@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { useControllableValue } from "ahooks";
import { Button, Drawer, type DrawerProps, Form, type FormProps, type ModalProps, Space } from "antd";
import { Button, Drawer, type DrawerProps, Flex, Form, type FormProps, type ModalProps } from "antd";
import { useAntdForm, useTriggerElement } from "@/hooks";
@@ -109,14 +109,14 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
<Drawer
{...mergedDrawerProps}
footer={
<Space className="w-full justify-end">
<Flex justify="end" gap="small">
<Button {...cancelButtonProps} onClick={handleCancelClick}>
{cancelText ?? t("common.button.cancel")}
</Button>
<Button {...okButtonProps} type="primary" loading={formPending} onClick={handleOkClick}>
{okText ?? t("common.button.ok")}
</Button>
</Space>
</Flex>
}
forceRender
open={open}
+64
View File
@@ -0,0 +1,64 @@
import { useTranslation } from "react-i18next";
import { Typography, theme } from "antd";
import Show from "./Show";
export interface EmptyProps {
className?: string;
style?: React.CSSProperties;
title?: React.ReactNode;
description?: React.ReactNode;
extra?: React.ReactNode;
icon?: React.ReactNode;
}
const Empty = (props: EmptyProps) => {
const { t } = useTranslation();
const { className, style, title = t("common.text.nodata"), description, extra, icon } = props;
const { token: themeToken } = theme.useToken();
const isPrimitive = (node: React.ReactNode): node is string | number | boolean | null => {
return typeof node === "string" || typeof node === "number" || typeof node === "boolean" || node == null;
};
return (
<div className={className} style={style}>
<div className="relative w-full overflow-hidden">
<div className="relative top-0 left-0 z-1 flex h-full w-full py-4">
<div className="relative mx-auto w-full max-w-lg">
<div className="flex flex-col gap-2 text-center">
<Show when={!!icon}>
<div className="mx-auto">
<div className="flex size-12 items-center justify-center overflow-hidden rounded-md border text-gray-600 shadow-sm dark:text-gray-200">
{icon}
</div>
</div>
</Show>
<div className="my-2">
<Show when={!!title}>
<div className="pb-2 text-xl" style={{ color: themeToken.colorTextLabel }}>
{title}
</div>
</Show>
<Show when={!!description}>
{isPrimitive(description) ? (
<Typography.Text type="secondary">{description}</Typography.Text>
) : (
<div style={{ color: themeToken.colorTextSecondary }}>{description}</div>
)}
</Show>
</div>
<Show when={!!extra}>
<div>{extra}</div>
</Show>
</div>
</div>
</div>
</div>
</div>
);
};
export default Empty;
+1 -1
View File
@@ -122,7 +122,7 @@ const ModalForm = <T extends NonNullable<unknown> = any>({
onOk={handleOkClick}
onCancel={handleCancelClick}
>
<div className="pb-2 pt-4">
<div className="pt-4 pb-2">
<Form className={className} style={style} {...mergedFormProps} form={formInst}>
{children}
</Form>
+12 -18
View File
@@ -1,16 +1,11 @@
import { type ChangeEvent, forwardRef, useImperativeHandle, useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import {
ArrowDownOutlined as ArrowDownOutlinedIcon,
ArrowUpOutlined as ArrowUpOutlinedIcon,
MinusOutlined as MinusOutlinedIcon,
PlusOutlined as PlusOutlinedIcon,
} from "@ant-design/icons";
import { IconCircleArrowDown, IconCircleArrowUp, IconCircleMinus, IconCirclePlus } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { Button, Input, type InputProps, type InputRef, Space } from "antd";
import { Button, Input, type InputProps, type InputRef } from "antd";
import { produce } from "immer";
export type MultipleInputProps = Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange" | "onPressEnter" | "onClear"> & {
export interface MultipleInputProps extends Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange" | "onPressEnter" | "onClear"> {
allowClear?: boolean;
defaultValue?: string[];
maxCount?: number;
@@ -22,7 +17,7 @@ export type MultipleInputProps = Omit<InputProps, "count" | "defaultValue" | "sh
onValueCreate?: (index: number) => void;
onValueRemove?: (index: number) => void;
onValueSort?: (oldIndex: number, newIndex: number) => void;
};
}
const MultipleInput = ({
allowClear = false,
@@ -129,7 +124,7 @@ const MultipleInput = ({
{t("common.button.add")}
</Button>
) : (
<Space className="w-full" direction="vertical" size="small">
<div className="flex flex-col gap-2">
{Array.from(value).map((element, index) => {
const allowUp = index > 0;
const allowDown = index < value.length - 1;
@@ -159,7 +154,7 @@ const MultipleInput = ({
/>
);
})}
</Space>
</div>
);
};
@@ -196,7 +191,6 @@ const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputIte
allowUp,
disabled,
showSortButton,
size,
onEntryAdd,
onEntryDown,
onEntryUp,
@@ -216,17 +210,17 @@ const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputIte
const upBtn = useMemo(() => {
if (!showSortButton) return null;
return <Button icon={<ArrowUpOutlinedIcon />} color="default" disabled={disabled || !allowUp} type="text" onClick={onEntryUp} />;
return <Button icon={<IconCircleArrowUp size="1.25em" />} color="default" disabled={disabled || !allowUp} type="text" onClick={onEntryUp} />;
}, [allowUp, disabled, showSortButton, onEntryUp]);
const downBtn = useMemo(() => {
if (!showSortButton) return null;
return <Button icon={<ArrowDownOutlinedIcon />} color="default" disabled={disabled || !allowDown} type="text" onClick={onEntryDown} />;
return <Button icon={<IconCircleArrowDown size="1.25em" />} color="default" disabled={disabled || !allowDown} type="text" onClick={onEntryDown} />;
}, [allowDown, disabled, showSortButton, onEntryDown]);
const removeBtn = useMemo(() => {
return <Button icon={<MinusOutlinedIcon />} color="default" disabled={disabled || !allowRemove} type="text" onClick={onEntryRemove} />;
return <Button icon={<IconCircleMinus size="1.25em" />} color="default" disabled={disabled || !allowRemove} type="text" onClick={onEntryRemove} />;
}, [allowRemove, disabled, onEntryRemove]);
const addBtn = useMemo(() => {
return <Button icon={<PlusOutlinedIcon />} color="default" disabled={disabled || !allowAdd} type="text" onClick={onEntryAdd} />;
return <Button icon={<IconCirclePlus size="1.25em" />} color="default" disabled={disabled || !allowAdd} type="text" onClick={onEntryAdd} />;
}, [allowAdd, disabled, onEntryAdd]);
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
@@ -259,12 +253,12 @@ const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputIte
onChange={handleInputChange}
/>
</div>
<Space.Compact size={size}>
<div className="flex items-center justify-end">
{removeBtn}
{upBtn}
{downBtn}
{addBtn}
</Space.Compact>
</div>
</div>
);
}
+30 -27
View File
@@ -1,8 +1,8 @@
import { type ChangeEvent, useEffect } from "react";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { nanoid } from "@ant-design/pro-components";
import { IconList } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { Button, Form, Input, type InputProps, Space } from "antd";
import { nanoid } from "nanoid";
import { useAntdForm } from "@/hooks";
import ModalForm from "./ModalForm";
@@ -10,10 +10,10 @@ import MultipleInput from "./MultipleInput";
type SplitOptions = {
removeEmpty?: boolean;
trim?: boolean;
trimSpace?: boolean;
};
export type MultipleSplitValueInputProps = Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange"> & {
export interface MultipleSplitValueInputProps extends Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange"> {
defaultValue?: string;
maxCount?: number;
minCount?: number;
@@ -25,13 +25,14 @@ export type MultipleSplitValueInputProps = Omit<InputProps, "count" | "defaultVa
splitOptions?: SplitOptions;
value?: string[];
onChange?: (value: string) => void;
};
}
const DEFAULT_SEPARATOR = ";";
const MultipleSplitValueInput = ({
className,
style,
size,
separator: delimiter = DEFAULT_SEPARATOR,
disabled,
maxCount,
@@ -56,7 +57,7 @@ const MultipleSplitValueInput = ({
initialValues: { value: value?.split(delimiter) },
onSubmit: (values) => {
const temp = values.value ?? [];
if (splitOptions.trim) {
if (splitOptions.trimSpace) {
temp.map((e) => e.trim());
}
if (splitOptions.removeEmpty) {
@@ -81,27 +82,29 @@ const MultipleSplitValueInput = ({
};
return (
<Space.Compact className={className} style={{ width: "100%", ...style }}>
<Input {...props} disabled={disabled} placeholder={placeholder} value={value} onChange={handleChange} onClear={handleClear} />
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={modalTitle}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
validateTrigger="onSubmit"
width={modalWidth}
>
<Form.Item name="value" noStyle>
<MultipleInput minCount={minCount} maxCount={maxCount} placeholder={placeholderInModal ?? placeholder} showSortButton={showSortButton} />
</Form.Item>
</ModalForm>
</Space.Compact>
<div className={className} style={style}>
<Space.Compact className="w-full">
<Input {...props} disabled={disabled} placeholder={placeholder} size={size} value={value} onChange={handleChange} onClear={handleClear} />
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={modalTitle}
trigger={
<Button className="px-2" disabled={disabled} size={size}>
<IconList size="1.25em" />
</Button>
}
validateTrigger="onSubmit"
width={modalWidth}
>
<Form.Item name="value" noStyle>
<MultipleInput minCount={minCount} maxCount={maxCount} placeholder={placeholderInModal ?? placeholder} showSortButton={showSortButton} />
</Form.Item>
</ModalForm>
</Space.Compact>
</div>
);
};
+2 -2
View File
@@ -1,8 +1,8 @@
export type ShowProps = {
export interface ShowProps {
when: boolean;
children: React.ReactNode;
fallback?: React.ReactNode;
};
}
const Show = ({ when, children, fallback }: ShowProps) => {
return when ? children : fallback;
+15 -14
View File
@@ -1,10 +1,9 @@
import { type ChangeEvent, useRef } from "react";
import { useTranslation } from "react-i18next";
import { UploadOutlined as UploadOutlinedIcon } from "@ant-design/icons";
import { Button, type ButtonProps, Input, Space, type UploadProps } from "antd";
import { IconFileImport } from "@tabler/icons-react";
import { Button, type ButtonProps, Input, type UploadProps } from "antd";
import { type TextAreaProps } from "antd/es/input/TextArea";
import { mergeCls } from "@/utils/css";
import { readFileContent } from "@/utils/file";
export interface TextFileInputProps extends Omit<TextAreaProps, "onChange"> {
@@ -34,17 +33,19 @@ const TextFileInput = ({ className, style, accept, disabled, readOnly, uploadTex
};
return (
<Space className={mergeCls("w-full", className)} style={style} direction="vertical" size="small">
<Input.TextArea {...props} disabled={disabled} readOnly={readOnly} onChange={(e) => onChange?.(e.target.value)} />
{!readOnly && (
<>
<Button {...uploadButtonProps} block disabled={disabled} icon={<UploadOutlinedIcon />} onClick={handleButtonClick}>
{uploadText ?? t("common.text.import_from_file")}
</Button>
<input ref={fileInputRef} type="file" style={{ display: "none" }} accept={accept} onChange={handleFileChange} />
</>
)}
</Space>
<div className={className} style={style}>
<div className="flex flex-col items-center gap-2">
<Input.TextArea {...props} disabled={disabled} readOnly={readOnly} onChange={(e) => onChange?.(e.target.value)} />
{!readOnly && (
<>
<Button {...uploadButtonProps} block disabled={disabled} icon={<IconFileImport size="1.25em" />} onClick={handleButtonClick}>
{uploadText ?? t("common.text.import_from_file")}
</Button>
<input ref={fileInputRef} type="file" style={{ display: "none" }} accept={accept} onChange={handleFileChange} />
</>
)}
</div>
</div>
);
};
-39
View File
@@ -1,39 +0,0 @@
import { memo } from "react";
import { useTranslation } from "react-i18next";
import { ReadOutlined as ReadOutlinedIcon } from "@ant-design/icons";
import { Badge, Divider, Space, Typography } from "antd";
import { version } from "@/domain/version";
import { useVersionChecker } from "@/hooks";
export type VersionProps = {
className?: string;
style?: React.CSSProperties;
};
const Version = ({ className, style }: VersionProps) => {
const { t } = useTranslation();
const { hasNewVersion } = useVersionChecker();
return (
<Space className={className} style={style} size={4}>
<Typography.Link type="secondary" href="https://docs.certimate.me" target="_blank">
<div className="flex items-center justify-center space-x-1">
<ReadOutlinedIcon />
<span>{t("common.menu.document")}</span>
</div>
</Typography.Link>
<Divider type="vertical" />
<Badge styles={{ indicator: { transform: "scale(0.75) translate(50%, -50%)" } }} count={hasNewVersion ? "NEW" : undefined}>
<Typography.Link type="secondary" href="https://github.com/certimate-go/certimate/releases" target="_blank">
{version}
</Typography.Link>
</Badge>
</Space>
);
};
export default memo(Version);
+32 -21
View File
@@ -1,7 +1,7 @@
import { useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useControllableValue } from "ahooks";
import { Button, Drawer, Space, notification } from "antd";
import { App, Button, Drawer, Flex } from "antd";
import { type AccessModel } from "@/domain/access";
import { useTriggerElement, useZustandShallowSelector } from "@/hooks";
@@ -10,21 +10,21 @@ import { getErrMsg } from "@/utils/error";
import AccessForm, { type AccessFormInstance, type AccessFormProps } from "./AccessForm";
export type AccessEditDrawerProps = {
export interface AccessEditDrawerProps {
data?: AccessFormProps["initialValues"];
loading?: boolean;
mode: AccessFormProps["mode"];
open?: boolean;
scene: AccessFormProps["scene"];
trigger?: React.ReactNode;
usage?: AccessFormProps["usage"];
onOpenChange?: (open: boolean) => void;
afterSubmit?: (record: AccessModel) => void;
};
}
const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, ...props }: AccessEditDrawerProps) => {
const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ...props }: AccessEditDrawerProps) => {
const { t } = useTranslation();
const [notificationApi, NotificationContextHolder] = notification.useNotification();
const { notification } = App.useApp();
const { createAccess, updateAccess } = useAccessesStore(useZustandShallowSelector(["createAccess", "updateAccess"]));
@@ -39,6 +39,11 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, .
const formRef = useRef<AccessFormInstance>(null);
const [formPending, setFormPending] = useState(false);
const [footerShow, setFooterShow] = useState(!!data?.provider);
useEffect(() => {
setFooterShow(!!data?.provider);
}, [data?.provider]);
const handleOkClick = async () => {
setFormPending(true);
try {
@@ -51,26 +56,26 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, .
try {
let values: AccessModel = formRef.current!.getFieldsValue();
if (scene === "add") {
if (mode === "create") {
if (data?.id) {
throw "Invalid props: `data`";
}
values = await createAccess(values);
} else if (scene === "edit") {
} else if (mode === "edit") {
if (!data?.id) {
throw "Invalid props: `data`";
}
values = await updateAccess({ ...data, ...values });
} else {
throw "Invalid props: `scene`";
throw "Invalid props: `action`";
}
afterSubmit?.(values);
setOpen(false);
} catch (err) {
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
notification.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
throw err;
} finally {
@@ -84,10 +89,12 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, .
setOpen(false);
};
const handleFormValuesChange: AccessFormProps["onValuesChange"] = (values) => {
setFooterShow(!!values.provider);
};
return (
<>
{NotificationContextHolder}
{triggerEl}
<Drawer
@@ -95,21 +102,25 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, .
closable={!formPending}
destroyOnHidden
footer={
<Space className="w-full justify-end">
<Button onClick={handleCancelClick}>{t("common.button.cancel")}</Button>
<Button loading={formPending} type="primary" onClick={handleOkClick}>
{scene === "edit" ? t("common.button.save") : t("common.button.submit")}
</Button>
</Space>
footerShow ? (
<Flex 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")}
</Button>
</Flex>
) : (
false
)
}
loading={loading}
maskClosable={!formPending}
open={open}
title={t(`access.action.${scene}`)}
title={t(`access.action.${mode}.modal.title`)}
width={720}
onClose={() => setOpen(false)}
>
<AccessForm ref={formRef} initialValues={data} scene={scene === "add" ? "add" : "edit"} usage={usage} />
<AccessForm ref={formRef} disabled={formPending} initialValues={data} mode={mode} usage={usage} onValuesChange={handleFormValuesChange} />
</Drawer>
</>
);
@@ -1,123 +0,0 @@
import { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useControllableValue } from "ahooks";
import { Modal, notification } from "antd";
import { type AccessModel } from "@/domain/access";
import { useTriggerElement, useZustandShallowSelector } from "@/hooks";
import { useAccessesStore } from "@/stores/access";
import { getErrMsg } from "@/utils/error";
import AccessForm, { type AccessFormInstance, type AccessFormProps } from "./AccessForm";
export type AccessEditModalProps = {
data?: AccessFormProps["initialValues"];
loading?: boolean;
open?: boolean;
usage?: AccessFormProps["usage"];
scene: AccessFormProps["scene"];
trigger?: React.ReactNode;
onOpenChange?: (open: boolean) => void;
afterSubmit?: (record: AccessModel) => void;
};
const AccessEditModal = ({ data, loading, trigger, scene, usage, afterSubmit, ...props }: AccessEditModalProps) => {
const { t } = useTranslation();
const [notificationApi, NotificationContextHolder] = notification.useNotification();
const { createAccess, updateAccess } = useAccessesStore(useZustandShallowSelector(["createAccess", "updateAccess"]));
const [open, setOpen] = useControllableValue<boolean>(props, {
valuePropName: "open",
defaultValuePropName: "defaultOpen",
trigger: "onOpenChange",
});
const triggerEl = useTriggerElement(trigger, { onClick: () => setOpen(true) });
const formRef = useRef<AccessFormInstance>(null);
const [formPending, setFormPending] = useState(false);
const handleOkClick = async () => {
setFormPending(true);
try {
await formRef.current!.validateFields();
} catch (err) {
setFormPending(false);
throw err;
}
try {
let values: AccessModel = formRef.current!.getFieldsValue();
if (scene === "add") {
if (data?.id) {
throw "Invalid props: `data`";
}
values = await createAccess(values);
} else if (scene === "edit") {
if (!data?.id) {
throw "Invalid props: `data`";
}
values = await updateAccess({ ...data, ...values });
} else {
throw "Invalid props: `preset`";
}
afterSubmit?.(values);
setOpen(false);
} catch (err) {
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
throw err;
} finally {
setFormPending(false);
}
};
const handleCancelClick = () => {
if (formPending) return;
setOpen(false);
};
return (
<>
{NotificationContextHolder}
{triggerEl}
<Modal
styles={{
content: {
maxHeight: "calc(80vh - 64px)",
overflowX: "hidden",
overflowY: "auto",
},
}}
afterClose={() => setOpen(false)}
cancelButtonProps={{ disabled: formPending }}
cancelText={t("common.button.cancel")}
closable
confirmLoading={formPending}
destroyOnHidden
loading={loading}
okText={scene === "edit" ? t("common.button.save") : t("common.button.submit")}
open={open}
title={t(`access.action.${scene}`)}
width={480}
onOk={handleOkClick}
onCancel={handleCancelClick}
>
<div className="pb-2 pt-4">
<AccessForm ref={formRef} initialValues={data} scene={scene === "add" ? "add" : "edit"} usage={usage} />
</div>
</Modal>
</>
);
};
export default AccessEditModal;
+25 -48
View File
@@ -2,7 +2,7 @@ import { forwardRef, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import AccessProviderPicker from "@/components/provider/AccessProviderPicker";
import AccessProviderSelect from "@/components/provider/AccessProviderSelect";
@@ -86,26 +86,26 @@ import AccessFormWestcnConfig from "./AccessFormWestcnConfig";
import AccessFormZeroSSLConfig from "./AccessFormZeroSSLConfig";
type AccessFormFieldValues = Partial<MaybeModelRecord<AccessModel>>;
type AccessFormScenes = "add" | "edit";
type AccessFormUsages = "both-dns-hosting" | "ca-only" | "notification-only";
type AccessFormModes = "create" | "edit";
type AccessFormUsages = "dns" | "hosting" | "dns-hosting" | "ca" | "notification";
export type AccessFormProps = {
export interface AccessFormProps {
className?: string;
style?: React.CSSProperties;
mode: AccessFormModes;
disabled?: boolean;
initialValues?: AccessFormFieldValues;
scene: AccessFormScenes;
usage?: AccessFormUsages;
onValuesChange?: (values: AccessFormFieldValues) => void;
};
}
export type AccessFormInstance = {
export interface AccessFormInstance {
getFieldsValue: () => ReturnType<FormInstance<AccessFormFieldValues>["getFieldsValue"]>;
resetFields: FormInstance<AccessFormFieldValues>["resetFields"];
validateFields: FormInstance<AccessFormFieldValues>["validateFields"];
};
}
const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className, style, disabled, initialValues, usage, scene, onValuesChange }, ref) => {
const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className, style, mode, disabled, initialValues, usage, onValuesChange }, ref) => {
const { t } = useTranslation();
const formSchema = z.object({
@@ -113,14 +113,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
.string(t("access.form.name.placeholder"))
.min(1, t("access.form.name.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 })),
provider: z.nativeEnum(ACCESS_PROVIDERS, {
message:
usage === "ca-only"
? t("access.form.certificate_authority.placeholder")
: usage === "notification-only"
? t("access.form.notification_channel.placeholder")
: t("access.form.provider.placeholder"),
}),
provider: z.enum(ACCESS_PROVIDERS, t("access.form.provider.placeholder")),
config: z.any(),
reserve: z.string().nullish(),
});
@@ -132,39 +125,23 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
const providerFilter = useMemo(() => {
switch (usage) {
case "both-dns-hosting":
case "dns":
return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.DNS);
case "hosting":
return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.HOSTING);
case "dns-hosting":
return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.DNS) || record.usages.includes(ACCESS_USAGES.HOSTING);
case "ca-only":
case "ca":
return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.CA);
case "notification-only":
case "notification":
return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.NOTIFICATION);
}
return undefined;
}, [usage]);
const providerLabel = useMemo(() => {
switch (usage) {
case "ca-only":
return t("access.form.certificate_authority.label");
case "notification-only":
return t("access.form.notification_channel.label");
}
return t("access.form.provider.label");
}, [usage]);
const providerPlaceholder = useMemo(() => {
switch (usage) {
case "ca-only":
return t("access.form.certificate_authority.placeholder");
case "notification-only":
return t("access.form.notification_channel.placeholder");
}
return t("access.form.provider.placeholder");
}, [usage]);
const providerTooltip = useMemo(() => {
switch (usage) {
case "both-dns-hosting":
case "dns-hosting":
return <span dangerouslySetInnerHTML={{ __html: t("access.form.provider.tooltip") }}></span>;
}
@@ -330,7 +307,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
case ACCESS_PROVIDERS.WEBHOOK:
return (
<AccessFormWebhookConfig
usage={usage === "notification-only" ? "notification" : usage === "both-dns-hosting" ? "deployment" : "none"}
usage={usage === "notification" ? "notification" : usage === "hosting" || usage === "dns-hosting" ? "deployment" : "none"}
{...nestedFormProps}
/>
);
@@ -365,7 +342,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
getFieldsValue: () => {
const values = formInst.getFieldsValue(true);
values.config = nestedFormInst.getFieldsValue();
values.reserve = usage === "ca-only" ? "ca" : usage === "notification-only" ? "notification" : undefined;
values.reserve = usage === "ca" ? "ca" : usage === "notification" ? "notification" : undefined;
return values;
},
resetFields: (fields) => {
@@ -394,7 +371,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
autoFocus
filter={providerFilter}
placeholder={t("access.form.provider.search.placeholder")}
showOptionTags={usage == null || (usage === "both-dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
showOptionTags={usage == null || (usage === "dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
onSelect={handleProviderPick}
/>
}
@@ -403,12 +380,12 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
<Input placeholder={t("access.form.name.placeholder")} />
</Form.Item>
<Form.Item name="provider" label={providerLabel} rules={[formRule]} tooltip={providerTooltip}>
<Form.Item name="provider" label={t("access.form.provider.label")} rules={[formRule]} tooltip={providerTooltip}>
<AccessProviderSelect
filter={providerFilter}
disabled={scene !== "add"}
placeholder={providerPlaceholder}
showOptionTags={usage == null || (usage === "both-dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
disabled={mode !== "create"}
placeholder={t("access.form.provider.placeholder")}
showOptionTags={usage == null || (usage === "dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
showSearch={!disabled}
/>
</Form.Item>
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Select, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigFor1Panel } from "@/domain/access";
type AccessForm1PanelConfigFieldValues = Nullish<AccessConfigFor1Panel>;
export type AccessForm1PanelConfigProps = {
export interface AccessForm1PanelConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessForm1PanelConfigFieldValues;
onValuesChange?: (values: AccessForm1PanelConfigFieldValues) => void;
};
}
const initFormModel = (): AccessForm1PanelConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForACMECA } from "@/domain/access";
type AccessFormACMECAConfigFieldValues = Nullish<AccessConfigForACMECA>;
export type AccessFormACMECAConfigProps = {
export interface AccessFormACMECAConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormACMECAConfigFieldValues;
onValuesChange?: (values: AccessFormACMECAConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormACMECAConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForACMEHttpReq } from "@/domain/access";
type AccessFormACMEHttpReqConfigFieldValues = Nullish<AccessConfigForACMEHttpReq>;
export type AccessFormACMEHttpReqConfigProps = {
export interface AccessFormACMEHttpReqConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormACMEHttpReqConfigFieldValues;
onValuesChange?: (values: AccessFormACMEHttpReqConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormACMEHttpReqConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForAPISIX } from "@/domain/access";
type AccessFormAPISIXConfigFieldValues = Nullish<AccessConfigForAPISIX>;
export type AccessFormAPISIXConfigProps = {
export interface AccessFormAPISIXConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormAPISIXConfigFieldValues;
onValuesChange?: (values: AccessFormAPISIXConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormAPISIXConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForAWS } from "@/domain/access";
type AccessFormAWSConfigFieldValues = Nullish<AccessConfigForAWS>;
export type AccessFormAWSConfigProps = {
export interface AccessFormAWSConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormAWSConfigFieldValues;
onValuesChange?: (values: AccessFormAWSConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormAWSConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForAliyun } from "@/domain/access";
type AccessFormAliyunConfigFieldValues = Nullish<AccessConfigForAliyun>;
export type AccessFormAliyunConfigProps = {
export interface AccessFormAliyunConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormAliyunConfigFieldValues;
onValuesChange?: (values: AccessFormAliyunConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormAliyunConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { AutoComplete, Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForAzure } from "@/domain/access";
type AccessFormAzureConfigFieldValues = Nullish<AccessConfigForAzure>;
export type AccessFormAzureConfigProps = {
export interface AccessFormAzureConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormAzureConfigFieldValues;
onValuesChange?: (values: AccessFormAzureConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormAzureConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBaiduCloud } from "@/domain/access";
type AccessFormBaiduCloudConfigFieldValues = Nullish<AccessConfigForBaiduCloud>;
export type AccessFormBaiduCloudConfigProps = {
export interface AccessFormBaiduCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBaiduCloudConfigFieldValues;
onValuesChange?: (values: AccessFormBaiduCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBaiduCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBaishan } from "@/domain/access";
type AccessFormBaishanConfigFieldValues = Nullish<AccessConfigForBaishan>;
export type AccessFormBaishanConfigProps = {
export interface AccessFormBaishanConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBaishanConfigFieldValues;
onValuesChange?: (values: AccessFormBaishanConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBaishanConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBaotaPanel } from "@/domain/access";
type AccessFormBaotaPanelConfigFieldValues = Nullish<AccessConfigForBaotaPanel>;
export type AccessFormBaotaPanelConfigProps = {
export interface AccessFormBaotaPanelConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBaotaPanelConfigFieldValues;
onValuesChange?: (values: AccessFormBaotaPanelConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBaotaPanelConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBaotaWAF } from "@/domain/access";
type AccessFormBaotaWAFConfigFieldValues = Nullish<AccessConfigForBaotaWAF>;
export type AccessFormBaotaWAFConfigProps = {
export interface AccessFormBaotaWAFConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBaotaWAFConfigFieldValues;
onValuesChange?: (values: AccessFormBaotaWAFConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBaotaWAFConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBunny } from "@/domain/access";
type AccessFormBunnyConfigFieldValues = Nullish<AccessConfigForBunny>;
export type AccessFormBunnyConfigProps = {
export interface AccessFormBunnyConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBunnyConfigFieldValues;
onValuesChange?: (values: AccessFormBunnyConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBunnyConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForBytePlus } from "@/domain/access";
type AccessFormBytePlusConfigFieldValues = Nullish<AccessConfigForBytePlus>;
export type AccessFormBytePlusConfigProps = {
export interface AccessFormBytePlusConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormBytePlusConfigFieldValues;
onValuesChange?: (values: AccessFormBytePlusConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormBytePlusConfigFieldValues => {
return {
@@ -1,18 +1,18 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForCMCCCloud } from "@/domain/access";
type AccessFormCMCCCloudConfigFieldValues = Nullish<AccessConfigForCMCCCloud>;
export type AccessFormCMCCCloudConfigProps = {
export interface AccessFormCMCCCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormCMCCCloudConfigFieldValues;
onValuesChange?: (values: AccessFormCMCCCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormCMCCCloudConfigFieldValues => {
return {
@@ -1,18 +1,18 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForCTCCCloud } from "@/domain/access";
type AccessFormCTCCCloudConfigFieldValues = Nullish<AccessConfigForCTCCCloud>;
export type AccessFormCTCCCloudConfigProps = {
export interface AccessFormCTCCCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormCTCCCloudConfigFieldValues;
onValuesChange?: (values: AccessFormCTCCCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormCTCCCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForCacheFly } from "@/domain/access";
type AccessFormCacheFlyConfigFieldValues = Nullish<AccessConfigForCacheFly>;
export type AccessFormCacheFlyConfigProps = {
export interface AccessFormCacheFlyConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormCacheFlyConfigFieldValues;
onValuesChange?: (values: AccessFormCacheFlyConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormCacheFlyConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForCdnfly } from "@/domain/access";
type AccessFormCdnflyConfigFieldValues = Nullish<AccessConfigForCdnfly>;
export type AccessFormCdnflyConfigProps = {
export interface AccessFormCdnflyConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormCdnflyConfigFieldValues;
onValuesChange?: (values: AccessFormCdnflyConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormCdnflyConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForClouDNS } from "@/domain/access";
type AccessFormClouDNSConfigFieldValues = Nullish<AccessConfigForClouDNS>;
export type AccessFormClouDNSConfigProps = {
export interface AccessFormClouDNSConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormClouDNSConfigFieldValues;
onValuesChange?: (values: AccessFormClouDNSConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormClouDNSConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForCloudflare } from "@/domain/access";
type AccessFormCloudflareConfigFieldValues = Nullish<AccessConfigForCloudflare>;
export type AccessFormCloudflareConfigProps = {
export interface AccessFormCloudflareConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormCloudflareConfigFieldValues;
onValuesChange?: (values: AccessFormCloudflareConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormCloudflareConfigFieldValues => {
return {
@@ -1,18 +1,18 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForConstellix } from "@/domain/access";
type AccessFormConstellixConfigFieldValues = Nullish<AccessConfigForConstellix>;
export type AccessFormConstellixConfigProps = {
export interface AccessFormConstellixConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormConstellixConfigFieldValues;
onValuesChange?: (values: AccessFormConstellixConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormConstellixConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDNSLA } from "@/domain/access";
type AccessFormDNSLAConfigFieldValues = Nullish<AccessConfigForDNSLA>;
export type AccessFormDNSLAConfigProps = {
export interface AccessFormDNSLAConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDNSLAConfigFieldValues;
onValuesChange?: (values: AccessFormDNSLAConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDNSLAConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDeSEC } from "@/domain/access";
type AccessFormDeSECConfigFieldValues = Nullish<AccessConfigForDeSEC>;
export type AccessFormDeSECConfigProps = {
export interface AccessFormDeSECConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDeSECConfigFieldValues;
onValuesChange?: (values: AccessFormDeSECConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDeSECConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDigitalOcean } from "@/domain/access";
type AccessFormDigitalOceanConfigFieldValues = Nullish<AccessConfigForDigitalOcean>;
export type AccessFormDigitalOceanConfigProps = {
export interface AccessFormDigitalOceanConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDigitalOceanConfigFieldValues;
onValuesChange?: (values: AccessFormDigitalOceanConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDigitalOceanConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDingTalkBot } from "@/domain/access";
type AccessFormDingTalkBotConfigFieldValues = Nullish<AccessConfigForDingTalkBot>;
export type AccessFormDingTalkBotConfigProps = {
export interface AccessFormDingTalkBotConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDingTalkBotConfigFieldValues;
onValuesChange?: (values: AccessFormDingTalkBotConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDingTalkBotConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDiscordBot } from "@/domain/access";
type AccessFormDiscordBotConfigFieldValues = Nullish<AccessConfigForDiscordBot>;
export type AccessFormDiscordBotConfigProps = {
export interface AccessFormDiscordBotConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDiscordBotConfigFieldValues;
onValuesChange?: (values: AccessFormDiscordBotConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDiscordBotConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDogeCloud } from "@/domain/access";
type AccessFormDogeCloudConfigFieldValues = Nullish<AccessConfigForDogeCloud>;
export type AccessFormDogeCloudConfigProps = {
export interface AccessFormDogeCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDogeCloudConfigFieldValues;
onValuesChange?: (values: AccessFormDogeCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDogeCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDuckDNS } from "@/domain/access";
type AccessFormDuckDNSConfigFieldValues = Nullish<AccessConfigForDuckDNS>;
export type AccessFormDuckDNSConfigProps = {
export interface AccessFormDuckDNSConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDuckDNSConfigFieldValues;
onValuesChange?: (values: AccessFormDuckDNSConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDuckDNSConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForDynv6 } from "@/domain/access";
type AccessFormDynv6ConfigFieldValues = Nullish<AccessConfigForDynv6>;
export type AccessFormDynv6ConfigProps = {
export interface AccessFormDynv6ConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormDynv6ConfigFieldValues;
onValuesChange?: (values: AccessFormDynv6ConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormDynv6ConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForEdgio } from "@/domain/access";
type AccessFormEdgioConfigFieldValues = Nullish<AccessConfigForEdgio>;
export type AccessFormEdgioConfigProps = {
export interface AccessFormEdgioConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormEdgioConfigFieldValues;
onValuesChange?: (values: AccessFormEdgioConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormEdgioConfigFieldValues => {
return {
@@ -1,20 +1,20 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, InputNumber, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForEmail } from "@/domain/access";
import { validEmailAddress, validPortNumber } from "@/utils/validators";
type AccessFormEmailConfigFieldValues = Nullish<AccessConfigForEmail>;
export type AccessFormEmailConfigProps = {
export interface AccessFormEmailConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormEmailConfigFieldValues;
onValuesChange?: (values: AccessFormEmailConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormEmailConfigFieldValues => {
return {
@@ -95,7 +95,7 @@ const AccessFormEmailConfig = ({ form: formInst, formName, disabled, initialValu
<div className="w-2/5">
<Form.Item name="smtpPort" label={t("access.form.email_smtp_port.label")} rules={[formRule]}>
<InputNumber className="w-full" placeholder={t("access.form.email_smtp_port.placeholder")} min={1} max={65535} />
<InputNumber style={{ width: "100%" }} placeholder={t("access.form.email_smtp_port.placeholder")} min={1} max={65535} />
</Form.Item>
</div>
</div>
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Radio, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForFlexCDN } from "@/domain/access";
type AccessFormFlexCDNConfigFieldValues = Nullish<AccessConfigForFlexCDN>;
export type AccessFormFlexCDNConfigProps = {
export interface AccessFormFlexCDNConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormFlexCDNConfigFieldValues;
onValuesChange?: (values: AccessFormFlexCDNConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormFlexCDNConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForGcore } from "@/domain/access";
type AccessFormGcoreConfigFieldValues = Nullish<AccessConfigForGcore>;
export type AccessFormGcoreConfigProps = {
export interface AccessFormGcoreConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormGcoreConfigFieldValues;
onValuesChange?: (values: AccessFormGcoreConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormGcoreConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForGname } from "@/domain/access";
type AccessFormGnameConfigFieldValues = Nullish<AccessConfigForGname>;
export type AccessFormGnameConfigProps = {
export interface AccessFormGnameConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormGnameConfigFieldValues;
onValuesChange?: (values: AccessFormGnameConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormGnameConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForGoDaddy } from "@/domain/access";
type AccessFormGoDaddyConfigFieldValues = Nullish<AccessConfigForGoDaddy>;
export type AccessFormGoDaddyConfigProps = {
export interface AccessFormGoDaddyConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormGoDaddyConfigFieldValues;
onValuesChange?: (values: AccessFormGoDaddyConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormGoDaddyConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Radio, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForGoEdge } from "@/domain/access";
type AccessFormGoEdgeConfigFieldValues = Nullish<AccessConfigForGoEdge>;
export type AccessFormGoEdgeConfigProps = {
export interface AccessFormGoEdgeConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormGoEdgeConfigFieldValues;
onValuesChange?: (values: AccessFormGoEdgeConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormGoEdgeConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForGoogleTrustServices } from "@/domain/access";
type AccessFormGoogleTrustServicesConfigFieldValues = Nullish<AccessConfigForGoogleTrustServices>;
export type AccessFormGoogleTrustServicesConfigProps = {
export interface AccessFormGoogleTrustServicesConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormGoogleTrustServicesConfigFieldValues;
onValuesChange?: (values: AccessFormGoogleTrustServicesConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormGoogleTrustServicesConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForHetzner } from "@/domain/access";
type AccessFormHetznerConfigFieldValues = Nullish<AccessConfigForHetzner>;
export type AccessFormHetznerConfigProps = {
export interface AccessFormHetznerConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormHetznerConfigFieldValues;
onValuesChange?: (values: AccessFormHetznerConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormHetznerConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForHuaweiCloud } from "@/domain/access";
type AccessFormHuaweiCloudConfigFieldValues = Nullish<AccessConfigForHuaweiCloud>;
export type AccessFormHuaweiCloudConfigProps = {
export interface AccessFormHuaweiCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormHuaweiCloudConfigFieldValues;
onValuesChange?: (values: AccessFormHuaweiCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormHuaweiCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForJDCloud } from "@/domain/access";
type AccessFormJDCloudConfigFieldValues = Nullish<AccessConfigForJDCloud>;
export type AccessFormJDCloudConfigProps = {
export interface AccessFormJDCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormJDCloudConfigFieldValues;
onValuesChange?: (values: AccessFormJDCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormJDCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForKong } from "@/domain/access";
type AccessFormKongConfigFieldValues = Nullish<AccessConfigForKong>;
export type AccessFormKongConfigProps = {
export interface AccessFormKongConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormKongConfigFieldValues;
onValuesChange?: (values: AccessFormKongConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormKongConfigFieldValues => {
return {
@@ -1,20 +1,20 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import TextFileInput from "@/components/TextFileInput";
import { type AccessConfigForKubernetes } from "@/domain/access";
type AccessFormKubernetesConfigFieldValues = Nullish<AccessConfigForKubernetes>;
export type AccessFormKubernetesConfigProps = {
export interface AccessFormKubernetesConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormKubernetesConfigFieldValues;
onValuesChange?: (values: AccessFormKubernetesConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormKubernetesConfigFieldValues => {
return {};
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForLarkBot } from "@/domain/access";
type AccessFormLarkBotConfigFieldValues = Nullish<AccessConfigForLarkBot>;
export type AccessFormLarkBotConfigProps = {
export interface AccessFormLarkBotConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormLarkBotConfigFieldValues;
onValuesChange?: (values: AccessFormLarkBotConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormLarkBotConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Radio, Select, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForLeCDN } from "@/domain/access";
type AccessFormLeCDNConfigFieldValues = Nullish<AccessConfigForLeCDN>;
export type AccessFormLeCDNConfigProps = {
export interface AccessFormLeCDNConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormLeCDNConfigFieldValues;
onValuesChange?: (values: AccessFormLeCDNConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormLeCDNConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForMattermost } from "@/domain/access";
type AccessFormMattermostConfigFieldValues = Nullish<AccessConfigForMattermost>;
export type AccessFormMattermostConfigProps = {
export interface AccessFormMattermostConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormMattermostConfigFieldValues;
onValuesChange?: (values: AccessFormMattermostConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormMattermostConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNS1 } from "@/domain/access";
type AccessFormNS1ConfigFieldValues = Nullish<AccessConfigForNS1>;
export type AccessFormNS1ConfigProps = {
export interface AccessFormNS1ConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNS1ConfigFieldValues;
onValuesChange?: (values: AccessFormNS1ConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNS1ConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNameDotCom } from "@/domain/access";
type AccessFormNameDotComConfigFieldValues = Nullish<AccessConfigForNameDotCom>;
export type AccessFormNameDotComConfigProps = {
export interface AccessFormNameDotComConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNameDotComConfigFieldValues;
onValuesChange?: (values: AccessFormNameDotComConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNameDotComConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNameSilo } from "@/domain/access";
type AccessFormNameSiloConfigFieldValues = Nullish<AccessConfigForNameSilo>;
export type AccessFormNameSiloConfigProps = {
export interface AccessFormNameSiloConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNameSiloConfigFieldValues;
onValuesChange?: (values: AccessFormNameSiloConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNameSiloConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNamecheap } from "@/domain/access";
type AccessFormNamecheapConfigFieldValues = Nullish<AccessConfigForNamecheap>;
export type AccessFormNamecheapConfigProps = {
export interface AccessFormNamecheapConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNamecheapConfigFieldValues;
onValuesChange?: (values: AccessFormNamecheapConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNamecheapConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNetcup } from "@/domain/access";
type AccessFormNetcupConfigFieldValues = Nullish<AccessConfigForNetcup>;
export type AccessFormNetcupConfigProps = {
export interface AccessFormNetcupConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNetcupConfigFieldValues;
onValuesChange?: (values: AccessFormNetcupConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNetcupConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForNetlify } from "@/domain/access";
type AccessFormNetlifyConfigFieldValues = Nullish<AccessConfigForNetlify>;
export type AccessFormNetlifyConfigProps = {
export interface AccessFormNetlifyConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNetlifyConfigFieldValues;
onValuesChange?: (values: AccessFormNetlifyConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormNetlifyConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForPorkbun } from "@/domain/access";
type AccessFormPorkbunConfigFieldValues = Nullish<AccessConfigForPorkbun>;
export type AccessFormPorkbunConfigProps = {
export interface AccessFormPorkbunConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormPorkbunConfigFieldValues;
onValuesChange?: (values: AccessFormPorkbunConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormPorkbunConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForPowerDNS } from "@/domain/access";
type AccessFormPowerDNSConfigFieldValues = Nullish<AccessConfigForPowerDNS>;
export type AccessFormPowerDNSConfigProps = {
export interface AccessFormPowerDNSConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormPowerDNSConfigFieldValues;
onValuesChange?: (values: AccessFormPowerDNSConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormPowerDNSConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForProxmoxVE } from "@/domain/access";
type AccessFormProxmoxVEConfigFieldValues = Nullish<AccessConfigForProxmoxVE>;
export type AccessFormProxmoxVEConfigProps = {
export interface AccessFormProxmoxVEConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormProxmoxVEConfigFieldValues;
onValuesChange?: (values: AccessFormProxmoxVEConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormProxmoxVEConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForQiniu } from "@/domain/access";
type AccessFormQiniuConfigFieldValues = Nullish<AccessConfigForQiniu>;
export type AccessFormQiniuConfigProps = {
export interface AccessFormQiniuConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormQiniuConfigFieldValues;
onValuesChange?: (values: AccessFormQiniuConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormQiniuConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForRainYun } from "@/domain/access";
type AccessFormRainYunConfigFieldValues = Nullish<AccessConfigForRainYun>;
export type AccessFormRainYunConfigProps = {
export interface AccessFormRainYunConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormRainYunConfigFieldValues;
onValuesChange?: (values: AccessFormRainYunConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormRainYunConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForRatPanel } from "@/domain/access";
type AccessFormRatPanelConfigFieldValues = Nullish<AccessConfigForRatPanel>;
export type AccessFormRatPanelConfigProps = {
export interface AccessFormRatPanelConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormRatPanelConfigFieldValues;
onValuesChange?: (values: AccessFormRatPanelConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormRatPanelConfigFieldValues => {
return {
@@ -1,8 +1,8 @@
import { useTranslation } from "react-i18next";
import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined, PlusOutlined } from "@ant-design/icons";
import { Button, Collapse, Form, type FormInstance, Input, InputNumber, Select, Space } from "antd";
import { IconCircleArrowDown, IconCircleArrowUp, IconCircleMinus, IconCirclePlus } from "@tabler/icons-react";
import { Button, Collapse, Form, type FormInstance, Input, InputNumber, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import Show from "@/components/Show";
import TextFileInput from "@/components/TextFileInput";
@@ -11,13 +11,13 @@ import { validDomainName, validIPv4Address, validIPv6Address, validPortNumber }
type AccessFormSSHConfigFieldValues = Nullish<AccessConfigForSSH>;
export type AccessFormSSHConfigProps = {
export interface AccessFormSSHConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormSSHConfigFieldValues;
onValuesChange?: (values: AccessFormSSHConfigFieldValues) => void;
};
}
const AUTH_METHOD_NONE = "none" as const;
const AUTH_METHOD_PASSWORD = "password" as const;
@@ -129,7 +129,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
<div className="w-1/3">
<Form.Item name="port" label={t("access.form.ssh_port.label")} rules={[formRule]}>
<InputNumber className="w-full" min={1} max={65535} placeholder={t("access.form.ssh_port.placeholder")} />
<InputNumber style={{ width: "100%" }} min={1} max={65535} placeholder={t("access.form.ssh_port.placeholder")} />
</Form.Item>
</div>
</div>
@@ -171,7 +171,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
<Form.Item name="jumpServers" label={t("access.form.ssh_jump_servers.label")} rules={[formRule]}>
<Form.List name="jumpServers">
{(fields, { add, remove, move }) => (
<Space className="w-full" direction="vertical" size="small">
<div className="flex flex-col gap-2">
{fields?.length > 0 ? (
<Collapse
items={fields.map((field, index) => {
@@ -198,7 +198,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
</div>
<div className="w-1/3">
<Form.Item name={[field.name, "port"]} label={t("access.form.ssh_port.label")} rules={[formRule]}>
<InputNumber className="w-full" placeholder={t("access.form.ssh_port.placeholder")} min={1} max={65535} />
<InputNumber style={{ width: "100%" }} placeholder={t("access.form.ssh_port.placeholder")} min={1} max={65535} />
</Form.Item>
</div>
</div>
@@ -244,9 +244,9 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
key: field.key,
label: <Label />,
extra: (
<Space.Compact>
<div className="flex items-center justify-end">
<Button
icon={<ArrowUpOutlined />}
icon={<IconCircleArrowUp size="1.25em" />}
color="default"
disabled={disabled || index === 0}
size="small"
@@ -257,7 +257,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
}}
/>
<Button
icon={<ArrowDownOutlined />}
icon={<IconCircleArrowDown size="1.25em" />}
color="default"
disabled={disabled || index === fields.length - 1}
size="small"
@@ -268,7 +268,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
}}
/>
<Button
icon={<CloseOutlined />}
icon={<IconCircleMinus size="1.25em" />}
color="default"
disabled={disabled}
size="small"
@@ -278,17 +278,17 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
e.stopPropagation();
}}
/>
</Space.Compact>
</div>
),
children: <Fields />,
};
})}
/>
) : null}
<Button className="w-full" type="dashed" icon={<PlusOutlined />} onClick={() => add(initFormModel())}>
<Button className="w-full" type="dashed" icon={<IconCirclePlus size="1.25em" />} onClick={() => add(initFormModel())}>
{t("access.form.ssh_jump_servers.add")}
</Button>
</Space>
</div>
)}
</Form.List>
</Form.Item>
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForSSLCom } from "@/domain/access";
type AccessFormSSLComConfigFieldValues = Nullish<AccessConfigForSSLCom>;
export type AccessFormSSLComConfigProps = {
export interface AccessFormSSLComConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormSSLComConfigFieldValues;
onValuesChange?: (values: AccessFormSSLComConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormSSLComConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForSafeLine } from "@/domain/access";
type AccessFormSafeLineConfigFieldValues = Nullish<AccessConfigForSafeLine>;
export type AccessFormSafeLineConfigProps = {
export interface AccessFormSafeLineConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormSafeLineConfigFieldValues;
onValuesChange?: (values: AccessFormSafeLineConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormSafeLineConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForSlackBot } from "@/domain/access";
type AccessFormSlackBotConfigFieldValues = Nullish<AccessConfigForSlackBot>;
export type AccessFormSlackBotConfigProps = {
export interface AccessFormSlackBotConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormSlackBotConfigFieldValues;
onValuesChange?: (values: AccessFormSlackBotConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormSlackBotConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForSpaceship } from "@/domain/access";
type AccessFormSpaceshipConfigFieldValues = Nullish<AccessConfigForSpaceship>;
export type AccessFormSpaceshipConfigProps = {
export interface AccessFormSpaceshipConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormSpaceshipConfigFieldValues;
onValuesChange?: (values: AccessFormSpaceshipConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormSpaceshipConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForTelegramBot } from "@/domain/access";
type AccessFormTelegramBotConfigFieldValues = Nullish<AccessConfigForTelegramBot>;
export type AccessFormTelegramBotConfigProps = {
export interface AccessFormTelegramBotConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormTelegramBotConfigFieldValues;
onValuesChange?: (values: AccessFormTelegramBotConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormTelegramBotConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForTencentCloud } from "@/domain/access";
type AccessFormTencentCloudConfigFieldValues = Nullish<AccessConfigForTencentCloud>;
export type AccessFormTencentCloudConfigProps = {
export interface AccessFormTencentCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormTencentCloudConfigFieldValues;
onValuesChange?: (values: AccessFormTencentCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormTencentCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForUCloud } from "@/domain/access";
type AccessFormUCloudConfigFieldValues = Nullish<AccessConfigForUCloud>;
export type AccessFormUCloudConfigProps = {
export interface AccessFormUCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormUCloudConfigFieldValues;
onValuesChange?: (values: AccessFormUCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormUCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForUniCloud } from "@/domain/access";
type AccessFormUniCloudConfigFieldValues = Nullish<AccessConfigForUniCloud>;
export type AccessFormUniCloudConfigProps = {
export interface AccessFormUniCloudConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormUniCloudConfigFieldValues;
onValuesChange?: (values: AccessFormUniCloudConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormUniCloudConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForUpyun } from "@/domain/access";
type AccessFormUpyunConfigFieldValues = Nullish<AccessConfigForUpyun>;
export type AccessFormUpyunConfigProps = {
export interface AccessFormUpyunConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormUpyunConfigFieldValues;
onValuesChange?: (values: AccessFormUpyunConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormUpyunConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForVercel } from "@/domain/access";
type AccessFormVercelConfigFieldValues = Nullish<AccessConfigForVercel>;
export type AccessFormVercelConfigProps = {
export interface AccessFormVercelConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormVercelConfigFieldValues;
onValuesChange?: (values: AccessFormVercelConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormVercelConfigFieldValues => {
return {
@@ -1,19 +1,19 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod/v4";
import { z } from "zod";
import { type AccessConfigForVolcEngine } from "@/domain/access";
type AccessFormVolcEngineConfigFieldValues = Nullish<AccessConfigForVolcEngine>;
export type AccessFormVolcEngineConfigProps = {
export interface AccessFormVolcEngineConfigProps {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormVolcEngineConfigFieldValues;
onValuesChange?: (values: AccessFormVolcEngineConfigFieldValues) => void;
};
}
const initFormModel = (): AccessFormVolcEngineConfigFieldValues => {
return {

Some files were not shown because too many files have changed in this diff Show More