refactor(editor): Move frontend permissions code to @n8n/permissions (no-changelog) (#16656)

This commit is contained in:
Alex Grozav
2025-06-24 14:41:29 +03:00
committed by GitHub
parent f133736b54
commit f58c1ce083
36 changed files with 42 additions and 39 deletions

View File

@@ -4,7 +4,7 @@ import dateformat from 'dateformat';
import { MODAL_CONFIRM, PROJECT_MOVE_RESOURCE_MODAL } from '@/constants';
import { useMessage } from '@/composables/useMessage';
import CredentialIcon from '@/components/CredentialIcon.vue';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useUIStore } from '@/stores/ui.store';
import { useCredentialsStore } from '@/stores/credentials.store';
import TimeAgo from '@/components/TimeAgo.vue';

View File

@@ -19,7 +19,7 @@ import {
EnterpriseEditionFeature,
NEW_ASSISTANT_SESSION_MODAL,
} from '@/constants';
import type { PermissionsRecord } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import { addCredentialTranslation } from '@n8n/i18n';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useNDVStore } from '@/stores/ndv.store';

View File

@@ -28,7 +28,7 @@ import { useMessage } from '@/composables/useMessage';
import { useNodeHelpers } from '@/composables/useNodeHelpers';
import { useToast } from '@/composables/useToast';
import { CREDENTIAL_EDIT_MODAL_KEY, EnterpriseEditionFeature, MODAL_CONFIRM } from '@/constants';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useNDVStore } from '@/stores/ndv.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';

View File

@@ -5,7 +5,7 @@ import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { EnterpriseEditionFeature } from '@/constants';
import type { ICredentialsDecryptedResponse, ICredentialsResponse } from '@/Interface';
import type { PermissionsRecord } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import { useProjectsStore } from '@/stores/projects.store';
import { useRolesStore } from '@/stores/roles.store';
import { useSettingsStore } from '@/stores/settings.store';

View File

