From 065e3e96fae2b1ee6270decc08494d575f670abe Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Tue, 22 Jul 2025 20:55:49 +0800 Subject: [PATCH] feat(ui): new AccessNew page --- ui/src/App.tsx | 2 +- ui/src/components/access/AccessEditDrawer.tsx | 14 +- ui/src/components/access/AccessEditModal.tsx | 131 ------------------ ui/src/components/access/AccessForm.tsx | 8 +- .../provider/AccessProviderPicker.tsx | 52 ++++--- .../provider/DeploymentProviderPicker.tsx | 20 ++- .../workflow/node/ApplyNodeConfigForm.tsx | 10 +- .../workflow/node/DeployNodeConfigForm.tsx | 6 +- .../workflow/node/NotifyNodeConfigForm.tsx | 6 +- .../components/workflow/node/UnknownNode.tsx | 2 +- .../components/workflow/node/_SharedNode.tsx | 2 +- ui/src/i18n/locales/en/nls.access.json | 3 + ui/src/i18n/locales/zh/nls.access.json | 5 +- ui/src/pages/accesses/AccessList.tsx | 45 +++--- ui/src/pages/accesses/AccessNew.tsx | 126 +++++++++++++++++ ui/src/pages/certificates/CertificateList.tsx | 1 - ui/src/pages/dashboard/Dashboard.tsx | 2 +- ui/src/pages/workflows/WorkflowList.tsx | 9 +- ui/src/pages/workflows/WorkflowNew.tsx | 4 +- ui/src/{router.tsx => routers/index.tsx} | 37 ++--- 20 files changed, 248 insertions(+), 237 deletions(-) delete mode 100644 ui/src/components/access/AccessEditModal.tsx create mode 100644 ui/src/pages/accesses/AccessNew.tsx rename ui/src/{router.tsx => routers/index.tsx} (62%) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 4fbce7893..47e50c056 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -10,7 +10,7 @@ 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 = { [localeNames.ZH]: AntdLocaleZhCN, diff --git a/ui/src/components/access/AccessEditDrawer.tsx b/ui/src/components/access/AccessEditDrawer.tsx index 339eeec09..13ccb2d2e 100644 --- a/ui/src/components/access/AccessEditDrawer.tsx +++ b/ui/src/components/access/AccessEditDrawer.tsx @@ -11,9 +11,9 @@ import { getErrMsg } from "@/utils/error"; import AccessForm, { type AccessFormInstance, type AccessFormProps } from "./AccessForm"; export interface AccessEditDrawerProps { - action: AccessFormProps["action"]; data?: AccessFormProps["initialValues"]; loading?: boolean; + mode: AccessFormProps["mode"]; open?: boolean; trigger?: React.ReactNode; usage?: AccessFormProps["usage"]; @@ -21,7 +21,7 @@ export interface AccessEditDrawerProps { afterSubmit?: (record: AccessModel) => void; } -const AccessEditDrawer = ({ action, data, loading, trigger, usage, afterSubmit, ...props }: AccessEditDrawerProps) => { +const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ...props }: AccessEditDrawerProps) => { const { t } = useTranslation(); const { notification } = App.useApp(); @@ -56,13 +56,13 @@ const AccessEditDrawer = ({ action, data, loading, trigger, usage, afterSubmit, try { let values: AccessModel = formRef.current!.getFieldsValue(); - if (action === "create") { + if (mode === "create") { if (data?.id) { throw "Invalid props: `data`"; } values = await createAccess(values); - } else if (action === "edit") { + } else if (mode === "edit") { if (!data?.id) { throw "Invalid props: `data`"; } @@ -106,7 +106,7 @@ const AccessEditDrawer = ({ action, data, loading, trigger, usage, afterSubmit, ) : ( @@ -116,11 +116,11 @@ const AccessEditDrawer = ({ action, data, loading, trigger, usage, afterSubmit, loading={loading} maskClosable={!formPending} open={open} - title={t(`access.action.${action}.modal.title`)} + title={t(`access.action.${mode}.modal.title`)} width={720} onClose={() => setOpen(false)} > - + ); diff --git a/ui/src/components/access/AccessEditModal.tsx b/ui/src/components/access/AccessEditModal.tsx deleted file mode 100644 index 819b57493..000000000 --- a/ui/src/components/access/AccessEditModal.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useControllableValue } from "ahooks"; -import { App, Modal } 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 interface AccessEditModalProps { - action: AccessFormProps["action"]; - data?: AccessFormProps["initialValues"]; - loading?: boolean; - open?: boolean; - usage?: AccessFormProps["usage"]; - trigger?: React.ReactNode; - onOpenChange?: (open: boolean) => void; - afterSubmit?: (record: AccessModel) => void; -} - -const AccessEditModal = ({ action, data, loading, trigger, usage, afterSubmit, ...props }: AccessEditModalProps) => { - const { t } = useTranslation(); - - const { notification } = App.useApp(); - - const { createAccess, updateAccess } = useAccessesStore(useZustandShallowSelector(["createAccess", "updateAccess"])); - - const [open, setOpen] = useControllableValue(props, { - valuePropName: "open", - defaultValuePropName: "defaultOpen", - trigger: "onOpenChange", - }); - - const triggerEl = useTriggerElement(trigger, { onClick: () => setOpen(true) }); - - const formRef = useRef(null); - const [formPending, setFormPending] = useState(false); - - const [footerShow, setFooterShow] = useState(!!data?.provider); - useEffect(() => { - setFooterShow(!!data?.provider); - }, [data?.provider]); - - const handleOkClick = async () => { - setFormPending(true); - try { - await formRef.current!.validateFields(); - } catch (err) { - setFormPending(false); - throw err; - } - - try { - let values: AccessModel = formRef.current!.getFieldsValue(); - - if (action === "create") { - if (data?.id) { - throw "Invalid props: `data`"; - } - - values = await createAccess(values); - } else if (action === "edit") { - if (!data?.id) { - throw "Invalid props: `data`"; - } - - values = await updateAccess({ ...data, ...values }); - } else { - throw "Invalid props: `action`"; - } - - afterSubmit?.(values); - setOpen(false); - } catch (err) { - notification.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); - - throw err; - } finally { - setFormPending(false); - } - }; - - const handleCancelClick = () => { - if (formPending) return; - - setOpen(false); - }; - - const handleFormValuesChange: AccessFormProps["onValuesChange"] = (values) => { - setFooterShow(!!values.provider); - }; - - return ( - <> - {triggerEl} - - setOpen(false)} - cancelButtonProps={{ disabled: formPending }} - cancelText={t("common.button.cancel")} - closable - confirmLoading={formPending} - destroyOnHidden - footer={footerShow ? undefined : false} - loading={loading} - okText={action === "edit" ? t("common.button.save") : t("common.button.submit")} - open={open} - title={t(`access.action.${action}.modal.title`)} - width={480} - onOk={handleOkClick} - onCancel={handleCancelClick} - > - - - - ); -}; - -export default AccessEditModal; diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 4908380c1..0b37526bb 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -86,13 +86,13 @@ import AccessFormWestcnConfig from "./AccessFormWestcnConfig"; import AccessFormZeroSSLConfig from "./AccessFormZeroSSLConfig"; type AccessFormFieldValues = Partial>; -type AccessFormActions = "create" | "edit"; +type AccessFormModes = "create" | "edit"; type AccessFormUsages = "dns" | "hosting" | "dns-hosting" | "ca" | "notification"; export interface AccessFormProps { className?: string; style?: React.CSSProperties; - action: AccessFormActions; + mode: AccessFormModes; disabled?: boolean; initialValues?: AccessFormFieldValues; usage?: AccessFormUsages; @@ -105,7 +105,7 @@ export interface AccessFormInstance { validateFields: FormInstance["validateFields"]; } -const AccessForm = forwardRef(({ className, style, action, disabled, initialValues, usage, onValuesChange }, ref) => { +const AccessForm = forwardRef(({ className, style, mode, disabled, initialValues, usage, onValuesChange }, ref) => { const { t } = useTranslation(); const formSchema = z.object({ @@ -383,7 +383,7 @@ const AccessForm = forwardRef(({ className, boolean; + gap?: number | "small" | "middle" | "large"; placeholder?: string; showOptionTags?: boolean | { [key in AccessUsageType]?: boolean }; onSelect?: (value: string) => void; } -const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder, showOptionTags, onSelect }: AccessProviderPickerProps) => { +const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder, showOptionTags, onSelect, ...props }: AccessProviderPickerProps) => { + const { gap = "middle" } = props; + const { t } = useTranslation(); const wrapperRef = useRef(null); @@ -31,6 +34,22 @@ const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder } }, []); + const showOptionTagForDNS = useMemo(() => { + return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.DNS] : !!showOptionTags; + }, [showOptionTags]); + const showOptionTagForHosting = useMemo(() => { + return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.HOSTING] : !!showOptionTags; + }, [showOptionTags]); + const showOptionTagForCA = useMemo(() => { + return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.CA] : !!showOptionTags; + }, [showOptionTags]); + const showOptionTagForNotification = useMemo(() => { + return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.NOTIFICATION] : !!showOptionTags; + }, [showOptionTags]); + const showOptionTagAnyhow = useMemo(() => { + return showOptionTagForDNS || showOptionTagForHosting || showOptionTagForCA || showOptionTagForNotification; + }, [showOptionTagForDNS, showOptionTagForHosting, showOptionTagForCA, showOptionTagForNotification]); + const providers = useMemo(() => { return Array.from(accessProvidersMap.values()) .filter((provider) => { @@ -54,25 +73,9 @@ const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder return 1; } - const cols = Math.floor(wrapperSize.width / 200); + const cols = Math.floor(wrapperSize.width / (showOptionTagAnyhow ? 240 : 200)); return Math.min(9, Math.max(1, cols)); - }, [wrapperSize]); - - const showOptionTagForDNS = useMemo(() => { - return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.DNS] : !!showOptionTags; - }, [showOptionTags]); - const showOptionTagForHosting = useMemo(() => { - return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.HOSTING] : !!showOptionTags; - }, [showOptionTags]); - const showOptionTagForCA = useMemo(() => { - return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.CA] : !!showOptionTags; - }, [showOptionTags]); - const showOptionTagForNotification = useMemo(() => { - return typeof showOptionTags === "object" ? !!showOptionTags?.[ACCESS_USAGES.NOTIFICATION] : !!showOptionTags; - }, [showOptionTags]); - const showOptionTagAnyhow = useMemo(() => { - return showOptionTagForDNS || showOptionTagForHosting || showOptionTagForCA || showOptionTagForNotification; - }, [showOptionTagForDNS, showOptionTagForHosting, showOptionTagForCA, showOptionTagForNotification]); + }, [wrapperSize, showOptionTagAnyhow]); const handleProviderTypeSelect = (value: string) => { onSelect?.(value); @@ -84,12 +87,19 @@ const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder
0} fallback={}> -
+
{providers.map((provider) => { return (
{ diff --git a/ui/src/components/provider/DeploymentProviderPicker.tsx b/ui/src/components/provider/DeploymentProviderPicker.tsx index 7259fa050..97b20ec46 100644 --- a/ui/src/components/provider/DeploymentProviderPicker.tsx +++ b/ui/src/components/provider/DeploymentProviderPicker.tsx @@ -12,11 +12,14 @@ export interface DeploymentProviderPickerProps { style?: React.CSSProperties; autoFocus?: boolean; filter?: (record: DeploymentProvider) => boolean; + gap?: number | "small" | "middle" | "large"; placeholder?: string; onSelect?: (value: string) => void; } -const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeholder, onSelect }: DeploymentProviderPickerProps) => { +const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeholder, onSelect, ...props }: DeploymentProviderPickerProps) => { + const { gap = "middle" } = props; + const { t } = useTranslation(); const wrapperRef = useRef(null); @@ -103,13 +106,20 @@ const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeho />
- 0} fallback={}> -
+ 0} fallback={}> +
{providers.map((provider) => { return (
{ @@ -120,7 +130,7 @@ const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeho
} shape="square" size={28} />
-
+
{t(provider.name) || "\u00A0"}
diff --git a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx index d2b2b534e..e1e495fe6 100644 --- a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx @@ -7,7 +7,7 @@ import { AutoComplete, Button, Divider, Flex, Form, type FormInstance, Input, In import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; -import AccessEditModal from "@/components/access/AccessEditModal"; +import AccessEditDrawer from "@/components/access/AccessEditDrawer"; import AccessSelect from "@/components/access/AccessSelect"; import MultipleSplitValueInput from "@/components/MultipleSplitValueInput"; import ACMEDns01ProviderSelect from "@/components/provider/ACMEDns01ProviderSelect"; @@ -325,8 +325,8 @@ const ApplyNodeConfigForm = forwardRef
- {t("workflow_node.apply.form.provider_access.button")} @@ -406,9 +406,9 @@ const ApplyNodeConfigForm = forwardRef{t("workflow_node.apply.form.ca_provider_access.label")}
- {t("workflow_node.apply.form.ca_provider_access.button")} diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index 736b4b363..aa67e0153 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -5,7 +5,7 @@ import { Button, Divider, Flex, Form, type FormInstance, Select, Switch, Tooltip import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; -import AccessEditModal from "@/components/access/AccessEditModal"; +import AccessEditDrawer from "@/components/access/AccessEditDrawer"; import AccessSelect from "@/components/access/AccessSelect"; import DeploymentProviderPicker from "@/components/provider/DeploymentProviderPicker.tsx"; import DeploymentProviderSelect from "@/components/provider/DeploymentProviderSelect.tsx"; @@ -487,9 +487,9 @@ const DeployNodeConfigForm = forwardRef
- {t("workflow_node.deploy.form.provider_access.button")} diff --git a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx index 3a0d5f680..aa9321f16 100644 --- a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx @@ -5,7 +5,7 @@ import { Button, Divider, Flex, Form, type FormInstance, Input, Switch, Typograp import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; -import AccessEditModal from "@/components/access/AccessEditModal"; +import AccessEditDrawer from "@/components/access/AccessEditDrawer"; import AccessSelect from "@/components/access/AccessSelect"; import NotificationProviderSelect from "@/components/provider/NotificationProviderSelect"; import Show from "@/components/Show"; @@ -198,8 +198,8 @@ const NotifyNodeConfigForm = forwardRef{t("workflow_node.notify.form.provider_access.label")}
- {t("workflow_node.notify.form.provider_access.button")} diff --git a/ui/src/components/workflow/node/UnknownNode.tsx b/ui/src/components/workflow/node/UnknownNode.tsx index 83240edf5..620a5451e 100644 --- a/ui/src/components/workflow/node/UnknownNode.tsx +++ b/ui/src/components/workflow/node/UnknownNode.tsx @@ -20,7 +20,7 @@ const UnknownNode = ({ node, disabled }: MonitorNodeProps) => { return ( <>
- +
{ + const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { t } = useTranslation(); @@ -182,19 +183,23 @@ const AccessList = () => { fetchAccesses(); }; + const handleCreateClick = () => { + navigate(`/accesses/new?usage=${filters["usage"]}`); + }; + const [detailRecord, setDetailRecord] = useState>(); - const [detailAction, setDetailAction] = useState("create"); + const [detailMode, setDetailMode] = useState("create"); const [detailOpen, setDetailOpen] = useState(false); const handleRecordDetailClick = (access: AccessModel) => { setDetailRecord(access); - setDetailAction("edit"); + setDetailMode("edit"); setDetailOpen(true); }; const handleRecordDuplicateClick = (access: AccessModel) => { setDetailRecord({ ...access, id: undefined, name: `${access.name}-copy` }); - setDetailAction("create"); + setDetailMode("create"); setDetailOpen(true); }; @@ -245,15 +250,9 @@ const AccessList = () => {
- } size="large" type="primary"> - {t("access.action.create.button")} - - } - /> +
@@ -291,15 +290,9 @@ const AccessList = () => { description={t("access.nodata.description")} icon={} extra={ - } type="primary"> - {t("access.action.create.button")} - - } - /> + } /> ), @@ -328,13 +321,7 @@ const AccessList = () => { })} /> - +
); diff --git a/ui/src/pages/accesses/AccessNew.tsx b/ui/src/pages/accesses/AccessNew.tsx new file mode 100644 index 000000000..fc036a63a --- /dev/null +++ b/ui/src/pages/accesses/AccessNew.tsx @@ -0,0 +1,126 @@ +import { useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate, useSearchParams } from "react-router-dom"; +import { App, Button, Flex } from "antd"; + +import AccessForm, { type AccessFormInstance, type AccessFormProps } from "@/components/access/AccessForm"; +import AccessProviderPicker from "@/components/provider/AccessProviderPicker"; +import Show from "@/components/Show"; +import { type AccessModel } from "@/domain/access"; +import { ACCESS_USAGES, type AccessProvider } from "@/domain/provider"; +import { useZustandShallowSelector } from "@/hooks"; +import { useAccessesStore } from "@/stores/access"; +import { getErrMsg } from "@/utils/error"; + +const AccessNew = () => { + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + + const { t } = useTranslation(); + + const { notification } = App.useApp(); + + const { createAccess } = useAccessesStore(useZustandShallowSelector(["createAccess"])); + + const formRef = useRef(null); + const [formModel, setFormModel] = useState>({}); + const [formPending, setFormPending] = useState(false); + + const providerUsage = useMemo(() => { + return searchParams.get("usage") as AccessFormProps["usage"]; + }, [searchParams]); + const providerFilter = useMemo(() => { + switch (providerUsage) { + 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": + return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.CA); + case "notification": + return (record: AccessProvider) => record.usages.includes(ACCESS_USAGES.NOTIFICATION); + } + + return undefined; + }, [providerUsage]); + + const handleProviderPick = (value: string) => { + setFormModel((prev) => { + return { ...prev, provider: value, config: undefined }; + }); + }; + + const handleSubmitClick = async () => { + setFormPending(true); + try { + await formRef.current!.validateFields(); + } catch (err) { + setFormPending(false); + throw err; + } + + try { + const values: AccessModel = formRef.current!.getFieldsValue(); + await createAccess(values); + + navigate(`/accesses?usage=${providerUsage}`, { replace: true }); + } catch (err) { + notification.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); + + throw err; + } finally { + setFormPending(false); + } + }; + + const handleCancelClick = () => { + setFormModel((prev) => { + return { ...prev, provider: undefined, config: undefined, reserve: undefined }; + }); + }; + + return ( +
+
+

{t("access.new.title")}

+

{t("access.new.subtitle")}

+
+ +
+ + } + > + setFormModel(values)} + /> + + + + + +
+
+ ); +}; + +export default AccessNew; diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx index 5b6621d5e..af93f3544 100644 --- a/ui/src/pages/certificates/CertificateList.tsx +++ b/ui/src/pages/certificates/CertificateList.tsx @@ -258,7 +258,6 @@ const CertificateList = () => {
{t("certificate.props.validity.filter.all")}, value: "" }, { label: {t("certificate.props.validity.filter.expire_soon")}, value: "expireSoon" }, diff --git a/ui/src/pages/dashboard/Dashboard.tsx b/ui/src/pages/dashboard/Dashboard.tsx index 7c814cd51..85773609e 100644 --- a/ui/src/pages/dashboard/Dashboard.tsx +++ b/ui/src/pages/dashboard/Dashboard.tsx @@ -13,7 +13,7 @@ import { IconUserShield, } from "@tabler/icons-react"; import { useRequest } from "ahooks"; -import { App, Button, Card, Col, Divider, Empty, Flex, Grid, Row, Space, Statistic, Table, type TableProps, Typography, theme } from "antd"; +import { App, Button, Card, Col, Divider, Empty, Flex, Grid, Row, Statistic, Table, type TableProps, Typography, theme } from "antd"; import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx index 7a856f2b1..d287c04f9 100644 --- a/ui/src/pages/workflows/WorkflowList.tsx +++ b/ui/src/pages/workflows/WorkflowList.tsx @@ -196,16 +196,16 @@ const WorkflowList = () => { setPage(1); }; - const handleCreateClick = () => { - navigate("/workflows/new"); - }; - const handleReloadClick = () => { if (loading) return; refreshData(); }; + const handleCreateClick = () => { + navigate("/workflows/new"); + }; + const handleRecordDetailClick = (workflow: WorkflowModel) => { navigate(`/workflows/${workflow.id}`); }; @@ -303,7 +303,6 @@ const WorkflowList = () => {
{t("workflow.props.state.filter.all")}, value: "" }, { label: {t("workflow.props.state.filter.enabled")}, value: "enabled" }, diff --git a/ui/src/pages/workflows/WorkflowNew.tsx b/ui/src/pages/workflows/WorkflowNew.tsx index 90bdd56c0..7a1583e27 100644 --- a/ui/src/pages/workflows/WorkflowNew.tsx +++ b/ui/src/pages/workflows/WorkflowNew.tsx @@ -115,12 +115,12 @@ const WorkflowNew = () => {

{t("workflow.new.title")}

-

{t("workflow.new.subtitle")}

+

{t("workflow.new.subtitle")}

-
{t("workflow.new.templates.title")}
+
{t("workflow.new.templates.title")}
diff --git a/ui/src/router.tsx b/ui/src/routers/index.tsx similarity index 62% rename from ui/src/router.tsx rename to ui/src/routers/index.tsx index 5c15c34dc..78ff91261 100644 --- a/ui/src/router.tsx +++ b/ui/src/routers/index.tsx @@ -1,20 +1,21 @@ -import { createHashRouter } from "react-router-dom"; +import { createHashRouter } from "react-router-dom"; -import AccessList from "./pages/accesses/AccessList"; -import AuthLayout from "./pages/AuthLayout"; -import CertificateList from "./pages/certificates/CertificateList"; -import ConsoleLayout from "./pages/ConsoleLayout"; -import Dashboard from "./pages/dashboard/Dashboard"; -import ErrorLayout from "./pages/ErrorLayout"; -import Login from "./pages/login/Login"; -import Settings from "./pages/settings/Settings"; -import SettingsAccount from "./pages/settings/SettingsAccount"; -import SettingsAppearance from "./pages/settings/SettingsAppearance"; -import SettingsPersistence from "./pages/settings/SettingsPersistence"; -import SettingsSSLProvider from "./pages/settings/SettingsSSLProvider"; -import WorkflowDetail from "./pages/workflows/WorkflowDetail"; -import WorkflowList from "./pages/workflows/WorkflowList"; -import WorkflowNew from "./pages/workflows/WorkflowNew"; +import AccessList from "@/pages/accesses/AccessList"; +import AccessNew from "@/pages/accesses/AccessNew"; +import AuthLayout from "@/pages/AuthLayout"; +import CertificateList from "@/pages/certificates/CertificateList"; +import ConsoleLayout from "@/pages/ConsoleLayout"; +import Dashboard from "@/pages/dashboard/Dashboard"; +import ErrorLayout from "@/pages/ErrorLayout"; +import Login from "@/pages/login/Login"; +import Settings from "@/pages/settings/Settings"; +import SettingsAccount from "@/pages/settings/SettingsAccount"; +import SettingsAppearance from "@/pages/settings/SettingsAppearance"; +import SettingsPersistence from "@/pages/settings/SettingsPersistence"; +import SettingsSSLProvider from "@/pages/settings/SettingsSSLProvider"; +import WorkflowDetail from "@/pages/workflows/WorkflowDetail"; +import WorkflowList from "@/pages/workflows/WorkflowList"; +import WorkflowNew from "@/pages/workflows/WorkflowNew"; export const router = createHashRouter([ { @@ -29,6 +30,10 @@ export const router = createHashRouter([ path: "/accesses", element: , }, + { + path: "/accesses/new", + element: , + }, { path: "/certificates", element: ,