fix(plugin-workflow): fix tasks count (#6474)

* fix(plugin-workflow): fix tasks count

* fix(plugin-workflow): add filter

* fix(plugin-workflow): always refresh all counts

* refactor(plugin-workflow): change to delete tasks when workflow deleted

* feat(plugin-workflow): add reload when click menu link
This commit is contained in:
Junyi 2025-03-16 15:04:20 +08:00 committed by GitHub
parent fd7c839228
commit cba610ecc8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 125 additions and 21 deletions

View File

@ -64,7 +64,11 @@ export interface TaskTypeOptions {
// children?: TaskTypeOptions[];
}
const TasksCountsContext = createContext<{ counts: Record<string, number>; total: number }>({ counts: {}, total: 0 });
const TasksCountsContext = createContext<{ reload: () => void; counts: Record<string, number>; total: number }>({
reload() {},
counts: {},
total: 0,
});
function MenuLink({ type }: any) {
const workflowPlugin = usePlugin(PluginWorkflowClient);
@ -299,13 +303,13 @@ export function WorkflowTasks() {
function WorkflowTasksLink() {
const workflowPlugin = usePlugin(PluginWorkflowClient);
const { total } = useContext(TasksCountsContext);
const { reload, total } = useContext(TasksCountsContext);
const types = Array.from(workflowPlugin.taskTypes.getKeys());
return types.length ? (
<Tooltip title={lang('Workflow todos')}>
<Button>
<Link to={`/admin/workflow/tasks/${types[0]}`}>
<Link to={`/admin/workflow/tasks/${types[0]}`} onClick={reload}>
<Badge count={total} size="small">
<CheckCircleOutlined />
</Badge>
@ -326,12 +330,7 @@ function TasksCountsProvider(props: any) {
const app = useApp();
const [counts, setCounts] = useState<Record<string, number>>({});
const onTaskUpdate = useCallback(({ detail = [] }: CustomEvent) => {
setCounts((prev) => {
return {
...prev,
...transform(detail),
};
});
setCounts(transform(detail));
}, []);
const { runAsync } = useRequest(
@ -344,21 +343,20 @@ function TasksCountsProvider(props: any) {
},
);
useEffect(() => {
const reload = useCallback(() => {
runAsync()
.then((res) => {
setCounts((prev) => {
return {
...prev,
...transform(res['data']),
};
});
setCounts(transform(res['data']));
})
.catch((err) => {
console.error(err);
});
}, [runAsync]);
useEffect(() => {
reload();
}, [reload]);
useEffect(() => {
app.eventBus.addEventListener('ws:message:workflow:tasks:updated', onTaskUpdate);
@ -369,7 +367,7 @@ function TasksCountsProvider(props: any) {
const total = Object.values(counts).reduce((a, b) => a + b, 0) || 0;
return <TasksCountsContext.Provider value={{ total, counts }}>{props.children}</TasksCountsContext.Provider>;
return <TasksCountsContext.Provider value={{ reload, total, counts }}>{props.children}</TasksCountsContext.Provider>;
}
export const TasksProvider = (props: any) => {

View File

@ -283,9 +283,17 @@ export default class PluginWorkflowServer extends Plugin {
db.on('workflows.afterUpdate', (model: WorkflowModel, { transaction }) =>
this.toggle(model, model.enabled, { transaction }),
);
db.on('workflows.afterDestroy', (model: WorkflowModel, { transaction }) =>
this.toggle(model, false, { transaction }),
);
db.on('workflows.afterDestroy', async (model: WorkflowModel, { transaction }) => {
this.toggle(model, false, { transaction });
const TaskRepo = this.db.getRepository('workflowTasks');
await TaskRepo.destroy({
filter: {
workflowId: model.id,
},
transaction,
});
});
// [Life Cycle]:
// * load all workflows in db

View File

@ -0,0 +1,97 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { MockServer } from '@nocobase/test';
import Database from '@nocobase/database';
import { getApp } from '@nocobase/plugin-workflow-test';
import Plugin from '..';
describe('workflow > tasks', () => {
let app: MockServer;
let db: Database;
let PostRepo;
let WorkflowModel;
let plugin: Plugin;
let TaskRepo;
let UserRepo;
let users;
let userAgents;
beforeEach(async () => {
app = await getApp({
plugins: ['users', 'auth'],
});
db = app.db;
WorkflowModel = db.getCollection('workflows').model;
PostRepo = db.getCollection('posts').repository;
plugin = app.pm.get(Plugin) as Plugin;
TaskRepo = db.getCollection('workflowTasks').repository;
UserRepo = db.getCollection('users').repository;
await UserRepo.create({});
users = await UserRepo.find();
userAgents = await Promise.all(users.map((user) => app.agent().login(user)));
});
afterEach(() => app.destroy());
describe('filter', () => {
it('only count current user tasks', async () => {
const workflow = await WorkflowModel.create({
sync: true,
enabled: true,
type: 'syncTrigger',
});
await plugin.trigger(workflow, {});
const e1s = await workflow.getExecutions();
expect(e1s.length).toBe(1);
const tasks = await TaskRepo.createMany({
records: [
{
userId: users[0].id,
workflowId: workflow.id,
type: 'test',
},
{
userId: users[0].id,
workflowId: workflow.id,
type: 'test',
},
{
userId: users[1].id,
workflowId: workflow.id,
type: 'test',
},
],
});
const res1 = await userAgents[0].resource('workflowTasks').countMine();
expect(res1.status).toBe(200);
expect(res1.body.data[0].count).toBe(2);
const res2 = await userAgents[1].resource('workflowTasks').countMine();
expect(res2.status).toBe(200);
expect(res2.body.data[0].count).toBe(1);
await workflow.destroy();
const res3 = await userAgents[0].resource('workflowTasks').countMine();
expect(res3.status).toBe(200);
expect(res3.body.data.length).toBe(0);
const res4 = await userAgents[1].resource('workflowTasks').countMine();
expect(res4.status).toBe(200);
expect(res4.body.data.length).toBe(0);
});
});
});

View File

@ -7,6 +7,7 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Op } from 'sequelize';
import { Context, utils } from '@nocobase/actions';
import WorkflowTasksRepository from '../repositories/WorkflowTasksRepository';
@ -20,5 +21,5 @@ export async function countMine(context: Context, next) {
},
})) || [];
next();
await next();
}