feat(ui): display artifact certificates in WorkflowRunDetail

This commit is contained in:
Fu Diwei
2025-02-10 12:13:54 +08:00
parent b8513eb0b6
commit 75c89b3d0b
14 changed files with 170 additions and 19 deletions

View File

@@ -1,9 +1,17 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Alert, Typography } from "antd";
import { SelectOutlined as SelectOutlinedIcon } from "@ant-design/icons";
import { useRequest } from "ahooks";
import { Alert, Button, Divider, Empty, Table, type TableProps, Tooltip, Typography, notification } from "antd";
import dayjs from "dayjs";
import { ClientResponseError } from "pocketbase";
import CertificateDetailDrawer from "@/components/certificate/CertificateDetailDrawer";
import Show from "@/components/Show";
import { type CertificateModel } from "@/domain/certificate";
import { WORKFLOW_RUN_STATUSES, type WorkflowRunModel } from "@/domain/workflowRun";
import { listByWorkflowRunId as listCertificateByWorkflowRunId } from "@/repository/certificate";
import { getErrMsg } from "@/utils/error";
export type WorkflowRunDetailProps = {
className?: string;
@@ -45,8 +53,108 @@ const WorkflowRunDetail = ({ data, ...props }: WorkflowRunDetailProps) => {
})}
</div>
</div>
<Show when={data.status === WORKFLOW_RUN_STATUSES.SUCCEEDED}>
<Divider />
<WorkflowRunArtifacts runId={data.id} />
</Show>
</div>
);
};
const WorkflowRunArtifacts = ({ runId }: { runId: string }) => {
const { t } = useTranslation();
const [notificationApi, NotificationContextHolder] = notification.useNotification();
const tableColumns: TableProps<CertificateModel>["columns"] = [
{
key: "$index",
align: "center",
fixed: "left",
width: 50,
render: (_, __, index) => index + 1,
},
{
key: "type",
title: t("workflow_run_artifact.props.type"),
render: () => t("workflow_run_artifact.props.type.certificate"),
},
{
key: "name",
title: t("workflow_run_artifact.props.name"),
ellipsis: true,
render: (_, record) => {
return (
<Typography.Text delete={!!record.deleted} ellipsis>
{record.subjectAltNames}
</Typography.Text>
);
},
},
{
key: "$action",
align: "end",
width: 120,
render: (_, record) => (
<Button.Group>
<CertificateDetailDrawer
data={record}
trigger={
<Tooltip title={t("certificate.action.view")}>
<Button color="primary" disabled={!!record.deleted} icon={<SelectOutlinedIcon />} variant="text" />
</Tooltip>
}
/>
</Button.Group>
),
},
];
const [tableData, setTableData] = useState<CertificateModel[]>([]);
const { loading: tableLoading } = useRequest(
() => {
return listCertificateByWorkflowRunId(runId);
},
{
refreshDeps: [runId],
onBefore: () => {
setTableData([]);
},
onSuccess: (res) => {
setTableData(res.items);
},
onError: (err) => {
if (err instanceof ClientResponseError && err.isAbort) {
return;
}
console.error(err);
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
throw err;
},
}
);
return (
<>
{NotificationContextHolder}
<Typography.Title level={5}>{t("workflow_run.artifacts")}</Typography.Title>
<Table<CertificateModel>
columns={tableColumns}
dataSource={tableData}
loading={tableLoading}
locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />,
}}
pagination={false}
rowKey={(record) => record.id}
size="small"
/>
</>
);
};
export default WorkflowRunDetail;

View File

@@ -301,7 +301,7 @@ const WorkflowRuns = ({ className, style, workflowId }: WorkflowRunsProps) => {
setPageSize(pageSize);
},
}}
rowKey={(record: WorkflowRunModel) => record.id}
rowKey={(record) => record.id}
scroll={{ x: "max(100%, 960px)" }}
/>
</div>

View File

@@ -86,7 +86,7 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
</Form.Item>
<Form.Item name="message" label={t("workflow_node.notify.form.message.label")} rules={[formRule]}>
<Input.TextArea autoSize={{ minRows: 3, maxRows: 10 }} placeholder={t("workflow_node.notify.form.message.placeholder")} />
<Input.TextArea autoSize={{ minRows: 3, maxRows: 5 }} placeholder={t("workflow_node.notify.form.message.placeholder")} />
</Form.Item>
<Form.Item className="mb-0">

View File

@@ -3,8 +3,7 @@ import { useTranslation } from "react-i18next";
import { Flex, Typography } from "antd";
import { produce } from "immer";
import type { WorkflowNodeConfigForUpload } from "@/domain/workflow";
import { WorkflowNodeType } from "@/domain/workflow";
import { type WorkflowNodeConfigForUpload, WorkflowNodeType } from "@/domain/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow";

View File

@@ -141,7 +141,7 @@ const UploadNodeConfigForm = forwardRef<UploadNodeConfigFormInstance, UploadNode
</Form.Item>
<Form.Item name="certificate" label={t("workflow_node.upload.form.certificate.label")} rules={[formRule]}>
<Input.TextArea readOnly autoSize={{ minRows: 5, maxRows: 10 }} placeholder={t("workflow_node.upload.form.certificate.placeholder")} />
<Input.TextArea readOnly autoSize={{ minRows: 5, maxRows: 5 }} placeholder={t("workflow_node.upload.form.certificate.placeholder")} />
</Form.Item>
<Form.Item>
@@ -151,7 +151,7 @@ const UploadNodeConfigForm = forwardRef<UploadNodeConfigFormInstance, UploadNode
</Form.Item>
<Form.Item name="privateKey" label={t("workflow_node.upload.form.private_key.label")} rules={[formRule]}>
<Input.TextArea readOnly autoSize={{ minRows: 5, maxRows: 10 }} placeholder={t("workflow_node.upload.form.private_key.placeholder")} />
<Input.TextArea readOnly autoSize={{ minRows: 5, maxRows: 5 }} placeholder={t("workflow_node.upload.form.private_key.placeholder")} />
</Form.Item>
<Form.Item>