2019-06-23 03:35:23 -07:00
|
|
|
<template>
|
|
|
|
<div v-if="credentialTypesNodeDescriptionDisplayed.length" class="node-credentials">
|
|
|
|
<div class="headline">
|
|
|
|
Credentials
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-for="credentialTypeDescription in credentialTypesNodeDescriptionDisplayed" :key="credentialTypeDescription.name" class="credential-data">
|
2021-09-11 01:15:36 -07:00
|
|
|
<el-row class="credential-parameter-wrapper">
|
2019-06-23 03:35:23 -07:00
|
|
|
<el-col :span="10" class="parameter-name">
|
|
|
|
{{credentialTypeNames[credentialTypeDescription.name]}}:
|
|
|
|
</el-col>
|
|
|
|
<el-col :span="12" class="parameter-value" :class="getIssues(credentialTypeDescription.name).length?'has-issues':''">
|
2021-08-29 04:36:17 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
<div :style="credentialInputWrapperStyle(credentialTypeDescription.name)">
|
2021-09-11 01:15:36 -07:00
|
|
|
<n8n-select :value="selected[credentialTypeDescription.name]" :disabled="isReadOnly" @change="(value) => credentialSelected(credentialTypeDescription.name, value)" placeholder="Select Credential" size="small">
|
2021-08-29 04:36:17 -07:00
|
|
|
<n8n-option
|
2021-09-11 01:15:36 -07:00
|
|
|
v-for="(item) in credentialOptions[credentialTypeDescription.name]"
|
|
|
|
:key="item.id"
|
2019-06-23 03:35:23 -07:00
|
|
|
:label="item.name"
|
|
|
|
:value="item.name">
|
2021-08-29 04:36:17 -07:00
|
|
|
</n8n-option>
|
2021-09-11 01:15:36 -07:00
|
|
|
<n8n-option
|
|
|
|
:key="NEW_CREDENTIALS_TEXT"
|
|
|
|
:value="NEW_CREDENTIALS_TEXT"
|
|
|
|
:label="NEW_CREDENTIALS_TEXT"
|
|
|
|
>
|
|
|
|
</n8n-option>
|
2021-08-29 04:36:17 -07:00
|
|
|
</n8n-select>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="credential-issues">
|
|
|
|
<n8n-tooltip placement="top" >
|
|
|
|
<div slot="content" v-html="'Issues:<br /> - ' + getIssues(credentialTypeDescription.name).join('<br /> - ')"></div>
|
|
|
|
<font-awesome-icon icon="exclamation-triangle" />
|
|
|
|
</n8n-tooltip>
|
2019-06-23 03:35:23 -07:00
|
|
|
</div>
|
2021-08-29 04:36:17 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
</el-col>
|
2021-08-29 04:36:17 -07:00
|
|
|
<el-col :span="2" class="parameter-value credential-action">
|
2021-09-11 01:15:36 -07:00
|
|
|
<font-awesome-icon v-if="selected[credentialTypeDescription.name] && isCredentialValid(credentialTypeDescription.name)" icon="pen" @click="editCredential(credentialTypeDescription.name)" class="update-credentials clickable" title="Update Credentials" />
|
2019-06-23 03:35:23 -07:00
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import { restApi } from '@/components/mixins/restApi';
|
|
|
|
import {
|
|
|
|
INodeUi,
|
|
|
|
INodeUpdatePropertiesInformation,
|
|
|
|
} from '@/Interface';
|
|
|
|
import {
|
|
|
|
ICredentialType,
|
|
|
|
INodeCredentialDescription,
|
|
|
|
INodeTypeDescription,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
|
|
|
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
|
|
|
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
|
|
|
import { showMessage } from '@/components/mixins/showMessage';
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
import { mapGetters } from "vuex";
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
import mixins from 'vue-typed-mixins';
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
const NEW_CREDENTIALS_TEXT = '- Create New -';
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
export default mixins(
|
|
|
|
genericHelpers,
|
|
|
|
nodeHelpers,
|
|
|
|
restApi,
|
|
|
|
showMessage,
|
|
|
|
).extend({
|
|
|
|
name: 'NodeCredentials',
|
|
|
|
props: [
|
|
|
|
'node', // INodeUi
|
|
|
|
],
|
2021-09-11 01:15:36 -07:00
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
NEW_CREDENTIALS_TEXT,
|
|
|
|
newCredentialUnsubscribe: null as null | (() => void),
|
|
|
|
};
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
computed: {
|
2021-09-11 01:15:36 -07:00
|
|
|
...mapGetters('credentials', {
|
|
|
|
credentialOptions: 'allCredentialsByType',
|
|
|
|
}),
|
2019-06-23 03:35:23 -07:00
|
|
|
credentialTypesNode (): string[] {
|
|
|
|
return this.credentialTypesNodeDescription
|
|
|
|
.map((credentialTypeDescription) => credentialTypeDescription.name);
|
|
|
|
},
|
|
|
|
credentialTypesNodeDescriptionDisplayed (): INodeCredentialDescription[] {
|
|
|
|
return this.credentialTypesNodeDescription
|
|
|
|
.filter((credentialTypeDescription) => {
|
|
|
|
return this.displayCredentials(credentialTypeDescription);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
credentialTypesNodeDescription (): INodeCredentialDescription[] {
|
|
|
|
const node = this.node as INodeUi;
|
|
|
|
|
|
|
|
const activeNodeType = this.$store.getters.nodeType(node.type) as INodeTypeDescription;
|
|
|
|
if (activeNodeType && activeNodeType.credentials) {
|
|
|
|
return activeNodeType.credentials;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
},
|
|
|
|
credentialTypeNames () {
|
|
|
|
const returnData: {
|
|
|
|
[key: string]: string;
|
|
|
|
} = {};
|
|
|
|
let credentialType: ICredentialType | null;
|
|
|
|
for (const credentialTypeName of this.credentialTypesNode) {
|
2021-09-11 01:15:36 -07:00
|
|
|
credentialType = this.$store.getters['credentials/getCredentialTypeByName'](credentialTypeName);
|
2019-06-23 03:35:23 -07:00
|
|
|
returnData[credentialTypeName] = credentialType !== null ? credentialType.displayName : credentialTypeName;
|
|
|
|
}
|
|
|
|
return returnData;
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
selected(): {[type: string]: string} {
|
|
|
|
return this.node.credentials || {};
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
credentialInputWrapperStyle (credentialType: string) {
|
|
|
|
let deductWidth = 0;
|
|
|
|
const styles = {
|
|
|
|
width: '100%',
|
|
|
|
};
|
|
|
|
if (this.getIssues(credentialType).length) {
|
|
|
|
deductWidth += 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (deductWidth !== 0) {
|
|
|
|
styles.width = `calc(100% - ${deductWidth}px)`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return styles;
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
|
|
|
|
listenForNewCredentials(credentialType: string) {
|
|
|
|
this.stopListeningForNewCredentials();
|
|
|
|
|
|
|
|
this.newCredentialUnsubscribe = this.$store.subscribe((mutation, state) => {
|
|
|
|
if (mutation.type === 'credentials/upsertCredential' || mutation.type === 'credentials/enableOAuthCredential'){
|
|
|
|
this.credentialSelected(credentialType, mutation.payload.name);
|
|
|
|
}
|
|
|
|
if (mutation.type === 'credentials/deleteCredential') {
|
|
|
|
this.credentialSelected(credentialType, mutation.payload.name);
|
|
|
|
this.stopListeningForNewCredentials();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
stopListeningForNewCredentials() {
|
|
|
|
if (this.newCredentialUnsubscribe) {
|
|
|
|
this.newCredentialUnsubscribe();
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
credentialSelected (credentialType: string, credentialName: string) {
|
|
|
|
let selected = undefined;
|
|
|
|
if (credentialName === NEW_CREDENTIALS_TEXT) {
|
|
|
|
this.listenForNewCredentials(credentialType);
|
|
|
|
this.$store.dispatch('ui/openNewCredential', { type: credentialType });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
selected = credentialName;
|
|
|
|
}
|
|
|
|
|
|
|
|
const node: INodeUi = this.node;
|
|
|
|
|
|
|
|
const credentials = {
|
|
|
|
...(node.credentials || {}),
|
|
|
|
[credentialType]: selected,
|
|
|
|
};
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
const updateInformation: INodeUpdatePropertiesInformation = {
|
2021-09-11 01:15:36 -07:00
|
|
|
name: this.node.name,
|
2019-06-23 03:35:23 -07:00
|
|
|
properties: {
|
2021-09-11 01:15:36 -07:00
|
|
|
credentials,
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
this.$emit('credentialSelected', updateInformation);
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
displayCredentials (credentialTypeDescription: INodeCredentialDescription): boolean {
|
|
|
|
if (credentialTypeDescription.displayOptions === undefined) {
|
|
|
|
// If it is not defined no need to do a proper check
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return this.displayParameter(this.node.parameters, credentialTypeDescription, '');
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
getIssues (credentialTypeName: string): string[] {
|
|
|
|
const node = this.node as INodeUi;
|
|
|
|
|
|
|
|
if (node.issues === undefined || node.issues.credentials === undefined) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node.issues.credentials.hasOwnProperty(credentialTypeName)) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return node.issues.credentials[credentialTypeName];
|
|
|
|
},
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
isCredentialValid(credentialType: string): boolean {
|
|
|
|
const name = this.node.credentials[credentialType];
|
|
|
|
const options = this.credentialOptions[credentialType];
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
return options.find((option: ICredentialType) => option.name === name);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
editCredential(credentialType: string): void {
|
|
|
|
const name = this.node.credentials[credentialType];
|
|
|
|
const options = this.credentialOptions[credentialType];
|
|
|
|
const selected = options.find((option: ICredentialType) => option.name === name);
|
|
|
|
this.$store.dispatch('ui/openExisitngCredential', { id: selected.id });
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
this.listenForNewCredentials(credentialType);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
beforeDestroy () {
|
|
|
|
this.stopListeningForNewCredentials();
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
|
|
|
.node-credentials {
|
|
|
|
padding-bottom: 1em;
|
|
|
|
margin: 0.5em;
|
|
|
|
border-bottom: 1px solid #ccc;
|
|
|
|
|
|
|
|
.credential-issues {
|
|
|
|
display: none;
|
|
|
|
width: 20px;
|
|
|
|
text-align: right;
|
|
|
|
float: right;
|
|
|
|
color: #ff8080;
|
|
|
|
font-size: 1.2em;
|
|
|
|
margin-top: 3px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.credential-data + .credential-data {
|
|
|
|
margin-top: 1em;
|
|
|
|
}
|
|
|
|
|
|
|
|
.has-issues {
|
|
|
|
.credential-issues {
|
|
|
|
display: inline-block;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.headline {
|
|
|
|
font-weight: bold;
|
|
|
|
margin-bottom: 0.7em;
|
|
|
|
}
|
|
|
|
|
2021-08-29 04:36:17 -07:00
|
|
|
.credential-parameter-wrapper {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
.parameter-name {
|
|
|
|
font-weight: 400;
|
|
|
|
}
|
|
|
|
|
2021-08-29 04:36:17 -07:00
|
|
|
.parameter-value {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.credential-action {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
2021-09-11 01:15:36 -07:00
|
|
|
color: var(--color-text-base);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|