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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
e8561287
Commit
e8561287
authored
Apr 17, 2017
by
Alfredo Sumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove IIFEs from diff_notes_bundle.js
parent
eeaeb275
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
731 additions
and
753 deletions
+731
-753
app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
.../javascripts/diff_notes/components/comment_resolve_btn.js
+49
-51
app/assets/javascripts/diff_notes/components/diff_note_avatars.js
...ts/javascripts/diff_notes/components/diff_note_avatars.js
+129
-131
app/assets/javascripts/diff_notes/components/jump_to_discussion.js
...s/javascripts/diff_notes/components/jump_to_discussion.js
+154
-156
app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js
...scripts/diff_notes/components/new_issue_for_discussion.js
+20
-22
app/assets/javascripts/diff_notes/components/resolve_btn.js
app/assets/javascripts/diff_notes/components/resolve_btn.js
+98
-100
app/assets/javascripts/diff_notes/components/resolve_count.js
...assets/javascripts/diff_notes/components/resolve_count.js
+17
-19
app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js
...vascripts/diff_notes/components/resolve_discussion_btn.js
+47
-49
app/assets/javascripts/diff_notes/mixins/discussion.js
app/assets/javascripts/diff_notes/mixins/discussion.js
+24
-26
app/assets/javascripts/diff_notes/services/resolve.js
app/assets/javascripts/diff_notes/services/resolve.js
+53
-55
app/assets/javascripts/diff_notes/stores/comments.js
app/assets/javascripts/diff_notes/stores/comments.js
+44
-46
spec/javascripts/diff_comments_store_spec.js
spec/javascripts/diff_comments_store_spec.js
+96
-98
No files found.
app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
View file @
e8561287
...
...
@@ -3,65 +3,63 @@
import
Vue
from
'
vue
'
;
(()
=>
{
const
CommentAndResolveBtn
=
Vue
.
extend
({
props
:
{
discussionId
:
String
,
const
CommentAndResolveBtn
=
Vue
.
extend
({
props
:
{
discussionId
:
String
,
},
data
()
{
return
{
textareaIsEmpty
:
true
,
discussion
:
{},
};
},
computed
:
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
();
}
else
{
return
false
;
}
},
data
()
{
return
{
textareaIsEmpty
:
true
,
discussion
:
{},
};
isDiscussionResolved
:
function
()
{
return
this
.
discussion
.
isResolved
();
},
computed
:
{
showButton
:
function
(
)
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
()
;
buttonText
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Unresolve discussion
"
;
}
else
{
return
false
;
return
"
Comment & unresolve discussion
"
;
}
},
isDiscussionResolved
:
function
()
{
return
this
.
discussion
.
isResolved
();
},
buttonText
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Unresolve discussion
"
;
}
else
{
return
"
Comment & unresolve discussion
"
;
}
}
else
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Resolve discussion
"
;
}
else
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Resolve discussion
"
;
}
else
{
return
"
Comment & resolve discussion
"
;
}
return
"
Comment & resolve discussion
"
;
}
}
},
created
()
{
if
(
this
.
discussionId
)
{
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
}
},
mounted
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
}
},
created
()
{
if
(
this
.
discussionId
)
{
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
}
},
mounted
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
const
$textarea
=
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
);
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
const
$textarea
=
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
);
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
$textarea
.
on
(
'
input.comment-and-resolve-btn
'
,
()
=>
{
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
});
},
destroyed
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
$textarea
.
on
(
'
input.comment-and-resolve-btn
'
,
()
=>
{
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
});
},
destroyed
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
).
off
(
'
input.comment-and-resolve-btn
'
);
}
});
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
).
off
(
'
input.comment-and-resolve-btn
'
);
}
});
Vue
.
component
(
'
comment-and-resolve-btn
'
,
CommentAndResolveBtn
);
})(
window
);
Vue
.
component
(
'
comment-and-resolve-btn
'
,
CommentAndResolveBtn
);
app/assets/javascripts/diff_notes/components/diff_note_avatars.js
View file @
e8561287
...
...
@@ -4,155 +4,153 @@
import
Vue
from
'
vue
'
;
import
collapseIcon
from
'
../icons/collapse_icon.svg
'
;
(()
=>
{
const
DiffNoteAvatars
=
Vue
.
extend
({
props
:
[
'
discussionId
'
],
data
()
{
return
{
isVisible
:
false
,
lineType
:
''
,
storeState
:
CommentsStore
.
state
,
shownAvatars
:
3
,
collapseIcon
,
};
},
template
:
`
<div class="diff-comment-avatar-holders"
v-show="notesCount !== 0">
<div v-if="!isVisible">
<img v-for="note in notesSubset"
class="avatar diff-comment-avatar has-tooltip js-diff-comment-avatar"
width="19"
height="19"
role="button"
data-container="body"
data-placement="top"
data-html="true"
:data-line-type="lineType"
:title="note.authorName + ': ' + note.noteTruncated"
:src="note.authorAvatar"
@click="clickedAvatar($event)" />
<span v-if="notesCount > shownAvatars"
class="diff-comments-more-count has-tooltip js-diff-comment-avatar"
data-container="body"
data-placement="top"
ref="extraComments"
role="button"
:data-line-type="lineType"
:title="extraNotesTitle"
@click="clickedAvatar($event)">{{ moreText }}</span>
</div>
<button class="diff-notes-collapse js-diff-comment-avatar"
type="button"
aria-label="Show comments"
const
DiffNoteAvatars
=
Vue
.
extend
({
props
:
[
'
discussionId
'
],
data
()
{
return
{
isVisible
:
false
,
lineType
:
''
,
storeState
:
CommentsStore
.
state
,
shownAvatars
:
3
,
collapseIcon
,
};
},
template
:
`
<div class="diff-comment-avatar-holders"
v-show="notesCount !== 0">
<div v-if="!isVisible">
<img v-for="note in notesSubset"
class="avatar diff-comment-avatar has-tooltip js-diff-comment-avatar"
width="19"
height="19"
role="button"
data-container="body"
data-placement="top"
data-html="true"
:data-line-type="lineType"
:title="note.authorName + ': ' + note.noteTruncated"
:src="note.authorAvatar"
@click="clickedAvatar($event)" />
<span v-if="notesCount > shownAvatars"
class="diff-comments-more-count has-tooltip js-diff-comment-avatar"
data-container="body"
data-placement="top"
ref="extraComments"
role="button"
:data-line-type="lineType"
@click="clickedAvatar($event)"
v-if="isVisible"
v-html="collapseIcon">
</button>
:title="extraNotesTitle"
@click="clickedAvatar($event)">{{ moreText }}</span>
</div>
`
,
mounted
()
{
<button class="diff-notes-collapse js-diff-comment-avatar"
type="button"
aria-label="Show comments"
:data-line-type="lineType"
@click="clickedAvatar($event)"
v-if="isVisible"
v-html="collapseIcon">
</button>
</div>
`
,
mounted
()
{
this
.
$nextTick
(()
=>
{
this
.
addNoCommentClass
();
this
.
setDiscussionVisible
();
this
.
lineType
=
$
(
this
.
$el
).
closest
(
'
.diff-line-num
'
).
hasClass
(
'
old_line
'
)
?
'
old
'
:
'
new
'
;
});
$
(
document
).
on
(
'
toggle.comments
'
,
()
=>
{
this
.
$nextTick
(()
=>
{
this
.
addNoCommentClass
();
this
.
setDiscussionVisible
();
this
.
lineType
=
$
(
this
.
$el
).
closest
(
'
.diff-line-num
'
).
hasClass
(
'
old_line
'
)
?
'
old
'
:
'
new
'
;
});
$
(
document
).
on
(
'
toggle.comments
'
,
()
=>
{
});
},
destroyed
()
{
$
(
document
).
off
(
'
toggle.comments
'
);
},
watch
:
{
storeState
:
{
handler
()
{
this
.
$nextTick
(()
=>
{
this
.
setDiscussionVisible
();
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
// We need to add/remove a class to an element that is outside the Vue instance
this
.
addNoCommentClass
();
});
});
},
destroyed
()
{
$
(
document
).
off
(
'
toggle.comments
'
);
},
watch
:
{
storeState
:
{
handler
()
{
this
.
$nextTick
(()
=>
{
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
// We need to add/remove a class to an element that is outside the Vue instance
this
.
addNoCommentClass
();
});
},
deep
:
true
,
},
deep
:
true
,
},
computed
:
{
notesSubset
()
{
let
notes
=
[];
if
(
this
.
discussion
)
{
notes
=
Object
.
keys
(
this
.
discussion
.
notes
)
.
slice
(
0
,
this
.
shownAvatars
)
.
map
(
noteId
=>
this
.
discussion
.
notes
[
noteId
]);
}
return
notes
;
},
extraNotesTitle
()
{
if
(
this
.
discussion
)
{
const
extra
=
this
.
discussion
.
notesCount
()
-
this
.
shownAvatars
;
},
computed
:
{
notesSubset
()
{
let
notes
=
[];
if
(
this
.
discussion
)
{
notes
=
Object
.
keys
(
this
.
discussion
.
notes
)
.
slice
(
0
,
this
.
shownAvatars
)
.
map
(
noteId
=>
this
.
discussion
.
notes
[
noteId
]);
}
return
notes
;
},
extraNotesTitle
()
{
if
(
this
.
discussion
)
{
const
extra
=
this
.
discussion
.
notesCount
()
-
this
.
shownAvatars
;
return
`
${
extra
}
more comment
${
extra
>
1
?
'
s
'
:
''
}
`
;
}
return
`
${
extra
}
more comment
${
extra
>
1
?
'
s
'
:
''
}
`
;
}
return
''
;
},
discussion
()
{
return
this
.
storeState
[
this
.
discussionId
];
},
notesCount
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
notesCount
();
}
return
''
;
},
discussion
()
{
return
this
.
storeState
[
this
.
discussionId
];
},
notesCount
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
notesCount
();
}
return
0
;
},
moreText
()
{
const
plusSign
=
this
.
notesCount
<
100
?
'
+
'
:
''
;
return
0
;
},
moreText
()
{
const
plusSign
=
this
.
notesCount
<
100
?
'
+
'
:
''
;
return
`
${
plusSign
}${
this
.
notesCount
-
this
.
shownAvatars
}
`
;
},
return
`
${
plusSign
}${
this
.
notesCount
-
this
.
shownAvatars
}
`
;
},
methods
:
{
clickedAvatar
(
e
)
{
notes
.
addDiffNote
(
e
);
},
methods
:
{
clickedAvatar
(
e
)
{
notes
.
addDiffNote
(
e
);
// Toggle the active state of the toggle all button
this
.
toggleDiscussionsToggleState
();
// Toggle the active state of the toggle all button
this
.
toggleDiscussionsToggleState
();
this
.
$nextTick
(()
=>
{
this
.
setDiscussionVisible
();
this
.
$nextTick
(()
=>
{
this
.
setDiscussionVisible
();
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
hide
'
);
});
},
addNoCommentClass
()
{
const
notesCount
=
this
.
notesCount
;
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
hide
'
);
});
},
addNoCommentClass
()
{
const
notesCount
=
this
.
notesCount
;
$
(
this
.
$el
).
closest
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
)
.
nextUntil
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
);
},
toggleDiscussionsToggleState
()
{
const
$notesHolders
=
$
(
this
.
$el
).
closest
(
'
.code
'
).
find
(
'
.notes_holder
'
);
const
$visibleNotesHolders
=
$notesHolders
.
filter
(
'
:visible
'
);
const
$toggleDiffCommentsBtn
=
$
(
this
.
$el
).
closest
(
'
.diff-file
'
).
find
(
'
.js-toggle-diff-comments
'
);
$
(
this
.
$el
).
closest
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
)
.
nextUntil
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
);
},
toggleDiscussionsToggleState
()
{
const
$notesHolders
=
$
(
this
.
$el
).
closest
(
'
.code
'
).
find
(
'
.notes_holder
'
);
const
$visibleNotesHolders
=
$notesHolders
.
filter
(
'
:visible
'
);
const
$toggleDiffCommentsBtn
=
$
(
this
.
$el
).
closest
(
'
.diff-file
'
).
find
(
'
.js-toggle-diff-comments
'
);
$toggleDiffCommentsBtn
.
toggleClass
(
'
active
'
,
$notesHolders
.
length
===
$visibleNotesHolders
.
length
);
},
setDiscussionVisible
()
{
this
.
isVisible
=
$
(
`.diffs .notes[data-discussion-id="
${
this
.
discussion
.
id
}
"]`
).
is
(
'
:visible
'
);
},
$toggleDiffCommentsBtn
.
toggleClass
(
'
active
'
,
$notesHolders
.
length
===
$visibleNotesHolders
.
length
);
},
setDiscussionVisible
()
{
this
.
isVisible
=
$
(
`.diffs .notes[data-discussion-id="
${
this
.
discussion
.
id
}
"]`
).
is
(
'
:visible
'
);
},
});
},
});
Vue
.
component
(
'
diff-note-avatars
'
,
DiffNoteAvatars
);
})();
Vue
.
component
(
'
diff-note-avatars
'
,
DiffNoteAvatars
);
app/assets/javascripts/diff_notes/components/jump_to_discussion.js
View file @
e8561287
This diff is collapsed.
Click to expand it.
app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js
View file @
e8561287
...
...
@@ -2,29 +2,27 @@
import
Vue
from
'
vue
'
;
(()
=>
{
const
NewIssueForDiscussion
=
Vue
.
extend
({
props
:
{
discussionId
:
{
type
:
String
,
required
:
true
,
},
const
NewIssueForDiscussion
=
Vue
.
extend
({
props
:
{
discussionId
:
{
type
:
String
,
required
:
true
,
},
data
()
{
return
{
discussions
:
CommentsStore
.
state
,
};
},
data
()
{
return
{
discussions
:
CommentsStore
.
state
,
};
},
computed
:
{
discussion
()
{
return
this
.
discussions
[
this
.
discussionId
];
},
computed
:
{
discussion
()
{
return
this
.
discussions
[
this
.
discussionId
];
},
showButton
()
{
if
(
this
.
discussion
)
return
!
this
.
discussion
.
isResolved
();
return
false
;
},
showButton
()
{
if
(
this
.
discussion
)
return
!
this
.
discussion
.
isResolved
();
return
false
;
},
});
},
});
Vue
.
component
(
'
new-issue-for-discussion-btn
'
,
NewIssueForDiscussion
);
})();
Vue
.
component
(
'
new-issue-for-discussion-btn
'
,
NewIssueForDiscussion
);
app/assets/javascripts/diff_notes/components/resolve_btn.js
View file @
e8561287
...
...
@@ -5,117 +5,115 @@
import
Vue
from
'
vue
'
;
(()
=>
{
const
ResolveBtn
=
Vue
.
extend
({
props
:
{
noteId
:
Number
,
discussionId
:
String
,
resolved
:
Boolean
,
canResolve
:
Boolean
,
resolvedBy
:
String
,
authorName
:
String
,
authorAvatar
:
String
,
noteTruncated
:
String
,
const
ResolveBtn
=
Vue
.
extend
({
props
:
{
noteId
:
Number
,
discussionId
:
String
,
resolved
:
Boolean
,
canResolve
:
Boolean
,
resolvedBy
:
String
,
authorName
:
String
,
authorAvatar
:
String
,
noteTruncated
:
String
,
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
,
loading
:
false
};
},
watch
:
{
'
discussions
'
:
{
handler
:
'
updateTooltip
'
,
deep
:
true
}
},
computed
:
{
discussion
:
function
()
{
return
this
.
discussions
[
this
.
discussionId
];
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
,
loading
:
false
};
note
:
function
()
{
return
this
.
discussion
?
this
.
discussion
.
getNote
(
this
.
noteId
)
:
{};
},
watch
:
{
'
discussions
'
:
{
handler
:
'
updateTooltip
'
,
deep
:
true
buttonText
:
function
()
{
if
(
this
.
isResolved
)
{
return
`Resolved by
${
this
.
resolvedByName
}
`
;
}
else
if
(
this
.
canResolve
)
{
return
'
Mark as resolved
'
;
}
else
{
return
'
Unable to resolve
'
;
}
},
computed
:
{
discussion
:
function
()
{
return
this
.
discussions
[
this
.
discussionId
];
},
note
:
function
()
{
return
this
.
discussion
?
this
.
discussion
.
getNote
(
this
.
noteId
)
:
{};
},
buttonText
:
function
()
{
if
(
this
.
isResolved
)
{
return
`Resolved by
${
this
.
resolvedByName
}
`
;
}
else
if
(
this
.
canResolve
)
{
return
'
Mark as resolved
'
;
}
else
{
return
'
Unable to resolve
'
;
}
},
isResolved
:
function
()
{
if
(
this
.
note
)
{
return
this
.
note
.
resolved
;
}
else
{
return
false
;
}
},
resolvedByName
:
function
()
{
return
this
.
note
.
resolved_by
;
},
isResolved
:
function
()
{
if
(
this
.
note
)
{
return
this
.
note
.
resolved
;
}
else
{
return
false
;
}
},
resolvedByName
:
function
()
{
return
this
.
note
.
resolved_by
;
},
methods
:
{
updateTooltip
:
function
()
{
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
.
button
)
.
tooltip
(
'
hide
'
)
.
tooltip
(
'
fixTitle
'
);
});
},
resolve
:
function
()
{
if
(
!
this
.
canResolve
)
return
;
},
methods
:
{
updateTooltip
:
function
()
{
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
.
button
)
.
tooltip
(
'
hide
'
)
.
tooltip
(
'
fixTitle
'
);
});
},
resolve
:
function
()
{
if
(
!
this
.
canResolve
)
return
;
let
promise
;
this
.
loading
=
true
;
let
promise
;
this
.
loading
=
true
;
if
(
this
.
isResolved
)
{
promise
=
ResolveService
.
unresolve
(
this
.
noteId
);
}
else
{
promise
=
ResolveService
.
resolve
(
this
.
noteId
);
}
if
(
this
.
isResolved
)
{
promise
=
ResolveService
.
unresolve
(
this
.
noteId
);
}
else
{
promise
=
ResolveService
.
resolve
(
this
.
noteId
);
}
promise
.
then
((
response
)
=>
{
this
.
loading
=
false
;
promise
.
then
((
response
)
=>
{
this
.
loading
=
false
;
if
(
response
.
status
===
200
)
{
const
data
=
response
.
json
();
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
if
(
response
.
status
===
200
)
{
const
data
=
response
.
json
();
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
CommentsStore
.
update
(
this
.
discussionId
,
this
.
noteId
,
!
this
.
isResolved
,
resolved_by
);
this
.
discussion
.
updateHeadline
(
data
);
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a comment. Please try again.
'
,
'
alert
'
);
}
CommentsStore
.
update
(
this
.
discussionId
,
this
.
noteId
,
!
this
.
isResolved
,
resolved_by
);
this
.
discussion
.
updateHeadline
(
data
);
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a comment. Please try again.
'
,
'
alert
'
);
}
this
.
updateTooltip
();
});
}
},
mounted
:
function
()
{
$
(
this
.
$refs
.
button
).
tooltip
({
container
:
'
body
'
});
},
beforeDestroy
:
function
()
{
CommentsStore
.
delete
(
this
.
discussionId
,
this
.
noteId
);
},
created
:
function
()
{
CommentsStore
.
create
({
discussionId
:
this
.
discussionId
,
noteId
:
this
.
noteId
,
canResolve
:
this
.
canResolve
,
resolved
:
this
.
resolved
,
resolvedBy
:
this
.
resolvedBy
,
authorName
:
this
.
authorName
,
authorAvatar
:
this
.
authorAvatar
,
noteTruncated
:
this
.
noteTruncated
,
this
.
updateTooltip
();
});
}
});
},
mounted
:
function
()
{
$
(
this
.
$refs
.
button
).
tooltip
({
container
:
'
body
'
});
},
beforeDestroy
:
function
()
{
CommentsStore
.
delete
(
this
.
discussionId
,
this
.
noteId
);
},
created
:
function
()
{
CommentsStore
.
create
({
discussionId
:
this
.
discussionId
,
noteId
:
this
.
noteId
,
canResolve
:
this
.
canResolve
,
resolved
:
this
.
resolved
,
resolvedBy
:
this
.
resolvedBy
,
authorName
:
this
.
authorName
,
authorAvatar
:
this
.
authorAvatar
,
noteTruncated
:
this
.
noteTruncated
,
});
}
});
Vue
.
component
(
'
resolve-btn
'
,
ResolveBtn
);
})();
Vue
.
component
(
'
resolve-btn
'
,
ResolveBtn
);
app/assets/javascripts/diff_notes/components/resolve_count.js
View file @
e8561287
...
...
@@ -4,24 +4,22 @@
import
Vue
from
'
vue
'
;
((
w
)
=>
{
w
.
ResolveCount
=
Vue
.
extend
({
mixins
:
[
DiscussionMixins
],
props
:
{
loggedOut
:
Boolean
window
.
ResolveCount
=
Vue
.
extend
({
mixins
:
[
DiscussionMixins
],
props
:
{
loggedOut
:
Boolean
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
resolvedDiscussionCount
===
this
.
discussionCount
;
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
resolvedDiscussionCount
===
this
.
discussionCount
;
},
resolvedCountText
()
{
return
this
.
discussionCount
===
1
?
'
discussion
'
:
'
discussions
'
;
}
resolvedCountText
()
{
return
this
.
discussionCount
===
1
?
'
discussion
'
:
'
discussions
'
;
}
}
);
})
(
window
)
;
}
});
app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js
View file @
e8561287
...
...
@@ -4,59 +4,57 @@
import
Vue
from
'
vue
'
;
(()
=>
{
const
ResolveDiscussionBtn
=
Vue
.
extend
({
props
:
{
discussionId
:
String
,
mergeRequestId
:
Number
,
canResolve
:
Boolean
,
},
data
:
function
()
{
return
{
discussion
:
{},
};
const
ResolveDiscussionBtn
=
Vue
.
extend
({
props
:
{
discussionId
:
String
,
mergeRequestId
:
Number
,
canResolve
:
Boolean
,
},
data
:
function
()
{
return
{
discussion
:
{},
};
},
computed
:
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
();
}
else
{
return
false
;
}
},
computed
:
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
();
}
else
{
return
false
;
}
},
isDiscussionResolved
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolved
();
}
else
{
return
false
;
}
},
buttonText
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
return
"
Unresolve discussion
"
;
}
else
{
return
"
Resolve discussion
"
;
}
},
loading
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
loading
;
}
else
{
return
false
;
}
isDiscussionResolved
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolved
();
}
else
{
return
false
;
}
},
methods
:
{
resolve
:
function
()
{
ResolveService
.
toggleResolveForDiscussion
(
this
.
mergeRequestId
,
this
.
discussionId
);
buttonText
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
return
"
Unresolve discussion
"
;
}
else
{
return
"
Resolve discussion
"
;
}
},
created
:
function
()
{
CommentsStore
.
createDiscussion
(
this
.
discussionId
,
this
.
canResolve
);
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
loading
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
loading
;
}
else
{
return
false
;
}
}
},
methods
:
{
resolve
:
function
()
{
ResolveService
.
toggleResolveForDiscussion
(
this
.
mergeRequestId
,
this
.
discussionId
);
}
});
},
created
:
function
()
{
CommentsStore
.
createDiscussion
(
this
.
discussionId
,
this
.
canResolve
);
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
}
});
Vue
.
component
(
'
resolve-discussion-btn
'
,
ResolveDiscussionBtn
);
})();
Vue
.
component
(
'
resolve-discussion-btn
'
,
ResolveDiscussionBtn
);
app/assets/javascripts/diff_notes/mixins/discussion.js
View file @
e8561287
/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, comma-dangle, no-param-reassign, max-len */
((
w
)
=>
{
w
.
DiscussionMixins
=
{
computed
:
{
discussionCount
:
function
()
{
return
Object
.
keys
(
this
.
discussions
).
length
;
},
resolvedDiscussionCount
:
function
()
{
let
resolvedCount
=
0
;
window
.
DiscussionMixins
=
{
computed
:
{
discussionCount
:
function
()
{
return
Object
.
keys
(
this
.
discussions
).
length
;
},
resolvedDiscussionCount
:
function
()
{
let
resolvedCount
=
0
;
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
if
(
discussion
.
isResolved
())
{
resolvedCount
+=
1
;
}
if
(
discussion
.
isResolved
())
{
resolvedCount
+=
1
;
}
}
return
resolvedCount
;
},
unresolvedDiscussionCount
:
function
()
{
let
unresolvedCount
=
0
;
return
resolvedCount
;
},
unresolvedDiscussionCount
:
function
()
{
let
unresolvedCount
=
0
;
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
if
(
!
discussion
.
isResolved
())
{
unresolvedCount
+=
1
;
}
if
(
!
discussion
.
isResolved
())
{
unresolvedCount
+=
1
;
}
return
unresolvedCount
;
}
return
unresolvedCount
;
}
}
;
}
)(
window
)
;
}
};
app/assets/javascripts/diff_notes/services/resolve.js
View file @
e8561287
...
...
@@ -9,76 +9,74 @@ require('../../vue_shared/vue_resource_interceptor');
Vue
.
use
(
VueResource
);
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
window
.
gl
=
window
.
gl
||
{};
class
ResolveServiceClass
{
constructor
(
root
)
{
this
.
noteResource
=
Vue
.
resource
(
`
${
root
}
/notes{/noteId}/resolve`
);
this
.
discussionResource
=
Vue
.
resource
(
`
${
root
}
/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`
);
}
resolve
(
noteId
)
{
return
this
.
noteResource
.
save
({
noteId
},
{});
}
class
ResolveServiceClass
{
constructor
(
root
)
{
this
.
noteResource
=
Vue
.
resource
(
`
${
root
}
/notes{/noteId}/resolve`
);
this
.
discussionResource
=
Vue
.
resource
(
`
${
root
}
/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`
);
}
un
resolve
(
noteId
)
{
return
this
.
noteResource
.
delet
e
({
noteId
},
{});
}
resolve
(
noteId
)
{
return
this
.
noteResource
.
sav
e
({
noteId
},
{});
}
toggleResolveForDiscussion
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
const
isResolved
=
discussion
.
isResolved
();
let
promise
;
unresolve
(
noteId
)
{
return
this
.
noteResource
.
delete
({
noteId
},
{});
}
if
(
isResolved
)
{
promise
=
this
.
unResolveAll
(
mergeRequestId
,
discussionId
);
}
else
{
promise
=
this
.
resolveAll
(
mergeRequestId
,
discussionId
);
}
toggleResolveForDiscussion
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
const
isResolved
=
discussion
.
isResolved
();
let
promise
;
promise
.
then
((
response
)
=>
{
discussion
.
loading
=
false
;
if
(
isResolved
)
{
promise
=
this
.
unResolveAll
(
mergeRequestId
,
discussionId
);
}
else
{
promise
=
this
.
resolveAll
(
mergeRequestId
,
discussionId
);
}
if
(
response
.
status
===
200
)
{
const
data
=
response
.
json
();
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
promise
.
then
((
response
)
=>
{
discussion
.
loading
=
false
;
if
(
isResolved
)
{
discussion
.
unResolveAllNotes
();
}
else
{
discussion
.
resolveAllNotes
(
resolved_by
);
}
if
(
response
.
status
===
200
)
{
const
data
=
response
.
json
();
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
discussion
.
updateHeadline
(
data
);
if
(
isResolved
)
{
discussion
.
unResolveAllNotes
();
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a discussion. Please try again.
'
,
'
alert
'
);
discussion
.
resolveAllNotes
(
resolved_by
);
}
});
}
resolveAll
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
discussion
.
updateHeadline
(
data
);
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a discussion. Please try again.
'
,
'
alert
'
);
}
});
}
discussion
.
loading
=
true
;
resolveAll
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
return
this
.
discussionResource
.
save
({
mergeRequestId
,
discussionId
},
{});
}
discussion
.
loading
=
true
;
return
this
.
discussionResource
.
save
({
mergeRequestId
,
discussionId
},
{});
}
unResolveAll
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
unResolveAll
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
discussion
.
loading
=
true
;
discussion
.
loading
=
true
;
return
this
.
discussionResource
.
delete
({
mergeRequestId
,
discussionId
},
{});
}
return
this
.
discussionResource
.
delete
({
mergeRequestId
,
discussionId
},
{});
}
}
gl
.
DiffNotesResolveServiceClass
=
ResolveServiceClass
;
})();
gl
.
DiffNotesResolveServiceClass
=
ResolveServiceClass
;
app/assets/javascripts/diff_notes/stores/comments.js
View file @
e8561287
...
...
@@ -3,56 +3,54 @@
import
Vue
from
'
vue
'
;
((
w
)
=>
{
w
.
CommentsStore
=
{
state
:
{},
get
:
function
(
discussionId
,
noteId
)
{
return
this
.
state
[
discussionId
].
getNote
(
noteId
);
},
createDiscussion
:
function
(
discussionId
,
canResolve
)
{
let
discussion
=
this
.
state
[
discussionId
];
if
(
!
this
.
state
[
discussionId
])
{
discussion
=
new
DiscussionModel
(
discussionId
);
Vue
.
set
(
this
.
state
,
discussionId
,
discussion
);
}
window
.
CommentsStore
=
{
state
:
{},
get
:
function
(
discussionId
,
noteId
)
{
return
this
.
state
[
discussionId
].
getNote
(
noteId
);
},
createDiscussion
:
function
(
discussionId
,
canResolve
)
{
let
discussion
=
this
.
state
[
discussionId
];
if
(
!
this
.
state
[
discussionId
])
{
discussion
=
new
DiscussionModel
(
discussionId
);
Vue
.
set
(
this
.
state
,
discussionId
,
discussion
);
}
if
(
canResolve
!==
undefined
)
{
discussion
.
canResolve
=
canResolve
;
}
if
(
canResolve
!==
undefined
)
{
discussion
.
canResolve
=
canResolve
;
}
return
discussion
;
},
create
:
function
(
noteObj
)
{
const
discussion
=
this
.
createDiscussion
(
noteObj
.
discussionId
);
return
discussion
;
},
create
:
function
(
noteObj
)
{
const
discussion
=
this
.
createDiscussion
(
noteObj
.
discussionId
);
discussion
.
createNote
(
noteObj
);
},
update
:
function
(
discussionId
,
noteId
,
resolved
,
resolved_by
)
{
const
discussion
=
this
.
state
[
discussionId
];
const
note
=
discussion
.
getNote
(
noteId
);
note
.
resolved
=
resolved
;
note
.
resolved_by
=
resolved_by
;
},
delete
:
function
(
discussionId
,
noteId
)
{
const
discussion
=
this
.
state
[
discussionId
];
discussion
.
deleteNote
(
noteId
);
if
(
discussion
.
notesCount
()
===
0
)
{
Vue
.
delete
(
this
.
state
,
discussionId
);
}
},
unresolvedDiscussionIds
:
function
()
{
const
ids
=
[];
discussion
.
createNote
(
noteObj
);
},
update
:
function
(
discussionId
,
noteId
,
resolved
,
resolved_by
)
{
const
discussion
=
this
.
state
[
discussionId
];
const
note
=
discussion
.
getNote
(
noteId
);
note
.
resolved
=
resolved
;
note
.
resolved_by
=
resolved_by
;
},
delete
:
function
(
discussionId
,
noteId
)
{
for
(
const
discussionId
in
this
.
state
)
{
const
discussion
=
this
.
state
[
discussionId
];
discussion
.
deleteNote
(
noteId
);
if
(
discussion
.
notesCount
()
===
0
)
{
Vue
.
delete
(
this
.
state
,
discussionI
d
);
if
(
!
discussion
.
isResolved
()
)
{
ids
.
push
(
discussion
.
i
d
);
}
},
unresolvedDiscussionIds
:
function
()
{
const
ids
=
[];
for
(
const
discussionId
in
this
.
state
)
{
const
discussion
=
this
.
state
[
discussionId
];
if
(
!
discussion
.
isResolved
())
{
ids
.
push
(
discussion
.
id
);
}
}
return
ids
;
}
};
})(
window
);
return
ids
;
}
};
spec/javascripts/diff_comments_store_spec.js
View file @
e8561287
...
...
@@ -5,129 +5,127 @@ require('~/diff_notes/models/discussion');
require
(
'
~/diff_notes/models/note
'
);
require
(
'
~/diff_notes/stores/comments
'
);
(()
=>
{
function
createDiscussion
(
noteId
=
1
,
resolved
=
true
)
{
CommentsStore
.
create
({
discussionId
:
'
a
'
,
noteId
,
canResolve
:
true
,
resolved
,
resolvedBy
:
'
test
'
,
authorName
:
'
test
'
,
authorAvatar
:
'
test
'
,
noteTruncated
:
'
test...
'
,
});
}
beforeEach
(()
=>
{
CommentsStore
.
state
=
{};
function
createDiscussion
(
noteId
=
1
,
resolved
=
true
)
{
CommentsStore
.
create
({
discussionId
:
'
a
'
,
noteId
,
canResolve
:
true
,
resolved
,
resolvedBy
:
'
test
'
,
authorName
:
'
test
'
,
authorAvatar
:
'
test
'
,
noteTruncated
:
'
test...
'
,
});
}
describe
(
'
New discussion
'
,
()
=>
{
it
(
'
creates new discussion
'
,
()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
});
beforeEach
(()
=>
{
CommentsStore
.
state
=
{};
});
it
(
'
creates new note in discussion
'
,
()
=>
{
createDiscussion
();
createDiscussion
(
2
);
describe
(
'
New discussion
'
,
()
=>
{
it
(
'
creates new discussion
'
,
()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
});
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
Object
.
keys
(
discussion
.
notes
).
length
).
toBe
(
2
);
});
it
(
'
creates new note in discussion
'
,
()
=>
{
createDiscussion
();
createDiscussion
(
2
);
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
Object
.
keys
(
discussion
.
notes
).
length
).
toBe
(
2
);
});
});
describe
(
'
Get note
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
describe
(
'
Get note
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
it
(
'
gets note by ID
'
,
()
=>
{
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
).
toBeDefined
();
expect
(
note
.
id
).
toBe
(
1
);
});
it
(
'
gets note by ID
'
,
()
=>
{
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
).
toBeDefined
();
expect
(
note
.
id
).
toBe
(
1
);
});
});
describe
(
'
Delete discussion
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
describe
(
'
Delete discussion
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
it
(
'
deletes discussion by ID
'
,
()
=>
{
CommentsStore
.
delete
(
'
a
'
,
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
it
(
'
deletes discussion by ID
'
,
()
=>
{
CommentsStore
.
delete
(
'
a
'
,
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
it
(
'
deletes discussion when no more notes
'
,
()
=>
{
createDiscussion
();
createDiscussion
(
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
[
'
a
'
].
notes
).
length
).
toBe
(
2
);
it
(
'
deletes discussion when no more notes
'
,
()
=>
{
createDiscussion
();
createDiscussion
(
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
[
'
a
'
].
notes
).
length
).
toBe
(
2
);
CommentsStore
.
delete
(
'
a
'
,
1
);
CommentsStore
.
delete
(
'
a
'
,
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
CommentsStore
.
delete
(
'
a
'
,
1
);
CommentsStore
.
delete
(
'
a
'
,
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
});
describe
(
'
Update note
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
describe
(
'
Update note
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
it
(
'
updates note to be unresolved
'
,
()
=>
{
CommentsStore
.
update
(
'
a
'
,
1
,
false
,
'
test
'
);
it
(
'
updates note to be unresolved
'
,
()
=>
{
CommentsStore
.
update
(
'
a
'
,
1
,
false
,
'
test
'
);
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
.
resolved
).
toBe
(
false
);
});
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
.
resolved
).
toBe
(
false
);
});
});
describe
(
'
Discussion resolved
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
describe
(
'
Discussion resolved
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
});
it
(
'
is resolved with single note
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
it
(
'
is resolved with single note
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
it
(
'
is unresolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
it
(
'
is unresolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
});
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
});
it
(
'
is resolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
it
(
'
is resolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
it
(
'
resolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
it
(
'
resolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
discussion
.
resolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
discussion
.
resolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
it
(
'
unresolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
it
(
'
unresolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
discussion
.
unResolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
});
discussion
.
unResolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
});
})
()
;
});
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