diff --git a/packages/@n8n/db/src/repositories/workflow-dependency.repository.ts b/packages/@n8n/db/src/repositories/workflow-dependency.repository.ts index aaac2ac69d4..336504705d2 100644 --- a/packages/@n8n/db/src/repositories/workflow-dependency.repository.ts +++ b/packages/@n8n/db/src/repositories/workflow-dependency.repository.ts @@ -1,6 +1,6 @@ import { DatabaseConfig } from '@n8n/config'; import { Service } from '@n8n/di'; -import { DataSource, EntityManager, In, IsNull, LessThan, Repository, Not } from '@n8n/typeorm'; +import { DataSource, EntityManager, IsNull, LessThan, Repository, Not } from '@n8n/typeorm'; import { WorkflowDependency } from '../entities'; @@ -159,17 +159,4 @@ export class WorkflowDependencyRepository extends Repository const { tablePrefix } = this.databaseConfig; return this.manager.connection.driver.escape(`${tablePrefix}${name}`); } - - /** - * Retrieve the caller → callee edges of workflows that reference any of the - * given workflows via an Execute Workflow node. `workflowId` is the caller, - * `dependencyKey` the called workflow's id. - */ - async findCallersOfWorkflows(workflowIds: string[]) { - if (workflowIds.length === 0) return []; - return await this.find({ - select: ['workflowId', 'dependencyKey'], - where: { dependencyType: 'workflowCall', dependencyKey: In(workflowIds) }, - }); - } } diff --git a/packages/cli/src/webhooks/__tests__/webhooks.controller.test.ts b/packages/cli/src/webhooks/__tests__/webhooks.controller.test.ts index e755c8cd6b7..bef8479f803 100644 --- a/packages/cli/src/webhooks/__tests__/webhooks.controller.test.ts +++ b/packages/cli/src/webhooks/__tests__/webhooks.controller.test.ts @@ -2,7 +2,6 @@ import { WebhookEntity } from '@n8n/db'; import type { Project, SharedWorkflowRepository, - WorkflowDependencyRepository, WorkflowEntity, WorkflowRepository, } from '@n8n/db'; @@ -29,13 +28,11 @@ describe('WebhooksController', () => { const webhookService = mock(); const workflowRepository = mock(); const sharedWorkflowRepository = mock(); - const workflowDependencyRepository = mock(); const nodeTypes = mock(); const controller = new WebhooksController( webhookService, workflowRepository, sharedWorkflowRepository, - workflowDependencyRepository, nodeTypes, ); @@ -46,7 +43,6 @@ describe('WebhooksController', () => { workflowRepository.findPublishedWithActiveVersionNodes.mockResolvedValue([]); workflowRepository.findUnpublishedWithNodes.mockResolvedValue([]); sharedWorkflowRepository.findOwnerProjectsByWorkflowIds.mockResolvedValue(new Map()); - workflowDependencyRepository.findCallersOfWorkflows.mockResolvedValue([]); vi.mocked(getTriggerKinds).mockReturnValue(new Map()); }); @@ -106,7 +102,6 @@ describe('WebhooksController', () => { nodeType: 'n8n-nodes-base.webhook', isActive: true, project: { name: 'My Project', type: 'team', icon: { type: 'icon', value: 'folder' } }, - calledBy: [], }, { kind: 'webhook', @@ -118,7 +113,6 @@ describe('WebhooksController', () => { nodeType: undefined, isActive: true, project: undefined, - calledBy: [], }, ]); }); @@ -152,14 +146,6 @@ describe('WebhooksController', () => { ['n3', 'persisted'], ]), ); - // Duplicate edges: draft and published versions index separately - workflowDependencyRepository.findCallersOfWorkflows.mockResolvedValue([ - { workflowId: 'caller1', dependencyKey: 'wf5' }, - { workflowId: 'caller1', dependencyKey: 'wf5' }, - ] as never); - workflowRepository.findByIds.mockResolvedValue([ - { id: 'caller1', name: 'Caller Workflow' } as WorkflowEntity, - ]); const result = await controller.getAll(); @@ -172,7 +158,6 @@ describe('WebhooksController', () => { nodeType: 'n8n-nodes-base.scheduleTrigger', isActive: true, project: undefined, - calledBy: [{ id: 'caller1', name: 'Caller Workflow' }], }, { kind: 'trigger', @@ -182,7 +167,6 @@ describe('WebhooksController', () => { nodeType: 'n8n-nodes-base.executeWorkflowTrigger', isActive: true, project: undefined, - calledBy: [{ id: 'caller1', name: 'Caller Workflow' }], }, ]); }); @@ -227,7 +211,6 @@ describe('WebhooksController', () => { nodeType: 'n8n-nodes-base.scheduleTrigger', isActive: false, project: undefined, - calledBy: [], }, { kind: 'webhook', @@ -239,7 +222,6 @@ describe('WebhooksController', () => { nodeType: 'n8n-nodes-base.webhook', isActive: false, project: undefined, - calledBy: [], }, ]); }); diff --git a/packages/cli/src/webhooks/webhooks.controller.ts b/packages/cli/src/webhooks/webhooks.controller.ts index 237831ad295..c76c2e9e121 100644 --- a/packages/cli/src/webhooks/webhooks.controller.ts +++ b/packages/cli/src/webhooks/webhooks.controller.ts @@ -1,9 +1,5 @@ import type { WorkflowEntity } from '@n8n/db'; -import { - SharedWorkflowRepository, - WorkflowDependencyRepository, - WorkflowRepository, -} from '@n8n/db'; +import { SharedWorkflowRepository, WorkflowRepository } from '@n8n/db'; import { Get, GlobalScope, Post, RestController } from '@n8n/decorators'; import { Request } from 'express'; import get from 'lodash/get'; @@ -35,7 +31,6 @@ export class WebhooksController { private readonly webhookService: WebhookService, private readonly workflowRepository: WorkflowRepository, private readonly sharedWorkflowRepository: SharedWorkflowRepository, - private readonly workflowDependencyRepository: WorkflowDependencyRepository, private readonly nodeTypes: NodeTypes, ) {} @@ -52,7 +47,6 @@ export class WebhooksController { const workflowIds = [...new Set(rows.map((row) => row.workflowId))]; const ownerProjects = await this.sharedWorkflowRepository.findOwnerProjectsByWorkflowIds(workflowIds); - const callersByCallee = await this.getCallersByCallee(workflowIds); return rows.map((row) => { const project = ownerProjects.get(row.workflowId); @@ -61,34 +55,10 @@ export class WebhooksController { project: project ? { name: project.name, type: project.type, icon: project.icon } : undefined, - calledBy: callersByCallee.get(row.workflowId) ?? [], }; }); } - /** Workflows calling each given workflow via an Execute Workflow node. */ - private async getCallersByCallee(workflowIds: string[]) { - const edges = await this.workflowDependencyRepository.findCallersOfWorkflows(workflowIds); - const callerIds = [...new Set(edges.map((edge) => edge.workflowId))]; - const callers = await this.workflowRepository.findByIds(callerIds, { fields: ['id', 'name'] }); - const callerNames = new Map(callers.map((workflow) => [workflow.id, workflow.name])); - - // Draft and published versions index separately, so dedupe callers per callee - const callersByCallee = new Map>(); - for (const edge of edges) { - const perCallee = callersByCallee.get(edge.dependencyKey) ?? new Map(); - perCallee.set(edge.workflowId, callerNames.get(edge.workflowId) ?? edge.workflowId); - callersByCallee.set(edge.dependencyKey, perCallee); - } - - return new Map( - [...callersByCallee.entries()].map(([calleeId, perCallee]) => [ - calleeId, - [...perCallee.entries()].map(([id, name]) => ({ id, name })), - ]), - ); - } - private async getActiveWebhooks(): Promise { const registered = await this.webhookService.findAll(); const workflowIds = [...new Set(registered.map((webhook) => webhook.workflowId))]; diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index 511912126a7..213df71d685 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -5585,7 +5585,6 @@ "settings.webhooks.column.project": "Project", "settings.webhooks.column.node": "Node", "settings.webhooks.column.calls": "Calls", - "settings.webhooks.column.calledBy": "Called by", "settings.webhooks.copy.tooltip": "Copy webhook URL", "settings.webhooks.copy.success": "Webhook URL copied", "settings.webhooks.empty.title": "No triggers", diff --git a/packages/frontend/@n8n/rest-api-client/src/api/webhooks.ts b/packages/frontend/@n8n/rest-api-client/src/api/webhooks.ts index 56d726cc55f..6b4ca7dc38a 100644 --- a/packages/frontend/@n8n/rest-api-client/src/api/webhooks.ts +++ b/packages/frontend/@n8n/rest-api-client/src/api/webhooks.ts @@ -24,7 +24,6 @@ export type InstanceWebhook = { type: 'personal' | 'team'; icon: { type: 'emoji' | 'icon'; value: string } | null; }; - calledBy: Array<{ id: string; name: string }>; }; export const findWebhook = async ( diff --git a/packages/frontend/editor-ui/src/features/settings/webhooks/views/SettingsWebhooksView.vue b/packages/frontend/editor-ui/src/features/settings/webhooks/views/SettingsWebhooksView.vue index 8de15ab983f..8066a443e66 100644 --- a/packages/frontend/editor-ui/src/features/settings/webhooks/views/SettingsWebhooksView.vue +++ b/packages/frontend/editor-ui/src/features/settings/webhooks/views/SettingsWebhooksView.vue @@ -9,7 +9,6 @@ import { N8nInput, N8nOption, N8nSelect, - N8nTag, N8nText, } from '@n8n/design-system'; import type { IconOrEmoji, TableHeader } from '@n8n/design-system'; @@ -71,12 +70,6 @@ const headers = computed>>(() => [ width: 90, align: 'end', }, - { - title: i18n.baseText('settings.webhooks.column.calledBy'), - key: 'calledBy', - width: 200, - disableSort: true, - }, ]); const nodeTypeFilter = ref([]); @@ -104,14 +97,9 @@ const filteredItems = computed(() => { } if (term) { items = items.filter((row) => - [ - row.path ?? '', - row.workflowName ?? '', - row.node, - row.method ?? '', - row.projectName, - ...row.calledBy.map((caller) => caller.name), - ].some((value) => value.toLowerCase().includes(term)), + [row.path ?? '', row.workflowName ?? '', row.node, row.method ?? '', row.projectName].some( + (value) => value.toLowerCase().includes(term), + ), ); } @@ -166,13 +154,6 @@ const getPathAbbreviation = (path: string) => { return shortened === path ? path : `${shortened}…`; }; -const MAX_CALLER_PILLS = 3; -const getOverflowCallers = (row: WebhookRow) => - row.calledBy - .slice(MAX_CALLER_PILLS) - .map((caller) => caller.name) - .join(', '); - const FLASH_DURATION_MS = 2000; const flashedKeys = ref(new Set()); const rowKey = (row: { workflowId: string; node: string; method?: string; path?: string }) => @@ -262,6 +243,7 @@ onMounted(async () => { multiple collapse-tags clearable + size="medium" :placeholder="i18n.baseText('settings.webhooks.filter.nodeType')" data-testid="webhooks-node-type-filter" :class="$style.nodeTypeFilter" @@ -275,6 +257,7 @@ onMounted(async () => { { {{ item.node }} - - @@ -392,6 +356,8 @@ onMounted(async () => { .controls { display: flex; justify-content: flex-end; + align-items: center; + gap: var(--spacing--2xs); } .search { @@ -426,12 +392,6 @@ onMounted(async () => { gap: var(--spacing--3xs); } -.pillCell { - display: flex; - flex-wrap: wrap; - gap: var(--spacing--3xs); -} - .ellipsis { white-space: nowrap; overflow: hidden;