mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(editor): CredentialsView.vue to script setup (#11094)
This commit is contained in:
parent
cb4294b9f4
commit
cd6edeae17
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue