mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-16 09:29:52 +00:00
feat(ui): improve responsive ui
This commit is contained in:
parent
e10fb64d6b
commit
831f0ee5d9
@ -13,7 +13,6 @@
|
|||||||
"dashboard.quick_actions": "快捷操作",
|
"dashboard.quick_actions": "快捷操作",
|
||||||
"dashboard.quick_actions.create_workflow": "新建工作流",
|
"dashboard.quick_actions.create_workflow": "新建工作流",
|
||||||
"dashboard.quick_actions.change_login_password": "修改登录密码",
|
"dashboard.quick_actions.change_login_password": "修改登录密码",
|
||||||
"dashboard.quick_actions.notification_settings": "消息推送设置",
|
"dashboard.quick_actions.cofigure_notification": "消息推送设置",
|
||||||
"dashboard.quick_actions.certificate_authority_configuration": "证书颁发机构配置"
|
"dashboard.quick_actions.configure_ca": "证书颁发机构配置"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,31 +29,54 @@ import { ClientResponseError } from "pocketbase";
|
|||||||
import { get as getStatistics } from "@/api/statistics";
|
import { get as getStatistics } from "@/api/statistics";
|
||||||
import WorkflowRunDetailDrawer from "@/components/workflow/WorkflowRunDetailDrawer";
|
import WorkflowRunDetailDrawer from "@/components/workflow/WorkflowRunDetailDrawer";
|
||||||
import { type Statistics } from "@/domain/statistics";
|
import { type Statistics } from "@/domain/statistics";
|
||||||
import { WORKFLOW_TRIGGERS } from "@/domain/workflow";
|
|
||||||
import { WORKFLOW_RUN_STATUSES, type WorkflowRunModel } from "@/domain/workflowRun";
|
import { WORKFLOW_RUN_STATUSES, type WorkflowRunModel } from "@/domain/workflowRun";
|
||||||
import { list as listWorkflowRuns } from "@/repository/workflowRun";
|
import { list as listWorkflowRuns } from "@/repository/workflowRun";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
const { useBreakpoint } = Grid;
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const screens = useBreakpoint();
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { token: themeToken } = theme.useToken();
|
const { token: themeToken } = theme.useToken();
|
||||||
|
const breakpoints = Grid.useBreakpoint();
|
||||||
|
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
|
const statisticsGridSpans = {
|
||||||
|
xs: { flex: "50%" },
|
||||||
|
md: { flex: "50%" },
|
||||||
|
lg: { flex: "33.3333%" },
|
||||||
|
xl: { flex: "33.3333%" },
|
||||||
|
xxl: { flex: "20%" },
|
||||||
|
};
|
||||||
|
const [statistics, setStatistics] = useState<Statistics>();
|
||||||
|
const { loading: statisticsLoading } = useRequest(
|
||||||
|
() => {
|
||||||
|
return getStatistics();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: (res) => {
|
||||||
|
setStatistics(res.data);
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
if (err instanceof ClientResponseError && err.isAbort) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(err);
|
||||||
|
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const tableColumns: TableProps<WorkflowRunModel>["columns"] = [
|
const tableColumns: TableProps<WorkflowRunModel>["columns"] = [
|
||||||
{
|
{
|
||||||
key: "$index",
|
key: "$index",
|
||||||
align: "center",
|
align: "center",
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
width: 50,
|
width: 50,
|
||||||
render: (_, __, index) => (page - 1) * pageSize + index + 1,
|
render: (_, __, index) => index + 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
@ -98,20 +121,6 @@ const Dashboard = () => {
|
|||||||
return <></>;
|
return <></>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "trigger",
|
|
||||||
title: t("workflow_run.props.trigger"),
|
|
||||||
ellipsis: true,
|
|
||||||
render: (_, record) => {
|
|
||||||
if (record.trigger === WORKFLOW_TRIGGERS.AUTO) {
|
|
||||||
return t("workflow_run.props.trigger.auto");
|
|
||||||
} else if (record.trigger === WORKFLOW_TRIGGERS.MANUAL) {
|
|
||||||
return t("workflow_run.props.trigger.manual");
|
|
||||||
}
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "startedAt",
|
key: "startedAt",
|
||||||
title: t("workflow_run.props.started_at"),
|
title: t("workflow_run.props.started_at"),
|
||||||
@ -139,7 +148,6 @@ const Dashboard = () => {
|
|||||||
{
|
{
|
||||||
key: "$action",
|
key: "$action",
|
||||||
align: "end",
|
align: "end",
|
||||||
fixed: "right",
|
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Button.Group>
|
<Button.Group>
|
||||||
@ -149,52 +157,17 @@ const Dashboard = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
const [tableData, setTableData] = useState<WorkflowRunModel[]>([]);
|
const [tableData, setTableData] = useState<WorkflowRunModel[]>([]);
|
||||||
const [_tableTotal, setTableTotal] = useState<number>(0);
|
const { loading: tableLoading } = useRequest(
|
||||||
|
|
||||||
const [page, _setPage] = useState<number>(1);
|
|
||||||
const [pageSize, _setPageSize] = useState<number>(3);
|
|
||||||
|
|
||||||
const { loading: loadingWorkflowRun } = useRequest(
|
|
||||||
() => {
|
() => {
|
||||||
return listWorkflowRuns({
|
return listWorkflowRuns({
|
||||||
page: page,
|
page: 1,
|
||||||
perPage: pageSize,
|
perPage: 5,
|
||||||
expand: true,
|
expand: true,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
refreshDeps: [page, pageSize],
|
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
setTableData(res.items);
|
setTableData(res.items);
|
||||||
setTableTotal(res.totalItems > 3 ? 3 : res.totalItems);
|
|
||||||
},
|
|
||||||
onError: (err) => {
|
|
||||||
if (err instanceof ClientResponseError && err.isAbort) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(err);
|
|
||||||
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const statisticsGridSpans = {
|
|
||||||
xs: { flex: "50%" },
|
|
||||||
md: { flex: "50%" },
|
|
||||||
lg: { flex: "33.3333%" },
|
|
||||||
xl: { flex: "33.3333%" },
|
|
||||||
xxl: { flex: "20%" },
|
|
||||||
};
|
|
||||||
const [statistics, setStatistics] = useState<Statistics>();
|
|
||||||
|
|
||||||
const { loading } = useRequest(
|
|
||||||
() => {
|
|
||||||
return getStatistics();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSuccess: (res) => {
|
|
||||||
setStatistics(res.data);
|
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
if (err instanceof ClientResponseError && err.isAbort) {
|
if (err instanceof ClientResponseError && err.isAbort) {
|
||||||
@ -218,7 +191,7 @@ const Dashboard = () => {
|
|||||||
<StatisticCard
|
<StatisticCard
|
||||||
icon={<SquareSigmaIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
|
icon={<SquareSigmaIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
|
||||||
label={t("dashboard.statistics.all_certificates")}
|
label={t("dashboard.statistics.all_certificates")}
|
||||||
loading={loading}
|
loading={statisticsLoading}
|
||||||
value={statistics?.certificateTotal ?? "-"}
|
value={statistics?.certificateTotal ?? "-"}
|
||||||
suffix={t("dashboard.statistics.unit")}
|
suffix={t("dashboard.statistics.unit")}
|
||||||
onClick={() => navigate("/certificates")}
|
onClick={() => navigate("/certificates")}
|
||||||
@ -228,7 +201,7 @@ const Dashboard = () => {
|
|||||||
<StatisticCard
|
<StatisticCard
|
||||||
icon={<CalendarClockIcon size={48} strokeWidth={1} color={themeToken.colorWarning} />}
|
icon={<CalendarClockIcon size={48} strokeWidth={1} color={themeToken.colorWarning} />}
|
||||||
label={t("dashboard.statistics.expire_soon_certificates")}
|
label={t("dashboard.statistics.expire_soon_certificates")}
|
||||||
loading={loading}
|
loading={statisticsLoading}
|
||||||
value={statistics?.certificateExpireSoon ?? "-"}
|
value={statistics?.certificateExpireSoon ?? "-"}
|
||||||
suffix={t("dashboard.statistics.unit")}
|
suffix={t("dashboard.statistics.unit")}
|
||||||
onClick={() => navigate("/certificates?state=expireSoon")}
|
onClick={() => navigate("/certificates?state=expireSoon")}
|
||||||
@ -238,7 +211,7 @@ const Dashboard = () => {
|
|||||||
<StatisticCard
|
<StatisticCard
|
||||||
icon={<CalendarX2Icon size={48} strokeWidth={1} color={themeToken.colorError} />}
|
icon={<CalendarX2Icon size={48} strokeWidth={1} color={themeToken.colorError} />}
|
||||||
label={t("dashboard.statistics.expired_certificates")}
|
label={t("dashboard.statistics.expired_certificates")}
|
||||||
loading={loading}
|
loading={statisticsLoading}
|
||||||
value={statistics?.certificateExpired ?? "-"}
|
value={statistics?.certificateExpired ?? "-"}
|
||||||
suffix={t("dashboard.statistics.unit")}
|
suffix={t("dashboard.statistics.unit")}
|
||||||
onClick={() => navigate("/certificates?state=expired")}
|
onClick={() => navigate("/certificates?state=expired")}
|
||||||
@ -248,7 +221,7 @@ const Dashboard = () => {
|
|||||||
<StatisticCard
|
<StatisticCard
|
||||||
icon={<WorkflowIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
|
icon={<WorkflowIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
|
||||||
label={t("dashboard.statistics.all_workflows")}
|
label={t("dashboard.statistics.all_workflows")}
|
||||||
loading={loading}
|
loading={statisticsLoading}
|
||||||
value={statistics?.workflowTotal ?? "-"}
|
value={statistics?.workflowTotal ?? "-"}
|
||||||
suffix={t("dashboard.statistics.unit")}
|
suffix={t("dashboard.statistics.unit")}
|
||||||
onClick={() => navigate("/workflows")}
|
onClick={() => navigate("/workflows")}
|
||||||
@ -258,7 +231,7 @@ const Dashboard = () => {
|
|||||||
<StatisticCard
|
<StatisticCard
|
||||||
icon={<FolderCheckIcon size={48} strokeWidth={1} color={themeToken.colorSuccess} />}
|
icon={<FolderCheckIcon size={48} strokeWidth={1} color={themeToken.colorSuccess} />}
|
||||||
label={t("dashboard.statistics.enabled_workflows")}
|
label={t("dashboard.statistics.enabled_workflows")}
|
||||||
loading={loading}
|
loading={statisticsLoading}
|
||||||
value={statistics?.workflowEnabled ?? "-"}
|
value={statistics?.workflowEnabled ?? "-"}
|
||||||
suffix={t("dashboard.statistics.unit")}
|
suffix={t("dashboard.statistics.unit")}
|
||||||
onClick={() => navigate("/workflows?state=enabled")}
|
onClick={() => navigate("/workflows?state=enabled")}
|
||||||
@ -268,34 +241,32 @@ const Dashboard = () => {
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Flex vertical={!screens.md} gap={16}>
|
<Flex justify="stretch" vertical={!breakpoints.lg} gap={16}>
|
||||||
<Card className="sm:h-full sm:w-[500px] sm:pb-32">
|
<Card className="max-lg:flex-1 lg:w-[360px]" title={t("dashboard.quick_actions")}>
|
||||||
<div className="text-lg font-semibold">{t("dashboard.quick_actions")}</div>
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
<div className="mt-9">
|
<Button block type="primary" size="large" icon={<PlusOutlined />} onClick={() => navigate("/workflows/new")}>
|
||||||
<Button className="w-full" type="primary" size="large" icon={<PlusOutlined />} onClick={() => navigate("/workflows/new")}>
|
|
||||||
{t("dashboard.quick_actions.create_workflow")}
|
{t("dashboard.quick_actions.create_workflow")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="mt-5 w-full" size="large" icon={<LockOutlined />} onClick={() => navigate("/settings/password")}>
|
<Button block size="large" icon={<LockOutlined />} onClick={() => navigate("/settings/password")}>
|
||||||
{t("dashboard.quick_actions.change_login_password")}
|
{t("dashboard.quick_actions.change_login_password")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="mt-5 w-full" size="large" icon={<SendOutlined />} onClick={() => navigate("/settings/notification")}>
|
<Button block size="large" icon={<SendOutlined />} onClick={() => navigate("/settings/notification")}>
|
||||||
{t("dashboard.quick_actions.notification_settings")}
|
{t("dashboard.quick_actions.notification_settings")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="mt-5 w-full" size="large" icon={<ApiOutlined />} onClick={() => navigate("/settings/ssl-provider")}>
|
<Button block size="large" icon={<ApiOutlined />} onClick={() => navigate("/settings/ssl-provider")}>
|
||||||
{t("dashboard.quick_actions.certificate_authority_configuration")}
|
{t("dashboard.quick_actions.certificate_authority_configuration")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="size-full">
|
<Card className="flex-1" title={t("dashboard.latest_workflow_run")}>
|
||||||
<div className="text-lg font-semibold">{t("dashboard.latest_workflow_run")} </div>
|
|
||||||
<Table<WorkflowRunModel>
|
<Table<WorkflowRunModel>
|
||||||
className="mt-5"
|
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
dataSource={tableData}
|
dataSource={tableData}
|
||||||
loading={loadingWorkflowRun}
|
loading={tableLoading}
|
||||||
locale={{
|
locale={{
|
||||||
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
|
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
|
||||||
}}
|
}}
|
||||||
|
pagination={false}
|
||||||
rowKey={(record: WorkflowRunModel) => record.id}
|
rowKey={(record: WorkflowRunModel) => record.id}
|
||||||
scroll={{ x: "max(100%, 960px)" }}
|
scroll={{ x: "max(100%, 960px)" }}
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user