2021-09-11 01:15:36 -07:00
|
|
|
<template>
|
|
|
|
<Modal
|
|
|
|
:name="modalName"
|
|
|
|
:customClass="$style.credentialModal"
|
|
|
|
:eventBus="modalBus"
|
|
|
|
:loading="loading"
|
|
|
|
:beforeClose="beforeClose"
|
2021-09-22 00:23:37 -07:00
|
|
|
width="70%"
|
|
|
|
height="80%"
|
2021-09-11 01:15:36 -07:00
|
|
|
>
|
|
|
|
<template slot="header">
|
2022-09-21 01:20:29 -07:00
|
|
|
<div :class="$style.header">
|
2021-09-11 01:15:36 -07:00
|
|
|
<div :class="$style.credInfo">
|
|
|
|
<div :class="$style.credIcon">
|
|
|
|
<CredentialIcon :credentialTypeName="credentialTypeName" />
|
|
|
|
</div>
|
|
|
|
<InlineNameEdit
|
|
|
|
:name="credentialName"
|
2022-09-21 01:20:29 -07:00
|
|
|
:subtitle="credentialType ? credentialType.displayName : ''"
|
|
|
|
:readonly="!credentialPermissions.updateName"
|
2021-09-11 01:15:36 -07:00
|
|
|
type="Credential"
|
|
|
|
@input="onNameEdit"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div :class="$style.credActions">
|
|
|
|
<n8n-icon-button
|
2022-09-21 01:20:29 -07:00
|
|
|
v-if="currentCredential && credentialPermissions.delete"
|
2021-12-15 04:16:53 -08:00
|
|
|
:title="$locale.baseText('credentialEdit.credentialEdit.delete')"
|
2021-09-11 01:15:36 -07:00
|
|
|
icon="trash"
|
2022-07-20 08:50:39 -07:00
|
|
|
size="medium"
|
|
|
|
type="tertiary"
|
2021-09-11 01:15:36 -07:00
|
|
|
:disabled="isSaving"
|
|
|
|
:loading="isDeleting"
|
|
|
|
@click="deleteCredential"
|
|
|
|
/>
|
|
|
|
<SaveButton
|
2022-09-21 01:20:29 -07:00
|
|
|
v-if="(hasUnsavedChanges || credentialId) && credentialPermissions.save"
|
2021-09-11 01:15:36 -07:00
|
|
|
:saved="!hasUnsavedChanges && !isTesting"
|
|
|
|
:isSaving="isSaving || isTesting"
|
2021-12-07 06:58:26 -08:00
|
|
|
:savingLabel="isTesting
|
2021-12-15 04:16:53 -08:00
|
|
|
? $locale.baseText('credentialEdit.credentialEdit.testing')
|
|
|
|
: $locale.baseText('credentialEdit.credentialEdit.saving')"
|
2021-09-11 01:15:36 -07:00
|
|
|
@click="saveCredential"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<hr />
|
|
|
|
</template>
|
|
|
|
<template slot="content">
|
|
|
|
<div :class="$style.container">
|
|
|
|
<div :class="$style.sidebar">
|
|
|
|
<n8n-menu
|
|
|
|
type="secondary"
|
|
|
|
@select="onTabSelect"
|
|
|
|
defaultActive="connection"
|
|
|
|
:light="true"
|
|
|
|
>
|
2022-09-21 01:20:29 -07:00
|
|
|
<n8n-menu-item index="connection">
|
|
|
|
<span slot="title">{{ $locale.baseText('credentialEdit.credentialEdit.connection') }}</span>
|
|
|
|
</n8n-menu-item>
|
|
|
|
<enterprise-edition v-if="credentialType" :features="[EnterpriseEditionFeature.Sharing]">
|
|
|
|
<n8n-menu-item index="sharing">
|
|
|
|
<span slot="title">{{ $locale.baseText('credentialEdit.credentialEdit.sharing') }}</span>
|
|
|
|
</n8n-menu-item>
|
|
|
|
<template #fallback>
|
|
|
|
<n8n-menu-item
|
|
|
|
v-for="fakeDoor in credentialsFakeDoorFeatures"
|
|
|
|
v-bind:key="fakeDoor.featureName"
|
|
|
|
:index="`coming-soon/${fakeDoor.id}`"
|
|
|
|
:class="$style.tab"
|
|
|
|
>
|
|
|
|
<span slot="title">{{ $locale.baseText(fakeDoor.featureName) }}</span>
|
|
|
|
</n8n-menu-item>
|
|
|
|
</template>
|
|
|
|
</enterprise-edition>
|
|
|
|
<n8n-menu-item v-if="credentialType" index="details">
|
|
|
|
<span slot="title">{{ $locale.baseText('credentialEdit.credentialEdit.details') }}</span>
|
2022-07-27 07:28:13 -07:00
|
|
|
</n8n-menu-item>
|
2021-09-11 01:15:36 -07:00
|
|
|
</n8n-menu>
|
|
|
|
</div>
|
|
|
|
<div v-if="activeTab === 'connection'" :class="$style.mainContent" ref="content">
|
|
|
|
<CredentialConfig
|
|
|
|
:credentialType="credentialType"
|
|
|
|
:credentialProperties="credentialProperties"
|
|
|
|
:credentialData="credentialData"
|
2022-09-21 01:20:29 -07:00
|
|
|
:credentialId="credentialId"
|
2021-09-11 01:15:36 -07:00
|
|
|
:showValidationWarning="showValidationWarning"
|
|
|
|
:authError="authError"
|
|
|
|
:testedSuccessfully="testedSuccessfully"
|
|
|
|
:isOAuthType="isOAuthType"
|
|
|
|
:isOAuthConnected="isOAuthConnected"
|
|
|
|
:isRetesting="isRetesting"
|
|
|
|
:parentTypes="parentTypes"
|
|
|
|
:requiredPropertiesFilled="requiredPropertiesFilled"
|
2022-09-21 01:20:29 -07:00
|
|
|
:credentialPermissions="credentialPermissions"
|
2021-09-11 01:15:36 -07:00
|
|
|
@change="onDataChange"
|
|
|
|
@oauth="oAuthCredentialAuthorize"
|
|
|
|
@retest="retestCredential"
|
|
|
|
@scrollToTop="scrollToTop"
|
|
|
|
/>
|
|
|
|
</div>
|
2022-09-21 01:20:29 -07:00
|
|
|
<enterprise-edition
|
|
|
|
v-else-if="activeTab === 'sharing' && credentialType"
|
|
|
|
:class="$style.mainContent"
|
|
|
|
:features="[EnterpriseEditionFeature.Sharing]"
|
|
|
|
>
|
|
|
|
<CredentialSharing
|
|
|
|
:credential="currentCredential"
|
|
|
|
:credentialData="credentialData"
|
|
|
|
:credentialId="credentialId"
|
|
|
|
:credentialPermissions="credentialPermissions"
|
|
|
|
@change="onChangeSharedWith"
|
|
|
|
/>
|
|
|
|
</enterprise-edition>
|
|
|
|
<div v-else-if="activeTab === 'details' && credentialType" :class="$style.mainContent">
|
2021-09-11 01:15:36 -07:00
|
|
|
<CredentialInfo
|
|
|
|
:nodeAccess="nodeAccess"
|
|
|
|
:nodesWithAccess="nodesWithAccess"
|
|
|
|
:currentCredential="currentCredential"
|
2022-09-21 01:20:29 -07:00
|
|
|
:credentialPermissions="credentialPermissions"
|
2021-09-11 01:15:36 -07:00
|
|
|
@accessChange="onNodeAccessChange"
|
|
|
|
/>
|
|
|
|
</div>
|
2022-09-21 01:20:29 -07:00
|
|
|
<div v-else-if="activeTab.startsWith('coming-soon')" :class="$style.mainContent">
|
2022-07-27 07:28:13 -07:00
|
|
|
<FeatureComingSoon :featureId="activeTab.split('/')[1]"></FeatureComingSoon>
|
|
|
|
</div>
|
2021-09-11 01:15:36 -07:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</Modal>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import Vue from 'vue';
|
|
|
|
|
|
|
|
import {
|
|
|
|
ICredentialsDecryptedResponse,
|
|
|
|
ICredentialsResponse,
|
2022-07-27 07:28:13 -07:00
|
|
|
IFakeDoor,
|
2021-09-11 01:15:36 -07:00
|
|
|
} from '@/Interface';
|
|
|
|
|
|
|
|
import {
|
|
|
|
CredentialInformation,
|
|
|
|
ICredentialDataDecryptedObject,
|
|
|
|
ICredentialNodeAccess,
|
|
|
|
ICredentialsDecrypted,
|
|
|
|
ICredentialType,
|
2022-07-27 07:28:13 -07:00
|
|
|
INode,
|
2022-02-05 13:55:43 -08:00
|
|
|
INodeCredentialTestResult,
|
2021-09-11 01:15:36 -07:00
|
|
|
INodeParameters,
|
|
|
|
INodeProperties,
|
|
|
|
INodeTypeDescription,
|
2022-07-09 23:53:04 -07:00
|
|
|
ITelemetryTrackProperties,
|
2022-09-21 01:20:29 -07:00
|
|
|
IUser,
|
2021-09-11 01:15:36 -07:00
|
|
|
NodeHelpers,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
import CredentialIcon from '../CredentialIcon.vue';
|
|
|
|
|
|
|
|
import mixins from 'vue-typed-mixins';
|
|
|
|
import { nodeHelpers } from '../mixins/nodeHelpers';
|
|
|
|
import { showMessage } from '../mixins/showMessage';
|
|
|
|
|
|
|
|
import CredentialConfig from './CredentialConfig.vue';
|
|
|
|
import CredentialInfo from './CredentialInfo.vue';
|
2022-09-21 01:20:29 -07:00
|
|
|
import CredentialSharing from "./CredentialSharing.ee.vue";
|
2021-09-11 01:15:36 -07:00
|
|
|
import SaveButton from '../SaveButton.vue';
|
|
|
|
import Modal from '../Modal.vue';
|
|
|
|
import InlineNameEdit from '../InlineNameEdit.vue';
|
2022-09-21 01:20:29 -07:00
|
|
|
import {EnterpriseEditionFeature} from "@/constants";
|
|
|
|
import {IDataObject} from "n8n-workflow";
|
2022-07-27 07:28:13 -07:00
|
|
|
import FeatureComingSoon from '../FeatureComingSoon.vue';
|
2022-09-21 01:20:29 -07:00
|
|
|
import {mapGetters} from "vuex";
|
|
|
|
import {getCredentialPermissions, IPermissions} from "@/permissions";
|
2021-09-11 01:15:36 -07:00
|
|
|
|
|
|
|
interface NodeAccessMap {
|
|
|
|
[nodeType: string]: ICredentialNodeAccess | null;
|
|
|
|
}
|
|
|
|
|
2021-12-07 07:14:40 -08:00
|
|
|
export default mixins(showMessage, nodeHelpers).extend({
|
2022-09-21 01:20:29 -07:00
|
|
|
name: 'CredentialEdit',
|
2021-09-11 01:15:36 -07:00
|
|
|
components: {
|
2022-09-21 01:20:29 -07:00
|
|
|
CredentialSharing,
|
2021-09-11 01:15:36 -07:00
|
|
|
CredentialConfig,
|
|
|
|
CredentialIcon,
|
|
|
|
CredentialInfo,
|
|
|
|
InlineNameEdit,
|
|
|
|
Modal,
|
|
|
|
SaveButton,
|
2022-07-27 07:28:13 -07:00
|
|
|
FeatureComingSoon,
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
props: {
|
|
|
|
modalName: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
activeId: {
|
2022-09-21 01:20:29 -07:00
|
|
|
type: [String, Number],
|
2021-09-11 01:15:36 -07:00
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
mode: {
|
|
|
|
type: String,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
activeTab: 'connection',
|
|
|
|
authError: '',
|
2022-09-21 01:20:29 -07:00
|
|
|
credentialId: '' as string | number,
|
2021-09-11 01:15:36 -07:00
|
|
|
credentialName: '',
|
|
|
|
credentialData: {} as ICredentialDataDecryptedObject,
|
|
|
|
modalBus: new Vue(),
|
|
|
|
nodeAccess: {} as NodeAccessMap,
|
|
|
|
isDeleting: false,
|
|
|
|
isSaving: false,
|
|
|
|
isTesting: false,
|
|
|
|
hasUnsavedChanges: false,
|
|
|
|
loading: true,
|
|
|
|
showValidationWarning: false,
|
|
|
|
testedSuccessfully: false,
|
|
|
|
isRetesting: false,
|
2022-09-21 01:20:29 -07:00
|
|
|
EnterpriseEditionFeature,
|
2021-09-11 01:15:36 -07:00
|
|
|
};
|
|
|
|
},
|
|
|
|
async mounted() {
|
|
|
|
this.nodeAccess = this.nodesWithAccess.reduce(
|
|
|
|
(accu: NodeAccessMap, node: { name: string }) => {
|
|
|
|
if (this.mode === 'new') {
|
|
|
|
accu[node.name] = { nodeType: node.name }; // enable all nodes by default
|
|
|
|
} else {
|
|
|
|
accu[node.name] = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return accu;
|
|
|
|
},
|
|
|
|
{},
|
|
|
|
);
|
|
|
|
|
|
|
|
if (this.mode === 'new') {
|
|
|
|
this.credentialName = await this.$store.dispatch(
|
|
|
|
'credentials/getNewCredentialName',
|
|
|
|
{ credentialTypeName: this.credentialTypeName },
|
|
|
|
);
|
2022-09-21 01:20:29 -07:00
|
|
|
|
|
|
|
Vue.set(this.credentialData, 'ownedBy', {
|
|
|
|
id: this.currentUser.id,
|
|
|
|
firstName: this.currentUser.firstName,
|
|
|
|
lastName: this.currentUser.lastName,
|
|
|
|
email: this.currentUser.email,
|
|
|
|
});
|
2021-09-11 01:15:36 -07:00
|
|
|
} else {
|
|
|
|
await this.loadCurrentCredential();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.credentialType) {
|
|
|
|
for (const property of this.credentialType.properties) {
|
|
|
|
if (!this.credentialData.hasOwnProperty(property.name)) {
|
2022-01-20 23:52:39 -08:00
|
|
|
Vue.set(this.credentialData, property.name, property.default as CredentialInformation);
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 11:28:37 -07:00
|
|
|
this.$externalHooks().run('credentialsEdit.credentialModalOpened', {
|
|
|
|
credentialType: this.credentialTypeName,
|
|
|
|
isEditingCredential: this.mode === 'edit',
|
|
|
|
activeNode: this.$store.getters.activeNode,
|
|
|
|
});
|
|
|
|
|
2021-10-09 11:42:30 -07:00
|
|
|
setTimeout(() => {
|
|
|
|
if (this.credentialId) {
|
|
|
|
if (!this.requiredPropertiesFilled) {
|
|
|
|
this.showValidationWarning = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.retestCredential();
|
|
|
|
}
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
2021-10-09 11:42:30 -07:00
|
|
|
}, 0);
|
2021-09-11 01:15:36 -07:00
|
|
|
|
|
|
|
this.loading = false;
|
|
|
|
},
|
|
|
|
computed: {
|
2022-09-21 01:20:29 -07:00
|
|
|
...mapGetters('users', ['currentUser']),
|
2021-09-11 01:15:36 -07:00
|
|
|
currentCredential(): ICredentialsResponse | null {
|
|
|
|
if (!this.credentialId) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.$store.getters['credentials/getCredentialById'](
|
|
|
|
this.credentialId,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
credentialTypeName(): string | null {
|
|
|
|
if (this.mode === 'edit') {
|
|
|
|
if (this.currentCredential) {
|
|
|
|
return this.currentCredential.type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
return `${this.activeId}`;
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
credentialType(): ICredentialType | null {
|
|
|
|
if (!this.credentialTypeName) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const type = this.$store.getters['credentials/getCredentialTypeByName'](
|
|
|
|
this.credentialTypeName,
|
|
|
|
);
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
if (!type) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
return {
|
|
|
|
...type,
|
|
|
|
properties: this.getCredentialProperties(this.credentialTypeName),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
isCredentialTestable (): boolean {
|
|
|
|
if (this.isOAuthType || !this.requiredPropertiesFilled) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
const { ownedBy, sharedWith, ...credentialData } = this.credentialData;
|
|
|
|
const hasExpressions = Object.values(credentialData).reduce((accu: boolean, value: CredentialInformation) => accu || (typeof value === 'string' && value.startsWith('=')), false);
|
2021-09-11 01:15:36 -07:00
|
|
|
if (hasExpressions) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nodesThatCanTest = this.nodesWithAccess.filter(node => {
|
|
|
|
if (node.credentials) {
|
|
|
|
// Returns a list of nodes that can test this credentials
|
|
|
|
const eligibleTesters = node.credentials.filter(credential => {
|
|
|
|
return credential.name === this.credentialTypeName && credential.testedBy;
|
|
|
|
});
|
|
|
|
// If we have any node that can test, return true.
|
|
|
|
return !!eligibleTesters.length;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
return !!nodesThatCanTest.length || (!!this.credentialType && !!this.credentialType.test);
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
nodesWithAccess(): INodeTypeDescription[] {
|
|
|
|
if (this.credentialTypeName) {
|
|
|
|
return this.$store.getters['credentials/getNodesWithAccess'](
|
|
|
|
this.credentialTypeName,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
},
|
|
|
|
parentTypes(): string[] {
|
|
|
|
if (this.credentialTypeName) {
|
|
|
|
return this.getParentTypes(this.credentialTypeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
},
|
|
|
|
isOAuthType(): boolean {
|
|
|
|
return !!this.credentialTypeName && (
|
2022-06-13 22:27:19 -07:00
|
|
|
(
|
|
|
|
(
|
|
|
|
this.credentialTypeName === 'oAuth2Api' ||
|
|
|
|
this.parentTypes.includes('oAuth2Api')
|
|
|
|
) && this.credentialData.grantType === 'authorizationCode'
|
|
|
|
)
|
|
|
|
||
|
|
|
|
(
|
|
|
|
this.credentialTypeName === 'oAuth1Api' ||
|
|
|
|
this.parentTypes.includes('oAuth1Api')
|
|
|
|
)
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
},
|
|
|
|
isOAuthConnected(): boolean {
|
|
|
|
return this.isOAuthType && !!this.credentialData.oauthTokenData;
|
|
|
|
},
|
|
|
|
credentialProperties(): INodeProperties[] {
|
|
|
|
if (!this.credentialType) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.credentialType.properties.filter(
|
|
|
|
(propertyData: INodeProperties) => {
|
|
|
|
if (!this.displayCredentialParameter(propertyData)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
!this.credentialType!.__overwrittenProperties ||
|
|
|
|
!this.credentialType!.__overwrittenProperties.includes(
|
|
|
|
propertyData.name,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
requiredPropertiesFilled(): boolean {
|
|
|
|
for (const property of this.credentialProperties) {
|
|
|
|
if (property.required !== true) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-10-09 11:42:30 -07:00
|
|
|
if (property.type === 'string' && !this.credentialData[property.name]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (property.type === 'number' && typeof this.credentialData[property.name] !== 'number') {
|
2021-09-11 01:15:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
2022-07-27 07:28:13 -07:00
|
|
|
credentialsFakeDoorFeatures(): IFakeDoor[] {
|
|
|
|
return this.$store.getters['ui/getFakeDoorByLocation']('credentialsModal');
|
|
|
|
},
|
2022-09-21 01:20:29 -07:00
|
|
|
credentialPermissions(): IPermissions {
|
|
|
|
if (this.loading) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return getCredentialPermissions(this.currentUser, (this.credentialId ? this.currentCredential : this.credentialData) as ICredentialsResponse, this.$store);
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
methods: {
|
2022-01-21 09:00:00 -08:00
|
|
|
async beforeClose() {
|
2021-09-11 01:15:36 -07:00
|
|
|
let keepEditing = false;
|
|
|
|
|
|
|
|
if (this.hasUnsavedChanges) {
|
|
|
|
const displayName = this.credentialType ? this.credentialType.displayName : '';
|
|
|
|
keepEditing = await this.confirmMessage(
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose1.message', { interpolate: { credentialDisplayName: displayName } }),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose1.headline'),
|
2021-09-11 01:15:36 -07:00
|
|
|
null,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose1.cancelButtonText'),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose1.confirmButtonText'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
2022-09-21 01:20:29 -07:00
|
|
|
} else if (this.credentialPermissions.isOwner && this.isOAuthType && !this.isOAuthConnected) {
|
2021-09-11 01:15:36 -07:00
|
|
|
keepEditing = await this.confirmMessage(
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.message'),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.headline'),
|
2021-09-11 01:15:36 -07:00
|
|
|
null,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.cancelButtonText'),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.confirmButtonText'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!keepEditing) {
|
2022-01-21 09:00:00 -08:00
|
|
|
return true;
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
else if (!this.requiredPropertiesFilled) {
|
|
|
|
this.showValidationWarning = true;
|
|
|
|
this.scrollToTop();
|
|
|
|
}
|
|
|
|
else if (this.isOAuthType) {
|
|
|
|
this.scrollToBottom();
|
|
|
|
}
|
2022-01-21 09:00:00 -08:00
|
|
|
|
|
|
|
return false;
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
displayCredentialParameter(parameter: INodeProperties): boolean {
|
|
|
|
if (parameter.type === 'hidden') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parameter.displayOptions === undefined) {
|
|
|
|
// If it is not defined no need to do a proper check
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.displayParameter(
|
|
|
|
this.credentialData as INodeParameters,
|
|
|
|
parameter,
|
|
|
|
'',
|
2022-04-28 10:04:09 -07:00
|
|
|
null,
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
},
|
|
|
|
getCredentialProperties(name: string): INodeProperties[] {
|
2022-09-21 01:20:29 -07:00
|
|
|
const credentialTypeData =
|
2021-09-11 01:15:36 -07:00
|
|
|
this.$store.getters['credentials/getCredentialTypeByName'](name);
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
if (!credentialTypeData) {
|
|
|
|
return [];
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
if (credentialTypeData.extends === undefined) {
|
|
|
|
return credentialTypeData.properties;
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const combineProperties = [] as INodeProperties[];
|
2022-09-21 01:20:29 -07:00
|
|
|
for (const credentialsTypeName of credentialTypeData.extends) {
|
2021-09-11 01:15:36 -07:00
|
|
|
const mergeCredentialProperties =
|
|
|
|
this.getCredentialProperties(credentialsTypeName);
|
|
|
|
NodeHelpers.mergeNodeProperties(
|
|
|
|
combineProperties,
|
|
|
|
mergeCredentialProperties,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The properties defined on the parent credentials take presidence
|
|
|
|
NodeHelpers.mergeNodeProperties(
|
|
|
|
combineProperties,
|
2022-09-21 01:20:29 -07:00
|
|
|
credentialTypeData.properties,
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
return combineProperties;
|
|
|
|
},
|
|
|
|
|
|
|
|
async loadCurrentCredential() {
|
|
|
|
this.credentialId = this.activeId;
|
|
|
|
|
|
|
|
try {
|
2022-09-21 01:20:29 -07:00
|
|
|
const currentCredentials: ICredentialsDecryptedResponse = await this.$store.dispatch('credentials/getCredentialData', {
|
|
|
|
id: this.credentialId,
|
|
|
|
});
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
if (!currentCredentials) {
|
|
|
|
throw new Error(
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.couldNotFindCredentialWithId') + ':' + this.credentialId,
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.credentialData = currentCredentials.data || {};
|
2022-09-21 01:20:29 -07:00
|
|
|
if (currentCredentials.sharedWith) {
|
|
|
|
Vue.set(this.credentialData, 'sharedWith', currentCredentials.sharedWith);
|
|
|
|
}
|
|
|
|
if (currentCredentials.ownedBy) {
|
|
|
|
Vue.set(this.credentialData, 'ownedBy', currentCredentials.ownedBy);
|
|
|
|
}
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
this.credentialName = currentCredentials.name;
|
|
|
|
currentCredentials.nodesAccess.forEach(
|
|
|
|
(access: { nodeType: string }) => {
|
|
|
|
// keep node access structure to keep dates when updating
|
|
|
|
this.nodeAccess[access.nodeType] = access;
|
|
|
|
},
|
|
|
|
);
|
2021-11-10 10:41:40 -08:00
|
|
|
} catch (error) {
|
2021-09-11 01:15:36 -07:00
|
|
|
this.$showError(
|
2021-11-10 10:41:40 -08:00
|
|
|
error,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.loadCredential.title'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
this.closeDialog();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onTabSelect(tab: string) {
|
|
|
|
this.activeTab = tab;
|
2022-07-27 07:28:13 -07:00
|
|
|
const tabName: string = tab.replaceAll('coming-soon/', '');
|
|
|
|
const credType: string = this.credentialType ? this.credentialType.name : '';
|
|
|
|
const activeNode: INode | null = this.$store.getters.activeNode;
|
|
|
|
|
|
|
|
this.$telemetry.track('User viewed credential tab', {
|
|
|
|
credential_type: credType,
|
|
|
|
node_type: activeNode ? activeNode.type : null,
|
|
|
|
tab: tabName,
|
2022-09-21 01:20:29 -07:00
|
|
|
workflow_id: this.$store.getters.workflowId,
|
|
|
|
credential_id: this.credentialId,
|
|
|
|
sharing_enabled: EnterpriseEditionFeature.Sharing,
|
2022-07-27 07:28:13 -07:00
|
|
|
});
|
2021-09-11 01:15:36 -07:00
|
|
|
},
|
|
|
|
onNodeAccessChange({name, value}: {name: string, value: boolean}) {
|
|
|
|
this.hasUnsavedChanges = true;
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
this.nodeAccess = {
|
|
|
|
...this.nodeAccess,
|
|
|
|
[name]: {
|
|
|
|
nodeType: name,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
this.nodeAccess = {
|
|
|
|
...this.nodeAccess,
|
|
|
|
[name]: null,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
2022-09-21 01:20:29 -07:00
|
|
|
onChangeSharedWith(sharees: IDataObject[]) {
|
|
|
|
Vue.set(this.credentialData, 'sharedWith', sharees);
|
|
|
|
this.hasUnsavedChanges = true;
|
|
|
|
},
|
2021-09-11 01:15:36 -07:00
|
|
|
onDataChange({ name, value }: { name: string; value: any }) { // tslint:disable-line:no-any
|
|
|
|
this.hasUnsavedChanges = true;
|
|
|
|
|
|
|
|
const { oauthTokenData, ...credData } = this.credentialData;
|
|
|
|
|
|
|
|
this.credentialData = {
|
|
|
|
...credData,
|
|
|
|
[name]: value,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
closeDialog() {
|
|
|
|
this.modalBus.$emit('close');
|
|
|
|
},
|
|
|
|
|
|
|
|
getParentTypes(name: string): string[] {
|
|
|
|
const credentialType =
|
|
|
|
this.$store.getters['credentials/getCredentialTypeByName'](name);
|
|
|
|
|
|
|
|
if (
|
|
|
|
credentialType === undefined ||
|
|
|
|
credentialType.extends === undefined
|
|
|
|
) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
const types: string[] = [];
|
|
|
|
for (const typeName of credentialType.extends) {
|
|
|
|
types.push(typeName);
|
2022-09-23 07:14:28 -07:00
|
|
|
types.push.apply(types, this.getParentTypes(typeName)); // eslint-disable-line prefer-spread
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return types;
|
|
|
|
},
|
|
|
|
|
|
|
|
onNameEdit(text: string) {
|
|
|
|
this.hasUnsavedChanges = true;
|
|
|
|
this.credentialName = text;
|
|
|
|
},
|
|
|
|
|
|
|
|
scrollToTop() {
|
|
|
|
setTimeout(() => {
|
|
|
|
const content = this.$refs.content as Element;
|
|
|
|
if (content) {
|
|
|
|
content.scrollTop = 0;
|
|
|
|
}
|
|
|
|
}, 0);
|
|
|
|
},
|
|
|
|
|
|
|
|
scrollToBottom() {
|
|
|
|
setTimeout(() => {
|
|
|
|
const content = this.$refs.content as Element;
|
|
|
|
if (content) {
|
|
|
|
content.scrollTop = content.scrollHeight;
|
|
|
|
}
|
|
|
|
}, 0);
|
|
|
|
},
|
|
|
|
|
|
|
|
async retestCredential() {
|
|
|
|
if (!this.isCredentialTestable) {
|
|
|
|
this.authError = '';
|
|
|
|
this.testedSuccessfully = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nodesAccess = Object.values(this.nodeAccess).filter(
|
|
|
|
(access) => !!access,
|
|
|
|
) as ICredentialNodeAccess[];
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
const { ownedBy, sharedWith, ...credentialData } = this.credentialData;
|
2021-09-11 01:15:36 -07:00
|
|
|
const details: ICredentialsDecrypted = {
|
2021-10-13 15:21:00 -07:00
|
|
|
id: this.credentialId,
|
2021-09-11 01:15:36 -07:00
|
|
|
name: this.credentialName,
|
|
|
|
type: this.credentialTypeName!,
|
2022-09-21 01:20:29 -07:00
|
|
|
data: credentialData,
|
2021-09-11 01:15:36 -07:00
|
|
|
nodesAccess,
|
|
|
|
};
|
|
|
|
|
|
|
|
this.isRetesting = true;
|
|
|
|
await this.testCredential(details);
|
|
|
|
this.isRetesting = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
async testCredential(credentialDetails: ICredentialsDecrypted) {
|
2022-02-05 13:55:43 -08:00
|
|
|
const result: INodeCredentialTestResult = await this.$store.dispatch('credentials/testCredential', credentialDetails);
|
2021-09-11 01:15:36 -07:00
|
|
|
if (result.status === 'Error') {
|
|
|
|
this.authError = result.message;
|
|
|
|
this.testedSuccessfully = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.authError = '';
|
|
|
|
this.testedSuccessfully = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.scrollToTop();
|
|
|
|
},
|
|
|
|
|
|
|
|
async saveCredential(): Promise<ICredentialsResponse | null> {
|
|
|
|
if (!this.requiredPropertiesFilled) {
|
|
|
|
this.showValidationWarning = true;
|
|
|
|
this.scrollToTop();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.showValidationWarning = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isSaving = true;
|
|
|
|
const nodesAccess = Object.values(this.nodeAccess).filter(
|
|
|
|
(access) => !!access,
|
|
|
|
) as ICredentialNodeAccess[];
|
|
|
|
|
|
|
|
// Save only the none default data
|
|
|
|
const data = NodeHelpers.getNodeParameters(
|
|
|
|
this.credentialType!.properties,
|
|
|
|
this.credentialData as INodeParameters,
|
|
|
|
false,
|
|
|
|
false,
|
2022-04-28 10:04:09 -07:00
|
|
|
null,
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
let sharedWith: IUser[] | undefined;
|
|
|
|
let ownedBy: IUser | undefined;
|
|
|
|
if (this.$store.getters['settings/isEnterpriseFeatureEnabled'](EnterpriseEditionFeature.Sharing)) {
|
|
|
|
sharedWith = this.credentialData.sharedWith as unknown as IUser[];
|
|
|
|
ownedBy = this.credentialData.ownedBy as unknown as IUser;
|
|
|
|
}
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
const credentialDetails: ICredentialsDecrypted = {
|
2021-10-13 15:21:00 -07:00
|
|
|
id: this.credentialId,
|
2021-09-11 01:15:36 -07:00
|
|
|
name: this.credentialName,
|
|
|
|
type: this.credentialTypeName!,
|
|
|
|
data: data as unknown as ICredentialDataDecryptedObject,
|
|
|
|
nodesAccess,
|
2022-09-21 01:20:29 -07:00
|
|
|
sharedWith,
|
|
|
|
ownedBy,
|
2021-09-11 01:15:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
let credential;
|
|
|
|
|
2022-07-09 23:53:04 -07:00
|
|
|
const isNewCredential = this.mode === 'new' && !this.credentialId;
|
|
|
|
|
|
|
|
if (isNewCredential) {
|
2021-09-11 01:15:36 -07:00
|
|
|
credential = await this.createCredential(
|
|
|
|
credentialDetails,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
credential = await this.updateCredential(
|
|
|
|
credentialDetails,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isSaving = false;
|
|
|
|
if (credential) {
|
|
|
|
this.credentialId = credential.id as string;
|
|
|
|
|
|
|
|
if (this.isCredentialTestable) {
|
|
|
|
this.isTesting = true;
|
2022-01-24 08:37:07 -08:00
|
|
|
// Add the full data including defaults for testing
|
|
|
|
credentialDetails.data = this.credentialData;
|
|
|
|
|
2022-07-19 01:09:06 -07:00
|
|
|
credentialDetails.id = this.credentialId;
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
await this.testCredential(credentialDetails);
|
|
|
|
this.isTesting = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.authError = '';
|
|
|
|
this.testedSuccessfully = false;
|
|
|
|
}
|
2022-07-09 23:53:04 -07:00
|
|
|
|
|
|
|
const trackProperties: ITelemetryTrackProperties = {
|
|
|
|
credential_type: credentialDetails.type,
|
|
|
|
workflow_id: this.$store.getters.workflowId,
|
|
|
|
credential_id: credential.id,
|
|
|
|
is_complete: !!this.requiredPropertiesFilled,
|
|
|
|
is_new: isNewCredential,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.isOAuthType) {
|
|
|
|
trackProperties.is_valid = !!this.isOAuthConnected;
|
|
|
|
} else if (this.isCredentialTestable) {
|
|
|
|
trackProperties.is_valid = !!this.testedSuccessfully;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.$store.getters.activeNode) {
|
|
|
|
trackProperties.node_type = this.$store.getters.activeNode.type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.authError && this.authError !== '') {
|
|
|
|
trackProperties.authError = this.authError;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$telemetry.track('User saved credentials', trackProperties);
|
2022-08-19 06:35:39 -07:00
|
|
|
this.$externalHooks().run('credentialEdit.saveCredential', trackProperties);
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return credential;
|
|
|
|
},
|
|
|
|
|
|
|
|
async createCredential(
|
|
|
|
credentialDetails: ICredentialsDecrypted,
|
|
|
|
): Promise<ICredentialsResponse | null> {
|
|
|
|
let credential;
|
|
|
|
|
|
|
|
try {
|
|
|
|
credential = (await this.$store.dispatch(
|
|
|
|
'credentials/createNewCredential',
|
|
|
|
credentialDetails,
|
|
|
|
)) as ICredentialsResponse;
|
|
|
|
this.hasUnsavedChanges = false;
|
|
|
|
} catch (error) {
|
|
|
|
this.$showError(
|
|
|
|
error,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.createCredential.title'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
this.$externalHooks().run('credential.saved', {
|
|
|
|
credential_type: credentialDetails.type,
|
|
|
|
credential_id: credential.id,
|
|
|
|
is_new: true,
|
2021-09-11 01:15:36 -07:00
|
|
|
});
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
this.$telemetry.track('User created credentials', {
|
|
|
|
credential_type: credentialDetails.type,
|
|
|
|
credential_id: credential.id,
|
|
|
|
workflow_id: this.$store.getters.workflowId,
|
|
|
|
});
|
2021-10-18 20:57:49 -07:00
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
return credential;
|
|
|
|
},
|
|
|
|
|
|
|
|
async updateCredential(
|
|
|
|
credentialDetails: ICredentialsDecrypted,
|
|
|
|
): Promise<ICredentialsResponse | null> {
|
|
|
|
let credential;
|
|
|
|
try {
|
|
|
|
credential = (await this.$store.dispatch(
|
|
|
|
'credentials/updateCredential',
|
|
|
|
{ id: this.credentialId, data: credentialDetails },
|
|
|
|
)) as ICredentialsResponse;
|
|
|
|
this.hasUnsavedChanges = false;
|
|
|
|
} catch (error) {
|
|
|
|
this.$showError(
|
|
|
|
error,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.updateCredential.title'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-09-21 01:20:29 -07:00
|
|
|
this.$externalHooks().run('credential.saved', {
|
|
|
|
credential_type: credentialDetails.type,
|
|
|
|
credential_id: credential.id,
|
|
|
|
is_new: false,
|
|
|
|
});
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
// Now that the credentials changed check if any nodes use credentials
|
|
|
|
// which have now a different name
|
|
|
|
this.updateNodesCredentialsIssues();
|
|
|
|
|
|
|
|
return credential;
|
|
|
|
},
|
|
|
|
|
|
|
|
async deleteCredential() {
|
|
|
|
if (!this.currentCredential) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const savedCredentialName = this.currentCredential.name;
|
|
|
|
|
|
|
|
const deleteConfirmed = await this.confirmMessage(
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.deleteCredential.message', { interpolate: { savedCredentialName } }),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.deleteCredential.headline'),
|
2021-09-11 01:15:36 -07:00
|
|
|
null,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.confirmMessage.deleteCredential.confirmButtonText'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
if (deleteConfirmed === false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.isDeleting = true;
|
|
|
|
await this.$store.dispatch('credentials/deleteCredential', {
|
|
|
|
id: this.credentialId,
|
|
|
|
});
|
|
|
|
this.hasUnsavedChanges = false;
|
|
|
|
} catch (error) {
|
|
|
|
this.$showError(
|
|
|
|
error,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.deleteCredential.title'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
this.isDeleting = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isDeleting = false;
|
|
|
|
// Now that the credentials were removed check if any nodes used them
|
|
|
|
this.updateNodesCredentialsIssues();
|
|
|
|
|
|
|
|
this.$showMessage({
|
2021-12-15 04:16:53 -08:00
|
|
|
title: this.$locale.baseText('credentialEdit.credentialEdit.showMessage.title'),
|
2021-09-11 01:15:36 -07:00
|
|
|
type: 'success',
|
|
|
|
});
|
|
|
|
this.closeDialog();
|
|
|
|
},
|
|
|
|
|
|
|
|
async oAuthCredentialAuthorize() {
|
|
|
|
let url;
|
|
|
|
|
|
|
|
const credential = await this.saveCredential();
|
|
|
|
if (!credential) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const types = this.parentTypes;
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (
|
|
|
|
this.credentialTypeName === 'oAuth2Api' ||
|
|
|
|
types.includes('oAuth2Api')
|
|
|
|
) {
|
|
|
|
url = (await this.$store.dispatch('credentials/oAuth2Authorize', {
|
|
|
|
...this.credentialData,
|
|
|
|
id: credential.id,
|
|
|
|
})) as string;
|
|
|
|
} else if (
|
|
|
|
this.credentialTypeName === 'oAuth1Api' ||
|
|
|
|
types.includes('oAuth1Api')
|
|
|
|
) {
|
|
|
|
url = (await this.$store.dispatch('credentials/oAuth1Authorize', {
|
|
|
|
...this.credentialData,
|
|
|
|
id: credential.id,
|
|
|
|
})) as string;
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
this.$showError(
|
|
|
|
error,
|
2021-12-15 04:16:53 -08:00
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.generateAuthorizationUrl.title'),
|
|
|
|
this.$locale.baseText('credentialEdit.credentialEdit.showError.generateAuthorizationUrl.message'),
|
2021-09-11 01:15:36 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const params = `scrollbars=no,resizable=yes,status=no,titlebar=noe,location=no,toolbar=no,menubar=no,width=500,height=700`;
|
|
|
|
const oauthPopup = window.open(url, 'OAuth2 Authorization', params);
|
|
|
|
Vue.set(this.credentialData, 'oauthTokenData', null);
|
|
|
|
|
|
|
|
const receiveMessage = (event: MessageEvent) => {
|
|
|
|
// // TODO: Add check that it came from n8n
|
|
|
|
// if (event.origin !== 'http://example.org:8080') {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
if (event.data === 'success') {
|
|
|
|
window.removeEventListener('message', receiveMessage, false);
|
|
|
|
|
|
|
|
// Set some kind of data that status changes.
|
|
|
|
// As data does not get displayed directly it does not matter what data.
|
|
|
|
Vue.set(this.credentialData, 'oauthTokenData', {});
|
|
|
|
this.$store.commit('credentials/enableOAuthCredential', credential);
|
|
|
|
|
|
|
|
// Close the window
|
|
|
|
if (oauthPopup) {
|
|
|
|
oauthPopup.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener('message', receiveMessage, false);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style module lang="scss">
|
|
|
|
.credentialModal {
|
2022-09-21 01:20:29 -07:00
|
|
|
--dialog-max-width: 900px;
|
|
|
|
--dialog-close-top: 31px;
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
.mainContent {
|
2022-09-21 01:20:29 -07:00
|
|
|
flex: 1;
|
2021-09-11 01:15:36 -07:00
|
|
|
overflow: auto;
|
|
|
|
padding-bottom: 100px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.sidebar {
|
|
|
|
max-width: 170px;
|
|
|
|
min-width: 170px;
|
|
|
|
margin-right: var(--spacing-l);
|
|
|
|
flex-grow: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.header {
|
|
|
|
display: flex;
|
|
|
|
}
|
|
|
|
|
|
|
|
.container {
|
|
|
|
display: flex;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.credInfo {
|
|
|
|
display: flex;
|
2022-09-21 01:20:29 -07:00
|
|
|
align-items: center;
|
|
|
|
flex-direction: row;
|
2021-09-11 01:15:36 -07:00
|
|
|
flex-grow: 1;
|
2022-09-21 01:20:29 -07:00
|
|
|
margin-bottom: var(--spacing-l);
|
2021-09-11 01:15:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
.credActions {
|
2022-07-20 08:50:39 -07:00
|
|
|
display: flex;
|
2022-09-21 01:20:29 -07:00
|
|
|
flex-direction: row;
|
|
|
|
align-items: center;
|
2021-09-11 01:15:36 -07:00
|
|
|
margin-right: var(--spacing-xl);
|
2022-09-21 01:20:29 -07:00
|
|
|
margin-bottom: var(--spacing-l);
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
> * {
|
|
|
|
margin-left: var(--spacing-2xs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.credIcon {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
margin-right: var(--spacing-xs);
|
|
|
|
}
|
|
|
|
</style>
|