feat(ui): improve responsive ui

This commit is contained in:
Fu Diwei 2025-01-16 21:50:16 +08:00
parent e10fb64d6b
commit 831f0ee5d9
2 changed files with 50 additions and 80 deletions

View File

@ -13,7 +13,6 @@
"dashboard.quick_actions": "快捷操作",
"dashboard.quick_actions.create_workflow": "新建工作流",
"dashboard.quick_actions.change_login_password": "修改登录密码",
"dashboard.quick_actions.notification_settings": "消息推送设置",
"dashboard.quick_actions.certificate_authority_configuration": "证书颁发机构配置"
"dashboard.quick_actions.cofigure_notification": "消息推送设置",
"dashboard.quick_actions.configure_ca": "证书颁发机构配置"
}

View File

@ -29,31 +29,54 @@ import { ClientResponseError } from "pocketbase";
import { get as getStatistics } from "@/api/statistics";
import WorkflowRunDetailDrawer from "@/components/workflow/WorkflowRunDetailDrawer";
import { type Statistics } from "@/domain/statistics";
import { WORKFLOW_TRIGGERS } from "@/domain/workflow";
import { WORKFLOW_RUN_STATUSES, type WorkflowRunModel } from "@/domain/workflowRun";
import { list as listWorkflowRuns } from "@/repository/workflowRun";
import { getErrMsg } from "@/utils/error";
const { useBreakpoint } = Grid;
const Dashboard = () => {
const navigate = useNavigate();
const screens = useBreakpoint();
const { t } = useTranslation();
const { token: themeToken } = theme.useToken();
const breakpoints = Grid.useBreakpoint();
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"] = [
{
key: "$index",
align: "center",
fixed: "left",
width: 50,
render: (_, __, index) => (page - 1) * pageSize + index + 1,
render: (_, __, index) => index + 1,
},
{
key: "name",
@ -98,20 +121,6 @@ const Dashboard = () => {
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",
title: t("workflow_run.props.started_at"),
@ -139,7 +148,6 @@ const Dashboard = () => {
{
key: "$action",
align: "end",
fixed: "right",
width: 120,
render: (_, record) => (
<Button.Group>
@ -149,52 +157,17 @@ const Dashboard = () => {
},
];
const [tableData, setTableData] = useState<WorkflowRunModel[]>([]);
const [_tableTotal, setTableTotal] = useState<number>(0);
const [page, _setPage] = useState<number>(1);
const [pageSize, _setPageSize] = useState<number>(3);
const { loading: loadingWorkflowRun } = useRequest(
const { loading: tableLoading } = useRequest(
() => {
return listWorkflowRuns({
page: page,
perPage: pageSize,
page: 1,
perPage: 5,
expand: true,
});
},
{
refreshDeps: [page, pageSize],
onSuccess: (res) => {
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) => {
if (err instanceof ClientResponseError && err.isAbort) {
@ -218,7 +191,7 @@ const Dashboard = () => {
<StatisticCard
icon={<SquareSigmaIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
label={t("dashboard.statistics.all_certificates")}
loading={loading}
loading={statisticsLoading}
value={statistics?.certificateTotal ?? "-"}
suffix={t("dashboard.statistics.unit")}
onClick={() => navigate("/certificates")}
@ -228,7 +201,7 @@ const Dashboard = () => {
<StatisticCard
icon={<CalendarClockIcon size={48} strokeWidth={1} color={themeToken.colorWarning} />}
label={t("dashboard.statistics.expire_soon_certificates")}
loading={loading}
loading={statisticsLoading}
value={statistics?.certificateExpireSoon ?? "-"}
suffix={t("dashboard.statistics.unit")}
onClick={() => navigate("/certificates?state=expireSoon")}
@ -238,7 +211,7 @@ const Dashboard = () => {
<StatisticCard
icon={<CalendarX2Icon size={48} strokeWidth={1} color={themeToken.colorError} />}
label={t("dashboard.statistics.expired_certificates")}
loading={loading}
loading={statisticsLoading}
value={statistics?.certificateExpired ?? "-"}
suffix={t("dashboard.statistics.unit")}
onClick={() => navigate("/certificates?state=expired")}
@ -248,7 +221,7 @@ const Dashboard = () => {
<StatisticCard
icon={<WorkflowIcon size={48} strokeWidth={1} color={themeToken.colorInfo} />}
label={t("dashboard.statistics.all_workflows")}
loading={loading}
loading={statisticsLoading}
value={statistics?.workflowTotal ?? "-"}
suffix={t("dashboard.statistics.unit")}
onClick={() => navigate("/workflows")}
@ -258,7 +231,7 @@ const Dashboard = () => {
<StatisticCard
icon={<FolderCheckIcon size={48} strokeWidth={1} color={themeToken.colorSuccess} />}
label={t("dashboard.statistics.enabled_workflows")}
loading={loading}
loading={statisticsLoading}
value={statistics?.workflowEnabled ?? "-"}
suffix={t("dashboard.statistics.unit")}
onClick={() => navigate("/workflows?state=enabled")}
@ -268,34 +241,32 @@ const Dashboard = () => {
<Divider />
<Flex vertical={!screens.md} gap={16}>
<Card className="sm:h-full sm:w-[500px] sm:pb-32">
<div className="text-lg font-semibold">{t("dashboard.quick_actions")}</div>
<div className="mt-9">
<Button className="w-full" type="primary" size="large" icon={<PlusOutlined />} onClick={() => navigate("/workflows/new")}>
<Flex justify="stretch" vertical={!breakpoints.lg} gap={16}>
<Card className="max-lg:flex-1 lg:w-[360px]" title={t("dashboard.quick_actions")}>
<Space className="w-full" direction="vertical" size="large">
<Button block type="primary" size="large" icon={<PlusOutlined />} onClick={() => navigate("/workflows/new")}>
{t("dashboard.quick_actions.create_workflow")}
</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")}
</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")}
</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")}
</Button>
</div>
</Space>
</Card>
<Card className="size-full">
<div className="text-lg font-semibold">{t("dashboard.latest_workflow_run")} </div>
<Card className="flex-1" title={t("dashboard.latest_workflow_run")}>
<Table<WorkflowRunModel>
className="mt-5"
columns={tableColumns}
dataSource={tableData}
loading={loadingWorkflowRun}
loading={tableLoading}
locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
}}
pagination={false}
rowKey={(record: WorkflowRunModel) => record.id}
scroll={{ x: "max(100%, 960px)" }}
/>