2019-06-23 03:35:23 -07:00
|
|
|
<template>
|
2022-05-24 02:36:19 -07:00
|
|
|
<div class="parameter-input-list-wrapper">
|
2022-06-02 00:36:08 -07:00
|
|
|
<div v-for="(parameter, index) in filteredParameters" :key="parameter.name" :class="{indent}">
|
2022-05-24 02:36:19 -07:00
|
|
|
<slot v-if="indexToShowSlotAt === index" />
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
<div
|
|
|
|
v-if="multipleValues(parameter) === true && parameter.type !== 'fixedCollection'"
|
|
|
|
class="parameter-item"
|
|
|
|
>
|
|
|
|
<multiple-parameter
|
|
|
|
:parameter="parameter"
|
|
|
|
:values="getParameterValue(nodeValues, parameter.name, path)"
|
|
|
|
:nodeValues="nodeValues"
|
|
|
|
:path="getPath(parameter.name)"
|
|
|
|
@valueChanged="valueChanged"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
2022-04-29 06:23:41 -07:00
|
|
|
<n8n-notice
|
|
|
|
v-else-if="parameter.type === 'notice'"
|
|
|
|
class="parameter-item"
|
|
|
|
:content="$locale.nodeText().inputLabelDisplayName(parameter, path)"
|
2022-06-20 12:39:24 -07:00
|
|
|
@action="onNoticeAction"
|
2022-04-29 06:23:41 -07:00
|
|
|
/>
|
2021-08-21 05:11:32 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
<div
|
|
|
|
v-else-if="['collection', 'fixedCollection'].includes(parameter.type)"
|
|
|
|
class="multi-parameter"
|
|
|
|
>
|
2021-12-15 04:16:53 -08:00
|
|
|
<div class="delete-option clickable" :title="$locale.baseText('parameterInputList.delete')" v-if="hideDelete !== true && !isReadOnly">
|
2021-10-27 12:55:37 -07:00
|
|
|
<font-awesome-icon
|
|
|
|
icon="trash"
|
|
|
|
class="reset-icon clickable"
|
2021-12-15 04:16:53 -08:00
|
|
|
:title="$locale.baseText('parameterInputList.parameterOptions')"
|
2021-10-27 12:55:37 -07:00
|
|
|
@click="deleteOption(parameter.name)"
|
|
|
|
/>
|
2019-06-23 03:35:23 -07:00
|
|
|
</div>
|
2021-10-27 12:55:37 -07:00
|
|
|
<n8n-input-label
|
2022-01-07 13:02:21 -08:00
|
|
|
:label="$locale.nodeText().inputLabelDisplayName(parameter, path)"
|
|
|
|
:tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)"
|
2021-10-27 12:55:37 -07:00
|
|
|
size="small"
|
|
|
|
:underline="true"
|
2022-07-20 04:32:51 -07:00
|
|
|
/>
|
|
|
|
<collection-parameter
|
|
|
|
v-if="parameter.type === 'collection'"
|
|
|
|
:parameter="parameter"
|
|
|
|
:values="getParameterValue(nodeValues, parameter.name, path)"
|
|
|
|
:nodeValues="nodeValues"
|
|
|
|
:path="getPath(parameter.name)"
|
|
|
|
@valueChanged="valueChanged"
|
|
|
|
/>
|
|
|
|
<fixed-collection-parameter
|
|
|
|
v-else-if="parameter.type === 'fixedCollection'"
|
|
|
|
:parameter="parameter"
|
|
|
|
:values="getParameterValue(nodeValues, parameter.name, path)"
|
|
|
|
:nodeValues="nodeValues"
|
|
|
|
:path="getPath(parameter.name)"
|
|
|
|
@valueChanged="valueChanged"
|
|
|
|
/>
|
2019-06-23 03:35:23 -07:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-else-if="displayNodeParameter(parameter)" class="parameter-item">
|
2021-12-15 04:16:53 -08:00
|
|
|
<div class="delete-option clickable" :title="$locale.baseText('parameterInputList.delete')" v-if="hideDelete !== true && !isReadOnly">
|
2019-06-23 03:35:23 -07:00
|
|
|
<font-awesome-icon
|
|
|
|
icon="trash"
|
|
|
|
class="reset-icon clickable"
|
2021-12-15 04:16:53 -08:00
|
|
|
:title="$locale.baseText('parameterInputList.deleteParameter')"
|
2019-06-23 03:35:23 -07:00
|
|
|
@click="deleteOption(parameter.name)"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<parameter-input-full
|
|
|
|
:parameter="parameter"
|
|
|
|
:value="getParameterValue(nodeValues, parameter.name, path)"
|
|
|
|
:displayOptions="true"
|
|
|
|
:path="getPath(parameter.name)"
|
2021-09-11 01:15:36 -07:00
|
|
|
:isReadOnly="isReadOnly"
|
2019-06-23 03:35:23 -07:00
|
|
|
@valueChanged="valueChanged"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-06-23 10:56:05 -07:00
|
|
|
<div
|
|
|
|
:class="{indent}"
|
|
|
|
v-if="filteredParameters.length === 0"
|
|
|
|
>
|
|
|
|
<slot/>
|
|
|
|
</div>
|
2019-06-23 03:35:23 -07:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
|
|
|
import {
|
2021-05-14 22:36:41 -07:00
|
|
|
INodeParameters,
|
2019-06-23 03:35:23 -07:00
|
|
|
INodeProperties,
|
2022-06-07 06:02:08 -07:00
|
|
|
INodeType,
|
|
|
|
INodeTypeDescription,
|
2021-05-15 15:51:14 -07:00
|
|
|
NodeParameterValue,
|
2019-06-23 03:35:23 -07:00
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
2022-04-28 10:04:09 -07:00
|
|
|
import { INodeUi, IUpdateInformation } from '@/Interface';
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
import MultipleParameter from '@/components/MultipleParameter.vue';
|
|
|
|
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
2021-05-14 22:28:51 -07:00
|
|
|
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
|
2019-06-23 03:35:23 -07:00
|
|
|
import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
|
|
|
|
2021-05-15 16:59:33 -07:00
|
|
|
import { get, set } from 'lodash';
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
import mixins from 'vue-typed-mixins';
|
2022-09-23 07:14:28 -07:00
|
|
|
import {Component} from "vue";
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
export default mixins(
|
|
|
|
genericHelpers,
|
2021-05-14 22:28:51 -07:00
|
|
|
workflowHelpers,
|
2019-06-23 03:35:23 -07:00
|
|
|
)
|
|
|
|
.extend({
|
|
|
|
name: 'ParameterInputList',
|
|
|
|
components: {
|
|
|
|
MultipleParameter,
|
|
|
|
ParameterInputFull,
|
2022-09-23 07:14:28 -07:00
|
|
|
FixedCollectionParameter: () => import('./FixedCollectionParameter.vue') as Promise<Component>,
|
|
|
|
CollectionParameter: () => import('./CollectionParameter.vue') as Promise<Component>,
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
props: [
|
|
|
|
'nodeValues', // INodeParameters
|
|
|
|
'parameters', // INodeProperties
|
|
|
|
'path', // string
|
|
|
|
'hideDelete', // boolean
|
2021-10-27 12:55:37 -07:00
|
|
|
'indent',
|
2019-06-23 03:35:23 -07:00
|
|
|
],
|
|
|
|
computed: {
|
2021-05-15 15:51:14 -07:00
|
|
|
filteredParameters (): INodeProperties[] {
|
2019-06-23 03:35:23 -07:00
|
|
|
return this.parameters.filter((parameter: INodeProperties) => this.displayNodeParameter(parameter));
|
|
|
|
},
|
2021-05-15 15:51:14 -07:00
|
|
|
filteredParameterNames (): string[] {
|
|
|
|
return this.filteredParameters.map(parameter => parameter.name);
|
|
|
|
},
|
2022-04-28 10:04:09 -07:00
|
|
|
node (): INodeUi {
|
|
|
|
return this.$store.getters.activeNode;
|
|
|
|
},
|
2022-05-24 02:36:19 -07:00
|
|
|
indexToShowSlotAt (): number {
|
2022-06-07 06:02:08 -07:00
|
|
|
let index = 0;
|
|
|
|
const credentialsDependencies = this.getCredentialsDependencies();
|
2022-05-24 02:36:19 -07:00
|
|
|
|
2022-06-07 06:02:08 -07:00
|
|
|
this.filteredParameters.forEach((prop, propIndex) => {
|
|
|
|
if (credentialsDependencies.has(prop.name)) {
|
|
|
|
index = propIndex + 1;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return index < this.filteredParameters.length ?
|
|
|
|
index : this.filteredParameters.length - 1;
|
2022-05-24 02:36:19 -07:00
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
methods: {
|
2022-06-07 06:02:08 -07:00
|
|
|
getCredentialsDependencies() {
|
|
|
|
const dependencies = new Set();
|
2022-08-01 13:43:50 -07:00
|
|
|
const nodeType = this.$store.getters['nodeTypes/getNodeType'](this.node.type, this.node.typeVersion) as INodeTypeDescription | undefined;
|
2022-06-07 06:02:08 -07:00
|
|
|
|
|
|
|
// Get names of all fields that credentials rendering depends on (using displayOptions > show)
|
|
|
|
if(nodeType && nodeType.credentials) {
|
|
|
|
for(const cred of nodeType.credentials) {
|
|
|
|
if(cred.displayOptions && cred.displayOptions.show) {
|
|
|
|
Object.keys(cred.displayOptions.show).forEach(fieldName => dependencies.add(fieldName));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dependencies;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
multipleValues (parameter: INodeProperties): boolean {
|
|
|
|
if (this.getArgument('multipleValues', parameter) === true) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
getArgument (
|
|
|
|
argumentName: string,
|
2019-12-29 13:02:21 -08:00
|
|
|
parameter: INodeProperties,
|
2020-01-04 20:28:09 -08:00
|
|
|
): string | string[] | number | boolean | undefined{
|
2019-06-23 03:35:23 -07:00
|
|
|
if (parameter.typeOptions === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parameter.typeOptions[argumentName] === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parameter.typeOptions[argumentName];
|
|
|
|
},
|
|
|
|
getPath (parameterName: string): string {
|
|
|
|
return (this.path ? `${this.path}.` : '') + parameterName;
|
|
|
|
},
|
|
|
|
deleteOption (optionName: string): void {
|
|
|
|
const parameterData = {
|
|
|
|
name: this.getPath(optionName),
|
2019-07-14 05:10:16 -07:00
|
|
|
value: undefined,
|
2019-06-23 03:35:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: If there is only one option it should delete the whole one
|
|
|
|
|
|
|
|
this.$emit('valueChanged', parameterData);
|
|
|
|
},
|
2022-05-24 02:36:19 -07:00
|
|
|
|
|
|
|
mustHideDuringCustomApiCall (parameter: INodeProperties, nodeValues: INodeParameters): boolean {
|
|
|
|
if (parameter && parameter.displayOptions && parameter.displayOptions.hide) return true;
|
|
|
|
|
|
|
|
const MUST_REMAIN_VISIBLE = ['authentication', 'resource', 'operation', ...Object.keys(nodeValues)];
|
|
|
|
|
|
|
|
return !MUST_REMAIN_VISIBLE.includes(parameter.name);
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
displayNodeParameter (parameter: INodeProperties): boolean {
|
2020-02-09 13:33:40 -08:00
|
|
|
if (parameter.type === 'hidden') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-24 02:36:19 -07:00
|
|
|
if (
|
|
|
|
this.isCustomApiCallSelected(this.nodeValues) &&
|
|
|
|
this.mustHideDuringCustomApiCall(parameter, this.nodeValues)
|
|
|
|
) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
if (parameter.displayOptions === undefined) {
|
|
|
|
// If it is not defined no need to do a proper check
|
|
|
|
return true;
|
|
|
|
}
|
2021-05-14 22:28:51 -07:00
|
|
|
|
2021-05-14 22:36:41 -07:00
|
|
|
const nodeValues: INodeParameters = {};
|
2021-05-14 22:28:51 -07:00
|
|
|
let rawValues = this.nodeValues;
|
|
|
|
if (this.path) {
|
|
|
|
rawValues = get(this.nodeValues, this.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve expressions
|
|
|
|
const resolveKeys = Object.keys(rawValues);
|
|
|
|
let key: string;
|
|
|
|
let i = 0;
|
2021-05-15 16:59:33 -07:00
|
|
|
let parameterGotResolved = false;
|
2021-05-14 22:28:51 -07:00
|
|
|
do {
|
2021-05-14 22:36:41 -07:00
|
|
|
key = resolveKeys.shift() as string;
|
2021-05-14 22:28:51 -07:00
|
|
|
if (typeof rawValues[key] === 'string' && rawValues[key].charAt(0) === '=') {
|
|
|
|
// Contains an expression that
|
|
|
|
if (rawValues[key].includes('$parameter') && resolveKeys.some(parameterName => rawValues[key].includes(parameterName))) {
|
|
|
|
// Contains probably an expression of a missing parameter so skip
|
|
|
|
resolveKeys.push(key);
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// Contains probably no expression with a missing parameter so resolve
|
2021-05-29 17:49:20 -07:00
|
|
|
try {
|
|
|
|
nodeValues[key] = this.resolveExpression(rawValues[key], nodeValues) as NodeParameterValue;
|
|
|
|
} catch (e) {
|
|
|
|
// If expression is invalid ignore
|
|
|
|
nodeValues[key] = '';
|
|
|
|
}
|
2021-05-15 16:59:33 -07:00
|
|
|
parameterGotResolved = true;
|
2021-05-14 22:28:51 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Does not contain an expression, add directly
|
|
|
|
nodeValues[key] = rawValues[key];
|
|
|
|
}
|
|
|
|
// TODO: Think about how to calculate this best
|
|
|
|
if (i++ > 50) {
|
|
|
|
// Make sure we do not get caught
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(resolveKeys.length !== 0);
|
|
|
|
|
2021-05-15 16:59:33 -07:00
|
|
|
if (parameterGotResolved === true) {
|
|
|
|
if (this.path) {
|
|
|
|
rawValues = JSON.parse(JSON.stringify(this.nodeValues));
|
|
|
|
set(rawValues, this.path, nodeValues);
|
2022-04-28 10:04:09 -07:00
|
|
|
return this.displayParameter(rawValues, parameter, this.path, this.node);
|
2021-05-15 16:59:33 -07:00
|
|
|
} else {
|
2022-04-28 10:04:09 -07:00
|
|
|
return this.displayParameter(nodeValues, parameter, '', this.node);
|
2021-05-15 16:59:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-28 10:04:09 -07:00
|
|
|
return this.displayParameter(this.nodeValues, parameter, this.path, this.node);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
valueChanged (parameterData: IUpdateInformation): void {
|
|
|
|
this.$emit('valueChanged', parameterData);
|
|
|
|
},
|
2022-06-20 12:39:24 -07:00
|
|
|
onNoticeAction(action: string) {
|
|
|
|
if (action === 'activate') {
|
|
|
|
this.$emit('activate');
|
|
|
|
}
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
2021-05-15 15:51:14 -07:00
|
|
|
watch: {
|
|
|
|
filteredParameterNames(newValue, oldValue) {
|
2021-05-29 17:49:20 -07:00
|
|
|
if (newValue === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
2021-05-15 15:51:14 -07:00
|
|
|
// After a parameter does not get displayed anymore make sure that its value gets removed
|
|
|
|
// Is only needed for the edge-case when a parameter gets displayed depending on another field
|
|
|
|
// which contains an expression.
|
|
|
|
for (const parameter of oldValue) {
|
|
|
|
if (!newValue.includes(parameter)) {
|
|
|
|
const parameterData = {
|
|
|
|
name: `${this.path}.${parameter}`,
|
|
|
|
node: this.$store.getters.activeNode.name,
|
|
|
|
value: undefined,
|
|
|
|
};
|
|
|
|
this.$emit('valueChanged', parameterData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss">
|
2022-05-24 02:36:19 -07:00
|
|
|
.parameter-input-list-wrapper {
|
2019-09-19 14:59:25 -07:00
|
|
|
.delete-option {
|
|
|
|
display: none;
|
|
|
|
position: absolute;
|
|
|
|
z-index: 999;
|
|
|
|
color: #f56c6c;
|
2021-10-27 12:55:37 -07:00
|
|
|
font-size: var(--font-size-2xs);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2019-09-19 14:59:25 -07:00
|
|
|
&:hover {
|
|
|
|
color: #ff0000;
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2021-10-27 12:55:37 -07:00
|
|
|
.indent > div {
|
|
|
|
padding-left: var(--spacing-s);
|
|
|
|
}
|
|
|
|
|
2019-09-19 14:59:25 -07:00
|
|
|
.multi-parameter {
|
|
|
|
position: relative;
|
2021-10-27 12:55:37 -07:00
|
|
|
margin: var(--spacing-xs) 0;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-10-27 12:55:37 -07:00
|
|
|
.delete-option {
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-10-27 12:55:37 -07:00
|
|
|
.parameter-info {
|
|
|
|
display: none;
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-19 14:59:25 -07:00
|
|
|
.parameter-item {
|
|
|
|
position: relative;
|
2021-10-27 12:55:37 -07:00
|
|
|
margin: var(--spacing-xs) 0;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2019-09-19 14:59:25 -07:00
|
|
|
>.delete-option {
|
2021-10-27 12:55:37 -07:00
|
|
|
top: var(--spacing-5xs);
|
|
|
|
left: 0;
|
2019-09-19 14:59:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.parameter-item:hover > .delete-option,
|
2021-10-27 12:55:37 -07:00
|
|
|
.multi-parameter:hover > .delete-option {
|
2019-09-19 14:59:25 -07:00
|
|
|
display: block;
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
2021-08-21 05:11:32 -07:00
|
|
|
|
|
|
|
.parameter-notice {
|
2022-07-26 03:45:55 -07:00
|
|
|
background-color: var(--color-warning-tint-2);
|
2022-09-23 07:14:28 -07:00
|
|
|
color: $custom-font-black;
|
2021-08-21 05:11:32 -07:00
|
|
|
margin: 0.3em 0;
|
2021-10-27 12:55:37 -07:00
|
|
|
padding: 0.7em;
|
2021-08-21 05:11:32 -07:00
|
|
|
|
2021-08-29 04:36:17 -07:00
|
|
|
a {
|
|
|
|
font-weight: var(--font-weight-bold);
|
2021-08-21 05:11:32 -07:00
|
|
|
}
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|