2022-11-11 23:37:41 +08:00
|
|
|
import React, { useEffect, useState } from 'react';
|
2022-10-30 11:54:14 +08:00
|
|
|
import { Link, useHistory } from 'react-router-dom';
|
2023-05-11 22:48:10 +08:00
|
|
|
import { Dropdown, Button, Tag, Switch, message, Breadcrumb, Modal } from 'antd';
|
2022-11-11 23:37:41 +08:00
|
|
|
import { DownOutlined, RightOutlined, EllipsisOutlined } from '@ant-design/icons';
|
2022-03-27 15:51:48 +08:00
|
|
|
import { cx } from '@emotion/css';
|
2022-10-30 11:54:14 +08:00
|
|
|
import classnames from 'classnames';
|
2022-12-01 22:52:46 +08:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2022-03-27 15:51:48 +08:00
|
|
|
|
|
|
|
import {
|
2022-11-11 23:37:41 +08:00
|
|
|
ActionContext,
|
2023-01-04 22:24:41 +08:00
|
|
|
ResourceActionProvider,
|
2022-11-11 23:37:41 +08:00
|
|
|
SchemaComponent,
|
2022-05-05 20:55:35 +08:00
|
|
|
useDocumentTitle,
|
2022-05-12 12:19:25 +08:00
|
|
|
useResourceActionContext,
|
2023-04-25 13:12:14 +08:00
|
|
|
useResourceContext,
|
2022-06-29 23:42:03 +08:00
|
|
|
} from '@nocobase/client';
|
|
|
|
|
2023-01-04 22:24:41 +08:00
|
|
|
import { FlowContext, useFlowContext } from './FlowContext';
|
2023-05-16 09:45:45 +08:00
|
|
|
import { workflowVersionDropdownClass } from './style';
|
2022-11-14 23:26:44 +08:00
|
|
|
import { executionSchema } from './schemas/executions';
|
2022-11-11 23:37:41 +08:00
|
|
|
import { ExecutionLink } from './ExecutionLink';
|
2022-11-14 23:26:44 +08:00
|
|
|
import { lang } from './locale';
|
2023-02-20 11:52:06 +08:00
|
|
|
import { linkNodes } from './utils';
|
2023-05-16 09:45:45 +08:00
|
|
|
import { CanvasContent } from './CanvasContent';
|
2022-03-27 15:51:48 +08:00
|
|
|
|
2023-01-04 22:24:41 +08:00
|
|
|
function ExecutionResourceProvider({ request, filter = {}, ...others }) {
|
|
|
|
const { workflow } = useFlowContext();
|
|
|
|
const props = {
|
|
|
|
...others,
|
|
|
|
request: {
|
|
|
|
...request,
|
|
|
|
params: {
|
|
|
|
...request?.params,
|
|
|
|
filter: {
|
2023-04-25 13:12:14 +08:00
|
|
|
...request?.params?.filter,
|
2023-01-04 22:24:41 +08:00
|
|
|
key: workflow.key,
|
2023-04-25 13:12:14 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-01-04 22:24:41 +08:00
|
|
|
};
|
|
|
|
|
2023-04-25 13:12:14 +08:00
|
|
|
return <ResourceActionProvider {...props} />;
|
2023-01-04 22:24:41 +08:00
|
|
|
}
|
|
|
|
|
2022-03-27 15:51:48 +08:00
|
|
|
export function WorkflowCanvas() {
|
2022-05-12 12:19:25 +08:00
|
|
|
const history = useHistory();
|
2022-12-01 22:52:46 +08:00
|
|
|
const { t } = useTranslation();
|
2022-03-27 15:51:48 +08:00
|
|
|
const { data, refresh, loading } = useResourceActionContext();
|
2023-02-20 11:52:06 +08:00
|
|
|
const { resource } = useResourceContext();
|
2022-05-05 20:55:35 +08:00
|
|
|
const { setTitle } = useDocumentTitle();
|
2022-11-11 23:37:41 +08:00
|
|
|
const [visible, setVisible] = useState(false);
|
2022-05-05 20:55:35 +08:00
|
|
|
useEffect(() => {
|
|
|
|
const { title } = data?.data ?? {};
|
2022-11-13 18:12:56 +08:00
|
|
|
setTitle?.(`${lang('Workflow')}${title ? `: ${title}` : ''}`);
|
2022-05-05 20:55:35 +08:00
|
|
|
}, [data?.data]);
|
|
|
|
|
2022-03-27 15:51:48 +08:00
|
|
|
if (!data?.data && !loading) {
|
2022-11-11 23:37:41 +08:00
|
|
|
return <div>{lang('Load failed')}</div>;
|
2022-03-27 15:51:48 +08:00
|
|
|
}
|
|
|
|
|
2022-05-12 12:19:25 +08:00
|
|
|
const { nodes = [], revisions = [], ...workflow } = data?.data ?? {};
|
2022-03-27 15:51:48 +08:00
|
|
|
|
2023-02-20 11:52:06 +08:00
|
|
|
linkNodes(nodes);
|
2022-03-27 15:51:48 +08:00
|
|
|
|
2023-04-25 13:12:14 +08:00
|
|
|
const entry = nodes.find((item) => !item.upstream);
|
2022-03-27 15:51:48 +08:00
|
|
|
|
2022-05-12 12:19:25 +08:00
|
|
|
function onSwitchVersion({ key }) {
|
|
|
|
if (key != workflow.id) {
|
|
|
|
history.push(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onToggle(value) {
|
|
|
|
await resource.update({
|
2023-02-20 11:52:06 +08:00
|
|
|
filterByTk: workflow.id,
|
2022-05-12 12:19:25 +08:00
|
|
|
values: {
|
2023-04-25 13:12:14 +08:00
|
|
|
enabled: value,
|
|
|
|
},
|
2022-05-12 12:19:25 +08:00
|
|
|
});
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
2022-06-09 16:40:10 +08:00
|
|
|
async function onRevision() {
|
2023-04-25 13:12:14 +08:00
|
|
|
const {
|
|
|
|
data: { data: revision },
|
|
|
|
} = await resource.revision({
|
2023-02-20 11:52:06 +08:00
|
|
|
filterByTk: workflow.id,
|
2022-12-01 22:52:46 +08:00
|
|
|
filter: {
|
2023-04-25 13:12:14 +08:00
|
|
|
key: workflow.key,
|
|
|
|
},
|
2022-05-12 12:19:25 +08:00
|
|
|
});
|
2022-12-01 22:52:46 +08:00
|
|
|
message.success(t('Operation succeeded'));
|
2022-05-12 12:19:25 +08:00
|
|
|
|
2022-06-09 16:40:10 +08:00
|
|
|
history.push(`${revision.id}`);
|
2022-05-12 12:19:25 +08:00
|
|
|
}
|
|
|
|
|
2023-05-11 22:48:10 +08:00
|
|
|
async function onDelete() {
|
|
|
|
const content = workflow.current
|
|
|
|
? lang('Delete a main version will cause all other revisions to be deleted too.')
|
|
|
|
: '';
|
|
|
|
Modal.confirm({
|
|
|
|
title: t('Are you sure you want to delete it?'),
|
|
|
|
content,
|
|
|
|
async onOk() {
|
|
|
|
await resource.destroy({
|
|
|
|
filterByTk: workflow.id,
|
|
|
|
});
|
|
|
|
message.success(t('Operation succeeded'));
|
|
|
|
|
|
|
|
history.push(workflow.current ? '..' : `${revisions.find((item) => item.current)?.id}`);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-11-11 23:37:41 +08:00
|
|
|
async function onMenuCommand({ key }) {
|
|
|
|
switch (key) {
|
|
|
|
case 'history':
|
|
|
|
setVisible(true);
|
|
|
|
return;
|
|
|
|
case 'revision':
|
|
|
|
return onRevision();
|
2023-05-11 22:48:10 +08:00
|
|
|
case 'delete':
|
|
|
|
return onDelete();
|
2022-11-11 23:37:41 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 13:12:14 +08:00
|
|
|
const revisionable =
|
|
|
|
workflow.executed &&
|
|
|
|
!revisions.find((item) => !item.executed && new Date(item.createdAt) > new Date(workflow.createdAt));
|
2022-11-11 23:37:41 +08:00
|
|
|
|
2022-03-27 15:51:48 +08:00
|
|
|
return (
|
2023-04-25 13:12:14 +08:00
|
|
|
<FlowContext.Provider
|
|
|
|
value={{
|
|
|
|
workflow,
|
|
|
|
nodes,
|
|
|
|
refresh,
|
|
|
|
}}
|
|
|
|
>
|
2022-05-12 12:19:25 +08:00
|
|
|
<div className="workflow-toolbar">
|
|
|
|
<header>
|
2022-11-13 18:12:56 +08:00
|
|
|
<Breadcrumb>
|
|
|
|
<Breadcrumb.Item>
|
2023-04-25 13:12:14 +08:00
|
|
|
<Link to={`/admin/settings/workflow/workflows`}>{lang('Workflow')}</Link>
|
2022-11-13 18:12:56 +08:00
|
|
|
</Breadcrumb.Item>
|
|
|
|
<Breadcrumb.Item>
|
|
|
|
<strong>{workflow.title}</strong>
|
|
|
|
</Breadcrumb.Item>
|
|
|
|
</Breadcrumb>
|
2022-05-12 12:19:25 +08:00
|
|
|
</header>
|
|
|
|
<aside>
|
|
|
|
<div className="workflow-versions">
|
|
|
|
<Dropdown
|
|
|
|
trigger={['click']}
|
2023-05-11 22:48:10 +08:00
|
|
|
menu={{
|
|
|
|
onClick: onSwitchVersion,
|
|
|
|
defaultSelectedKeys: [`${workflow.id}`],
|
|
|
|
className: cx(workflowVersionDropdownClass),
|
|
|
|
items: revisions
|
|
|
|
.sort((a, b) => b.id - a.id)
|
|
|
|
.map((item, index) => ({
|
|
|
|
key: `${item.id}`,
|
|
|
|
icon: item.current ? <RightOutlined /> : null,
|
|
|
|
label: (
|
|
|
|
<span
|
|
|
|
className={classnames({
|
|
|
|
executed: item.executed,
|
|
|
|
unexecuted: !item.executed,
|
|
|
|
enabled: item.enabled,
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
<strong>{`#${item.id}`}</strong>
|
|
|
|
<time>{new Date(item.createdAt).toLocaleString()}</time>
|
|
|
|
</span>
|
|
|
|
),
|
|
|
|
})),
|
|
|
|
}}
|
2022-05-12 12:19:25 +08:00
|
|
|
>
|
2022-11-13 18:12:56 +08:00
|
|
|
<Button type="text">
|
|
|
|
<label>{lang('Version')}</label>
|
|
|
|
<span>{workflow?.id ? `#${workflow.id}` : null}</span>
|
|
|
|
<DownOutlined />
|
|
|
|
</Button>
|
2022-05-12 12:19:25 +08:00
|
|
|
</Dropdown>
|
|
|
|
</div>
|
|
|
|
<Switch
|
|
|
|
checked={workflow.enabled}
|
|
|
|
onChange={onToggle}
|
2022-11-11 23:37:41 +08:00
|
|
|
checkedChildren={lang('On')}
|
|
|
|
unCheckedChildren={lang('Off')}
|
2022-05-12 12:19:25 +08:00
|
|
|
/>
|
2022-11-11 23:37:41 +08:00
|
|
|
<Dropdown
|
2023-05-11 22:48:10 +08:00
|
|
|
menu={{
|
|
|
|
items: [
|
|
|
|
{ key: 'history', label: lang('Execution history'), disabled: !workflow.allExecuted },
|
|
|
|
{ key: 'revision', label: lang('Copy to new version'), disabled: !revisionable },
|
|
|
|
{ key: 'delete', label: t('Delete') },
|
|
|
|
],
|
|
|
|
onClick: onMenuCommand,
|
|
|
|
}}
|
2022-11-11 23:37:41 +08:00
|
|
|
>
|
|
|
|
<Button type="text" icon={<EllipsisOutlined />} />
|
|
|
|
</Dropdown>
|
|
|
|
<ActionContext.Provider value={{ visible, setVisible }}>
|
|
|
|
<SchemaComponent
|
2022-11-14 23:26:44 +08:00
|
|
|
schema={executionSchema}
|
2022-11-11 23:37:41 +08:00
|
|
|
components={{
|
|
|
|
ExecutionResourceProvider,
|
2023-04-25 13:12:14 +08:00
|
|
|
ExecutionLink,
|
2022-11-11 23:37:41 +08:00
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</ActionContext.Provider>
|
2022-05-12 12:19:25 +08:00
|
|
|
</aside>
|
|
|
|
</div>
|
2023-05-16 09:45:45 +08:00
|
|
|
<CanvasContent entry={entry} />
|
2022-03-27 15:51:48 +08:00
|
|
|
</FlowContext.Provider>
|
|
|
|
);
|
|
|
|
}
|