mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
refactor(editor): Refactor VariableSelector and VariableSelectorItem to composition API (no-changelog) (#10030)
This commit is contained in:
@@ -1,32 +1,7 @@
|
|||||||
<template>
|
<script setup lang="ts">
|
||||||
<div class="variable-selector-wrapper" @keydown.stop>
|
import { ref, computed } from 'vue';
|
||||||
<div class="input-wrapper">
|
import { useRouter } from 'vue-router';
|
||||||
<n8n-input
|
import { storeToRefs } from 'pinia';
|
||||||
ref="inputField"
|
|
||||||
v-model="variableFilter"
|
|
||||||
:placeholder="$locale.baseText('variableSelector.variableFilter')"
|
|
||||||
size="small"
|
|
||||||
type="text"
|
|
||||||
></n8n-input>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="result-wrapper">
|
|
||||||
<VariableSelectorItem
|
|
||||||
v-for="option in currentResults"
|
|
||||||
:key="option.key"
|
|
||||||
:item="option"
|
|
||||||
:extend-all="extendAll"
|
|
||||||
:redact-values="redactValues"
|
|
||||||
@item-selected="forwardItemSelected"
|
|
||||||
></VariableSelectorItem>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
/* eslint-disable prefer-spread */
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { mapStores } from 'pinia';
|
|
||||||
import { PLACEHOLDER_FILLED_AT_EXECUTION_TIME, STICKY_NODE_TYPE } from '@/constants';
|
import { PLACEHOLDER_FILLED_AT_EXECUTION_TIME, STICKY_NODE_TYPE } from '@/constants';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -43,66 +18,49 @@ import type {
|
|||||||
import { NodeConnectionType, WorkflowDataProxy } from 'n8n-workflow';
|
import { NodeConnectionType, WorkflowDataProxy } from 'n8n-workflow';
|
||||||
|
|
||||||
import VariableSelectorItem from '@/components/VariableSelectorItem.vue';
|
import VariableSelectorItem from '@/components/VariableSelectorItem.vue';
|
||||||
import type { INodeUi, IVariableItemSelected, IVariableSelectorOption } from '@/Interface';
|
import type { IVariableItemSelected, IVariableSelectorOption } from '@/Interface';
|
||||||
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useRootStore } from '@/stores/root.store';
|
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { escapeMappingString } from '@/utils/mappingUtils';
|
import { escapeMappingString } from '@/utils/mappingUtils';
|
||||||
|
|
||||||
// Node types that should not be displayed in variable selector
|
// Node types that should not be displayed in variable selector
|
||||||
const SKIPPED_NODE_TYPES = [STICKY_NODE_TYPE];
|
const SKIPPED_NODE_TYPES = [STICKY_NODE_TYPE];
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
name: 'VariableSelector',
|
path: string;
|
||||||
components: {
|
redactValues: boolean;
|
||||||
VariableSelectorItem,
|
}>();
|
||||||
},
|
|
||||||
props: ['path', 'redactValues'],
|
const emit = defineEmits<{
|
||||||
setup() {
|
itemSelected: [value: IVariableItemSelected];
|
||||||
|
}>();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const i18n = useI18n();
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
return {
|
const workflowsStore = useWorkflowsStore();
|
||||||
workflowHelpers,
|
const ndvStore = useNDVStore();
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
variableFilter: '',
|
|
||||||
selectorOpenInputIndex: null as number | null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapStores(useNDVStore, useRootStore, useWorkflowsStore),
|
|
||||||
activeNode(): INodeUi | null {
|
|
||||||
const activeNode = this.ndvStore.activeNode!;
|
|
||||||
if (!activeNode) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.workflow.getParentMainInputNode(activeNode);
|
|
||||||
},
|
|
||||||
extendAll(): boolean {
|
|
||||||
if (this.variableFilter) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
const { activeNode } = storeToRefs(ndvStore);
|
||||||
},
|
|
||||||
currentResults(): IVariableSelectorOption[] {
|
const variableFilter = ref('');
|
||||||
return this.getFilterResults(this.variableFilter.toLowerCase(), 0);
|
|
||||||
},
|
const extendAll = computed(() => !!variableFilter.value);
|
||||||
workflow(): Workflow {
|
|
||||||
return this.workflowHelpers.getCurrentWorkflow();
|
const currentResults = computed(() => getFilterResults(variableFilter.value.toLowerCase(), 0));
|
||||||
},
|
|
||||||
},
|
const workflow = computed(() => workflowHelpers.getCurrentWorkflow());
|
||||||
methods: {
|
|
||||||
forwardItemSelected(eventData: IVariableItemSelected) {
|
// Helper functions
|
||||||
this.$emit('itemSelected', eventData);
|
|
||||||
},
|
/**
|
||||||
sortOptions(options: IVariableSelectorOption[] | null): IVariableSelectorOption[] | null {
|
* Sorts the options alphabetically. Categories get sorted before items.
|
||||||
|
*/
|
||||||
|
function sortOptions(options: IVariableSelectorOption[] | null): IVariableSelectorOption[] | null {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -127,15 +85,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
removeEmptyEntries(
|
|
||||||
|
/**
|
||||||
|
* Removes all empty entries from the list
|
||||||
|
*/
|
||||||
|
function removeEmptyEntries(
|
||||||
inputData: IVariableSelectorOption[] | IVariableSelectorOption | null,
|
inputData: IVariableSelectorOption[] | IVariableSelectorOption | null,
|
||||||
): IVariableSelectorOption[] | IVariableSelectorOption | null {
|
): IVariableSelectorOption[] | IVariableSelectorOption | null {
|
||||||
if (Array.isArray(inputData)) {
|
if (Array.isArray(inputData)) {
|
||||||
const newItems: IVariableSelectorOption[] = [];
|
const newItems: IVariableSelectorOption[] = [];
|
||||||
let tempItem: IVariableSelectorOption;
|
let tempItem: IVariableSelectorOption;
|
||||||
inputData.forEach((item) => {
|
inputData.forEach((item) => {
|
||||||
tempItem = this.removeEmptyEntries(item) as IVariableSelectorOption;
|
tempItem = removeEmptyEntries(item) as IVariableSelectorOption;
|
||||||
if (tempItem !== null) {
|
if (tempItem !== null) {
|
||||||
newItems.push(tempItem);
|
newItems.push(tempItem);
|
||||||
}
|
}
|
||||||
@@ -144,7 +106,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inputData?.options) {
|
if (inputData?.options) {
|
||||||
const newOptions = this.removeEmptyEntries(inputData.options);
|
const newOptions = removeEmptyEntries(inputData.options);
|
||||||
if (Array.isArray(newOptions) && newOptions.length) {
|
if (Array.isArray(newOptions) && newOptions.length) {
|
||||||
// Has still options left so return
|
// Has still options left so return
|
||||||
inputData.options = newOptions;
|
inputData.options = newOptions;
|
||||||
@@ -159,9 +121,12 @@ export default defineComponent({
|
|||||||
// Is an item no category
|
// Is an item no category
|
||||||
return inputData;
|
return inputData;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// Normalizes the path so compare paths which have use dots or brakets
|
|
||||||
getPathNormalized(path: string | undefined): string {
|
/**
|
||||||
|
* Normalizes the path so compare paths which have use dots or brakets
|
||||||
|
*/
|
||||||
|
function getPathNormalized(path: string | undefined): string {
|
||||||
if (path === undefined) {
|
if (path === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -197,8 +162,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return finalArray.join('|');
|
return finalArray.join('|');
|
||||||
},
|
}
|
||||||
jsonDataToFilterOption(
|
|
||||||
|
function jsonDataToFilterOption(
|
||||||
inputData: IDataObject | GenericValue | IDataObject[] | GenericValue[] | null,
|
inputData: IDataObject | GenericValue | IDataObject[] | GenericValue[] | null,
|
||||||
parentPath: string,
|
parentPath: string,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
@@ -231,9 +197,8 @@ export default defineComponent({
|
|||||||
const arrayData: IVariableSelectorOption[] = [];
|
const arrayData: IVariableSelectorOption[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < inputData.length; i++) {
|
for (let i = 0; i < inputData.length; i++) {
|
||||||
arrayData.push.apply(
|
arrayData.push(
|
||||||
arrayData,
|
...jsonDataToFilterOption(
|
||||||
this.jsonDataToFilterOption(
|
|
||||||
inputData[i],
|
inputData[i],
|
||||||
newParentPath,
|
newParentPath,
|
||||||
newPropertyName,
|
newPropertyName,
|
||||||
@@ -256,9 +221,8 @@ export default defineComponent({
|
|||||||
const tempValue: IVariableSelectorOption[] = [];
|
const tempValue: IVariableSelectorOption[] = [];
|
||||||
|
|
||||||
for (const key of Object.keys(inputData)) {
|
for (const key of Object.keys(inputData)) {
|
||||||
tempValue.push.apply(
|
tempValue.push(
|
||||||
tempValue,
|
...jsonDataToFilterOption(
|
||||||
this.jsonDataToFilterOption(
|
|
||||||
(inputData as IDataObject)[key],
|
(inputData as IDataObject)[key],
|
||||||
fullpath,
|
fullpath,
|
||||||
key,
|
key,
|
||||||
@@ -273,7 +237,7 @@ export default defineComponent({
|
|||||||
if (tempValue.length) {
|
if (tempValue.length) {
|
||||||
returnData.push({
|
returnData.push({
|
||||||
name: displayName || propertyName,
|
name: displayName || propertyName,
|
||||||
options: this.sortOptions(tempValue),
|
options: sortOptions(tempValue),
|
||||||
key: fullpath,
|
key: fullpath,
|
||||||
allowParentSelect: true,
|
allowParentSelect: true,
|
||||||
dataType: 'object',
|
dataType: 'object',
|
||||||
@@ -281,11 +245,12 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (filterText !== undefined && propertyName.toLowerCase().indexOf(filterText) === -1) {
|
if (filterText !== undefined && propertyName.toLowerCase().indexOf(filterText) === -1) {
|
||||||
|
// If filter is set apply it
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip is currently only needed for leafs so only check here
|
// Skip is currently only needed for leafs so only check here
|
||||||
if (this.getPathNormalized(skipKey) !== this.getPathNormalized(fullpath)) {
|
if (getPathNormalized(skipKey) !== getPathNormalized(fullpath)) {
|
||||||
returnData.push({
|
returnData.push({
|
||||||
name: propertyName,
|
name: propertyName,
|
||||||
key: fullpath,
|
key: fullpath,
|
||||||
@@ -295,7 +260,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the node's output using runData
|
* Get the node's output using runData
|
||||||
@@ -309,7 +274,7 @@ export default defineComponent({
|
|||||||
* @param {number} [outputIndex=0] The index of the output
|
* @param {number} [outputIndex=0] The index of the output
|
||||||
* @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
|
* @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
|
||||||
*/
|
*/
|
||||||
getNodeRunDataOutput(
|
function getNodeRunDataOutput(
|
||||||
nodeName: string,
|
nodeName: string,
|
||||||
runData: IRunData,
|
runData: IRunData,
|
||||||
filterText: string,
|
filterText: string,
|
||||||
@@ -338,29 +303,29 @@ export default defineComponent({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!runData[nodeName][runIndex].data!.hasOwnProperty(inputName)) {
|
if (!runData[nodeName][runIndex].data.hasOwnProperty(inputName)) {
|
||||||
// No data found for inputName
|
// No data found for inputName
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runData[nodeName][runIndex].data![inputName].length <= outputIndex) {
|
if (runData[nodeName][runIndex].data[inputName].length <= outputIndex) {
|
||||||
// No data found for output Index
|
// No data found for output Index
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The data should be identical no matter to which node it gets so always select the first one
|
// The data should be identical no matter to which node it gets so always select the first one
|
||||||
if (
|
if (
|
||||||
runData[nodeName][runIndex].data![inputName][outputIndex] === null ||
|
runData[nodeName][runIndex].data[inputName][outputIndex] === null ||
|
||||||
runData[nodeName][runIndex].data![inputName][outputIndex]!.length <= itemIndex
|
runData[nodeName][runIndex].data[inputName][outputIndex].length <= itemIndex
|
||||||
) {
|
) {
|
||||||
// No data found for node connection found
|
// No data found for node connection found
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputData = runData[nodeName][runIndex].data![inputName][outputIndex]![itemIndex];
|
const outputData = runData[nodeName][runIndex].data[inputName][outputIndex][itemIndex];
|
||||||
|
|
||||||
return this.getNodeOutput(nodeName, outputData, filterText, useShort);
|
return getNodeOutput(nodeName, outputData, filterText, useShort);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the node's output using pinData
|
* Get the node's output using pinData
|
||||||
@@ -370,7 +335,7 @@ export default defineComponent({
|
|||||||
* @param {string} filterText Filter text for parameters
|
* @param {string} filterText Filter text for parameters
|
||||||
* @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
|
* @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
|
||||||
*/
|
*/
|
||||||
getNodePinDataOutput(
|
function getNodePinDataOutput(
|
||||||
nodeName: string,
|
nodeName: string,
|
||||||
pinData: IPinData[string],
|
pinData: IPinData[string],
|
||||||
filterText: string,
|
filterText: string,
|
||||||
@@ -378,8 +343,8 @@ export default defineComponent({
|
|||||||
): IVariableSelectorOption[] | null {
|
): IVariableSelectorOption[] | null {
|
||||||
const outputData = pinData.map((data) => ({ json: data }) as INodeExecutionData)[0];
|
const outputData = pinData.map((data) => ({ json: data }) as INodeExecutionData)[0];
|
||||||
|
|
||||||
return this.getNodeOutput(nodeName, outputData, filterText, useShort);
|
return getNodeOutput(nodeName, outputData, filterText, useShort);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node's output data
|
* Returns the node's output data
|
||||||
@@ -389,7 +354,7 @@ export default defineComponent({
|
|||||||
* @param {string} filterText Filter text for parameters
|
* @param {string} filterText Filter text for parameters
|
||||||
* @param {boolean} [useShort=false] Use short notation
|
* @param {boolean} [useShort=false] Use short notation
|
||||||
*/
|
*/
|
||||||
getNodeOutput(
|
function getNodeOutput(
|
||||||
nodeName: string,
|
nodeName: string,
|
||||||
outputData: INodeExecutionData,
|
outputData: INodeExecutionData,
|
||||||
filterText: string,
|
filterText: string,
|
||||||
@@ -405,9 +370,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
const jsonDataOptions: IVariableSelectorOption[] = [];
|
const jsonDataOptions: IVariableSelectorOption[] = [];
|
||||||
for (const propertyName of Object.keys(outputData.json)) {
|
for (const propertyName of Object.keys(outputData.json)) {
|
||||||
jsonDataOptions.push.apply(
|
jsonDataOptions.push(
|
||||||
jsonDataOptions,
|
...jsonDataToFilterOption(
|
||||||
this.jsonDataToFilterOption(
|
|
||||||
outputData.json[propertyName],
|
outputData.json[propertyName],
|
||||||
jsonPropertyPrefix,
|
jsonPropertyPrefix,
|
||||||
propertyName,
|
propertyName,
|
||||||
@@ -419,7 +383,7 @@ export default defineComponent({
|
|||||||
if (jsonDataOptions.length) {
|
if (jsonDataOptions.length) {
|
||||||
returnData.push({
|
returnData.push({
|
||||||
name: 'JSON',
|
name: 'JSON',
|
||||||
options: this.sortOptions(jsonDataOptions),
|
options: sortOptions(jsonDataOptions),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -456,7 +420,7 @@ export default defineComponent({
|
|||||||
binaryData.push({
|
binaryData.push({
|
||||||
name: dataPropertyName,
|
name: dataPropertyName,
|
||||||
key: `${binaryPropertyPrefix}.${dataPropertyName}`,
|
key: `${binaryPropertyPrefix}.${dataPropertyName}`,
|
||||||
options: this.sortOptions(binaryPropertyData),
|
options: sortOptions(binaryPropertyData),
|
||||||
allowParentSelect: true,
|
allowParentSelect: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -465,15 +429,16 @@ export default defineComponent({
|
|||||||
returnData.push({
|
returnData.push({
|
||||||
name: 'Binary',
|
name: 'Binary',
|
||||||
key: binaryPropertyPrefix,
|
key: binaryPropertyPrefix,
|
||||||
options: this.sortOptions(binaryData),
|
options: sortOptions(binaryData),
|
||||||
allowParentSelect: true,
|
allowParentSelect: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
}
|
||||||
getNodeContext(
|
|
||||||
|
function getNodeContext(
|
||||||
workflow: Workflow,
|
workflow: Workflow,
|
||||||
runExecutionData: IRunExecutionData | null,
|
runExecutionData: IRunExecutionData | null,
|
||||||
parentNode: string[],
|
parentNode: string[],
|
||||||
@@ -485,16 +450,16 @@ export default defineComponent({
|
|||||||
const runIndex = 0;
|
const runIndex = 0;
|
||||||
const returnData: IVariableSelectorOption[] = [];
|
const returnData: IVariableSelectorOption[] = [];
|
||||||
|
|
||||||
if (this.activeNode === null) {
|
if (activeNode.value === null) {
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeConnection = this.workflow.getNodeConnectionIndexes(
|
const nodeConnection = workflow.getNodeConnectionIndexes(
|
||||||
this.activeNode.name,
|
activeNode.value.name,
|
||||||
parentNode[0],
|
parentNode[0],
|
||||||
inputName,
|
inputName,
|
||||||
);
|
);
|
||||||
const connectionInputData = this.workflowHelpers.connectionInputData(
|
const connectionInputData = workflowHelpers.connectionInputData(
|
||||||
parentNode,
|
parentNode,
|
||||||
nodeName,
|
nodeName,
|
||||||
inputName,
|
inputName,
|
||||||
@@ -532,7 +497,6 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
const proxy = dataProxy.getDataProxy();
|
const proxy = dataProxy.getDataProxy();
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const nodeContext = proxy.$node[nodeName].context as IContextObject;
|
const nodeContext = proxy.$node[nodeName].context as IContextObject;
|
||||||
for (const key of Object.keys(nodeContext)) {
|
for (const key of Object.keys(nodeContext)) {
|
||||||
if (filterText !== undefined && key.toLowerCase().indexOf(filterText) === -1) {
|
if (filterText !== undefined && key.toLowerCase().indexOf(filterText) === -1) {
|
||||||
@@ -543,13 +507,13 @@ export default defineComponent({
|
|||||||
returnData.push({
|
returnData.push({
|
||||||
name: key,
|
name: key,
|
||||||
key: `$('${escapeMappingString(nodeName)}').context['${escapeMappingString(key)}']`,
|
key: `$('${escapeMappingString(nodeName)}').context['${escapeMappingString(key)}']`,
|
||||||
// @ts-ignore
|
|
||||||
value: nodeContext[key],
|
value: nodeContext[key],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the node parameters with values
|
* Returns all the node parameters with values
|
||||||
*
|
*
|
||||||
@@ -558,13 +522,13 @@ export default defineComponent({
|
|||||||
* @param {string} [skipParameter] Parameter to skip
|
* @param {string} [skipParameter] Parameter to skip
|
||||||
* @param {string} [filterText] Filter text for parameters
|
* @param {string} [filterText] Filter text for parameters
|
||||||
*/
|
*/
|
||||||
getNodeParameters(
|
function getNodeParameters(
|
||||||
nodeName: string,
|
nodeName: string,
|
||||||
path: string,
|
path: string,
|
||||||
skipParameter?: string,
|
skipParameter?: string,
|
||||||
filterText?: string,
|
filterText?: string,
|
||||||
): IVariableSelectorOption[] | null {
|
): IVariableSelectorOption[] | null {
|
||||||
const node = this.workflow.getNode(nodeName);
|
const node = workflow.value.getNode(nodeName);
|
||||||
if (node === null) {
|
if (node === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -581,9 +545,8 @@ export default defineComponent({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
returnParameters.push.apply(
|
returnParameters.push(
|
||||||
returnParameters,
|
...jsonDataToFilterOption(
|
||||||
this.jsonDataToFilterOption(
|
|
||||||
node.parameters[parameterName],
|
node.parameters[parameterName],
|
||||||
path,
|
path,
|
||||||
parameterName,
|
parameterName,
|
||||||
@@ -596,17 +559,18 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return returnParameters;
|
return returnParameters;
|
||||||
},
|
}
|
||||||
getFilterResults(filterText: string, itemIndex: number): IVariableSelectorOption[] {
|
|
||||||
|
function getFilterResults(filterText: string, itemIndex: number): IVariableSelectorOption[] {
|
||||||
const inputName = NodeConnectionType.Main;
|
const inputName = NodeConnectionType.Main;
|
||||||
|
|
||||||
if (this.activeNode === null) {
|
if (activeNode.value === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const executionData = this.workflowsStore.getWorkflowExecution;
|
const executionData = workflowsStore.getWorkflowExecution;
|
||||||
let parentNode = this.workflow.getParentNodes(this.activeNode.name, inputName, 1);
|
let parentNode = workflow.value.getParentNodes(activeNode.value.name, inputName, 1);
|
||||||
let runData = this.workflowsStore.getWorkflowRunData;
|
let runData = workflowsStore.getWorkflowRunData;
|
||||||
|
|
||||||
if (runData === null) {
|
if (runData === null) {
|
||||||
runData = {};
|
runData = {};
|
||||||
@@ -625,17 +589,17 @@ export default defineComponent({
|
|||||||
if (executionData?.data !== undefined) {
|
if (executionData?.data !== undefined) {
|
||||||
const runExecutionData: IRunExecutionData = executionData.data;
|
const runExecutionData: IRunExecutionData = executionData.data;
|
||||||
|
|
||||||
tempOptions = this.getNodeContext(
|
tempOptions = getNodeContext(
|
||||||
this.workflow,
|
workflow.value,
|
||||||
runExecutionData,
|
runExecutionData,
|
||||||
parentNode,
|
parentNode,
|
||||||
this.activeNode.name,
|
activeNode.value.name,
|
||||||
filterText,
|
filterText,
|
||||||
) as IVariableSelectorOption[];
|
) as IVariableSelectorOption[];
|
||||||
if (tempOptions.length) {
|
if (tempOptions.length) {
|
||||||
currentNodeData.push({
|
currentNodeData.push({
|
||||||
name: 'Context',
|
name: 'Context',
|
||||||
options: this.sortOptions(tempOptions),
|
options: sortOptions(tempOptions),
|
||||||
} as IVariableSelectorOption);
|
} as IVariableSelectorOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,27 +609,29 @@ export default defineComponent({
|
|||||||
if (parentNode.length) {
|
if (parentNode.length) {
|
||||||
// If the node has an input node add the input data
|
// If the node has an input node add the input data
|
||||||
|
|
||||||
let ndvInputNodeName = this.ndvStore.ndvInputNodeName;
|
let ndvInputNodeName = ndvStore.ndvInputNodeName;
|
||||||
if (!ndvInputNodeName) {
|
if (!ndvInputNodeName) {
|
||||||
// If no input node is set use the first parent one
|
// If no input node is set use the first parent one
|
||||||
// this is imporant for config-nodes which do not have
|
// this is important for config-nodes which do not have
|
||||||
// a main input
|
// a main input
|
||||||
ndvInputNodeName = parentNode[0];
|
ndvInputNodeName = parentNode[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeInputParentNode = parentNode.find((node) => node === ndvInputNodeName)!;
|
const activeInputParentNode = parentNode.find((node) => node === ndvInputNodeName);
|
||||||
|
if (!activeInputParentNode) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
// Check from which output to read the data.
|
// Check from which output to read the data.
|
||||||
// Depends on how the nodes are connected.
|
// Depends on how the nodes are connected.
|
||||||
// (example "IF" node. If node is connected to "true" or to "false" output)
|
// (example "IF" node. If node is connected to "true" or to "false" output)
|
||||||
const nodeConnection = this.workflow.getNodeConnectionIndexes(
|
const nodeConnection = workflow.value.getNodeConnectionIndexes(
|
||||||
this.activeNode.name,
|
activeNode.value.name,
|
||||||
activeInputParentNode,
|
activeInputParentNode,
|
||||||
inputName,
|
inputName,
|
||||||
);
|
);
|
||||||
const outputIndex = nodeConnection === undefined ? 0 : nodeConnection.sourceIndex;
|
const outputIndex = nodeConnection === undefined ? 0 : nodeConnection.sourceIndex;
|
||||||
|
|
||||||
tempOutputData = this.getNodeRunDataOutput(
|
tempOutputData = getNodeRunDataOutput(
|
||||||
activeInputParentNode,
|
activeInputParentNode,
|
||||||
runData,
|
runData,
|
||||||
filterText,
|
filterText,
|
||||||
@@ -683,18 +649,18 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
parentNode.forEach((parentNodeName) => {
|
parentNode.forEach((parentNodeName) => {
|
||||||
const pinData = this.workflowsStore.pinDataByNodeName(parentNodeName);
|
const pinData = workflowsStore.pinDataByNodeName(parentNodeName);
|
||||||
|
|
||||||
if (pinData) {
|
if (pinData) {
|
||||||
const output = this.getNodePinDataOutput(parentNodeName, pinData, filterText, true);
|
const output = getNodePinDataOutput(parentNodeName, pinData, filterText, true);
|
||||||
|
|
||||||
pinDataOptions[0].options = pinDataOptions[0].options!.concat(
|
if (pinDataOptions[0].options) {
|
||||||
output?.[0]?.options ?? [],
|
pinDataOptions[0].options = pinDataOptions[0].options.concat(output?.[0]?.options ?? []);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (pinDataOptions[0].options!.length > 0) {
|
if ((pinDataOptions[0]?.options ?? []).length > 0) {
|
||||||
if (tempOutputData) {
|
if (tempOutputData) {
|
||||||
const jsonTempOutputData = tempOutputData.find((tempData) => tempData.name === 'JSON');
|
const jsonTempOutputData = tempOutputData.find((tempData) => tempData.name === 'JSON');
|
||||||
|
|
||||||
@@ -703,7 +669,7 @@ export default defineComponent({
|
|||||||
jsonTempOutputData.options = [];
|
jsonTempOutputData.options = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
(pinDataOptions[0].options || []).forEach((pinDataOption) => {
|
(pinDataOptions[0].options ?? []).forEach((pinDataOption) => {
|
||||||
const existingOptionIndex = jsonTempOutputData.options!.findIndex(
|
const existingOptionIndex = jsonTempOutputData.options!.findIndex(
|
||||||
(option) => option.name === pinDataOption.name,
|
(option) => option.name === pinDataOption.name,
|
||||||
);
|
);
|
||||||
@@ -726,7 +692,7 @@ export default defineComponent({
|
|||||||
// Data is reasonable small (< 100kb) so add it
|
// Data is reasonable small (< 100kb) so add it
|
||||||
currentNodeData.push({
|
currentNodeData.push({
|
||||||
name: 'Input Data',
|
name: 'Input Data',
|
||||||
options: this.sortOptions(tempOutputData),
|
options: sortOptions(tempOutputData),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Data is to large so do not add
|
// Data is to large so do not add
|
||||||
@@ -743,16 +709,16 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const initialPath = '$parameter';
|
const initialPath = '$parameter';
|
||||||
let skipParameter = this.path;
|
let skipParameter = props.path;
|
||||||
if (skipParameter.startsWith('parameters.')) {
|
if (skipParameter.startsWith('parameters.')) {
|
||||||
skipParameter = initialPath + skipParameter.substring(10);
|
skipParameter = initialPath + skipParameter.substring(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentNodeData.push({
|
currentNodeData.push({
|
||||||
name: this.$locale.baseText('variableSelector.parameters'),
|
name: i18n.baseText('variableSelector.parameters'),
|
||||||
options: this.sortOptions(
|
options: sortOptions(
|
||||||
this.getNodeParameters(
|
getNodeParameters(
|
||||||
this.activeNode.name,
|
activeNode.value.name,
|
||||||
initialPath,
|
initialPath,
|
||||||
skipParameter,
|
skipParameter,
|
||||||
filterText,
|
filterText,
|
||||||
@@ -761,8 +727,8 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
returnData.push({
|
returnData.push({
|
||||||
name: this.$locale.baseText('variableSelector.currentNode'),
|
name: i18n.baseText('variableSelector.currentNode'),
|
||||||
options: this.sortOptions(currentNodeData),
|
options: sortOptions(currentNodeData),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the input data
|
// Add the input data
|
||||||
@@ -772,9 +738,9 @@ export default defineComponent({
|
|||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
const allNodesData: IVariableSelectorOption[] = [];
|
const allNodesData: IVariableSelectorOption[] = [];
|
||||||
let nodeOptions: IVariableSelectorOption[];
|
let nodeOptions: IVariableSelectorOption[];
|
||||||
const upstreamNodes = this.workflow.getParentNodes(this.activeNode.name, inputName);
|
const upstreamNodes = workflow.value.getParentNodes(activeNode.value.name, inputName);
|
||||||
|
|
||||||
const workflowNodes = Object.entries(this.workflow.nodes);
|
const workflowNodes = Object.entries(workflow.value.nodes);
|
||||||
|
|
||||||
// Sort the nodes according to their position relative to the current node
|
// Sort the nodes according to their position relative to the current node
|
||||||
workflowNodes.sort((a, b) => {
|
workflowNodes.sort((a, b) => {
|
||||||
@@ -785,7 +751,7 @@ export default defineComponent({
|
|||||||
// Add the parameters of all nodes
|
// Add the parameters of all nodes
|
||||||
// TODO: Later have to make sure that no parameters can be referenced which have expression which use input-data (for nodes which are not parent nodes)
|
// TODO: Later have to make sure that no parameters can be referenced which have expression which use input-data (for nodes which are not parent nodes)
|
||||||
|
|
||||||
if (nodeName === this.activeNode.name) {
|
if (nodeName === activeNode.value.name) {
|
||||||
// Skip the current node as this one get added separately
|
// Skip the current node as this one get added separately
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -796,9 +762,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
nodeOptions = [
|
nodeOptions = [
|
||||||
{
|
{
|
||||||
name: this.$locale.baseText('variableSelector.parameters'),
|
name: i18n.baseText('variableSelector.parameters'),
|
||||||
options: this.sortOptions(
|
options: sortOptions(
|
||||||
this.getNodeParameters(
|
getNodeParameters(
|
||||||
nodeName,
|
nodeName,
|
||||||
`$('${escapeMappingString(nodeName)}').params`,
|
`$('${escapeMappingString(nodeName)}').params`,
|
||||||
undefined,
|
undefined,
|
||||||
@@ -811,9 +777,9 @@ export default defineComponent({
|
|||||||
if (executionData?.data !== undefined) {
|
if (executionData?.data !== undefined) {
|
||||||
const runExecutionData: IRunExecutionData = executionData.data;
|
const runExecutionData: IRunExecutionData = executionData.data;
|
||||||
|
|
||||||
parentNode = this.workflow.getParentNodes(nodeName, inputName, 1);
|
parentNode = workflow.value.getParentNodes(nodeName, inputName, 1);
|
||||||
tempOptions = this.getNodeContext(
|
tempOptions = getNodeContext(
|
||||||
this.workflow,
|
workflow.value,
|
||||||
runExecutionData,
|
runExecutionData,
|
||||||
parentNode,
|
parentNode,
|
||||||
nodeName,
|
nodeName,
|
||||||
@@ -822,8 +788,8 @@ export default defineComponent({
|
|||||||
if (tempOptions.length) {
|
if (tempOptions.length) {
|
||||||
nodeOptions = [
|
nodeOptions = [
|
||||||
{
|
{
|
||||||
name: this.$locale.baseText('variableSelector.context'),
|
name: i18n.baseText('variableSelector.context'),
|
||||||
options: this.sortOptions(tempOptions),
|
options: sortOptions(tempOptions),
|
||||||
} as IVariableSelectorOption,
|
} as IVariableSelectorOption,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -831,48 +797,75 @@ export default defineComponent({
|
|||||||
|
|
||||||
if (upstreamNodes.includes(nodeName)) {
|
if (upstreamNodes.includes(nodeName)) {
|
||||||
// If the node is an upstream node add also the output data which can be referenced
|
// If the node is an upstream node add also the output data which can be referenced
|
||||||
const pinData = this.workflowsStore.pinDataByNodeName(nodeName);
|
const pinData = workflowsStore.pinDataByNodeName(nodeName);
|
||||||
tempOutputData = pinData
|
tempOutputData = pinData
|
||||||
? this.getNodePinDataOutput(nodeName, pinData, filterText)
|
? getNodePinDataOutput(nodeName, pinData, filterText)
|
||||||
: this.getNodeRunDataOutput(nodeName, runData, filterText, itemIndex);
|
: getNodeRunDataOutput(nodeName, runData, filterText, itemIndex);
|
||||||
|
|
||||||
if (tempOutputData) {
|
if (tempOutputData) {
|
||||||
nodeOptions.push({
|
nodeOptions.push({
|
||||||
name: this.$locale.baseText('variableSelector.outputData'),
|
name: i18n.baseText('variableSelector.outputData'),
|
||||||
options: this.sortOptions(tempOutputData),
|
options: sortOptions(tempOutputData),
|
||||||
} as IVariableSelectorOption);
|
} as IVariableSelectorOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortNodeType = this.$locale.shortNodeType(node.type);
|
const shortNodeType = i18n.shortNodeType(node.type);
|
||||||
|
|
||||||
allNodesData.push({
|
allNodesData.push({
|
||||||
name: this.$locale.headerText({
|
name: i18n.headerText({
|
||||||
key: `headers.${shortNodeType}.displayName`,
|
key: `headers.${shortNodeType}.displayName`,
|
||||||
fallback: nodeName,
|
fallback: nodeName,
|
||||||
}),
|
}),
|
||||||
options: this.sortOptions(nodeOptions),
|
options: sortOptions(nodeOptions),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData.push({
|
returnData.push({
|
||||||
name: this.$locale.baseText('variableSelector.nodes'),
|
name: i18n.baseText('variableSelector.nodes'),
|
||||||
options: allNodesData,
|
options: allNodesData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove empty entries and return
|
// Remove empty entries and return
|
||||||
returnData = this.removeEmptyEntries(returnData) as IVariableSelectorOption[] | null;
|
returnData = removeEmptyEntries(returnData) as IVariableSelectorOption[] | null;
|
||||||
|
|
||||||
if (returnData === null) {
|
if (returnData === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
}
|
||||||
},
|
|
||||||
});
|
function forwardItemSelected(eventData: IVariableItemSelected) {
|
||||||
|
emit('itemSelected', eventData);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="variable-selector-wrapper" @keydown.stop>
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<n8n-input
|
||||||
|
ref="inputField"
|
||||||
|
v-model="variableFilter"
|
||||||
|
:placeholder="i18n.baseText('variableSelector.variableFilter')"
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
></n8n-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="result-wrapper">
|
||||||
|
<VariableSelectorItem
|
||||||
|
v-for="option in currentResults"
|
||||||
|
:key="option.key"
|
||||||
|
:item="option"
|
||||||
|
:extend-all="extendAll"
|
||||||
|
:redact-values="redactValues"
|
||||||
|
@item-selected="forwardItemSelected"
|
||||||
|
></VariableSelectorItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.variable-selector-wrapper {
|
.variable-selector-wrapper {
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
|
|||||||
@@ -59,68 +59,70 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import type { IVariableSelectorOption, IVariableItemSelected } from '@/Interface';
|
import type { IVariableSelectorOption, IVariableItemSelected } from '@/Interface';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
name: 'VariableSelectorItem',
|
allowParentSelect?: boolean;
|
||||||
props: ['allowParentSelect', 'extendAll', 'item', 'redactValues'],
|
extendAll?: boolean;
|
||||||
data() {
|
item: IVariableSelectorOption;
|
||||||
return {
|
redactValues?: boolean;
|
||||||
extended: false,
|
}>();
|
||||||
};
|
|
||||||
},
|
const emit = defineEmits<{
|
||||||
computed: {
|
itemSelected: [value: IVariableItemSelected];
|
||||||
itemAddOperations() {
|
}>();
|
||||||
|
|
||||||
|
const extended = ref(false);
|
||||||
|
|
||||||
|
const itemAddOperations = computed(() => {
|
||||||
const returnOptions = [
|
const returnOptions = [
|
||||||
{
|
{
|
||||||
command: 'raw',
|
command: 'raw',
|
||||||
displayName: 'Raw value',
|
displayName: 'Raw value',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
if (this.item.dataType === 'array') {
|
if (props.item.dataType === 'array') {
|
||||||
returnOptions.push({
|
returnOptions.push(
|
||||||
|
{
|
||||||
command: 'arrayLength',
|
command: 'arrayLength',
|
||||||
displayName: 'Length',
|
displayName: 'Length',
|
||||||
});
|
},
|
||||||
returnOptions.push({
|
{
|
||||||
command: 'arrayValues',
|
command: 'arrayValues',
|
||||||
displayName: 'Values',
|
displayName: 'Values',
|
||||||
});
|
},
|
||||||
} else if (this.item.dataType === 'object') {
|
);
|
||||||
returnOptions.push({
|
} else if (props.item.dataType === 'object') {
|
||||||
|
returnOptions.push(
|
||||||
|
{
|
||||||
command: 'objectKeys',
|
command: 'objectKeys',
|
||||||
displayName: 'Keys',
|
displayName: 'Keys',
|
||||||
});
|
},
|
||||||
returnOptions.push({
|
{
|
||||||
command: 'objectValues',
|
command: 'objectValues',
|
||||||
displayName: 'Values',
|
displayName: 'Values',
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnOptions;
|
return returnOptions;
|
||||||
},
|
});
|
||||||
},
|
|
||||||
mounted() {
|
onMounted(() => {
|
||||||
if (this.extended) return;
|
if (extended.value) return;
|
||||||
|
|
||||||
const shouldAutoExtend =
|
const shouldAutoExtend =
|
||||||
[
|
['Current Node', 'Input Data', 'Binary', 'JSON'].includes(props.item.name) &&
|
||||||
this.$locale.baseText('variableSelectorItem.currentNode'),
|
props.item.key === undefined;
|
||||||
this.$locale.baseText('variableSelectorItem.inputData'),
|
|
||||||
this.$locale.baseText('variableSelectorItem.binary'),
|
|
||||||
this.$locale.baseText('variableSelectorItem.json'),
|
|
||||||
].includes(this.item.name) && this.item.key === undefined;
|
|
||||||
|
|
||||||
if (shouldAutoExtend) {
|
if (shouldAutoExtend) {
|
||||||
this.extended = true;
|
extended.value = true;
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
methods: {
|
|
||||||
optionSelected(command: string, item: IVariableSelectorOption) {
|
const optionSelected = (command: string, item: IVariableSelectorOption) => {
|
||||||
// By default it is raw
|
let variable = item.key ?? '';
|
||||||
let variable = item.key;
|
|
||||||
if (command === 'arrayValues') {
|
if (command === 'arrayValues') {
|
||||||
variable = `${item.key}.join(', ')`;
|
variable = `${item.key}.join(', ')`;
|
||||||
} else if (command === 'arrayLength') {
|
} else if (command === 'arrayLength') {
|
||||||
@@ -130,16 +132,16 @@ export default defineComponent({
|
|||||||
} else if (command === 'objectValues') {
|
} else if (command === 'objectValues') {
|
||||||
variable = `Object.values(${item.key}).join(', ')`;
|
variable = `Object.values(${item.key}).join(', ')`;
|
||||||
}
|
}
|
||||||
this.$emit('itemSelected', { variable });
|
emit('itemSelected', { variable });
|
||||||
},
|
};
|
||||||
selectItem(item: IVariableSelectorOption) {
|
|
||||||
this.$emit('itemSelected', { variable: item.key });
|
const selectItem = (item: IVariableSelectorOption) => {
|
||||||
},
|
emit('itemSelected', { variable: item.key ?? '' });
|
||||||
forwardItemSelected(eventData: IVariableItemSelected) {
|
};
|
||||||
this.$emit('itemSelected', eventData);
|
|
||||||
},
|
const forwardItemSelected = (eventData: IVariableItemSelected) => {
|
||||||
},
|
emit('itemSelected', eventData);
|
||||||
});
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
Reference in New Issue
Block a user