@@ -180,7 +180,7 @@ const googleBigQueryOAuth2Api: ICredentialType = {
supportedNodes: ['n8n-nodes-base.googleBigQuery'],
};
vi.mock('@/permissions', () => ({
vi.mock('@n8n/permissions', () => ({
getResourcePermissions: vi.fn(() => ({
credential: {
create: true,

View File

@@ -18,7 +18,7 @@ import type {
ICredentialsResponse,
IUsedCredential,
} from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import MoveToFolderDropdown from './MoveToFolderDropdown.vue';
import { ResourceType, getTruncatedProjectName } from '@/utils/projects.utils';
import { useWorkflowsStore } from '@/stores/workflows.store';

View File

@@ -36,7 +36,7 @@ import { saveAs } from 'file-saver';
import { useDocumentTitle } from '@/composables/useDocumentTitle';
import { useMessage } from '@/composables/useMessage';
import { useToast } from '@/composables/useToast';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { createEventBus } from '@n8n/utils/event-bus';
import { nodeViewEventBus } from '@/event-bus';
import { hasPermission } from '@/utils/rbac/permissions';

View File

@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
import { createEventBus } from '@n8n/utils/event-bus';
import { useI18n } from '@n8n/i18n';
import { hasPermission } from '@/utils/rbac/permissions';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useToast } from '@/composables/useToast';
import { useLoadingService } from '@/composables/useLoadingService';
import { useUIStore } from '@/stores/ui.store';

View File

@@ -93,7 +93,7 @@ import { useExternalHooks } from '@/composables/useExternalHooks';
import { useI18n } from '@n8n/i18n';
import { useRoute, useRouter } from 'vue-router';
import { useUIStore } from '@/stores/ui.store';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
const SURVEY_VERSION = 'v4';

View File

@@ -9,7 +9,7 @@ import { type ProjectIcon as ProjectIconType, ProjectTypes } from '@/types/proje
import { useProjectsStore } from '@/stores/projects.store';
import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
import ProjectIcon from '@/components/Projects/ProjectIcon.vue';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { VIEWS } from '@/constants';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import ProjectCreateResource from '@/components/Projects/ProjectCreateResource.vue';

View File

@@ -6,7 +6,7 @@ import { useTelemetry } from '@/composables/useTelemetry';
import { useToast } from '@/composables/useToast';
import { VIEWS } from '@/constants';
import type { ICredentialsResponse, IUsedCredential, IWorkflowDb } from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useProjectsStore } from '@/stores/projects.store';
import { useUIStore } from '@/stores/ui.store';

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { RouteLocationNamedRaw } from 'vue-router';
import type { ICredentialsResponse, IUsedCredential } from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { VIEWS } from '@/constants';
const props = withDefaults(

View File

@@ -6,7 +6,7 @@ import { getActivatableTriggerNodes } from '@/utils/nodeTypesUtils';
import type { VNode } from 'vue';
import { computed, h, watch } from 'vue';
import { useI18n } from '@n8n/i18n';
import type { PermissionsRecord } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import {
WORKFLOW_ACTIVATION_CONFLICTING_WEBHOOK_MODAL_KEY,
EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,

View File

@@ -9,7 +9,7 @@ import {
} from '@/constants';
import { useMessage } from '@/composables/useMessage';
import { useToast } from '@/composables/useToast';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import dateformat from 'dateformat';
import WorkflowActivator from '@/components/WorkflowActivator.vue';
import { useUIStore } from '@/stores/ui.store';

View File

@@ -20,7 +20,7 @@ import { createEventBus } from '@n8n/utils/event-bus';
import { useExternalHooks } from '@/composables/useExternalHooks';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import { ProjectTypes } from '@/types/projects.types';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useI18n } from '@n8n/i18n';
import { useTelemetry } from '@/composables/useTelemetry';

View File

@@ -9,7 +9,7 @@ import {
PLACEHOLDER_EMPTY_WORKFLOW_ID,
WORKFLOW_SHARE_MODAL_KEY,
} from '@/constants';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useMessage } from '@/composables/useMessage';
import { useToast } from '@/composables/useToast';
import { nodeViewEventBus } from '@/event-bus';

View File

@@ -9,8 +9,8 @@ import { useTelemetry } from '@/composables/useTelemetry';
import { useToast } from '@/composables/useToast';
import { EnterpriseEditionFeature, MODAL_CONFIRM } from '@/constants';
import type { ExecutionFilterType, ExecutionSummaryWithScopes, IWorkflowDb } from '@/Interface';
import type { PermissionsRecord } from '@/permissions';
import { getResourcePermissions } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useExecutionsStore } from '@/stores/executions.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useWorkflowsStore } from '@/stores/workflows.store';

View File

@@ -4,7 +4,7 @@ import ExecutionsTime from '@/components/executions/ExecutionsTime.vue';
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
import { useI18n } from '@n8n/i18n';
import { VIEWS } from '@/constants';
import type { PermissionsRecord } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
import {
N8nButton,

View File

@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
import type { ExecutionSummary } from 'n8n-workflow';
import { useI18n } from '@n8n/i18n';
import { ElDropdown } from 'element-plus';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useRoute } from 'vue-router';

View File

@@ -8,7 +8,7 @@ import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
import type { ExecutionSummary } from 'n8n-workflow';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useI18n } from '@n8n/i18n';
import type { PermissionsRecord } from '@/permissions';
import type { PermissionsRecord } from '@n8n/permissions';
import { useSettingsStore } from '@/stores/settings.store';
import { toDayMonth, toTime } from '@/utils/formatters/dateFormatter';

View File

@@ -9,7 +9,7 @@ import { useI18n } from '@n8n/i18n';
import { useToast } from '@/composables/useToast';
import { useMessage } from '@/composables/useMessage';
import { EnterpriseEditionFeature, MODAL_CONFIRM, VIEWS } from '@/constants';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useSettingsStore } from '@/stores/settings.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus';

View File

@@ -11,7 +11,7 @@ import type { ExecutionSummary } from 'n8n-workflow';
import { useExecutionsStore } from '@/stores/executions.store';
import type { ExecutionFilterType, IWorkflowDb } from '@/Interface';
import { isComponentPublicInstance } from '@/utils/typeGuards';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useI18n } from '@n8n/i18n';
import { useSettingsStore } from '@/stores/settings.store';
import ConcurrentExecutionsHeader from '@/components/executions/ConcurrentExecutionsHeader.vue';

View File

@@ -11,7 +11,7 @@ import { getMousePosition } from '../utils/nodeViewUtils';
import { useI18n } from '@n8n/i18n';
import { usePinnedData } from './usePinnedData';
import { isPresent } from '../utils/typesUtils';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
export type ContextMenuTarget =
| { source: 'canvas'; nodeIds: string[]; nodeId?: string }

View File

@@ -8,7 +8,7 @@ import { useProjectsStore } from '@/stores/projects.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import type { Scope } from '@n8n/permissions';
import type { RouteLocationRaw } from 'vue-router';

View File

@@ -7,7 +7,7 @@ import { useRootStore } from '@n8n/stores/useRootStore';
import { useUsersStore } from '@/stores/users.store';
import { useSettingsStore } from '@/stores/settings.store';
import { transformInsightsSummary } from '@/features/insights/insights.utils';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
export const useInsightsStore = defineStore('insights', () => {
const rootStore = useRootStore();

View File

@@ -1,134 +0,0 @@
import type { PermissionsRecord } from '@/permissions';
import { getResourcePermissions } from '@/permissions';
import type { Scope } from '@n8n/permissions';
describe('permissions', () => {
it('getResourcePermissions for empty scopes', () => {
expect(getResourcePermissions()).toEqual({
annotationTag: {},
auditLogs: {},
banner: {},
community: {},
communityPackage: {},
credential: {},
externalSecretsProvider: {},
externalSecret: {},
eventBusDestination: {},
ldap: {},
license: {},
logStreaming: {},
oidc: {},
orchestration: {},
project: {},
saml: {},
securityAudit: {},
sourceControl: {},
tag: {},
user: {},
variable: {},
workersView: {},
workflow: {},
folder: {},
insights: {},
});
});
it('getResourcePermissions', () => {
const scopes: Scope[] = [
'credential:create',
'credential:delete',
'credential:list',
'credential:move',
'credential:read',
'credential:share',
'credential:update',
'eventBusDestination:list',
'eventBusDestination:test',
'project:list',
'project:read',
'tag:create',
'tag:list',
'tag:read',
'tag:update',
'user:list',
'variable:list',
'variable:read',
'workflow:create',
'workflow:delete',
'workflow:execute',
'workflow:list',
'workflow:move',
'workflow:read',
'workflow:share',
'workflow:update',
'folder:create',
'insights:list',
];
const permissionRecord: PermissionsRecord = {
annotationTag: {},
auditLogs: {},
banner: {},
community: {},
communityPackage: {},
credential: {
create: true,
delete: true,
list: true,
move: true,
read: true,
share: true,
update: true,
},
eventBusDestination: {
list: true,
test: true,
},
externalSecret: {},
externalSecretsProvider: {},
ldap: {},
license: {},
logStreaming: {},
orchestration: {},
project: {
list: true,
read: true,
},
saml: {},
oidc: {},
securityAudit: {},
sourceControl: {},
tag: {
create: true,
list: true,
read: true,
update: true,
},
user: {
list: true,
},
variable: {
list: true,
read: true,
},
workersView: {},
workflow: {
create: true,
delete: true,
execute: true,
list: true,
move: true,
read: true,
share: true,
update: true,
},
folder: {
create: true,
},
insights: {
list: true,
},
};
expect(getResourcePermissions(scopes)).toEqual(permissionRecord);
});
});

View File

@@ -1,32 +0,0 @@
import type { Scope } from '@n8n/permissions';
import { RESOURCES } from '@n8n/permissions';
type ExtractScopePrefixSuffix<T> = T extends `${infer Prefix}:${infer Suffix}`
? [Prefix, Suffix]
: never;
type ActionBooleans<T extends readonly string[]> = {
[K in T[number]]?: boolean;
};
export type PermissionsRecord = {
[K in keyof typeof RESOURCES]: ActionBooleans<(typeof RESOURCES)[K]>;
};
export const getResourcePermissions = (resourceScopes: Scope[] = []): PermissionsRecord =>
Object.keys(RESOURCES).reduce(
(permissions, key) => ({
...permissions,
[key]: resourceScopes.reduce((resourcePermissions, scope) => {
const [prefix, suffix] = scope.split(':') as ExtractScopePrefixSuffix<Scope>;
if (prefix === key) {
return {
...resourcePermissions,
[suffix]: true,
};
}
return resourcePermissions;
}, {}),
}),
{} as PermissionsRecord,
);

View File

@@ -1,7 +1,7 @@
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
import { VIEWS } from '@/constants';
import { useProjectsStore } from '@/stores/projects.store';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
const MainSidebar = async () => await import('@/components/MainSidebar.vue');
const WorkflowsView = async () => await import('@/views/WorkflowsView.vue');

View File

@@ -15,7 +15,7 @@ import type { IWorkflowDb } from '@/Interface';
import { useCredentialsStore } from '@/stores/credentials.store';
import { STORES } from '@n8n/stores';
import { useUsersStore } from '@/stores/users.store';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import type { CreateProjectDto, UpdateProjectDto } from '@n8n/api-types';
import { useSourceControlStore } from '@/stores/sourceControl.store';

View File

@@ -15,7 +15,7 @@ import {
import InsightsSummary from '@/features/insights/components/InsightsSummary.vue';
import { useInsightsStore } from '@/features/insights/insights.store';
import type { ICredentialTypeMap } from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useCredentialsStore } from '@/stores/credentials.store';
import useEnvironmentsStore from '@/stores/environments.ee.store';
import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store';

View File

@@ -117,7 +117,7 @@ import { N8nCallout } from '@n8n/design-system';
import type { PinDataSource } from '@/composables/usePinnedData';
import { useClipboard } from '@/composables/useClipboard';
import { useBeforeUnload } from '@/composables/useBeforeUnload';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
import { createCanvasConnectionHandleString } from '@/utils/canvasUtils';
import { isValidNodeConnectionType } from '@/utils/typeGuards';

View File

@@ -12,7 +12,7 @@ import { hasPermission } from '@/utils/rbac/permissions';
import N8nInfoTip from '@n8n/design-system/components/N8nInfoTip';
import { COMMUNITY_PLUS_ENROLLMENT_MODAL } from '@/constants';
import { useUsersStore } from '@/stores/users.store';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
const usageStore = useUsageStore();

View File

@@ -20,7 +20,7 @@ import type { BaseFilters, Resource, VariableResource } from '@/Interface';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { EnterpriseEditionFeature, MODAL_CONFIRM } from '@/constants';
import type { DatatableColumn, EnvironmentVariable } from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import {
N8nActionBox,
N8nBadge,

View File

@@ -19,7 +19,7 @@ import { useUIStore } from '@/stores/ui.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { telemetry } from '@/plugins/telemetry';
import { useRootStore } from '@n8n/stores/useRootStore';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import type { IUser } from 'n8n-workflow';

View File

@@ -37,7 +37,7 @@ import type {
WorkflowListItem,
WorkflowListResource,
} from '@/Interface';
import { getResourcePermissions } from '@/permissions';
import { getResourcePermissions } from '@n8n/permissions';
import { useFoldersStore } from '@/stores/folders.store';
import { usePostHog } from '@/stores/posthog.store';
import { useProjectsStore } from '@/stores/projects.store';