2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
import Vue from 'vue';
|
|
|
|
import Vuex from 'vuex';
|
|
|
|
|
2021-09-21 10:38:24 -07:00
|
|
|
import { PLACEHOLDER_EMPTY_WORKFLOW_ID, DEFAULT_NODETYPE_VERSION } from '@/constants';
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
import {
|
|
|
|
IConnection,
|
|
|
|
IConnections,
|
|
|
|
ICredentialType,
|
2020-09-30 06:50:43 -07:00
|
|
|
IDataObject,
|
2019-06-23 03:35:23 -07:00
|
|
|
INodeConnections,
|
|
|
|
INodeIssueData,
|
|
|
|
INodeTypeDescription,
|
|
|
|
IRunData,
|
|
|
|
ITaskData,
|
|
|
|
IWorkflowSettings,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
|
|
|
import {
|
|
|
|
ICredentialsResponse,
|
|
|
|
IExecutionResponse,
|
2019-07-24 05:25:30 -07:00
|
|
|
IExecutionsCurrentSummaryExtended,
|
2021-05-29 11:31:21 -07:00
|
|
|
IRootState,
|
2021-04-09 13:44:53 -07:00
|
|
|
IMenuItem,
|
2019-06-23 03:35:23 -07:00
|
|
|
INodeUi,
|
|
|
|
INodeUpdatePropertiesInformation,
|
2021-04-09 13:44:53 -07:00
|
|
|
IPushDataExecutionFinished,
|
|
|
|
IPushDataNodeExecuteAfter,
|
2019-06-23 03:35:23 -07:00
|
|
|
IUpdateInformation,
|
2021-04-09 13:44:53 -07:00
|
|
|
IWorkflowDb,
|
2019-06-23 03:35:23 -07:00
|
|
|
XYPositon,
|
2021-05-29 11:31:21 -07:00
|
|
|
IRestApiContext,
|
2019-06-23 03:35:23 -07:00
|
|
|
} from './Interface';
|
|
|
|
|
2021-09-11 01:15:36 -07:00
|
|
|
import credentials from './modules/credentials';
|
2021-05-29 11:31:21 -07:00
|
|
|
import tags from './modules/tags';
|
|
|
|
import ui from './modules/ui';
|
|
|
|
import workflows from './modules/workflows';
|
2021-07-22 01:22:17 -07:00
|
|
|
import versions from './modules/versions';
|
2021-05-29 11:31:21 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
Vue.use(Vuex);
|
|
|
|
|
2021-05-29 11:31:21 -07:00
|
|
|
const state: IRootState = {
|
|
|
|
activeExecutions: [],
|
|
|
|
activeWorkflows: [],
|
|
|
|
activeActions: [],
|
|
|
|
activeNode: null,
|
|
|
|
// @ts-ignore
|
|
|
|
baseUrl: process.env.VUE_APP_URL_BASE_API ? process.env.VUE_APP_URL_BASE_API : (window.BASE_PATH === '/%BASE_PATH%/' ? '/' : window.BASE_PATH),
|
|
|
|
endpointWebhook: 'webhook',
|
|
|
|
endpointWebhookTest: 'webhook-test',
|
|
|
|
executionId: null,
|
|
|
|
executingNode: '',
|
|
|
|
executionWaitingForWebhook: false,
|
|
|
|
pushConnectionActive: true,
|
|
|
|
saveDataErrorExecution: 'all',
|
|
|
|
saveDataSuccessExecution: 'all',
|
|
|
|
saveManualExecutions: false,
|
|
|
|
timezone: 'America/New_York',
|
|
|
|
stateIsDirty: false,
|
|
|
|
executionTimeout: -1,
|
|
|
|
maxExecutionTimeout: Number.MAX_SAFE_INTEGER,
|
|
|
|
versionCli: '0.0.0',
|
|
|
|
oauthCallbackUrls: {},
|
|
|
|
n8nMetadata: {},
|
|
|
|
workflowExecutionData: null,
|
|
|
|
lastSelectedNode: null,
|
|
|
|
lastSelectedNodeOutputIndex: null,
|
|
|
|
nodeIndex: [],
|
|
|
|
nodeTypes: [],
|
|
|
|
nodeViewOffsetPosition: [0, 0],
|
|
|
|
nodeViewMoveInProgress: false,
|
|
|
|
selectedNodes: [],
|
|
|
|
sessionId: Math.random().toString(36).substring(2, 15),
|
|
|
|
urlBaseWebhook: 'http://localhost:5678/',
|
|
|
|
workflow: {
|
|
|
|
id: PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
|
|
|
name: '',
|
|
|
|
active: false,
|
|
|
|
createdAt: -1,
|
|
|
|
updatedAt: -1,
|
|
|
|
connections: {},
|
|
|
|
nodes: [],
|
|
|
|
settings: {},
|
|
|
|
tags: [],
|
|
|
|
},
|
|
|
|
sidebarMenuItems: [],
|
2021-07-22 01:22:17 -07:00
|
|
|
instanceId: '',
|
2021-05-29 11:31:21 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const modules = {
|
2021-09-11 01:15:36 -07:00
|
|
|
credentials,
|
2021-05-29 11:31:21 -07:00
|
|
|
tags,
|
|
|
|
workflows,
|
2021-07-22 01:22:17 -07:00
|
|
|
versions,
|
2021-09-11 01:15:36 -07:00
|
|
|
ui,
|
2021-05-29 11:31:21 -07:00
|
|
|
};
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
export const store = new Vuex.Store({
|
|
|
|
strict: process.env.NODE_ENV !== 'production',
|
2021-05-29 11:31:21 -07:00
|
|
|
modules,
|
|
|
|
state,
|
2019-06-23 03:35:23 -07:00
|
|
|
mutations: {
|
|
|
|
// Active Actions
|
|
|
|
addActiveAction (state, action: string) {
|
|
|
|
if (!state.activeActions.includes(action)) {
|
|
|
|
state.activeActions.push(action);
|
|
|
|
}
|
|
|
|
},
|
2020-09-01 07:06:08 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
removeActiveAction (state, action: string) {
|
|
|
|
const actionIndex = state.activeActions.indexOf(action);
|
|
|
|
if (actionIndex !== -1) {
|
|
|
|
state.activeActions.splice(actionIndex, 1);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-07-24 05:25:30 -07:00
|
|
|
// Active Executions
|
|
|
|
addActiveExecution (state, newActiveExecution: IExecutionsCurrentSummaryExtended) {
|
|
|
|
// Check if the execution exists already
|
|
|
|
const activeExecution = state.activeExecutions.find(execution => {
|
2021-02-13 11:40:27 -08:00
|
|
|
return execution.id === newActiveExecution.id;
|
2019-07-24 05:25:30 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
if (activeExecution !== undefined) {
|
|
|
|
// Exists already so no need to add it again
|
|
|
|
if (activeExecution.workflowName === undefined) {
|
|
|
|
activeExecution.workflowName = newActiveExecution.workflowName;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state.activeExecutions.unshift(newActiveExecution);
|
|
|
|
},
|
|
|
|
finishActiveExecution (state, finishedActiveExecution: IPushDataExecutionFinished) {
|
|
|
|
// Find the execution to set to finished
|
|
|
|
const activeExecution = state.activeExecutions.find(execution => {
|
2021-02-13 11:40:27 -08:00
|
|
|
return execution.id === finishedActiveExecution.executionId;
|
2019-07-24 05:25:30 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
if (activeExecution === undefined) {
|
|
|
|
// The execution could not be found
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-13 11:40:27 -08:00
|
|
|
if (finishedActiveExecution.executionId !== undefined) {
|
|
|
|
Vue.set(activeExecution, 'id', finishedActiveExecution.executionId);
|
2019-07-24 05:25:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Vue.set(activeExecution, 'finished', finishedActiveExecution.data.finished);
|
|
|
|
Vue.set(activeExecution, 'stoppedAt', finishedActiveExecution.data.stoppedAt);
|
|
|
|
},
|
|
|
|
setActiveExecutions (state, newActiveExecutions: IExecutionsCurrentSummaryExtended[]) {
|
|
|
|
Vue.set(state, 'activeExecutions', newActiveExecutions);
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
// Active Workflows
|
|
|
|
setActiveWorkflows (state, newActiveWorkflows: string[]) {
|
|
|
|
state.activeWorkflows = newActiveWorkflows;
|
|
|
|
},
|
|
|
|
setWorkflowActive (state, workflowId: string) {
|
2020-12-11 10:22:24 -08:00
|
|
|
state.stateIsDirty = false;
|
2019-06-23 03:35:23 -07:00
|
|
|
const index = state.activeWorkflows.indexOf(workflowId);
|
|
|
|
if (index === -1) {
|
|
|
|
state.activeWorkflows.push(workflowId);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
setWorkflowInactive (state, workflowId: string) {
|
|
|
|
const index = state.activeWorkflows.indexOf(workflowId);
|
|
|
|
if (index !== -1) {
|
|
|
|
state.selectedNodes.splice(index, 1);
|
|
|
|
}
|
|
|
|
},
|
2020-09-01 07:06:08 -07:00
|
|
|
// Set state condition dirty or not
|
|
|
|
// ** Dirty: if current workflow state has been synchronized with database AKA has it been saved
|
|
|
|
setStateDirty (state, dirty : boolean) {
|
|
|
|
state.stateIsDirty = dirty;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
// Selected Nodes
|
|
|
|
addSelectedNode (state, node: INodeUi) {
|
|
|
|
state.selectedNodes.push(node);
|
|
|
|
},
|
|
|
|
removeNodeFromSelection (state, node: INodeUi) {
|
|
|
|
let index;
|
|
|
|
for (index in state.selectedNodes) {
|
|
|
|
if (state.selectedNodes[index].name === node.name) {
|
|
|
|
state.selectedNodes.splice(parseInt(index, 10), 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
resetSelectedNodes (state) {
|
|
|
|
Vue.set(state, 'selectedNodes', []);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Active
|
|
|
|
setActive (state, newActive: boolean) {
|
|
|
|
state.workflow.active = newActive;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Connections
|
2020-09-09 05:28:13 -07:00
|
|
|
addConnection (state, data) {
|
|
|
|
if (data.connection.length !== 2) {
|
2019-06-23 03:35:23 -07:00
|
|
|
// All connections need two entries
|
|
|
|
// TODO: Check if there is an error or whatever that is supposed to be returned
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-09 05:28:13 -07:00
|
|
|
if (data.setStateDirty === true) {
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
|
|
|
}
|
|
|
|
|
2020-09-09 05:28:13 -07:00
|
|
|
const sourceData: IConnection = data.connection[0];
|
|
|
|
const destinationData: IConnection = data.connection[1];
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
// Check if source node and type exist already and if not add them
|
|
|
|
if (!state.workflow.connections.hasOwnProperty(sourceData.node)) {
|
|
|
|
Vue.set(state.workflow.connections, sourceData.node, {});
|
|
|
|
}
|
|
|
|
if (!state.workflow.connections[sourceData.node].hasOwnProperty(sourceData.type)) {
|
|
|
|
Vue.set(state.workflow.connections[sourceData.node], sourceData.type, []);
|
|
|
|
}
|
|
|
|
if (state.workflow.connections[sourceData.node][sourceData.type].length < (sourceData.index + 1)) {
|
|
|
|
for (let i = state.workflow.connections[sourceData.node][sourceData.type].length; i <= sourceData.index; i++) {
|
|
|
|
state.workflow.connections[sourceData.node][sourceData.type].push([]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the same connection exists already
|
|
|
|
const checkProperties = ['index', 'node', 'type'];
|
|
|
|
let propertyName: string;
|
|
|
|
let connectionExists = false;
|
|
|
|
connectionLoop:
|
|
|
|
for (const existingConnection of state.workflow.connections[sourceData.node][sourceData.type][sourceData.index]) {
|
|
|
|
for (propertyName of checkProperties) {
|
|
|
|
if ((existingConnection as any)[propertyName] !== (destinationData as any)[propertyName]) { // tslint:disable-line:no-any
|
|
|
|
continue connectionLoop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
connectionExists = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the new connection if it does not exist already
|
|
|
|
if (connectionExists === false) {
|
|
|
|
state.workflow.connections[sourceData.node][sourceData.type][sourceData.index].push(destinationData);
|
|
|
|
}
|
2020-09-01 07:06:08 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
removeConnection (state, data) {
|
|
|
|
const sourceData = data.connection[0];
|
|
|
|
const destinationData = data.connection[1];
|
|
|
|
|
|
|
|
if (!state.workflow.connections.hasOwnProperty(sourceData.node)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!state.workflow.connections[sourceData.node].hasOwnProperty(sourceData.type)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (state.workflow.connections[sourceData.node][sourceData.type].length < (sourceData.index + 1)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
const connections = state.workflow.connections[sourceData.node][sourceData.type][sourceData.index];
|
|
|
|
for (const index in connections) {
|
|
|
|
if (connections[index].node === destinationData.node && connections[index].type === destinationData.type && connections[index].index === destinationData.index) {
|
|
|
|
// Found the connection to remove
|
|
|
|
connections.splice(parseInt(index, 10), 1);
|
|
|
|
}
|
|
|
|
}
|
2020-09-01 07:06:08 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
2020-09-01 07:06:08 -07:00
|
|
|
removeAllConnections (state, data) {
|
2020-10-26 11:28:32 -07:00
|
|
|
if (data && data.setStateDirty === true) {
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
state.workflow.connections = {};
|
|
|
|
},
|
|
|
|
removeAllNodeConnection (state, node: INodeUi) {
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-06-23 03:35:23 -07:00
|
|
|
// Remove all source connections
|
|
|
|
if (state.workflow.connections.hasOwnProperty(node.name)) {
|
|
|
|
delete state.workflow.connections[node.name];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove all destination connections
|
|
|
|
const indexesToRemove = [];
|
|
|
|
let sourceNode: string, type: string, sourceIndex: string, connectionIndex: string, connectionData: IConnection;
|
|
|
|
for (sourceNode of Object.keys(state.workflow.connections)) {
|
|
|
|
for (type of Object.keys(state.workflow.connections[sourceNode])) {
|
|
|
|
for (sourceIndex of Object.keys(state.workflow.connections[sourceNode][type])) {
|
|
|
|
indexesToRemove.length = 0;
|
|
|
|
for (connectionIndex of Object.keys(state.workflow.connections[sourceNode][type][parseInt(sourceIndex, 10)])) {
|
|
|
|
connectionData = state.workflow.connections[sourceNode][type][parseInt(sourceIndex, 10)][parseInt(connectionIndex, 10)];
|
|
|
|
if (connectionData.node === node.name) {
|
|
|
|
indexesToRemove.push(connectionIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
indexesToRemove.forEach((index) => {
|
|
|
|
state.workflow.connections[sourceNode][type][parseInt(sourceIndex, 10)].splice(parseInt(index, 10), 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
renameNodeSelectedAndExecution (state, nameData) {
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-06-23 03:35:23 -07:00
|
|
|
// If node has any WorkflowResultData rename also that one that the data
|
|
|
|
// does still get displayed also after node got renamed
|
|
|
|
if (state.workflowExecutionData !== null && state.workflowExecutionData.data.resultData.runData.hasOwnProperty(nameData.old)) {
|
|
|
|
state.workflowExecutionData.data.resultData.runData[nameData.new] = state.workflowExecutionData.data.resultData.runData[nameData.old];
|
|
|
|
delete state.workflowExecutionData.data.resultData.runData[nameData.old];
|
|
|
|
}
|
|
|
|
|
|
|
|
// In case the renamed node was last selected set it also there with the new name
|
|
|
|
if (state.lastSelectedNode === nameData.old) {
|
|
|
|
state.lastSelectedNode = nameData.new;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
resetAllNodesIssues (state) {
|
|
|
|
state.workflow.nodes.forEach((node) => {
|
|
|
|
node.issues = undefined;
|
|
|
|
});
|
2020-09-01 07:06:08 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
setNodeIssue (state, nodeIssueData: INodeIssueData) {
|
2020-09-01 07:06:08 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
const node = state.workflow.nodes.find(node => {
|
|
|
|
return node.name === nodeIssueData.node;
|
|
|
|
});
|
|
|
|
if (!node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeIssueData.value === null) {
|
|
|
|
// Remove the value if one exists
|
|
|
|
if (node.issues === undefined || node.issues[nodeIssueData.type] === undefined) {
|
|
|
|
// No values for type exist so nothing has to get removed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
Vue.delete(node.issues, nodeIssueData.type);
|
|
|
|
} else {
|
|
|
|
if (node.issues === undefined) {
|
|
|
|
Vue.set(node, 'issues', {});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/Overwrite the value
|
|
|
|
Vue.set(node.issues!, nodeIssueData.type, nodeIssueData.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Id
|
|
|
|
setWorkflowId (state, id: string) {
|
|
|
|
state.workflow.id = id;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Name
|
2020-09-09 05:28:13 -07:00
|
|
|
setWorkflowName (state, data) {
|
|
|
|
if (data.setStateDirty === true) {
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
|
|
|
}
|
2020-09-09 05:28:13 -07:00
|
|
|
state.workflow.name = data.newName;
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// Nodes
|
|
|
|
addNode (state, nodeData: INodeUi) {
|
|
|
|
if (!nodeData.hasOwnProperty('name')) {
|
|
|
|
// All nodes have to have a name
|
|
|
|
// TODO: Check if there is an error or whatever that is supposed to be returned
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state.workflow.nodes.push(nodeData);
|
|
|
|
},
|
|
|
|
removeNode (state, node: INodeUi) {
|
|
|
|
for (let i = 0; i < state.workflow.nodes.length; i++) {
|
|
|
|
if (state.workflow.nodes[i].name === node.name) {
|
|
|
|
state.workflow.nodes.splice(i, 1);
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-06-23 03:35:23 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-09-01 07:06:08 -07:00
|
|
|
removeAllNodes (state, data) {
|
|
|
|
if (data.setStateDirty === true) {
|
|
|
|
state.stateIsDirty = true;
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
state.workflow.nodes.splice(0, state.workflow.nodes.length);
|
|
|
|
},
|
|
|
|
updateNodeProperties (state, updateInformation: INodeUpdatePropertiesInformation) {
|
|
|
|
// Find the node that should be updated
|
|
|
|
const node = state.workflow.nodes.find(node => {
|
|
|
|
return node.name === updateInformation.name;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (node) {
|
|
|
|
for (const key of Object.keys(updateInformation.properties)) {
|
2020-09-02 06:26:17 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-06-23 03:35:23 -07:00
|
|
|
Vue.set(node, key, updateInformation.properties[key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2019-07-14 05:10:16 -07:00
|
|
|
setNodeValue (state, updateInformation: IUpdateInformation) {
|
2019-06-23 03:35:23 -07:00
|
|
|
// Find the node that should be updated
|
|
|
|
const node = state.workflow.nodes.find(node => {
|
|
|
|
return node.name === updateInformation.name;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (node === undefined || node === null) {
|
|
|
|
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
|
|
|
|
}
|
|
|
|
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-07-14 05:10:16 -07:00
|
|
|
Vue.set(node, updateInformation.key, updateInformation.value);
|
|
|
|
},
|
|
|
|
setNodeParameters (state, updateInformation: IUpdateInformation) {
|
|
|
|
// Find the node that should be updated
|
|
|
|
const node = state.workflow.nodes.find(node => {
|
|
|
|
return node.name === updateInformation.name;
|
|
|
|
});
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2019-07-14 05:10:16 -07:00
|
|
|
if (node === undefined || node === null) {
|
|
|
|
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
2019-07-14 05:10:16 -07:00
|
|
|
|
2020-09-01 07:06:08 -07:00
|
|
|
state.stateIsDirty = true;
|
2019-07-14 05:10:16 -07:00
|
|
|
Vue.set(node, 'parameters', updateInformation.value);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// Node-Index
|
|
|
|
addToNodeIndex (state, nodeName: string) {
|
|
|
|
state.nodeIndex.push(nodeName);
|
|
|
|
},
|
|
|
|
setNodeIndex (state, newData: { index: number, name: string | null}) {
|
|
|
|
state.nodeIndex[newData.index] = newData.name;
|
|
|
|
},
|
|
|
|
resetNodeIndex (state) {
|
|
|
|
Vue.set(state, 'nodeIndex', []);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Node-View
|
|
|
|
setNodeViewMoveInProgress (state, value: boolean) {
|
|
|
|
state.nodeViewMoveInProgress = value;
|
|
|
|
},
|
2020-09-09 05:28:13 -07:00
|
|
|
setNodeViewOffsetPosition (state, data) {
|
|
|
|
state.nodeViewOffsetPosition = data.newOffset;
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// Node-Types
|
|
|
|
setNodeTypes (state, nodeTypes: INodeTypeDescription[]) {
|
|
|
|
Vue.set(state, 'nodeTypes', nodeTypes);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Active Execution
|
|
|
|
setExecutingNode (state, executingNode: string) {
|
|
|
|
state.executingNode = executingNode;
|
|
|
|
},
|
|
|
|
setExecutionWaitingForWebhook (state, newWaiting: boolean) {
|
|
|
|
state.executionWaitingForWebhook = newWaiting;
|
|
|
|
},
|
|
|
|
setActiveExecutionId (state, executionId: string | null) {
|
|
|
|
state.executionId = executionId;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Push Connection
|
|
|
|
setPushConnectionActive (state, newActive: boolean) {
|
|
|
|
state.pushConnectionActive = newActive;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Webhooks
|
|
|
|
setUrlBaseWebhook (state, urlBaseWebhook: string) {
|
|
|
|
Vue.set(state, 'urlBaseWebhook', urlBaseWebhook);
|
|
|
|
},
|
|
|
|
setEndpointWebhook (state, endpointWebhook: string) {
|
|
|
|
Vue.set(state, 'endpointWebhook', endpointWebhook);
|
|
|
|
},
|
|
|
|
setEndpointWebhookTest (state, endpointWebhookTest: string) {
|
|
|
|
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
|
|
|
|
},
|
|
|
|
|
2019-07-14 05:10:16 -07:00
|
|
|
setSaveDataErrorExecution (state, newValue: string) {
|
2019-07-10 11:53:13 -07:00
|
|
|
Vue.set(state, 'saveDataErrorExecution', newValue);
|
|
|
|
},
|
2019-07-14 05:10:16 -07:00
|
|
|
setSaveDataSuccessExecution (state, newValue: string) {
|
2019-07-10 11:53:13 -07:00
|
|
|
Vue.set(state, 'saveDataSuccessExecution', newValue);
|
|
|
|
},
|
2019-07-10 09:06:26 -07:00
|
|
|
setSaveManualExecutions (state, saveManualExecutions: boolean) {
|
|
|
|
Vue.set(state, 'saveManualExecutions', saveManualExecutions);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
setTimezone (state, timezone: string) {
|
|
|
|
Vue.set(state, 'timezone', timezone);
|
|
|
|
},
|
2020-07-29 05:12:54 -07:00
|
|
|
setExecutionTimeout (state, executionTimeout: number) {
|
|
|
|
Vue.set(state, 'executionTimeout', executionTimeout);
|
|
|
|
},
|
|
|
|
setMaxExecutionTimeout (state, maxExecutionTimeout: number) {
|
|
|
|
Vue.set(state, 'maxExecutionTimeout', maxExecutionTimeout);
|
|
|
|
},
|
2021-07-22 01:22:17 -07:00
|
|
|
setVersionCli(state, version: string) {
|
2019-09-11 09:40:22 -07:00
|
|
|
Vue.set(state, 'versionCli', version);
|
|
|
|
},
|
2021-07-22 01:22:17 -07:00
|
|
|
setInstanceId(state, instanceId: string) {
|
|
|
|
Vue.set(state, 'instanceId', instanceId);
|
|
|
|
},
|
2020-09-30 06:50:43 -07:00
|
|
|
setOauthCallbackUrls(state, urls: IDataObject) {
|
|
|
|
Vue.set(state, 'oauthCallbackUrls', urls);
|
|
|
|
},
|
2021-01-19 14:48:30 -08:00
|
|
|
setN8nMetadata(state, metadata: IDataObject) {
|
|
|
|
Vue.set(state, 'n8nMetadata', metadata);
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
setActiveNode (state, nodeName: string) {
|
|
|
|
state.activeNode = nodeName;
|
|
|
|
},
|
|
|
|
|
|
|
|
setLastSelectedNode (state, nodeName: string) {
|
|
|
|
state.lastSelectedNode = nodeName;
|
|
|
|
},
|
|
|
|
|
2019-12-10 11:31:11 -08:00
|
|
|
setLastSelectedNodeOutputIndex (state, outputIndex: number | null) {
|
2019-12-10 06:39:14 -08:00
|
|
|
state.lastSelectedNodeOutputIndex = outputIndex;
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
setWorkflowExecutionData (state, workflowResultData: IExecutionResponse | null) {
|
|
|
|
state.workflowExecutionData = workflowResultData;
|
|
|
|
},
|
|
|
|
addNodeExecutionData (state, pushData: IPushDataNodeExecuteAfter): void {
|
|
|
|
if (state.workflowExecutionData === null) {
|
|
|
|
throw new Error('The "workflowExecutionData" is not initialized!');
|
|
|
|
}
|
|
|
|
if (state.workflowExecutionData.data.resultData.runData[pushData.nodeName] === undefined) {
|
|
|
|
Vue.set(state.workflowExecutionData.data.resultData.runData, pushData.nodeName, []);
|
|
|
|
}
|
|
|
|
state.workflowExecutionData.data.resultData.runData[pushData.nodeName].push(pushData.data);
|
|
|
|
},
|
|
|
|
|
|
|
|
setWorkflowSettings (state, workflowSettings: IWorkflowSettings) {
|
|
|
|
Vue.set(state.workflow, 'settings', workflowSettings);
|
|
|
|
},
|
|
|
|
|
2021-05-29 11:31:21 -07:00
|
|
|
setWorkflowTagIds (state, tags: string[]) {
|
|
|
|
Vue.set(state.workflow, 'tags', tags);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeWorkflowTagId (state, tagId: string) {
|
|
|
|
const tags = state.workflow.tags as string[];
|
|
|
|
const updated = tags.filter((id: string) => id !== tagId);
|
|
|
|
|
|
|
|
Vue.set(state.workflow, 'tags', updated);
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
// Workflow
|
|
|
|
setWorkflow (state, workflow: IWorkflowDb) {
|
|
|
|
Vue.set(state, 'workflow', workflow);
|
|
|
|
|
|
|
|
if (!state.workflow.hasOwnProperty('active')) {
|
|
|
|
Vue.set(state.workflow, 'active', false);
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('connections')) {
|
|
|
|
Vue.set(state.workflow, 'connections', {});
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('createdAt')) {
|
|
|
|
Vue.set(state.workflow, 'createdAt', -1);
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('updatedAt')) {
|
|
|
|
Vue.set(state.workflow, 'updatedAt', -1);
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('id')) {
|
|
|
|
Vue.set(state.workflow, 'id', PLACEHOLDER_EMPTY_WORKFLOW_ID);
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('nodes')) {
|
|
|
|
Vue.set(state.workflow, 'nodes', []);
|
|
|
|
}
|
|
|
|
if (!state.workflow.hasOwnProperty('settings')) {
|
|
|
|
Vue.set(state.workflow, 'settings', {});
|
|
|
|
}
|
|
|
|
},
|
2020-10-22 08:24:35 -07:00
|
|
|
|
|
|
|
updateNodeTypes (state, nodeTypes: INodeTypeDescription[]) {
|
2021-09-21 10:38:24 -07:00
|
|
|
const oldNodesToKeep = state.nodeTypes.filter(node => !nodeTypes.find(n => n.name === node.name && n.version === node.version));
|
|
|
|
const newNodesState = [...oldNodesToKeep, ...nodeTypes];
|
|
|
|
Vue.set(state, 'nodeTypes', newNodesState);
|
|
|
|
state.nodeTypes = newNodesState;
|
2020-10-22 08:24:35 -07:00
|
|
|
},
|
2021-04-09 13:44:53 -07:00
|
|
|
|
|
|
|
addSidebarMenuItems (state, menuItems: IMenuItem[]) {
|
|
|
|
const updated = state.sidebarMenuItems.concat(menuItems);
|
|
|
|
Vue.set(state, 'sidebarMenuItems', updated);
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
getters: {
|
|
|
|
|
|
|
|
isActionActive: (state) => (action: string): boolean => {
|
|
|
|
return state.activeActions.includes(action);
|
|
|
|
},
|
|
|
|
|
2019-07-24 05:25:30 -07:00
|
|
|
getActiveExecutions: (state): IExecutionsCurrentSummaryExtended[] => {
|
|
|
|
return state.activeExecutions;
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
getBaseUrl: (state): string => {
|
|
|
|
return state.baseUrl;
|
|
|
|
},
|
|
|
|
getRestUrl: (state): string => {
|
|
|
|
let endpoint = 'rest';
|
|
|
|
if (process.env.VUE_APP_ENDPOINT_REST) {
|
|
|
|
endpoint = process.env.VUE_APP_ENDPOINT_REST;
|
|
|
|
}
|
|
|
|
return `${state.baseUrl}${endpoint}`;
|
|
|
|
},
|
2021-05-29 11:31:21 -07:00
|
|
|
getRestApiContext(state): IRestApiContext {
|
|
|
|
let endpoint = 'rest';
|
|
|
|
if (process.env.VUE_APP_ENDPOINT_REST) {
|
|
|
|
endpoint = process.env.VUE_APP_ENDPOINT_REST;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
baseUrl: `${state.baseUrl}${endpoint}`,
|
|
|
|
sessionId: state.sessionId,
|
|
|
|
};
|
|
|
|
},
|
2020-05-12 02:27:07 -07:00
|
|
|
getWebhookBaseUrl: (state): string => {
|
|
|
|
return state.urlBaseWebhook;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
getWebhookUrl: (state): string => {
|
|
|
|
return `${state.urlBaseWebhook}${state.endpointWebhook}`;
|
|
|
|
},
|
|
|
|
getWebhookTestUrl: (state): string => {
|
|
|
|
return `${state.urlBaseWebhook}${state.endpointWebhookTest}`;
|
|
|
|
},
|
|
|
|
|
2020-09-01 07:06:08 -07:00
|
|
|
getStateIsDirty: (state) : boolean => {
|
|
|
|
return state.stateIsDirty;
|
|
|
|
},
|
|
|
|
|
2019-07-10 11:53:13 -07:00
|
|
|
saveDataErrorExecution: (state): string => {
|
|
|
|
return state.saveDataErrorExecution;
|
|
|
|
},
|
|
|
|
saveDataSuccessExecution: (state): string => {
|
|
|
|
return state.saveDataSuccessExecution;
|
|
|
|
},
|
2019-07-10 09:06:26 -07:00
|
|
|
saveManualExecutions: (state): boolean => {
|
|
|
|
return state.saveManualExecutions;
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
timezone: (state): string => {
|
|
|
|
return state.timezone;
|
|
|
|
},
|
2020-07-29 05:12:54 -07:00
|
|
|
executionTimeout: (state): number => {
|
|
|
|
return state.executionTimeout;
|
|
|
|
},
|
|
|
|
maxExecutionTimeout: (state): number => {
|
|
|
|
return state.maxExecutionTimeout;
|
|
|
|
},
|
2019-09-11 09:40:22 -07:00
|
|
|
versionCli: (state): string => {
|
|
|
|
return state.versionCli;
|
|
|
|
},
|
2020-09-30 06:50:43 -07:00
|
|
|
oauthCallbackUrls: (state): object => {
|
|
|
|
return state.oauthCallbackUrls;
|
|
|
|
},
|
2021-01-19 14:48:30 -08:00
|
|
|
n8nMetadata: (state): object => {
|
|
|
|
return state.n8nMetadata;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
// Push Connection
|
|
|
|
pushConnectionActive: (state): boolean => {
|
|
|
|
return state.pushConnectionActive;
|
|
|
|
},
|
|
|
|
sessionId: (state): string => {
|
|
|
|
return state.sessionId;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Active Workflows
|
|
|
|
getActiveWorkflows: (state): string[] => {
|
|
|
|
return state.activeWorkflows;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Node-Index
|
|
|
|
getNodeIndex: (state) => (nodeName: string): number => {
|
|
|
|
return state.nodeIndex.indexOf(nodeName);
|
|
|
|
},
|
|
|
|
getNodeNameByIndex: (state) => (index: number): string | null => {
|
|
|
|
return state.nodeIndex[index];
|
|
|
|
},
|
|
|
|
|
|
|
|
getNodeViewOffsetPosition: (state): XYPositon => {
|
|
|
|
return state.nodeViewOffsetPosition;
|
|
|
|
},
|
|
|
|
isNodeViewMoveInProgress: (state): boolean => {
|
|
|
|
return state.nodeViewMoveInProgress;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Selected Nodes
|
|
|
|
getSelectedNodes: (state): INodeUi[] => {
|
|
|
|
return state.selectedNodes;
|
|
|
|
},
|
|
|
|
isNodeSelected: (state) => (nodeName: string): boolean => {
|
|
|
|
let index;
|
|
|
|
for (index in state.selectedNodes) {
|
|
|
|
if (state.selectedNodes[index].name === nodeName) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
isActive: (state): boolean => {
|
|
|
|
return state.workflow.active;
|
|
|
|
},
|
|
|
|
allConnections: (state): IConnections => {
|
|
|
|
return state.workflow.connections;
|
|
|
|
},
|
|
|
|
// connectionsByNodeName: (state) => (nodeName: string): {[key: string]: Connection[][]} | null => {
|
|
|
|
// connectionsByNodeName: (state) => (nodeName: string): { [key: string]: NodeConnections} | null => {
|
|
|
|
connectionsByNodeName: (state) => (nodeName: string): INodeConnections => {
|
|
|
|
if (state.workflow.connections.hasOwnProperty(nodeName)) {
|
|
|
|
return state.workflow.connections[nodeName];
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
allNodes: (state): INodeUi[] => {
|
|
|
|
return state.workflow.nodes;
|
|
|
|
},
|
|
|
|
nodeByName: (state) => (nodeName: string): INodeUi | null => {
|
|
|
|
const foundNode = state.workflow.nodes.find(node => {
|
|
|
|
return node.name === nodeName;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (foundNode === undefined) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return foundNode;
|
|
|
|
},
|
|
|
|
nodesIssuesExist: (state): boolean => {
|
|
|
|
for (const node of state.workflow.nodes) {
|
|
|
|
if (node.issues === undefined || Object.keys(node.issues).length === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
allNodeTypes: (state): INodeTypeDescription[] => {
|
|
|
|
return state.nodeTypes;
|
|
|
|
},
|
2021-09-21 10:38:24 -07:00
|
|
|
nodeType: (state, getters) => (nodeType: string, typeVersion?: number): INodeTypeDescription | null => {
|
2019-06-23 03:35:23 -07:00
|
|
|
const foundType = state.nodeTypes.find(typeData => {
|
2021-09-21 10:38:24 -07:00
|
|
|
return typeData.name === nodeType && typeData.version === (typeVersion || typeData.defaultVersion || DEFAULT_NODETYPE_VERSION);
|
2019-06-23 03:35:23 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
if (foundType === undefined) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return foundType;
|
|
|
|
},
|
|
|
|
activeNode: (state, getters): INodeUi | null => {
|
|
|
|
return getters.nodeByName(state.activeNode);
|
|
|
|
},
|
|
|
|
lastSelectedNode: (state, getters): INodeUi | null => {
|
|
|
|
return getters.nodeByName(state.lastSelectedNode);
|
|
|
|
},
|
2019-12-10 06:39:14 -08:00
|
|
|
lastSelectedNodeOutputIndex: (state, getters): number | null => {
|
|
|
|
return state.lastSelectedNodeOutputIndex;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
// Active Execution
|
|
|
|
executingNode: (state): string | null => {
|
|
|
|
return state.executingNode;
|
|
|
|
},
|
|
|
|
activeExecutionId: (state): string | null => {
|
|
|
|
return state.executionId;
|
|
|
|
},
|
|
|
|
executionWaitingForWebhook: (state): boolean => {
|
|
|
|
return state.executionWaitingForWebhook;
|
|
|
|
},
|
|
|
|
|
|
|
|
workflowName: (state): string => {
|
|
|
|
return state.workflow.name;
|
|
|
|
},
|
|
|
|
workflowId: (state): string => {
|
|
|
|
return state.workflow.id;
|
|
|
|
},
|
|
|
|
workflowSettings: (state): IWorkflowSettings => {
|
|
|
|
if (state.workflow.settings === undefined) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
return state.workflow.settings;
|
|
|
|
},
|
|
|
|
|
2021-05-29 11:31:21 -07:00
|
|
|
workflowTags: (state): string[] => {
|
|
|
|
return state.workflow.tags as string[];
|
|
|
|
},
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
// Workflow Result Data
|
|
|
|
getWorkflowExecution: (state): IExecutionResponse | null => {
|
|
|
|
return state.workflowExecutionData;
|
|
|
|
},
|
|
|
|
getWorkflowRunData: (state): IRunData | null => {
|
|
|
|
if (state.workflowExecutionData === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.workflowExecutionData.data.resultData.runData;
|
|
|
|
},
|
|
|
|
getWorkflowResultDataByNodeName: (state, getters) => (nodeName: string): ITaskData[] | null => {
|
|
|
|
const workflowRunData = getters.getWorkflowRunData;
|
|
|
|
|
|
|
|
if (workflowRunData === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (!workflowRunData.hasOwnProperty(nodeName)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return workflowRunData[nodeName];
|
|
|
|
},
|
|
|
|
|
2021-04-09 13:44:53 -07:00
|
|
|
sidebarMenuItems: (state): IMenuItem[] => {
|
|
|
|
return state.sidebarMenuItems;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
});
|