diff --git a/packages/backend/src/controllers/api/v1/executions/get-executions.js b/packages/backend/src/controllers/api/v1/executions/get-executions.js index 474b0c87..e2862ab9 100644 --- a/packages/backend/src/controllers/api/v1/executions/get-executions.js +++ b/packages/backend/src/controllers/api/v1/executions/get-executions.js @@ -2,17 +2,17 @@ import { renderObject } from '../../../../helpers/renderer.js'; import paginateRest from '../../../../helpers/pagination.js'; export default async (request, response) => { - const executionsQuery = request.currentUser.authorizedExecutions - .clone() - .withSoftDeleted() - .orderBy('created_at', 'desc') - .withGraphFetched({ - flow: { - steps: true, - }, - }); + const executionsQuery = request.currentUser.getExecutions( + executionParams(request) + ); const executions = await paginateRest(executionsQuery, request.query.page); renderObject(response, executions); }; + +const executionParams = (request) => { + return { + name: request.query.name, + }; +}; diff --git a/packages/backend/src/models/user.js b/packages/backend/src/models/user.js index 35ce8e1a..8ace0c8d 100644 --- a/packages/backend/src/models/user.js +++ b/packages/backend/src/models/user.js @@ -566,6 +566,27 @@ class User extends Base { .orderBy('updated_at', 'desc'); } + getExecutions({ name }) { + return this.authorizedExecutions + .clone() + .withSoftDeleted() + .joinRelated({ + flow: true, + }) + .withGraphFetched({ + flow: { + steps: true, + }, + }) + .where((builder) => { + builder.withSoftDeleted(); + if (name) { + builder.where('flow.name', 'ilike', `%${name}%`); + } + }) + .orderBy('created_at', 'desc'); + } + async getApps(name) { const connections = await this.authorizedConnections .clone() diff --git a/packages/backend/src/models/user.test.js b/packages/backend/src/models/user.test.js index 0a1c4419..ddc08f7c 100644 --- a/packages/backend/src/models/user.test.js +++ b/packages/backend/src/models/user.test.js @@ -1349,6 +1349,91 @@ describe('User model', () => { }); }); + describe('getExecutions', () => { + let currentUser, + currentUserRole, + anotherUser, + flow, + executionOne, + executionTwo, + executionThree; + + beforeEach(async () => { + currentUser = await createUser(); + currentUserRole = await currentUser.$relatedQuery('role'); + + anotherUser = await createUser(); + + flow = await createFlow({ + userId: currentUser.id, + name: 'Test Flow', + }); + + const anotherUserFlow = await createFlow({ + userId: anotherUser.id, + name: 'Another User Flow', + }); + + executionOne = await createExecution({ + flowId: flow.id, + testRun: false, + }); + + executionTwo = await createExecution({ + flowId: flow.id, + testRun: true, + }); + + executionThree = await createExecution({ + flowId: anotherUserFlow.id, + testRun: false, + }); + + await createPermission({ + action: 'read', + subject: 'Execution', + roleId: currentUserRole.id, + conditions: [], + }); + + currentUser = await currentUser.$query().withGraphFetched({ + role: true, + permissions: true, + }); + }); + + it('should return executions filtered by name', async () => { + const executions = await currentUser.getExecutions({ name: 'Test Flow' }); + + expect(executions).toHaveLength(2); + + expect(executions[0].id).toBe(executionTwo.id); + expect(executions[1].id).toBe(executionOne.id); + }); + + it('should return all executions when no filter is applied', async () => { + const executions = await currentUser.getExecutions({}); + + expect(executions.length).toBeGreaterThanOrEqual(3); + + expect(executions.some((e) => e.id === executionOne.id)).toBe(true); + expect(executions.some((e) => e.id === executionTwo.id)).toBe(true); + expect(executions.some((e) => e.id === executionThree.id)).toBe(true); + }); + + it('should include flow and steps in the returned executions', async () => { + const step = await createStep({ + flowId: flow.id, + type: 'trigger', + }); + + const executions = await currentUser.getExecutions({ name: 'Test Flow' }); + + expect(executions[0].flow.id).toBe(flow.id); + expect(executions[0].flow.steps[0].id).toBe(step.id); + }); + }); + it.todo('getApps'); it('createAdmin should create admin with given data and mark the installation completed', async () => {