feat(ui): replace action buttons with dropdown menus in list pages

This commit is contained in:
Fu Diwei 2025-07-23 11:21:24 +08:00
parent 8e9e55d1bb
commit 9db0530ee4
4 changed files with 153 additions and 124 deletions

View File

@ -1,9 +1,9 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useSearchParams } from "react-router-dom";
import { IconCirclePlus, IconCopy, IconEdit, IconFingerprint, IconPlus, IconReload, IconTrash } from "@tabler/icons-react";
import { IconCirclePlus, IconCopy, IconDotsVertical, IconFingerprint, IconPlus, IconReload, IconTrash } from "@tabler/icons-react";
import { useRequest } from "ahooks";
import { App, Avatar, Button, Input, Skeleton, Table, type TableProps, Tabs, Tooltip, Typography } from "antd";
import { App, Avatar, Button, Dropdown, Input, Skeleton, Table, type TableProps, Tabs, Typography } from "antd";
import dayjs from "dayjs";
import { ClientResponseError } from "pocketbase";
@ -77,42 +77,51 @@ const AccessList = () => {
key: "$action",
align: "end",
fixed: "right",
width: 120,
width: 64,
render: (_, record) => (
<div className="flex items-center justify-end">
<Tooltip title={t("common.button.edit")}>
<Button
color="primary"
icon={<IconEdit size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDetailClick(record);
}}
/>
</Tooltip>
<Tooltip title={t("common.button.duplicate")}>
<Button
color="primary"
icon={<IconCopy size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDuplicateClick(record);
}}
/>
</Tooltip>
<Tooltip title={t("common.button.delete")}>
<Button
color="danger"
icon={<IconTrash size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDeleteClick(record);
}}
/>
</Tooltip>
<div
className="flex items-center justify-end"
onClick={(e) => {
e.stopPropagation();
}}
>
<Dropdown
menu={{
items: [
{
key: "duplicate",
label: t("common.button.duplicate"),
icon: (
<span className="anticon scale-125">
<IconCopy size="1em" />
</span>
),
onClick: () => {
handleRecordDuplicateClick(record);
},
},
{
type: "divider",
},
{
key: "delete",
label: t("common.button.delete"),
danger: true,
icon: (
<span className="anticon scale-125">
<IconTrash size="1em" />
</span>
),
onClick: () => {
handleRecordDeleteClick(record);
},
},
],
}}
trigger={["click"]}
>
<Button icon={<IconDotsVertical size="1.25em" />} type="text" />
</Dropdown>
</div>
),
},

View File

@ -1,9 +1,9 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useSearchParams } from "react-router-dom";
import { IconBrowserShare, IconCertificate, IconExternalLink, IconReload, IconTrash } from "@tabler/icons-react";
import { IconCertificate, IconDotsVertical, IconExternalLink, IconReload, IconTrash } from "@tabler/icons-react";
import { useRequest } from "ahooks";
import { App, Button, Input, Segmented, Skeleton, Table, type TableProps, Tooltip, Typography } from "antd";
import { App, Button, Dropdown, Input, Segmented, Skeleton, Table, type TableProps, Typography } from "antd";
import dayjs from "dayjs";
import { ClientResponseError } from "pocketbase";
@ -136,31 +136,36 @@ const CertificateList = () => {
key: "$action",
align: "end",
fixed: "right",
width: 120,
width: 64,
render: (_, record) => (
<div className="flex items-center justify-end">
<Tooltip title={t("common.button.view")}>
<Button
color="primary"
icon={<IconBrowserShare size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDetailClick(record);
}}
/>
</Tooltip>
<Tooltip title={t("common.button.delete")}>
<Button
color="danger"
icon={<IconTrash size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDeleteClick(record);
}}
/>
</Tooltip>
<div
className="flex items-center justify-end"
onClick={(e) => {
e.stopPropagation();
}}
>
<Dropdown
menu={{
items: [
{
key: "delete",
label: t("common.button.delete"),
danger: true,
icon: (
<span className="anticon scale-125">
<IconTrash size="1em" />
</span>
),
onClick: () => {
handleRecordDeleteClick(record);
},
},
],
}}
trigger={["click"]}
>
<Button icon={<IconDotsVertical size="1.25em" />} type="text" />
</Dropdown>
</div>
),
},

View File

