diff --git a/packages/editor-ui/src/components/MainHeader.vue b/packages/editor-ui/src/components/MainHeader.vue
index 2b9696e2b..97a4a55f5 100644
--- a/packages/editor-ui/src/components/MainHeader.vue
+++ b/packages/editor-ui/src/components/MainHeader.vue
@@ -12,14 +12,14 @@
- of
+ of
"{{workflowName}}"
workflow
- Workflow: {{workflowName}}
+ Workflow: {{workflowName}}*
Workflow was not saved!
@@ -154,6 +154,9 @@ export default mixins(
workflowRunning (): boolean {
return this.$store.getters.isActionActive('workflowRunning');
},
+ isDirty () : boolean {
+ return this.$store.getters.getStateIsDirty;
+ },
},
methods: {
async openWorkflow (workflowId: string) {
diff --git a/packages/editor-ui/src/components/MainSidebar.vue b/packages/editor-ui/src/components/MainSidebar.vue
index a54b53058..863d028e1 100644
--- a/packages/editor-ui/src/components/MainSidebar.vue
+++ b/packages/editor-ui/src/components/MainSidebar.vue
@@ -398,7 +398,7 @@ export default mixins(
return;
}
- this.$store.commit('setWorkflowName', workflowName);
+ this.$store.commit('setWorkflowName', {newName: workflowName, setStateDirty: false});
this.$showMessage({
title: 'Workflow renamed',
@@ -448,13 +448,28 @@ export default mixins(
} else if (key === 'workflow-settings') {
this.workflowSettingsDialogVisible = true;
} else if (key === 'workflow-new') {
- this.$router.push({ name: 'NodeViewNew' });
+ const result = this.$store.getters.getStateIsDirty;
+ if(result) {
+ const importConfirm = await this.confirmMessage(`When you switch workflows your current workflow changes will be lost.`, 'Save your Changes?', 'warning', 'Yes, switch workflows and forget changes');
+ if (importConfirm === true) {
+ this.$store.commit('setStateDirty', false);
+ this.$router.push({ name: 'NodeViewNew' });
- this.$showMessage({
- title: 'Workflow created',
- message: 'A new workflow got created!',
- type: 'success',
- });
+ this.$showMessage({
+ title: 'Workflow created',
+ message: 'A new workflow got created!',
+ type: 'success',
+ });
+ }
+ } else {
+ this.$router.push({ name: 'NodeViewNew' });
+
+ this.$showMessage({
+ title: 'Workflow created',
+ message: 'A new workflow got created!',
+ type: 'success',
+ });
+ }
} else if (key === 'credentials-open') {
this.credentialOpenDialogVisible = true;
} else if (key === 'credentials-new') {
diff --git a/packages/editor-ui/src/components/WorkflowOpen.vue b/packages/editor-ui/src/components/WorkflowOpen.vue
index abedea5b4..6d7a1efe8 100644
--- a/packages/editor-ui/src/components/WorkflowOpen.vue
+++ b/packages/editor-ui/src/components/WorkflowOpen.vue
@@ -33,6 +33,7 @@ import WorkflowActivator from '@/components/WorkflowActivator.vue';
import { restApi } from '@/components/mixins/restApi';
import { genericHelpers } from '@/components/mixins/genericHelpers';
+import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import { titleChange } from '@/components/mixins/titleChange';
import { IWorkflowShortResponse } from '@/Interface';
@@ -43,7 +44,7 @@ export default mixins(
genericHelpers,
restApi,
showMessage,
- titleChange,
+ workflowHelpers,
).extend({
name: 'WorkflowOpen',
props: [
@@ -89,10 +90,35 @@ export default mixins(
this.$emit('closeDialog');
return false;
},
- openWorkflow (data: IWorkflowShortResponse, column: any) { // tslint:disable-line:no-any
+ async openWorkflow (data: IWorkflowShortResponse, column: any) { // tslint:disable-line:no-any
if (column.label !== 'Active') {
- this.$titleSet(data.name, 'IDLE');
- this.$emit('openWorkflow', data.id);
+
+ const currentWorkflowId = this.$store.getters.workflowId;
+
+ if (data.id === currentWorkflowId) {
+ this.$showMessage({
+ title: 'Already open',
+ message: 'This is the current workflow',
+ type: 'error',
+ duration: 1500,
+ });
+ // Do nothing if current workflow is the one user chose to open
+ return;
+ }
+
+ const result = this.$store.getters.getStateIsDirty;
+ if(result) {
+ const importConfirm = await this.confirmMessage(`When you switch workflows your current workflow changes will be lost.`, 'Save your Changes?', 'warning', 'Yes, switch workflows and forget changes');
+ if (importConfirm === false) {
+ return;
+ } else {
+ // This is used to avoid duplicating the message
+ this.$store.commit('setStateDirty', false);
+ this.$emit('openWorkflow', data.id);
+ }
+ } else {
+ this.$emit('openWorkflow', data.id);
+ }
}
},
openDialog () {
diff --git a/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts b/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts
index 5a0be7dbd..b1250003f 100644
--- a/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts
+++ b/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts
@@ -33,7 +33,7 @@ export const moveNodeWorkflow = mixins(
const nodeViewOffsetPositionX = offsetPosition[0] + (position.x - this.moveLastPosition[0]);
const nodeViewOffsetPositionY = offsetPosition[1] + (position.y - this.moveLastPosition[1]);
- this.$store.commit('setNodeViewOffsetPosition', [nodeViewOffsetPositionX, nodeViewOffsetPositionY]);
+ this.$store.commit('setNodeViewOffsetPosition', {newOffset: [nodeViewOffsetPositionX, nodeViewOffsetPositionY], setStateDirty: true});
// Update the last position
this.moveLastPosition[0] = position.x;
@@ -101,7 +101,7 @@ export const moveNodeWorkflow = mixins(
const offsetPosition = this.$store.getters.getNodeViewOffsetPosition;
const nodeViewOffsetPositionX = offsetPosition[0] - normalized.pixelX;
const nodeViewOffsetPositionY = offsetPosition[1] - normalized.pixelY;
- this.$store.commit('setNodeViewOffsetPosition', [nodeViewOffsetPositionX, nodeViewOffsetPositionY]);
+ this.$store.commit('setNodeViewOffsetPosition', {newOffset: [nodeViewOffsetPositionX, nodeViewOffsetPositionY], setStateDirty: true});
},
},
});
diff --git a/packages/editor-ui/src/components/mixins/workflowHelpers.ts b/packages/editor-ui/src/components/mixins/workflowHelpers.ts
index a55ac3362..ba01dfb00 100644
--- a/packages/editor-ui/src/components/mixins/workflowHelpers.ts
+++ b/packages/editor-ui/src/components/mixins/workflowHelpers.ts
@@ -22,6 +22,7 @@ import {
INodeTypesMaxCount,
INodeUi,
IWorkflowData,
+ IWorkflowDb,
IWorkflowDataUpdate,
XYPositon,
} from '../../Interface';
@@ -30,6 +31,8 @@ import { restApi } from '@/components/mixins/restApi';
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
import { showMessage } from '@/components/mixins/showMessage';
+import { isEqual } from 'lodash';
+
import mixins from 'vue-typed-mixins';
export const workflowHelpers = mixins(
@@ -417,7 +420,7 @@ export const workflowHelpers = mixins(
this.$store.commit('setActive', workflowData.active || false);
this.$store.commit('setWorkflowId', workflowData.id);
- this.$store.commit('setWorkflowName', workflowData.name);
+ this.$store.commit('setWorkflowName', {newName: workflowData.name, setStateDirty: false});
this.$store.commit('setWorkflowSettings', workflowData.settings || {});
} else {
// Workflow exists already so update it
@@ -432,7 +435,7 @@ export const workflowHelpers = mixins(
}
this.$store.commit('removeActiveAction', 'workflowSaving');
-
+ this.$store.commit('setStateDirty', false);
this.$showMessage({
title: 'Workflow saved',
message: `The workflow "${workflowData.name}" got saved!`,
@@ -478,5 +481,29 @@ export const workflowHelpers = mixins(
node.position[1] += offsetPosition[1];
}
},
+ async dataHasChanged(id: string) {
+ const currentData = await this.getWorkflowDataToSave();
+
+ let data: IWorkflowDb;
+ data = await this.restApi().getWorkflow(id);
+
+ if(data !== undefined) {
+ const x = {
+ nodes: data.nodes,
+ connections: data.connections,
+ settings: data.settings,
+ name: data.name,
+ };
+ const y = {
+ nodes: currentData.nodes,
+ connections: currentData.connections,
+ settings: currentData.settings,
+ name: currentData.name,
+ };
+ return !isEqual(x, y);
+ }
+
+ return true;
+ },
},
});
diff --git a/packages/editor-ui/src/components/mixins/workflowSave.ts b/packages/editor-ui/src/components/mixins/workflowSave.ts
index 1584d9a7c..60dd135fe 100644
--- a/packages/editor-ui/src/components/mixins/workflowSave.ts
+++ b/packages/editor-ui/src/components/mixins/workflowSave.ts
@@ -74,12 +74,14 @@ export const workflowSave = mixins(
this.$store.commit('setActive', workflowData.active || false);
this.$store.commit('setWorkflowId', workflowData.id);
- this.$store.commit('setWorkflowName', workflowData.name);
+ this.$store.commit('setWorkflowName', {newName: workflowData.name, setStateDirty: false});
this.$store.commit('setWorkflowSettings', workflowData.settings || {});
} else {
// Workflow exists already so update it
await this.restApi().updateWorkflow(currentWorkflow, workflowData);
}
+ // Set dirty = false before pushing route so unsaved changes message doesnt trigger.
+ this.$store.commit('setStateDirty', false);
if (this.$route.params.name !== workflowData.id) {
this.$router.push({
@@ -89,7 +91,6 @@ export const workflowSave = mixins(
}
this.$store.commit('removeActiveAction', 'workflowSaving');
-
this.$showMessage({
title: 'Workflow saved',
message: `The workflow "${workflowData.name}" got saved!`,
diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts
index ba5ca7265..c55764095 100644
--- a/packages/editor-ui/src/store.ts
+++ b/packages/editor-ui/src/store.ts
@@ -53,6 +53,7 @@ export const store = new Vuex.Store({
saveDataSuccessExecution: 'all',
saveManualExecutions: false,
timezone: 'America/New_York',
+ stateIsDirty: false,
executionTimeout: -1,
maxExecutionTimeout: Number.MAX_SAFE_INTEGER,
versionCli: '0.0.0',
@@ -85,6 +86,7 @@ export const store = new Vuex.Store({
state.activeActions.push(action);
}
},
+
removeActiveAction (state, action: string) {
const actionIndex = state.activeActions.indexOf(action);
if (actionIndex !== -1) {
@@ -94,6 +96,7 @@ export const store = new Vuex.Store({
// Active Executions
addActiveExecution (state, newActiveExecution: IExecutionsCurrentSummaryExtended) {
+ state.stateIsDirty = true;
// Check if the execution exists already
const activeExecution = state.activeExecutions.find(execution => {
return execution.idActive === newActiveExecution.idActive;
@@ -110,6 +113,7 @@ export const store = new Vuex.Store({
state.activeExecutions.unshift(newActiveExecution);
},
finishActiveExecution (state, finishedActiveExecution: IPushDataExecutionFinished) {
+ state.stateIsDirty = true;
// Find the execution to set to finished
const activeExecution = state.activeExecutions.find(execution => {
return execution.idActive === finishedActiveExecution.executionIdActive;
@@ -128,6 +132,7 @@ export const store = new Vuex.Store({
Vue.set(activeExecution, 'stoppedAt', finishedActiveExecution.data.stoppedAt);
},
setActiveExecutions (state, newActiveExecutions: IExecutionsCurrentSummaryExtended[]) {
+ state.stateIsDirty = true;
Vue.set(state, 'activeExecutions', newActiveExecutions);
},
@@ -136,23 +141,31 @@ export const store = new Vuex.Store({
state.activeWorkflows = newActiveWorkflows;
},
setWorkflowActive (state, workflowId: string) {
+ state.stateIsDirty = true;
const index = state.activeWorkflows.indexOf(workflowId);
if (index === -1) {
state.activeWorkflows.push(workflowId);
}
},
setWorkflowInactive (state, workflowId: string) {
+ state.stateIsDirty = true;
const index = state.activeWorkflows.indexOf(workflowId);
if (index !== -1) {
state.selectedNodes.splice(index, 1);
}
},
+ // 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;
+ },
// Selected Nodes
addSelectedNode (state, node: INodeUi) {
state.selectedNodes.push(node);
},
removeNodeFromSelection (state, node: INodeUi) {
+ state.stateIsDirty = true;
let index;
for (index in state.selectedNodes) {
if (state.selectedNodes[index].name === node.name) {
@@ -178,6 +191,10 @@ export const store = new Vuex.Store({
return;
}
+ if (data.setStateDirty === true) {
+ state.stateIsDirty = true;
+ }
+
const sourceData: IConnection = data.connection[0];
const destinationData: IConnection = data.connection[1];
@@ -213,6 +230,7 @@ export const store = new Vuex.Store({
if (connectionExists === false) {
state.workflow.connections[sourceData.node][sourceData.type][sourceData.index].push(destinationData);
}
+
},
removeConnection (state, data) {
const sourceData = data.connection[0];
@@ -228,6 +246,8 @@ export const store = new Vuex.Store({
return;
}
+ state.stateIsDirty = true;
+
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) {
@@ -235,11 +255,16 @@ export const store = new Vuex.Store({
connections.splice(parseInt(index, 10), 1);
}
}
+
},
- removeAllConnections (state) {
+ removeAllConnections (state, data) {
+ if (data.setStateDirty === true) {
+ state.stateIsDirty = true;
+ }
state.workflow.connections = {};
},
removeAllNodeConnection (state, node: INodeUi) {
+ state.stateIsDirty = true;
// Remove all source connections
if (state.workflow.connections.hasOwnProperty(node.name)) {
delete state.workflow.connections[node.name];
@@ -277,6 +302,7 @@ export const store = new Vuex.Store({
if (state.credentials === null) {
return;
}
+
for (let i = 0; i < state.credentials.length; i++) {
if (state.credentials[i].id === credentialData.id) {
state.credentials.splice(i, 1);
@@ -288,6 +314,7 @@ export const store = new Vuex.Store({
if (state.credentials === null) {
return;
}
+
for (let i = 0; i < state.credentials.length; i++) {
if (state.credentials[i].id === credentialData.id) {
state.credentials[i] = credentialData;
@@ -303,6 +330,7 @@ export const store = new Vuex.Store({
},
renameNodeSelectedAndExecution (state, nameData) {
+ state.stateIsDirty = true;
// 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)) {
@@ -320,10 +348,12 @@ export const store = new Vuex.Store({
state.workflow.nodes.forEach((node) => {
node.issues = undefined;
});
+
return true;
},
setNodeIssue (state, nodeIssueData: INodeIssueData) {
+
const node = state.workflow.nodes.find(node => {
return node.name === nodeIssueData.node;
});
@@ -347,6 +377,7 @@ export const store = new Vuex.Store({
// Set/Overwrite the value
Vue.set(node.issues!, nodeIssueData.type, nodeIssueData.value);
+ state.stateIsDirty = true;
}
return true;
@@ -358,8 +389,11 @@ export const store = new Vuex.Store({
},
// Name
- setWorkflowName (state, newName: string) {
- state.workflow.name = newName;
+ setWorkflowName (state, data) {
+ if (data.setStateDirty === true) {
+ state.stateIsDirty = true;
+ }
+ state.workflow.name = data.newName;
},
// Nodes
@@ -376,11 +410,15 @@ export const store = new Vuex.Store({
for (let i = 0; i < state.workflow.nodes.length; i++) {
if (state.workflow.nodes[i].name === node.name) {
state.workflow.nodes.splice(i, 1);
+ state.stateIsDirty = true;
return;
}
}
},
- removeAllNodes (state) {
+ removeAllNodes (state, data) {
+ if (data.setStateDirty === true) {
+ state.stateIsDirty = true;
+ }
state.workflow.nodes.splice(0, state.workflow.nodes.length);
},
updateNodeProperties (state, updateInformation: INodeUpdatePropertiesInformation) {
@@ -391,6 +429,7 @@ export const store = new Vuex.Store({
if (node) {
for (const key of Object.keys(updateInformation.properties)) {
+ state.stateIsDirty = true;
Vue.set(node, key, updateInformation.properties[key]);
}
}
@@ -405,6 +444,7 @@ export const store = new Vuex.Store({
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
}
+ state.stateIsDirty = true;
Vue.set(node, updateInformation.key, updateInformation.value);
},
setNodeParameters (state, updateInformation: IUpdateInformation) {
@@ -417,6 +457,7 @@ export const store = new Vuex.Store({
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
}
+ state.stateIsDirty = true;
Vue.set(node, 'parameters', updateInformation.value);
},
@@ -425,6 +466,7 @@ export const store = new Vuex.Store({
state.nodeIndex.push(nodeName);
},
setNodeIndex (state, newData: { index: number, name: string | null}) {
+ state.stateIsDirty = true;
state.nodeIndex[newData.index] = newData.name;
},
resetNodeIndex (state) {
@@ -435,8 +477,11 @@ export const store = new Vuex.Store({
setNodeViewMoveInProgress (state, value: boolean) {
state.nodeViewMoveInProgress = value;
},
- setNodeViewOffsetPosition (state, newOffset: XYPositon) {
- state.nodeViewOffsetPosition = newOffset;
+ setNodeViewOffsetPosition (state, data) {
+ if (data.setStateDirty === true) {
+ state.stateIsDirty = true;
+ }
+ state.nodeViewOffsetPosition = data.newOffset;
},
// Node-Types
@@ -502,7 +547,7 @@ export const store = new Vuex.Store({
// TODO: Check if there is an error or whatever that is supposed to be returned
return;
}
-
+ state.stateIsDirty = true;
state.nodeTypes.push(typeData);
},
@@ -528,7 +573,7 @@ export const store = new Vuex.Store({
if (state.workflowExecutionData.data.resultData.runData[pushData.nodeName] === undefined) {
Vue.set(state.workflowExecutionData.data.resultData.runData, pushData.nodeName, []);
}
-
+ state.stateIsDirty = true;
state.workflowExecutionData.data.resultData.runData[pushData.nodeName].push(pushData.data);
},
@@ -601,6 +646,10 @@ export const store = new Vuex.Store({
return `${state.urlBaseWebhook}${state.endpointWebhookTest}`;
},
+ getStateIsDirty: (state) : boolean => {
+ return state.stateIsDirty;
+ },
+
saveDataErrorExecution: (state): string => {
return state.saveDataErrorExecution;
},
diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue
index b0146a467..2cf41645e 100644
--- a/packages/editor-ui/src/views/NodeView.vue
+++ b/packages/editor-ui/src/views/NodeView.vue
@@ -131,9 +131,7 @@ import NodeSettings from '@/components/NodeSettings.vue';
import RunData from '@/components/RunData.vue';
import mixins from 'vue-typed-mixins';
-
-import { v4 as uuidv4 } from 'uuid';
-
+import { v4 as uuidv4} from 'uuid';
import { debounce } from 'lodash';
import axios from 'axios';
import {
@@ -195,6 +193,41 @@ export default mixins(
// When a node gets set as active deactivate the create-menu
this.createNodeActive = false;
},
+ nodes: {
+ async handler (val, oldVal) {
+ // Load a workflow
+ let workflowId = null as string | null;
+ if (this.$route && this.$route.params.name) {
+ workflowId = this.$route.params.name;
+ }
+ },
+ deep: true,
+ },
+ connections: {
+ async handler (val, oldVal) {
+ // Load a workflow
+ let workflowId = null as string | null;
+ if (this.$route && this.$route.params.name) {
+ workflowId = this.$route.params.name;
+ }
+ },
+ deep: true,
+ },
+ },
+ async beforeRouteLeave(to, from, next) {
+ const result = this.$store.getters.getStateIsDirty;
+ if(result) {
+ const importConfirm = await this.confirmMessage(`When you switch workflows your current workflow changes will be lost.`, 'Save your Changes?', 'warning', 'Yes, switch workflows and forget changes');
+ if (importConfirm === false) {
+ next(false);
+ } else {
+ // Prevent other popups from displaying
+ this.$store.commit('setStateDirty', false);
+ next();
+ }
+ } else {
+ next();
+ }
},
computed: {
activeNode (): INodeUi | null {
@@ -311,7 +344,7 @@ export default mixins(
throw new Error(`Execution with id "${executionId}" could not be found!`);
}
- this.$store.commit('setWorkflowName', data.workflowData.name);
+ this.$store.commit('setWorkflowName', {newName: data.workflowData.name, setStateDirty: false});
this.$store.commit('setWorkflowId', PLACEHOLDER_EMPTY_WORKFLOW_ID);
this.$store.commit('setWorkflowExecutionData', data);
@@ -335,10 +368,14 @@ export default mixins(
this.$store.commit('setActive', data.active || false);
this.$store.commit('setWorkflowId', workflowId);
- this.$store.commit('setWorkflowName', data.name);
+ this.$store.commit('setWorkflowName', {newName: data.name, setStateDirty: false});
this.$store.commit('setWorkflowSettings', data.settings || {});
await this.addNodes(data.nodes, data.connections);
+
+ this.$store.commit('setStateDirty', false);
+
+ return data;
},
touchTap (e: MouseEvent | TouchEvent) {
if (this.isTouchDevice) {
@@ -446,6 +483,8 @@ export default mixins(
e.stopPropagation();
e.preventDefault();
+ this.$store.commit('setStateDirty', false);
+
this.callDebounced('saveCurrentWorkflow', 1000);
} else if (e.key === 'Enter') {
// Activate the last selected node
@@ -1227,7 +1266,6 @@ export default mixins(
if (![null, undefined].includes(inputNameOverlay)) {
inputNameOverlay.setVisible(false);
}
-
this.$store.commit('addConnection', {
connection: [
{
@@ -1241,6 +1279,7 @@ export default mixins(
index: targetInfo.index,
},
],
+ setStateDirty: true,
});
});
@@ -1317,11 +1356,14 @@ export default mixins(
];
await this.addNodes(defaultNodes);
+ this.$store.commit('setStateDirty', false);
+
},
async initView (): Promise {
if (this.$route.params.action === 'workflowSave') {
// In case the workflow got saved we do not have to run init
// as only the route changed but all the needed data is already loaded
+ this.$store.commit('setStateDirty', false);
return Promise.resolve();
}
@@ -1330,12 +1372,20 @@ export default mixins(
const executionId = this.$route.params.id;
await this.openExecution(executionId);
} else {
+
+ const result = this.$store.getters.getStateIsDirty;
+ if(result) {
+ const importConfirm = await this.confirmMessage(`When you switch workflows your current workflow changes will be lost.`, 'Save your Changes?', 'warning', 'Yes, switch workflows and forget changes');
+ if (importConfirm === false) {
+ return Promise.resolve();
+ }
+ }
+
// Load a workflow
let workflowId = null as string | null;
if (this.$route.params.name) {
workflowId = this.$route.params.name;
}
-
if (workflowId !== null) {
const workflow = await this.restApi().getWorkflow(workflowId);
this.$titleSet(workflow.name, 'IDLE');
@@ -1349,6 +1399,17 @@ export default mixins(
document.addEventListener('keydown', this.keyDown);
document.addEventListener('keyup', this.keyUp);
+
+ window.addEventListener("beforeunload", (e) => {
+ if(this.$store.getters.getStateIsDirty === true) {
+ const confirmationMessage = 'It looks like you have been editing something. '
+ + 'If you leave before saving, your changes will be lost.';
+ (e || window.event).returnValue = confirmationMessage; //Gecko + IE
+ return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
+ } else {
+ return;
+ }
+ });
},
__addConnection (connection: [IConnection, IConnection], addVisualConnection = false) {
if (addVisualConnection === true) {
@@ -1364,9 +1425,10 @@ export default mixins(
detachable: !this.isReadOnly,
});
} else {
+ const connectionProperties = {connection, setStateDirty: false};
// When nodes get connected it gets saved automatically to the storage
// so if we do not connect we have to save the connection manually
- this.$store.commit('addConnection', { connection });
+ this.$store.commit('addConnection', connectionProperties);
}
},
__removeConnection (connection: [IConnection, IConnection], removeVisualConnection = false) {
@@ -1556,7 +1618,7 @@ export default mixins(
this.instance.deleteEveryEndpoint();
}
this.$store.commit('removeAllConnections');
- this.$store.commit('removeAllNodes');
+ this.$store.commit('removeAllNodes', {setStateDirty: true});
// Wait a tick that the old nodes had time to get removed
await Vue.nextTick();
@@ -1858,8 +1920,8 @@ export default mixins(
});
}
- this.$store.commit('removeAllConnections');
- this.$store.commit('removeAllNodes');
+ this.$store.commit('removeAllConnections', {setStateDirty: false});
+ this.$store.commit('removeAllNodes', {setStateDirty: false});
// Reset workflow execution data
this.$store.commit('setWorkflowExecutionData', null);
@@ -1868,7 +1930,7 @@ export default mixins(
this.$store.commit('setActive', false);
this.$store.commit('setWorkflowId', PLACEHOLDER_EMPTY_WORKFLOW_ID);
- this.$store.commit('setWorkflowName', '');
+ this.$store.commit('setWorkflowName', {newName: '', setStateDirty: false});
this.$store.commit('setWorkflowSettings', {});
this.$store.commit('setActiveExecutionId', null);
@@ -1879,7 +1941,7 @@ export default mixins(
this.$store.commit('resetNodeIndex');
this.$store.commit('resetSelectedNodes');
- this.$store.commit('setNodeViewOffsetPosition', [0, 0]);
+ this.$store.commit('setNodeViewOffsetPosition', {newOffset: [0, 0], setStateDirty: false});
return Promise.resolve();
},
@@ -1929,13 +1991,13 @@ export default mixins(
async mounted () {
this.$root.$on('importWorkflowData', async (data: IDataObject) => {
- await this.importWorkflowData(data.data as IWorkflowDataUpdate);
+ const resData = await this.importWorkflowData(data.data as IWorkflowDataUpdate);
});
this.$root.$on('importWorkflowUrl', async (data: IDataObject) => {
const workflowData = await this.getWorkflowDataFromUrl(data.url as string);
if (workflowData !== undefined) {
- await this.importWorkflowData(workflowData);
+ const resData = await this.importWorkflowData(workflowData);
}
});