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