@ -3,7 +3,6 @@ import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import {
IconActivity,
IconBrowserShare,
IconHierarchy3,
IconPlugConnected,
IconPlus,
@ -255,16 +254,6 @@ const WorkflowRunHistoryTable = () => {
return <></>;
},
},
{
key: "$action",
align: "end",
width: 120,
render: (_, record) => (
<div className="flex items-center justify-end">
<WorkflowRunDetailDrawer data={record} trigger={<Button color="primary" icon={<IconBrowserShare size="1.25em" />} variant="text" />} />
</div>
),
},
];
const [tableData, setTableData] = useState<WorkflowRunModel[]>([]);
const { loading: tableLoading } = useRequest(
@ -292,19 +281,37 @@ const WorkflowRunHistoryTable = () => {
}
);
const [detailRecord, setDetailRecord] = useState<WorkflowRunModel>();
const [detailOpen, setDetailOpen] = useState<boolean>(false);
const handleRecordDetailClick = (workflowRun: WorkflowRunModel) => {
setDetailRecord(workflowRun);
setDetailOpen(true);
};
return (
<Table<WorkflowRunModel>
columns={tableColumns}
dataSource={tableData}
loading={tableLoading}
locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
}}
pagination={false}
rowKey={(record) => record.id}
scroll={{ x: "max(100%, 720px)" }}
size="small"
/>
<>
<Table<WorkflowRunModel>
columns={tableColumns}
dataSource={tableData}
loading={tableLoading}
locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
}}
pagination={false}
rowClassName="cursor-pointer"
rowKey={(record) => record.id}
scroll={{ x: "max(100%, 720px)" }}
size="small"
onRow={(record) => ({
onClick: () => {
handleRecordDetailClick(record);
},
})}
/>
<WorkflowRunDetailDrawer data={detailRecord} open={detailOpen} onOpenChange={setDetailOpen} />
</>
);
};

View File

@ -1,9 +1,9 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useSearchParams } from "react-router-dom";
import { IconCirclePlus, IconCopy, IconEdit, IconHierarchy3, IconPlus, IconReload, IconTrash } from "@tabler/icons-react";
import { IconCirclePlus, IconCopy, IconDotsVertical, IconHierarchy3, IconPlus, IconReload, IconTrash } from "@tabler/icons-react";
import { useRequest } from "ahooks";
import { App, Button, Flex, Input, Segmented, Skeleton, Switch, Table, type TableProps, Tooltip, Typography } from "antd";
import { App, Button, Dropdown, Flex, Input, Segmented, Skeleton, Switch, Table, type TableProps, Typography } from "antd";
import dayjs from "dayjs";
import { ClientResponseError } from "pocketbase";
@ -123,43 +123,51 @@ const WorkflowList = () => {
key: "$action",
align: "end",
fixed: "right",
width: 120,
width: 64,
render: (_, record) => (
<div className="flex items-center justify-end">
<Tooltip title={t("common.button.edit")}>
<Button
color="primary"
icon={<IconEdit size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDetailClick(record);
}}
/>
</Tooltip>
<Tooltip title={t("common.button.duplicate")}>
<Button
color="primary"
icon={<IconCopy size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDuplicateClick(record);
}}
/>
</Tooltip>
<Tooltip title={t("common.button.delete")}>
<Button
color="danger"
danger
icon={<IconTrash size="1.25em" />}
variant="text"
onClick={(e) => {
e.stopPropagation();
handleRecordDeleteClick(record);
}}
/>
</Tooltip>
<div
className="flex items-center justify-end"
onClick={(e) => {
e.stopPropagation();
}}
>
<Dropdown
menu={{
items: [
{
key: "duplicate",
label: t("common.button.duplicate"),
icon: (
<span className="anticon scale-125">
<IconCopy size="1em" />
</span>
),
onClick: () => {
handleRecordDuplicateClick(record);
},
},
{
type: "divider",
},
{
key: "delete",
label: t("common.button.delete"),
danger: true,
icon: (
<span className="anticon scale-125">
<IconTrash size="1em" />
</span>
),
onClick: () => {
handleRecordDeleteClick(record);
},
},
],
}}
trigger={["click"]}
>
<Button icon={<IconDotsVertical size="1.25em" />} type="text" />
</Dropdown>
</div>
),
},