fix(plugin-workflow): fix stats cascade deleted (#7103)

This commit is contained in:
Junyi 2025-06-20 00:07:54 +08:00 committed by GitHub
parent aa1070ad0f
commit 2c8934bd9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 180 additions and 18 deletions

View File

@ -204,11 +204,9 @@ export function WorkflowTasks() {
const compile = useCompile();
const { setTitle } = useDocumentTitle();
const navigate = useNavigate();
const apiClient = useAPIClient();
const { taskType, status = TASK_STATUS.PENDING, popupId } = useParams();
const { token } = useToken();
const [currentRecord, setCurrentRecord] = useState<any>(null);
const items = useTaskTypeItems();
const { title, collection, action = 'list', useActionParams, Item, Detail } = useCurrentTaskType();
@ -227,21 +225,9 @@ export function WorkflowTasks() {
useEffect(() => {
if (popupId && !currentRecord) {
apiClient
.resource(collection)
.get({
filterByTk: popupId,
})
.then((res) => {
if (res.data?.data) {
setCurrentRecord(res.data.data);
}
})
.catch((err) => {
console.error(err);
});
setCurrentRecord({ id: popupId });
}
}, [popupId, collection, currentRecord, apiClient]);
}, [popupId, currentRecord]);
const typeKey = taskType ?? items[0].key;

View File

@ -150,7 +150,6 @@ export default {
foreignKey: 'key',
sourceKey: 'key',
constraints: false,
onDelete: 'CASCADE',
// interface: 'oho',
// uiSchema: {
// type: 'object',

View File

@ -251,6 +251,60 @@ describe('workflow > actions > workflows', () => {
const versionStatsCount = await WorkflowVersionStatsRepo.count();
expect(versionStatsCount).toBe(0);
});
it('destroy current version should delete stats record too', async () => {
const w1 = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 1,
collection: 'posts',
},
});
const s1 = await WorkflowStatsRepo.find();
expect(s1.length).toBe(1);
expect(s1[0].key).toBe(w1.key);
await agent.resource(`workflows`).destroy({
filterByTk: w1.id,
});
const statsCount = await WorkflowStatsRepo.count();
expect(statsCount).toBe(0);
});
it('destroy non-current version should not delete stats record', async () => {
const w1 = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 1,
collection: 'posts',
},
});
const s1 = await WorkflowStatsRepo.find();
expect(s1.length).toBe(1);
expect(s1[0].key).toBe(w1.key);
const w2 = await WorkflowRepo.revision({
filterByTk: w1.id,
filter: {
key: w1.key,
},
context: {
app,
},
});
await agent.resource(`workflows`).destroy({
filterByTk: w2.id,
});
const statsCount = await WorkflowStatsRepo.count();
expect(statsCount).toBe(1);
});
});
describe('revision', () => {

View File

@ -0,0 +1,69 @@
/**
* 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 { describe, test } from 'vitest';
import { MockServer } from '@nocobase/test';
import { getApp } from '@nocobase/plugin-workflow-test';
import Migration from '../../migrations/20250619213102-add-missed-stats';
import PluginWorkflowServer from '../..';
import { EXECUTION_STATUS } from '../../constants';
describe('20250619213102-add-missed-stats', () => {
let app: MockServer;
let plugin: PluginWorkflowServer;
let WorkflowRepo;
let WorkflowStatsRepo;
describe('missed stats should be added', () => {
beforeEach(async () => {
app = await getApp();
await app.version.update('1.7.0');
plugin = app.pm.get(PluginWorkflowServer) as PluginWorkflowServer;
WorkflowRepo = app.db.getRepository('workflows');
WorkflowStatsRepo = app.db.getRepository('workflowStats');
});
afterEach(() => app.destroy());
test('current workflow stats missing', async () => {
const workflow = await WorkflowRepo.create({
values: {
type: 'syncTrigger',
key: 'abc',
current: true,
},
hooks: false,
});
const e1 = await workflow.createExecution({
key: workflow.get('key'),
eventKey: '1',
context: {},
status: EXECUTION_STATUS.RESOLVED,
});
const s1 = await WorkflowStatsRepo.findOne({
filterByTk: workflow.get('key'),
});
expect(s1).toBeNull();
const migration = new Migration({ app, db: app.db } as any);
await migration.up();
const s2 = await WorkflowStatsRepo.findOne({
filterByTk: workflow.get('key'),
});
expect(s2).not.toBeNull();
expect(s2.get('executed')).toBe(1);
});
});
});

View File

@ -57,11 +57,20 @@ export async function destroy(context: Context, next) {
revisions.forEach((item) => ids.add(item.id));
context.body = await repository.destroy({
const deleted = await repository.destroy({
filterByTk: Array.from(ids),
individualHooks: true,
transaction,
});
const StatsRepo = context.db.getRepository('workflowStats');
await StatsRepo.destroy({
filter: {
key: Array.from(keysSet),
},
transaction,
});
context.body = deleted;
});
next();

View File

@ -0,0 +1,45 @@
/**
* 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 { Migration } from '@nocobase/server';
export default class extends Migration {
appVersion = '<1.8.0';
on = 'afterLoad';
async up() {
const { db } = this.context;
const WorkflowRepo = db.getRepository('workflows');
const ExecutionRepo = db.getRepository('executions');
await db.sequelize.transaction(async (transaction) => {
const workflows = await WorkflowRepo.find({
filter: {
current: true,
},
appends: ['stats'],
transaction,
});
for (const workflow of workflows) {
if (!workflow.stats) {
const executed =
(await ExecutionRepo.count({
filter: {
key: workflow.key,
},
transaction,
})) ||
workflow.allExecuted ||
0;
await workflow.createStats({ executed }, { transaction });
}
}
});
}
}