Reset New branch button when issue state changes
This commit is contained in:
parent
defdf45ab5
commit
83c9d8cf86
3 changed files with 172 additions and 138 deletions
|
@ -20,57 +20,60 @@ class Issue {
|
|||
});
|
||||
Issue.initIssueBtnEventListeners();
|
||||
}
|
||||
|
||||
Issue.$btnNewBranch = $('#new-branch');
|
||||
|
||||
Issue.initMergeRequests();
|
||||
Issue.initRelatedBranches();
|
||||
Issue.initCanCreateBranch();
|
||||
}
|
||||
|
||||
static initIssueBtnEventListeners() {
|
||||
var issueFailMessage;
|
||||
issueFailMessage = 'Unable to update this issue at this time.';
|
||||
return $('a.btn-close, a.btn-reopen').on('click', function(e) {
|
||||
var $this, isClose, shouldSubmit, url;
|
||||
const issueFailMessage = 'Unable to update this issue at this time.';
|
||||
|
||||
const closeButtons = $('a.btn-close');
|
||||
const isClosedBadge = $('div.status-box-closed');
|
||||
const isOpenBadge = $('div.status-box-open');
|
||||
const projectIssuesCounter = $('.issue_counter');
|
||||
const reopenButtons = $('a.btn-reopen');
|
||||
|
||||
return closeButtons.add(reopenButtons).on('click', function(e) {
|
||||
var $this, shouldSubmit, url;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
$this = $(this);
|
||||
isClose = $this.hasClass('btn-close');
|
||||
shouldSubmit = $this.hasClass('btn-comment');
|
||||
if (shouldSubmit) {
|
||||
Issue.submitNoteForm($this.closest('form'));
|
||||
}
|
||||
$this.prop('disabled', true);
|
||||
Issue.setNewBranchButtonState(true, null);
|
||||
url = $this.attr('href');
|
||||
return $.ajax({
|
||||
type: 'PUT',
|
||||
url: url,
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
var issueStatus;
|
||||
issueStatus = isClose ? 'close' : 'open';
|
||||
return new Flash(issueFailMessage, 'alert');
|
||||
},
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
if ('id' in data) {
|
||||
$(document).trigger('issuable:change');
|
||||
let total = Number($('.issue_counter').text().replace(/[^\d]/, ''));
|
||||
if (isClose) {
|
||||
$('a.btn-close').addClass('hidden');
|
||||
$('a.btn-reopen').removeClass('hidden');
|
||||
$('div.status-box-closed').removeClass('hidden');
|
||||
$('div.status-box-open').addClass('hidden');
|
||||
total -= 1;
|
||||
} else {
|
||||
$('a.btn-reopen').addClass('hidden');
|
||||
$('a.btn-close').removeClass('hidden');
|
||||
$('div.status-box-closed').addClass('hidden');
|
||||
$('div.status-box-open').removeClass('hidden');
|
||||
total += 1;
|
||||
}
|
||||
$('.issue_counter').text(gl.text.addDelimiter(total));
|
||||
} else {
|
||||
new Flash(issueFailMessage, 'alert');
|
||||
}
|
||||
return $this.prop('disabled', false);
|
||||
url: url
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
new Flash(issueFailMessage);
|
||||
Issue.initCanCreateBranch();
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
if ('id' in data) {
|
||||
$(document).trigger('issuable:change');
|
||||
|
||||
const isClosed = $this.hasClass('btn-close');
|
||||
closeButtons.toggleClass('hidden', isClosed);
|
||||
reopenButtons.toggleClass('hidden', !isClosed);
|
||||
isClosedBadge.toggleClass('hidden', !isClosed);
|
||||
isOpenBadge.toggleClass('hidden', isClosed);
|
||||
|
||||
let numProjectIssues = Number(projectIssuesCounter.text().replace(/[^\d]/, ''));
|
||||
numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
|
||||
projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues));
|
||||
} else {
|
||||
new Flash(issueFailMessage);
|
||||
}
|
||||
|
||||
$this.prop('disabled', false);
|
||||
Issue.initCanCreateBranch();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -86,9 +89,9 @@ class Issue {
|
|||
static initMergeRequests() {
|
||||
var $container;
|
||||
$container = $('#merge-requests');
|
||||
return $.getJSON($container.data('url')).error(function() {
|
||||
return new Flash('Failed to load referenced merge requests', 'alert');
|
||||
}).success(function(data) {
|
||||
return $.getJSON($container.data('url')).fail(function() {
|
||||
return new Flash('Failed to load referenced merge requests');
|
||||
}).done(function(data) {
|
||||
if ('html' in data) {
|
||||
return $container.html(data.html);
|
||||
}
|
||||
|
@ -98,9 +101,9 @@ class Issue {
|
|||
static initRelatedBranches() {
|
||||
var $container;
|
||||
$container = $('#related-branches');
|
||||
return $.getJSON($container.data('url')).error(function() {
|
||||
return new Flash('Failed to load related branches', 'alert');
|
||||
}).success(function(data) {
|
||||
return $.getJSON($container.data('url')).fail(function() {
|
||||
return new Flash('Failed to load related branches');
|
||||
}).done(function(data) {
|
||||
if ('html' in data) {
|
||||
return $container.html(data.html);
|
||||
}
|
||||
|
@ -108,24 +111,27 @@ class Issue {
|
|||
}
|
||||
|
||||
static initCanCreateBranch() {
|
||||
var $container;
|
||||
$container = $('#new-branch');
|
||||
// If the user doesn't have the required permissions the container isn't
|
||||
// rendered at all.
|
||||
if ($container.length === 0) {
|
||||
if (Issue.$btnNewBranch.length === 0) {
|
||||
return;
|
||||
}
|
||||
return $.getJSON($container.data('path')).error(function() {
|
||||
$container.find('.unavailable').show();
|
||||
return new Flash('Failed to check if a new branch can be created.', 'alert');
|
||||
}).success(function(data) {
|
||||
if (data.can_create_branch) {
|
||||
$container.find('.available').show();
|
||||
} else {
|
||||
return $container.find('.unavailable').show();
|
||||
}
|
||||
return $.getJSON(Issue.$btnNewBranch.data('path')).fail(function() {
|
||||
Issue.setNewBranchButtonState(false, false);
|
||||
new Flash('Failed to check if a new branch can be created.');
|
||||
}).done(function(data) {
|
||||
Issue.setNewBranchButtonState(false, data.can_create_branch);
|
||||
});
|
||||
}
|
||||
|
||||
static setNewBranchButtonState(isPending, canCreate) {
|
||||
if (Issue.$btnNewBranch.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Issue.$btnNewBranch.find('.available').toggle(!isPending && canCreate);
|
||||
Issue.$btnNewBranch.find('.unavailable').toggle(!isPending && !canCreate);
|
||||
}
|
||||
}
|
||||
|
||||
export default Issue;
|
||||
|
|
4
changelogs/unreleased/reset-new-branch-button.yml
Normal file
4
changelogs/unreleased/reset-new-branch-button.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Reset New branch button when issue state changes
|
||||
merge_request: 5962
|
||||
author: winniehell
|
|
@ -1,18 +1,17 @@
|
|||
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
|
||||
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
|
||||
import Issue from '~/issue';
|
||||
|
||||
require('~/lib/utils/text_utility');
|
||||
|
||||
describe('Issue', function() {
|
||||
var INVALID_URL = 'http://goesnowhere.nothing/whereami';
|
||||
var $boxClosed, $boxOpen, $btnClose, $btnReopen;
|
||||
let $boxClosed, $boxOpen, $btnClose, $btnReopen;
|
||||
|
||||
preloadFixtures('issues/closed-issue.html.raw');
|
||||
preloadFixtures('issues/issue-with-task-list.html.raw');
|
||||
preloadFixtures('issues/open-issue.html.raw');
|
||||
|
||||
function expectErrorMessage() {
|
||||
var $flashMessage = $('div.flash-alert');
|
||||
const $flashMessage = $('div.flash-alert');
|
||||
expect($flashMessage).toExist();
|
||||
expect($flashMessage).toBeVisible();
|
||||
expect($flashMessage).toHaveText('Unable to update this issue at this time.');
|
||||
|
@ -26,10 +25,28 @@ describe('Issue', function() {
|
|||
expectVisibility($btnReopen, !isIssueOpen);
|
||||
}
|
||||
|
||||
function expectPendingRequest(req, $triggeredButton) {
|
||||
expect(req.type).toBe('PUT');
|
||||
expect(req.url).toBe($triggeredButton.attr('href'));
|
||||
expect($triggeredButton).toHaveProp('disabled', true);
|
||||
function expectNewBranchButtonState(isPending, canCreate) {
|
||||
if (Issue.$btnNewBranch.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $available = Issue.$btnNewBranch.find('.available');
|
||||
expect($available).toHaveText('New branch');
|
||||
|
||||
if (!isPending && canCreate) {
|
||||
expect($available).toBeVisible();
|
||||
} else {
|
||||
expect($available).toBeHidden();
|
||||
}
|
||||
|
||||
const $unavailable = Issue.$btnNewBranch.find('.unavailable');
|
||||
expect($unavailable).toHaveText('New branch unavailable');
|
||||
|
||||
if (!isPending && !canCreate) {
|
||||
expect($unavailable).toBeVisible();
|
||||
} else {
|
||||
expect($unavailable).toBeHidden();
|
||||
}
|
||||
}
|
||||
|
||||
function expectVisibility($element, shouldBeVisible) {
|
||||
|
@ -81,100 +98,107 @@ describe('Issue', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('close issue', function() {
|
||||
beforeEach(function() {
|
||||
loadFixtures('issues/open-issue.html.raw');
|
||||
findElements();
|
||||
this.issue = new Issue();
|
||||
[true, false].forEach((isIssueInitiallyOpen) => {
|
||||
describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, function() {
|
||||
const action = isIssueInitiallyOpen ? 'close' : 'reopen';
|
||||
|
||||
expectIssueState(true);
|
||||
});
|
||||
function ajaxSpy(req) {
|
||||
if (req.url === this.$triggeredButton.attr('href')) {
|
||||
expect(req.type).toBe('PUT');
|
||||
expect(this.$triggeredButton).toHaveProp('disabled', true);
|
||||
expectNewBranchButtonState(true, false);
|
||||
return this.issueStateDeferred;
|
||||
} else if (req.url === Issue.$btnNewBranch.data('path')) {
|
||||
expect(req.type).toBe('get');
|
||||
expectNewBranchButtonState(true, false);
|
||||
return this.canCreateBranchDeferred;
|
||||
}
|
||||
|
||||
it('closes an issue', function() {
|
||||
spyOn(jQuery, 'ajax').and.callFake(function(req) {
|
||||
expectPendingRequest(req, $btnClose);
|
||||
req.success({
|
||||
id: 34
|
||||
});
|
||||
expect(req.url).toBe('unexpected');
|
||||
return null;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
if (isIssueInitiallyOpen) {
|
||||
loadFixtures('issues/open-issue.html.raw');
|
||||
} else {
|
||||
loadFixtures('issues/closed-issue.html.raw');
|
||||
}
|
||||
|
||||
findElements();
|
||||
this.issue = new Issue();
|
||||
expectIssueState(isIssueInitiallyOpen);
|
||||
this.$triggeredButton = isIssueInitiallyOpen ? $btnClose : $btnReopen;
|
||||
|
||||
this.$projectIssuesCounter = $('.issue_counter');
|
||||
this.$projectIssuesCounter.text('1,001');
|
||||
|
||||
this.issueStateDeferred = new jQuery.Deferred();
|
||||
this.canCreateBranchDeferred = new jQuery.Deferred();
|
||||
|
||||
spyOn(jQuery, 'ajax').and.callFake(ajaxSpy.bind(this));
|
||||
});
|
||||
|
||||
$btnClose.trigger('click');
|
||||
it(`${action}s the issue`, function() {
|
||||
this.$triggeredButton.trigger('click');
|
||||
this.issueStateDeferred.resolve({
|
||||
id: 34
|
||||
});
|
||||
this.canCreateBranchDeferred.resolve({
|
||||
can_create_branch: !isIssueInitiallyOpen
|
||||
});
|
||||
|
||||
expectIssueState(false);
|
||||
expect($btnClose).toHaveProp('disabled', false);
|
||||
expect($('.issue_counter')).toHaveText(0);
|
||||
});
|
||||
expectIssueState(!isIssueInitiallyOpen);
|
||||
expect(this.$triggeredButton).toHaveProp('disabled', false);
|
||||
expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002');
|
||||
expectNewBranchButtonState(false, !isIssueInitiallyOpen);
|
||||
});
|
||||
|
||||
it('fails to close an issue with success:false', function() {
|
||||
spyOn(jQuery, 'ajax').and.callFake(function(req) {
|
||||
expectPendingRequest(req, $btnClose);
|
||||
req.success({
|
||||
it(`fails to ${action} the issue if saved:false`, function() {
|
||||
this.$triggeredButton.trigger('click');
|
||||
this.issueStateDeferred.resolve({
|
||||
saved: false
|
||||
});
|
||||
});
|
||||
|
||||
$btnClose.attr('href', INVALID_URL);
|
||||
$btnClose.trigger('click');
|
||||
|
||||
expectIssueState(true);
|
||||
expect($btnClose).toHaveProp('disabled', false);
|
||||
expectErrorMessage();
|
||||
expect($('.issue_counter')).toHaveText(1);
|
||||
});
|
||||
|
||||
it('fails to closes an issue with HTTP error', function() {
|
||||
spyOn(jQuery, 'ajax').and.callFake(function(req) {
|
||||
expectPendingRequest(req, $btnClose);
|
||||
req.error();
|
||||
});
|
||||
|
||||
$btnClose.attr('href', INVALID_URL);
|
||||
$btnClose.trigger('click');
|
||||
|
||||
expectIssueState(true);
|
||||
expect($btnClose).toHaveProp('disabled', true);
|
||||
expectErrorMessage();
|
||||
expect($('.issue_counter')).toHaveText(1);
|
||||
});
|
||||
|
||||
it('updates counter', () => {
|
||||
spyOn(jQuery, 'ajax').and.callFake(function(req) {
|
||||
expectPendingRequest(req, $btnClose);
|
||||
req.success({
|
||||
id: 34
|
||||
this.canCreateBranchDeferred.resolve({
|
||||
can_create_branch: isIssueInitiallyOpen
|
||||
});
|
||||
|
||||
expectIssueState(isIssueInitiallyOpen);
|
||||
expect(this.$triggeredButton).toHaveProp('disabled', false);
|
||||
expectErrorMessage();
|
||||
expect(this.$projectIssuesCounter.text()).toBe('1,001');
|
||||
expectNewBranchButtonState(false, isIssueInitiallyOpen);
|
||||
});
|
||||
|
||||
expect($('.issue_counter')).toHaveText(1);
|
||||
$('.issue_counter').text('1,001');
|
||||
expect($('.issue_counter').text()).toEqual('1,001');
|
||||
$btnClose.trigger('click');
|
||||
expect($('.issue_counter').text()).toEqual('1,000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('reopen issue', function() {
|
||||
beforeEach(function() {
|
||||
loadFixtures('issues/closed-issue.html.raw');
|
||||
findElements();
|
||||
this.issue = new Issue();
|
||||
|
||||
expectIssueState(false);
|
||||
});
|
||||
|
||||
it('reopens an issue', function() {
|
||||
spyOn(jQuery, 'ajax').and.callFake(function(req) {
|
||||
expectPendingRequest(req, $btnReopen);
|
||||
req.success({
|
||||
id: 34
|
||||
it(`fails to ${action} the issue if HTTP error occurs`, function() {
|
||||
this.$triggeredButton.trigger('click');
|
||||
this.issueStateDeferred.reject();
|
||||
this.canCreateBranchDeferred.resolve({
|
||||
can_create_branch: isIssueInitiallyOpen
|
||||
});
|
||||
|
||||
expectIssueState(isIssueInitiallyOpen);
|
||||
expect(this.$triggeredButton).toHaveProp('disabled', true);
|
||||
expectErrorMessage();
|
||||
expect(this.$projectIssuesCounter.text()).toBe('1,001');
|
||||
expectNewBranchButtonState(false, isIssueInitiallyOpen);
|
||||
});
|
||||
|
||||
$btnReopen.trigger('click');
|
||||
it('disables the new branch button if Ajax call fails', function() {
|
||||
this.$triggeredButton.trigger('click');
|
||||
this.issueStateDeferred.reject();
|
||||
this.canCreateBranchDeferred.reject();
|
||||
|
||||
expectIssueState(true);
|
||||
expect($btnReopen).toHaveProp('disabled', false);
|
||||
expect($('.issue_counter')).toHaveText(1);
|
||||
expectNewBranchButtonState(false, false);
|
||||
});
|
||||
|
||||
it('does not trigger Ajax call if new branch button is missing', function() {
|
||||
Issue.$btnNewBranch = $();
|
||||
this.canCreateBranchDeferred = null;
|
||||
|
||||
this.$triggeredButton.trigger('click');
|
||||
this.issueStateDeferred.reject();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue