mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-21 04:37:50 +08:00
fix(core): Show AI Builder draft workflows in workflow list (#29670)
This commit is contained in:
@@ -2,7 +2,7 @@ import { GlobalConfig } from '@n8n/config';
|
||||
import { In, type SelectQueryBuilder } from '@n8n/typeorm';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
import { AiBuilderTemporaryWorkflow, WorkflowEntity } from '../../entities';
|
||||
import { WorkflowEntity } from '../../entities';
|
||||
import { mockEntityManager } from '../../utils/test-utils/mock-entity-manager';
|
||||
import { mockInstance } from '../../utils/test-utils/mock-instance';
|
||||
import { FolderRepository } from '../folder.repository';
|
||||
@@ -32,17 +32,9 @@ describe('WorkflowRepository', () => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
queryBuilder = mock<SelectQueryBuilder<WorkflowEntity>>();
|
||||
const subQueryBuilder = mock<SelectQueryBuilder<AiBuilderTemporaryWorkflow>>();
|
||||
subQueryBuilder.select.mockReturnThis();
|
||||
subQueryBuilder.from.mockReturnThis();
|
||||
subQueryBuilder.where.mockReturnThis();
|
||||
subQueryBuilder.getQuery.mockReturnValue(
|
||||
'(SELECT 1 FROM "ai_builder_temporary_workflow" "aitw" WHERE aitw."workflowId" = workflow.id)',
|
||||
);
|
||||
|
||||
queryBuilder.where.mockReturnThis();
|
||||
queryBuilder.andWhere.mockReturnThis();
|
||||
queryBuilder.subQuery.mockReturnValue(subQueryBuilder);
|
||||
queryBuilder.orWhere.mockReturnThis();
|
||||
queryBuilder.select.mockReturnThis();
|
||||
queryBuilder.addSelect.mockReturnThis();
|
||||
@@ -65,18 +57,6 @@ describe('WorkflowRepository', () => {
|
||||
jest.spyOn(workflowRepository, 'createQueryBuilder').mockReturnValue(queryBuilder);
|
||||
});
|
||||
|
||||
describe('applyAiBuilderTemporaryFilter', () => {
|
||||
it('hides marker-table rows through a prefix-safe entity subquery', async () => {
|
||||
await workflowRepository.getMany(['workflow1']);
|
||||
|
||||
expect(queryBuilder.subQuery).toHaveBeenCalled();
|
||||
expect(queryBuilder.subQuery().from).toHaveBeenCalledWith(AiBuilderTemporaryWorkflow, 'aitw');
|
||||
expect(queryBuilder.andWhere).toHaveBeenCalledWith(
|
||||
expect.stringContaining('NOT EXISTS (SELECT 1 FROM "ai_builder_temporary_workflow"'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyNameFilter', () => {
|
||||
it('should search for workflows containing all words from the query', async () => {
|
||||
const workflowIds = ['workflow1'];
|
||||
|
||||
@@ -18,7 +18,6 @@ import { SharedWorkflowRepository } from './shared-workflow.repository';
|
||||
import { WorkflowHistoryRepository } from './workflow-history.repository';
|
||||
import {
|
||||
WebhookEntity,
|
||||
AiBuilderTemporaryWorkflow,
|
||||
TagEntity,
|
||||
WorkflowEntity,
|
||||
WorkflowTagMapping,
|
||||
@@ -883,23 +882,6 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||
this.applyParentFolderFilter(qb, filter);
|
||||
this.applyNodeTypesFilter(qb, filter);
|
||||
this.applyAvailableInMCPFilter(qb, filter);
|
||||
this.applyAiBuilderTemporaryFilter(qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide workflows the AI builder created and has not yet promoted to the
|
||||
* main deliverable. The orchestrator clears the marker on the main at
|
||||
* build-time and reaps the rest at run-finish, but in the window between
|
||||
* create and reap, marked rows must not surface in the workflows list.
|
||||
*/
|
||||
private applyAiBuilderTemporaryFilter(qb: SelectQueryBuilder<WorkflowEntity>): void {
|
||||
const markerSubquery = qb
|
||||
.subQuery()
|
||||
.select('1')
|
||||
.from(AiBuilderTemporaryWorkflow, 'aitw')
|
||||
.where('aitw."workflowId" = workflow.id')
|
||||
.getQuery();
|
||||
qb.andWhere(`NOT EXISTS ${markerSubquery}`);
|
||||
}
|
||||
|
||||
private applyAvailableInMCPFilter(
|
||||
|
||||
Reference in New Issue
Block a user