/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.sidebar.versionControl = (function() { var sidebarContent; var sections; var allChanges = {}; var unstagedChangesList; var stageAllButton; var stagedChangesList; var unstageAllButton; var unstagedChanges; var stagedChanges; var bulkChangeSpinner; var unmergedContent; var unmergedChangesList; var commitButton; var mergeConflictNotification; var localChanges; var localCommitList; var localCommitListShade; // var remoteCommitList; var isMerging; // TODO: DRY projectSummary.js function createChangeEntry(row, entry, status, state) { row.addClass("sidebar-version-control-change-entry"); var container = $('
').appendTo(row); if (entry.label) { row.addClass('node-info-none'); container.text(entry.label); return; } var icon = $('').appendTo(container); var label = $('').appendTo(container); var bg = $('
').appendTo(row); var viewDiffButton = $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); var activeProject = RED.projects.getActiveProject(); var diffTarget = (state === 'staged')?"index":"tree"; utils.sendRequest({ url: "projects/"+activeProject.name+"/diff/"+diffTarget+"/"+encodeURIComponent(entry.file), type: "GET", responses: { 0: function(error) { console.log(error); // done(error,null); }, 200: function(data) { if (mergeConflictNotification) { mergeConflictNotification.close(); mergeConflictNotification = null; } var title; if (state === 'unstaged') { title = 'Unstaged changes : '+entry.file } else if (state === 'staged') { title = 'Staged changes : '+entry.file } else { title = 'Resolve conflicts : '+entry.file } var options = { diff: data.diff, title: title, unmerged: state === 'unmerged', project: activeProject } if (state == 'unstaged') { options.oldRevTitle = entry.indexStatus === " "?"HEAD":"Staged"; options.newRevTitle = "Unstaged"; options.oldRev = entry.indexStatus === " "?"@":":0"; options.newRev = "_"; } else if (state === 'staged') { options.oldRevTitle = "HEAD"; options.newRevTitle = "Staged"; options.oldRev = "@"; options.newRev = ":0"; } else { options.onresolve = function(resolution) { utils.sendRequest({ url: "projects/"+activeProject.name+"/resolve/"+encodeURIComponent(entry.file), type: "POST", responses: { 0: function(error) { console.log(error); // done(error,null); }, 200: function(data) { refresh(true); }, 400: { 'unexpected_error': function(error) { console.log(error); // done(error,null); } }, } },{resolutions:resolution.resolutions[entry.file]}); } } options.oncancel = showMergeConflictNotification; RED.diff.showUnifiedDiff(options); // console.log(data.diff); }, 400: { 'unexpected_error': function(error) { console.log(error); // done(error,null); } } } }) }) if (state !== 'unmerged') { $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); var activeProject = RED.projects.getActiveProject(); entry.spinner = utils.addSpinnerOverlay(row).addClass('projects-version-control-spinner-sidebar'); utils.sendRequest({ url: "projects/"+activeProject.name+"/stage/"+encodeURIComponent(entry.file), type: (state==='unstaged')?"POST":"DELETE", responses: { 0: function(error) { console.log(error); // done(error,null); }, 200: function(data) { refreshFiles(data); }, 400: { 'unexpected_error': function(error) { console.log(error); // done(error,null); } }, } },{}); }); } entry["update"+((state==='unstaged')?"Unstaged":"Staged")] = function(entry,status) { container.removeClass(); var iconClass = ""; if (status === 'A') { container.addClass("node-diff-added"); iconClass = "fa-plus-square"; } else if (status === '?') { container.addClass("node-diff-unchanged"); iconClass = "fa-question-circle-o"; } else if (status === 'D') { container.addClass("node-diff-deleted"); iconClass = "fa-minus-square"; } else if (status === 'M') { container.addClass("node-diff-changed"); iconClass = "fa-square"; } else if (status === 'R') { container.addClass("node-diff-changed"); iconClass = "fa-toggle-right"; } else if (status === 'U') { container.addClass("node-diff-conflicted"); iconClass = "fa-exclamation-triangle"; } else { iconClass = "fa-exclamation-triangle" } label.empty(); $('').text(entry.file.replace(/\\(.)/g,"$1")).appendTo(label); if (entry.oldName) { $('').prependTo(label); $('').text(entry.oldName.replace(/\\(.)/g,"$1")).prependTo(label); // label.text(entry.oldName+" -> "+entry.file); } // console.log(entry.file,status,iconClass); icon.removeClass(); icon.addClass("fa "+iconClass); if (entry.spinner) { entry.spinner.remove(); delete entry.spinner; } viewDiffButton.attr("disabled",(status === 'D' || status === '?')); viewDiffButton.find("i") .toggleClass('fa-eye',!(status === 'D' || status === '?')) .toggleClass('fa-eye-slash',(status === 'D' || status === '?')) } entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status); } var utils; function init(_utils) { utils = _utils; RED.actions.add("core:show-version-control-tab",show); RED.events.on("deploy", function() { var activeProject = RED.projects.getActiveProject(); if (activeProject) { // TODO: this is a full refresh of the files - should be able to // just do an incremental refresh allChanges = {}; unstagedChangesList.editableList('empty'); stagedChangesList.editableList('empty'); unmergedChangesList.editableList('empty'); $.getJSON("/projects/"+activeProject.name+"/status",function(result) { refreshFiles(result); }); } }) sidebarContent = $('
', {class:"sidebar-version-control"}); var stackContainer = $("
",{class:"sidebar-version-control-stack"}).appendTo(sidebarContent); sections = RED.stack.create({ container: stackContainer, fill: true, singleExpanded: true }); localChanges = sections.add({ title: "Local Changes", collapsible: true }); localChanges.expand(); localChanges.content.css({height:"100%"}); var bg = $('
').appendTo(localChanges.header); $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); refresh(true); }) var unstagedContent = $('').appendTo(localChanges.content); var header = $('').appendTo(unstagedContent); stageAllButton = $('') .appendTo(header) .click(function(evt) { evt.preventDefault(); evt.stopPropagation(); var toStage = Object.keys(allChanges).filter(function(fn) { return allChanges[fn].treeStatus !== ' '; }); updateBulk(toStage,true); }); unstagedChangesList = $("
    ",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(unstagedContent); unstagedChangesList.editableList({ addButton: false, scrollOnAdd: false, addItem: function(row,index,entry) { createChangeEntry(row,entry,entry.treeStatus,'unstaged'); }, sort: function(A,B) { if (A.treeStatus === '?' && B.treeStatus !== '?') { return 1; } else if (A.treeStatus !== '?' && B.treeStatus === '?') { return -1; } return A.file.localeCompare(B.file); } }) unmergedContent = $('').appendTo(localChanges.content); header = $('').appendTo(unmergedContent); bg = $('
    ').appendTo(header); var abortMergeButton = $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); evt.stopPropagation(); var spinner =u(unmergedContent); var activeProject = RED.projects.getActiveProject(); utils.sendRequest({ url: "projects/"+activeProject.name+"/merge", type: "DELETE", responses: { 0: function(error) { console.log(error); }, 200: function(data) { spinner.remove(); refresh(true); }, 400: { 'unexpected_error': function(error) { console.log(error); } }, } }); }); unmergedChangesList = $("
      ",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(unmergedContent); unmergedChangesList.editableList({ addButton: false, scrollOnAdd: false, addItem: function(row,index,entry) { createChangeEntry(row,entry,entry.treeStatus,'unmerged'); }, sort: function(A,B) { if (A.treeStatus === '?' && B.treeStatus !== '?') { return 1; } else if (A.treeStatus !== '?' && B.treeStatus === '?') { return -1; } return A.file.localeCompare(B.file); } }) var stagedContent = $('').appendTo(localChanges.content); header = $('').appendTo(stagedContent); bg = $('
      ').appendTo(header); commitButton = $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); evt.stopPropagation(); commitMessage.val(""); submitCommitButton.attr("disabled",true); unstagedContent.css("height","30px"); if (unmergedContent.is(":visible")) { unmergedContent.css("height","30px"); stagedContent.css("height","calc(100% - 60px - 175px)"); } else { stagedContent.css("height","calc(100% - 30px - 175px)"); } commitBox.show(); setTimeout(function() { commitBox.css("height","175px"); },10); stageAllButton.attr("disabled",true); unstageAllButton.attr("disabled",true); commitButton.attr("disabled",true); commitMessage.focus(); }); unstageAllButton = $('') .appendTo(bg) .click(function(evt) { evt.preventDefault(); evt.stopPropagation(); var toUnstage = Object.keys(allChanges).filter(function(fn) { return allChanges[fn].indexStatus !== ' ' && allChanges[fn].indexStatus !== '?'; }); updateBulk(toUnstage,false); }); stagedChangesList = $("
        ",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(stagedContent); stagedChangesList.editableList({ addButton: false, scrollOnAdd: false, addItem: function(row,index,entry) { createChangeEntry(row,entry,entry.indexStatus,'staged'); }, sort: function(A,B) { return A.file.localeCompare(B.file); } }) commitBox = $('').hide().appendTo(localChanges.content); var commitMessage = $('