Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
83c9d8cf
Commit
83c9d8cf
authored
Apr 12, 2017
by
💃 Winnie 💃
Committed by
Alfredo Sumaran
Apr 12, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reset New branch button when issue state changes
parent
defdf45a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
170 additions
and
136 deletions
+170
-136
app/assets/javascripts/issue.js
app/assets/javascripts/issue.js
+57
-51
changelogs/unreleased/reset-new-branch-button.yml
changelogs/unreleased/reset-new-branch-button.yml
+4
-0
spec/javascripts/issue_spec.js
spec/javascripts/issue_spec.js
+109
-85
No files found.
app/assets/javascripts/issue.js
View file @
83c9d8cf
...
...
@@ -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
;
changelogs/unreleased/reset-new-branch-button.yml
0 → 100644
View file @
83c9d8cf
---
title
:
Reset New branch button when issue state changes
merge_request
:
5962
author
:
winniehell
spec/javascripts/issue_spec.js
View file @
83c9d8cf
/* 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
();
expectIssueState
(
true
);
});
[
true
,
false
].
forEach
((
isIssueInitiallyOpen
)
=>
{
describe
(
`with
${
isIssueInitiallyOpen
?
'
open
'
:
'
closed
'
}
issue`
,
function
()
{
const
action
=
isIssueInitiallyOpen
?
'
close
'
:
'
reopen
'
;
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
;
}
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
));
});
it
(
'
closes an issue
'
,
function
()
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
(
function
(
req
)
{
expectPendingRequest
(
req
,
$btnClose
);
req
.
success
({
it
(
`
${
action
}
s the issue`
,
function
()
{
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
resolve
({
id
:
34
});
});
$btnClose
.
trigger
(
'
click
'
);
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
);
});
this
.
canCreateBranchDeferred
.
resolve
({
can_create_branch
:
isIssueInitiallyOpen
});
it
(
'
fails to closes an issue with HTTP error
'
,
function
()
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
(
function
(
req
)
{
expectPendingRequest
(
req
,
$btnClose
);
req
.
error
();
expectIssueState
(
isIssueInitiallyOpen
);
expect
(
this
.
$triggeredButton
).
toHaveProp
(
'
disabled
'
,
false
);
expectErrorMessage
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
});
$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
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
});
});
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
'
);
});
});
expectIssueState
(
isIssueInitiallyOpen
);
expect
(
this
.
$triggeredButton
).
toHaveProp
(
'
disabled
'
,
true
);
expectErrorMessage
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
});
describe
(
'
reopen issue
'
,
function
()
{
beforeEach
(
function
()
{
loadFixtures
(
'
issues/closed-issue.html.raw
'
);
findElements
();
this
.
issue
=
new
Issue
();
it
(
'
disables the new branch button if Ajax call fails
'
,
function
()
{
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
reject
();
this
.
canCreateBranchDeferred
.
reject
();
expectIssueState
(
false
);
});
it
(
'
reopens an issue
'
,
function
()
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
(
function
(
req
)
{
expectPendingRequest
(
req
,
$btnReopen
);
req
.
success
({
id
:
34
});
expectNewBranchButtonState
(
false
,
false
);
});
$btnReopen
.
trigger
(
'
click
'
);
it
(
'
does not trigger Ajax call if new branch button is missing
'
,
function
()
{
Issue
.
$btnNewBranch
=
$
();
this
.
canCreateBranchDeferred
=
null
;
expectIssueState
(
true
);
expect
(
$btnReopen
).
toHaveProp
(
'
disabled
'
,
false
);
expect
(
$
(
'
.issue_counter
'
)).
toHaveText
(
1
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
reject
(
);
}
);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment