mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Romain Minaud <romain.minaud@gmail.com> Co-authored-by: Valya Bullions <valya@n8n.io> Co-authored-by: Csaba Tuncsik <csaba@n8n.io> Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Omar Ajoue <krynble@gmail.com>
186 lines
4.6 KiB
Vue
186 lines
4.6 KiB
Vue
<script lang="ts" setup>
|
|
import type { PropType, Ref } from 'vue';
|
|
import type { ExternalSecretsProvider } from '@/Interface';
|
|
import ExternalSecretsProviderImage from '@/components/ExternalSecretsProviderImage.ee.vue';
|
|
import ExternalSecretsProviderConnectionSwitch from '@/components/ExternalSecretsProviderConnectionSwitch.ee.vue';
|
|
import { useExternalSecretsStore, useUIStore } from '@/stores';
|
|
import { useExternalSecretsProvider, useI18n, useToast } from '@/composables';
|
|
import { EXTERNAL_SECRETS_PROVIDER_MODAL_KEY } from '@/constants';
|
|
import { DateTime } from 'luxon';
|
|
import { computed, nextTick, onMounted, toRefs } from 'vue';
|
|
|
|
const props = defineProps({
|
|
provider: {
|
|
type: Object as PropType<ExternalSecretsProvider>,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const externalSecretsStore = useExternalSecretsStore();
|
|
const i18n = useI18n();
|
|
const uiStore = useUIStore();
|
|
const toast = useToast();
|
|
|
|
const { provider } = toRefs(props) as Ref<ExternalSecretsProvider>;
|
|
const providerData = computed(() => provider.value.data);
|
|
const {
|
|
connectionState,
|
|
initialConnectionState,
|
|
normalizedProviderData,
|
|
testConnection,
|
|
setConnectionState,
|
|
} = useExternalSecretsProvider(provider, providerData);
|
|
|
|
const actionDropdownOptions = computed(() => [
|
|
{
|
|
value: 'setup',
|
|
label: i18n.baseText('settings.externalSecrets.card.actionDropdown.setup'),
|
|
},
|
|
...(props.provider.connected
|
|
? [
|
|
{
|
|
value: 'reload',
|
|
label: i18n.baseText('settings.externalSecrets.card.actionDropdown.reload'),
|
|
},
|
|
]
|
|
: []),
|
|
]);
|
|
|
|
const canConnect = computed(() => {
|
|
return props.provider.connected || Object.keys(props.provider.data).length > 0;
|
|
});
|
|
|
|
const formattedDate = computed((provider: ExternalSecretsProvider) => {
|
|
return DateTime.fromISO(props.provider.connectedAt!).toFormat('dd LLL yyyy');
|
|
});
|
|
|
|
onMounted(() => {
|
|
setConnectionState(props.provider.state);
|
|
});
|
|
|
|
async function onBeforeConnectionUpdate() {
|
|
if (props.provider.connected) {
|
|
return true;
|
|
}
|
|
|
|
await externalSecretsStore.getProvider(props.provider.name);
|
|
await nextTick();
|
|
const status = await testConnection();
|
|
|
|
return status !== 'error';
|
|
}
|
|
|
|
function openExternalSecretProvider() {
|
|
uiStore.openModalWithData({
|
|
name: EXTERNAL_SECRETS_PROVIDER_MODAL_KEY,
|
|
data: { name: props.provider.name },
|
|
});
|
|
}
|
|
|
|
async function reloadProvider() {
|
|
try {
|
|
await externalSecretsStore.reloadProvider(props.provider.name);
|
|
toast.showMessage({
|
|
title: i18n.baseText('settings.externalSecrets.card.reload.success.title'),
|
|
message: i18n.baseText('settings.externalSecrets.card.reload.success.description', {
|
|
interpolate: { provider: props.provider.displayName },
|
|
}),
|
|
type: 'success',
|
|
});
|
|
} catch (error) {
|
|
toast.showError(error, i18n.baseText('error'));
|
|
}
|
|
}
|
|
|
|
async function onActionDropdownClick(id: string) {
|
|
switch (id) {
|
|
case 'setup':
|
|
openExternalSecretProvider();
|
|
break;
|
|
case 'reload':
|
|
await reloadProvider();
|
|
break;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<n8n-card :class="$style.card">
|
|
<div :class="$style.cardBody">
|
|
<ExternalSecretsProviderImage :class="$style.cardImage" :provider="provider" />
|
|
<div :class="$style.cardContent">
|
|
<n8n-text bold>{{ provider.displayName }}</n8n-text>
|
|
<n8n-text color="text-light" size="small" v-if="provider.connected">
|
|
<span>
|
|
{{
|
|
i18n.baseText('settings.externalSecrets.card.secretsCount', {
|
|
interpolate: {
|
|
count: `${externalSecretsStore.secrets[provider.name]?.length}`,
|
|
},
|
|
})
|
|
}}
|
|
</span>
|
|
|
|
|
<span>
|
|
{{
|
|
i18n.baseText('settings.externalSecrets.card.connectedAt', {
|
|
interpolate: {
|
|
date: formattedDate,
|
|
},
|
|
})
|
|
}}
|
|
</span>
|
|
</n8n-text>
|
|
</div>
|
|
<div :class="$style.cardActions" v-if="canConnect">
|
|
<ExternalSecretsProviderConnectionSwitch
|
|
:provider="provider"
|
|
:beforeUpdate="onBeforeConnectionUpdate"
|
|
:disabled="connectionState === 'error' && !provider.connected"
|
|
/>
|
|
<n8n-action-toggle
|
|
class="ml-s"
|
|
theme="dark"
|
|
:actions="actionDropdownOptions"
|
|
@action="onActionDropdownClick"
|
|
/>
|
|
</div>
|
|
<n8n-button v-else type="tertiary" @click="openExternalSecretProvider()">
|
|
{{ i18n.baseText('settings.externalSecrets.card.setUp') }}
|
|
</n8n-button>
|
|
</div>
|
|
</n8n-card>
|
|
</template>
|
|
|
|
<style lang="scss" module>
|
|
.card {
|
|
position: relative;
|
|
margin-bottom: var(--spacing-2xs);
|
|
}
|
|
|
|
.cardImage {
|
|
width: 28px;
|
|
height: 28px;
|
|
}
|
|
|
|
.cardBody {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
|
|
.cardContent {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
margin-left: var(--spacing-s);
|
|
}
|
|
|
|
.cardActions {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
margin-left: var(--spacing-s);
|
|
}
|
|
</style>
|