feat: RBAC (#8922)

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Val <68596159+valya@users.noreply.github.com>
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
Co-authored-by: Valya Bullions <valya@n8n.io>
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: Danny Martini <despair.blue@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
Co-authored-by: oleg <me@olegivaniv.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: Elias Meire <elias@meire.dev>
Co-authored-by: Giulio Andreini <andreini@netseven.it>
Co-authored-by: Giulio Andreini <g.andreini@gmail.com>
Co-authored-by: Ayato Hayashi <go12limchangyong@gmail.com>
This commit is contained in:
Csaba Tuncsik
2024-05-17 10:53:15 +02:00
committed by GitHub
parent b1f977ebd0
commit 596c472ecc
292 changed files with 14129 additions and 3989 deletions

View File

@@ -290,6 +290,7 @@ import type {
Workflow,
ConnectionTypes,
INodeOutputConfiguration,
IRun,
} from 'n8n-workflow';
import {
deepCopy,
@@ -317,6 +318,7 @@ import type {
NodeCreatorOpenSource,
AddedNodesAndConnections,
ToggleNodeCreatorOptions,
IPushDataExecutionFinished,
AIAssistantConnectionInfo,
} from '@/Interface';
@@ -388,6 +390,8 @@ import { useCanvasPanning } from '@/composables/useCanvasPanning';
import { tryToParseNumber } from '@/utils/typesUtils';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { useRunWorkflow } from '@/composables/useRunWorkflow';
import { useProjectsStore } from '@/features/projects/projects.store';
import type { ProjectSharingData } from '@/features/projects/projects.types';
import { useAIStore } from '@/stores/ai.store';
import { useStorage } from '@/composables/useStorage';
import { isJSPlumbEndpointElement } from '@/utils/typeGuards';
@@ -555,7 +559,7 @@ export default defineComponent({
this.resetWorkspace();
this.uiStore.stateIsDirty = previousDirtyState;
}
await Promise.all([this.loadCredentials(), this.initView()]);
await this.initView();
this.canvasStore.stopLoading();
if (this.blankRedirect) {
this.blankRedirect = false;
@@ -617,6 +621,7 @@ export default defineComponent({
usePushConnectionStore,
useSourceControlStore,
useExecutionsStore,
useProjectsStore,
useAIStore,
),
nativelyNumberSuffixedDefaults(): string[] {
@@ -837,11 +842,7 @@ export default defineComponent({
const loadPromises = (() => {
if (this.settingsStore.isPreviewMode && this.isDemo) return [];
const promises = [
this.loadActiveWorkflows(),
this.loadCredentials(),
this.loadCredentialTypes(),
];
const promises = [this.loadActiveWorkflows(), this.loadCredentialTypes()];
if (this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Variables)) {
promises.push(this.loadVariables());
}
@@ -1282,17 +1283,10 @@ export default defineComponent({
this.workflowsStore.setWorkflowPinData(data.workflowData.pinData);
}
if (data.workflowData.ownedBy) {
this.workflowsEEStore.setWorkflowOwnedBy({
workflowId: data.workflowData.id,
ownedBy: data.workflowData.ownedBy,
});
}
if (data.workflowData.sharedWith) {
if (data.workflowData.sharedWithProjects) {
this.workflowsEEStore.setWorkflowSharedWith({
workflowId: data.workflowData.id,
sharedWith: data.workflowData.sharedWith,
sharedWithProjects: data.workflowData.sharedWithProjects,
});
}
@@ -1418,7 +1412,11 @@ export default defineComponent({
await this.$router.replace({ name: VIEWS.NEW_WORKFLOW, query: { templateId } });
await this.addNodes(data.workflow.nodes, data.workflow.connections);
this.workflowData = (await this.workflowsStore.getNewWorkflowData(data.name)) || {};
this.workflowData =
(await this.workflowsStore.getNewWorkflowData(
data.name,
this.projectsStore.currentProjectId,
)) || {};
this.workflowsStore.addToWorkflowMetadata({ templateId });
await this.$nextTick();
this.canvasStore.zoomToFit();
@@ -1447,17 +1445,10 @@ export default defineComponent({
this.workflowsStore.setWorkflowVersionId(workflow.versionId);
this.workflowsStore.setWorkflowMetadata(workflow.meta);
if (workflow.ownedBy) {
this.workflowsEEStore.setWorkflowOwnedBy({
workflowId: workflow.id,
ownedBy: workflow.ownedBy,
});
}
if (workflow.sharedWith) {
if (workflow.sharedWithProjects) {
this.workflowsEEStore.setWorkflowSharedWith({
workflowId: workflow.id,
sharedWith: workflow.sharedWith,
sharedWithProjects: workflow.sharedWithProjects,
});
}
@@ -3647,10 +3638,21 @@ export default defineComponent({
// Clear the interval to prevent the notification from being sent
clearTimeout(this.unloadTimeout);
},
makeNewWorkflowShareable() {
const { currentProject, personalProject } = this.projectsStore;
const homeProject = currentProject ?? personalProject ?? {};
const scopes = currentProject?.scopes ?? personalProject?.scopes ?? [];
this.workflowsStore.workflow.homeProject = homeProject as ProjectSharingData;
this.workflowsStore.workflow.scopes = scopes;
},
async newWorkflow(): Promise<void> {
this.canvasStore.startLoading();
this.resetWorkspace();
this.workflowData = await this.workflowsStore.getNewWorkflowData();
this.workflowData = await this.workflowsStore.getNewWorkflowData(
undefined,
this.projectsStore.currentProjectId,
);
this.workflowsStore.currentWorkflowExecutions = [];
this.executionsStore.activeExecution = null;
@@ -3660,6 +3662,7 @@ export default defineComponent({
this.uiStore.nodeViewInitialized = true;
this.historyStore.reset();
this.executionsStore.activeExecution = null;
this.makeNewWorkflowShareable();
this.canvasStore.stopLoading();
},
async tryToAddWelcomeSticky(): Promise<void> {
@@ -3700,6 +3703,7 @@ export default defineComponent({
return;
}
}
await this.loadCredentials();
// Load a workflow
let workflowId = null as string | null;
if (this.$route.params.name) {
@@ -4664,7 +4668,12 @@ export default defineComponent({
await this.credentialsStore.fetchCredentialTypes(true);
},
async loadCredentials(): Promise<void> {
await this.credentialsStore.fetchAllCredentials();
const workflow = this.workflowsStore.getWorkflowById(this.currentWorkflow);
const projectId =
workflow?.homeProject?.type === 'personal'
? this.projectsStore.personalProject?.id
: workflow?.homeProject?.id;
await this.credentialsStore.fetchAllCredentials(projectId);
},
async loadVariables(): Promise<void> {
await this.environmentsStore.fetchAllVariables();
@@ -4968,7 +4977,7 @@ export default defineComponent({
this.resetWorkspace();
this.uiStore.stateIsDirty = false;
await this.$router.replace({ name: VIEWS.WORKFLOWS });
await this.$router.replace({ name: VIEWS.HOMEPAGE });
});
}
},
@@ -5032,7 +5041,7 @@ export default defineComponent({
}
try {
await Promise.all([this.loadCredentials(), this.loadVariables(), this.tagsStore.fetchAll()]);
await Promise.all([this.loadVariables(), this.tagsStore.fetchAll(), this.loadCredentials()]);
if (workflowId !== null && !this.uiStore.stateIsDirty) {
const workflow: IWorkflowDb | undefined =