mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add commit-diff view
This commit is contained in:
parent
b9a3563e5b
commit
57533fd831
@ -21,15 +21,9 @@ RED.diff = (function() {
|
||||
RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
|
||||
|
||||
}
|
||||
|
||||
function buildDiffPanel(container) {
|
||||
var diffPanel = $('<div id="node-dialog-view-diff"><div id="node-dialog-view-diff-headers"></div><ol id="node-dialog-view-diff-diff"></ol></div>').appendTo(container);
|
||||
|
||||
var toolbar = $('<div class="node-diff-toolbar">'+
|
||||
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
|
||||
'</div>').prependTo(diffPanel);
|
||||
|
||||
diffList = diffPanel.find("#node-dialog-view-diff-diff").editableList({
|
||||
function createDiffTable(container) {
|
||||
var diffList = $('<ol class="node-dialog-view-diff-diff"></ol>').appendTo(container);
|
||||
diffList.editableList({
|
||||
addButton: false,
|
||||
scrollOnAdd: false,
|
||||
addItem: function(container,i,object) {
|
||||
@ -290,7 +284,180 @@ RED.diff = (function() {
|
||||
container.i18n();
|
||||
}
|
||||
});
|
||||
return diffPanel;
|
||||
return diffList;
|
||||
}
|
||||
function buildDiffPanel(container,diff,options) {
|
||||
var diffPanel = $('<div class="node-dialog-view-diff-panel"></div>').appendTo(container);
|
||||
var diffHeaders = $('<div class="node-dialog-view-diff-headers"></div>').appendTo(diffPanel);
|
||||
if (options.mode === "merge") {
|
||||
diffPanel.addClass("node-dialog-view-diff-panel-merge");
|
||||
var toolbar = $('<div class="node-diff-toolbar">'+
|
||||
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
|
||||
'</div>').prependTo(diffPanel);
|
||||
}
|
||||
var diffList = createDiffTable(diffPanel);
|
||||
|
||||
var localDiff = diff.localDiff;
|
||||
var remoteDiff = diff.remoteDiff;
|
||||
var conflicts = diff.conflicts;
|
||||
|
||||
var currentConfig = localDiff.currentConfig;
|
||||
var newConfig = localDiff.newConfig;
|
||||
|
||||
|
||||
if (remoteDiff !== undefined) {
|
||||
diffPanel.addClass('node-diff-three-way');
|
||||
var localTitle = options.oldRevTitle || RED._('diff.local');
|
||||
var remoteTitle = options.newRevTitle || RED._('diff.remote');
|
||||
$('<div></div>').text(localTitle).appendTo(diffHeaders);
|
||||
$('<div></div>').text(remoteTitle).appendTo(diffHeaders);
|
||||
} else {
|
||||
diffPanel.removeClass('node-diff-three-way');
|
||||
}
|
||||
|
||||
return {
|
||||
list: diffList,
|
||||
finish: function() {
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
category: 'config',
|
||||
color: '#f0f0f0'
|
||||
},
|
||||
tab: {
|
||||
n: {},
|
||||
nodes: currentConfig.globals
|
||||
},
|
||||
newTab: {
|
||||
n: {},
|
||||
nodes: newConfig.globals
|
||||
}
|
||||
};
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteTab = {
|
||||
n:{},
|
||||
nodes:remoteDiff.newConfig.globals
|
||||
};
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el);
|
||||
|
||||
var seenTabs = {};
|
||||
|
||||
currentConfig.tabOrder.forEach(function(tabId) {
|
||||
var tab = currentConfig.tabs[tabId];
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab
|
||||
};
|
||||
if (newConfig.tabs.hasOwnProperty(tabId)) {
|
||||
el.newTab = newConfig.tabs[tabId];
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteTab = remoteDiff.newConfig.tabs[tabId];
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
seenTabs[tabId] = true;
|
||||
diffList.editableList('addItem',el)
|
||||
});
|
||||
newConfig.tabOrder.forEach(function(tabId) {
|
||||
if (!seenTabs[tabId]) {
|
||||
seenTabs[tabId] = true;
|
||||
var tab = newConfig.tabs[tabId];
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab,
|
||||
newTab: tab
|
||||
};
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
});
|
||||
if (remoteDiff !== undefined) {
|
||||
remoteDiff.newConfig.tabOrder.forEach(function(tabId) {
|
||||
if (!seenTabs[tabId]) {
|
||||
var tab = remoteDiff.newConfig.tabs[tabId];
|
||||
// TODO how to recognise this is a remotely added flow
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
remoteDiff: remoteDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab,
|
||||
remoteTab:tab
|
||||
};
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
});
|
||||
}
|
||||
var subflowId;
|
||||
for (subflowId in currentConfig.subflows) {
|
||||
if (currentConfig.subflows.hasOwnProperty(subflowId)) {
|
||||
seenTabs[subflowId] = true;
|
||||
el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:currentConfig.subflows[subflowId]
|
||||
}
|
||||
if (newConfig.subflows.hasOwnProperty(subflowId)) {
|
||||
el.newTab = newConfig.subflows[subflowId];
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteTab = remoteDiff.newConfig.subflows[subflowId];
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
for (subflowId in newConfig.subflows) {
|
||||
if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
|
||||
seenTabs[subflowId] = true;
|
||||
el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:newConfig.subflows[subflowId],
|
||||
newTab:newConfig.subflows[subflowId]
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
for (subflowId in remoteDiff.newConfig.subflows) {
|
||||
if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
|
||||
el = {
|
||||
diff: localDiff,
|
||||
remoteDiff: remoteDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:remoteDiff.newConfig.subflows[subflowId],
|
||||
remoteTab: remoteDiff.newConfig.subflows[subflowId]
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function formatWireProperty(wires,allNodes) {
|
||||
var result = $("<div>",{class:"node-diff-property-wires"})
|
||||
@ -917,7 +1084,7 @@ RED.diff = (function() {
|
||||
if (diff === undefined) {
|
||||
getRemoteDiff(showRemoteDiff);
|
||||
} else {
|
||||
showDiff(diff);
|
||||
showDiff(diff,{mode:'merge'});
|
||||
}
|
||||
}
|
||||
function parseNodes(nodeList) {
|
||||
@ -1054,10 +1221,12 @@ RED.diff = (function() {
|
||||
return diff;
|
||||
}
|
||||
|
||||
function showDiff(diff) {
|
||||
function showDiff(diff,options) {
|
||||
if (diffVisible) {
|
||||
return;
|
||||
}
|
||||
options = options || {};
|
||||
var mode = options.mode || 'merge';
|
||||
|
||||
var localDiff = diff.localDiff;
|
||||
var remoteDiff = diff.remoteDiff;
|
||||
@ -1065,15 +1234,56 @@ RED.diff = (function() {
|
||||
currentDiff = diff;
|
||||
|
||||
var trayOptions = {
|
||||
title: "Review Changes", //TODO: nls
|
||||
title: options.title||"Review Changes", //TODO: nls
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
text: RED._((options.mode === 'merge')?"common.label.cancel":"common.label.close"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
// trayWidth = dimensions.width;
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var diffTable = buildDiffPanel(trayBody,diff,options);
|
||||
diffTable.list.hide();
|
||||
if (remoteDiff) {
|
||||
$("#node-diff-view-diff-merge").show();
|
||||
if (Object.keys(conflicts).length === 0) {
|
||||
$("#node-diff-view-diff-merge").removeClass('disabled');
|
||||
} else {
|
||||
$("#node-diff-view-diff-merge").addClass('disabled');
|
||||
}
|
||||
} else {
|
||||
$("#node-diff-view-diff-merge").hide();
|
||||
}
|
||||
refreshConflictHeader();
|
||||
// console.log("--------------");
|
||||
// console.log(localDiff);
|
||||
// console.log(remoteDiff);
|
||||
|
||||
setTimeout(function() {
|
||||
diffTable.finish();
|
||||
diffTable.list.show();
|
||||
},300);
|
||||
$("#sidebar-shade").show();
|
||||
},
|
||||
close: function() {
|
||||
diffVisible = false;
|
||||
$("#sidebar-shade").hide();
|
||||
|
||||
},
|
||||
show: function() {
|
||||
|
||||
}
|
||||
}
|
||||
if (options.mode === 'merge') {
|
||||
trayOptions.buttons.push(
|
||||
{
|
||||
id: "node-diff-view-diff-merge",
|
||||
text: RED._("deploy.confirm.button.merge"),
|
||||
@ -1086,189 +1296,9 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
// trayWidth = dimensions.width;
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var diffPanel = buildDiffPanel(trayBody);
|
||||
if (remoteDiff) {
|
||||
$("#node-diff-view-diff-merge").show();
|
||||
if (Object.keys(conflicts).length === 0) {
|
||||
$("#node-diff-view-diff-merge").removeClass('disabled');
|
||||
} else {
|
||||
$("#node-diff-view-diff-merge").addClass('disabled');
|
||||
}
|
||||
} else {
|
||||
$("#node-diff-view-diff-merge").hide();
|
||||
}
|
||||
refreshConflictHeader();
|
||||
|
||||
$("#node-dialog-view-diff-headers").empty();
|
||||
// console.log("--------------");
|
||||
// console.log(localDiff);
|
||||
// console.log(remoteDiff);
|
||||
var currentConfig = localDiff.currentConfig;
|
||||
var newConfig = localDiff.newConfig;
|
||||
conflicts = conflicts || {};
|
||||
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
category: 'config',
|
||||
color: '#f0f0f0'
|
||||
},
|
||||
tab: {
|
||||
n: {},
|
||||
nodes: currentConfig.globals
|
||||
},
|
||||
newTab: {
|
||||
n: {},
|
||||
nodes: newConfig.globals
|
||||
}
|
||||
};
|
||||
|
||||
if (remoteDiff !== undefined) {
|
||||
diffPanel.addClass('node-diff-three-way');
|
||||
|
||||
$('<div data-i18n="diff.local"></div><div data-i18n="diff.remote"></div>').i18n().appendTo("#node-dialog-view-diff-headers");
|
||||
el.remoteTab = {
|
||||
n:{},
|
||||
nodes:remoteDiff.newConfig.globals
|
||||
};
|
||||
el.remoteDiff = remoteDiff;
|
||||
} else {
|
||||
diffPanel.removeClass('node-diff-three-way');
|
||||
);
|
||||
}
|
||||
|
||||
diffList.editableList('addItem',el);
|
||||
|
||||
var seenTabs = {};
|
||||
|
||||
currentConfig.tabOrder.forEach(function(tabId) {
|
||||
var tab = currentConfig.tabs[tabId];
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab
|
||||
};
|
||||
if (newConfig.tabs.hasOwnProperty(tabId)) {
|
||||
el.newTab = newConfig.tabs[tabId];
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteTab = remoteDiff.newConfig.tabs[tabId];
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
seenTabs[tabId] = true;
|
||||
diffList.editableList('addItem',el)
|
||||
});
|
||||
newConfig.tabOrder.forEach(function(tabId) {
|
||||
if (!seenTabs[tabId]) {
|
||||
seenTabs[tabId] = true;
|
||||
var tab = newConfig.tabs[tabId];
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab,
|
||||
newTab: tab
|
||||
};
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
});
|
||||
if (remoteDiff !== undefined) {
|
||||
remoteDiff.newConfig.tabOrder.forEach(function(tabId) {
|
||||
if (!seenTabs[tabId]) {
|
||||
var tab = remoteDiff.newConfig.tabs[tabId];
|
||||
// TODO how to recognise this is a remotely added flow
|
||||
var el = {
|
||||
diff: localDiff,
|
||||
remoteDiff: remoteDiff,
|
||||
def: RED.nodes.getType('tab'),
|
||||
tab:tab,
|
||||
remoteTab:tab
|
||||
};
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
});
|
||||
}
|
||||
var subflowId;
|
||||
for (subflowId in currentConfig.subflows) {
|
||||
if (currentConfig.subflows.hasOwnProperty(subflowId)) {
|
||||
seenTabs[subflowId] = true;
|
||||
el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:currentConfig.subflows[subflowId]
|
||||
}
|
||||
if (newConfig.subflows.hasOwnProperty(subflowId)) {
|
||||
el.newTab = newConfig.subflows[subflowId];
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteTab = remoteDiff.newConfig.subflows[subflowId];
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
for (subflowId in newConfig.subflows) {
|
||||
if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
|
||||
seenTabs[subflowId] = true;
|
||||
el = {
|
||||
diff: localDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:newConfig.subflows[subflowId],
|
||||
newTab:newConfig.subflows[subflowId]
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
el.remoteDiff = remoteDiff;
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
if (remoteDiff !== undefined) {
|
||||
for (subflowId in remoteDiff.newConfig.subflows) {
|
||||
if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
|
||||
el = {
|
||||
diff: localDiff,
|
||||
remoteDiff: remoteDiff,
|
||||
def: {
|
||||
defaults:{},
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
color: "#da9"
|
||||
},
|
||||
tab:remoteDiff.newConfig.subflows[subflowId],
|
||||
remoteTab: remoteDiff.newConfig.subflows[subflowId]
|
||||
}
|
||||
diffList.editableList('addItem',el)
|
||||
}
|
||||
}
|
||||
}
|
||||
$("#sidebar-shade").show();
|
||||
},
|
||||
close: function() {
|
||||
diffVisible = false;
|
||||
$("#sidebar-shade").hide();
|
||||
|
||||
},
|
||||
show: function() {
|
||||
|
||||
}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
@ -1374,7 +1404,7 @@ RED.diff = (function() {
|
||||
overlay: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("common.label.done"),
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
@ -1646,7 +1676,7 @@ RED.diff = (function() {
|
||||
return string1 === string2 ? 0 : 1;
|
||||
}
|
||||
|
||||
function createUnifiedDiffTable(files) {
|
||||
function createUnifiedDiffTable(files,commitOptions) {
|
||||
var diffPanel = $('<div></div>');
|
||||
files.forEach(function(file) {
|
||||
var hunks = file.hunks;
|
||||
@ -1655,10 +1685,61 @@ RED.diff = (function() {
|
||||
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
||||
var codeBody = $('<tbody>').appendTo(codeTable);
|
||||
|
||||
var diffRow = $('<tr class="node-text-diff-file-header">').appendTo(codeBody);
|
||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
||||
var diffFileRow = $('<tr class="node-text-diff-file-header">').appendTo(codeBody);
|
||||
var content = $('<td colspan="3"></td>').appendTo(diffFileRow);
|
||||
|
||||
var chevron = $('<i class="node-diff-chevron fa fa-angle-down"></i>').appendTo(content);
|
||||
diffFileRow.click(function(e) {
|
||||
diffFileRow.toggleClass("collapsed");
|
||||
var isCollapsed = diffFileRow.hasClass("collapsed");
|
||||
diffFileRow.nextUntil(".node-text-diff-file-header").toggle(!isCollapsed);
|
||||
})
|
||||
var label = $('<span></span>').text(file.file).appendTo(content);
|
||||
|
||||
if (commitOptions.project.files && commitOptions.project.files.flow === file.file) {
|
||||
var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
|
||||
$('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var projectName = commitOptions.project.name;
|
||||
var filename = commitOptions.project.files.flow;
|
||||
var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
|
||||
var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
|
||||
$.when($.getJSON(oldVersionUrl),$.getJSON(newVersionUrl)).done(function(oldVersion,newVersion) {
|
||||
var oldFlow;
|
||||
var newFlow;
|
||||
try {
|
||||
oldFlow = JSON.parse(oldVersion[0].content||"[]");
|
||||
} catch(err) {
|
||||
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
newFlow = JSON.parse(newVersion[0].content||"[]");
|
||||
} catch(err) {
|
||||
console.log("New Version doesn't contain valid JSON:",newFlow);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
var localDiff = generateDiff(oldFlow,oldFlow);
|
||||
var remoteDiff = generateDiff(oldFlow,newFlow);
|
||||
var diff = resolveDiffs(localDiff,remoteDiff);
|
||||
showDiff(diff,{
|
||||
title: filename,
|
||||
mode: 'view',
|
||||
oldRevTitle: commitOptions.oldRevTitle,
|
||||
newRevTitle: commitOptions.newRevTitle
|
||||
});
|
||||
// var flowDiffRow = $("<tr>").insertAfter(diffRow);
|
||||
// var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
|
||||
// currentDiff = diff;
|
||||
// var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
for (var i=0;i<hunks.length;i++) {
|
||||
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
||||
@ -1681,9 +1762,13 @@ RED.diff = (function() {
|
||||
$('<span class="prefix">').text(lineText[0]).appendTo(line);
|
||||
$('<span>').text(lineText.substring(1)).appendTo(line);
|
||||
if (lineText[0] === '+') {
|
||||
localLineNo.addClass("added");
|
||||
remoteLineNo.addClass("added");
|
||||
line.addClass("added");
|
||||
remoteLineNo.text(remoteLine++);
|
||||
} else if (lineText[0] === '-') {
|
||||
localLineNo.addClass("removed");
|
||||
remoteLineNo.addClass("removed");
|
||||
line.addClass("removed");
|
||||
localLineNo.text(localLine++);
|
||||
} else {
|
||||
@ -1701,15 +1786,15 @@ RED.diff = (function() {
|
||||
return diffPanel;
|
||||
}
|
||||
|
||||
function showCommitDiff(diff,title) {
|
||||
var commit = parseCommitDiff(diff);
|
||||
function showCommitDiff(options) {
|
||||
var commit = parseCommitDiff(options.commit);
|
||||
var trayOptions = {
|
||||
title: title||"Compare Changes", //TODO: nls
|
||||
title: "View Commit Changes", //TODO: nls
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("common.label.done"),
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
@ -1726,12 +1811,17 @@ RED.diff = (function() {
|
||||
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
||||
var codeBody = $('<tbody>').appendTo(codeTable);
|
||||
|
||||
var diffRow = $('<tr class="node-text-diff-file-header">').appendTo(codeBody);
|
||||
var diffRow = $('<tr class="node-text-diff-commit-header">').appendTo(codeBody);
|
||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
||||
var label = $('<pre></pre>').text(commit.preamble).appendTo(content);
|
||||
|
||||
$("<h3>").text(commit.title).appendTo(content);
|
||||
$('<div class="commit-body"></div>').text(commit.comment).appendTo(content);
|
||||
var summary = $('<div class="commit-summary"></div>').appendTo(content);
|
||||
$('<div style="float: right">').text("Commit "+commit.sha).appendTo(summary);
|
||||
$('<div>').text((commit.authorName||commit.author)+" - "+options.date).appendTo(summary);
|
||||
|
||||
|
||||
createUnifiedDiffTable(commit.files).appendTo(diffPanel);
|
||||
createUnifiedDiffTable(commit.files,options).appendTo(diffPanel);
|
||||
|
||||
|
||||
},
|
||||
@ -1744,7 +1834,10 @@ RED.diff = (function() {
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
function showUnifiedDiff(diff,title) {
|
||||
function showUnifiedDiff(options) {
|
||||
var diff = options.diff;
|
||||
var title = options.title;
|
||||
|
||||
var files = parseUnifiedDiff(diff);
|
||||
var trayOptions = {
|
||||
title: title||"Compare Changes", //TODO: nls
|
||||
@ -1752,7 +1845,7 @@ RED.diff = (function() {
|
||||
overlay: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("common.label.done"),
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
@ -1764,7 +1857,7 @@ RED.diff = (function() {
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
|
||||
createUnifiedDiffTable(files).appendTo(diffPanel);
|
||||
createUnifiedDiffTable(files,options).appendTo(diffPanel);
|
||||
|
||||
|
||||
},
|
||||
@ -1779,16 +1872,35 @@ RED.diff = (function() {
|
||||
}
|
||||
|
||||
function parseCommitDiff(diff) {
|
||||
var result = {
|
||||
};
|
||||
var result = {};
|
||||
var lines = diff.split("\n");
|
||||
var comment = [];
|
||||
for (var i=0;i<lines.length;i++) {
|
||||
if (/^diff /.test(lines[i])) {
|
||||
if (/^commit /.test(lines[i])) {
|
||||
result.sha = lines[i].substring(7);
|
||||
} else if (/^Author: /.test(lines[i])) {
|
||||
result.author = lines[i].substring(8);
|
||||
var m = /^(.*) <(.*)>$/.exec(result.author);
|
||||
if (m) {
|
||||
result.authorName = m[1];
|
||||
result.authorEmail = m[2];
|
||||
}
|
||||
} else if (/^Date: /.test(lines[i])) {
|
||||
result.date = lines[i].substring(8);
|
||||
} else if (/^ /.test(lines[i])) {
|
||||
if (!result.title) {
|
||||
result.title = lines[i].substring(4);
|
||||
} else {
|
||||
if (lines[i].length !== 4 || comment.length > 0) {
|
||||
comment.push(lines[i].substring(4));
|
||||
}
|
||||
}
|
||||
} else if (/^diff /.test(lines[i])) {
|
||||
result.files = parseUnifiedDiff(lines.slice(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.preamble = lines.slice(0,i).join("\n");
|
||||
result.comment = comment.join("\n");
|
||||
return result;
|
||||
}
|
||||
function parseUnifiedDiff(diff) {
|
||||
|
@ -489,9 +489,10 @@ RED.editor = (function() {
|
||||
|
||||
function getEditStackTitle() {
|
||||
var title = '<ul class="editor-tray-breadcrumbs">';
|
||||
for (var i=0;i<editStack.length;i++) {
|
||||
var label;
|
||||
for (var i=editStack.length-1;i<editStack.length;i++) {
|
||||
var node = editStack[i];
|
||||
var label = node.type;
|
||||
label = node.type;
|
||||
if (node.type === '_expression') {
|
||||
label = RED._("expressionEditor.title");
|
||||
} else if (node.type === '_json') {
|
||||
@ -524,7 +525,7 @@ RED.editor = (function() {
|
||||
title += '<li>'+label+'</li>';
|
||||
}
|
||||
title += '</ul>';
|
||||
return title;
|
||||
return label;
|
||||
}
|
||||
|
||||
function buildEditForm(container,formId,type,ns) {
|
||||
|
@ -908,9 +908,6 @@ RED.projects.settings = (function() {
|
||||
},payload).always(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
var updateForm = function() {
|
||||
if (activeProject.settings.credentialSecretInvalid) {
|
||||
|
@ -44,11 +44,13 @@ RED.projects = (function() {
|
||||
},
|
||||
'create': (function() {
|
||||
var projectNameInput;
|
||||
var projectSummaryEditor;
|
||||
var projectSummaryInput;
|
||||
var projectFlowFileInput;
|
||||
var projectSecretInput;
|
||||
var projectSecretSelect;
|
||||
var copyProject;
|
||||
var projectRepoInput;
|
||||
var emptyProjectCredentialInput;
|
||||
|
||||
return {
|
||||
title: "Create a new project", // TODO: NLS
|
||||
@ -84,6 +86,16 @@ RED.projects = (function() {
|
||||
projectRepoInput.removeClass("input-error");
|
||||
|
||||
}
|
||||
} else if (projectType === 'empty') {
|
||||
projectFlowFileInput.toggleClass("input-error",projectFlowFileInput.val()==='')
|
||||
valid = valid && projectFlowFileInput.val()!=='';
|
||||
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
||||
if (encryptionState === 'enabled') {
|
||||
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
||||
if (encryptionKeyType === 'custom') {
|
||||
valid = valid && emptyProjectCredentialInput.val()!==''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$("#projects-dialog-create").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
|
||||
@ -108,12 +120,79 @@ RED.projects = (function() {
|
||||
|
||||
projectNameInput = $('<input type="text"></input>').appendTo(row);
|
||||
var projectNameInputChanged = false;
|
||||
projectNameInput.on("change keyup paste",function() { validateForm(); });
|
||||
projectNameInput.on("change keyup paste",function() { projectNameInputChanged = true; validateForm(); });
|
||||
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row);
|
||||
|
||||
// Empty Project
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
|
||||
$('<label>Summary <small>(optional)</small></label>').appendTo(row);
|
||||
projectSummaryEditor = $('<input type="text">').appendTo(row);
|
||||
$('<label>Description</label>').appendTo(row);
|
||||
projectSummaryInput = $('<input type="text">').appendTo(row);
|
||||
$('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row);
|
||||
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
|
||||
$('<label>Flow file</label>').appendTo(row);
|
||||
projectFlowFileInput = $('<input type="text">').val("flow.json")
|
||||
.on("change keyup paste",validateForm)
|
||||
.appendTo(row);
|
||||
$('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
|
||||
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
|
||||
$('<label>Credentials</label>').appendTo(row);
|
||||
|
||||
var credentialsBox = $('<div style="width: 550px">').appendTo(row);
|
||||
var credentialsRightBox = $('<div style="min-height:150px; box-sizing: border-box; float: right; vertical-align: top; width: 331px; margin-left: -1px; padding: 15px; margin-top: -15px; border: 1px solid #ccc; border-radius: 3px; display: inline-block">').appendTo(credentialsBox);
|
||||
var credentialsLeftBox = $('<div style="vertical-align: top; width: 220px; display: inline-block">').appendTo(credentialsBox);
|
||||
|
||||
var credentialsEnabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid #ccc;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: white;"></div>').appendTo(credentialsLeftBox);
|
||||
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" checked style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="enabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-lock"></i> <span style="vertical-align: middle;">Enable encryption</span></label>').appendTo(credentialsEnabledBox);
|
||||
var credentialsDisabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid white;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: #ccc; "></div>').appendTo(credentialsLeftBox);
|
||||
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="disabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-unlock"></i> <span style="vertical-align: middle;">Disable encryption</span></label>').appendTo(credentialsDisabledBox);
|
||||
|
||||
credentialsLeftBox.find("input[name=projects-encryption-type]").click(function(e) {
|
||||
var val = $(this).val();
|
||||
var toEnable;
|
||||
var toDisable;
|
||||
if (val === 'enabled') {
|
||||
toEnable = credentialsEnabledBox;
|
||||
toDisable = credentialsDisabledBox;
|
||||
$(".projects-encryption-enabled-row").show();
|
||||
$(".projects-encryption-disabled-row").hide();
|
||||
} else {
|
||||
toDisable = credentialsEnabledBox;
|
||||
toEnable = credentialsDisabledBox;
|
||||
$(".projects-encryption-enabled-row").hide();
|
||||
$(".projects-encryption-disabled-row").show();
|
||||
|
||||
}
|
||||
|
||||
toEnable.css({
|
||||
borderColor: "#ccc",
|
||||
borderRightColor: "white"
|
||||
});
|
||||
toDisable.css({
|
||||
borderColor: "white",
|
||||
borderRightColor: "#ccc"
|
||||
})
|
||||
validateForm();
|
||||
})
|
||||
|
||||
row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
|
||||
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" checked style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="default" name="projects-encryption-key"> <span style="vertical-align: middle;">Use default key</span></label>').appendTo(row);
|
||||
row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
|
||||
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="custom" name="projects-encryption-key"> <span style="vertical-align: middle;">Use custom key</span></label>').appendTo(row);
|
||||
row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
|
||||
emptyProjectCredentialInput = $('<input disabled type="password" style="margin-left: 25px; width: calc(100% - 30px);"></input>').appendTo(row);
|
||||
emptyProjectCredentialInput.on("change keyup paste", validateForm);
|
||||
|
||||
row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox);
|
||||
$('<div class="form-tips form-warning" style="padding: 15px; margin: 5px;"><i class="fa fa-warning"></i> The credentials file will not be encrypted and its contents easily read</div>').appendTo(row);
|
||||
|
||||
credentialsRightBox.find("input[name=projects-encryption-key]").click(function() {
|
||||
var val = $(this).val();
|
||||
emptyProjectCredentialInput.attr("disabled",val === 'default');
|
||||
validateForm();
|
||||
})
|
||||
|
||||
|
||||
// Copy Project
|
||||
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-copy"></div>').appendTo(container);
|
||||
@ -151,11 +230,13 @@ RED.projects = (function() {
|
||||
validateForm();
|
||||
});
|
||||
|
||||
// Secret - empty/clone
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||
$('<label>Credentials key</label>').appendTo(row);
|
||||
// Secret - clone
|
||||
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||
$('<label>Credentials encryption key</label>').appendTo(row);
|
||||
projectSecretInput = $('<input type="text"></input>').appendTo(row);
|
||||
|
||||
createAsEmpty.click();
|
||||
|
||||
return container;
|
||||
},
|
||||
buttons: [
|
||||
@ -177,8 +258,25 @@ RED.projects = (function() {
|
||||
name: projectNameInput.val(),
|
||||
}
|
||||
if (projectType === 'empty') {
|
||||
projectData.summary = projectSummaryEditor.val();
|
||||
projectData.credentialSecret = projectSecretInput.val();
|
||||
projectData.summary = projectSummaryInput.val();
|
||||
projectData.files = {
|
||||
flow: projectFlowFileInput.val()
|
||||
};
|
||||
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
||||
if (encryptionState === 'enabled') {
|
||||
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
||||
if (encryptionKeyType === 'custom') {
|
||||
projectData.credentialSecret = emptyProjectCredentialInput.val();
|
||||
} else {
|
||||
// If 'use default', leave projectData.credentialSecret blank - as that will trigger
|
||||
// it to use the default (TODO: if its set...)
|
||||
}
|
||||
} else {
|
||||
// Disabled encryption by explicitly setting credSec to false
|
||||
projectData.credentialSecret = false;
|
||||
}
|
||||
|
||||
|
||||
} else if (projectType === 'copy') {
|
||||
projectData.copy = copyProject.name;
|
||||
} else if (projectType === 'clone') {
|
||||
|
@ -65,7 +65,16 @@ RED.sidebar.versionControl = (function() {
|
||||
// done(error,null);
|
||||
},
|
||||
200: function(data) {
|
||||
RED.diff.showUnifiedDiff(data.diff,(unstaged?"Unstaged":"Staged")+" changes : "+entry.file);
|
||||
var options = {
|
||||
diff: data.diff,
|
||||
title: (unstaged?"Unstaged":"Staged")+" changes : "+entry.file,
|
||||
oldRevTitle: unstaged?(entry.indexStatus === " "?"HEAD":"Staged"):"HEAD",
|
||||
newRevTitle: unstaged?"Unstaged":"Staged",
|
||||
oldRev: unstaged?(entry.indexStatus === " "?"@":":0"):"@",
|
||||
newRev: unstaged?"_":":0",
|
||||
project: activeProject
|
||||
}
|
||||
RED.diff.showUnifiedDiff(options);
|
||||
// console.log(data.diff);
|
||||
},
|
||||
400: {
|
||||
@ -336,7 +345,13 @@ RED.sidebar.versionControl = (function() {
|
||||
var activeProject = RED.projects.getActiveProject();
|
||||
if (activeProject) {
|
||||
$.getJSON("/projects/"+activeProject.name+"/commits/"+entry.sha,function(result) {
|
||||
RED.diff.showCommitDiff(result.commit);
|
||||
result.project = activeProject;
|
||||
result.oldRev = entry.sha+"~1";
|
||||
result.newRev = entry.sha;
|
||||
result.oldRevTitle = "Commit "+entry.sha.substring(0,7)+"~1";
|
||||
result.newRevTitle = "Commit "+entry.sha.substring(0,7);
|
||||
result.date = humanizeSinceDate(parseInt(entry.date));
|
||||
RED.diff.showCommitDiff(result);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -32,7 +32,11 @@ RED.tray = (function() {
|
||||
// var growButton = $('<a class="editor-tray-resize-button" style="cursor: w-resize;"><i class="fa fa-angle-left"></i></a>').appendTo(resizer);
|
||||
// var shrinkButton = $('<a class="editor-tray-resize-button" style="cursor: e-resize;"><i style="margin-left: 1px;" class="fa fa-angle-right"></i></a>').appendTo(resizer);
|
||||
if (options.title) {
|
||||
$('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header);
|
||||
var titles = stack.map(function(e) { return e.options.title });
|
||||
titles.push(options.title);
|
||||
var title = '<ul class="editor-tray-breadcrumbs"><li>'+titles.join("</li><li>")+'</li></ul>';
|
||||
|
||||
$('<div class="editor-tray-titlebar">'+title+'</div>').appendTo(header);
|
||||
}
|
||||
if (options.width === Infinity) {
|
||||
options.maximized = true;
|
||||
|
@ -15,15 +15,15 @@
|
||||
**/
|
||||
|
||||
|
||||
#node-dialog-view-diff {
|
||||
.node-dialog-view-diff-panel {
|
||||
.red-ui-editableList-container {
|
||||
border-radius:1px;
|
||||
padding:0;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
#node-dialog-view-diff-diff {
|
||||
.node-dialog-view-diff-diff {
|
||||
position: absolute;
|
||||
top:80px;
|
||||
top:30px;
|
||||
bottom:10px;
|
||||
left:10px;
|
||||
right:10px;
|
||||
@ -38,12 +38,22 @@
|
||||
padding: 5px;
|
||||
// padding-bottom: 5px;
|
||||
}
|
||||
&.node-dialog-view-diff-panel-merge {
|
||||
.node-dialog-view-diff-diff {
|
||||
top: 80px
|
||||
}
|
||||
#node-dialog-view-diff-headers {
|
||||
.node-dialog-view-diff-headers {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.node-dialog-view-diff-headers {
|
||||
position: absolute;
|
||||
left:237px;
|
||||
right:18px;
|
||||
top: 55px;
|
||||
top: 5px;
|
||||
height: 25px;
|
||||
div {
|
||||
height: 25px;
|
||||
@ -553,7 +563,6 @@
|
||||
margin: 10px;
|
||||
border: 1px solid $secondary-border-color;
|
||||
border-radius: 3px;
|
||||
font-family: monospace;
|
||||
table-layout: fixed;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
@ -562,6 +571,7 @@
|
||||
word-wrap: break-word;
|
||||
}
|
||||
td.lineno {
|
||||
font-family: monospace;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
background: #fafafa;
|
||||
@ -571,6 +581,7 @@
|
||||
border-left: 1px solid $secondary-border-color;
|
||||
}
|
||||
td.linetext {
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
padding: 1px 5px;
|
||||
span.prefix {
|
||||
@ -602,12 +613,42 @@
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
tr.node-text-diff-file-header td {
|
||||
font-family: monospace;
|
||||
background: #f3f3f3;
|
||||
padding: 5px 10px 5px 0;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
i.node-diff-chevron {
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
tr.node-text-diff-file-header.collapsed {
|
||||
td i.node-diff-chevron {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
tr.node-text-diff-commit-header td {
|
||||
background: #f3f3f3;
|
||||
padding: 5px 10px;
|
||||
color: #333;
|
||||
h3 {
|
||||
font-size: 1.4em;
|
||||
margin: 0;
|
||||
}
|
||||
.commit-summary {
|
||||
border-top: 1px solid $secondary-border-color;
|
||||
padding-top: 5px;
|
||||
color: #999;
|
||||
}
|
||||
.commit-body {
|
||||
margin-bottom:15px;
|
||||
white-space: pre;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
tr.node-text-diff-header td {
|
||||
font-family: monospace;
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
color: #666;
|
||||
|
@ -23,10 +23,23 @@
|
||||
.projects-edit-form form {
|
||||
margin: 0;
|
||||
.form-row {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
label {
|
||||
width: auto;
|
||||
color: #555;
|
||||
width: 100%;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
&.projects-edit-form-sublabel {
|
||||
color: #999;
|
||||
text-align: right;
|
||||
margin-bottom: -15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
&.projects-edit-form-inline-label {
|
||||
font-weight: normal;
|
||||
color: inherit;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
input[type=text], input[type=password],textarea {
|
||||
width: 100%;
|
||||
@ -36,6 +49,7 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.projects-dialog-spinner {
|
||||
position: absolute;
|
||||
|
@ -129,9 +129,24 @@ module.exports = {
|
||||
})
|
||||
});
|
||||
|
||||
app.post(/([^\/]+)\/stage\/(.+)$/, function(req,res) {
|
||||
var projectName = req.params[0];
|
||||
var file = req.params[1];
|
||||
// /:project/files/:treeish/file-path
|
||||
app.get("/:id/files/:treeish/*", function(req,res) {
|
||||
var projectId = req.params.id;
|
||||
var treeish = req.params.treeish;
|
||||
var filePath = req.params[0];
|
||||
|
||||
runtime.storage.projects.getFile(projectId,filePath,treeish).then(function(data) {
|
||||
res.json({content:data});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log(err.stack);
|
||||
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||
})
|
||||
});
|
||||
|
||||
app.post("/:id/stage/*", function(req,res) {
|
||||
var projectName = req.params.id;
|
||||
var file = req.params[0];
|
||||
|
||||
runtime.storage.projects.stageFile(projectName,file).then(function(data) {
|
||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
||||
@ -166,9 +181,9 @@ module.exports = {
|
||||
})
|
||||
});
|
||||
|
||||
app.delete(/([^\/]+)\/stage\/(.+)$/, function(req,res) {
|
||||
var projectName = req.params[0];
|
||||
var file = req.params[1];
|
||||
app.delete("/:id/stage/*", function(req,res) {
|
||||
var projectName = req.params.id;
|
||||
var file = req.params[0];
|
||||
|
||||
runtime.storage.projects.unstageFile(projectName,file).then(function(data) {
|
||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
||||
@ -189,10 +204,10 @@ module.exports = {
|
||||
})
|
||||
});
|
||||
|
||||
app.get(/([^\/]+)\/diff\/([^\/]+)\/(.+)$/, function(req,res) {
|
||||
var projectName = req.params[0];
|
||||
var type = req.params[1];
|
||||
var file = req.params[2];
|
||||
app.get("/:id/diff/:type/*", function(req,res) {
|
||||
var projectName = req.params.id;
|
||||
var type = req.params.type;
|
||||
var file = req.params[0];
|
||||
runtime.storage.projects.getFileDiff(projectName,file,type).then(function(data) {
|
||||
res.json({
|
||||
diff: data
|
||||
@ -229,14 +244,6 @@ module.exports = {
|
||||
})
|
||||
});
|
||||
|
||||
app.get(new RegExp("/([^\/]+)\/files\/(.*)"), function(req,res) {
|
||||
// Get project file
|
||||
});
|
||||
|
||||
app.post(new RegExp("/([^\/]+)\/files\/(.*)"), function(req,res) {
|
||||
// Update project file
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
@ -27,11 +27,6 @@ var projects = require("./projects");
|
||||
|
||||
var initialFlowLoadComplete = false;
|
||||
var settings;
|
||||
var flowsFile;
|
||||
var flowsFullPath;
|
||||
var flowsFileBackup;
|
||||
var credentialsFile;
|
||||
var credentialsFileBackup;
|
||||
|
||||
var localfilesystem = {
|
||||
init: function(_settings, runtime) {
|
||||
|
@ -212,6 +212,13 @@ Project.prototype.getCommits = function(options) {
|
||||
Project.prototype.getCommit = function(sha) {
|
||||
return gitTools.getCommit(this.path,sha);
|
||||
}
|
||||
Project.prototype.getFile = function (filePath,treeish) {
|
||||
if (treeish !== "_") {
|
||||
return gitTools.getFile(this.path, filePath, treeish);
|
||||
} else {
|
||||
return fs.readFile(fspath.join(this.path,filePath),"utf8");
|
||||
}
|
||||
};
|
||||
|
||||
Project.prototype.getFlowFile = function() {
|
||||
console.log("Project.getFlowFile = ",this.paths.flowFile);
|
||||
@ -255,7 +262,16 @@ Project.prototype.toJSON = function () {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function getCredentialsFilename(filename) {
|
||||
// TODO: DRY - ./index.js
|
||||
var ffDir = fspath.dirname(filename);
|
||||
var ffExt = fspath.extname(filename);
|
||||
var ffBase = fspath.basename(filename,ffExt);
|
||||
return fspath.join(ffDir,ffBase+"_cred"+ffExt);
|
||||
}
|
||||
function getBackupFilename(filename) {
|
||||
// TODO: DRY - ./index.js
|
||||
var ffName = fspath.basename(filename);
|
||||
var ffDir = fspath.dirname(filename);
|
||||
return fspath.join(ffDir,"."+ffName+".backup");
|
||||
@ -287,8 +303,23 @@ function createDefaultProject(project) {
|
||||
promises.push(util.writeFile(fspath.join(projectPath,file),defaultFileSet[file](project)));
|
||||
}
|
||||
}
|
||||
if (project.files) {
|
||||
if (project.files.flow && !/\.\./.test(project.files.flow)) {
|
||||
var flowFilePath = fspath.join(projectPath,project.files.flow);
|
||||
promises.push(util.writeFile(flowFilePath,"[]"));
|
||||
var credsFilePath = getCredentialsFilename(flowFilePath);
|
||||
promises.push(util.writeFile(credsFilePath,"{}"));
|
||||
}
|
||||
}
|
||||
return when.all(promises).then(function() {
|
||||
return gitTools.stageFile(projectPath,Object.keys(defaultFileSet));
|
||||
var files = Object.keys(defaultFileSet);
|
||||
if (project.files) {
|
||||
if (project.files.flow && !/\.\./.test(project.files.flow)) {
|
||||
files.push(project.files.flow);
|
||||
files.push(getCredentialsFilename(flowFilePath))
|
||||
}
|
||||
}
|
||||
return gitTools.stageFile(projectPath,files);
|
||||
}).then(function() {
|
||||
return gitTools.commit(projectPath,"Create project");
|
||||
})
|
||||
@ -339,7 +370,7 @@ function createProject(metadata) {
|
||||
createProjectDirectory(project).then(function() {
|
||||
var projects = settings.get('projects');
|
||||
projects.projects[project] = {};
|
||||
if (metadata.credentialSecret) {
|
||||
if (metadata.hasOwnProperty('credentialSecret')) {
|
||||
projects.projects[project].credentialSecret = metadata.credentialSecret;
|
||||
}
|
||||
if (metadata.remote) {
|
||||
|
@ -14,20 +14,43 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
var fspath = require("path");
|
||||
|
||||
function getCredentialsFilename(filename) {
|
||||
// TODO: DRY - ./index.js
|
||||
var ffDir = fspath.dirname(filename);
|
||||
var ffExt = fspath.extname(filename);
|
||||
var ffBase = fspath.basename(filename,ffExt);
|
||||
return fspath.join(ffDir,ffBase+"_cred"+ffExt);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
"package.json": function(project) {
|
||||
return JSON.stringify({
|
||||
var package = {
|
||||
"name": project.name,
|
||||
"description": project.summary||"A Node-RED Project",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {}
|
||||
},"",4);
|
||||
"dependencies": {},
|
||||
"node-red": {
|
||||
"settings": {
|
||||
}
|
||||
}
|
||||
};
|
||||
if (project.files) {
|
||||
if (project.files.flow) {
|
||||
package['node-red'].settings.flowFile = project.files.flow;
|
||||
package['node-red'].settings.credentialsFile = getCredentialsFilename(project.files.flow);
|
||||
}
|
||||
}
|
||||
return JSON.stringify(package,"",4);
|
||||
},
|
||||
"README.md": function(project) {
|
||||
return project.name+"\n"+("=".repeat(project.name.length))+"\n\n"+(project.summary||"A Node-RED Project")+"\n\n";
|
||||
},
|
||||
"settings.json": function() { return "{}" },
|
||||
"flow.json": function() { return "[]" },
|
||||
"flow_cred.json": function() { return "{}" },
|
||||
// "flow.json": function() { return "[]" },
|
||||
// "flow_cred.json": function() { return "{}" },
|
||||
".gitignore": function() { return "*.backup" ;}
|
||||
}
|
||||
|
@ -215,6 +215,10 @@ module.exports = {
|
||||
return runCommand(gitCommand,args,cwd);
|
||||
},
|
||||
getFiles: getFiles,
|
||||
getFile: function(cwd, filePath, treeish) {
|
||||
var args = ["show",treeish+":"+filePath];
|
||||
return runCommand(gitCommand,args,cwd);
|
||||
},
|
||||
stageFile: function(cwd,file) {
|
||||
var args = ["add"];
|
||||
if (Array.isArray(file)) {
|
||||
|
@ -153,8 +153,9 @@ function getCommit(project,sha) {
|
||||
return activeProject.getCommit(sha);
|
||||
}
|
||||
|
||||
function getFile(project,path) {
|
||||
|
||||
function getFile(project,filePath,sha) {
|
||||
checkActiveProject(project);
|
||||
return activeProject.getFile(filePath,sha);
|
||||
}
|
||||
|
||||
function getActiveProject() {
|
||||
@ -339,6 +340,7 @@ module.exports = {
|
||||
createProject: createProject,
|
||||
updateProject: updateProject,
|
||||
getFiles: getFiles,
|
||||
getFile: getFile,
|
||||
stageFile: stageFile,
|
||||
unstageFile: unstageFile,
|
||||
commit: commit,
|
||||
|
Loading…
Reference in New Issue
Block a user