refactor(editor): CredentialsView.vue to script setup (#11094)

This commit is contained in:
Raúl Gómez Morales 2024-10-04 14:04:15 +02:00 committed by GitHub
parent cb4294b9f4
commit cd6edeae17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,154 +1,138 @@
<script lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { ICredentialsResponse, ICredentialTypeMap } from '@/Interface'; import type { ICredentialsResponse, ICredentialTypeMap } from '@/Interface';
import { defineComponent } from 'vue';
import type { IResource } from '@/components/layouts/ResourcesListLayout.vue'; import type { IResource } from '@/components/layouts/ResourcesListLayout.vue';
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue'; import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
import CredentialCard from '@/components/CredentialCard.vue'; import CredentialCard from '@/components/CredentialCard.vue';
import type { ICredentialType } from 'n8n-workflow'; import type { ICredentialType } from 'n8n-workflow';
import { CREDENTIAL_SELECT_MODAL_KEY, EnterpriseEditionFeature } from '@/constants'; import { CREDENTIAL_SELECT_MODAL_KEY, EnterpriseEditionFeature } from '@/constants';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useCredentialsStore } from '@/stores/credentials.store'; import { useCredentialsStore } from '@/stores/credentials.store';
import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store'; import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store';
import { useSourceControlStore } from '@/stores/sourceControl.store'; import { useSourceControlStore } from '@/stores/sourceControl.store';
import { useProjectsStore } from '@/stores/projects.store'; import { useProjectsStore } from '@/stores/projects.store';
import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
import useEnvironmentsStore from '@/stores/environments.ee.store'; import useEnvironmentsStore from '@/stores/environments.ee.store';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
import { getResourcePermissions } from '@/permissions'; import { getResourcePermissions } from '@/permissions';
import { useDocumentTitle } from '@/composables/useDocumentTitle'; import { useDocumentTitle } from '@/composables/useDocumentTitle';
import { useTelemetry } from '@/composables/useTelemetry';
import { useI18n } from '@/composables/useI18n';
import { N8nButton, N8nInputLabel, N8nSelect, N8nOption } from 'n8n-design-system';
export default defineComponent({ const credentialsStore = useCredentialsStore();
name: 'CredentialsView', const nodeTypesStore = useNodeTypesStore();
components: { const uiStore = useUIStore();
ResourcesListLayout, const sourceControlStore = useSourceControlStore();
CredentialCard, const externalSecretsStore = useExternalSecretsStore();
ProjectTabs, const projectsStore = useProjectsStore();
},
data() {
return {
filters: {
search: '',
homeProject: '',
type: '',
},
sourceControlStoreUnsubscribe: () => {},
loading: false,
documentTitle: useDocumentTitle(),
};
},
computed: {
...mapStores(
useCredentialsStore,
useNodeTypesStore,
useUIStore,
useSourceControlStore,
useExternalSecretsStore,
useProjectsStore,
),
allCredentials(): IResource[] {
return this.credentialsStore.allCredentials.map((credential) => ({
id: credential.id,
name: credential.name,
value: '',
updatedAt: credential.updatedAt,
createdAt: credential.createdAt,
homeProject: credential.homeProject,
scopes: credential.scopes,
type: credential.type,
sharedWithProjects: credential.sharedWithProjects,
readOnly: !getResourcePermissions(credential.scopes).credential.update,
}));
},
allCredentialTypes(): ICredentialType[] {
return this.credentialsStore.allCredentialTypes;
},
credentialTypesById(): ICredentialTypeMap {
return this.credentialsStore.credentialTypesById;
},
addCredentialButtonText() {
return this.projectsStore.currentProject
? this.$locale.baseText('credentials.project.add')
: this.$locale.baseText('credentials.add');
},
readOnlyEnv(): boolean {
return this.sourceControlStore.preferences.branchReadOnly;
},
projectPermissions() {
return getResourcePermissions(
this.projectsStore.currentProject?.scopes ?? this.projectsStore.personalProject?.scopes,
);
},
},
watch: {
'$route.params.projectId'() {
void this.initialize();
},
},
mounted() {
this.documentTitle.set(this.$locale.baseText('credentials.heading'));
this.sourceControlStoreUnsubscribe = this.sourceControlStore.$onAction(({ name, after }) => {
if (name === 'pullWorkfolder' && after) {
after(() => {
void this.initialize();
});
}
});
},
beforeUnmount() {
this.sourceControlStoreUnsubscribe();
},
methods: {
addCredential() {
this.uiStore.openModal(CREDENTIAL_SELECT_MODAL_KEY);
this.$telemetry.track('User clicked add cred button', { const documentTitle = useDocumentTitle();
source: 'Creds list', const route = useRoute();
}); const telemetry = useTelemetry();
}, const i18n = useI18n();
async initialize() {
this.loading = true;
const isVarsEnabled =
useSettingsStore().isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables];
const loadPromises = [ const filters = ref({
this.credentialsStore.fetchAllCredentials( search: '',
this.$route?.params?.projectId as string | undefined, homeProject: '',
), type: '',
this.credentialsStore.fetchCredentialTypes(false), });
this.externalSecretsStore.fetchAllSecrets(),
this.nodeTypesStore.loadNodeTypesIfNotLoaded(),
isVarsEnabled ? useEnvironmentsStore().fetchAllVariables() : Promise.resolve(), // for expression resolution
];
await Promise.all(loadPromises); const loading = ref(false);
this.loading = false;
},
onFilter(
resource: ICredentialsResponse,
filters: { type: string[]; search: string },
matches: boolean,
): boolean {
if (filters.type.length > 0) {
matches = matches && filters.type.includes(resource.type);
}
if (filters.search) { const allCredentials = computed<IResource[]>(() =>
const searchString = filters.search.toLowerCase(); credentialsStore.allCredentials.map((credential) => ({
id: credential.id,
name: credential.name,
value: '',
updatedAt: credential.updatedAt,
createdAt: credential.createdAt,
homeProject: credential.homeProject,
scopes: credential.scopes,
type: credential.type,
sharedWithProjects: credential.sharedWithProjects,
readOnly: !getResourcePermissions(credential.scopes).credential.update,
})),
);
matches = const allCredentialTypes = computed<ICredentialType[]>(() => credentialsStore.allCredentialTypes);
matches ||
(this.credentialTypesById[resource.type] &&
this.credentialTypesById[resource.type].displayName
.toLowerCase()
.includes(searchString));
}
return matches; const credentialTypesById = computed<ICredentialTypeMap>(
}, () => credentialsStore.credentialTypesById,
}, );
const addCredentialButtonText = computed(() =>
projectsStore.currentProject
? i18n.baseText('credentials.project.add')
: i18n.baseText('credentials.add'),
);
const readOnlyEnv = computed(() => sourceControlStore.preferences.branchReadOnly);
const projectPermissions = computed(() =>
getResourcePermissions(
projectsStore.currentProject?.scopes ?? projectsStore.personalProject?.scopes,
),
);
const addCredential = () => {
uiStore.openModal(CREDENTIAL_SELECT_MODAL_KEY);
telemetry.track('User clicked add cred button', {
source: 'Creds list',
});
};
const onFilter = (
resource: ICredentialsResponse,
filtersToApply: { type: string[]; search: string },
matches: boolean,
): boolean => {
if (filtersToApply.type.length > 0) {
matches = matches && filtersToApply.type.includes(resource.type);
}
if (filtersToApply.search) {
const searchString = filtersToApply.search.toLowerCase();
matches =
matches ||
(credentialTypesById.value[resource.type] &&
credentialTypesById.value[resource.type].displayName.toLowerCase().includes(searchString));
}
return matches;
};
const initialize = async () => {
loading.value = true;
const isVarsEnabled =
useSettingsStore().isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables];
const loadPromises = [
credentialsStore.fetchAllCredentials(route?.params?.projectId as string | undefined),
credentialsStore.fetchCredentialTypes(false),
externalSecretsStore.fetchAllSecrets(),
nodeTypesStore.loadNodeTypesIfNotLoaded(),
isVarsEnabled ? useEnvironmentsStore().fetchAllVariables() : Promise.resolve(), // for expression resolution
];
await Promise.all(loadPromises);
loading.value = false;
};
sourceControlStore.$onAction(({ name, after }) => {
if (name !== 'pullWorkfolder') return;
after(() => {
void initialize();
});
});
watch(() => route?.params?.projectId, initialize);
onMounted(() => {
documentTitle.set(i18n.baseText('credentials.heading'));
}); });
</script> </script>
@ -171,7 +155,7 @@ export default defineComponent({
</template> </template>
<template #add-button="{ disabled }"> <template #add-button="{ disabled }">
<div> <div>
<n8n-button <N8nButton
size="large" size="large"
block block
:disabled="disabled" :disabled="disabled"
@ -179,7 +163,7 @@ export default defineComponent({
@click="addCredential" @click="addCredential"
> >
{{ addCredentialButtonText }} {{ addCredentialButtonText }}
</n8n-button> </N8nButton>
</div> </div>
</template> </template>
<template #default="{ data }"> <template #default="{ data }">
@ -192,14 +176,14 @@ export default defineComponent({
</template> </template>
<template #filters="{ setKeyValue }"> <template #filters="{ setKeyValue }">
<div class="mb-s"> <div class="mb-s">
<n8n-input-label <N8nInputLabel
:label="$locale.baseText('credentials.filters.type')" :label="i18n.baseText('credentials.filters.type')"
:bold="false" :bold="false"
size="small" size="small"
color="text-base" color="text-base"
class="mb-3xs" class="mb-3xs"
/> />
<n8n-select <N8nSelect
ref="typeInput" ref="typeInput"
:model-value="filters.type" :model-value="filters.type"
size="medium" size="medium"
@ -208,13 +192,13 @@ export default defineComponent({
:class="$style['type-input']" :class="$style['type-input']"
@update:model-value="setKeyValue('type', $event)" @update:model-value="setKeyValue('type', $event)"
> >
<n8n-option <N8nOption
v-for="credentialType in allCredentialTypes" v-for="credentialType in allCredentialTypes"
:key="credentialType.name" :key="credentialType.name"
:value="credentialType.name" :value="credentialType.name"
:label="credentialType.displayName" :label="credentialType.displayName"
/> />
</n8n-select> </N8nSelect>
</div> </div>
</template> </template>
</ResourcesListLayout> </ResourcesListLayout>