Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions htmlContent/git-panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
<div class="btn-group git-available dropup">
<button type="button" class="git-remotes btn small dropdown-toggle" data-toggle="dropdown" title="{{TOOLTIP_PICK_REMOTE}}">
<span class="caret"></span>
<span class="ftp-prefix">FTP: </span>
<span class="git-selected-remote">&mdash;</span>
<span class="ftp-prefix" hidden>FTP: </span>
<span class="git-selected-remote">&mdash; first</span>
</button>
<ul class="dropdown-menu git-remotes-dropdown"></ul>
<button title="{{TOOLTIP_PULL}}" class="btn small git-pull"><i class="octicon octicon-repo-pull"></i></button>
Expand Down
10 changes: 5 additions & 5 deletions htmlContent/git-remotes-picker.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!-- List of remotes defined for the current local repository -->
<li class="dropdown-header">{{Strings.GIT_REMOTES}}</li>
{{#gitFtpEnabled}}<li class="dropdown-header git-remotes-header">{{Strings.GIT_REMOTES}}</li>{{/gitFtpEnabled}}
{{#hasRemotes}}
{{#remotes}}
<li class="remote">
<a href="#" data-remote-name="{{name}}" data-is-gitftp="false">
<a href="#" data-remote-name="{{name}}" data-type="git" class="remote-name">
{{#deletable}}<span class="trash-icon remove-remote">&times;</span>{{/deletable}}
<span class="change-remote">{{name}}</span>
</a>
Expand All @@ -12,14 +12,14 @@
{{/hasRemotes}}
<li><a class="git-remote-new"><span>{{Strings.CREATE_NEW_REMOTE}}</span></a></li>

<!-- List of Git-FTP remotes, used only if Git-FTP is available and enabled -->
{{#gitFtpEnabled}}
<!-- List of Git-FTP remotes defined for the current local repository -->
<li class="divider"></li>
<li class="dropdown-header">{{Strings.GITFTP_REMOTES}}</li>
<li class="dropdown-header ftp-remotes-header">{{Strings.GITFTP_REMOTES}}</li>
{{#hasFtpRemotes}}
{{#ftpRemotes}}
<li class="gitftp-remote">
<a href="#" data-remote-name="{{name}}" data-is-gitftp="true">
<a href="#" data-remote-name="{{name}}" data-type="ftp" class="remote-name">
<span class="trash-icon gitftp-remove-remote">&times;</span>
<span class="change-remote">{{name}}</span>
</a>
Expand Down
6 changes: 1 addition & 5 deletions less/brackets-git.less
Original file line number Diff line number Diff line change
Expand Up @@ -259,18 +259,14 @@
}
}

[data-is-gitftp=true] .change-remote:before {
[data-type=ftp] .change-remote:before {
content: "FTP:";
padding-right: 5px;
opacity: 0.5;
}
.ftp-prefix {
display: none;
padding-right: 5px;
opacity: 0.5;
&[data-is-gitftp=true] {
display: inline;
}
}

.dropdown-menu {
Expand Down
64 changes: 44 additions & 20 deletions src/Ftp.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ define(function (require) {
var gitFtpRemote = $gitPanel.find(".git-remote-selected").text().trim();
$gitPanel.find(".gitftp-push").prop("disabled", true).addClass("btn-loading");

GitFtp.gitFtpPush(gitFtpRemote).done(function (result) {
GitFtp.push(gitFtpRemote).done(function (result) {
Dialogs.showModalDialog(
DefaultDialogs.DIALOG_ID_INFO,
Strings.GITFTP_PUSH_RESPONSE, // title
Expand All @@ -57,32 +57,56 @@ define(function (require) {
.addClass("btn-loading")
.prop("disabled", true);

return Utils.askQuestion(Strings.CREATE_GITFTP_NEW_REMOTE,
Strings.ENTER_GITFTP_REMOTE_NAME).then(function (name) {
return Utils.askQuestion(Strings.CREATE_GITFTP_NEW_REMOTE,
Strings.ENTER_GITFTP_REMOTE_URL,
{defaultValue: "ftp://user:passwd@example.org/folder"}).then(function (url) {

return GitFtp.gitFtpAddScope(name, url).then(function () {
// return handleGitFtpRemoteInit();
}).fail(function (err) {
ErrorHandler.showError(err, "Git-FTP remote creation failed");
});

return Utils.askQuestion(Strings.CREATE_GITFTP_NEW_REMOTE, Strings.ENTER_GITFTP_REMOTE_NAME)
.then(function (name) {
return Utils.askQuestion(
Strings.CREATE_GITFTP_NEW_REMOTE,
Strings.ENTER_GITFTP_REMOTE_URL,
{defaultValue: "ftp://user:passwd@example.org/folder"}
)
.then(function (url) {
return GitFtp.addScope(name, url).then(function () {

// Render the list element of the new remote
// TODO: replace this part with a way to call `Remotes.refreshRemotesPicker()`
var $newRemote = $("<li/>")
.addClass("gitftp-remote")
.append("<a/>")
.find("a")
.attr({href: "#", "data-remote-name": name, "data-type": "ftp"})
.addClass("remote-name")
.append("<span/>")
.find("span")
.addClass("trash-icon gitftp-remove-remote")
.html("&times;")
.end()
.append("<span/>")
.find("span:nth-child(2)")
.addClass("change-remote")
.text(name)
.end()
.end();

$gitPanel.find(".git-remotes-dropdown .ftp-remotes-header").after($newRemote);

}).fail(function (err) {
ErrorHandler.showError(err, "Git-FTP remote creation failed");
});
});
})
.finally(function () {
$gitPanel.find(".git-remotes")
.removeClass("btn-loading")
.prop("disabled", false);
});
}).finally(function () {
$gitPanel.find(".git-remotes")
.removeClass("btn-loading")
.prop("disabled", false);
});
}

function handleGitFtpRemoteRemove($this) {
$gitPanel.find(".git-remotes")
.addClass("btn-loading")
.prop("disabled", true);

var $selectedElement = $this.closest("a[.remote-name]"),
var $selectedElement = $this.closest(".remote-name"),
$currentRemote = $gitPanel.find(".git-remote-selected"),
remoteName = $selectedElement.data("remote-name");

Expand All @@ -92,7 +116,7 @@ define(function (require) {
{booleanResponse: true}
).then(function (response) {
if (response) {
return GitFtp.gitFtpRemoveScope(remoteName).then(function () {
return GitFtp.removeScope(remoteName).then(function () {
$selectedElement.parent().remove();
var newRemote = $gitPanel.find(".git-remotes-dropdown .remote").first().find("a").data("remote-name");
$currentRemote.data("remote-name", newRemote).html(newRemote);
Expand Down
22 changes: 11 additions & 11 deletions src/Git/GitFtp.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ define(function (require, exports) {

// Implementation

function gitFtpInit(scope) {
function init(scope) {
return git(["ftp", "init", "--scope", scope]);
}

function gitFtpPush(scope) {
function push(scope) {
return git(["ftp", "push", "--scope", scope]);
}

function getFtpRemotes() {
function getRemotes() {
return git(["config", "--list"]).then(function (stdout) {
return stdout.split("\n").reduce(function (result, row) {
var io = row.indexOf(".url");
Expand All @@ -37,7 +37,7 @@ define(function (require, exports) {
});
}

function gitFtpAddScope(scope, url) {
function addScope(scope, url) {
var uri = new URI(url),
username = uri.username(),
password = uri.password();
Expand All @@ -54,20 +54,20 @@ define(function (require, exports) {
git(scopeArgs),
git(usernameArgs),
git(passwordArgs)
]).fail(function (err) {
]).catch(function (err) {
throw ErrorHandler.rewrapError(err, "There was a problem editing Git configuration file. Operation aborted.");
});
}

function gitFtpRemoveScope(scope) {
function removeScope(scope) {
return git(["ftp", "remove-scope", scope]);
}

// Public API
exports.gitFtpInit = gitFtpInit;
exports.gitFtpPush = gitFtpPush;
exports.getFtpRemotes = getFtpRemotes;
exports.gitFtpAddScope = gitFtpAddScope;
exports.gitFtpRemoveScope = gitFtpRemoveScope;
exports.init = init;
exports.push = push;
exports.getRemotes = getRemotes;
exports.addScope = addScope;
exports.removeScope = removeScope;

});
139 changes: 81 additions & 58 deletions src/Remotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,26 @@ define(function (require) {
Events = require("src/Events"),
EventEmitter = require("src/EventEmitter"),
Git = require("src/Git/Git"),
GitFtp = require("src/Git/GitFtp"),
Preferences = require("src/Preferences"),
Promise = require("bluebird"),
Strings = require("strings"),
Utils = require("src/Utils");

// Templates
var gitRemotesPickerTemplate = require("text!htmlContent/git-remotes-picker.html");

// Module variables
var $selectedRemote = null,
$remotesDropdown = null;
$remotesDropdown = null,
$gitPanel = null,
gitFtpEnabled = false;

function initVariables() {
var $gitPanel = $("#git-panel");
$gitPanel = $("#git-panel");
$selectedRemote = $gitPanel.find(".git-selected-remote");
$remotesDropdown = $gitPanel.find(".git-remotes-dropdown");
gitFtpEnabled = Preferences.get("useGitFtp");
}

// Implementation
Expand All @@ -43,66 +50,84 @@ define(function (require) {

function clearRemotePicker() {
$selectedRemote
.html("&mdash;")
.data("remote", null);
.html("&mdash;")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use 4 spaces for indentation

.data("remote", null);
}

function selectRemote(remoteName) {
if (!remoteName) {
return clearRemotePicker();
}
setDefaultRemote(remoteName);
$selectedRemote
.text(remoteName)
.data("remote", remoteName);
}
// Check if the selected remote is a FTP remote
var isGitFtp = ($remotesDropdown.find(".remote-name[data-type=ftp][data-remote-name=\"" + remoteName + "\"]").length) ? true : false;

function refreshRemotesPicker() {
Git.getRemotes().then(function (remotes) {
var defaultRemoteName = getDefaultRemote(),
defaultRemote;
// Set as default remote only if is not an FTP remote
if (!isGitFtp) { setDefaultRemote(remoteName); }

// empty the list first
$remotesDropdown.empty();
// If is an FTP remote, disable the "pull" button, if not, enable it
$gitPanel.find("git-pull").prop("disabled", isGitFtp);

// Add option to define new remote
$remotesDropdown.append("<li><a class=\"git-remote-new\"><span>" + Strings.CREATE_NEW_REMOTE + "</span></a></li>");
$remotesDropdown.append("<li class=\"divider\"></li>");
// Enable the Git-FTP prefix if needed (or disable it)
$selectedRemote.prev(".ftp-prefix").prop("hidden", !isGitFtp);

if (remotes.length > 0) {
EventEmitter.emit(Events.GIT_REMOTE_AVAILABLE);
} else {
EventEmitter.emit(Events.GIT_REMOTE_NOT_AVAILABLE);
clearRemotePicker();
return;
}
// Update remote name of $selectedRemote
$selectedRemote.text(remoteName).data("remote", remoteName);
}

// Add options to change remote
remotes.forEach(function (remoteInfo) {
var canDelete = remoteInfo.name !== "origin";
function refreshRemotesPicker() {

var $a = $("<a/>")
.attr("href", "#")
.addClass("remote-name")
.data("remote-name", remoteInfo.name);
// TODO: replace `settle` with `all` applying [this](https://github.com/zaggino/brackets-git/pull/288#issuecomment-38674930)
// Run both getRemotes and getFtpRemotes and render with Mustache the template
Promise.settle([Git.getRemotes(), GitFtp.getRemotes()]).spread(function (remotes, ftpRemotes) {

// If Git.getRemotes was fulfilled and (GitFtp.getRemotes was fulfilled or disabled)...
if (remotes.isFulfilled() && (ftpRemotes.isFulfilled() || !gitFtpEnabled)) {

// Set default remote name and cache the remotes dropdown menu
var defaultRemoteName = getDefaultRemote(),
$remotesDropdown = $gitPanel.find(".git-remotes-dropdown"),
$remotesDropdownList = "";

// Disable Git-push and Git-pull if there are not remotes defined
$gitPanel
.find(".git-pull, .git-push")
.prop("disabled", (remotes._settledValue.length === 0 && ftpRemotes._settledValue.length === 0));

// Add options to change remote
remotes._settledValue = $.map(remotes._settledValue, function (remote) {
return {
"name": remote.name,
"deletable": (remote.name !== "origin") ? true : false
};
});

if (canDelete) {
$a.append("<span class='trash-icon remove-remote'>&times;</span>");
}
// Pass to Mustache the needed data
$remotesDropdownList = Mustache.render(gitRemotesPickerTemplate, {
Strings: Strings,
remotes: remotes._settledValue,
ftpRemotes: ftpRemotes._settledValue,
hasRemotes: remotes._settledValue.length ? true : false,
hasFtpRemotes: ftpRemotes._settledValue.length ? true : false,
gitFtpEnabled: gitFtpEnabled
});

$a.append("<span class='change-remote'>" + remoteInfo.name + "</span>");
$a.appendTo($("<li class=\"remote\"/>").appendTo($remotesDropdown));
// Inject the rendered template inside the $remotesDropdown
$remotesDropdown.html($remotesDropdownList);

if (remoteInfo.name === defaultRemoteName) {
defaultRemote = remoteInfo.name;
if (remotes._settledValue.length !== 0) {
selectRemote(defaultRemoteName);
} else {
clearRemotePicker();
}
}
// Git.getRemotes was not fulfilled or (GitFtp.getRemotes was not fulfilled and enabled)...
else {
ErrorHandler.showError(remotes.error(), "Git remotes fetching failed.");
if (ftpRemotes.isRejected() && gitFtpEnabled) {
ErrorHandler.showError(ftpRemotes.error(), "Git-FTP remotes fetching failed.");
}
}

return $a;
});

selectRemote(defaultRemote || _.first(remotes).name);
}).catch(function (err) {
ErrorHandler.showError(err, "Preparing remotes picker failed");
});
}

Expand All @@ -124,19 +149,17 @@ define(function (require) {
}

function deleteRemote(remoteName) {
return Utils.askQuestion(Strings.DELETE_REMOTE,
StringUtils.format(Strings.DELETE_REMOTE_NAME, remoteName),
{ booleanResponse: true })
.then(function (response) {
if (response === true) {
return Git.deleteRemote(remoteName).then(function () {
return refreshRemotesPicker();
});
}
})
.catch(function (err) {
ErrorHandler.logError(err);
});
return Utils.askQuestion(Strings.DELETE_REMOTE, StringUtils.format(Strings.DELETE_REMOTE_NAME, remoteName), { booleanResponse: true })
.then(function (response) {
if (response === true) {
return Git.deleteRemote(remoteName).then(function () {
return refreshRemotesPicker();
});
}
})
.catch(function (err) {
ErrorHandler.logError(err);
});
}

function pullFromRemote(remoteName) {
Expand Down