mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-28 22:19:41 -08:00
refactor(editor): Migrate ndv.store
to composition API (#11574)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
This commit is contained in:
parent
aec372793b
commit
38fefff348
|
@ -1585,3 +1585,44 @@ export type ApiKey = {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InputPanel = {
|
||||||
|
displayMode: IRunDataDisplayMode;
|
||||||
|
nodeName?: string;
|
||||||
|
run?: number;
|
||||||
|
branch?: number;
|
||||||
|
data: {
|
||||||
|
isEmpty: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OutputPanel = {
|
||||||
|
branch?: number;
|
||||||
|
displayMode: IRunDataDisplayMode;
|
||||||
|
data: {
|
||||||
|
isEmpty: boolean;
|
||||||
|
};
|
||||||
|
editMode: {
|
||||||
|
enabled: boolean;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Draggable = {
|
||||||
|
isDragging: boolean;
|
||||||
|
type: string;
|
||||||
|
data: string;
|
||||||
|
dimensions: DOMRect | null;
|
||||||
|
activeTarget: { id: string; stickyPosition: null | XYPosition } | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MainPanelType = 'regular' | 'dragless' | 'inputless' | 'unknown' | 'wide';
|
||||||
|
|
||||||
|
export type MainPanelDimensions = Record<
|
||||||
|
MainPanelType,
|
||||||
|
{
|
||||||
|
relativeLeft: number;
|
||||||
|
relativeRight: number;
|
||||||
|
relativeWidth: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
|
@ -26,7 +26,8 @@ describe('InlineExpressionTip.vue', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockNdvState = {
|
mockNdvState = {
|
||||||
hasInputData: true,
|
hasInputData: true,
|
||||||
isNDVDataEmpty: vi.fn(() => true),
|
isInputPanelEmpty: true,
|
||||||
|
isOutputPanelEmpty: true,
|
||||||
setHighlightDraggables: vi.fn(),
|
setHighlightDraggables: vi.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -42,7 +43,8 @@ describe('InlineExpressionTip.vue', () => {
|
||||||
test('should show the drag-n-drop tip', async () => {
|
test('should show the drag-n-drop tip', async () => {
|
||||||
mockNdvState = {
|
mockNdvState = {
|
||||||
hasInputData: true,
|
hasInputData: true,
|
||||||
isNDVDataEmpty: vi.fn(() => false),
|
isInputPanelEmpty: false,
|
||||||
|
isOutputPanelEmpty: false,
|
||||||
focusedMappableInput: 'Some Input',
|
focusedMappableInput: 'Some Input',
|
||||||
setHighlightDraggables: vi.fn(),
|
setHighlightDraggables: vi.fn(),
|
||||||
};
|
};
|
||||||
|
@ -62,7 +64,8 @@ describe('InlineExpressionTip.vue', () => {
|
||||||
mockNdvState = {
|
mockNdvState = {
|
||||||
hasInputData: false,
|
hasInputData: false,
|
||||||
isInputParentOfActiveNode: true,
|
isInputParentOfActiveNode: true,
|
||||||
isNDVDataEmpty: vi.fn(() => false),
|
isInputPanelEmpty: false,
|
||||||
|
isOutputPanelEmpty: false,
|
||||||
focusedMappableInput: 'Some Input',
|
focusedMappableInput: 'Some Input',
|
||||||
setHighlightDraggables: vi.fn(),
|
setHighlightDraggables: vi.fn(),
|
||||||
};
|
};
|
||||||
|
@ -77,7 +80,8 @@ describe('InlineExpressionTip.vue', () => {
|
||||||
test('should show the correct tip for objects', async () => {
|
test('should show the correct tip for objects', async () => {
|
||||||
mockNdvState = {
|
mockNdvState = {
|
||||||
hasInputData: true,
|
hasInputData: true,
|
||||||
isNDVDataEmpty: vi.fn(() => false),
|
isInputPanelEmpty: false,
|
||||||
|
isOutputPanelEmpty: false,
|
||||||
focusedMappableInput: 'Some Input',
|
focusedMappableInput: 'Some Input',
|
||||||
setHighlightDraggables: vi.fn(),
|
setHighlightDraggables: vi.fn(),
|
||||||
};
|
};
|
||||||
|
@ -106,7 +110,8 @@ describe('InlineExpressionTip.vue', () => {
|
||||||
test('should show the correct tip for primitives', async () => {
|
test('should show the correct tip for primitives', async () => {
|
||||||
mockNdvState = {
|
mockNdvState = {
|
||||||
hasInputData: true,
|
hasInputData: true,
|
||||||
isNDVDataEmpty: vi.fn(() => false),
|
isInputPanelEmpty: false,
|
||||||
|
isOutputPanelEmpty: false,
|
||||||
focusedMappableInput: 'Some Input',
|
focusedMappableInput: 'Some Input',
|
||||||
setHighlightDraggables: vi.fn(),
|
setHighlightDraggables: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,7 @@ const canAddDotToExpression = ref(false);
|
||||||
const resolvedExpressionHasFields = ref(false);
|
const resolvedExpressionHasFields = ref(false);
|
||||||
|
|
||||||
const canDragToFocusedInput = computed(
|
const canDragToFocusedInput = computed(
|
||||||
() => !ndvStore.isNDVDataEmpty('input') && ndvStore.focusedMappableInput,
|
() => !ndvStore.isInputPanelEmpty && ndvStore.focusedMappableInput,
|
||||||
);
|
);
|
||||||
|
|
||||||
const emptyExpression = computed(() => props.unresolvedExpression.trim().length === 0);
|
const emptyExpression = computed(() => props.unresolvedExpression.trim().length === 0);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { ndvEventBus } from '@/event-bus';
|
import { ndvEventBus } from '@/event-bus';
|
||||||
import NDVFloatingNodes from '@/components/NDVFloatingNodes.vue';
|
import NDVFloatingNodes from '@/components/NDVFloatingNodes.vue';
|
||||||
import { useDebounce } from '@/composables/useDebounce';
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
import type { XYPosition } from '@/Interface';
|
import type { MainPanelType, XYPosition } from '@/Interface';
|
||||||
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue';
|
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const PANEL_WIDTH = 350;
|
||||||
const PANEL_WIDTH_LARGE = 420;
|
const PANEL_WIDTH_LARGE = 420;
|
||||||
const MIN_WINDOW_WIDTH = 2 * (SIDE_MARGIN + SIDE_PANELS_MARGIN) + MIN_PANEL_WIDTH;
|
const MIN_WINDOW_WIDTH = 2 * (SIDE_MARGIN + SIDE_PANELS_MARGIN) + MIN_PANEL_WIDTH;
|
||||||
|
|
||||||
const initialMainPanelWidth: { [key: string]: number } = {
|
const initialMainPanelWidth: Record<MainPanelType, number> = {
|
||||||
regular: MAIN_NODE_PANEL_WIDTH,
|
regular: MAIN_NODE_PANEL_WIDTH,
|
||||||
dragless: MAIN_NODE_PANEL_WIDTH,
|
dragless: MAIN_NODE_PANEL_WIDTH,
|
||||||
unknown: MAIN_NODE_PANEL_WIDTH,
|
unknown: MAIN_NODE_PANEL_WIDTH,
|
||||||
|
@ -106,22 +106,16 @@ watch(containerWidth, (width) => {
|
||||||
setPositions(mainPanelDimensions.value.relativeLeft);
|
setPositions(mainPanelDimensions.value.relativeLeft);
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentNodePaneType = computed((): string => {
|
const currentNodePaneType = computed((): MainPanelType => {
|
||||||
if (!hasInputSlot.value) return 'inputless';
|
if (!hasInputSlot.value) return 'inputless';
|
||||||
if (!props.isDraggable) return 'dragless';
|
if (!props.isDraggable) return 'dragless';
|
||||||
if (props.nodeType === null) return 'unknown';
|
if (props.nodeType === null) return 'unknown';
|
||||||
return props.nodeType.parameterPane ?? 'regular';
|
return props.nodeType.parameterPane ?? 'regular';
|
||||||
});
|
});
|
||||||
|
|
||||||
const mainPanelDimensions = computed(
|
const mainPanelDimensions = computed(() => {
|
||||||
(): {
|
return ndvStore.mainPanelDimensions[currentNodePaneType.value];
|
||||||
relativeWidth: number;
|
});
|
||||||
relativeLeft: number;
|
|
||||||
relativeRight: number;
|
|
||||||
} => {
|
|
||||||
return ndvStore.getMainPanelDimensions(currentNodePaneType.value);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const calculatedPositions = computed(
|
const calculatedPositions = computed(
|
||||||
(): { inputPanelRelativeRight: number; outputPanelRelativeLeft: number } => {
|
(): { inputPanelRelativeRight: number; outputPanelRelativeLeft: number } => {
|
||||||
|
|
|
@ -316,7 +316,7 @@ async function onClick() {
|
||||||
codeGenerationInProgress.value = false;
|
codeGenerationInProgress.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChatNode.value || (isChatChild.value && ndvStore.isNDVDataEmpty('input'))) {
|
if (isChatNode.value || (isChatChild.value && ndvStore.isInputPanelEmpty)) {
|
||||||
ndvStore.setActiveNodeName(null);
|
ndvStore.setActiveNodeName(null);
|
||||||
nodeViewEventBus.emit('openChat');
|
nodeViewEventBus.emit('openChat');
|
||||||
} else if (isListeningForEvents.value) {
|
} else if (isListeningForEvents.value) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ const { isSubNodeType } = useNodeType({
|
||||||
});
|
});
|
||||||
const pinnedData = usePinnedData(activeNode, {
|
const pinnedData = usePinnedData(activeNode, {
|
||||||
runIndex: props.runIndex,
|
runIndex: props.runIndex,
|
||||||
displayMode: ndvStore.getPanelDisplayMode('output'),
|
displayMode: ndvStore.outputPanelDisplayMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
|
|
|
@ -54,7 +54,8 @@ describe('ParameterInput.vue', () => {
|
||||||
type: 'test',
|
type: 'test',
|
||||||
typeVersion: 1,
|
typeVersion: 1,
|
||||||
},
|
},
|
||||||
isNDVDataEmpty: vi.fn(() => false),
|
isInputPanelEmpty: false,
|
||||||
|
isOutputPanelEmpty: false,
|
||||||
};
|
};
|
||||||
mockNodeTypesState = {
|
mockNodeTypesState = {
|
||||||
allNodeTypes: [],
|
allNodeTypes: [],
|
||||||
|
|
|
@ -523,7 +523,7 @@ const isHtmlNode = computed(() => !!node.value && node.value.type === HTML_NODE_
|
||||||
const isInputTypeString = computed(() => props.parameter.type === 'string');
|
const isInputTypeString = computed(() => props.parameter.type === 'string');
|
||||||
const isInputTypeNumber = computed(() => props.parameter.type === 'number');
|
const isInputTypeNumber = computed(() => props.parameter.type === 'number');
|
||||||
|
|
||||||
const isInputDataEmpty = computed(() => ndvStore.isNDVDataEmpty('input'));
|
const isInputDataEmpty = computed(() => ndvStore.isInputPanelEmpty);
|
||||||
const isDropDisabled = computed(
|
const isDropDisabled = computed(
|
||||||
() =>
|
() =>
|
||||||
props.parameter.noDataExpression ||
|
props.parameter.noDataExpression ||
|
||||||
|
|
|
@ -185,12 +185,17 @@ const node = toRef(props, 'node');
|
||||||
|
|
||||||
const pinnedData = usePinnedData(node, {
|
const pinnedData = usePinnedData(node, {
|
||||||
runIndex: props.runIndex,
|
runIndex: props.runIndex,
|
||||||
displayMode: ndvStore.getPanelDisplayMode(props.paneType),
|
displayMode:
|
||||||
|
props.paneType === 'input' ? ndvStore.inputPanelDisplayMode : ndvStore.outputPanelDisplayMode,
|
||||||
});
|
});
|
||||||
const { isSubNodeType } = useNodeType({
|
const { isSubNodeType } = useNodeType({
|
||||||
node,
|
node,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const displayMode = computed(() =>
|
||||||
|
props.paneType === 'input' ? ndvStore.inputPanelDisplayMode : ndvStore.outputPanelDisplayMode,
|
||||||
|
);
|
||||||
|
|
||||||
const isReadOnlyRoute = computed(() => route.meta.readOnlyCanvas === true);
|
const isReadOnlyRoute = computed(() => route.meta.readOnlyCanvas === true);
|
||||||
const isWaitNodeWaiting = computed(
|
const isWaitNodeWaiting = computed(
|
||||||
() =>
|
() =>
|
||||||
|
@ -200,7 +205,6 @@ const isWaitNodeWaiting = computed(
|
||||||
);
|
);
|
||||||
|
|
||||||
const { activeNode } = storeToRefs(ndvStore);
|
const { activeNode } = storeToRefs(ndvStore);
|
||||||
const displayMode = computed(() => ndvStore.getPanelDisplayMode(props.paneType));
|
|
||||||
const nodeType = computed(() => {
|
const nodeType = computed(() => {
|
||||||
if (!node.value) return null;
|
if (!node.value) return null;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import type {
|
import type {
|
||||||
INodeUi,
|
Draggable,
|
||||||
|
InputPanel,
|
||||||
IRunDataDisplayMode,
|
IRunDataDisplayMode,
|
||||||
|
MainPanelDimensions,
|
||||||
|
MainPanelType,
|
||||||
NDVState,
|
NDVState,
|
||||||
NodePanelType,
|
NodePanelType,
|
||||||
|
OutputPanel,
|
||||||
TargetItem,
|
TargetItem,
|
||||||
XYPosition,
|
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import { useStorage } from '@/composables/useStorage';
|
import { useStorage } from '@/composables/useStorage';
|
||||||
import {
|
import {
|
||||||
|
@ -13,316 +16,411 @@ import {
|
||||||
LOCAL_STORAGE_TABLE_HOVER_IS_ONBOARDED,
|
LOCAL_STORAGE_TABLE_HOVER_IS_ONBOARDED,
|
||||||
STORES,
|
STORES,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import type { INodeExecutionData, INodeIssues } from 'n8n-workflow';
|
import type { INodeIssues } from 'n8n-workflow';
|
||||||
import { NodeConnectionType } from 'n8n-workflow';
|
import { NodeConnectionType } from 'n8n-workflow';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { useWorkflowsStore } from './workflows.store';
|
import { useWorkflowsStore } from './workflows.store';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
export const useNDVStore = defineStore(STORES.NDV, {
|
const DEFAULT_MAIN_PANEL_DIMENSIONS = {
|
||||||
state: (): NDVState => ({
|
relativeLeft: 1,
|
||||||
activeNodeName: null,
|
relativeRight: 1,
|
||||||
mainPanelDimensions: {},
|
relativeWidth: 1,
|
||||||
pushRef: '',
|
};
|
||||||
input: {
|
|
||||||
displayMode: 'schema',
|
export const useNDVStore = defineStore(STORES.NDV, () => {
|
||||||
nodeName: undefined,
|
const localStorageMappingIsOnboarded = useStorage(LOCAL_STORAGE_MAPPING_IS_ONBOARDED);
|
||||||
run: undefined,
|
const localStorageTableHoverIsOnboarded = useStorage(LOCAL_STORAGE_TABLE_HOVER_IS_ONBOARDED);
|
||||||
branch: undefined,
|
const localStorageAutoCompleteIsOnboarded = useStorage(LOCAL_STORAGE_AUTOCOMPLETE_IS_ONBOARDED);
|
||||||
data: {
|
|
||||||
isEmpty: true,
|
const activeNodeName = ref<string | null>(null);
|
||||||
},
|
const mainPanelDimensions = ref<MainPanelDimensions>({
|
||||||
|
unknown: { ...DEFAULT_MAIN_PANEL_DIMENSIONS },
|
||||||
|
regular: { ...DEFAULT_MAIN_PANEL_DIMENSIONS },
|
||||||
|
dragless: { ...DEFAULT_MAIN_PANEL_DIMENSIONS },
|
||||||
|
inputless: { ...DEFAULT_MAIN_PANEL_DIMENSIONS },
|
||||||
|
wide: { ...DEFAULT_MAIN_PANEL_DIMENSIONS },
|
||||||
|
});
|
||||||
|
const pushRef = ref('');
|
||||||
|
const input = ref<InputPanel>({
|
||||||
|
displayMode: 'schema',
|
||||||
|
nodeName: undefined,
|
||||||
|
run: undefined,
|
||||||
|
branch: undefined,
|
||||||
|
data: {
|
||||||
|
isEmpty: true,
|
||||||
},
|
},
|
||||||
output: {
|
});
|
||||||
displayMode: 'table',
|
const output = ref<OutputPanel>({
|
||||||
branch: undefined,
|
displayMode: 'table',
|
||||||
data: {
|
branch: undefined,
|
||||||
isEmpty: true,
|
data: {
|
||||||
},
|
isEmpty: true,
|
||||||
editMode: {
|
|
||||||
enabled: false,
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
focusedMappableInput: '',
|
editMode: {
|
||||||
focusedInputPath: '',
|
enabled: false,
|
||||||
mappingTelemetry: {},
|
value: '',
|
||||||
hoveringItem: null,
|
},
|
||||||
expressionOutputItemIndex: 0,
|
});
|
||||||
draggable: {
|
const focusedMappableInput = ref('');
|
||||||
|
const focusedInputPath = ref('');
|
||||||
|
const mappingTelemetry = ref<Record<string, string | number | boolean>>({});
|
||||||
|
const hoveringItem = ref<null | TargetItem>(null);
|
||||||
|
const expressionOutputItemIndex = ref(0);
|
||||||
|
const draggable = ref<Draggable>({
|
||||||
|
isDragging: false,
|
||||||
|
type: '',
|
||||||
|
data: '',
|
||||||
|
dimensions: null,
|
||||||
|
activeTarget: null,
|
||||||
|
});
|
||||||
|
const isMappingOnboarded = ref(localStorageMappingIsOnboarded.value === 'true');
|
||||||
|
const isTableHoverOnboarded = ref(localStorageTableHoverIsOnboarded.value === 'true');
|
||||||
|
|
||||||
|
const isAutocompleteOnboarded = ref(localStorageAutoCompleteIsOnboarded.value === 'true');
|
||||||
|
|
||||||
|
const highlightDraggables = ref(false);
|
||||||
|
|
||||||
|
const workflowsStore = useWorkflowsStore();
|
||||||
|
|
||||||
|
const activeNode = computed(() => {
|
||||||
|
return workflowsStore.getNodeByName(activeNodeName.value || '');
|
||||||
|
});
|
||||||
|
|
||||||
|
const ndvInputData = computed(() => {
|
||||||
|
const executionData = workflowsStore.getWorkflowExecution;
|
||||||
|
const inputNodeName: string | undefined = input.value.nodeName;
|
||||||
|
const inputRunIndex: number = input.value.run ?? 0;
|
||||||
|
const inputBranchIndex: number = input.value.branch ?? 0;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!executionData ||
|
||||||
|
!inputNodeName ||
|
||||||
|
inputRunIndex === undefined ||
|
||||||
|
inputBranchIndex === undefined
|
||||||
|
) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
executionData.data?.resultData?.runData?.[inputNodeName]?.[inputRunIndex]?.data?.main?.[
|
||||||
|
inputBranchIndex
|
||||||
|
] ?? []
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const ndvInputNodeName = computed(() => {
|
||||||
|
return input.value.nodeName;
|
||||||
|
});
|
||||||
|
|
||||||
|
const ndvInputDataWithPinnedData = computed(() => {
|
||||||
|
const data = ndvInputData.value;
|
||||||
|
return ndvInputNodeName.value
|
||||||
|
? (workflowsStore.pinDataByNodeName(ndvInputNodeName.value) ?? data)
|
||||||
|
: data;
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasInputData = computed(() => {
|
||||||
|
return ndvInputDataWithPinnedData.value.length > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputPanelDisplayMode = computed(() => input.value.displayMode);
|
||||||
|
|
||||||
|
const outputPanelDisplayMode = computed(() => output.value.displayMode);
|
||||||
|
|
||||||
|
const isDraggableDragging = computed(() => draggable.value.isDragging);
|
||||||
|
|
||||||
|
const draggableType = computed(() => draggable.value.type);
|
||||||
|
|
||||||
|
const draggableData = computed(() => draggable.value.data);
|
||||||
|
|
||||||
|
const canDraggableDrop = computed(() => draggable.value.activeTarget !== null);
|
||||||
|
|
||||||
|
const outputPanelEditMode = computed(() => output.value.editMode);
|
||||||
|
|
||||||
|
const draggableStickyPos = computed(() => draggable.value.activeTarget?.stickyPosition ?? null);
|
||||||
|
|
||||||
|
const ndvNodeInputNumber = computed(() => {
|
||||||
|
const returnData: { [nodeName: string]: number[] } = {};
|
||||||
|
const workflow = workflowsStore.getCurrentWorkflow();
|
||||||
|
const activeNodeConections = (
|
||||||
|
workflow.connectionsByDestinationNode[activeNode.value?.name || ''] ?? {}
|
||||||
|
).main;
|
||||||
|
|
||||||
|
if (!activeNodeConections || activeNodeConections.length < 2) return returnData;
|
||||||
|
|
||||||
|
for (const [index, connection] of activeNodeConections.entries()) {
|
||||||
|
for (const node of connection) {
|
||||||
|
if (!returnData[node.node]) {
|
||||||
|
returnData[node.node] = [];
|
||||||
|
}
|
||||||
|
returnData[node.node].push(index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnData;
|
||||||
|
});
|
||||||
|
|
||||||
|
const ndvInputRunIndex = computed(() => input.value.run);
|
||||||
|
|
||||||
|
const ndvInputBranchIndex = computed(() => input.value.branch);
|
||||||
|
|
||||||
|
const isInputPanelEmpty = computed(() => input.value.data.isEmpty);
|
||||||
|
|
||||||
|
const isOutputPanelEmpty = computed(() => output.value.data.isEmpty);
|
||||||
|
|
||||||
|
const isInputParentOfActiveNode = computed(() => {
|
||||||
|
const inputNodeName = ndvInputNodeName.value;
|
||||||
|
if (!activeNode.value || !inputNodeName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const workflow = workflowsStore.getCurrentWorkflow();
|
||||||
|
const parentNodes = workflow.getParentNodes(activeNode.value.name, NodeConnectionType.Main, 1);
|
||||||
|
return parentNodes.includes(inputNodeName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getHoveringItem = computed(() => {
|
||||||
|
if (isInputParentOfActiveNode.value) {
|
||||||
|
return hoveringItem.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const expressionTargetItem = computed(() => {
|
||||||
|
if (getHoveringItem.value) {
|
||||||
|
return getHoveringItem.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expressionOutputItemIndex.value && ndvInputNodeName.value) {
|
||||||
|
return {
|
||||||
|
nodeName: ndvInputNodeName.value,
|
||||||
|
runIndex: ndvInputRunIndex.value ?? 0,
|
||||||
|
outputIndex: ndvInputBranchIndex.value ?? 0,
|
||||||
|
itemIndex: expressionOutputItemIndex.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isNDVOpen = computed(() => activeNodeName.value !== null);
|
||||||
|
|
||||||
|
const setActiveNodeName = (nodeName: string | null): void => {
|
||||||
|
activeNodeName.value = nodeName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInputNodeName = (nodeName: string | undefined): void => {
|
||||||
|
input.value.nodeName = nodeName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInputRunIndex = (run?: number): void => {
|
||||||
|
input.value.run = run;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setMainPanelDimensions = (params: {
|
||||||
|
panelType: MainPanelType;
|
||||||
|
dimensions: { relativeLeft?: number; relativeRight?: number; relativeWidth?: number };
|
||||||
|
}): void => {
|
||||||
|
mainPanelDimensions.value[params.panelType] = {
|
||||||
|
...mainPanelDimensions.value[params.panelType],
|
||||||
|
...params.dimensions,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const setNDVPushRef = (): void => {
|
||||||
|
pushRef.value = `ndv-${uuid()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetNDVPushRef = (): void => {
|
||||||
|
pushRef.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPanelDisplayMode = (params: {
|
||||||
|
pane: NodePanelType;
|
||||||
|
mode: IRunDataDisplayMode;
|
||||||
|
}): void => {
|
||||||
|
if (params.pane === 'input') {
|
||||||
|
input.value.displayMode = params.mode;
|
||||||
|
} else {
|
||||||
|
output.value.displayMode = params.mode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setOutputPanelEditModeEnabled = (isEnabled: boolean): void => {
|
||||||
|
output.value.editMode.enabled = isEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setOutputPanelEditModeValue = (payload: string): void => {
|
||||||
|
output.value.editMode.value = payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setMappableNDVInputFocus = (paramName: string): void => {
|
||||||
|
focusedMappableInput.value = paramName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const draggableStartDragging = ({
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
dimensions,
|
||||||
|
}: { type: string; data: string; dimensions: DOMRect | null }): void => {
|
||||||
|
draggable.value = {
|
||||||
|
isDragging: true,
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
dimensions,
|
||||||
|
activeTarget: null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const draggableStopDragging = (): void => {
|
||||||
|
draggable.value = {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
type: '',
|
type: '',
|
||||||
data: '',
|
data: '',
|
||||||
dimensions: null,
|
dimensions: null,
|
||||||
activeTarget: null,
|
activeTarget: null,
|
||||||
},
|
};
|
||||||
isMappingOnboarded: useStorage(LOCAL_STORAGE_MAPPING_IS_ONBOARDED).value === 'true',
|
};
|
||||||
isTableHoverOnboarded: useStorage(LOCAL_STORAGE_TABLE_HOVER_IS_ONBOARDED).value === 'true',
|
|
||||||
isAutocompleteOnboarded: useStorage(LOCAL_STORAGE_AUTOCOMPLETE_IS_ONBOARDED).value === 'true',
|
|
||||||
highlightDraggables: false,
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
activeNode(): INodeUi | null {
|
|
||||||
const workflowsStore = useWorkflowsStore();
|
|
||||||
return workflowsStore.getNodeByName(this.activeNodeName || '');
|
|
||||||
},
|
|
||||||
ndvInputData(): INodeExecutionData[] {
|
|
||||||
const workflowsStore = useWorkflowsStore();
|
|
||||||
const executionData = workflowsStore.getWorkflowExecution;
|
|
||||||
const inputNodeName: string | undefined = this.input.nodeName;
|
|
||||||
const inputRunIndex: number = this.input.run ?? 0;
|
|
||||||
const inputBranchIndex: number = this.input.branch ?? 0;
|
|
||||||
|
|
||||||
if (
|
const setDraggableTarget = (target: NDVState['draggable']['activeTarget']): void => {
|
||||||
!executionData ||
|
draggable.value.activeTarget = target;
|
||||||
!inputNodeName ||
|
};
|
||||||
inputRunIndex === undefined ||
|
|
||||||
inputBranchIndex === undefined
|
|
||||||
) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
const setMappingTelemetry = (telemetry: { [key: string]: string | number | boolean }): void => {
|
||||||
executionData.data?.resultData?.runData?.[inputNodeName]?.[inputRunIndex]?.data?.main?.[
|
mappingTelemetry.value = { ...mappingTelemetry.value, ...telemetry };
|
||||||
inputBranchIndex
|
};
|
||||||
] ?? []
|
|
||||||
);
|
|
||||||
},
|
|
||||||
ndvInputDataWithPinnedData(): INodeExecutionData[] {
|
|
||||||
const data = this.ndvInputData;
|
|
||||||
return this.ndvInputNodeName
|
|
||||||
? (useWorkflowsStore().pinDataByNodeName(this.ndvInputNodeName) ?? data)
|
|
||||||
: data;
|
|
||||||
},
|
|
||||||
hasInputData(): boolean {
|
|
||||||
return this.ndvInputDataWithPinnedData.length > 0;
|
|
||||||
},
|
|
||||||
getPanelDisplayMode() {
|
|
||||||
return (panel: NodePanelType) => this[panel].displayMode;
|
|
||||||
},
|
|
||||||
inputPanelDisplayMode(): IRunDataDisplayMode {
|
|
||||||
return this.input.displayMode;
|
|
||||||
},
|
|
||||||
outputPanelDisplayMode(): IRunDataDisplayMode {
|
|
||||||
return this.output.displayMode;
|
|
||||||
},
|
|
||||||
isDraggableDragging(): boolean {
|
|
||||||
return this.draggable.isDragging;
|
|
||||||
},
|
|
||||||
draggableType(): string {
|
|
||||||
return this.draggable.type;
|
|
||||||
},
|
|
||||||
draggableData(): string {
|
|
||||||
return this.draggable.data;
|
|
||||||
},
|
|
||||||
canDraggableDrop(): boolean {
|
|
||||||
return this.draggable.activeTarget !== null;
|
|
||||||
},
|
|
||||||
outputPanelEditMode(): NDVState['output']['editMode'] {
|
|
||||||
return this.output.editMode;
|
|
||||||
},
|
|
||||||
getMainPanelDimensions() {
|
|
||||||
return (panelType: string) => {
|
|
||||||
const defaults = { relativeRight: 1, relativeLeft: 1, relativeWidth: 1 };
|
|
||||||
return { ...defaults, ...this.mainPanelDimensions[panelType] };
|
|
||||||
};
|
|
||||||
},
|
|
||||||
draggableStickyPos(): XYPosition | null {
|
|
||||||
return this.draggable.activeTarget?.stickyPosition ?? null;
|
|
||||||
},
|
|
||||||
ndvInputNodeName(): string | undefined {
|
|
||||||
return this.input.nodeName;
|
|
||||||
},
|
|
||||||
ndvInputRunIndex(): number | undefined {
|
|
||||||
return this.input.run;
|
|
||||||
},
|
|
||||||
ndvInputBranchIndex(): number | undefined {
|
|
||||||
return this.input.branch;
|
|
||||||
},
|
|
||||||
isNDVDataEmpty() {
|
|
||||||
return (panel: 'input' | 'output'): boolean => this[panel].data.isEmpty;
|
|
||||||
},
|
|
||||||
isInputParentOfActiveNode(): boolean {
|
|
||||||
const inputNodeName = this.ndvInputNodeName;
|
|
||||||
if (!this.activeNode || !inputNodeName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const workflow = useWorkflowsStore().getCurrentWorkflow();
|
|
||||||
const parentNodes = workflow.getParentNodes(this.activeNode.name, NodeConnectionType.Main, 1);
|
|
||||||
return parentNodes.includes(inputNodeName);
|
|
||||||
},
|
|
||||||
getHoveringItem(): TargetItem | null {
|
|
||||||
if (this.isInputParentOfActiveNode) {
|
|
||||||
return this.hoveringItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
const resetMappingTelemetry = (): void => {
|
||||||
},
|
mappingTelemetry.value = {};
|
||||||
expressionTargetItem(): TargetItem | null {
|
};
|
||||||
if (this.getHoveringItem) {
|
|
||||||
return this.getHoveringItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.expressionOutputItemIndex && this.ndvInputNodeName) {
|
const setHoveringItem = (item: TargetItem | null): void => {
|
||||||
return {
|
if (item) setTableHoverOnboarded();
|
||||||
nodeName: this.ndvInputNodeName,
|
hoveringItem.value = item;
|
||||||
runIndex: this.ndvInputRunIndex ?? 0,
|
};
|
||||||
outputIndex: this.ndvInputBranchIndex ?? 0,
|
|
||||||
itemIndex: this.expressionOutputItemIndex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
const setNDVBranchIndex = (e: { pane: NodePanelType; branchIndex: number }): void => {
|
||||||
},
|
if (e.pane === 'input') {
|
||||||
isNDVOpen(): boolean {
|
input.value.branch = e.branchIndex;
|
||||||
return this.activeNodeName !== null;
|
} else {
|
||||||
},
|
output.value.branch = e.branchIndex;
|
||||||
ndvNodeInputNumber() {
|
}
|
||||||
const returnData: { [nodeName: string]: number[] } = {};
|
};
|
||||||
const workflow = useWorkflowsStore().getCurrentWorkflow();
|
|
||||||
const activeNodeConections = (
|
|
||||||
workflow.connectionsByDestinationNode[this.activeNode?.name || ''] ?? {}
|
|
||||||
).main;
|
|
||||||
|
|
||||||
if (!activeNodeConections || activeNodeConections.length < 2) return returnData;
|
const setNDVPanelDataIsEmpty = (params: {
|
||||||
|
panel: NodePanelType;
|
||||||
|
isEmpty: boolean;
|
||||||
|
}): void => {
|
||||||
|
if (params.panel === 'input') {
|
||||||
|
input.value.data.isEmpty = params.isEmpty;
|
||||||
|
} else {
|
||||||
|
output.value.data.isEmpty = params.isEmpty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (const [index, connection] of activeNodeConections.entries()) {
|
const setMappingOnboarded = () => {
|
||||||
for (const node of connection) {
|
isMappingOnboarded.value = true;
|
||||||
if (!returnData[node.node]) {
|
localStorageMappingIsOnboarded.value = 'true';
|
||||||
returnData[node.node] = [];
|
};
|
||||||
}
|
|
||||||
returnData[node.node].push(index + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnData;
|
const setTableHoverOnboarded = () => {
|
||||||
},
|
isTableHoverOnboarded.value = true;
|
||||||
},
|
localStorageTableHoverIsOnboarded.value = 'true';
|
||||||
actions: {
|
};
|
||||||
setActiveNodeName(nodeName: string | null): void {
|
|
||||||
this.activeNodeName = nodeName;
|
const setAutocompleteOnboarded = () => {
|
||||||
},
|
isAutocompleteOnboarded.value = true;
|
||||||
setInputNodeName(nodeName: string | undefined): void {
|
localStorageAutoCompleteIsOnboarded.value = 'true';
|
||||||
this.input = {
|
};
|
||||||
...this.input,
|
|
||||||
nodeName,
|
const setHighlightDraggables = (highlight: boolean) => {
|
||||||
};
|
highlightDraggables.value = highlight;
|
||||||
},
|
};
|
||||||
setInputRunIndex(run?: number): void {
|
|
||||||
this.input = {
|
const updateNodeParameterIssues = (issues: INodeIssues): void => {
|
||||||
...this.input,
|
const activeNode = workflowsStore.getNodeByName(activeNodeName.value || '');
|
||||||
run,
|
|
||||||
};
|
if (activeNode) {
|
||||||
},
|
const nodeIndex = workflowsStore.workflow.nodes.findIndex((node) => {
|
||||||
setMainPanelDimensions(params: {
|
return node.name === activeNode.name;
|
||||||
panelType: string;
|
});
|
||||||
dimensions: { relativeLeft?: number; relativeRight?: number; relativeWidth?: number };
|
|
||||||
}): void {
|
workflowsStore.updateNodeAtIndex(nodeIndex, {
|
||||||
this.mainPanelDimensions = {
|
issues: {
|
||||||
...this.mainPanelDimensions,
|
...activeNode.issues,
|
||||||
[params.panelType]: {
|
...issues,
|
||||||
...this.mainPanelDimensions[params.panelType],
|
|
||||||
...params.dimensions,
|
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
},
|
}
|
||||||
setNDVPushRef(): void {
|
};
|
||||||
this.pushRef = `ndv-${uuid()}`;
|
|
||||||
},
|
|
||||||
resetNDVPushRef(): void {
|
|
||||||
this.pushRef = '';
|
|
||||||
},
|
|
||||||
setPanelDisplayMode(params: { pane: NodePanelType; mode: IRunDataDisplayMode }): void {
|
|
||||||
this[params.pane].displayMode = params.mode;
|
|
||||||
},
|
|
||||||
setOutputPanelEditModeEnabled(isEnabled: boolean): void {
|
|
||||||
this.output.editMode.enabled = isEnabled;
|
|
||||||
},
|
|
||||||
setOutputPanelEditModeValue(payload: string): void {
|
|
||||||
this.output.editMode.value = payload;
|
|
||||||
},
|
|
||||||
setMappableNDVInputFocus(paramName: string): void {
|
|
||||||
this.focusedMappableInput = paramName;
|
|
||||||
},
|
|
||||||
draggableStartDragging({
|
|
||||||
type,
|
|
||||||
data,
|
|
||||||
dimensions,
|
|
||||||
}: {
|
|
||||||
type: string;
|
|
||||||
data: string;
|
|
||||||
dimensions: DOMRect | null;
|
|
||||||
}): void {
|
|
||||||
this.draggable = {
|
|
||||||
isDragging: true,
|
|
||||||
type,
|
|
||||||
data,
|
|
||||||
dimensions,
|
|
||||||
activeTarget: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
draggableStopDragging(): void {
|
|
||||||
this.draggable = {
|
|
||||||
isDragging: false,
|
|
||||||
type: '',
|
|
||||||
data: '',
|
|
||||||
dimensions: null,
|
|
||||||
activeTarget: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
setDraggableTarget(target: NDVState['draggable']['activeTarget']): void {
|
|
||||||
this.draggable.activeTarget = target;
|
|
||||||
},
|
|
||||||
setMappingTelemetry(telemetry: { [key: string]: string | number | boolean }): void {
|
|
||||||
this.mappingTelemetry = { ...this.mappingTelemetry, ...telemetry };
|
|
||||||
},
|
|
||||||
resetMappingTelemetry(): void {
|
|
||||||
this.mappingTelemetry = {};
|
|
||||||
},
|
|
||||||
setHoveringItem(item: null | NDVState['hoveringItem']): void {
|
|
||||||
if (item) this.setTableHoverOnboarded();
|
|
||||||
this.hoveringItem = item;
|
|
||||||
},
|
|
||||||
setNDVBranchIndex(e: { pane: 'input' | 'output'; branchIndex: number }): void {
|
|
||||||
this[e.pane].branch = e.branchIndex;
|
|
||||||
},
|
|
||||||
setNDVPanelDataIsEmpty(payload: { panel: 'input' | 'output'; isEmpty: boolean }): void {
|
|
||||||
this[payload.panel].data.isEmpty = payload.isEmpty;
|
|
||||||
},
|
|
||||||
setMappingOnboarded() {
|
|
||||||
this.isMappingOnboarded = true;
|
|
||||||
useStorage(LOCAL_STORAGE_MAPPING_IS_ONBOARDED).value = 'true';
|
|
||||||
},
|
|
||||||
setTableHoverOnboarded() {
|
|
||||||
this.isTableHoverOnboarded = true;
|
|
||||||
useStorage(LOCAL_STORAGE_TABLE_HOVER_IS_ONBOARDED).value = 'true';
|
|
||||||
},
|
|
||||||
setAutocompleteOnboarded() {
|
|
||||||
this.isAutocompleteOnboarded = true;
|
|
||||||
useStorage(LOCAL_STORAGE_AUTOCOMPLETE_IS_ONBOARDED).value = 'true';
|
|
||||||
},
|
|
||||||
setHighlightDraggables(highlight: boolean) {
|
|
||||||
this.highlightDraggables = highlight;
|
|
||||||
},
|
|
||||||
updateNodeParameterIssues(issues: INodeIssues): void {
|
|
||||||
const workflowsStore = useWorkflowsStore();
|
|
||||||
const activeNode = workflowsStore.getNodeByName(this.activeNodeName || '');
|
|
||||||
|
|
||||||
if (activeNode) {
|
const setFocusedInputPath = (path: string) => {
|
||||||
const nodeIndex = workflowsStore.workflow.nodes.findIndex((node) => {
|
focusedInputPath.value = path;
|
||||||
return node.name === activeNode.name;
|
};
|
||||||
});
|
|
||||||
|
|
||||||
workflowsStore.updateNodeAtIndex(nodeIndex, {
|
return {
|
||||||
issues: {
|
activeNode,
|
||||||
...activeNode.issues,
|
ndvInputData,
|
||||||
...issues,
|
ndvInputNodeName,
|
||||||
},
|
ndvInputDataWithPinnedData,
|
||||||
});
|
hasInputData,
|
||||||
}
|
inputPanelDisplayMode,
|
||||||
},
|
outputPanelDisplayMode,
|
||||||
setFocusedInputPath(path: string) {
|
isDraggableDragging,
|
||||||
this.focusedInputPath = path;
|
draggableType,
|
||||||
},
|
draggableData,
|
||||||
},
|
canDraggableDrop,
|
||||||
|
outputPanelEditMode,
|
||||||
|
draggableStickyPos,
|
||||||
|
ndvNodeInputNumber,
|
||||||
|
ndvInputRunIndex,
|
||||||
|
ndvInputBranchIndex,
|
||||||
|
isInputParentOfActiveNode,
|
||||||
|
getHoveringItem,
|
||||||
|
expressionTargetItem,
|
||||||
|
isNDVOpen,
|
||||||
|
isInputPanelEmpty,
|
||||||
|
isOutputPanelEmpty,
|
||||||
|
focusedMappableInput,
|
||||||
|
isMappingOnboarded,
|
||||||
|
pushRef,
|
||||||
|
activeNodeName,
|
||||||
|
focusedInputPath,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
hoveringItem,
|
||||||
|
highlightDraggables,
|
||||||
|
mappingTelemetry,
|
||||||
|
draggable,
|
||||||
|
isAutocompleteOnboarded,
|
||||||
|
expressionOutputItemIndex,
|
||||||
|
isTableHoverOnboarded,
|
||||||
|
mainPanelDimensions,
|
||||||
|
setActiveNodeName,
|
||||||
|
setInputNodeName,
|
||||||
|
setInputRunIndex,
|
||||||
|
setMainPanelDimensions,
|
||||||
|
setNDVPushRef,
|
||||||
|
resetNDVPushRef,
|
||||||
|
setPanelDisplayMode,
|
||||||
|
setOutputPanelEditModeEnabled,
|
||||||
|
setOutputPanelEditModeValue,
|
||||||
|
setMappableNDVInputFocus,
|
||||||
|
draggableStartDragging,
|
||||||
|
draggableStopDragging,
|
||||||
|
setDraggableTarget,
|
||||||
|
setMappingTelemetry,
|
||||||
|
resetMappingTelemetry,
|
||||||
|
setHoveringItem,
|
||||||
|
setNDVBranchIndex,
|
||||||
|
setNDVPanelDataIsEmpty,
|
||||||
|
setMappingOnboarded,
|
||||||
|
setTableHoverOnboarded,
|
||||||
|
setAutocompleteOnboarded,
|
||||||
|
setHighlightDraggables,
|
||||||
|
updateNodeParameterIssues,
|
||||||
|
setFocusedInputPath,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue