mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix: Fix automatic credential selection when credentials are shared (#5020)
* fix: fix default credentials when inserting nodes * fix: update default without sharing * fix: fix clearing credential bug, automatically selecting shared cred bug * fix: include sharable creds in automatic selections * fix: update getter * fix: refactor subscribe logic, fix update bug * fix: remove unnessary import * format: prettier
This commit is contained in:
@@ -123,7 +123,7 @@ export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.listenForNewCredentials();
|
this.listenForCredentialUpdates();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(
|
...mapStores(
|
||||||
@@ -133,9 +133,6 @@ export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend(
|
|||||||
useUsersStore,
|
useUsersStore,
|
||||||
useWorkflowsStore,
|
useWorkflowsStore,
|
||||||
),
|
),
|
||||||
allCredentialsByType(): { [type: string]: ICredentialsResponse[] } {
|
|
||||||
return this.credentialsStore.allCredentialsByType;
|
|
||||||
},
|
|
||||||
currentUser(): IUser {
|
currentUser(): IUser {
|
||||||
return this.usersStore.currentUser || ({} as IUser);
|
return this.usersStore.currentUser || ({} as IUser);
|
||||||
},
|
},
|
||||||
@@ -182,13 +179,7 @@ export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend(
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getCredentialOptions(type: string): ICredentialsResponse[] {
|
getCredentialOptions(type: string): ICredentialsResponse[] {
|
||||||
return (this.allCredentialsByType as Record<string, ICredentialsResponse[]>)[type].filter(
|
return this.credentialsStore.allUsableCredentialsByType[type];
|
||||||
(credential) => {
|
|
||||||
const permissions = getCredentialPermissions(this.currentUser, credential);
|
|
||||||
|
|
||||||
return permissions.use;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
getSelectedId(type: string) {
|
getSelectedId(type: string) {
|
||||||
if (this.isCredentialExisting(type)) {
|
if (this.isCredentialExisting(type)) {
|
||||||
@@ -221,41 +212,71 @@ export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend(
|
|||||||
|
|
||||||
return styles;
|
return styles;
|
||||||
},
|
},
|
||||||
// TODO: Investigate if this can be solved using only the store data (storing selected flag in credentials objects, ...)
|
// Listen for credentials store changes so credential selection can be updated if creds are changed from the modal
|
||||||
listenForNewCredentials() {
|
listenForCredentialUpdates() {
|
||||||
// Listen for credentials store changes so credential selection can be updated if creds are changed from the modal
|
const getCounts = () => {
|
||||||
this.credentialsStore.$subscribe((mutation, state) => {
|
return Object.keys(this.credentialsStore.allUsableCredentialsByType).reduce(
|
||||||
|
(counts: { [key: string]: number }, key: string) => {
|
||||||
|
counts[key] = this.credentialsStore.allUsableCredentialsByType[key].length;
|
||||||
|
return counts;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let previousCredentialCounts = getCounts();
|
||||||
|
const onCredentialMutation = () => {
|
||||||
// This data pro stores credential type that the component is currently interested in
|
// This data pro stores credential type that the component is currently interested in
|
||||||
const credentialType = this.subscribedToCredentialType;
|
const credentialType = this.subscribedToCredentialType;
|
||||||
let credentialsOfType = this.credentialsStore.allCredentialsByType[credentialType];
|
if (!credentialType) {
|
||||||
|
return;
|
||||||
if (credentialsOfType) {
|
|
||||||
credentialsOfType = credentialsOfType.sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
||||||
if (credentialsOfType.length > 0) {
|
|
||||||
// If nothing has been selected previously, select the first one (newly added)
|
|
||||||
if (!this.selected[credentialType]) {
|
|
||||||
this.onCredentialSelected(credentialType, credentialsOfType[0].id);
|
|
||||||
} else {
|
|
||||||
// Else, check id currently selected cred has been updated
|
|
||||||
const newSelected = credentialsOfType.find(
|
|
||||||
(cred) => cred.id === this.selected[credentialType].id,
|
|
||||||
);
|
|
||||||
// If it has changed, select it
|
|
||||||
if (newSelected && newSelected.name !== this.selected[credentialType].name) {
|
|
||||||
this.onCredentialSelected(credentialType, newSelected.id);
|
|
||||||
} else {
|
|
||||||
// Else select the last cred with that type since selected has been deleted or a new one has been added
|
|
||||||
this.onCredentialSelected(
|
|
||||||
credentialType,
|
|
||||||
credentialsOfType[credentialsOfType.length - 1].id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.subscribedToCredentialType = '';
|
|
||||||
|
let credentialsOfType = [
|
||||||
|
...(this.credentialsStore.allUsableCredentialsByType[credentialType] || []),
|
||||||
|
];
|
||||||
|
// all credentials were deleted
|
||||||
|
if (credentialsOfType.length === 0) {
|
||||||
|
this.clearSelectedCredential(credentialType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialsOfType = credentialsOfType.sort((a, b) => (a.id < b.id ? -1 : 1));
|
||||||
|
const previousCredsOfType = previousCredentialCounts[credentialType] || 0;
|
||||||
|
const current = this.selected[credentialType];
|
||||||
|
|
||||||
|
// new credential was added
|
||||||
|
if (credentialsOfType.length > previousCredsOfType || !current) {
|
||||||
|
this.onCredentialSelected(
|
||||||
|
credentialType,
|
||||||
|
credentialsOfType[credentialsOfType.length - 1].id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingCredential = credentialsOfType.find((cred) => cred.id === current.id);
|
||||||
|
// credential was deleted, select last one added to replace with
|
||||||
|
if (!matchingCredential) {
|
||||||
|
this.onCredentialSelected(
|
||||||
|
credentialType,
|
||||||
|
credentialsOfType[credentialsOfType.length - 1].id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// credential was updated
|
||||||
|
if (matchingCredential.name !== current.name) {
|
||||||
|
// credential name was changed, update it
|
||||||
|
this.onCredentialSelected(credentialType, current.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.credentialsStore.$subscribe((mutation, state) => {
|
||||||
|
onCredentialMutation();
|
||||||
|
previousCredentialCounts = getCounts();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
clearSelectedCredential(credentialType: string) {
|
clearSelectedCredential(credentialType: string) {
|
||||||
const node: INodeUi = this.node;
|
const node: INodeUi = this.node;
|
||||||
|
|
||||||
@@ -277,7 +298,6 @@ export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend(
|
|||||||
|
|
||||||
onCredentialSelected(credentialType: string, credentialId: string | null | undefined) {
|
onCredentialSelected(credentialType: string, credentialId: string | null | undefined) {
|
||||||
if (credentialId === this.NEW_CREDENTIALS_TEXT) {
|
if (credentialId === this.NEW_CREDENTIALS_TEXT) {
|
||||||
// this.listenForNewCredentials(credentialType);
|
|
||||||
this.subscribedToCredentialType = credentialType;
|
this.subscribedToCredentialType = credentialType;
|
||||||
}
|
}
|
||||||
if (!credentialId || credentialId === this.NEW_CREDENTIALS_TEXT) {
|
if (!credentialId || credentialId === this.NEW_CREDENTIALS_TEXT) {
|
||||||
|
|||||||
@@ -72,6 +72,22 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
allUsableCredentialsByType(): { [type: string]: ICredentialsResponse[] } {
|
||||||
|
const credentials = this.allCredentials;
|
||||||
|
const types = this.allCredentialTypes;
|
||||||
|
const usersStore = useUsersStore();
|
||||||
|
|
||||||
|
return types.reduce(
|
||||||
|
(accu: { [type: string]: ICredentialsResponse[] }, type: ICredentialType) => {
|
||||||
|
accu[type.name] = credentials.filter((cred: ICredentialsResponse) => {
|
||||||
|
return cred.type === type.name && usersStore.isResourceAccessible(cred);
|
||||||
|
});
|
||||||
|
|
||||||
|
return accu;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
},
|
||||||
getCredentialTypeByName() {
|
getCredentialTypeByName() {
|
||||||
return (type: string): ICredentialType => this.credentialTypes[type];
|
return (type: string): ICredentialType => this.credentialTypes[type];
|
||||||
},
|
},
|
||||||
@@ -89,6 +105,11 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
|||||||
return this.allCredentialsByType[credentialType] || [];
|
return this.allCredentialsByType[credentialType] || [];
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
getUsableCredentialByType() {
|
||||||
|
return (credentialType: string): ICredentialsResponse[] => {
|
||||||
|
return this.allUsableCredentialsByType[credentialType] || [];
|
||||||
|
};
|
||||||
|
},
|
||||||
getNodesWithAccess() {
|
getNodesWithAccess() {
|
||||||
return (credentialTypeName: string) => {
|
return (credentialTypeName: string) => {
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
|
|||||||
@@ -18,14 +18,16 @@ import {
|
|||||||
validatePasswordToken,
|
validatePasswordToken,
|
||||||
validateSignupToken,
|
validateSignupToken,
|
||||||
} from '@/api/users';
|
} from '@/api/users';
|
||||||
import { PERSONALIZATION_MODAL_KEY, STORES } from '@/constants';
|
import { EnterpriseEditionFeature, PERSONALIZATION_MODAL_KEY, STORES } from '@/constants';
|
||||||
import {
|
import {
|
||||||
|
ICredentialsResponse,
|
||||||
IInviteResponse,
|
IInviteResponse,
|
||||||
IPersonalizationLatestVersion,
|
IPersonalizationLatestVersion,
|
||||||
IUser,
|
IUser,
|
||||||
IUserResponse,
|
IUserResponse,
|
||||||
IUsersState,
|
IUsersState,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
import { getCredentialPermissions } from '@/permissions';
|
||||||
import { getPersonalizedNodeTypes, isAuthorized, PERMISSIONS, ROLE } from '@/utils';
|
import { getPersonalizedNodeTypes, isAuthorized, PERMISSIONS, ROLE } from '@/utils';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
@@ -90,6 +92,13 @@ export const useUsersStore = defineStore(STORES.USERS, {
|
|||||||
}
|
}
|
||||||
return getPersonalizedNodeTypes(answers);
|
return getPersonalizedNodeTypes(answers);
|
||||||
},
|
},
|
||||||
|
isResourceAccessible() {
|
||||||
|
return (resource: ICredentialsResponse): boolean => {
|
||||||
|
const permissions = getCredentialPermissions(this.currentUser, resource);
|
||||||
|
|
||||||
|
return permissions.use;
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
addUsers(users: IUserResponse[]) {
|
addUsers(users: IUserResponse[]) {
|
||||||
|
|||||||
@@ -1714,7 +1714,7 @@ export default mixins(
|
|||||||
const credentialPerType =
|
const credentialPerType =
|
||||||
nodeTypeData.credentials &&
|
nodeTypeData.credentials &&
|
||||||
nodeTypeData.credentials
|
nodeTypeData.credentials
|
||||||
.map((type) => this.credentialsStore.getCredentialsByType(type.name))
|
.map((type) => this.credentialsStore.getUsableCredentialByType(type.name))
|
||||||
.flat();
|
.flat();
|
||||||
|
|
||||||
if (credentialPerType && credentialPerType.length === 1) {
|
if (credentialPerType && credentialPerType.length === 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user