mirror of
https://github.com/n8n-io/n8n.git
synced 2026-07-27 19:15:01 +02:00
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:
parent
0739aeb970
commit
5ceaa3b17b
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
154
packages/frontend/@n8n/stores/src/rbac.store.ts
Normal file
154
packages/frontend/@n8n/stores/src/rbac.store.ts
Normal 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,
|
||||
};
|
||||
});
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user