diff --git a/ui/src/components/Empty.tsx b/ui/src/components/Empty.tsx index f40edde8a..83f79083a 100644 --- a/ui/src/components/Empty.tsx +++ b/ui/src/components/Empty.tsx @@ -27,7 +27,7 @@ const Empty = (props: EmptyProps) => {
-
+
diff --git a/ui/src/components/access/AccessEditDrawer.tsx b/ui/src/components/access/AccessEditDrawer.tsx index d4a7a4b59..9eba19a97 100644 --- a/ui/src/components/access/AccessEditDrawer.tsx +++ b/ui/src/components/access/AccessEditDrawer.tsx @@ -51,7 +51,7 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, . try { let values: AccessModel = formRef.current!.getFieldsValue(); - if (scene === "add") { + if (scene === "create") { if (data?.id) { throw "Invalid props: `data`"; } @@ -109,7 +109,7 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, . width={720} onClose={() => setOpen(false)} > - + ); diff --git a/ui/src/components/access/AccessEditModal.tsx b/ui/src/components/access/AccessEditModal.tsx index a20d50b97..dab018dd4 100644 --- a/ui/src/components/access/AccessEditModal.tsx +++ b/ui/src/components/access/AccessEditModal.tsx @@ -51,7 +51,7 @@ const AccessEditModal = ({ data, loading, trigger, scene, usage, afterSubmit, .. try { let values: AccessModel = formRef.current!.getFieldsValue(); - if (scene === "add") { + if (scene === "create") { if (data?.id) { throw "Invalid props: `data`"; } @@ -113,7 +113,7 @@ const AccessEditModal = ({ data, loading, trigger, scene, usage, afterSubmit, .. onCancel={handleCancelClick} >
- +
diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index ba9e1318f..0a7bb35b1 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -86,7 +86,7 @@ import AccessFormWestcnConfig from "./AccessFormWestcnConfig"; import AccessFormZeroSSLConfig from "./AccessFormZeroSSLConfig"; type AccessFormFieldValues = Partial>; -type AccessFormScenes = "add" | "edit"; +type AccessFormScenes = "create" | "edit"; type AccessFormUsages = "both-dns-hosting" | "ca-only" | "notification-only"; export type AccessFormProps = { @@ -406,7 +406,7 @@ const AccessForm = forwardRef(({ className,
{t("workflow_node.apply.form.provider_access.button")} @@ -408,7 +408,7 @@ const ApplyNodeConfigForm = forwardRef {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 27a72600e..f78fb5995 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -489,7 +489,7 @@ 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 1bfd2b43d..da9f62daa 100644 --- a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx @@ -199,7 +199,7 @@ const NotifyNodeConfigForm = forwardRef
{t("workflow_node.notify.form.provider_access.button")} diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index 9db5b047c..db735bb55 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -2,7 +2,10 @@ "access.page.title": "Credentials", "access.page.subtitle": "Credentials store authentication information (username and password, API key, OAuth tokens, etc.) to connect with specific third-party apps and services.", - "access.nodata": "No credentials. Please create an credential first.", + "access.nodata": "No credentials", + "access.nodata.title": "No credentials", + "access.nodata.description": "Add a credential to store authentication information.", + "access.nodata.button": "Create credential", "access.search.placeholder": "Search by credential name ...", @@ -13,7 +16,6 @@ "access.action.delete.confirm": "Are you sure want to delete this \"{{name}}\" credential?
This action cannot be undone.", "access.props.name": "Name", - "access.props.provider": "Provider", "access.props.provider.usage.dns": "DNS provider", "access.props.provider.usage.hosting": "Hosting provider", "access.props.provider.usage.ca": "Certificate authority", diff --git a/ui/src/i18n/locales/en/nls.certificate.json b/ui/src/i18n/locales/en/nls.certificate.json index fc654faec..d8ba23d41 100644 --- a/ui/src/i18n/locales/en/nls.certificate.json +++ b/ui/src/i18n/locales/en/nls.certificate.json @@ -3,8 +3,8 @@ "certificate.page.subtitle": "SSL certificates contain the website's public key and the website's identity, along with related information. They are generated from the execution output of workflows.", "certificate.nodata.title": "No Certificates", - "certificate.nodata.description": "Create a workflow to generate certificates!", - "certificate.nodata.button": "Create workflow", + "certificate.nodata.description": "Add a workflow to generate certificates!", + "certificate.nodata.button": "Go to workflows", "certificate.search.placeholder": "Search by certificate name or serial number ...", @@ -19,9 +19,9 @@ "certificate.props.validity.less_than_a_day": "Less than 1 day", "certificate.props.validity.expired": "Expired", "certificate.props.validity.expiration": "Expire on {{date}}", - "certificate.props.validity.filters.all": "All", - "certificate.props.validity.filters.expire_soon": "Expire soon", - "certificate.props.validity.filters.expired": "Expired", + "certificate.props.validity.filter.all": "All", + "certificate.props.validity.filter.expire_soon": "Expire soon", + "certificate.props.validity.filter.expired": "Expired", "certificate.props.brand": "Brand", "certificate.props.source": "Source", "certificate.props.source.workflow": "Workflow", diff --git a/ui/src/i18n/locales/en/nls.workflow.json b/ui/src/i18n/locales/en/nls.workflow.json index 304e3b69e..c8baf5067 100644 --- a/ui/src/i18n/locales/en/nls.workflow.json +++ b/ui/src/i18n/locales/en/nls.workflow.json @@ -23,8 +23,8 @@ "workflow.props.trigger.manual": "Manual", "workflow.props.last_run_at": "Last run at", "workflow.props.state": "State", - "workflow.props.state.filters.enabled": "Active", - "workflow.props.state.filters.disabled": "Inactive", + "workflow.props.state.filter.enabled": "Active", + "workflow.props.state.filter.disabled": "Inactive", "workflow.props.created_at": "Created at", "workflow.props.updated_at": "Updated at", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index e0c933d0d..edb09fce0 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -2,7 +2,9 @@ "access.page.title": "授权管理", "access.page.subtitle": "授权中存储有用于访问特定第三方应用程序和服务的身份验证信息(如账号密码、API 密钥、OAuth 令牌等)。", - "access.nodata": "暂无授权信息,请先新建授权", + "access.nodata.title": "暂无授权", + "access.nodata.description": "新建一个授权并存储身份验证信息吧~", + "access.nodata.button": "新建授权", "access.search.placeholder": "按授权名称搜索……", @@ -13,7 +15,6 @@ "access.action.delete.confirm": "确定要删除授权「{{name}}」吗?
注意此操作不可撤销,请谨慎操作。", "access.props.name": "名称", - "access.props.provider": "提供商", "access.props.provider.usage.dns": "DNS 提供商", "access.props.provider.usage.hosting": "主机提供商", "access.props.provider.usage.ca": "证书颁发机构", diff --git a/ui/src/i18n/locales/zh/nls.certificate.json b/ui/src/i18n/locales/zh/nls.certificate.json index f89028ad1..78569f948 100644 --- a/ui/src/i18n/locales/zh/nls.certificate.json +++ b/ui/src/i18n/locales/zh/nls.certificate.json @@ -4,7 +4,7 @@ "certificate.nodata.title": "暂无证书", "certificate.nodata.description": "新建一个工作流去生成证书吧~", - "certificate.nodata.button": "新建工作流", + "certificate.nodata.button": "前往工作流", "certificate.search.placeholder": "按证书名称或序列号搜索……", @@ -19,9 +19,9 @@ "certificate.props.validity.less_than_a_day": "不足 1 天", "certificate.props.validity.expired": "已过期", "certificate.props.validity.expiration": "{{date}} 过期", - "certificate.props.validity.filters.all": "全部", - "certificate.props.validity.filters.expire_soon": "即将过期", - "certificate.props.validity.filters.expired": "已过期", + "certificate.props.validity.filter.all": "全部", + "certificate.props.validity.filter.expire_soon": "即将过期", + "certificate.props.validity.filter.expired": "已过期", "certificate.props.brand": "证书品牌", "certificate.props.source": "来源", "certificate.props.source.workflow": "工作流", diff --git a/ui/src/i18n/locales/zh/nls.workflow.json b/ui/src/i18n/locales/zh/nls.workflow.json index c13f3dcab..bcf823bb8 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.json +++ b/ui/src/i18n/locales/zh/nls.workflow.json @@ -23,8 +23,8 @@ "workflow.props.trigger.manual": "手动", "workflow.props.last_run_at": "最近执行时间", "workflow.props.state": "启用状态", - "workflow.props.state.filters.enabled": "启用", - "workflow.props.state.filters.disabled": "未启用", + "workflow.props.state.filter.enabled": "启用", + "workflow.props.state.filter.disabled": "未启用", "workflow.props.created_at": "创建时间", "workflow.props.updated_at": "更新时间", diff --git a/ui/src/pages/accesses/AccessList.tsx b/ui/src/pages/accesses/AccessList.tsx index 7ce89c523..b01b583ef 100644 --- a/ui/src/pages/accesses/AccessList.tsx +++ b/ui/src/pages/accesses/AccessList.tsx @@ -1,13 +1,14 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useSearchParams } from "react-router-dom"; -import { IconCopy, IconEdit, IconPlus, IconReload, IconTrash } from "@tabler/icons-react"; +import { IconCirclePlus, IconCopy, IconEdit, IconFingerprint, IconPlus, IconReload, IconTrash } from "@tabler/icons-react"; import { useRequest } from "ahooks"; -import { App, Avatar, Button, Empty, Input, Table, type TableProps, Tabs, Tooltip, Typography } from "antd"; +import { App, Avatar, Button, Input, Skeleton, Table, type TableProps, Tabs, Tooltip, Typography } from "antd"; import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; import AccessEditDrawer, { type AccessEditDrawerProps } from "@/components/access/AccessEditDrawer"; +import Empty from "@/components/Empty"; import { type AccessModel } from "@/domain/access"; import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider"; import { useZustandShallowSelector } from "@/hooks"; @@ -48,17 +49,16 @@ const AccessList = () => { key: "name", title: t("access.props.name"), ellipsis: true, - render: (_, record) => <>{record.name}, - }, - { - key: "provider", - title: t("access.props.provider"), - ellipsis: true, render: (_, record) => { return ( -
- - {t(accessProvidersMap.get(record.provider)?.name ?? "")} +
+ +
+ {record.name} + + {t(accessProvidersMap.get(record.provider)?.name ?? "")} + +
); }, @@ -71,14 +71,6 @@ const AccessList = () => { return dayjs(record.created!).format("YYYY-MM-DD HH:mm:ss"); }, }, - { - key: "updatedAt", - title: t("access.props.updated_at"), - ellipsis: true, - render: (_, record) => { - return dayjs(record.updated!).format("YYYY-MM-DD HH:mm:ss"); - }, - }, { key: "$action", align: "end", @@ -86,35 +78,36 @@ const AccessList = () => { width: 120, render: (_, record) => (
- -
} size="large" type="primary"> {t("access.action.create")} @@ -269,12 +278,32 @@ const AccessList = () => { size="large" onChange={(key) => handleTabChange(key)} /> + columns={tableColumns} dataSource={tableData} loading={!loadedAtOnce || loading} locale={{ - emptyText: , + emptyText: loading ? ( + + ) : ( + } + extra={ + } type="primary"> + {t("access.action.create")} + + } + /> + } + /> + ), }} pagination={{ current: page, @@ -290,9 +319,17 @@ const AccessList = () => { setPageSize(pageSize); }, }} + rowClassName="cursor-pointer" rowKey={(record) => record.id} scroll={{ x: "max(100%, 960px)" }} + onRow={(record) => ({ + onClick: () => { + handleRecordDetailClick(record); + }, + })} /> + +
); diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx index ace2e0d34..aebc892c6 100644 --- a/ui/src/pages/certificates/CertificateList.tsx +++ b/ui/src/pages/certificates/CertificateList.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate, useSearchParams } from "react-router-dom"; -import { IconBrowserShare, IconCirclePlus, IconReload, IconShieldCheckeredFilled, IconTrash } from "@tabler/icons-react"; +import { IconBrowserShare, IconExternalLink, IconReload, IconShieldCheckeredFilled, IconTrash } from "@tabler/icons-react"; import { useRequest } from "ahooks"; import { App, Button, Input, Segmented, Skeleton, Table, type TableProps, Tooltip, Typography } from "antd"; import dayjs from "dayjs"; @@ -34,6 +34,13 @@ const CertificateList = () => { const [pageSize, setPageSize] = useState(() => parseInt(+searchParams.get("perPage")! + "") || 15); const tableColumns: TableProps["columns"] = [ + { + key: "$index", + align: "center", + fixed: "left", + width: 50, + render: (_, __, index) => (page - 1) * pageSize + index + 1, + }, { key: "name", title: t("certificate.props.subject_alt_names"), @@ -209,8 +216,8 @@ const CertificateList = () => { const [detailRecord, setDetailRecord] = useState(); const [detailOpen, setDetailOpen] = useState(false); - const handleRecordDetailClick = (record: CertificateModel) => { - setDetailRecord(record); + const handleRecordDetailClick = (certificate: CertificateModel) => { + setDetailRecord(certificate); setDetailOpen(true); }; @@ -252,9 +259,9 @@ const CertificateList = () => { {t("certificate.props.validity.filters.all")}, value: "" }, - { label: {t("certificate.props.validity.filters.expire_soon")}, value: "expireSoon" }, - { label: {t("certificate.props.validity.filters.expired")}, value: "expired" }, + { label: {t("certificate.props.validity.filter.all")}, value: "" }, + { label: {t("certificate.props.validity.filter.expire_soon")}, value: "expireSoon" }, + { label: {t("certificate.props.validity.filter.expired")}, value: "expired" }, ]} size="large" value={(filters["state"] as string) || ""} @@ -300,8 +307,8 @@ const CertificateList = () => { {t("common.button.reload")} ) : ( - ) } diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx index c92cacca2..4007c0180 100644 --- a/ui/src/pages/workflows/WorkflowList.tsx +++ b/ui/src/pages/workflows/WorkflowList.tsx @@ -77,8 +77,8 @@ const WorkflowList = () => { defaultFilteredValue: searchParams.has("state") ? [searchParams.get("state") as string] : undefined, filterDropdown: ({ setSelectedKeys, confirm, clearFilters }) => { const items: Required["items"] = [ - ["enabled", "workflow.props.state.filters.enabled"], - ["disabled", "workflow.props.state.filters.disabled"], + ["enabled", "workflow.props.state.filter.enabled"], + ["disabled", "workflow.props.state.filter.disabled"], ].map(([key, label]) => { return { key,