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");
|
RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
function createDiffTable(container) {
|
||||||
function buildDiffPanel(container) {
|
var diffList = $('<ol class="node-dialog-view-diff-diff"></ol>').appendTo(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);
|
diffList.editableList({
|
||||||
|
|
||||||
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({
|
|
||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
addItem: function(container,i,object) {
|
addItem: function(container,i,object) {
|
||||||
@ -290,7 +284,180 @@ RED.diff = (function() {
|
|||||||
container.i18n();
|
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) {
|
function formatWireProperty(wires,allNodes) {
|
||||||
var result = $("<div>",{class:"node-diff-property-wires"})
|
var result = $("<div>",{class:"node-diff-property-wires"})
|
||||||
@ -917,7 +1084,7 @@ RED.diff = (function() {
|
|||||||
if (diff === undefined) {
|
if (diff === undefined) {
|
||||||
getRemoteDiff(showRemoteDiff);
|
getRemoteDiff(showRemoteDiff);
|
||||||
} else {
|
} else {
|
||||||
showDiff(diff);
|
showDiff(diff,{mode:'merge'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function parseNodes(nodeList) {
|
function parseNodes(nodeList) {
|
||||||
@ -1054,10 +1221,12 @@ RED.diff = (function() {
|
|||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDiff(diff) {
|
function showDiff(diff,options) {
|
||||||
if (diffVisible) {
|
if (diffVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
options = options || {};
|
||||||
|
var mode = options.mode || 'merge';
|
||||||
|
|
||||||
var localDiff = diff.localDiff;
|
var localDiff = diff.localDiff;
|
||||||
var remoteDiff = diff.remoteDiff;
|
var remoteDiff = diff.remoteDiff;
|
||||||
@ -1065,15 +1234,56 @@ RED.diff = (function() {
|
|||||||
currentDiff = diff;
|
currentDiff = diff;
|
||||||
|
|
||||||
var trayOptions = {
|
var trayOptions = {
|
||||||
title: "Review Changes", //TODO: nls
|
title: options.title||"Review Changes", //TODO: nls
|
||||||
width: Infinity,
|
width: Infinity,
|
||||||
|
overlay: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.cancel"),
|
text: RED._((options.mode === 'merge')?"common.label.cancel":"common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
RED.tray.close();
|
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",
|
id: "node-diff-view-diff-merge",
|
||||||
text: RED._("deploy.confirm.button.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);
|
RED.tray.show(trayOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1374,7 +1404,7 @@ RED.diff = (function() {
|
|||||||
overlay: true,
|
overlay: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.done"),
|
text: RED._("common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
RED.tray.close();
|
RED.tray.close();
|
||||||
}
|
}
|
||||||
@ -1646,7 +1676,7 @@ RED.diff = (function() {
|
|||||||
return string1 === string2 ? 0 : 1;
|
return string1 === string2 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createUnifiedDiffTable(files) {
|
function createUnifiedDiffTable(files,commitOptions) {
|
||||||
var diffPanel = $('<div></div>');
|
var diffPanel = $('<div></div>');
|
||||||
files.forEach(function(file) {
|
files.forEach(function(file) {
|
||||||
var hunks = file.hunks;
|
var hunks = file.hunks;
|
||||||
@ -1655,10 +1685,61 @@ RED.diff = (function() {
|
|||||||
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
||||||
var codeBody = $('<tbody>').appendTo(codeTable);
|
var codeBody = $('<tbody>').appendTo(codeTable);
|
||||||
|
|
||||||
var diffRow = $('<tr class="node-text-diff-file-header">').appendTo(codeBody);
|
var diffFileRow = $('<tr class="node-text-diff-file-header">').appendTo(codeBody);
|
||||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
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);
|
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++) {
|
for (var i=0;i<hunks.length;i++) {
|
||||||
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
||||||
@ -1681,9 +1762,13 @@ RED.diff = (function() {
|
|||||||
$('<span class="prefix">').text(lineText[0]).appendTo(line);
|
$('<span class="prefix">').text(lineText[0]).appendTo(line);
|
||||||
$('<span>').text(lineText.substring(1)).appendTo(line);
|
$('<span>').text(lineText.substring(1)).appendTo(line);
|
||||||
if (lineText[0] === '+') {
|
if (lineText[0] === '+') {
|
||||||
|
localLineNo.addClass("added");
|
||||||
|
remoteLineNo.addClass("added");
|
||||||
line.addClass("added");
|
line.addClass("added");
|
||||||
remoteLineNo.text(remoteLine++);
|
remoteLineNo.text(remoteLine++);
|
||||||
} else if (lineText[0] === '-') {
|
} else if (lineText[0] === '-') {
|
||||||
|
localLineNo.addClass("removed");
|
||||||
|
remoteLineNo.addClass("removed");
|
||||||
line.addClass("removed");
|
line.addClass("removed");
|
||||||
localLineNo.text(localLine++);
|
localLineNo.text(localLine++);
|
||||||
} else {
|
} else {
|
||||||
@ -1701,15 +1786,15 @@ RED.diff = (function() {
|
|||||||
return diffPanel;
|
return diffPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCommitDiff(diff,title) {
|
function showCommitDiff(options) {
|
||||||
var commit = parseCommitDiff(diff);
|
var commit = parseCommitDiff(options.commit);
|
||||||
var trayOptions = {
|
var trayOptions = {
|
||||||
title: title||"Compare Changes", //TODO: nls
|
title: "View Commit Changes", //TODO: nls
|
||||||
width: Infinity,
|
width: Infinity,
|
||||||
overlay: true,
|
overlay: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.done"),
|
text: RED._("common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
RED.tray.close();
|
RED.tray.close();
|
||||||
}
|
}
|
||||||
@ -1726,12 +1811,17 @@ RED.diff = (function() {
|
|||||||
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
|
||||||
var codeBody = $('<tbody>').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 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);
|
RED.tray.show(trayOptions);
|
||||||
}
|
}
|
||||||
function showUnifiedDiff(diff,title) {
|
function showUnifiedDiff(options) {
|
||||||
|
var diff = options.diff;
|
||||||
|
var title = options.title;
|
||||||
|
|
||||||
var files = parseUnifiedDiff(diff);
|
var files = parseUnifiedDiff(diff);
|
||||||
var trayOptions = {
|
var trayOptions = {
|
||||||
title: title||"Compare Changes", //TODO: nls
|
title: title||"Compare Changes", //TODO: nls
|
||||||
@ -1752,7 +1845,7 @@ RED.diff = (function() {
|
|||||||
overlay: true,
|
overlay: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.done"),
|
text: RED._("common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
RED.tray.close();
|
RED.tray.close();
|
||||||
}
|
}
|
||||||
@ -1764,7 +1857,7 @@ RED.diff = (function() {
|
|||||||
open: function(tray) {
|
open: function(tray) {
|
||||||
var trayBody = tray.find('.editor-tray-body');
|
var trayBody = tray.find('.editor-tray-body');
|
||||||
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
|
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) {
|
function parseCommitDiff(diff) {
|
||||||
var result = {
|
var result = {};
|
||||||
};
|
|
||||||
var lines = diff.split("\n");
|
var lines = diff.split("\n");
|
||||||
|
var comment = [];
|
||||||
for (var i=0;i<lines.length;i++) {
|
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));
|
result.files = parseUnifiedDiff(lines.slice(i));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.preamble = lines.slice(0,i).join("\n");
|
result.comment = comment.join("\n");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
function parseUnifiedDiff(diff) {
|
function parseUnifiedDiff(diff) {
|
||||||
|
@ -489,9 +489,10 @@ RED.editor = (function() {
|
|||||||
|
|
||||||
function getEditStackTitle() {
|
function getEditStackTitle() {
|
||||||
var title = '<ul class="editor-tray-breadcrumbs">';
|
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 node = editStack[i];
|
||||||
var label = node.type;
|
label = node.type;
|
||||||
if (node.type === '_expression') {
|
if (node.type === '_expression') {
|
||||||
label = RED._("expressionEditor.title");
|
label = RED._("expressionEditor.title");
|
||||||
} else if (node.type === '_json') {
|
} else if (node.type === '_json') {
|
||||||
@ -524,7 +525,7 @@ RED.editor = (function() {
|
|||||||
title += '<li>'+label+'</li>';
|
title += '<li>'+label+'</li>';
|
||||||
}
|
}
|
||||||
title += '</ul>';
|
title += '</ul>';
|
||||||
return title;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEditForm(container,formId,type,ns) {
|
function buildEditForm(container,formId,type,ns) {
|
||||||
|
@ -908,9 +908,6 @@ RED.projects.settings = (function() {
|
|||||||
},payload).always(function() {
|
},payload).always(function() {
|
||||||
RED.deploy.setDeployInflight(false);
|
RED.deploy.setDeployInflight(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
var updateForm = function() {
|
var updateForm = function() {
|
||||||
if (activeProject.settings.credentialSecretInvalid) {
|
if (activeProject.settings.credentialSecretInvalid) {
|
||||||
|
@ -44,11 +44,13 @@ RED.projects = (function() {
|
|||||||
},
|
},
|
||||||
'create': (function() {
|
'create': (function() {
|
||||||
var projectNameInput;
|
var projectNameInput;
|
||||||
var projectSummaryEditor;
|
var projectSummaryInput;
|
||||||
|
var projectFlowFileInput;
|
||||||
var projectSecretInput;
|
var projectSecretInput;
|
||||||
var projectSecretSelect;
|
var projectSecretSelect;
|
||||||
var copyProject;
|
var copyProject;
|
||||||
var projectRepoInput;
|
var projectRepoInput;
|
||||||
|
var emptyProjectCredentialInput;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: "Create a new project", // TODO: NLS
|
title: "Create a new project", // TODO: NLS
|
||||||
@ -84,6 +86,16 @@ RED.projects = (function() {
|
|||||||
projectRepoInput.removeClass("input-error");
|
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);
|
$("#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);
|
projectNameInput = $('<input type="text"></input>').appendTo(row);
|
||||||
var projectNameInputChanged = false;
|
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
|
// Empty Project
|
||||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
|
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);
|
$('<label>Description</label>').appendTo(row);
|
||||||
projectSummaryEditor = $('<input type="text">').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
|
// Copy Project
|
||||||
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-copy"></div>').appendTo(container);
|
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();
|
validateForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Secret - empty/clone
|
// Secret - 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);
|
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||||
$('<label>Credentials key</label>').appendTo(row);
|
$('<label>Credentials encryption key</label>').appendTo(row);
|
||||||
projectSecretInput = $('<input type="text"></input>').appendTo(row);
|
projectSecretInput = $('<input type="text"></input>').appendTo(row);
|
||||||
|
|
||||||
|
createAsEmpty.click();
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
@ -177,8 +258,25 @@ RED.projects = (function() {
|
|||||||
name: projectNameInput.val(),
|
name: projectNameInput.val(),
|
||||||
}
|
}
|
||||||
if (projectType === 'empty') {
|
if (projectType === 'empty') {
|
||||||
projectData.summary = projectSummaryEditor.val();
|
projectData.summary = projectSummaryInput.val();
|
||||||
projectData.credentialSecret = projectSecretInput.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') {
|
} else if (projectType === 'copy') {
|
||||||
projectData.copy = copyProject.name;
|
projectData.copy = copyProject.name;
|
||||||
} else if (projectType === 'clone') {
|
} else if (projectType === 'clone') {
|
||||||
|
@ -65,7 +65,16 @@ RED.sidebar.versionControl = (function() {
|
|||||||
// done(error,null);
|
// done(error,null);
|
||||||
},
|
},
|
||||||
200: function(data) {
|
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);
|
// console.log(data.diff);
|
||||||
},
|
},
|
||||||
400: {
|
400: {
|
||||||
@ -336,7 +345,13 @@ RED.sidebar.versionControl = (function() {
|
|||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
if (activeProject) {
|
if (activeProject) {
|
||||||
$.getJSON("/projects/"+activeProject.name+"/commits/"+entry.sha,function(result) {
|
$.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 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);
|
// 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) {
|
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) {
|
if (options.width === Infinity) {
|
||||||
options.maximized = true;
|
options.maximized = true;
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
#node-dialog-view-diff {
|
.node-dialog-view-diff-panel {
|
||||||
.red-ui-editableList-container {
|
.red-ui-editableList-container {
|
||||||
border-radius:1px;
|
border-radius:1px;
|
||||||
padding:0;
|
padding:0;
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
}
|
}
|
||||||
#node-dialog-view-diff-diff {
|
.node-dialog-view-diff-diff {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top:80px;
|
top:30px;
|
||||||
bottom:10px;
|
bottom:10px;
|
||||||
left:10px;
|
left:10px;
|
||||||
right:10px;
|
right:10px;
|
||||||
@ -38,12 +38,22 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
// padding-bottom: 5px;
|
// padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
&.node-dialog-view-diff-panel-merge {
|
||||||
|
.node-dialog-view-diff-diff {
|
||||||
|
top: 80px
|
||||||
|
}
|
||||||
|
.node-dialog-view-diff-headers {
|
||||||
|
top: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#node-dialog-view-diff-headers {
|
|
||||||
|
.node-dialog-view-diff-headers {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left:237px;
|
left:237px;
|
||||||
right:18px;
|
right:18px;
|
||||||
top: 55px;
|
top: 5px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
div {
|
div {
|
||||||
height: 25px;
|
height: 25px;
|
||||||
@ -553,7 +563,6 @@
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
border: 1px solid $secondary-border-color;
|
border: 1px solid $secondary-border-color;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-family: monospace;
|
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: calc(100% - 20px);
|
width: calc(100% - 20px);
|
||||||
}
|
}
|
||||||
@ -562,6 +571,7 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
td.lineno {
|
td.lineno {
|
||||||
|
font-family: monospace;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #999;
|
color: #999;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
@ -571,6 +581,7 @@
|
|||||||
border-left: 1px solid $secondary-border-color;
|
border-left: 1px solid $secondary-border-color;
|
||||||
}
|
}
|
||||||
td.linetext {
|
td.linetext {
|
||||||
|
font-family: monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
span.prefix {
|
span.prefix {
|
||||||
@ -602,12 +613,42 @@
|
|||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
tr.node-text-diff-file-header td {
|
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;
|
background: #f3f3f3;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
color: #333;
|
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 {
|
tr.node-text-diff-header td {
|
||||||
|
font-family: monospace;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
@ -23,10 +23,23 @@
|
|||||||
.projects-edit-form form {
|
.projects-edit-form form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
.form-row {
|
.form-row {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 15px;
|
||||||
label {
|
label {
|
||||||
width: auto;
|
color: #555;
|
||||||
|
width: 100%;
|
||||||
display: block;
|
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 {
|
input[type=text], input[type=password],textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -36,6 +49,7 @@
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.projects-dialog-spinner {
|
.projects-dialog-spinner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -129,9 +129,24 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post(/([^\/]+)\/stage\/(.+)$/, function(req,res) {
|
// /:project/files/:treeish/file-path
|
||||||
var projectName = req.params[0];
|
app.get("/:id/files/:treeish/*", function(req,res) {
|
||||||
var file = req.params[1];
|
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) {
|
runtime.storage.projects.stageFile(projectName,file).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
||||||
@ -166,9 +181,9 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
app.delete(/([^\/]+)\/stage\/(.+)$/, function(req,res) {
|
app.delete("/:id/stage/*", function(req,res) {
|
||||||
var projectName = req.params[0];
|
var projectName = req.params.id;
|
||||||
var file = req.params[1];
|
var file = req.params[0];
|
||||||
|
|
||||||
runtime.storage.projects.unstageFile(projectName,file).then(function(data) {
|
runtime.storage.projects.unstageFile(projectName,file).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
||||||
@ -189,10 +204,10 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(/([^\/]+)\/diff\/([^\/]+)\/(.+)$/, function(req,res) {
|
app.get("/:id/diff/:type/*", function(req,res) {
|
||||||
var projectName = req.params[0];
|
var projectName = req.params.id;
|
||||||
var type = req.params[1];
|
var type = req.params.type;
|
||||||
var file = req.params[2];
|
var file = req.params[0];
|
||||||
runtime.storage.projects.getFileDiff(projectName,file,type).then(function(data) {
|
runtime.storage.projects.getFileDiff(projectName,file,type).then(function(data) {
|
||||||
res.json({
|
res.json({
|
||||||
diff: data
|
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;
|
return app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,6 @@ var projects = require("./projects");
|
|||||||
|
|
||||||
var initialFlowLoadComplete = false;
|
var initialFlowLoadComplete = false;
|
||||||
var settings;
|
var settings;
|
||||||
var flowsFile;
|
|
||||||
var flowsFullPath;
|
|
||||||
var flowsFileBackup;
|
|
||||||
var credentialsFile;
|
|
||||||
var credentialsFileBackup;
|
|
||||||
|
|
||||||
var localfilesystem = {
|
var localfilesystem = {
|
||||||
init: function(_settings, runtime) {
|
init: function(_settings, runtime) {
|
||||||
|
@ -212,6 +212,13 @@ Project.prototype.getCommits = function(options) {
|
|||||||
Project.prototype.getCommit = function(sha) {
|
Project.prototype.getCommit = function(sha) {
|
||||||
return gitTools.getCommit(this.path,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() {
|
Project.prototype.getFlowFile = function() {
|
||||||
console.log("Project.getFlowFile = ",this.paths.flowFile);
|
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) {
|
function getBackupFilename(filename) {
|
||||||
|
// TODO: DRY - ./index.js
|
||||||
var ffName = fspath.basename(filename);
|
var ffName = fspath.basename(filename);
|
||||||
var ffDir = fspath.dirname(filename);
|
var ffDir = fspath.dirname(filename);
|
||||||
return fspath.join(ffDir,"."+ffName+".backup");
|
return fspath.join(ffDir,"."+ffName+".backup");
|
||||||
@ -287,8 +303,23 @@ function createDefaultProject(project) {
|
|||||||
promises.push(util.writeFile(fspath.join(projectPath,file),defaultFileSet[file](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 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() {
|
}).then(function() {
|
||||||
return gitTools.commit(projectPath,"Create project");
|
return gitTools.commit(projectPath,"Create project");
|
||||||
})
|
})
|
||||||
@ -339,7 +370,7 @@ function createProject(metadata) {
|
|||||||
createProjectDirectory(project).then(function() {
|
createProjectDirectory(project).then(function() {
|
||||||
var projects = settings.get('projects');
|
var projects = settings.get('projects');
|
||||||
projects.projects[project] = {};
|
projects.projects[project] = {};
|
||||||
if (metadata.credentialSecret) {
|
if (metadata.hasOwnProperty('credentialSecret')) {
|
||||||
projects.projects[project].credentialSecret = metadata.credentialSecret;
|
projects.projects[project].credentialSecret = metadata.credentialSecret;
|
||||||
}
|
}
|
||||||
if (metadata.remote) {
|
if (metadata.remote) {
|
||||||
|
@ -14,20 +14,43 @@
|
|||||||
* limitations under the License.
|
* 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 = {
|
module.exports = {
|
||||||
"package.json": function(project) {
|
"package.json": function(project) {
|
||||||
return JSON.stringify({
|
var package = {
|
||||||
"name": project.name,
|
"name": project.name,
|
||||||
"description": project.summary||"A Node-RED Project",
|
"description": project.summary||"A Node-RED Project",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {}
|
"dependencies": {},
|
||||||
},"",4);
|
"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) {
|
"README.md": function(project) {
|
||||||
return project.name+"\n"+("=".repeat(project.name.length))+"\n\n"+(project.summary||"A Node-RED Project")+"\n\n";
|
return project.name+"\n"+("=".repeat(project.name.length))+"\n\n"+(project.summary||"A Node-RED Project")+"\n\n";
|
||||||
},
|
},
|
||||||
"settings.json": function() { return "{}" },
|
"settings.json": function() { return "{}" },
|
||||||
"flow.json": function() { return "[]" },
|
// "flow.json": function() { return "[]" },
|
||||||
"flow_cred.json": function() { return "{}" },
|
// "flow_cred.json": function() { return "{}" },
|
||||||
".gitignore": function() { return "*.backup" ;}
|
".gitignore": function() { return "*.backup" ;}
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,10 @@ module.exports = {
|
|||||||
return runCommand(gitCommand,args,cwd);
|
return runCommand(gitCommand,args,cwd);
|
||||||
},
|
},
|
||||||
getFiles: getFiles,
|
getFiles: getFiles,
|
||||||
|
getFile: function(cwd, filePath, treeish) {
|
||||||
|
var args = ["show",treeish+":"+filePath];
|
||||||
|
return runCommand(gitCommand,args,cwd);
|
||||||
|
},
|
||||||
stageFile: function(cwd,file) {
|
stageFile: function(cwd,file) {
|
||||||
var args = ["add"];
|
var args = ["add"];
|
||||||
if (Array.isArray(file)) {
|
if (Array.isArray(file)) {
|
||||||
|
@ -153,8 +153,9 @@ function getCommit(project,sha) {
|
|||||||
return activeProject.getCommit(sha);
|
return activeProject.getCommit(sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFile(project,path) {
|
function getFile(project,filePath,sha) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.getFile(filePath,sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveProject() {
|
function getActiveProject() {
|
||||||
@ -339,6 +340,7 @@ module.exports = {
|
|||||||
createProject: createProject,
|
createProject: createProject,
|
||||||
updateProject: updateProject,
|
updateProject: updateProject,
|
||||||
getFiles: getFiles,
|
getFiles: getFiles,
|
||||||
|
getFile: getFile,
|
||||||
stageFile: stageFile,
|
stageFile: stageFile,
|
||||||
unstageFile: unstageFile,
|
unstageFile: unstageFile,
|
||||||
commit: commit,
|
commit: commit,
|
||||||
|
Loading…
Reference in New Issue
Block a user