import { ActionContextProvider, css, SchemaComponent, useCompile, useDocumentTitle, useResourceActionContext, } from '@nocobase/client'; import { str2moment } from '@nocobase/utils/client'; import { Breadcrumb, Tag } from 'antd'; import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { CanvasContent } from './CanvasContent'; import { ExecutionStatusOptionsMap, JobStatusOptions } from './constants'; import { FlowContext, useFlowContext } from './FlowContext'; import { lang, NAMESPACE } from './locale'; import { instructions } from './nodes'; import useStyles from './style'; import { linkNodes } from './utils'; function attachJobs(nodes, jobs: any[] = []): void { const nodesMap = new Map(); nodes.forEach((item) => { item.jobs = []; nodesMap.set(item.id, item); }); jobs.forEach((item) => { const node = nodesMap.get(item.nodeId); node.jobs.push(item); item.node = { id: node.id, title: node.title, type: node.type, }; }); nodes.forEach((item) => { item.jobs = item.jobs.sort((a, b) => a.id - b.id); }); } function JobModal() { const compile = useCompile(); const { viewJob: job, setViewJob } = useFlowContext(); const { styles } = useStyles(); const { node = {} } = job ?? {}; const instruction = instructions.get(node.type); return ( {compile(instruction?.title)} {node.title} #{node.id} ), properties: { status: { type: 'number', title: `{{t("Status", { ns: "${NAMESPACE}" })}}`, 'x-decorator': 'FormItem', 'x-component': 'Select', enum: JobStatusOptions, 'x-read-pretty': true, }, updatedAt: { type: 'string', title: `{{t("Executed at", { ns: "${NAMESPACE}" })}}`, 'x-decorator': 'FormItem', 'x-component': 'DatePicker', 'x-component-props': { showTime: true, }, 'x-read-pretty': true, }, result: { type: 'object', title: `{{t("Node result", { ns: "${NAMESPACE}" })}}`, 'x-decorator': 'FormItem', 'x-component': 'Input.JSON', 'x-component-props': { className: css` padding: 1em; background-color: #eee; `, }, 'x-read-pretty': true, }, }, }, }, }} /> ); } export function ExecutionCanvas() { const compile = useCompile(); const { data, loading } = useResourceActionContext(); const { setTitle } = useDocumentTitle(); const [viewJob, setViewJob] = useState(null); useEffect(() => { const { workflow } = data?.data ?? {}; setTitle?.(`${workflow?.title ? `${workflow.title} - ` : ''}${lang('Execution history')}`); }, [data?.data]); if (!data?.data) { if (loading) { return
{lang('Loading')}
; } else { return
{lang('Load failed')}
; } } const { jobs = [], workflow: { nodes = [], revisions = [], ...workflow } = {}, ...execution } = data?.data ?? {}; linkNodes(nodes); attachJobs(nodes, jobs); const entry = nodes.find((item) => !item.upstream); const statusOption = ExecutionStatusOptionsMap[execution.status]; return (
{lang('Workflow')} }, { title: {workflow.title} }, { title: {`#${execution.id}`} }, ]} />
); }