Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a7c65c7
Support data tables
CharlieKolb Mar 3, 2026
d2eb3dd
Implement feature
CharlieKolb Mar 3, 2026
a7d4a29
add missing files
CharlieKolb Mar 4, 2026
1fb7a8e
fix overview page
CharlieKolb Mar 4, 2026
4736882
Use dropdown instead of modal
CharlieKolb Mar 5, 2026
5e642c6
Add tests
CharlieKolb Mar 5, 2026
e2b0e6d
Also add to data table view
CharlieKolb Mar 5, 2026
61fcb81
Final touches
CharlieKolb Mar 11, 2026
b3d3e81
improve tests
CharlieKolb Mar 11, 2026
8bbfd4c
fix badge spacing
CharlieKolb Mar 11, 2026
10197d0
Merge remote-tracking branch 'origin/master' into dt_dependencies
CharlieKolb Mar 11, 2026
d4d4883
Self review 1
CharlieKolb Mar 12, 2026
968bc70
self review 2
CharlieKolb Mar 12, 2026
a053059
undo claude settings change
CharlieKolb Mar 12, 2026
1c3d25a
clean up
CharlieKolb Mar 12, 2026
2bc4722
undo claude md change
CharlieKolb Mar 12, 2026
6e2cfbc
revamp backend
CharlieKolb Mar 12, 2026
4f66fb4
Merge remote-tracking branch 'origin/master' into dt_dependencies
CharlieKolb Mar 12, 2026
77e74cf
clean up
CharlieKolb Mar 13, 2026
87c2a68
Limit by user access
CharlieKolb Mar 13, 2026
e3ed2c9
Split out functionality and tests
CharlieKolb Mar 13, 2026
a2a077b
self review
CharlieKolb Mar 13, 2026
32e761f
fix tests
CharlieKolb Mar 13, 2026
92c4705
Update packages/frontend/@n8n/i18n/src/locales/en.json
CharlieKolb Mar 13, 2026
0aee7d1
Update packages/frontend/@n8n/i18n/src/locales/en.json
CharlieKolb Mar 13, 2026
6817ab2
feedback 1
CharlieKolb Mar 13, 2026
427198c
pr feedback 2
CharlieKolb Mar 13, 2026
839a70d
PR Feedback 3
CharlieKolb Mar 13, 2026
4034c60
PR feedback
CharlieKolb Mar 16, 2026
697ecec
Dont leak ids of inaccessible resources
CharlieKolb Mar 18, 2026
33e61c3
fix tests
CharlieKolb Mar 18, 2026
21bac65
Merge remote-tracking branch 'origin/master' into dt_dependencies
CharlieKolb Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/@n8n/api-types/src/dto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export { TransferWorkflowBodyDto } from './workflows/transfer.dto';
export { ActivateWorkflowDto } from './workflows/activate-workflow.dto';
export { DeactivateWorkflowDto } from './workflows/deactivate-workflow.dto';
export { ArchiveWorkflowDto } from './workflows/archive-workflow.dto';
export { GetResourceDependencyCountsDto } from './workflows/get-resource-dependency-counts.dto';
export { GetResourceDependenciesDto } from './workflows/get-resource-dependencies.dto';

export { CreateOrUpdateTagRequestDto } from './tag/create-or-update-tag-request.dto';
export { RetrieveTagQueryDto } from './tag/retrieve-tag-query.dto';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from 'zod';

import { Z } from '../../zod-class';

export class GetResourceDependenciesDto extends Z.class({
resourceIds: z.array(z.string()).min(1).max(100),
resourceType: z.enum(['workflow', 'credential', 'dataTable']),
}) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from 'zod';

import { Z } from '../../zod-class';

export class GetResourceDependencyCountsDto extends Z.class({
resourceIds: z.array(z.string()).min(1).max(100),
resourceType: z.enum(['workflow', 'credential', 'dataTable']),
}) {}
12 changes: 12 additions & 0 deletions packages/@n8n/api-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ export {
WORKFLOW_VERSION_NAME_MAX_LENGTH,
WORKFLOW_VERSION_DESCRIPTION_MAX_LENGTH,
} from './schemas/workflow-version.schema';
export type {
DependencyType,
DependencyResourceType,
ResolvedDependency,
ResolvedDependenciesResult,
DependenciesBatchResponse,
} from './schemas/dependency.schema';

export type {
DependencyTypeCounts,
DependencyCountsBatchResponse,
} from './schemas/dependency-counts.schema';

