mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Improve background conflict handling
This commit is contained in:
parent
0e0bba25c1
commit
18d0fa2259
@ -59,18 +59,53 @@ RED.history = (function() {
|
||||
t: 'replace',
|
||||
config: RED.nodes.createCompleteNodeSet(),
|
||||
changed: {},
|
||||
rev: RED.nodes.version()
|
||||
moved: {},
|
||||
complete: true,
|
||||
rev: RED.nodes.version(),
|
||||
dirty: RED.nodes.dirty()
|
||||
};
|
||||
var selectedTab = RED.workspaces.active();
|
||||
inverseEv.config.forEach(n => {
|
||||
const node = RED.nodes.node(n.id)
|
||||
if (node) {
|
||||
inverseEv.changed[n.id] = node.changed
|
||||
inverseEv.moved[n.id] = node.moved
|
||||
}
|
||||
})
|
||||
RED.nodes.clear();
|
||||
var imported = RED.nodes.import(ev.config);
|
||||
// Clear all change flags from the import
|
||||
RED.nodes.dirty(false);
|
||||
|
||||
const flowsToLock = new Set()
|
||||
function ensureUnlocked(id) {
|
||||
const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
|
||||
const isLocked = flow ? flow.locked : false;
|
||||
if (flow && isLocked) {
|
||||
flow.locked = false;
|
||||
flowsToLock.add(flow)
|
||||
}
|
||||
}
|
||||
imported.nodes.forEach(function(n) {
|
||||
if (ev.changed[n.id]) {
|
||||
ensureUnlocked(n.z)
|
||||
n.changed = true;
|
||||
inverseEv.changed[n.id] = true;
|
||||
}
|
||||
if (ev.moved[n.id]) {
|
||||
ensureUnlocked(n.z)
|
||||
n.moved = true;
|
||||
}
|
||||
})
|
||||
flowsToLock.forEach(flow => {
|
||||
flow.locked = true
|
||||
})
|
||||
|
||||
RED.nodes.version(ev.rev);
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.workspaces.show(selectedTab, true);
|
||||
RED.sidebar.config.refresh();
|
||||
} else {
|
||||
var importMap = {};
|
||||
ev.config.forEach(function(n) {
|
||||
|
@ -34,6 +34,8 @@ RED.deploy = (function() {
|
||||
|
||||
var currentDiff = null;
|
||||
|
||||
var activeBackgroundDeployNotification;
|
||||
|
||||
function changeDeploymentType(type) {
|
||||
deploymentType = type;
|
||||
$("#red-ui-header-button-deploy-icon").attr("src",deploymentTypes[type].img);
|
||||
@ -133,37 +135,38 @@ RED.deploy = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
var activeNotifyMessage;
|
||||
RED.comms.subscribe("notification/runtime-deploy",function(topic,msg) {
|
||||
if (!activeNotifyMessage) {
|
||||
var currentRev = RED.nodes.version();
|
||||
if (currentRev === null || deployInflight || currentRev === msg.revision) {
|
||||
return;
|
||||
}
|
||||
var message = $('<p>').text(RED._('deploy.confirm.backgroundUpdate'));
|
||||
activeNotifyMessage = RED.notify(message,{
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._('deploy.confirm.button.ignore'),
|
||||
click: function() {
|
||||
activeNotifyMessage.close();
|
||||
activeNotifyMessage = null;
|
||||
}
|
||||
},
|
||||
{
|
||||
text: RED._('deploy.confirm.button.review'),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
activeNotifyMessage.close();
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
resolveConflict(nns,false);
|
||||
activeNotifyMessage = null;
|
||||
}
|
||||
var currentRev = RED.nodes.version();
|
||||
if (currentRev === null || deployInflight || currentRev === msg.revision) {
|
||||
return;
|
||||
}
|
||||
if (activeBackgroundDeployNotification?.hidden) {
|
||||
activeBackgroundDeployNotification.showNotification()
|
||||
return
|
||||
}
|
||||
const message = $('<p>').text(RED._('deploy.confirm.backgroundUpdate'));
|
||||
const options = {
|
||||
id: 'background-update',
|
||||
type: 'compact',
|
||||
modal: false,
|
||||
fixed: true,
|
||||
timeout: 10000,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._('deploy.confirm.button.review'),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
activeBackgroundDeployNotification.hideNotification();
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
resolveConflict(nns,false);
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
]
|
||||
}
|
||||
if (!activeBackgroundDeployNotification || activeBackgroundDeployNotification.closed) {
|
||||
activeBackgroundDeployNotification = RED.notify(message, options)
|
||||
} else {
|
||||
activeBackgroundDeployNotification.update(message, options)
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -220,7 +223,11 @@ RED.deploy = (function() {
|
||||
class: "primary disabled",
|
||||
click: function() {
|
||||
if (!$("#red-ui-deploy-dialog-confirm-deploy-review").hasClass('disabled')) {
|
||||
RED.diff.showRemoteDiff();
|
||||
RED.diff.showRemoteDiff(null, {
|
||||
onmerge: function () {
|
||||
activeBackgroundDeployNotification.close()
|
||||
}
|
||||
});
|
||||
conflictNotification.close();
|
||||
}
|
||||
}
|
||||
@ -233,6 +240,7 @@ RED.deploy = (function() {
|
||||
if (!$("#red-ui-deploy-dialog-confirm-deploy-merge").hasClass('disabled')) {
|
||||
RED.diff.mergeDiff(currentDiff);
|
||||
conflictNotification.close();
|
||||
activeBackgroundDeployNotification.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,6 +253,7 @@ RED.deploy = (function() {
|
||||
click: function() {
|
||||
save(true,activeDeploy);
|
||||
conflictNotification.close();
|
||||
activeBackgroundDeployNotification.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -255,21 +264,17 @@ RED.deploy = (function() {
|
||||
buttons: buttons
|
||||
});
|
||||
|
||||
var now = Date.now();
|
||||
RED.diff.getRemoteDiff(function(diff) {
|
||||
var ellapsed = Math.max(1000 - (Date.now()-now), 0);
|
||||
currentDiff = diff;
|
||||
setTimeout(function() {
|
||||
conflictCheck.hide();
|
||||
var d = Object.keys(diff.conflicts);
|
||||
if (d.length === 0) {
|
||||
conflictAutoMerge.show();
|
||||
$("#red-ui-deploy-dialog-confirm-deploy-merge").removeClass('disabled')
|
||||
} else {
|
||||
conflictManualMerge.show();
|
||||
}
|
||||
$("#red-ui-deploy-dialog-confirm-deploy-review").removeClass('disabled')
|
||||
},ellapsed);
|
||||
conflictCheck.hide();
|
||||
var d = Object.keys(diff.conflicts);
|
||||
if (d.length === 0) {
|
||||
conflictAutoMerge.show();
|
||||
$("#red-ui-deploy-dialog-confirm-deploy-merge").removeClass('disabled')
|
||||
} else {
|
||||
conflictManualMerge.show();
|
||||
}
|
||||
$("#red-ui-deploy-dialog-confirm-deploy-review").removeClass('disabled')
|
||||
})
|
||||
}
|
||||
function cropList(list) {
|
||||
|
@ -1099,11 +1099,11 @@ RED.diff = (function() {
|
||||
// var diff = generateDiff(originalFlow,nns);
|
||||
// showDiff(diff);
|
||||
// }
|
||||
function showRemoteDiff(diff) {
|
||||
if (diff === undefined) {
|
||||
getRemoteDiff(showRemoteDiff);
|
||||
function showRemoteDiff(diff, options = {}) {
|
||||
if (!diff) {
|
||||
getRemoteDiff((remoteDiff) => showRemoteDiff(remoteDiff, options));
|
||||
} else {
|
||||
showDiff(diff,{mode:'merge'});
|
||||
showDiff(diff,{...options, mode:'merge'});
|
||||
}
|
||||
}
|
||||
function parseNodes(nodeList) {
|
||||
@ -1240,7 +1240,7 @@ RED.diff = (function() {
|
||||
return diff;
|
||||
}
|
||||
|
||||
function showDiff(diff,options) {
|
||||
function showDiff(diff, options) {
|
||||
if (diffVisible) {
|
||||
return;
|
||||
}
|
||||
@ -1315,6 +1315,9 @@ RED.diff = (function() {
|
||||
if (!$("#red-ui-diff-view-diff-merge").hasClass('disabled')) {
|
||||
refreshConflictHeader(diff);
|
||||
mergeDiff(diff);
|
||||
if (options.onmerge) {
|
||||
options.onmerge()
|
||||
}
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@ -1345,6 +1348,7 @@ RED.diff = (function() {
|
||||
var newConfig = [];
|
||||
var node;
|
||||
var nodeChangedStates = {};
|
||||
var nodeMovedStates = {};
|
||||
var localChangedStates = {};
|
||||
for (id in localDiff.newConfig.all) {
|
||||
if (localDiff.newConfig.all.hasOwnProperty(id)) {
|
||||
@ -1352,12 +1356,14 @@ RED.diff = (function() {
|
||||
if (resolutions[id] === 'local') {
|
||||
if (node) {
|
||||
nodeChangedStates[id] = node.changed;
|
||||
nodeMovedStates[id] = node.moved;
|
||||
}
|
||||
newConfig.push(localDiff.newConfig.all[id]);
|
||||
} else if (resolutions[id] === 'remote') {
|
||||
if (!remoteDiff.deleted[id] && remoteDiff.newConfig.all.hasOwnProperty(id)) {
|
||||
if (node) {
|
||||
nodeChangedStates[id] = node.changed;
|
||||
nodeMovedStates[id] = node.moved;
|
||||
}
|
||||
localChangedStates[id] = 1;
|
||||
newConfig.push(remoteDiff.newConfig.all[id]);
|
||||
@ -1381,8 +1387,9 @@ RED.diff = (function() {
|
||||
}
|
||||
return {
|
||||
config: newConfig,
|
||||
nodeChangedStates: nodeChangedStates,
|
||||
localChangedStates: localChangedStates
|
||||
nodeChangedStates,
|
||||
nodeMovedStates,
|
||||
localChangedStates
|
||||
}
|
||||
}
|
||||
|
||||
@ -1393,6 +1400,7 @@ RED.diff = (function() {
|
||||
|
||||
var newConfig = appliedDiff.config;
|
||||
var nodeChangedStates = appliedDiff.nodeChangedStates;
|
||||
var nodeMovedStates = appliedDiff.nodeMovedStates;
|
||||
var localChangedStates = appliedDiff.localChangedStates;
|
||||
|
||||
var isDirty = RED.nodes.dirty();
|
||||
@ -1401,33 +1409,56 @@ RED.diff = (function() {
|
||||
t:"replace",
|
||||
config: RED.nodes.createCompleteNodeSet(),
|
||||
changed: nodeChangedStates,
|
||||
moved: nodeMovedStates,
|
||||
complete: true,
|
||||
dirty: isDirty,
|
||||
rev: RED.nodes.version()
|
||||
}
|
||||
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
var originalFlow = RED.nodes.originalFlow();
|
||||
// originalFlow is what the editor things it loaded
|
||||
// - add any newly added nodes from remote diff as they are now part of the record
|
||||
for (var id in diff.remoteDiff.added) {
|
||||
if (diff.remoteDiff.added.hasOwnProperty(id)) {
|
||||
if (diff.remoteDiff.newConfig.all.hasOwnProperty(id)) {
|
||||
originalFlow.push(JSON.parse(JSON.stringify(diff.remoteDiff.newConfig.all[id])));
|
||||
}
|
||||
}
|
||||
}
|
||||
// var originalFlow = RED.nodes.originalFlow();
|
||||
// // originalFlow is what the editor thinks it loaded
|
||||
// // - add any newly added nodes from remote diff as they are now part of the record
|
||||
// for (var id in diff.remoteDiff.added) {
|
||||
// if (diff.remoteDiff.added.hasOwnProperty(id)) {
|
||||
// if (diff.remoteDiff.newConfig.all.hasOwnProperty(id)) {
|
||||
// originalFlow.push(JSON.parse(JSON.stringify(diff.remoteDiff.newConfig.all[id])));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
RED.nodes.clear();
|
||||
var imported = RED.nodes.import(newConfig);
|
||||
|
||||
// Restore the original flow so subsequent merge resolutions can properly
|
||||
// identify new-vs-old
|
||||
RED.nodes.originalFlow(originalFlow);
|
||||
// // Restore the original flow so subsequent merge resolutions can properly
|
||||
// // identify new-vs-old
|
||||
// RED.nodes.originalFlow(originalFlow);
|
||||
|
||||
// Clear all change flags from the import
|
||||
RED.nodes.dirty(false);
|
||||
|
||||
const flowsToLock = new Set()
|
||||
function ensureUnlocked(id) {
|
||||
const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
|
||||
const isLocked = flow ? flow.locked : false;
|
||||
if (flow && isLocked) {
|
||||
flow.locked = false;
|
||||
flowsToLock.add(flow)
|
||||
}
|
||||
}
|
||||
imported.nodes.forEach(function(n) {
|
||||
if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
|
||||
if (nodeChangedStates[n.id]) {
|
||||
ensureUnlocked(n.z)
|
||||
n.changed = true;
|
||||
}
|
||||
if (nodeMovedStates[n.id]) {
|
||||
ensureUnlocked(n.z)
|
||||
n.moved = true;
|
||||
}
|
||||
})
|
||||
flowsToLock.forEach(flow => {
|
||||
flow.locked = true
|
||||
})
|
||||
|
||||
RED.nodes.version(diff.remoteDiff.rev);
|
||||
|
@ -221,12 +221,12 @@ RED.notifications = (function() {
|
||||
if (newType) {
|
||||
n.className = "red-ui-notification red-ui-notification-"+newType;
|
||||
}
|
||||
|
||||
newTimeout = newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout
|
||||
if (!fixed || newOptions.fixed === false) {
|
||||
newTimeout = (newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout)||5000;
|
||||
newTimeout === newTimeout || 5000
|
||||
}
|
||||
if (newOptions.buttons) {
|
||||
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
|
||||
var buttonSet = $('<div class="ui-dialog-buttonset"></div>').appendTo(nn)
|
||||
newOptions.buttons.forEach(function(buttonDef) {
|
||||
var b = $('<button>').text(buttonDef.text).on("click", buttonDef.click).appendTo(buttonSet);
|
||||
if (buttonDef.id) {
|
||||
@ -272,6 +272,15 @@ RED.notifications = (function() {
|
||||
};
|
||||
})());
|
||||
n.timeoutid = window.setTimeout(n.close,timeout||5000);
|
||||
} else if (timeout) {
|
||||
$(n).on("click.red-ui-notification-close", (function() {
|
||||
var nn = n;
|
||||
return function() {
|
||||
nn.hideNotification();
|
||||
window.clearTimeout(nn.timeoutid);
|
||||
};
|
||||
})());
|
||||
n.timeoutid = window.setTimeout(n.hideNotification,timeout||5000);
|
||||
}
|
||||
currentNotifications.push(n);
|
||||
if (options.id) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user