refactor(editor): Move rbac.store into @n8n/stores (no-changelog) (#34141)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Alex Grozav 2026-07-14 14:24:39 +02:00 committed by GitHub
parent 0739aeb970
commit 5ceaa3b17b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 173 additions and 156 deletions

View File

@ -36,6 +36,8 @@
"format:check": "biome ci . && prettier --check . --ignore-path ../../../../.prettierignore"
},
"dependencies": {
"@n8n/api-types": "workspace:*",
"@n8n/permissions": "workspace:*",
"n8n-workflow": "workspace:*",
"@vueuse/core": "catalog:frontend",
"pinia": "catalog:frontend",

View File

@ -1,10 +1,12 @@
import { createPinia, setActivePinia } from 'pinia';
import { useRBACStore } from '@/app/stores/rbac.store';
import type * as PermissionsModule from '@n8n/permissions';
import type { Scope } from '@n8n/permissions';
import { hasScope } from '@n8n/permissions';
import { createPinia, setActivePinia } from 'pinia';
import { useRBACStore } from './rbac.store';
vi.mock('@n8n/permissions', async () => {
const { hasScope } = await vi.importActual<typeof import('@n8n/permissions')>('@n8n/permissions');
const { hasScope } = await vi.importActual<typeof PermissionsModule>('@n8n/permissions');
return {
hasScope: vi.fn().mockImplementation(hasScope),
};

View File

@ -0,0 +1,154 @@
import type { Role } from '@n8n/api-types';
import { hasScope as genericHasScope } from '@n8n/permissions';
import type { ScopeOptions, Scope, Resource } from '@n8n/permissions';
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { STORES } from './constants';
export const useRBACStore = defineStore(STORES.RBAC, () => {
const globalRoles = ref<Role[]>([]);
const rolesByProjectId = ref<Record<string, string[]>>({});
const globalScopes = ref<Scope[]>([]);
const scopesByProjectId = ref<Record<string, Scope[]>>({});
const scopesByResourceId = ref<Record<Resource, Record<string, Scope[]>>>({
agent: {},
aiAssistant: {},
workflow: {},
tag: {},
annotationTag: {},
user: {},
credential: {},
variable: {},
projectVariable: {},
sourceControl: {},
externalSecretsProvider: {},
externalSecret: {},
project: {},
orchestration: {},
workersView: {},
eventBusDestination: {},
auditLogs: {},
banner: {},
community: {},
communityPackage: {},
ldap: {},
license: {},
logStreaming: {},
saml: {},
oidc: {},
provisioning: {},
securityAudit: {},
folder: {},
insights: {},
dataTable: {},
execution: {},
testRun: {},
workflowTags: {},
role: {},
mcp: {},
mcpApiKey: {},
chatHub: {},
chatHubAgent: {},
breakingChanges: {},
apiKey: {},
encryptionKey: {},
credentialResolver: {},
instanceAi: {},
securitySettings: {},
roleMappingRule: {},
otel: {},
});
function addGlobalRole(role: Role) {
if (!globalRoles.value.includes(role)) {
globalRoles.value.push(role);
}
}
function hasRole(role: Role) {
return globalRoles.value.includes(role);
}
function addGlobalScope(scope: Scope) {
if (!globalScopes.value.includes(scope)) {
globalScopes.value.push(scope);
}
}
function setGlobalScopes(scopes: Scope[]) {
globalScopes.value = scopes;
}
function addProjectScope(
scope: Scope,
context: {
projectId: string;
},
) {
if (!scopesByProjectId.value[context.projectId]) {
scopesByProjectId.value[context.projectId] = [];
}
if (!scopesByProjectId.value[context.projectId].includes(scope)) {
scopesByProjectId.value[context.projectId].push(scope);
}
}
function addResourceScope(
scope: Scope,
context: {
resourceType: Resource;
resourceId: string;
},
) {
const scopesByResourceType = scopesByResourceId.value[context.resourceType];
if (!scopesByResourceType[context.resourceId]) {
scopesByResourceType[context.resourceId] = [];
}
if (!scopesByResourceType[context.resourceId].includes(scope)) {
scopesByResourceType[context.resourceId].push(scope);
}
}
function hasScope(
scope: Scope | Scope[],
context?: {
resourceType?: Resource;
resourceId?: string;
projectId?: string;
},
options?: ScopeOptions,
): boolean {
return genericHasScope(
scope,
{
global: globalScopes.value,
project: context?.projectId ? scopesByProjectId.value[context.projectId] : [],
resource:
context?.resourceType && context?.resourceId
? scopesByResourceId.value[context.resourceType][context.resourceId]
: [],
},
undefined,
options,
);
}
return {
globalRoles,
rolesByProjectId,
globalScopes,
scopesByProjectId,
scopesByResourceId,
addGlobalRole,
hasRole,
addGlobalScope,
setGlobalScopes,
addProjectScope,
addResourceScope,
hasScope,
};
});

View File

@ -1,153 +1,6 @@
import { defineStore } from 'pinia';
import { hasScope as genericHasScope } from '@n8n/permissions';
import type { ScopeOptions, Scope, Resource } from '@n8n/permissions';
import { ref } from 'vue';
import { STORES } from '@n8n/stores';
import type { Role } from '@n8n/api-types';
export const useRBACStore = defineStore(STORES.RBAC, () => {
const globalRoles = ref<Role[]>([]);
const rolesByProjectId = ref<Record<string, string[]>>({});
const globalScopes = ref<Scope[]>([]);
const scopesByProjectId = ref<Record<string, Scope[]>>({});
const scopesByResourceId = ref<Record<Resource, Record<string, Scope[]>>>({
agent: {},
aiAssistant: {},
workflow: {},
tag: {},
annotationTag: {},
user: {},
credential: {},
variable: {},
projectVariable: {},
sourceControl: {},
externalSecretsProvider: {},
externalSecret: {},
project: {},
orchestration: {},
workersView: {},
eventBusDestination: {},
auditLogs: {},
banner: {},
community: {},
communityPackage: {},
ldap: {},
license: {},
logStreaming: {},
saml: {},
oidc: {},
provisioning: {},
securityAudit: {},
folder: {},
insights: {},
dataTable: {},
execution: {},
testRun: {},
workflowTags: {},
role: {},
mcp: {},
mcpApiKey: {},
chatHub: {},
chatHubAgent: {},
breakingChanges: {},
apiKey: {},
encryptionKey: {},
credentialResolver: {},
instanceAi: {},
securitySettings: {},
roleMappingRule: {},
otel: {},
});
function addGlobalRole(role: Role) {
if (!globalRoles.value.includes(role)) {
globalRoles.value.push(role);
}
}
function hasRole(role: Role) {
return globalRoles.value.includes(role);
}
function addGlobalScope(scope: Scope) {
if (!globalScopes.value.includes(scope)) {
globalScopes.value.push(scope);
}
}
function setGlobalScopes(scopes: Scope[]) {
globalScopes.value = scopes;
}
function addProjectScope(
scope: Scope,
context: {
projectId: string;
},
) {
if (!scopesByProjectId.value[context.projectId]) {
scopesByProjectId.value[context.projectId] = [];
}
if (!scopesByProjectId.value[context.projectId].includes(scope)) {
scopesByProjectId.value[context.projectId].push(scope);
}
}
function addResourceScope(
scope: Scope,
context: {
resourceType: Resource;
resourceId: string;
},
) {
const scopesByResourceType = scopesByResourceId.value[context.resourceType];
if (!scopesByResourceType[context.resourceId]) {
scopesByResourceType[context.resourceId] = [];
}
if (!scopesByResourceType[context.resourceId].includes(scope)) {
scopesByResourceType[context.resourceId].push(scope);
}
}
function hasScope(
scope: Scope | Scope[],
context?: {
resourceType?: Resource;
resourceId?: string;
projectId?: string;
},
options?: ScopeOptions,
): boolean {
return genericHasScope(
scope,
{
global: globalScopes.value,
project: context?.projectId ? scopesByProjectId.value[context.projectId] : [],
resource:
context?.resourceType && context?.resourceId
? scopesByResourceId.value[context.resourceType][context.resourceId]
: [],
},
undefined,
options,
);
}
return {
globalRoles,
rolesByProjectId,
globalScopes,
scopesByProjectId,
scopesByResourceId,
addGlobalRole,
hasRole,
addGlobalScope,
setGlobalScopes,
addProjectScope,
addResourceScope,
hasScope,
};
});
/**
* @deprecated Import from `@n8n/stores/rbac.store` instead. This store moved to
* `@n8n/stores` (CAT-3686 kernel slice); this re-export is a temporary shim kept
* so existing importers keep working and will be removed once call sites migrate.
*/
export * from '@n8n/stores/rbac.store';

View File

@ -5207,6 +5207,12 @@ importers:
packages/frontend/@n8n/stores:
dependencies:
'@n8n/api-types':
specifier: workspace:*
version: link:../../../@n8n/api-types
'@n8n/permissions':
specifier: workspace:*
version: link:../../../@n8n/permissions
'@vueuse/core':
specifier: catalog:frontend
version: 10.11.0(vue@3.5.26(typescript@6.0.2))