3 changed files with 0 additions and 211 deletions
@ -1,172 +0,0 @@ |
|||||
"use client"; |
|
||||
|
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"; |
|
||||
import { App, Button, Card, Empty, Modal, Pagination, Popconfirm, Space, Spin, Typography } from "antd"; |
|
||||
import { useRouter, useSearchParams } from "next/navigation"; |
|
||||
import { useI18n } from "@/i18n"; |
|
||||
import { |
|
||||
deleteCanvasWorkflow, |
|
||||
listCanvasWorkflows, |
|
||||
type CanvasWorkflowListItem, |
|
||||
type CanvasWorkflowPageInfo, |
|
||||
} from "@/lib/canvasWorkflowApi"; |
|
||||
import { useCanvasWorkflowStore } from "@/store/canvasWorkflowStore"; |
|
||||
|
|
||||
interface CanvasWorkflowPickerModalProps { |
|
||||
isOpen: boolean; |
|
||||
onClose: () => void; |
|
||||
} |
|
||||
|
|
||||
const DEFAULT_PAGE_INFO: CanvasWorkflowPageInfo = { |
|
||||
page: 1, |
|
||||
pageSize: 10, |
|
||||
pageCount: 1, |
|
||||
total: 0, |
|
||||
}; |
|
||||
|
|
||||
function workflowDisplayTitle(workflow: CanvasWorkflowListItem): string { |
|
||||
return workflow.title?.trim() || workflow.code?.trim() || `#${workflow.id}`; |
|
||||
} |
|
||||
|
|
||||
function formatWorkflowTime(value?: string): string { |
|
||||
if (!value) return "-"; |
|
||||
const date = new Date(value); |
|
||||
if (Number.isNaN(date.getTime())) return value; |
|
||||
return date.toLocaleString(); |
|
||||
} |
|
||||
|
|
||||
function buildCanvasWorkflowUrl(searchParams: URLSearchParams): string { |
|
||||
const query = searchParams.toString(); |
|
||||
return query ? `/canvas?${query}` : "/canvas"; |
|
||||
} |
|
||||
|
|
||||
export function CanvasWorkflowPickerModal({ isOpen, onClose }: CanvasWorkflowPickerModalProps) { |
|
||||
const { t } = useI18n(); |
|
||||
const { message } = App.useApp(); |
|
||||
const router = useRouter(); |
|
||||
const searchParams = useSearchParams(); |
|
||||
const currentCanvasWorkflowId = useCanvasWorkflowStore((state) => state.currentCanvasWorkflowId); |
|
||||
const clearCurrentCanvasWorkflow = useCanvasWorkflowStore((state) => state.clearCurrentCanvasWorkflow); |
|
||||
const [workflows, setWorkflows] = useState<CanvasWorkflowListItem[]>([]); |
|
||||
const [pageInfo, setPageInfo] = useState<CanvasWorkflowPageInfo>(DEFAULT_PAGE_INFO); |
|
||||
const [isLoading, setIsLoading] = useState(false); |
|
||||
|
|
||||
const loadWorkflows = useCallback(async (page = pageInfo.page, pageSize = pageInfo.pageSize) => { |
|
||||
setIsLoading(true); |
|
||||
try { |
|
||||
const data = await listCanvasWorkflows({ page, pageSize }); |
|
||||
setWorkflows(data.list); |
|
||||
setPageInfo(data.pageInfo); |
|
||||
} catch (error) { |
|
||||
const errorMessage = error instanceof Error ? error.message : t("canvasWorkflow.listFailed"); |
|
||||
void message.error(errorMessage); |
|
||||
} finally { |
|
||||
setIsLoading(false); |
|
||||
} |
|
||||
}, [message, pageInfo.page, pageInfo.pageSize, t]); |
|
||||
|
|
||||
useEffect(() => { |
|
||||
if (isOpen) { |
|
||||
void loadWorkflows(1, pageInfo.pageSize); |
|
||||
} |
|
||||
}, [isOpen]); |
|
||||
|
|
||||
const openWorkflow = (workflow: CanvasWorkflowListItem) => { |
|
||||
const nextParams = new URLSearchParams(searchParams.toString()); |
|
||||
nextParams.set("workflowId", String(workflow.id)); |
|
||||
router.push(buildCanvasWorkflowUrl(nextParams)); |
|
||||
onClose(); |
|
||||
}; |
|
||||
|
|
||||
const handleDelete = async (workflow: CanvasWorkflowListItem) => { |
|
||||
try { |
|
||||
await deleteCanvasWorkflow(workflow.id); |
|
||||
void message.success(t("canvasWorkflow.deleteSuccess")); |
|
||||
if (currentCanvasWorkflowId === workflow.id) { |
|
||||
const nextParams = new URLSearchParams(searchParams.toString()); |
|
||||
nextParams.delete("workflowId"); |
|
||||
router.replace(buildCanvasWorkflowUrl(nextParams)); |
|
||||
clearCurrentCanvasWorkflow(); |
|
||||
} |
|
||||
await loadWorkflows(pageInfo.page, pageInfo.pageSize); |
|
||||
} catch (error) { |
|
||||
const errorMessage = error instanceof Error ? error.message : t("canvasWorkflow.deleteFailed"); |
|
||||
void message.error(errorMessage); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
const cards = useMemo(() => workflows.map((workflow) => ( |
|
||||
<Card |
|
||||
key={workflow.id} |
|
||||
size="small" |
|
||||
className="h-full" |
|
||||
title={ |
|
||||
<Typography.Text strong ellipsis> |
|
||||
{workflowDisplayTitle(workflow)} |
|
||||
</Typography.Text> |
|
||||
} |
|
||||
extra={<Typography.Text type="secondary">#{workflow.id}</Typography.Text>} |
|
||||
actions={[ |
|
||||
<Button key="open" type="link" size="small" onClick={() => openWorkflow(workflow)}> |
|
||||
{t("canvasWorkflow.open")} |
|
||||
</Button>, |
|
||||
<Popconfirm |
|
||||
key="delete" |
|
||||
title={t("canvasWorkflow.deleteConfirmTitle")} |
|
||||
description={t("canvasWorkflow.deleteConfirmDesc")} |
|
||||
okText={t("common.remove")} |
|
||||
cancelText={t("common.cancel")} |
|
||||
onConfirm={() => handleDelete(workflow)} |
|
||||
> |
|
||||
<Button type="link" danger size="small"> |
|
||||
{t("common.remove")} |
|
||||
</Button> |
|
||||
</Popconfirm>, |
|
||||
]} |
|
||||
> |
|
||||
<Space direction="vertical" size={8} className="w-full"> |
|
||||
<Typography.Paragraph |
|
||||
type="secondary" |
|
||||
ellipsis={{ rows: 2 }} |
|
||||
className="!mb-0 min-h-11" |
|
||||
> |
|
||||
{workflow.desp?.trim() || t("canvasWorkflow.noDescription")} |
|
||||
</Typography.Paragraph> |
|
||||
<Typography.Text type="secondary" className="text-xs"> |
|
||||
{t("canvasWorkflow.columnUpdatedAt")}: {formatWorkflowTime(workflow.updateTime)} |
|
||||
</Typography.Text> |
|
||||
</Space> |
|
||||
</Card> |
|
||||
)), [workflows, t, searchParams, currentCanvasWorkflowId, pageInfo.page, pageInfo.pageSize]); |
|
||||
|
|
||||
return ( |
|
||||
<Modal |
|
||||
title={t("canvasWorkflow.projects")} |
|
||||
open={isOpen} |
|
||||
onCancel={onClose} |
|
||||
footer={null} |
|
||||
width={760} |
|
||||
destroyOnHidden |
|
||||
> |
|
||||
<Spin spinning={isLoading}> |
|
||||
{workflows.length > 0 ? ( |
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-2"> |
|
||||
{cards} |
|
||||
</div> |
|
||||
) : ( |
|
||||
<Empty description={t("canvasWorkflow.empty")} /> |
|
||||
)} |
|
||||
<div className="mt-4 flex justify-end"> |
|
||||
<Pagination |
|
||||
current={pageInfo.page} |
|
||||
pageSize={pageInfo.pageSize} |
|
||||
total={pageInfo.total} |
|
||||
showSizeChanger |
|
||||
pageSizeOptions={["10", "20", "50"]} |
|
||||
onChange={(page, pageSize) => void loadWorkflows(page, pageSize)} |
|
||||
/> |
|
||||
</div> |
|
||||
</Spin> |
|
||||
</Modal> |
|
||||
); |
|
||||
} |
|
||||
Loading…
Reference in new issue