n8n/packages/editor-ui/src/components/CredentialPicker/CredentialPicker.vue
2024-06-18 09:55:10 +02:00

145 lines
3.6 KiB
Vue

<script setup lang="ts">
import { computed, ref } from 'vue';
import { listenForModalChanges, useUIStore } from '@/stores/ui.store';
import { listenForCredentialChanges, useCredentialsStore } from '@/stores/credentials.store';
import { assert } from '@/utils/assert';
import CredentialsDropdown from './CredentialsDropdown.vue';
import { useI18n } from '@/composables/useI18n';
import { CREDENTIAL_EDIT_MODAL_KEY } from '@/constants';
const props = defineProps<{
appName: string;
credentialType: string;
selectedCredentialId: string | null;
}>();
const $emit = defineEmits({
credentialSelected: (_credentialId: string) => true,
credentialDeselected: () => true,
credentialModalOpened: () => true,
});
const uiStore = useUIStore();
const credentialsStore = useCredentialsStore();
const i18n = useI18n();
const wasModalOpenedFromHere = ref(false);
const availableCredentials = computed(() => {
return credentialsStore.getCredentialsByType(props.credentialType);
});
const credentialOptions = computed(() => {
return availableCredentials.value.map((credential) => ({
id: credential.id,
name: credential.name,
typeDisplayName: credentialsStore.getCredentialTypeByName(credential.type)?.displayName,
}));
});
const onCredentialSelected = (credentialId: string) => {
$emit('credentialSelected', credentialId);
};
const createNewCredential = () => {
uiStore.openNewCredential(props.credentialType, true);
wasModalOpenedFromHere.value = true;
$emit('credentialModalOpened');
};
const editCredential = () => {
assert(props.selectedCredentialId);
uiStore.openExistingCredential(props.selectedCredentialId);
wasModalOpenedFromHere.value = true;
$emit('credentialModalOpened');
};
listenForCredentialChanges({
store: credentialsStore,
onCredentialCreated: (credential) => {
if (!wasModalOpenedFromHere.value) {
return;
}
$emit('credentialSelected', credential.id);
},
onCredentialDeleted: (deletedCredentialId) => {
if (!wasModalOpenedFromHere.value) {
return;
}
if (deletedCredentialId !== props.selectedCredentialId) {
return;
}
const optionsWoDeleted = credentialOptions.value
.map((credential) => credential.id)
.filter((id) => id !== deletedCredentialId);
if (optionsWoDeleted.length > 0) {
$emit('credentialSelected', optionsWoDeleted[0]);
} else {
$emit('credentialDeselected');
}
},
});
listenForModalChanges({
store: uiStore,
onModalClosed(modalName) {
if (modalName === CREDENTIAL_EDIT_MODAL_KEY && wasModalOpenedFromHere.value) {
wasModalOpenedFromHere.value = false;
}
},
});
</script>
<template>
<div>
<div v-if="credentialOptions.length > 0" :class="$style.dropdown">
<CredentialsDropdown
:credential-type="props.credentialType"
:credential-options="credentialOptions"
:selected-credential-id="props.selectedCredentialId"
@credential-selected="onCredentialSelected"
@new-credential="createNewCredential"
/>
<n8n-icon-button
icon="pen"
type="secondary"
:class="{
[$style.edit]: true,
[$style.invisible]: !props.selectedCredentialId,
}"
:title="i18n.baseText('nodeCredentials.updateCredential')"
data-test-id="credential-edit-button"
@click="editCredential()"
/>
</div>
<n8n-button
v-else
:label="`Create new ${props.appName} credential`"
data-test-id="create-credential"
@click="createNewCredential"
/>
</div>
</template>
<style lang="scss" module>
.dropdown {
display: flex;
}
.edit {
display: flex;
justify-content: center;
align-items: center;
min-width: 20px;
margin-left: var(--spacing-2xs);
font-size: var(--font-size-s);
}
.invisible {
visibility: hidden;
}
</style>