mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
* ✨ Added pinia support. Migrated community nodes module. * ✨ Added ui pinia store, moved some data from root store to it, updated modals to work with pinia stores * ✨ Added ui pinia store and migrated a part of the root store * ✨ Migrated `settings` store to pinia * ✨ Removing vuex store refs from router * ✨ Migrated `users` module to pinia store * ⚡ Fixing errors after sync with master * ⚡ One more error after merge * ⚡ Created `workflows` pinia store. Moved large part of root store to it. Started updating references. * ✨ Finished migrating workflows store to pinia * ⚡ Renaming some getters and actions to make more sense * ✨ Finished migrating the root store to pinia * ✨ Migrated ndv store to pinia * ⚡ Renaming main panel dimensions getter so it doesn't clash with data prop name * ✔️ Fixing lint errors * ✨ Migrated `templates` store to pinia * ✨ Migrated the `nodeTypes`store * ⚡ Removed unused pieces of code and oold vuex modules * ✨ Adding vuex calls to pinia store, fi xing wrong references * 💄 Removing leftover $store refs * ⚡ Added legacy getters and mutations to store to support webhooks * ⚡ Added missing front-end hooks, updated vuex state subscriptions to pinia * ✔️ Fixing linting errors * ⚡ Removing vue composition api plugin * ⚡ Fixing main sidebar state when loading node view * 🐛 Fixing an error when activating workflows * 🐛 Fixing isses with workflow settings and executions auto-refresh * 🐛 Removing duplicate listeners which cause import error * 🐛 Fixing route authentication * ⚡ Updating freshly pulled $store refs * Adding deleted const * ⚡ Updating store references in ee features. Reseting NodeView credentials update flag when resetting workspace * ⚡ Adding return type to email submission modal * ⚡ Making NodeView only react to paste event when active * 🐛 Fixing signup view errors * 👌 Addressing PR review comments * 👌 Addressing new PR comments * 👌 Updating invite id logic in signup view
314 lines
11 KiB
TypeScript
314 lines
11 KiB
TypeScript
import {
|
|
getCredentialTypes,
|
|
getCredentialsNewName,
|
|
getAllCredentials,
|
|
deleteCredential,
|
|
getCredentialData,
|
|
createNewCredential,
|
|
updateCredential,
|
|
oAuth2CredentialAuthorize,
|
|
oAuth1CredentialAuthorize,
|
|
testCredential,
|
|
getForeignCredentials,
|
|
} from '@/api/credentials';
|
|
import Vue from 'vue';
|
|
import { ActionContext, Module } from 'vuex';
|
|
import {
|
|
ICredentialMap,
|
|
ICredentialsResponse,
|
|
ICredentialsState,
|
|
ICredentialTypeMap,
|
|
IRootState,
|
|
} from '@/Interface';
|
|
import {
|
|
ICredentialType,
|
|
ICredentialsDecrypted,
|
|
INodeCredentialTestResult,
|
|
INodeTypeDescription,
|
|
INodeProperties,
|
|
} from 'n8n-workflow';
|
|
import { getAppNameFromCredType } from '@/components/helpers';
|
|
import {i18n} from "@/plugins/i18n";
|
|
import {credentialsEEModule} from "@/modules/credentials.ee";
|
|
import {EnterpriseEditionFeature} from "@/constants";
|
|
import { useUsersStore } from '@/stores/users';
|
|
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
|
import { useRootStore } from '@/stores/n8nRootStore';
|
|
import { useSettingsStore } from '@/stores/settings';
|
|
|
|
const DEFAULT_CREDENTIAL_NAME = 'Unnamed credential';
|
|
const DEFAULT_CREDENTIAL_POSTFIX = 'account';
|
|
const TYPES_WITH_DEFAULT_NAME = ['httpBasicAuth', 'oAuth2Api', 'httpDigestAuth', 'oAuth1Api'];
|
|
|
|
const module: Module<ICredentialsState, IRootState> = {
|
|
namespaced: true,
|
|
state: {
|
|
credentialTypes: {},
|
|
credentials: {},
|
|
...credentialsEEModule.state,
|
|
},
|
|
mutations: {
|
|
setCredentialTypes: (state: ICredentialsState, credentialTypes: ICredentialType[]) => {
|
|
state.credentialTypes = credentialTypes.reduce((accu: ICredentialTypeMap, cred: ICredentialType) => {
|
|
accu[cred.name] = cred;
|
|
|
|
return accu;
|
|
}, {});
|
|
},
|
|
setCredentials: (state: ICredentialsState, credentials: ICredentialsResponse[]) => {
|
|
state.credentials = credentials.reduce((accu: ICredentialMap, cred: ICredentialsResponse) => {
|
|
if (cred.id) {
|
|
accu[cred.id] = cred;
|
|
}
|
|
|
|
return accu;
|
|
}, {});
|
|
},
|
|
setForeignCredentials: (state: ICredentialsState, credentials: ICredentialsResponse[]) => {
|
|
state.foreignCredentials = credentials.reduce((accu: ICredentialMap, cred: ICredentialsResponse) => {
|
|
if (cred.id) {
|
|
accu[cred.id] = cred;
|
|
}
|
|
|
|
return accu;
|
|
}, {});
|
|
},
|
|
upsertCredential(state: ICredentialsState, credential: ICredentialsResponse) {
|
|
if (credential.id) {
|
|
Vue.set(state.credentials, credential.id, { ...state.credentials[credential.id], ...credential });
|
|
}
|
|
},
|
|
deleteCredential(state: ICredentialsState, id: string) {
|
|
Vue.delete(state.credentials, id);
|
|
},
|
|
enableOAuthCredential(state: ICredentialsState, credential: ICredentialsResponse) {
|
|
// enable oauth event to track change between modals
|
|
},
|
|
...credentialsEEModule.mutations,
|
|
},
|
|
getters: {
|
|
credentialTypesById(state: ICredentialsState): Record<ICredentialType['name'], ICredentialType> {
|
|
return state.credentialTypes;
|
|
},
|
|
allCredentialTypes(state: ICredentialsState): ICredentialType[] {
|
|
return Object.values(state.credentialTypes)
|
|
.sort((a, b) => a.displayName.localeCompare(b.displayName));
|
|
},
|
|
allCredentials(state: ICredentialsState): ICredentialsResponse[] {
|
|
return Object.values(state.credentials)
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
},
|
|
allForeignCredentials(state: ICredentialsState): ICredentialsResponse[] {
|
|
return Object.values(state.foreignCredentials || {})
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
},
|
|
allCredentialsByType(state: ICredentialsState, getters: any): {[type: string]: ICredentialsResponse[]} { // tslint:disable-line:no-any
|
|
const credentials = getters.allCredentials as ICredentialsResponse[];
|
|
const types = getters.allCredentialTypes as ICredentialType[];
|
|
|
|
return types.reduce((accu: {[type: string]: ICredentialsResponse[]}, type: ICredentialType) => {
|
|
accu[type.name] = credentials.filter((cred: ICredentialsResponse) => cred.type === type.name);
|
|
|
|
return accu;
|
|
}, {});
|
|
},
|
|
getCredentialTypeByName: (state: ICredentialsState) => {
|
|
return (type: string) => state.credentialTypes[type];
|
|
},
|
|
getCredentialById: (state: ICredentialsState) => {
|
|
return (id: string) => state.credentials[id];
|
|
},
|
|
getCredentialByIdAndType: (state: ICredentialsState) => {
|
|
return (id: string, type: string) => {
|
|
const credential = state.credentials[id];
|
|
return !credential || credential.type !== type ? undefined : credential;
|
|
};
|
|
},
|
|
getCredentialsByType: (state: ICredentialsState, getters: any) => { // tslint:disable-line:no-any
|
|
return (credentialType: string): ICredentialsResponse[] => {
|
|
return (getters.allCredentialsByType[credentialType] || []);
|
|
};
|
|
},
|
|
getNodesWithAccess (state: ICredentialsState, getters: any, rootState: IRootState, rootGetters: any) { // tslint:disable-line:no-any
|
|
return (credentialTypeName: string) => {
|
|
const nodeTypesStore = useNodeTypesStore();
|
|
const allLatestNodeTypes: INodeTypeDescription[] = nodeTypesStore.allLatestNodeTypes;
|
|
|
|
return allLatestNodeTypes.filter((nodeType: INodeTypeDescription) => {
|
|
if (!nodeType.credentials) {
|
|
return false;
|
|
}
|
|
|
|
for (const credentialTypeDescription of nodeType.credentials) {
|
|
if (credentialTypeDescription.name === credentialTypeName ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
});
|
|
};
|
|
},
|
|
getScopesByCredentialType (_: ICredentialsState, getters: any) { // tslint:disable-line:no-any
|
|
return (credentialTypeName: string) => {
|
|
const credentialType = getters.getCredentialTypeByName(credentialTypeName) as {
|
|
properties: INodeProperties[];
|
|
};
|
|
|
|
const scopeProperty = credentialType.properties.find((p) => p.name === 'scope');
|
|
|
|
if (
|
|
!scopeProperty ||
|
|
!scopeProperty.default ||
|
|
typeof scopeProperty.default !== 'string' ||
|
|
scopeProperty.default === ''
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
let { default: scopeDefault } = scopeProperty;
|
|
|
|
// disregard expressions for display
|
|
scopeDefault = scopeDefault.replace(/^=/, '').replace(/\{\{.*\}\}/, '');
|
|
|
|
if (/ /.test(scopeDefault)) return scopeDefault.split(' ');
|
|
|
|
if (/,/.test(scopeDefault)) return scopeDefault.split(',');
|
|
|
|
return [scopeDefault];
|
|
};
|
|
},
|
|
getCredentialOwnerName: (state: ICredentialsState, getters: any) => // tslint:disable-line:no-any
|
|
(credentialId: string): string => {
|
|
const credential = getters.getCredentialById(credentialId);
|
|
return credential && credential.ownedBy && credential.ownedBy.firstName
|
|
? `${credential.ownedBy.firstName} ${credential.ownedBy.lastName} (${credential.ownedBy.email})`
|
|
: i18n.baseText('credentialEdit.credentialSharing.info.sharee.fallback');
|
|
},
|
|
...credentialsEEModule.getters,
|
|
},
|
|
actions: {
|
|
fetchCredentialTypes: async (context: ActionContext<ICredentialsState, IRootState>, forceFetch: boolean) => {
|
|
if (context.getters.allCredentialTypes.length > 0 && forceFetch !== true) {
|
|
return;
|
|
}
|
|
const rootStore = useRootStore();
|
|
const credentialTypes = await getCredentialTypes(rootStore.getRestApiContext);
|
|
context.commit('setCredentialTypes', credentialTypes);
|
|
},
|
|
fetchAllCredentials: async (context: ActionContext<ICredentialsState, IRootState>): Promise<ICredentialsResponse[]> => {
|
|
const rootStore = useRootStore();
|
|
const credentials = await getAllCredentials(rootStore.getRestApiContext);
|
|
context.commit('setCredentials', credentials);
|
|
|
|
return credentials;
|
|
},
|
|
fetchForeignCredentials: async (context: ActionContext<ICredentialsState, IRootState>): Promise<ICredentialsResponse[]> => {
|
|
const rootStore = useRootStore();
|
|
const credentials = await getForeignCredentials(rootStore.getRestApiContext);
|
|
context.commit('setForeignCredentials', credentials);
|
|
|
|
return credentials;
|
|
},
|
|
getCredentialData: async (context: ActionContext<ICredentialsState, IRootState>, { id }: {id: string}) => {
|
|
const rootStore = useRootStore();
|
|
return await getCredentialData(rootStore.getRestApiContext, id);
|
|
},
|
|
createNewCredential: async (context: ActionContext<ICredentialsState, IRootState>, data: ICredentialsDecrypted) => {
|
|
const rootStore = useRootStore();
|
|
const settingsStore = useSettingsStore();
|
|
const credential = await createNewCredential(rootStore.getRestApiContext, data);
|
|
|
|
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
|
context.commit('upsertCredential', credential);
|
|
|
|
if (data.ownedBy) {
|
|
context.commit('setCredentialOwnedBy', {
|
|
credentialId: credential.id,
|
|
ownedBy: data.ownedBy,
|
|
});
|
|
|
|
const usersStore = useUsersStore();
|
|
if (data.sharedWith && data.ownedBy.id === usersStore.currentUserId) {
|
|
await context.dispatch('setCredentialSharedWith', {
|
|
credentialId: credential.id,
|
|
sharedWith: data.sharedWith,
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
context.commit('upsertCredential', credential);
|
|
}
|
|
|
|
return credential;
|
|
},
|
|
updateCredential: async (context: ActionContext<ICredentialsState, IRootState>, params: {data: ICredentialsDecrypted, id: string}) => {
|
|
const { id, data } = params;
|
|
const rootStore = useRootStore();
|
|
const settingsStore = useSettingsStore();
|
|
const credential = await updateCredential(rootStore.getRestApiContext, id, data);
|
|
|
|
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
|
context.commit('upsertCredential', credential);
|
|
|
|
if (data.ownedBy) {
|
|
context.commit('setCredentialOwnedBy', {
|
|
credentialId: credential.id,
|
|
ownedBy: data.ownedBy,
|
|
});
|
|
|
|
const usersStore = useUsersStore();
|
|
if (data.sharedWith && data.ownedBy.id === usersStore.currentUserId) {
|
|
await context.dispatch('setCredentialSharedWith', {
|
|
credentialId: credential.id,
|
|
sharedWith: data.sharedWith,
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
context.commit('upsertCredential', credential);
|
|
}
|
|
|
|
return credential;
|
|
},
|
|
deleteCredential: async (context: ActionContext<ICredentialsState, IRootState>, { id }: {id: string}) => {
|
|
const rootStore = useRootStore();
|
|
const deleted = await deleteCredential(rootStore.getRestApiContext, id);
|
|
if (deleted) {
|
|
context.commit('deleteCredential', id);
|
|
}
|
|
},
|
|
oAuth2Authorize: async (context: ActionContext<ICredentialsState, IRootState>, data: ICredentialsResponse) => {
|
|
const rootStore = useRootStore();
|
|
return oAuth2CredentialAuthorize(rootStore.getRestApiContext, data);
|
|
},
|
|
oAuth1Authorize: async (context: ActionContext<ICredentialsState, IRootState>, data: ICredentialsResponse) => {
|
|
const rootStore = useRootStore();
|
|
return oAuth1CredentialAuthorize(rootStore.getRestApiContext, data);
|
|
},
|
|
testCredential: async (context: ActionContext<ICredentialsState, IRootState>, data: ICredentialsDecrypted): Promise<INodeCredentialTestResult> => {
|
|
const rootStore = useRootStore();
|
|
return testCredential(rootStore.getRestApiContext, { credentials: data });
|
|
},
|
|
getNewCredentialName: async (context: ActionContext<ICredentialsState, IRootState>, params: { credentialTypeName: string }) => {
|
|
try {
|
|
const { credentialTypeName } = params;
|
|
let newName = DEFAULT_CREDENTIAL_NAME;
|
|
if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) {
|
|
const { displayName } = context.getters.getCredentialTypeByName(credentialTypeName);
|
|
newName = getAppNameFromCredType(displayName);
|
|
newName = newName.length > 0 ? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}` : DEFAULT_CREDENTIAL_NAME;
|
|
}
|
|
const rootStore = useRootStore();
|
|
const res = await getCredentialsNewName(rootStore.getRestApiContext, newName);
|
|
return res.name;
|
|
} catch (e) {
|
|
return DEFAULT_CREDENTIAL_NAME;
|
|
}
|
|
},
|
|
...credentialsEEModule.actions,
|
|
},
|
|
};
|
|
|
|
export default module;
|