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,
|
2020-09-30 06:50:43 -07:00
|
|
|
IDataObject,
|
2019-06-23 03:35:23 -07:00
|
|
|
INodeConnections,
|
|
|
|
INodeIssueData,
|
|
|
|
INodeTypeDescription,
|
|
|
|
IRunData,
|
2021-10-18 20:57:49 -07:00
|
|
|
ITelemetrySettings,
|
2019-06-23 03:35:23 -07:00
|
|
|
ITaskData,
|
|
|
|
IWorkflowSettings,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
|
|
|
import {
|
|
|
|
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,
|
2021-11-19 01:17:13 -08:00
|
|
|
XYPosition,
|
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';
|
2021-10-18 20:57:49 -07:00
|
|
|
import settings from './modules/settings';
|
2021-05-29 11:31:21 -07:00
|
|
|
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),
|
2021-11-15 02:19:43 -08:00
|
|
|
credentialTextRenderKeys: null,
|
2021-11-09 00:59:48 -08:00
|
|
|
defaultLocale: 'en',
|
2021-05-29 11:31:21 -07:00
|
|
|
endpointWebhook: 'webhook',
|
|
|
|
endpointWebhookTest: 'webhook-test',
|
|
|
|
executionId: null,
|
|
|
|
executingNode: '',
|
|
|
|
executionWaitingForWebhook: false,
|
|
|
|
pushConnectionActive: true,
|
|
|
|
saveDataErrorExecution: 'all',
|
|
|
|
saveDataSuccessExecution: 'all',
|
2021-10-06 10:13:39 -07:00
|
|
|
saveManualExecutions: false,
|
2021-05-29 11:31:21 -07:00
|
|
|
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-10-18 20:57:49 -07:00
|
|
|
telemetry: null,
|
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,
|
2021-10-18 20:57:49 -07:00
|
|
|
settings,
|
2021-05-29 11:31:21 -07:00
|
|
|
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
|
|
|
},
|
|
|
|
|
2021-10-13 15:21:00 -07:00
|
|
|
// replace invalid credentials in workflow
|
|
|
|
replaceInvalidWorkflowCredentials(state, {credentials, invalid, type }) {
|
|
|
|
state.workflow.nodes.forEach((node) => {
|
|
|
|
if (!node.credentials || !node.credentials[type]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const nodeCredentials = node.credentials[type];
|
|
|
|
|
|
|
|
if (typeof nodeCredentials === 'string' && nodeCredentials === invalid.name) {
|
|
|
|
node.credentials[type] = credentials;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeCredentials.id === null) {
|
|
|
|
if (nodeCredentials.name === invalid.name){
|
|
|
|
node.credentials[type] = credentials;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeCredentials.id === invalid.id) {
|
|
|
|
node.credentials[type] = credentials;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
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);
|
|
|
|
},
|
2021-10-06 10:13:39 -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);
|
|
|
|
},
|
2021-10-18 20:57:49 -07:00
|
|
|
setTelemetry(state, telemetry: ITelemetrySettings) {
|
|
|
|
Vue.set(state, 'telemetry', telemetry);
|
|
|
|
},
|
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);
|
|
|
|
},
|
2021-11-09 00:59:48 -08:00
|
|
|
setDefaultLocale(state, locale: string) {
|
|
|
|
Vue.set(state, 'defaultLocale', locale);
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
setActiveNode (state, nodeName: string) {
|
|
|
|
state.activeNode = nodeName;
|
|
|
|
},
|
2021-11-15 02:19:43 -08:00
|
|
|
setCredentialTextRenderKeys (state, renderKeys: { nodeType: string; credentialType: string; }) {
|
|
|
|
state.credentialTextRenderKeys = renderKeys;
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
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);
|
|
|
|
},
|
2021-11-19 01:17:13 -08:00
|
|
|
clearNodeExecutionData (state, nodeName: string): void {
|
|
|
|
if (state.workflowExecutionData === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vue.delete(state.workflowExecutionData.data.resultData.runData, nodeName);
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
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);
|
|
|
|
},
|
|
|
|
|
2021-09-22 00:23:37 -07:00
|
|
|
isNewWorkflow: (state) => {
|
|
|
|
return state.workflow.id === PLACEHOLDER_EMPTY_WORKFLOW_ID;
|
|
|
|
},
|
|
|
|
|
:zap: Add Value Survey (#2499)
* N8N-2619 Value Survey Front-end
* N8N-2619 Added Contact Prompt Modal and logic
* N8N-2619 Added Link to Toast Message on Successful submitting ValueSurvey
* N8N-2619 Updated TypeForm URL in ValueSurvey Success Toast
* N8N-2619 Fixed Typo placeholder for ValueSurvey and ContactPrompt Modal
* N8N-2619 Fixed Toast not close automatically in ValueSurvey, Make part of the title bold, Changed Font-sizes on Value Survey
* N8N-2619 Fixed Close Button on ValueSurvey, Vertical Allignment for Questions in ValueSurvey Drawer
* N8N-2619 Make Value Survey with static height
* N8N-2619 Fixed Telemetry Events on closing ValueSurvey
* N8N-2619 Updated N8NPrompt Interface, Added Dynamic Title and Description on ContactPrompt Modal
* N8N-2619 Reversed Answers in ValueSurveyModal
* N8N-2619 Added Telemetry Event on user close ValueSurvey on second Question
* N8N-2619 Re-work, Optimized, Simplify the code after technical review
* N8N-2619 Fixed If else statement in openUserPromptsIfPossible
* N8N-2619 Change Text under Email Box - ValueSurvey, ContactPrompt, Added new Telemetary Event on ValueSurvey Open, Fixed Toast to close aftet 15s
* N8N-2619 Change ContactPrompt Modal to use Atoms like N8N-Heading and N8N-Text
* N8N-2619 Change Design & Logic on ValueSurvey - When to open
* N8N-2619 Updated Value Survey with new Telemetry Events (Refactor), Simplified functions, Added Atoms in ValueSurvey + ContactPrompt
* N8N-2619 Refactor in Interfaces, Updated/Refactor Getters and Vuex store props
* N8N-2619 Defined IN8nValueSurveyData interface
* N8N-2619 Disabled Keyboard shortcuts to be activated on typing in ValueSurvey Input field, Fire an event on Saving WF from Menu and with shorcut, Make Drawer keep-alive
* N8N-2619 Added Atoms in Value Survey Modal (buttons), Rework css
* N8N-2619 Added Responses on ValueSurvey Submit
* N8N-2619 Added Response for SubmittingContactInfo
* N8N-2619 Added loading state for buttons / ValueSurvey
* N8N-2619 Changed ValueSurvey and ContactPrompt to support enter key on submit, Simplifed closeDialog Function, Changed css for button in ValueSurvey, Prevent showing the Modals if Saving WF fails, Add Debouncing on showing prompt
* N8N-2619 Added IsTelemetryEnabled Getter in Vuex.store
* N8N-2619 Created/Added N8N-SquareButton to Design-system
* N8N-2619 Change Promise in MainSideBar with Async/Await function, Nitpick simpliefied
* N8N-2619 Update the text under the input fields
* N8N-2619 Update the text in ContactPrompt Modal
* N8N-2619 Allign Send button on ValueSurvey Modal
* N8N-2619 Fixed Input in ValueSurvey Modal
* N8N-2619 Check if the workflow is saving
* N8N-2619 Check if WF is saving to allowed performs fetchPromptsData
* N8N-2619 Hotfix
* N8N-2619 Fixed ValueSurvey, Updated onSaveButtonClick function, Created onSaveKeyboardShortcut function in NodeView
* N8N-2619 Rework css module classes for ValueSurvey, Simplified
* N8N-2619 Simplified N8N-SquareButton Component, removed dead code
* N8N-2619 Added Breakpoints for Mobile/Tablet View
* N8N-2619 Formatting fix
* N8N-2619 Update css for mobile/tablet, change promises to asyn/await functions in ContactPrompt and ValueSurvey, Added isActive prop to ValueSurvey
* N8N-2619 Update TEMPLATE_BASE_URL to production
2021-12-11 08:38:16 -08:00
|
|
|
isTelemetryEnabled: (state) => {
|
|
|
|
return state.telemetry && state.telemetry.enabled;
|
|
|
|
},
|
|
|
|
|
2021-10-06 10:06:33 -07:00
|
|
|
currentWorkflowHasWebhookNode: (state: IRootState): boolean => {
|
|
|
|
return !!state.workflow.nodes.find((node: INodeUi) => !!node.webhookId);
|
|
|
|
},
|
|
|
|
|
2019-07-24 05:25:30 -07:00
|
|
|
getActiveExecutions: (state): IExecutionsCurrentSummaryExtended[] => {
|
|
|
|
return state.activeExecutions;
|
|
|
|
},
|
|
|
|
|
2021-11-15 02:19:43 -08:00
|
|
|
credentialTextRenderKeys: (state): object | null => {
|
|
|
|
return state.credentialTextRenderKeys;
|
|
|
|
},
|
|
|
|
|
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;
|
|
|
|
},
|
|
|
|
|
2021-10-18 20:57:49 -07:00
|
|
|
instanceId: (state): string => {
|
|
|
|
return state.instanceId;
|
|
|
|
},
|
|
|
|
|
2019-07-10 11:53:13 -07:00
|
|
|
saveDataErrorExecution: (state): string => {
|
|
|
|
return state.saveDataErrorExecution;
|
|
|
|
},
|
|
|
|
saveDataSuccessExecution: (state): string => {
|
|
|
|
return state.saveDataSuccessExecution;
|
|
|
|
},
|
2021-10-06 10:13:39 -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;
|
|
|
|
},
|
2021-10-18 20:57:49 -07:00
|
|
|
telemetry: (state): ITelemetrySettings | null => {
|
|
|
|
return state.telemetry;
|
|
|
|
},
|
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;
|
|
|
|
},
|
2021-11-09 00:59:48 -08:00
|
|
|
defaultLocale: (state): string => {
|
|
|
|
return state.defaultLocale;
|
|
|
|
},
|
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;
|
|
|
|
},
|
|
|
|
|
:sparkles: Improve Waiting Webhook call state in WF Canvas (#2430)
* N8N-2586 Improve Waiting Webhook call state in WF Canvas
* N8N-2586 Added watcher for showing Webhook's Node Tooltip on execution
* N8N-2586 Show helping tooltip for trigger node if wokrflow is running, it is a trigger node, if it is only one trigger node in WF
* N8N-2586 Rework/Move logic to computed property, Created getter for ActveTriggerNodesInWokrflow, Add style to trigger node's tooltip, remove comments
* N8N-2586 Added EventTriggerDescription prop in INodeTypeDescription Interface, Updated Logic for TriggerNode Tooltip based on the new prop
* N8N-2586 Add new use cases/watcher to show Trigger Nodes Tooltip / If has issues, if paused, if wokrlfow is running, Refactor Getter
* N8N-2586 Added z-index to tooltip, Added new Scenario for Tooltip if it is Draged&Droped on the WF
* N8N-2586 Refactor computed property for draged nodes
* N8N-2586 Fixed Conflicts
* N8N-2586 Fixed Tooltip
* N8N-2586 Dont show tooltip on core trigger nodes that execute automatically
* N8N-2586 Fixed Webhook tooltip when adding/deleting canvas during WF execution
* N8N-2586 Updated Logic, Simplify the code
* N8N-2586 Simplify Code
* N8N-2586 Added check for nodetype
* update dragging to use local state
* N8N-2586 Added eventTriggerDescription to Interval Node
* add comment, use new getter
* update to always check
Co-authored-by: Mutasem <mutdmour@gmail.com>
2021-11-25 14:33:41 -08:00
|
|
|
workflowTriggerNodes: (state, getters) => {
|
|
|
|
return state.workflow.nodes.filter(node => {
|
|
|
|
return getters.nodeType(node.type).group.includes('trigger');
|
|
|
|
});
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
// Node-Index
|
|
|
|
getNodeIndex: (state) => (nodeName: string): number => {
|
|
|
|
return state.nodeIndex.indexOf(nodeName);
|
|
|
|
},
|
|
|
|
getNodeNameByIndex: (state) => (index: number): string | null => {
|
|
|
|
return state.nodeIndex[index];
|
|
|
|
},
|
|
|
|
|
2021-11-19 01:17:13 -08:00
|
|
|
getNodeViewOffsetPosition: (state): XYPosition => {
|
2019-06-23 03:35:23 -07:00
|
|
|
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;
|
|
|
|
},
|
2021-11-19 01:17:13 -08:00
|
|
|
outgoingConnectionsByNodeName: (state) => (nodeName: string): INodeConnections => {
|
2019-06-23 03:35:23 -07:00
|
|
|
if (state.workflow.connections.hasOwnProperty(nodeName)) {
|
|
|
|
return state.workflow.connections[nodeName];
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
allNodes: (state): INodeUi[] => {
|
|
|
|
return state.workflow.nodes;
|
|
|
|
},
|
2021-11-19 01:17:13 -08:00
|
|
|
nodesByName: (state: IRootState): {[name: string]: INodeUi} => {
|
|
|
|
return state.workflow.nodes.reduce((accu: {[name: string]: INodeUi}, node) => {
|
|
|
|
accu[node.name] = node;
|
|
|
|
return accu;
|
|
|
|
}, {});
|
|
|
|
},
|
|
|
|
getNodeByName: (state, getters) => (nodeName: string): INodeUi | null => {
|
|
|
|
return getters.nodesByName[nodeName] || null;
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
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-11-29 00:34:59 -08:00
|
|
|
|
|
|
|
/**
|
2021-11-29 03:20:10 -08:00
|
|
|
* Getter for node default names ending with a number: `'S3'`, `'Magento 2'`, etc.
|
2021-11-29 00:34:59 -08:00
|
|
|
*/
|
2021-11-29 03:20:10 -08:00
|
|
|
nativelyNumberSuffixedDefaults: (_, getters): string[] => {
|
|
|
|
const { allNodeTypes } = getters as {
|
|
|
|
allNodeTypes: Array<INodeTypeDescription & { defaults: { name: string } }>;
|
|
|
|
};
|
2021-11-29 00:34:59 -08:00
|
|
|
|
|
|
|
return allNodeTypes.reduce<string[]>((acc, cur) => {
|
2021-11-29 03:20:10 -08:00
|
|
|
if (/\d$/.test(cur.defaults.name)) acc.push(cur.defaults.name);
|
2021-11-29 00:34:59 -08:00
|
|
|
return acc;
|
|
|
|
}, []);
|
|
|
|
},
|
|
|
|
|
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 => {
|
2021-11-19 01:17:13 -08:00
|
|
|
return getters.getNodeByName(state.activeNode);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
|
|
|
lastSelectedNode: (state, getters): INodeUi | null => {
|
2021-11-19 01:17:13 -08:00
|
|
|
return getters.getNodeByName(state.lastSelectedNode);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
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;
|
|
|
|
},
|
2021-10-06 10:06:33 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
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 => {
|
2021-12-03 09:53:55 -08:00
|
|
|
if (!state.workflowExecutionData || !state.workflowExecutionData.data || !state.workflowExecutionData.data.resultData) {
|
2019-06-23 03:35:23 -07:00
|
|
|
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
|
|
|
},
|
|
|
|
});
|