refactor(editor): Migrate Credentials.store to use composition API (no-changelog) (#9767)

This commit is contained in:
Ricardo Espinoza 2024-06-17 04:54:38 -04:00 committed by GitHub
parent 076c35d193
commit 60491d979d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -7,20 +7,8 @@ import type {
ICredentialsState, ICredentialsState,
ICredentialTypeMap, ICredentialTypeMap,
} from '@/Interface'; } from '@/Interface';
import { import * as credentialsApi from '@/api/credentials';
createNewCredential, import * as credentialsEeApi from '@/api/credentials.ee';
deleteCredential,
getAllCredentials,
getAllCredentialsForWorkflow,
getCredentialData,
getCredentialsNewName,
getCredentialTypes,
oAuth1CredentialAuthorize,
oAuth2CredentialAuthorize,
testCredential,
updateCredential,
} from '@/api/credentials';
import { setCredentialSharedWith } from '@/api/credentials.ee';
import { makeRestApiRequest } from '@/utils/apiUtils'; import { makeRestApiRequest } from '@/utils/apiUtils';
import { getAppNameFromCredType } from '@/utils/nodeTypesUtils'; import { getAppNameFromCredType } from '@/utils/nodeTypesUtils';
import { EnterpriseEditionFeature, STORES } from '@/constants'; import { EnterpriseEditionFeature, STORES } from '@/constants';
@ -38,6 +26,7 @@ import { useSettingsStore } from './settings.store';
import { isEmpty } from '@/utils/typesUtils'; import { isEmpty } from '@/utils/typesUtils';
import type { ProjectSharingData } from '@/types/projects.types'; import type { ProjectSharingData } from '@/types/projects.types';
import { splitName } from '@/utils/projects.utils'; import { splitName } from '@/utils/projects.utils';
import { computed, ref } from 'vue';
const DEFAULT_CREDENTIAL_NAME = 'Unnamed credential'; const DEFAULT_CREDENTIAL_NAME = 'Unnamed credential';
const DEFAULT_CREDENTIAL_POSTFIX = 'account'; const DEFAULT_CREDENTIAL_POSTFIX = 'account';
@ -45,57 +34,44 @@ const TYPES_WITH_DEFAULT_NAME = ['httpBasicAuth', 'oAuth2Api', 'httpDigestAuth',
export type CredentialsStore = ReturnType<typeof useCredentialsStore>; export type CredentialsStore = ReturnType<typeof useCredentialsStore>;
export const useCredentialsStore = defineStore(STORES.CREDENTIALS, { export const useCredentialsStore = defineStore(STORES.CREDENTIALS, () => {
state: (): ICredentialsState => ({ const state = ref<ICredentialsState>({ credentialTypes: {}, credentials: {} });
credentialTypes: {},
credentials: {}, // ---------------------------------------------------------------------------
}), // #region Computed
getters: { // ---------------------------------------------------------------------------
credentialTypesById(): Record<ICredentialType['name'], ICredentialType> {
return this.credentialTypes; const credentialTypesById = computed(() => {
}, return state.value.credentialTypes;
allCredentialTypes(): ICredentialType[] { });
return Object.values(this.credentialTypes).sort((a, b) =>
const allCredentialTypes = computed(() => {
return Object.values(state.value.credentialTypes).sort((a, b) =>
a.displayName.localeCompare(b.displayName), a.displayName.localeCompare(b.displayName),
); );
}, });
allCredentials(): ICredentialsResponse[] {
return Object.values(this.credentials).sort((a, b) => a.name.localeCompare(b.name));
},
allCredentialsByType(): { [type: string]: ICredentialsResponse[] } {
const credentials = this.allCredentials;
const types = this.allCredentialTypes;
const allCredentials = computed(() => {
return Object.values(state.value.credentials).sort((a, b) => a.name.localeCompare(b.name));
});
const allCredentialsByType = computed(() => {
const credentials = allCredentials.value;
const types = allCredentialTypes.value;
return types.reduce( return types.reduce(
(accu: { [type: string]: ICredentialsResponse[] }, type: ICredentialType) => { (accu: { [type: string]: ICredentialsResponse[] }, type: ICredentialType) => {
accu[type.name] = credentials.filter( accu[type.name] = credentials.filter(
(cred: ICredentialsResponse) => cred.type === type.name, (cred: ICredentialsResponse) => cred.type === type.name,
); );
return accu; return accu;
}, },
{}, {},
); );
},
allUsableCredentialsForNode() {
return (node: INodeUi): ICredentialsResponse[] => {
let credentials: ICredentialsResponse[] = [];
const nodeType = useNodeTypesStore().getNodeType(node.type, node.typeVersion);
if (nodeType?.credentials) {
nodeType.credentials.forEach((cred) => {
credentials = credentials.concat(this.allUsableCredentialsByType[cred.name]);
}); });
}
return credentials.sort((a, b) => { const allUsableCredentialsByType = computed(() => {
const aDate = new Date(a.updatedAt); const credentials = allCredentials.value;
const bDate = new Date(b.updatedAt); const types = allCredentialTypes.value;
return aDate.getTime() - bDate.getTime();
});
};
},
allUsableCredentialsByType(): { [type: string]: ICredentialsResponse[] } {
const credentials = this.allCredentials;
const types = this.allCredentialTypes;
return types.reduce( return types.reduce(
(accu: { [type: string]: ICredentialsResponse[] }, type: ICredentialType) => { (accu: { [type: string]: ICredentialsResponse[] }, type: ICredentialType) => {
@ -107,30 +83,53 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
}, },
{}, {},
); );
}, });
getCredentialTypeByName() {
return (type: string): ICredentialType | undefined => this.credentialTypes[type]; const allUsableCredentialsForNode = computed(() => {
}, return (node: INodeUi): ICredentialsResponse[] => {
getCredentialById() { let credentials: ICredentialsResponse[] = [];
return (id: string): ICredentialsResponse => this.credentials[id]; const nodeType = useNodeTypesStore().getNodeType(node.type, node.typeVersion);
}, if (nodeType?.credentials) {
getCredentialByIdAndType() { nodeType.credentials.forEach((cred) => {
credentials = credentials.concat(allUsableCredentialsByType.value[cred.name]);
});
}
return credentials.sort((a, b) => {
const aDate = new Date(a.updatedAt);
const bDate = new Date(b.updatedAt);
return aDate.getTime() - bDate.getTime();
});
};
});
const getCredentialTypeByName = computed(() => {
return (type: string): ICredentialType | undefined => state.value.credentialTypes[type];
});
const getCredentialById = computed(() => {
return (id: string): ICredentialsResponse => state.value.credentials[id];
});
const getCredentialByIdAndType = computed(() => {
return (id: string, type: string): ICredentialsResponse | undefined => { return (id: string, type: string): ICredentialsResponse | undefined => {
const credential = this.credentials[id]; const credential = state.value.credentials[id];
return !credential || credential.type !== type ? undefined : credential; return !credential || credential.type !== type ? undefined : credential;
}; };
}, });
getCredentialsByType() {
const getCredentialsByType = computed(() => {
return (credentialType: string): ICredentialsResponse[] => { return (credentialType: string): ICredentialsResponse[] => {
return this.allCredentialsByType[credentialType] || []; return allCredentialsByType.value[credentialType] || [];
}; };
}, });
getUsableCredentialByType() {
const getUsableCredentialByType = computed(() => {
return (credentialType: string): ICredentialsResponse[] => { return (credentialType: string): ICredentialsResponse[] => {
return this.allUsableCredentialsByType[credentialType] || []; return allUsableCredentialsByType.value[credentialType] || [];
}; };
}, });
getNodesWithAccess() {
const getNodesWithAccess = computed(() => {
return (credentialTypeName: string) => { return (credentialTypeName: string) => {
const nodeTypesStore = useNodeTypesStore(); const nodeTypesStore = useNodeTypesStore();
const allNodeTypes: INodeTypeDescription[] = nodeTypesStore.allNodeTypes; const allNodeTypes: INodeTypeDescription[] = nodeTypesStore.allNodeTypes;
@ -149,10 +148,11 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
return false; return false;
}); });
}; };
}, });
getScopesByCredentialType() {
const getScopesByCredentialType = computed(() => {
return (credentialTypeName: string) => { return (credentialTypeName: string) => {
const credentialType = this.getCredentialTypeByName(credentialTypeName); const credentialType = getCredentialTypeByName.value(credentialTypeName);
if (!credentialType) { if (!credentialType) {
return []; return [];
} }
@ -179,8 +179,9 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
return [scopeDefault]; return [scopeDefault];
}; };
}, });
getCredentialOwnerName() {
const getCredentialOwnerName = computed(() => {
return (credential: ICredentialsResponse | IUsedCredential | undefined): string => { return (credential: ICredentialsResponse | IUsedCredential | undefined): string => {
const { firstName, lastName, email } = splitName(credential?.homeProject?.name ?? ''); const { firstName, lastName, email } = splitName(credential?.homeProject?.name ?? '');
@ -188,21 +189,28 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
? `${firstName} ${lastName} (${email})` ? `${firstName} ${lastName} (${email})`
: i18n.baseText('credentialEdit.credentialSharing.info.sharee.fallback'); : i18n.baseText('credentialEdit.credentialSharing.info.sharee.fallback');
}; };
}, });
getCredentialOwnerNameById() {
return (credentialId: string): string => {
const credential = this.getCredentialById(credentialId);
return this.getCredentialOwnerName(credential); const getCredentialOwnerNameById = computed(() => {
return (credentialId: string): string => {
const credential = getCredentialById.value(credentialId);
return getCredentialOwnerName.value(credential);
}; };
}, });
httpOnlyCredentialTypes(): ICredentialType[] {
return this.allCredentialTypes.filter((credentialType) => credentialType.httpRequestNode); const httpOnlyCredentialTypes = computed(() => {
}, return allCredentialTypes.value.filter((credentialType) => credentialType.httpRequestNode);
}, });
actions: {
setCredentialTypes(credentialTypes: ICredentialType[]): void { // #endregion
this.credentialTypes = credentialTypes.reduce(
// ---------------------------------------------------------------------------
// #region Methods
// ---------------------------------------------------------------------------
const setCredentialTypes = (credentialTypes: ICredentialType[]) => {
state.value.credentialTypes = credentialTypes.reduce(
(accu: ICredentialTypeMap, cred: ICredentialType) => { (accu: ICredentialTypeMap, cred: ICredentialType) => {
accu[cred.name] = cred; accu[cred.name] = cred;
@ -210,177 +218,237 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
}, },
{}, {},
); );
}, };
setCredentials(credentials: ICredentialsResponse[]): void {
this.credentials = credentials.reduce((accu: ICredentialMap, cred: ICredentialsResponse) => { const addCredentials = (credentials: ICredentialsResponse[]) => {
credentials.forEach((cred: ICredentialsResponse) => {
if (cred.id) {
state.value.credentials[cred.id] = { ...state.value.credentials[cred.id], ...cred };
}
});
};
const setCredentials = (credentials: ICredentialsResponse[]) => {
state.value.credentials = credentials.reduce(
(accu: ICredentialMap, cred: ICredentialsResponse) => {
if (cred.id) { if (cred.id) {
accu[cred.id] = cred; accu[cred.id] = cred;
} }
return accu; return accu;
}, {});
}, },
addCredentials(credentials: ICredentialsResponse[]): void { {},
credentials.forEach((cred: ICredentialsResponse) => { );
if (cred.id) { };
this.credentials[cred.id] = { ...this.credentials[cred.id], ...cred };
} const upsertCredential = (credential: ICredentialsResponse) => {
});
},
upsertCredential(credential: ICredentialsResponse): void {
if (credential.id) { if (credential.id) {
this.credentials = { state.value.credentials = {
...this.credentials, ...state.value.credentials,
[credential.id]: { [credential.id]: {
...this.credentials[credential.id], ...state.value.credentials[credential.id],
...credential, ...credential,
}, },
}; };
} }
}, };
async fetchCredentialTypes(forceFetch: boolean): Promise<void> {
if (this.allCredentialTypes.length > 0 && !forceFetch) { const fetchCredentialTypes = async (forceFetch: boolean) => {
if (allCredentialTypes.value.length > 0 && !forceFetch) {
return; return;
} }
const rootStore = useRootStore(); const rootStore = useRootStore();
const credentialTypes = await getCredentialTypes(rootStore.getBaseUrl); const credentialTypes = await credentialsApi.getCredentialTypes(rootStore.getBaseUrl);
this.setCredentialTypes(credentialTypes); setCredentialTypes(credentialTypes);
}, };
async fetchAllCredentials(
const fetchAllCredentials = async (
projectId?: string, projectId?: string,
includeScopes = true, includeScopes = true,
): Promise<ICredentialsResponse[]> { ): Promise<ICredentialsResponse[]> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
const filter = { const filter = {
projectId, projectId,
}; };
const credentials = await getAllCredentials( const credentials = await credentialsApi.getAllCredentials(
rootStore.getRestApiContext, rootStore.getRestApiContext,
isEmpty(filter) ? undefined : filter, isEmpty(filter) ? undefined : filter,
includeScopes, includeScopes,
); );
this.setCredentials(credentials); setCredentials(credentials);
return credentials; return credentials;
}, };
async fetchAllCredentialsForWorkflow(
const fetchAllCredentialsForWorkflow = async (
options: { workflowId: string } | { projectId: string }, options: { workflowId: string } | { projectId: string },
): Promise<ICredentialsResponse[]> { ): Promise<ICredentialsResponse[]> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
const credentials = await getAllCredentialsForWorkflow(rootStore.getRestApiContext, options); const credentials = await credentialsApi.getAllCredentialsForWorkflow(
this.setCredentials(credentials); rootStore.getRestApiContext,
options,
);
setCredentials(credentials);
return credentials; return credentials;
}, };
async getCredentialData({
const getCredentialData = async ({
id, id,
}: { }: {
id: string; id: string;
}): Promise<ICredentialsResponse | ICredentialsDecryptedResponse | undefined> { }): Promise<ICredentialsResponse | ICredentialsDecryptedResponse | undefined> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
return await getCredentialData(rootStore.getRestApiContext, id); return await credentialsApi.getCredentialData(rootStore.getRestApiContext, id);
}, };
async createNewCredential(
const createNewCredential = async (
data: ICredentialsDecrypted, data: ICredentialsDecrypted,
projectId?: string, projectId?: string,
): Promise<ICredentialsResponse> { ): Promise<ICredentialsResponse> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const credential = await createNewCredential(rootStore.getRestApiContext, data, projectId); const credential = await credentialsApi.createNewCredential(
rootStore.getRestApiContext,
data,
projectId,
);
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) { if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
this.upsertCredential(credential); upsertCredential(credential);
if (data.sharedWithProjects) { if (data.sharedWithProjects) {
await this.setCredentialSharedWith({ await setCredentialSharedWith({
credentialId: credential.id, credentialId: credential.id,
sharedWithProjects: data.sharedWithProjects, sharedWithProjects: data.sharedWithProjects,
}); });
} }
} else { } else {
this.upsertCredential(credential); upsertCredential(credential);
} }
return credential; return credential;
}, };
async updateCredential(params: {
const updateCredential = async (params: {
data: ICredentialsDecrypted; data: ICredentialsDecrypted;
id: string; id: string;
}): Promise<ICredentialsResponse> { }): Promise<ICredentialsResponse> => {
const { id, data } = params; const { id, data } = params;
const rootStore = useRootStore(); const rootStore = useRootStore();
const credential = await updateCredential(rootStore.getRestApiContext, id, data); const credential = await credentialsApi.updateCredential(rootStore.getRestApiContext, id, data);
this.upsertCredential(credential); upsertCredential(credential);
return credential; return credential;
}, };
async deleteCredential({ id }: { id: string }) {
const deleteCredential = async ({ id }: { id: string }) => {
const rootStore = useRootStore(); const rootStore = useRootStore();
const deleted = await deleteCredential(rootStore.getRestApiContext, id); const deleted = await credentialsApi.deleteCredential(rootStore.getRestApiContext, id);
if (deleted) { if (deleted) {
const { [id]: deletedCredential, ...rest } = this.credentials; const { [id]: deletedCredential, ...rest } = state.value.credentials;
this.credentials = rest; state.value.credentials = rest;
} }
}, };
async oAuth2Authorize(data: ICredentialsResponse): Promise<string> {
const oAuth2Authorize = async (data: ICredentialsResponse): Promise<string> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
return await oAuth2CredentialAuthorize(rootStore.getRestApiContext, data); return await credentialsApi.oAuth2CredentialAuthorize(rootStore.getRestApiContext, data);
}, };
async oAuth1Authorize(data: ICredentialsResponse): Promise<string> {
const oAuth1Authorize = async (data: ICredentialsResponse): Promise<string> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
return await oAuth1CredentialAuthorize(rootStore.getRestApiContext, data); return await credentialsApi.oAuth1CredentialAuthorize(rootStore.getRestApiContext, data);
}, };
async testCredential(data: ICredentialsDecrypted): Promise<INodeCredentialTestResult> {
const testCredential = async (
data: ICredentialsDecrypted,
): Promise<INodeCredentialTestResult> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
return await testCredential(rootStore.getRestApiContext, { credentials: data }); return await credentialsApi.testCredential(rootStore.getRestApiContext, { credentials: data });
}, };
async getNewCredentialName(params: { credentialTypeName: string }): Promise<string> {
const getNewCredentialName = async (params: { credentialTypeName: string }): Promise<string> => {
try { try {
const { credentialTypeName } = params; const { credentialTypeName } = params;
let newName = DEFAULT_CREDENTIAL_NAME; let newName = DEFAULT_CREDENTIAL_NAME;
if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) { if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) {
const cred = this.getCredentialTypeByName(credentialTypeName); const cred = getCredentialTypeByName.value(credentialTypeName);
newName = cred ? getAppNameFromCredType(cred.displayName) : ''; newName = cred ? getAppNameFromCredType(cred.displayName) : '';
newName = newName =
newName.length > 0 newName.length > 0 ? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}` : DEFAULT_CREDENTIAL_NAME;
? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}`
: DEFAULT_CREDENTIAL_NAME;
} }
const rootStore = useRootStore(); const rootStore = useRootStore();
const res = await getCredentialsNewName(rootStore.getRestApiContext, newName); const res = await credentialsApi.getCredentialsNewName(rootStore.getRestApiContext, newName);
return res.name; return res.name;
} catch (e) { } catch (e) {
return DEFAULT_CREDENTIAL_NAME; return DEFAULT_CREDENTIAL_NAME;
} }
}, };
async setCredentialSharedWith(payload: {
const setCredentialSharedWith = async (payload: {
sharedWithProjects: ProjectSharingData[]; sharedWithProjects: ProjectSharingData[];
credentialId: string; credentialId: string;
}): Promise<ICredentialsResponse> { }): Promise<ICredentialsResponse> => {
if (useSettingsStore().isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) { if (useSettingsStore().isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
await setCredentialSharedWith(useRootStore().getRestApiContext, payload.credentialId, { await credentialsEeApi.setCredentialSharedWith(
useRootStore().getRestApiContext,
payload.credentialId,
{
shareWithIds: payload.sharedWithProjects.map((project) => project.id), shareWithIds: payload.sharedWithProjects.map((project) => project.id),
}); },
);
this.credentials[payload.credentialId] = { state.value.credentials[payload.credentialId] = {
...this.credentials[payload.credentialId], ...state.value.credentials[payload.credentialId],
sharedWithProjects: payload.sharedWithProjects, sharedWithProjects: payload.sharedWithProjects,
}; };
} }
return this.credentials[payload.credentialId]; return state.value.credentials[payload.credentialId];
}, };
async getCredentialTranslation(credentialType: string): Promise<object> { const getCredentialTranslation = async (credentialType: string): Promise<object> => {
const rootStore = useRootStore(); const rootStore = useRootStore();
return await makeRestApiRequest( return await makeRestApiRequest(rootStore.getRestApiContext, 'GET', '/credential-translation', {
rootStore.getRestApiContext,
'GET',
'/credential-translation',
{
credentialType, credentialType,
}, });
); };
},
}, // #endregion
return {
getCredentialOwnerName,
getCredentialsByType,
getCredentialById,
getCredentialTypeByName,
getCredentialByIdAndType,
getNodesWithAccess,
getUsableCredentialByType,
credentialTypesById,
httpOnlyCredentialTypes,
getScopesByCredentialType,
getCredentialOwnerNameById,
allUsableCredentialsForNode,
allCredentials,
allCredentialTypes,
allUsableCredentialsByType,
setCredentialTypes,
addCredentials,
setCredentials,
deleteCredential,
upsertCredential,
fetchCredentialTypes,
fetchAllCredentials,
fetchAllCredentialsForWorkflow,
createNewCredential,
updateCredential,
getCredentialData,
oAuth1Authorize,
oAuth2Authorize,
getNewCredentialName,
testCredential,
getCredentialTranslation,
setCredentialSharedWith,
};
}); });
/** /**
@ -404,12 +472,12 @@ export const listenForCredentialChanges = (opts: {
switch (name) { switch (name) {
case 'createNewCredential': case 'createNewCredential':
const createdCredential = returnValue as ICredentialsResponse; const createdCredential = returnValue as unknown as ICredentialsResponse;
onCredentialCreated?.(createdCredential); onCredentialCreated?.(createdCredential);
break; break;
case 'updateCredential': case 'updateCredential':
const updatedCredential = returnValue as ICredentialsResponse; const updatedCredential = returnValue as unknown as ICredentialsResponse;
onCredentialUpdated?.(updatedCredential); onCredentialUpdated?.(updatedCredential);
break; break;