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
Léo-Paul Géneau
gitlab-ce
Commits
18da66a5
Commit
18da66a5
authored
Apr 19, 2017
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'remove-iife-diff-notes-bundle' into 'master'
Remove IIFE's in diff_notes_bundle.js See merge request !10729
parents
ba1e9495
e8561287
Changes
11
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 @
18da66a5
...
@@ -3,65 +3,63 @@
...
@@ -3,65 +3,63 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
(()
=>
{
const
CommentAndResolveBtn
=
Vue
.
extend
({
const
CommentAndResolveBtn
=
Vue
.
extend
({
props
:
{
props
:
{
discussionId
:
String
,
discussionId
:
String
,
},
data
()
{
return
{
textareaIsEmpty
:
true
,
discussion
:
{},
};
},
computed
:
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
();
}
else
{
return
false
;
}
},
},
data
()
{
isDiscussionResolved
:
function
()
{
return
{
return
this
.
discussion
.
isResolved
();
textareaIsEmpty
:
true
,
discussion
:
{},
};
},
},
computed
:
{
buttonText
:
function
()
{
showButton
:
function
(
)
{
if
(
this
.
isDiscussionResolved
)
{
if
(
this
.
discussion
)
{
if
(
this
.
textareaIsEmpty
)
{
return
this
.
discussion
.
isResolvable
()
;
return
"
Unresolve discussion
"
;
}
else
{
}
else
{
return
false
;
return
"
Comment & unresolve discussion
"
;
}
}
},
}
else
{
isDiscussionResolved
:
function
()
{
if
(
this
.
textareaIsEmpty
)
{
return
this
.
discussion
.
isResolved
();
return
"
Resolve discussion
"
;
},
buttonText
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Unresolve discussion
"
;
}
else
{
return
"
Comment & unresolve discussion
"
;
}
}
else
{
}
else
{
if
(
this
.
textareaIsEmpty
)
{
return
"
Comment & resolve discussion
"
;
return
"
Resolve discussion
"
;
}
else
{
return
"
Comment & resolve discussion
"
;
}
}
}
}
}
},
}
created
()
{
},
if
(
this
.
discussionId
)
{
created
()
{
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
if
(
this
.
discussionId
)
{
}
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
},
}
mounted
:
function
()
{
},
if
(
!
this
.
discussionId
)
return
;
mounted
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
const
$textarea
=
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
);
const
$textarea
=
$
(
`.js-discussion-note-form[data-discussion-id=
${
this
.
discussionId
}
] .note-textarea`
);
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
$textarea
.
on
(
'
input.comment-and-resolve-btn
'
,
()
=>
{
$textarea
.
on
(
'
input.comment-and-resolve-btn
'
,
()
=>
{
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
this
.
textareaIsEmpty
=
$textarea
.
val
()
===
''
;
});
});
},
},
destroyed
:
function
()
{
destroyed
:
function
()
{
if
(
!
this
.
discussionId
)
return
;
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
);
Vue
.
component
(
'
comment-and-resolve-btn
'
,
CommentAndResolveBtn
);
})(
window
);
app/assets/javascripts/diff_notes/components/diff_note_avatars.js
View file @
18da66a5
...
@@ -4,155 +4,153 @@
...
@@ -4,155 +4,153 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
collapseIcon
from
'
../icons/collapse_icon.svg
'
;
import
collapseIcon
from
'
../icons/collapse_icon.svg
'
;
(()
=>
{
const
DiffNoteAvatars
=
Vue
.
extend
({
const
DiffNoteAvatars
=
Vue
.
extend
({
props
:
[
'
discussionId
'
],
props
:
[
'
discussionId
'
],
data
()
{
data
()
{
return
{
return
{
isVisible
:
false
,
isVisible
:
false
,
lineType
:
''
,
lineType
:
''
,
storeState
:
CommentsStore
.
state
,
storeState
:
CommentsStore
.
state
,
shownAvatars
:
3
,
shownAvatars
:
3
,
collapseIcon
,
collapseIcon
,
};
};
},
},
template
:
`
template
:
`
<div class="diff-comment-avatar-holders"
<div class="diff-comment-avatar-holders"
v-show="notesCount !== 0">
v-show="notesCount !== 0">
<div v-if="!isVisible">
<div v-if="!isVisible">
<img v-for="note in notesSubset"
<img v-for="note in notesSubset"
class="avatar diff-comment-avatar has-tooltip js-diff-comment-avatar"
class="avatar diff-comment-avatar has-tooltip js-diff-comment-avatar"
width="19"
width="19"
height="19"
height="19"
role="button"
role="button"
data-container="body"
data-container="body"
data-placement="top"
data-placement="top"
data-html="true"
data-html="true"
:data-line-type="lineType"
:data-line-type="lineType"
:title="note.authorName + ': ' + note.noteTruncated"
:title="note.authorName + ': ' + note.noteTruncated"
:src="note.authorAvatar"
:src="note.authorAvatar"
@click="clickedAvatar($event)" />
@click="clickedAvatar($event)" />
<span v-if="notesCount > shownAvatars"
<span v-if="notesCount > shownAvatars"
class="diff-comments-more-count has-tooltip js-diff-comment-avatar"
class="diff-comments-more-count has-tooltip js-diff-comment-avatar"
data-container="body"
data-container="body"
data-placement="top"
data-placement="top"
ref="extraComments"
ref="extraComments"
role="button"
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"
:data-line-type="lineType"
:data-line-type="lineType"
@click="clickedAvatar($event)"
:title="extraNotesTitle"
v-if="isVisible"
@click="clickedAvatar($event)">{{ moreText }}</span>
v-html="collapseIcon">
</button>
</div>
</div>
`
,
<button class="diff-notes-collapse js-diff-comment-avatar"
mounted
()
{
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
.
$nextTick
(()
=>
{
this
.
addNoCommentClass
();
this
.
setDiscussionVisible
();
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
.
$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
()
{
computed
:
{
let
notes
=
[];
notesSubset
()
{
let
notes
=
[];
if
(
this
.
discussion
)
{
notes
=
Object
.
keys
(
this
.
discussion
.
notes
)
if
(
this
.
discussion
)
{
.
slice
(
0
,
this
.
shownAvatars
)
notes
=
Object
.
keys
(
this
.
discussion
.
notes
)
.
map
(
noteId
=>
this
.
discussion
.
notes
[
noteId
]);
.
slice
(
0
,
this
.
shownAvatars
)
}
.
map
(
noteId
=>
this
.
discussion
.
notes
[
noteId
]);
}
return
notes
;
},
return
notes
;
extraNotesTitle
()
{
},
if
(
this
.
discussion
)
{
extraNotesTitle
()
{
const
extra
=
this
.
discussion
.
notesCount
()
-
this
.
shownAvatars
;
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
''
;
return
''
;
},
},
discussion
()
{
discussion
()
{
return
this
.
storeState
[
this
.
discussionId
];
return
this
.
storeState
[
this
.
discussionId
];
},
},
notesCount
()
{
notesCount
()
{
if
(
this
.
discussion
)
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
notesCount
();
return
this
.
discussion
.
notesCount
();
}
}
return
0
;
return
0
;
},
},
moreText
()
{
moreText
()
{
const
plusSign
=
this
.
notesCount
<
100
?
'
+
'
:
''
;
const
plusSign
=
this
.
notesCount
<
100
?
'
+
'
:
''
;
return
`
${
plusSign
}${
this
.
notesCount
-
this
.
shownAvatars
}
`
;
return
`
${
plusSign
}${
this
.
notesCount
-
this
.
shownAvatars
}
`
;
},
},
},
methods
:
{
},
clickedAvatar
(
e
)
{
methods
:
{
notes
.
addDiffNote
(
e
);
clickedAvatar
(
e
)
{
notes
.
addDiffNote
(
e
);
// Toggle the active state of the toggle all button
// Toggle the active state of the toggle all button
this
.
toggleDiscussionsToggleState
();
this
.
toggleDiscussionsToggleState
();
this
.
$nextTick
(()
=>
{
this
.
$nextTick
(()
=>
{
this
.
setDiscussionVisible
();
this
.
setDiscussionVisible
();
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
fixTitle
'
);
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
hide
'
);
$
(
'
.has-tooltip
'
,
this
.
$el
).
tooltip
(
'
hide
'
);
});
});
},
},
addNoCommentClass
()
{
addNoCommentClass
()
{
const
notesCount
=
this
.
notesCount
;
const
notesCount
=
this
.
notesCount
;
$
(
this
.
$el
).
closest
(
'
.js-avatar-container
'
)
$
(
this
.
$el
).
closest
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
)
.
nextUntil
(
'
.js-avatar-container
'
)
.
nextUntil
(
'
.js-avatar-container
'
)
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
);
.
toggleClass
(
'
js-no-comment-btn
'
,
notesCount
>
0
);
},
},
toggleDiscussionsToggleState
()
{
toggleDiscussionsToggleState
()
{
const
$notesHolders
=
$
(
this
.
$el
).
closest
(
'
.code
'
).
find
(
'
.notes_holder
'
);
const
$notesHolders
=
$
(
this
.
$el
).
closest
(
'
.code
'
).
find
(
'
.notes_holder
'
);
const
$visibleNotesHolders
=
$notesHolders
.
filter
(
'
:visible
'
);
const
$visibleNotesHolders
=
$notesHolders
.
filter
(
'
:visible
'
);
const
$toggleDiffCommentsBtn
=
$
(
this
.
$el
).
closest
(
'
.diff-file
'
).
find
(
'
.js-toggle-diff-comments
'
);
const
$toggleDiffCommentsBtn
=
$
(
this
.
$el
).
closest
(
'
.diff-file
'
).
find
(
'
.js-toggle-diff-comments
'
);
$toggleDiffCommentsBtn
.
toggleClass
(
'
active
'
,
$notesHolders
.
length
===
$visibleNotesHolders
.
length
);
$toggleDiffCommentsBtn
.
toggleClass
(
'
active
'
,
$notesHolders
.
length
===
$visibleNotesHolders
.
length
);
},
},
setDiscussionVisible
()
{
setDiscussionVisible
()
{
this
.
isVisible
=
$
(
`.diffs .notes[data-discussion-id="
${
this
.
discussion
.
id
}
"]`
).
is
(
'
:visible
'
);
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 @
18da66a5
...
@@ -4,192 +4,190 @@
...
@@ -4,192 +4,190 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
(()
=>
{
const
JumpToDiscussion
=
Vue
.
extend
({
const
JumpToDiscussion
=
Vue
.
extend
({
mixins
:
[
DiscussionMixins
],
mixins
:
[
DiscussionMixins
],
props
:
{
props
:
{
discussionId
:
String
discussionId
:
String
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
,
discussion
:
{},
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
unresolvedDiscussionCount
===
0
;
},
},
data
:
function
()
{
showButton
:
function
()
{
return
{
if
(
this
.
discussionId
)
{
discussions
:
CommentsStore
.
state
,
if
(
this
.
unresolvedDiscussionCount
>
1
)
{
discussion
:
{},
return
true
;
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
unresolvedDiscussionCount
===
0
;
},
showButton
:
function
()
{
if
(
this
.
discussionId
)
{
if
(
this
.
unresolvedDiscussionCount
>
1
)
{
return
true
;
}
else
{
return
this
.
discussionId
!==
this
.
lastResolvedId
;
}
}
else
{
}
else
{
return
this
.
unresolvedDiscussionCount
>=
1
;
return
this
.
discussionId
!==
this
.
lastResolvedId
;
}
}
},
}
else
{
lastResolvedId
:
function
()
{
return
this
.
unresolvedDiscussionCount
>=
1
;
let
lastId
;
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
if
(
!
discussion
.
isResolved
())
{
lastId
=
discussion
.
id
;
}
}
return
lastId
;
}
}
},
},
methods
:
{
lastResolvedId
:
function
()
{
jumpToNextUnresolvedDiscussion
:
function
()
{
let
lastId
;
let
discussionsSelector
;
for
(
const
discussionId
in
this
.
discussions
)
{
let
discussionIdsInScope
;
const
discussion
=
this
.
discussions
[
discussionId
];
let
firstUnresolvedDiscussionId
;
let
nextUnresolvedDiscussionId
;
let
activeTab
=
window
.
mrTabs
.
currentAction
;
let
hasDiscussionsToJumpTo
=
true
;
let
jumpToFirstDiscussion
=
!
this
.
discussionId
;
const
discussionIdsForElements
=
function
(
elements
)
{
return
elements
.
map
(
function
()
{
return
$
(
this
).
attr
(
'
data-discussion-id
'
);
}).
toArray
();
};
const
discussions
=
this
.
discussions
;
if
(
activeTab
===
'
diffs
'
)
{
discussionsSelector
=
'
.diffs .notes[data-discussion-id]
'
;
discussionIdsInScope
=
discussionIdsForElements
(
$
(
discussionsSelector
));
let
unresolvedDiscussionCount
=
0
;
for
(
let
i
=
0
;
i
<
discussionIdsInScope
.
length
;
i
+=
1
)
{
const
discussionId
=
discussionIdsInScope
[
i
];
const
discussion
=
discussions
[
discussionId
];
if
(
discussion
&&
!
discussion
.
isResolved
())
{
unresolvedDiscussionCount
+=
1
;
}
}
if
(
this
.
discussionId
&&
!
this
.
discussion
.
isResolved
())
{
if
(
!
discussion
.
isResolved
())
{
// If this is the last unresolved discussion on the diffs tab,
lastId
=
discussion
.
id
;
// there are no discussions to jump to.
if
(
unresolvedDiscussionCount
===
1
)
{
hasDiscussionsToJumpTo
=
false
;
}
}
else
{
// If there are no unresolved discussions on the diffs tab at all,
// there are no discussions to jump to.
if
(
unresolvedDiscussionCount
===
0
)
{
hasDiscussionsToJumpTo
=
false
;
}
}
}
else
if
(
activeTab
!==
'
notes
'
)
{
// If we are on the commits or builds tabs,
// there are no discussions to jump to.
hasDiscussionsToJumpTo
=
false
;
}
}
}
return
lastId
;
}
},
methods
:
{
jumpToNextUnresolvedDiscussion
:
function
()
{
let
discussionsSelector
;
let
discussionIdsInScope
;
let
firstUnresolvedDiscussionId
;
let
nextUnresolvedDiscussionId
;
let
activeTab
=
window
.
mrTabs
.
currentAction
;
let
hasDiscussionsToJumpTo
=
true
;
let
jumpToFirstDiscussion
=
!
this
.
discussionId
;
const
discussionIdsForElements
=
function
(
elements
)
{
return
elements
.
map
(
function
()
{
return
$
(
this
).
attr
(
'
data-discussion-id
'
);
}).
toArray
();
};
if
(
!
hasDiscussionsToJumpTo
)
{
const
discussions
=
this
.
discussions
;
// If there are no discussions to jump to on the current page,
// switch to the notes tab and jump to the first disucssion there.
window
.
mrTabs
.
activateTab
(
'
notes
'
);
activeTab
=
'
notes
'
;
jumpToFirstDiscussion
=
true
;
}
if
(
activeTab
===
'
notes
'
)
{
if
(
activeTab
===
'
diffs
'
)
{
discussionsSelector
=
'
.discussion[data-discussion-id]
'
;
discussionsSelector
=
'
.diffs .notes[data-discussion-id]
'
;
discussionIdsInScope
=
discussionIdsForElements
(
$
(
discussionsSelector
));
discussionIdsInScope
=
discussionIdsForElements
(
$
(
discussionsSelector
));
}
let
unresolvedDiscussionCount
=
0
;
let
currentDiscussionFound
=
false
;
for
(
let
i
=
0
;
i
<
discussionIdsInScope
.
length
;
i
+=
1
)
{
for
(
let
i
=
0
;
i
<
discussionIdsInScope
.
length
;
i
+=
1
)
{
const
discussionId
=
discussionIdsInScope
[
i
];
const
discussionId
=
discussionIdsInScope
[
i
];
const
discussion
=
discussions
[
discussionId
];
const
discussion
=
discussions
[
discussionId
];
if
(
discussion
&&
!
discussion
.
isResolved
())
{
unresolvedDiscussionCount
+=
1
;
}
}
if
(
!
discussion
)
{
if
(
this
.
discussionId
&&
!
this
.
discussion
.
isResolved
())
{
// Discussions for comments on commits in this MR don't have a resolved status.
// If this is the last unresolved discussion on the diffs tab,
continue
;
// there are no discussions to jump to.
if
(
unresolvedDiscussionCount
===
1
)
{
hasDiscussionsToJumpTo
=
false
;
}
}
else
{
// If there are no unresolved discussions on the diffs tab at all,
// there are no discussions to jump to.
if
(
unresolvedDiscussionCount
===
0
)
{
hasDiscussionsToJumpTo
=
false
;
}
}
}
}
else
if
(
activeTab
!==
'
notes
'
)
{
// If we are on the commits or builds tabs,
// there are no discussions to jump to.
hasDiscussionsToJumpTo
=
false
;
}
if
(
!
firstUnresolvedDiscussionId
&&
!
discussion
.
isResolved
())
{
if
(
!
hasDiscussionsToJumpTo
)
{
firstUnresolvedDiscussionId
=
discussionId
;
// If there are no discussions to jump to on the current page,
// switch to the notes tab and jump to the first disucssion there.
window
.
mrTabs
.
activateTab
(
'
notes
'
);
activeTab
=
'
notes
'
;
jumpToFirstDiscussion
=
true
;
}
if
(
jumpToFirstDiscussion
)
{
if
(
activeTab
===
'
notes
'
)
{
break
;
discussionsSelector
=
'
.discussion[data-discussion-id]
'
;
}
discussionIdsInScope
=
discussionIdsForElements
(
$
(
discussionsSelector
));
}
let
currentDiscussionFound
=
false
;
for
(
let
i
=
0
;
i
<
discussionIdsInScope
.
length
;
i
+=
1
)
{
const
discussionId
=
discussionIdsInScope
[
i
];
const
discussion
=
discussions
[
discussionId
];
if
(
!
discussion
)
{
// Discussions for comments on commits in this MR don't have a resolved status.
continue
;
}
if
(
!
firstUnresolvedDiscussionId
&&
!
discussion
.
isResolved
())
{
firstUnresolvedDiscussionId
=
discussionId
;
if
(
jumpToFirstDiscussion
)
{
break
;
}
}
}
if
(
!
jumpToFirstDiscussion
)
{
if
(
!
jumpToFirstDiscussion
)
{
if
(
currentDiscussionFound
)
{
if
(
currentDiscussionFound
)
{
if
(
!
discussion
.
isResolved
())
{
if
(
!
discussion
.
isResolved
())
{
nextUnresolvedDiscussionId
=
discussionId
;
nextUnresolvedDiscussionId
=
discussionId
;
break
;
break
;
}
else
{
continue
;
}
}
}
else
{
if
(
discussionId
===
this
.
discussionId
)
{
continue
;
currentDiscussionFound
=
true
;
}
}
}
}
if
(
discussionId
===
this
.
discussionId
)
{
currentDiscussionFound
=
true
;
}
}
}
}
nextUnresolvedDiscussionId
=
nextUnresolvedDiscussionId
||
firstUnresolvedDiscussionId
;
nextUnresolvedDiscussionId
=
nextUnresolvedDiscussionId
||
firstUnresolvedDiscussionId
;
if
(
!
nextUnresolvedDiscussionId
)
{
if
(
!
nextUnresolvedDiscussionId
)
{
return
;
return
;
}
}
let
$target
=
$
(
`
${
discussionsSelector
}
[data-discussion-id="
${
nextUnresolvedDiscussionId
}
"]`
);
let
$target
=
$
(
`
${
discussionsSelector
}
[data-discussion-id="
${
nextUnresolvedDiscussionId
}
"]`
);
if
(
activeTab
===
'
notes
'
)
{
if
(
activeTab
===
'
notes
'
)
{
$target
=
$target
.
closest
(
'
.note-discussion
'
);
$target
=
$target
.
closest
(
'
.note-discussion
'
);
// If the next discussion is closed, toggle it open.
// If the next discussion is closed, toggle it open.
if
(
$target
.
find
(
'
.js-toggle-content
'
).
is
(
'
:hidden
'
))
{
if
(
$target
.
find
(
'
.js-toggle-content
'
).
is
(
'
:hidden
'
))
{
$target
.
find
(
'
.js-toggle-button i
'
).
trigger
(
'
click
'
);
$target
.
find
(
'
.js-toggle-button i
'
).
trigger
(
'
click
'
);
}
}
else
if
(
activeTab
===
'
diffs
'
)
{
// Resolved discussions are hidden in the diffs tab by default.
// If they are marked unresolved on the notes tab, they will still be hidden on the diffs tab.
// When jumping between unresolved discussions on the diffs tab, we show them.
$target
.
closest
(
"
.content
"
).
show
();
$target
=
$target
.
closest
(
"
tr.notes_holder
"
);
$target
.
show
();
// If we are on the diffs tab, we don't scroll to the discussion itself, but to
// 4 diff lines above it: the line the discussion was in response to + 3 context
let
prevEl
;
for
(
let
i
=
0
;
i
<
4
;
i
+=
1
)
{
prevEl
=
$target
.
prev
();
// If the discussion doesn't have 4 lines above it, we'll have to do with fewer.
if
(
!
prevEl
.
hasClass
(
"
line_holder
"
))
{
break
;
}
}
}
else
if
(
activeTab
===
'
diffs
'
)
{
// Resolved discussions are hidden in the diffs tab by default.
// If they are marked unresolved on the notes tab, they will still be hidden on the diffs tab.
// When jumping between unresolved discussions on the diffs tab, we show them.
$target
.
closest
(
"
.content
"
).
show
();
$target
=
$target
.
closest
(
"
tr.notes_holder
"
);
$target
.
show
();
// If we are on the diffs tab, we don't scroll to the discussion itself, but to
// 4 diff lines above it: the line the discussion was in response to + 3 context
let
prevEl
;
for
(
let
i
=
0
;
i
<
4
;
i
+=
1
)
{
prevEl
=
$target
.
prev
();
// If the discussion doesn't have 4 lines above it, we'll have to do with fewer.
if
(
!
prevEl
.
hasClass
(
"
line_holder
"
))
{
break
;
}
$target
=
prevEl
;
$target
=
prevEl
;
}
}
}
$
.
scrollTo
(
$target
,
{
offset
:
0
});
}
}
},
created
()
{
this
.
discussion
=
this
.
discussions
[
this
.
discussionId
];
},
});
Vue
.
component
(
'
jump-to-discussion
'
,
JumpToDiscussion
);
$
.
scrollTo
(
$target
,
{
})();
offset
:
0
});
}
},
created
()
{
this
.
discussion
=
this
.
discussions
[
this
.
discussionId
];
},
});
Vue
.
component
(
'
jump-to-discussion
'
,
JumpToDiscussion
);
app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js
View file @
18da66a5
...
@@ -2,29 +2,27 @@
...
@@ -2,29 +2,27 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
(()
=>
{
const
NewIssueForDiscussion
=
Vue
.
extend
({
const
NewIssueForDiscussion
=
Vue
.
extend
({
props
:
{
props
:
{
discussionId
:
{
discussionId
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
},
},
},
data
()
{
},
return
{
data
()
{
discussions
:
CommentsStore
.
state
,
return
{
};
discussions
:
CommentsStore
.
state
,
};
},
computed
:
{
discussion
()
{
return
this
.
discussions
[
this
.
discussionId
];
},
},
computed
:
{
showButton
()
{
discussion
()
{
if
(
this
.
discussion
)
return
!
this
.
discussion
.
isResolved
();
return
this
.
discussions
[
this
.
discussionId
];
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 @
18da66a5
...
@@ -5,117 +5,115 @@
...
@@ -5,117 +5,115 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
(()
=>
{
const
ResolveBtn
=
Vue
.
extend
({
const
ResolveBtn
=
Vue
.
extend
({
props
:
{
props
:
{
noteId
:
Number
,
noteId
:
Number
,
discussionId
:
String
,
discussionId
:
String
,
resolved
:
Boolean
,
resolved
:
Boolean
,
canResolve
:
Boolean
,
canResolve
:
Boolean
,
resolvedBy
:
String
,
resolvedBy
:
String
,
authorName
:
String
,
authorName
:
String
,
authorAvatar
:
String
,
authorAvatar
:
String
,
noteTruncated
:
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
()
{
note
:
function
()
{
return
{
return
this
.
discussion
?
this
.
discussion
.
getNote
(
this
.
noteId
)
:
{};
discussions
:
CommentsStore
.
state
,
loading
:
false
};
},
},
watch
:
{
buttonText
:
function
()
{
'
discussions
'
:
{
if
(
this
.
isResolved
)
{
handler
:
'
updateTooltip
'
,
return
`Resolved by
${
this
.
resolvedByName
}
`
;
deep
:
true
}
else
if
(
this
.
canResolve
)
{
return
'
Mark as resolved
'
;
}
else
{
return
'
Unable to resolve
'
;
}
}
},
},
computed
:
{
isResolved
:
function
()
{
discussion
:
function
()
{
if
(
this
.
note
)
{
return
this
.
discussions
[
this
.
discussionId
];
return
this
.
note
.
resolved
;
},
}
else
{
note
:
function
()
{
return
false
;
return
this
.
discussion
?
this
.
discussion
.
getNote
(
this
.
noteId
)
:
{};
}
},
},
buttonText
:
function
()
{
resolvedByName
:
function
()
{
if
(
this
.
isResolved
)
{
return
this
.
note
.
resolved_by
;
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
;
},
},
},
methods
:
{
},
updateTooltip
:
function
()
{
methods
:
{
this
.
$nextTick
(()
=>
{
updateTooltip
:
function
()
{
$
(
this
.
$refs
.
button
)
this
.
$nextTick
(()
=>
{
.
tooltip
(
'
hide
'
)
$
(
this
.
$refs
.
button
)
.
tooltip
(
'
fixTitle
'
);
.
tooltip
(
'
hide
'
)
});
.
tooltip
(
'
fixTitle
'
);
},
});
resolve
:
function
()
{
},
if
(
!
this
.
canResolve
)
return
;
resolve
:
function
()
{
if
(
!
this
.
canResolve
)
return
;
let
promise
;
let
promise
;
this
.
loading
=
true
;
this
.
loading
=
true
;
if
(
this
.
isResolved
)
{
if
(
this
.
isResolved
)
{
promise
=
ResolveService
promise
=
ResolveService
.
unresolve
(
this
.
noteId
);
.
unresolve
(
this
.
noteId
);
}
else
{
}
else
{
promise
=
ResolveService
promise
=
ResolveService
.
resolve
(
this
.
noteId
);
.
resolve
(
this
.
noteId
);
}
}
promise
.
then
((
response
)
=>
{
promise
.
then
((
response
)
=>
{
this
.
loading
=
false
;
this
.
loading
=
false
;
if
(
response
.
status
===
200
)
{
if
(
response
.
status
===
200
)
{
const
data
=
response
.
json
();
const
data
=
response
.
json
();
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
CommentsStore
.
update
(
this
.
discussionId
,
this
.
noteId
,
!
this
.
isResolved
,
resolved_by
);
CommentsStore
.
update
(
this
.
discussionId
,
this
.
noteId
,
!
this
.
isResolved
,
resolved_by
);
this
.
discussion
.
updateHeadline
(
data
);
this
.
discussion
.
updateHeadline
(
data
);
}
else
{
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a comment. Please try again.
'
,
'
alert
'
);
new
Flash
(
'
An error occurred when trying to resolve a comment. Please try again.
'
,
'
alert
'
);
}
}
this
.
updateTooltip
();
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
,
});
});
}
}
});
},
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 @
18da66a5
...
@@ -4,24 +4,22 @@
...
@@ -4,24 +4,22 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
((
w
)
=>
{
window
.
ResolveCount
=
Vue
.
extend
({
w
.
ResolveCount
=
Vue
.
extend
({
mixins
:
[
DiscussionMixins
],
mixins
:
[
DiscussionMixins
],
props
:
{
props
:
{
loggedOut
:
Boolean
loggedOut
:
Boolean
},
data
:
function
()
{
return
{
discussions
:
CommentsStore
.
state
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
resolvedDiscussionCount
===
this
.
discussionCount
;
},
},
data
:
function
()
{
resolvedCountText
()
{
return
{
return
this
.
discussionCount
===
1
?
'
discussion
'
:
'
discussions
'
;
discussions
:
CommentsStore
.
state
};
},
computed
:
{
allResolved
:
function
()
{
return
this
.
resolvedDiscussionCount
===
this
.
discussionCount
;
},
resolvedCountText
()
{
return
this
.
discussionCount
===
1
?
'
discussion
'
:
'
discussions
'
;
}
}
}
}
);
}
})
(
window
)
;
});
app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js
View file @
18da66a5
...
@@ -4,59 +4,57 @@
...
@@ -4,59 +4,57 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
(()
=>
{
const
ResolveDiscussionBtn
=
Vue
.
extend
({
const
ResolveDiscussionBtn
=
Vue
.
extend
({
props
:
{
props
:
{
discussionId
:
String
,
discussionId
:
String
,
mergeRequestId
:
Number
,
mergeRequestId
:
Number
,
canResolve
:
Boolean
,
canResolve
:
Boolean
,
},
},
data
:
function
()
{
data
:
function
()
{
return
{
return
{
discussion
:
{},
discussion
:
{},
};
};
},
computed
:
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolvable
();
}
else
{
return
false
;
}
},
},
computed
:
{
isDiscussionResolved
:
function
()
{
showButton
:
function
()
{
if
(
this
.
discussion
)
{
if
(
this
.
discussion
)
{
return
this
.
discussion
.
isResolved
();
return
this
.
discussion
.
isResolvable
();
}
else
{
}
else
{
return
false
;
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
;
}
}
}
},
},
methods
:
{
buttonText
:
function
()
{
resolve
:
function
()
{
if
(
this
.
isDiscussionResolved
)
{
ResolveService
.
toggleResolveForDiscussion
(
this
.
mergeRequestId
,
this
.
discussionId
);
return
"
Unresolve discussion
"
;
}
else
{
return
"
Resolve discussion
"
;
}
}
},
},
created
:
function
()
{
loading
:
function
()
{
CommentsStore
.
createDiscussion
(
this
.
discussionId
,
this
.
canResolve
);
if
(
this
.
discussion
)
{
return
this
.
discussion
.
loading
;
this
.
discussion
=
CommentsStore
.
state
[
this
.
discussionId
];
}
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 @
18da66a5
/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, comma-dangle, no-param-reassign, max-len */
/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, comma-dangle, no-param-reassign, max-len */
((
w
)
=>
{
window
.
DiscussionMixins
=
{
w
.
DiscussionMixins
=
{
computed
:
{
computed
:
{
discussionCount
:
function
()
{
discussionCount
:
function
()
{
return
Object
.
keys
(
this
.
discussions
).
length
;
return
Object
.
keys
(
this
.
discussions
).
length
;
},
},
resolvedDiscussionCount
:
function
()
{
resolvedDiscussionCount
:
function
()
{
let
resolvedCount
=
0
;
let
resolvedCount
=
0
;
for
(
const
discussionId
in
this
.
discussions
)
{
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
const
discussion
=
this
.
discussions
[
discussionId
];
if
(
discussion
.
isResolved
())
{
if
(
discussion
.
isResolved
())
{
resolvedCount
+=
1
;
resolvedCount
+=
1
;
}
}
}
}
return
resolvedCount
;
return
resolvedCount
;
},
},
unresolvedDiscussionCount
:
function
()
{
unresolvedDiscussionCount
:
function
()
{
let
unresolvedCount
=
0
;
let
unresolvedCount
=
0
;
for
(
const
discussionId
in
this
.
discussions
)
{
for
(
const
discussionId
in
this
.
discussions
)
{
const
discussion
=
this
.
discussions
[
discussionId
];
const
discussion
=
this
.
discussions
[
discussionId
];
if
(
!
discussion
.
isResolved
())
{
if
(
!
discussion
.
isResolved
())
{
unresolvedCount
+=
1
;
unresolvedCount
+=
1
;
}
}
}
return
unresolvedCount
;
}
}
return
unresolvedCount
;
}
}
}
;
}
}
)(
window
)
;
};
app/assets/javascripts/diff_notes/services/resolve.js
View file @
18da66a5
...
@@ -9,76 +9,74 @@ require('../../vue_shared/vue_resource_interceptor');
...
@@ -9,76 +9,74 @@ require('../../vue_shared/vue_resource_interceptor');
Vue
.
use
(
VueResource
);
Vue
.
use
(
VueResource
);
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
window
.
gl
=
window
.
gl
||
{};
class
ResolveServiceClass
{
class
ResolveServiceClass
{
constructor
(
root
)
{
constructor
(
root
)
{
this
.
noteResource
=
Vue
.
resource
(
`
${
root
}
/notes{/noteId}/resolve`
);
this
.
noteResource
=
Vue
.
resource
(
`
${
root
}
/notes{/noteId}/resolve`
);
this
.
discussionResource
=
Vue
.
resource
(
`
${
root
}
/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`
);
this
.
discussionResource
=
Vue
.
resource
(
`
${
root
}
/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`
);
}
}
resolve
(
noteId
)
{
return
this
.
noteResource
.
save
({
noteId
},
{});
}
un
resolve
(
noteId
)
{
resolve
(
noteId
)
{
return
this
.
noteResource
.
delet
e
({
noteId
},
{});
return
this
.
noteResource
.
sav
e
({
noteId
},
{});
}
}
toggleResolveForDiscussion
(
mergeRequestId
,
discussionId
)
{
unresolve
(
noteId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
return
this
.
noteResource
.
delete
({
noteId
},
{});
const
isResolved
=
discussion
.
isResolved
();
}
let
promise
;
if
(
isResolved
)
{
toggleResolveForDiscussion
(
mergeRequestId
,
discussionId
)
{
promise
=
this
.
unResolveAll
(
mergeRequestId
,
discussionId
);
const
discussion
=
CommentsStore
.
state
[
discussionId
];
}
else
{
const
isResolved
=
discussion
.
isResolved
();
promise
=
this
.
resolveAll
(
mergeRequestId
,
discussionId
);
let
promise
;
}
promise
.
then
((
response
)
=>
{
if
(
isResolved
)
{
discussion
.
loading
=
false
;
promise
=
this
.
unResolveAll
(
mergeRequestId
,
discussionId
);
}
else
{
promise
=
this
.
resolveAll
(
mergeRequestId
,
discussionId
);
}
if
(
response
.
status
===
200
)
{
promise
.
then
((
response
)
=>
{
const
data
=
response
.
json
();
discussion
.
loading
=
false
;
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
if
(
isResolved
)
{
if
(
response
.
status
===
200
)
{
discussion
.
unResolveAllNotes
();
const
data
=
response
.
json
();
}
else
{
const
resolved_by
=
data
?
data
.
resolved_by
:
null
;
discussion
.
resolveAllNotes
(
resolved_by
);
}
discussion
.
updateHeadline
(
data
);
if
(
isResolved
)
{
discussion
.
unResolveAllNotes
();
}
else
{
}
else
{
new
Flash
(
'
An error occurred when trying to resolve a discussion. Please try again.
'
,
'
alert
'
);
discussion
.
resolveAllNotes
(
resolved_by
);
}
}
});
}
resolveAll
(
mergeRequestId
,
discussionId
)
{
discussion
.
updateHeadline
(
data
);
const
discussion
=
CommentsStore
.
state
[
discussionId
];
}
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
({
discussion
.
loading
=
true
;
mergeRequestId
,
discussionId
return
this
.
discussionResource
.
save
({
},
{});
mergeRequestId
,
}
discussionId
},
{});
}
unResolveAll
(
mergeRequestId
,
discussionId
)
{
unResolveAll
(
mergeRequestId
,
discussionId
)
{
const
discussion
=
CommentsStore
.
state
[
discussionId
];
const
discussion
=
CommentsStore
.
state
[
discussionId
];
discussion
.
loading
=
true
;
discussion
.
loading
=
true
;
return
this
.
discussionResource
.
delete
({
return
this
.
discussionResource
.
delete
({
mergeRequestId
,
mergeRequestId
,
discussionId
discussionId
},
{});
},
{});
}
}
}
}
gl
.
DiffNotesResolveServiceClass
=
ResolveServiceClass
;
gl
.
DiffNotesResolveServiceClass
=
ResolveServiceClass
;
})();
app/assets/javascripts/diff_notes/stores/comments.js
View file @
18da66a5
...
@@ -3,56 +3,54 @@
...
@@ -3,56 +3,54 @@
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
((
w
)
=>
{
window
.
CommentsStore
=
{
w
.
CommentsStore
=
{
state
:
{},
state
:
{},
get
:
function
(
discussionId
,
noteId
)
{
get
:
function
(
discussionId
,
noteId
)
{
return
this
.
state
[
discussionId
].
getNote
(
noteId
);
return
this
.
state
[
discussionId
].
getNote
(
noteId
);
},
},
createDiscussion
:
function
(
discussionId
,
canResolve
)
{
createDiscussion
:
function
(
discussionId
,
canResolve
)
{
let
discussion
=
this
.
state
[
discussionId
];
let
discussion
=
this
.
state
[
discussionId
];
if
(
!
this
.
state
[
discussionId
])
{
if
(
!
this
.
state
[
discussionId
])
{
discussion
=
new
DiscussionModel
(
discussionId
);
discussion
=
new
DiscussionModel
(
discussionId
);
Vue
.
set
(
this
.
state
,
discussionId
,
discussion
);
Vue
.
set
(
this
.
state
,
discussionId
,
discussion
);
}
}
if
(
canResolve
!==
undefined
)
{
if
(
canResolve
!==
undefined
)
{
discussion
.
canResolve
=
canResolve
;
discussion
.
canResolve
=
canResolve
;
}
}
return
discussion
;
return
discussion
;
},
},
create
:
function
(
noteObj
)
{
create
:
function
(
noteObj
)
{
const
discussion
=
this
.
createDiscussion
(
noteObj
.
discussionId
);
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
);
for
(
const
discussionId
in
this
.
state
)
{
},
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
];
const
discussion
=
this
.
state
[
discussionId
];
discussion
.
deleteNote
(
noteId
);
if
(
discussion
.
notesCount
()
===
0
)
{
if
(
!
discussion
.
isResolved
()
)
{
Vue
.
delete
(
this
.
state
,
discussionI
d
);
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 @
18da66a5
...
@@ -5,129 +5,127 @@ require('~/diff_notes/models/discussion');
...
@@ -5,129 +5,127 @@ require('~/diff_notes/models/discussion');
require
(
'
~/diff_notes/models/note
'
);
require
(
'
~/diff_notes/models/note
'
);
require
(
'
~/diff_notes/stores/comments
'
);
require
(
'
~/diff_notes/stores/comments
'
);
(()
=>
{
function
createDiscussion
(
noteId
=
1
,
resolved
=
true
)
{
function
createDiscussion
(
noteId
=
1
,
resolved
=
true
)
{
CommentsStore
.
create
({
CommentsStore
.
create
({
discussionId
:
'
a
'
,
discussionId
:
'
a
'
,
noteId
,
noteId
,
canResolve
:
true
,
canResolve
:
true
,
resolved
,
resolved
,
resolvedBy
:
'
test
'
,
resolvedBy
:
'
test
'
,
authorName
:
'
test
'
,
authorName
:
'
test
'
,
authorAvatar
:
'
test
'
,
authorAvatar
:
'
test
'
,
noteTruncated
:
'
test...
'
,
noteTruncated
:
'
test...
'
,
});
}
beforeEach
(()
=>
{
CommentsStore
.
state
=
{};
});
});
}
describe
(
'
New discussion
'
,
()
=>
{
beforeEach
(()
=>
{
it
(
'
creates new discussion
'
,
()
=>
{
CommentsStore
.
state
=
{};
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
createDiscussion
();
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
});
it
(
'
creates new note in discussion
'
,
()
=>
{
describe
(
'
New discussion
'
,
()
=>
{
createDiscussion
();
it
(
'
creates new discussion
'
,
()
=>
{
createDiscussion
(
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
});
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
it
(
'
creates new note in discussion
'
,
()
=>
{
expect
(
Object
.
keys
(
discussion
.
notes
).
length
).
toBe
(
2
);
createDiscussion
();
});
createDiscussion
(
2
);
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
Object
.
keys
(
discussion
.
notes
).
length
).
toBe
(
2
);
});
});
});
describe
(
'
Get note
'
,
()
=>
{
describe
(
'
Get note
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
createDiscussion
();
});
});
it
(
'
gets note by ID
'
,
()
=>
{
it
(
'
gets note by ID
'
,
()
=>
{
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
).
toBeDefined
();
expect
(
note
).
toBeDefined
();
expect
(
note
.
id
).
toBe
(
1
);
expect
(
note
.
id
).
toBe
(
1
);
});
});
});
});
describe
(
'
Delete discussion
'
,
()
=>
{
describe
(
'
Delete discussion
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
createDiscussion
();
});
});
it
(
'
deletes discussion by ID
'
,
()
=>
{
it
(
'
deletes discussion by ID
'
,
()
=>
{
CommentsStore
.
delete
(
'
a
'
,
1
);
CommentsStore
.
delete
(
'
a
'
,
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
});
it
(
'
deletes discussion when no more notes
'
,
()
=>
{
it
(
'
deletes discussion when no more notes
'
,
()
=>
{
createDiscussion
();
createDiscussion
();
createDiscussion
(
2
);
createDiscussion
(
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
1
);
expect
(
Object
.
keys
(
CommentsStore
.
state
[
'
a
'
].
notes
).
length
).
toBe
(
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
[
'
a
'
].
notes
).
length
).
toBe
(
2
);
CommentsStore
.
delete
(
'
a
'
,
1
);
CommentsStore
.
delete
(
'
a
'
,
1
);
CommentsStore
.
delete
(
'
a
'
,
2
);
CommentsStore
.
delete
(
'
a
'
,
2
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
});
});
});
});
describe
(
'
Update note
'
,
()
=>
{
describe
(
'
Update note
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
createDiscussion
();
});
});
it
(
'
updates note to be unresolved
'
,
()
=>
{
it
(
'
updates note to be unresolved
'
,
()
=>
{
CommentsStore
.
update
(
'
a
'
,
1
,
false
,
'
test
'
);
CommentsStore
.
update
(
'
a
'
,
1
,
false
,
'
test
'
);
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
const
note
=
CommentsStore
.
get
(
'
a
'
,
1
);
expect
(
note
.
resolved
).
toBe
(
false
);
expect
(
note
.
resolved
).
toBe
(
false
);
});
});
});
});
describe
(
'
Discussion resolved
'
,
()
=>
{
describe
(
'
Discussion resolved
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
expect
(
Object
.
keys
(
CommentsStore
.
state
).
length
).
toBe
(
0
);
createDiscussion
();
createDiscussion
();
});
});
it
(
'
is resolved with single note
'
,
()
=>
{
it
(
'
is resolved with single note
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
});
it
(
'
is unresolved with 2 notes
'
,
()
=>
{
it
(
'
is unresolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
createDiscussion
(
2
,
false
);
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
});
});
it
(
'
is resolved with 2 notes
'
,
()
=>
{
it
(
'
is resolved with 2 notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
createDiscussion
(
2
);
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
});
it
(
'
resolve all notes
'
,
()
=>
{
it
(
'
resolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
,
false
);
createDiscussion
(
2
,
false
);
discussion
.
resolveAllNotes
();
discussion
.
resolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
expect
(
discussion
.
isResolved
()).
toBe
(
true
);
});
});
it
(
'
unresolve all notes
'
,
()
=>
{
it
(
'
unresolve all notes
'
,
()
=>
{
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
const
discussion
=
CommentsStore
.
state
[
'
a
'
];
createDiscussion
(
2
);
createDiscussion
(
2
);
discussion
.
unResolveAllNotes
();
discussion
.
unResolveAllNotes
();
expect
(
discussion
.
isResolved
()).
toBe
(
false
);
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