export type {
ProjectType,
Expand Down
12 changes: 12 additions & 0 deletions packages/@n8n/api-types/src/schemas/dependency-counts.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface DependencyTypeCounts {
credentialId: number;
dataTableId: number;
workflowCall: number;
workflowParent: number;
}

/**
* Lightweight response for workflow cards — only the counts per type,
* no resolved names / project IDs. Keyed by resource ID.
*/
export type DependencyCountsBatchResponse = Record<string, DependencyTypeCounts>;
19 changes: 19 additions & 0 deletions packages/@n8n/api-types/src/schemas/dependency.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export type DependencyType = 'credentialId' | 'dataTableId' | 'workflowCall' | 'workflowParent';
Comment thread
dariacodes marked this conversation as resolved.

export type DependencyResourceType = 'workflow' | 'credential' | 'dataTable';

export interface ResolvedDependency {

@cubic-dev-ai cubic-dev-ai Bot Mar 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: projectId should be required on the dataTableId variant instead of optional on every dependency. Otherwise a data-table dependency can be emitted without the field the frontend needs to build its link.

(Based on your team's feedback about preferring precise union DTOs over looser shared types.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/@n8n/api-types/src/schemas/dependency.schema.ts, line 5:

<comment>`projectId` should be required on the `dataTableId` variant instead of optional on every dependency. Otherwise a data-table dependency can be emitted without the field the frontend needs to build its link.

(Based on your team's feedback about preferring precise union DTOs over looser shared types.) </comment>

<file context>
@@ -0,0 +1,13 @@
+
+export type DependencyResourceType = 'workflow' | 'credential' | 'dataTable';
+
+export interface ResolvedDependency {
+	type: DependencyType;
+	id: string;
</file context>
Fix with Cubic

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case it's also optional for the case where a user doesn't have access to it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

type: DependencyType;
id: string;
name: string;
/** Project ID — included for data tables so the frontend can build a direct link */
projectId?: string;
}

export interface ResolvedDependenciesResult {
dependencies: ResolvedDependency[];
/** Number of dependencies the user does not have access to view */
inaccessibleCount: number;
}

export type DependenciesBatchResponse = Record<string, ResolvedDependenciesResult>;
48 changes: 48 additions & 0 deletions packages/cli/src/credentials/credentials-finder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,54 @@ export class CredentialsFinderService {
return sharedCredentialsList;
}

/**
* Given a list of credential IDs, return only those the user can access with the given scopes.
*/
async findCredentialIdsWithScopeForUser(

@cubic-dev-ai cubic-dev-ai Bot Mar 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add tests for the new credential access-filtering helper. This introduces authorization logic for dependency visibility, but there is no coverage for the new helper or its workflow-dependency integration, so regressions here would be easy to miss.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/credentials/credentials-finder.service.ts, line 230:

<comment>Add tests for the new credential access-filtering helper. This introduces authorization logic for dependency visibility, but there is no coverage for the new helper or its workflow-dependency integration, so regressions here would be easy to miss.</comment>

<file context>
@@ -224,6 +224,54 @@ export class CredentialsFinderService {
+	/**
+	 * Given a list of credential IDs, return only those the user can access with the given scopes.
+	 */
+	async findCredentialIdsWithScopeForUser(
+		credentialIds: string[],
+		user: User,
</file context>
Fix with Cubic

credentialIds: string[],
user: User,
scopes: Scope[],
): Promise<Set<string>> {
if (credentialIds.length === 0) return new Set();

let where: FindOptionsWhere<SharedCredentials> = { credentialsId: In(credentialIds) };

if (!hasGlobalScope(user, scopes, { mode: 'allOf' })) {
const [projectRoles, credentialRoles] = await Promise.all([
this.roleService.rolesWithScope('project', scopes),
this.roleService.rolesWithScope('credential', scopes),
]);
where = {
...where,
role: In(credentialRoles),
project: {
projectRelations: {
role: In(projectRoles),
userId: user.id,
},
},
};
}

const sharedCredentials = await this.sharedCredentialsRepository.find({
select: { credentialsId: true },
where,
});

const result = new Set(sharedCredentials.map((sc) => sc.credentialsId));

// Also include global credentials if scopes allow read-only access
if (this.hasGlobalReadOnlyAccess(scopes)) {
const globalCreds = await this.credentialsRepository.find({
where: { id: In(credentialIds), isGlobal: true },
select: ['id'],
});
for (const gc of globalCreds) result.add(gc.id);
}

return result;
}

async getCredentialIdsByUserAndRole(
userIds: string[],
options:
Expand Down
Loading
Loading