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
ffef1669
Commit
ffef1669
authored
Jul 26, 2017
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use mapActions, mapGetters and mapMutations for components
parent
4e81ad2a
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
850 additions
and
804 deletions
+850
-804
app/assets/javascripts/notes/components/issue_comment_form.vue
...ssets/javascripts/notes/components/issue_comment_form.vue
+5
-1
app/assets/javascripts/notes/components/issue_discussion.vue
app/assets/javascripts/notes/components/issue_discussion.vue
+100
-96
app/assets/javascripts/notes/components/issue_note.vue
app/assets/javascripts/notes/components/issue_note.vue
+107
-101
app/assets/javascripts/notes/components/issue_note_actions.vue
...ssets/javascripts/notes/components/issue_note_actions.vue
+70
-63
app/assets/javascripts/notes/components/issue_note_awards_list.vue
...s/javascripts/notes/components/issue_note_awards_list.vue
+160
-155
app/assets/javascripts/notes/components/issue_note_body.vue
app/assets/javascripts/notes/components/issue_note_body.vue
+59
-59
app/assets/javascripts/notes/components/issue_note_edited_text.vue
...s/javascripts/notes/components/issue_note_edited_text.vue
+25
-24
app/assets/javascripts/notes/components/issue_note_form.vue
app/assets/javascripts/notes/components/issue_note_form.vue
+74
-74
app/assets/javascripts/notes/components/issue_note_header.vue
...assets/javascripts/notes/components/issue_note_header.vue
+67
-59
app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue
...scripts/notes/components/issue_note_signed_out_widget.vue
+13
-13
app/assets/javascripts/notes/components/issue_notes.vue
app/assets/javascripts/notes/components/issue_notes.vue
+118
-107
app/assets/javascripts/notes/components/issue_placeholder_note.vue
...s/javascripts/notes/components/issue_placeholder_note.vue
+14
-13
app/assets/javascripts/notes/components/issue_placeholder_system_note.vue
...cripts/notes/components/issue_placeholder_system_note.vue
+7
-7
app/assets/javascripts/notes/components/issue_system_note.vue
...assets/javascripts/notes/components/issue_system_note.vue
+27
-27
app/assets/javascripts/notes/constants.js
app/assets/javascripts/notes/constants.js
+1
-1
app/assets/javascripts/notes/stores/actions.js
app/assets/javascripts/notes/stores/actions.js
+3
-4
No files found.
app/assets/javascripts/notes/components/issue_comment_form.vue
View file @
ffef1669
<
script
>
<
script
>
/* global Flash */
/* global Flash */
import
{
mapActions
}
from
'
vuex
'
;
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
markdownField
from
'
../../vue_shared/components/markdown/field.vue
'
;
import
markdownField
from
'
../../vue_shared/components/markdown/field.vue
'
;
import
issueNoteSignedOutWidget
from
'
./issue_note_signed_out_widget.vue
'
;
import
issueNoteSignedOutWidget
from
'
./issue_note_signed_out_widget.vue
'
;
...
@@ -60,6 +61,9 @@
...
@@ -60,6 +61,9 @@
},
},
},
},
methods
:
{
methods
:
{
...
mapActions
([
'
saveNote
'
]),
handleSave
(
withIssueAction
)
{
handleSave
(
withIssueAction
)
{
if
(
this
.
note
.
length
)
{
if
(
this
.
note
.
length
)
{
const
noteData
=
{
const
noteData
=
{
...
@@ -79,7 +83,7 @@
...
@@ -79,7 +83,7 @@
noteData
.
data
.
note
.
type
=
constants
.
DISCUSSION_NOTE
;
noteData
.
data
.
note
.
type
=
constants
.
DISCUSSION_NOTE
;
}
}
this
.
$store
.
dispatch
(
'
saveNote
'
,
noteData
)
this
.
saveNote
(
noteData
)
.
then
((
res
)
=>
{
.
then
((
res
)
=>
{
if
(
res
.
errors
)
{
if
(
res
.
errors
)
{
if
(
res
.
errors
.
commands_only
)
{
if
(
res
.
errors
.
commands_only
)
{
...
...
app/assets/javascripts/notes/components/issue_discussion.vue
View file @
ffef1669
<
script
>
<
script
>
/* global Flash */
/* global Flash */
import
{
mapActions
}
from
'
vuex
'
;
import
{
TOGGLE_DISCUSSION
}
from
'
../stores/mutation_types
'
;
import
{
SYSTEM_NOTE
}
from
'
../constants
'
;
import
issueNote
from
'
./issue_note.vue
'
;
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
import
issueNoteActions
from
'
./issue_note_actions.vue
'
;
import
issueNoteSignedOutWidget
from
'
./issue_note_signed_out_widget.vue
'
;
import
issueNoteEditedText
from
'
./issue_note_edited_text.vue
'
;
import
issueNoteForm
from
'
./issue_note_form.vue
'
;
import
placeholderNote
from
'
./issue_placeholder_note.vue
'
;
import
placeholderSystemNote
from
'
./issue_placeholder_system_note.vue
'
;
import
issueNote
from
'
./issue_note.vue
'
;
export
default
{
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
props
:
{
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
note
:
{
import
issueNoteActions
from
'
./issue_note_actions.vue
'
;
type
:
Object
,
import
issueNoteSignedOutWidget
from
'
./issue_note_signed_out_widget.vue
'
;
required
:
true
,
import
issueNoteEditedText
from
'
./issue_note_edited_text.vue
'
;
},
import
issueNoteForm
from
'
./issue_note_form.vue
'
;
import
placeholderNote
from
'
./issue_placeholder_note.vue
'
;
import
placeholderSystemNote
from
'
./issue_placeholder_system_note.vue
'
;
export
default
{
props
:
{
note
:
{
type
:
Object
,
required
:
true
,
},
},
},
data
()
{
data
()
{
return
{
return
{
newNotePath
:
window
.
gl
.
issueData
.
create_note_path
,
newNotePath
:
window
.
gl
.
issueData
.
create_note_path
,
isReplying
:
false
,
isReplying
:
false
,
};
};
},
components
:
{
issueNote
,
userAvatarLink
,
issueNoteHeader
,
issueNoteActions
,
issueNoteSignedOutWidget
,
issueNoteEditedText
,
issueNoteForm
,
placeholderNote
,
placeholderSystemNote
,
},
computed
:
{
discussion
()
{
return
this
.
note
.
notes
[
0
];
},
},
author
()
{
components
:
{
return
this
.
discussion
.
author
;
issueNote
,
userAvatarLink
,
issueNoteHeader
,
issueNoteActions
,
issueNoteSignedOutWidget
,
issueNoteEditedText
,
issueNoteForm
,
placeholderNote
,
placeholderSystemNote
,
},
},
canReply
()
{
computed
:
{
return
window
.
gl
.
issueData
.
current_user
.
can_create_note
;
discussion
()
{
return
this
.
note
.
notes
[
0
];
},
author
()
{
return
this
.
discussion
.
author
;
},
canReply
()
{
return
window
.
gl
.
issueData
.
current_user
.
can_create_note
;
},
},
},
},
methods
:
{
methods
:
{
...
mapActions
([
componentName
(
note
)
{
'
saveNote
'
,
if
(
note
.
isPlaceholderNote
)
{
]),
if
(
note
.
placeholderType
===
'
systemNote
'
)
{
...
mapMutations
({
return
placeholderSystemNote
;
toggleDiscussion
:
TOGGLE_DISCUSSION
,
}),
componentName
(
note
)
{
if
(
note
.
isPlaceholderNote
)
{
if
(
note
.
placeholderType
===
SYSTEM_NOTE
)
{
return
placeholderSystemNote
;
}
return
placeholderNote
;
}
}
return
placeholderNote
;
}
return
issueNote
;
return
issueNote
;
},
},
componentData
(
note
)
{
componentData
(
note
)
{
return
note
.
isPlaceholderNote
?
note
.
notes
[
0
]
:
note
;
return
note
.
isPlaceholderNote
?
note
.
notes
[
0
]
:
note
;
},
},
toggleDiscussion
()
{
toggleDiscussion
()
{
this
.
$store
.
commit
(
'
toggleDiscussion
'
,
{
this
.
toggleDiscussion
({
discussionId
:
this
.
note
.
id
});
discussionId
:
this
.
note
.
id
,
},
});
showReplyForm
()
{
},
this
.
isReplying
=
true
;
showReplyForm
()
{
},
this
.
isReplying
=
true
;
cancelReplyForm
(
shouldConfirm
)
{
},
if
(
shouldConfirm
&&
this
.
$refs
.
noteForm
.
isDirty
)
{
cancelReplyForm
(
shouldConfirm
)
{
const
msg
=
'
Are you sure you want to cancel creating this comment?
'
;
if
(
shouldConfirm
&&
this
.
$refs
.
noteForm
.
isDirty
)
{
// eslint-disable-next-line no-alert
const
msg
=
'
Are you sure you want to cancel creating this comment?
'
;
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-next-line no-alert
if
(
!
isConfirmed
)
{
const
isConfirmed
=
confirm
(
msg
);
return
;
if
(
!
isConfirmed
)
{
}
return
;
}
}
}
this
.
isReplying
=
false
;
this
.
isReplying
=
false
;
},
},
saveReply
({
note
})
{
saveReply
({
note
})
{
const
replyData
=
{
const
replyData
=
{
endpoint
:
this
.
newNotePath
,
endpoint
:
this
.
newNotePath
,
flashContainer
:
this
.
$el
,
flashContainer
:
this
.
$el
,
data
:
{
data
:
{
in_reply_to_discussion_id
:
this
.
note
.
reply_id
,
in_reply_to_discussion_id
:
this
.
note
.
reply_id
,
target_type
:
'
issue
'
,
target_type
:
'
issue
'
,
target_id
:
this
.
discussion
.
noteable_id
,
target_id
:
this
.
discussion
.
noteable_id
,
note
:
{
note
},
note
:
{
note
},
full_data
:
true
,
full_data
:
true
,
},
},
};
};
this
.
$store
.
dispatch
(
'
saveNote
'
,
replyData
)
this
.
saveNote
(
replyData
)
.
then
(()
=>
{
.
then
(()
=>
{
this
.
isReplying
=
false
;
this
.
isReplying
=
false
;
})
})
.
catch
(()
=>
{
.
catch
(()
=>
Flash
(
'
Something went wrong while adding your reply. Please try again.
'
));
Flash
(
'
Something went wrong while adding your reply. Please try again.
'
);
},
});
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -132,8 +136,7 @@ export default {
...
@@ -132,8 +136,7 @@ export default {
:edited-at=
"note.last_updated_at"
:edited-at=
"note.last_updated_at"
:edited-by=
"note.last_updated_by"
:edited-by=
"note.last_updated_by"
actionText=
"Last updated"
actionText=
"Last updated"
className=
"discussion-headline-light js-discussion-headline"
className=
"discussion-headline-light js-discussion-headline"
/>
/>
</div>
</div>
</div>
</div>
<div
<div
...
@@ -162,7 +165,8 @@ export default {
...
@@ -162,7 +165,8 @@ export default {
saveButtonTitle=
"Comment"
saveButtonTitle=
"Comment"
:update-handler=
"saveReply"
:update-handler=
"saveReply"
:cancel-handler=
"cancelReplyForm"
:cancel-handler=
"cancelReplyForm"
ref=
"noteForm"
/>
ref=
"noteForm"
/>
<issue-note-signed-out-widget
v-if=
"!canReply"
/>
<issue-note-signed-out-widget
v-if=
"!canReply"
/>
</div>
</div>
</div>
</div>
...
...
app/assets/javascripts/notes/components/issue_note.vue
View file @
ffef1669
<
script
>
<
script
>
/* global Flash */
/* global Flash */
import
{
mapGetter
s
}
from
'
vuex
'
;
import
{
mapGetters
,
mapAction
s
}
from
'
vuex
'
;
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
import
issueNoteActions
from
'
./issue_note_actions.vue
'
;
import
issueNoteActions
from
'
./issue_note_actions.vue
'
;
import
issueNoteBody
from
'
./issue_note_body.vue
'
;
import
issueNoteBody
from
'
./issue_note_body.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
export
default
{
props
:
{
props
:
{
note
:
{
note
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
},
},
data
()
{
data
()
{
return
{
isEditing
:
false
,
isDeleting
:
false
,
};
},
components
:
{
userAvatarLink
,
issueNoteHeader
,
issueNoteActions
,
issueNoteBody
,
},
computed
:
{
...
mapGetters
([
'
targetNoteHash
'
,
]),
author
()
{
return
this
.
note
.
author
;
},
classNameBindings
()
{
return
{
return
{
'
is-editing
'
:
this
.
isEditing
,
isEditing
:
false
,
'
disabled-content
'
:
this
.
isDeleting
,
isDeleting
:
false
,
'
js-my-note
'
:
this
.
author
.
id
===
window
.
gon
.
current_user_id
,
target
:
this
.
targetNoteHash
===
this
.
noteAnchorId
,
};
};
},
},
c
anReportAsAbuse
()
{
c
omponents
:
{
return
this
.
note
.
report_abuse_path
&&
this
.
author
.
id
!==
window
.
gon
.
current_user_id
;
userAvatarLink
,
}
,
issueNoteHeader
,
noteAnchorId
()
{
issueNoteActions
,
return
`note_
${
this
.
note
.
id
}
`
;
issueNoteBody
,
},
},
},
computed
:
{
methods
:
{
...
mapGetters
([
editHandler
()
{
'
targetNoteHash
'
,
this
.
isEditing
=
true
;
]),
author
()
{
return
this
.
note
.
author
;
},
classNameBindings
()
{
return
{
'
is-editing
'
:
this
.
isEditing
,
'
disabled-content
'
:
this
.
isDeleting
,
'
js-my-note
'
:
this
.
author
.
id
===
window
.
gon
.
current_user_id
,
target
:
this
.
targetNoteHash
===
this
.
noteAnchorId
,
};
},
canReportAsAbuse
()
{
return
this
.
note
.
report_abuse_path
&&
this
.
author
.
id
!==
window
.
gon
.
current_user_id
;
},
noteAnchorId
()
{
return
`note_
${
this
.
note
.
id
}
`
;
},
},
},
deleteHandler
()
{
methods
:
{
const
msg
=
'
Are you sure you want to delete this list?
'
;
...
mapActions
([
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
'
deleteNote
'
,
'
updateNote
'
,
'
scrollToNoteIfNeeded
'
,
]),
editHandler
()
{
this
.
isEditing
=
true
;
},
deleteHandler
()
{
const
msg
=
'
Are you sure you want to delete this list?
'
;
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
if
(
isConfirmed
)
{
this
.
isDeleting
=
true
;
this
.
deleteNote
(
this
.
note
)
.
then
(()
=>
{
this
.
isDeleting
=
false
;
})
.
catch
(()
=>
{
Flash
(
'
Something went wrong while deleting your note. Please try again.
'
);
this
.
isDeleting
=
false
;
});
}
},
formUpdateHandler
(
note
)
{
const
data
=
{
endpoint
:
this
.
note
.
path
,
note
:
{
full_data
:
true
,
target_type
:
'
issue
'
,
target_id
:
this
.
note
.
noteable_id
,
note
,
},
};
if
(
isConfirmed
)
{
this
.
updateNote
(
data
)
this
.
isDeleting
=
true
;
this
.
$store
.
dispatch
(
'
deleteNote
'
,
this
.
note
)
.
then
(()
=>
{
.
then
(()
=>
{
this
.
isDeleting
=
false
;
this
.
isEditing
=
false
;
$
(
this
.
$refs
.
noteBody
.
$el
).
renderGFM
();
})
})
.
catch
(()
=>
{
.
catch
(()
=>
Flash
(
'
Something went wrong while editing your comment. Please try again.
'
));
new
Flash
(
'
Something went wrong while deleting your note. Please try again.
'
);
// eslint-disable-line
},
this
.
isDeleting
=
false
;
formCancelHandler
(
shouldConfirm
)
{
});
if
(
shouldConfirm
&&
this
.
$refs
.
noteBody
.
$refs
.
noteForm
.
isDirty
)
{
}
const
msg
=
'
Are you sure you want to cancel editing this comment?
'
;
},
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
formUpdateHandler
(
note
)
{
if
(
!
isConfirmed
)
{
const
data
=
{
return
;
endpoint
:
this
.
note
.
path
,
}
note
:
{
}
full_data
:
true
,
target_type
:
'
issue
'
,
target_id
:
this
.
note
.
noteable_id
,
note
,
},
};
this
.
$store
.
dispatch
(
'
updateNote
'
,
data
)
this
.
isEditing
=
false
;
.
then
(()
=>
{
},
this
.
isEditing
=
false
;
$
(
this
.
$refs
.
noteBody
.
$el
).
renderGFM
();
})
.
catch
(()
=>
{
Flash
(
'
Something went wrong while editing your comment. Please try again.
'
);
});
},
},
formCancelHandler
(
shouldConfirm
)
{
created
()
{
if
(
shouldConfirm
&&
this
.
$refs
.
noteBody
.
$refs
.
noteForm
.
isDirty
)
{
eventHub
.
$on
(
'
enterEditMode
'
,
({
noteId
})
=>
{
const
msg
=
'
Are you sure you want to cancel editing this comment?
'
;
if
(
noteId
===
this
.
note
.
id
)
{
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
this
.
isEditing
=
true
;
if
(
!
isConfirmed
)
{
this
.
scrollToNoteIfNeeded
(
$
(
this
.
$el
));
return
;
}
}
}
});
this
.
isEditing
=
false
;
},
},
},
};
created
()
{
eventHub
.
$on
(
'
enterEditMode
'
,
({
noteId
})
=>
{
if
(
noteId
===
this
.
note
.
id
)
{
this
.
isEditing
=
true
;
this
.
$store
.
dispatch
(
'
scrollToNoteIfNeeded
'
,
$
(
this
.
$el
));
}
});
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -124,7 +126,8 @@ export default {
...
@@ -124,7 +126,8 @@ export default {
:link-href=
"author.path"
:link-href=
"author.path"
:img-src=
"author.avatar_url"
:img-src=
"author.avatar_url"
:img-alt=
"author.name"
:img-alt=
"author.name"
:img-size=
"40"
/>
:img-size=
"40"
/>
</div>
</div>
<div
class=
"timeline-content"
>
<div
class=
"timeline-content"
>
<div
class=
"note-header"
>
<div
class=
"note-header"
>
...
@@ -132,7 +135,8 @@ export default {
...
@@ -132,7 +135,8 @@ export default {
:author=
"author"
:author=
"author"
:created-at=
"note.created_at"
:created-at=
"note.created_at"
:note-id=
"note.id"
:note-id=
"note.id"
actionText=
"commented"
/>
actionText=
"commented"
/>
<issue-note-actions
<issue-note-actions
:author-id=
"author.id"
:author-id=
"author.id"
:note-id=
"note.id"
:note-id=
"note.id"
...
@@ -142,7 +146,8 @@ export default {
...
@@ -142,7 +146,8 @@ export default {
:can-report-as-abuse=
"canReportAsAbuse"
:can-report-as-abuse=
"canReportAsAbuse"
:report-abuse-path=
"note.report_abuse_path"
:report-abuse-path=
"note.report_abuse_path"
:edit-handler=
"editHandler"
:edit-handler=
"editHandler"
:delete-handler=
"deleteHandler"
/>
:delete-handler=
"deleteHandler"
/>
</div>
</div>
<issue-note-body
<issue-note-body
:note=
"note"
:note=
"note"
...
@@ -150,7 +155,8 @@ export default {
...
@@ -150,7 +155,8 @@ export default {
:is-editing=
"isEditing"
:is-editing=
"isEditing"
:form-update-handler=
"formUpdateHandler"
:form-update-handler=
"formUpdateHandler"
:form-cancel-handler=
"formCancelHandler"
:form-cancel-handler=
"formCancelHandler"
ref=
"noteBody"
/>
ref=
"noteBody"
/>
</div>
</div>
</div>
</div>
</li>
</li>
...
...
app/assets/javascripts/notes/components/issue_note_actions.vue
View file @
ffef1669
<
script
>
<
script
>
import
emojiSmiling
from
'
icons/_emoji_slightly_smiling_face.svg
'
;
import
emojiSmiling
from
'
icons/_emoji_slightly_smiling_face.svg
'
;
import
emojiSmile
from
'
icons/_emoji_smile.svg
'
;
import
emojiSmile
from
'
icons/_emoji_smile.svg
'
;
import
emojiSmiley
from
'
icons/_emoji_smiley.svg
'
;
import
emojiSmiley
from
'
icons/_emoji_smiley.svg
'
;
import
loadingIcon
from
'
../../vue_shared/components/loadingI
con.vue
'
;
import
loadingIcon
from
'
../../vue_shared/components/loading_i
con.vue
'
;
export
default
{
export
default
{
props
:
{
props
:
{
authorId
:
{
authorId
:
{
type
:
Number
,
type
:
Number
,
required
:
true
,
required
:
true
,
},
noteId
:
{
type
:
Number
,
required
:
true
,
},
accessLevel
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
reportAbusePath
:
{
type
:
String
,
required
:
true
,
},
canEdit
:
{
type
:
Boolean
,
required
:
true
,
},
canDelete
:
{
type
:
Boolean
,
required
:
true
,
},
canReportAsAbuse
:
{
type
:
Boolean
,
required
:
true
,
},
editHandler
:
{
type
:
Function
,
required
:
true
,
},
deleteHandler
:
{
type
:
Function
,
required
:
true
,
},
},
},
noteId
:
{
data
()
{
type
:
Number
,
return
{
required
:
true
,
emojiSmiling
,
emojiSmile
,
emojiSmiley
,
};
},
},
accessLevel
:
{
components
:
{
type
:
String
,
loadingIcon
,
required
:
false
,
default
:
''
,
},
},
reportAbusePath
:
{
computed
:
{
type
:
String
,
shouldShowActionsDropdown
()
{
required
:
true
,
return
window
.
gon
.
current_user_id
&&
(
this
.
canEdit
||
this
.
canReportAsAbuse
);
},
canAddAwardEmoji
()
{
return
window
.
gon
.
current_user_id
;
},
isAuthoredByMe
()
{
return
this
.
authorId
===
window
.
gon
.
current_user_id
;
},
},
},
canEdit
:
{
};
type
:
Boolean
,
required
:
true
,
},
canDelete
:
{
type
:
Boolean
,
required
:
true
,
},
canReportAsAbuse
:
{
type
:
Boolean
,
required
:
true
,
},
editHandler
:
{
type
:
Function
,
required
:
true
,
},
deleteHandler
:
{
type
:
Function
,
required
:
true
,
},
},
data
()
{
return
{
emojiSmiling
,
emojiSmile
,
emojiSmiley
,
};
},
computed
:
{
shouldShowActionsDropdown
()
{
return
window
.
gon
.
current_user_id
&&
(
this
.
canEdit
||
this
.
canReportAsAbuse
);
},
canAddAwardEmoji
()
{
return
window
.
gon
.
current_user_id
;
},
isAuthoredByMe
()
{
return
this
.
authorId
===
window
.
gon
.
current_user_id
;
},
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -82,13 +85,16 @@ export default {
...
@@ -82,13 +85,16 @@ export default {
<loading-icon
/>
<loading-icon
/>
<span
<span
v-html=
"emojiSmiling"
v-html=
"emojiSmiling"
class=
"link-highlight award-control-icon-neutral"
></span>
class=
"link-highlight award-control-icon-neutral"
>
</span>
<span
<span
v-html=
"emojiSmiley"
v-html=
"emojiSmiley"
class=
"link-highlight award-control-icon-positive"
></span>
class=
"link-highlight award-control-icon-positive"
>
</span>
<span
<span
v-html=
"emojiSmile"
v-html=
"emojiSmile"
class=
"link-highlight award-control-icon-super-positive"
></span>
class=
"link-highlight award-control-icon-super-positive"
>
</span>
</a>
</a>
<div
<div
v-if=
"shouldShowActionsDropdown"
v-if=
"shouldShowActionsDropdown"
...
@@ -101,7 +107,8 @@ export default {
...
@@ -101,7 +107,8 @@ export default {
data-container=
"body"
>
data-container=
"body"
>
<i
<i
aria-hidden=
"true"
aria-hidden=
"true"
class=
"fa fa-ellipsis-v icon"
></i>
class=
"fa fa-ellipsis-v icon"
>
</i>
</button>
</button>
<ul
class=
"dropdown-menu more-actions-dropdown dropdown-open-left"
>
<ul
class=
"dropdown-menu more-actions-dropdown dropdown-open-left"
>
<template
v-if=
"canEdit"
>
<template
v-if=
"canEdit"
>
...
...
app/assets/javascripts/notes/components/issue_note_awards_list.vue
View file @
ffef1669
This diff is collapsed.
Click to expand it.
app/assets/javascripts/notes/components/issue_note_body.vue
View file @
ffef1669
<
script
>
<
script
>
import
issueNoteEditedText
from
'
./issue_note_edited_text.vue
'
;
import
issueNoteEditedText
from
'
./issue_note_edited_text.vue
'
;
import
issueNoteAwardsList
from
'
./issue_note_awards_list.vue
'
;
import
issueNoteAwardsList
from
'
./issue_note_awards_list.vue
'
;
import
issueNoteForm
from
'
./issue_note_form.vue
'
;
import
issueNoteForm
from
'
./issue_note_form.vue
'
;
import
TaskList
from
'
../../task_list
'
;
import
TaskList
from
'
../../task_list
'
;
export
default
{
export
default
{
props
:
{
props
:
{
note
:
{
note
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
canEdit
:
{
type
:
Boolean
,
required
:
true
,
},
isEditing
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
formUpdateHandler
:
{
type
:
Function
,
required
:
true
,
},
formCancelHandler
:
{
type
:
Function
,
required
:
true
,
},
},
},
canEdit
:
{
components
:
{
type
:
Boolean
,
issueNoteEditedText
,
required
:
true
,
issueNoteAwardsList
,
issueNoteForm
,
},
},
isEditing
:
{
computed
:
{
type
:
Boolean
,
noteBody
()
{
required
:
false
,
return
this
.
note
.
note
;
default
:
false
,
}
,
},
},
formUpdateHandler
:
{
methods
:
{
type
:
Function
,
renderGFM
()
{
required
:
true
,
$
(
this
.
$refs
[
'
note-body
'
]).
renderGFM
();
},
},
formCancelHandler
:
{
initTaskList
()
{
type
:
Function
,
if
(
this
.
canEdit
)
{
required
:
true
,
this
.
taskList
=
new
TaskList
({
},
dataType
:
'
note
'
,
},
fieldName
:
'
note
'
,
components
:
{
selector
:
'
.notes
'
,
issueNoteEditedText
,
});
issueNoteAwardsList
,
}
issueNoteForm
,
},
},
handleFormUpdate
()
{
computed
:
{
this
.
formUpdateHandler
({
noteBody
()
{
note
:
this
.
$refs
.
noteForm
.
note
,
return
this
.
note
.
note
;
},
},
methods
:
{
renderGFM
()
{
$
(
this
.
$refs
[
'
note-body
'
]).
renderGFM
();
},
initTaskList
()
{
if
(
this
.
canEdit
)
{
this
.
taskList
=
new
TaskList
({
dataType
:
'
note
'
,
fieldName
:
'
note
'
,
selector
:
'
.notes
'
,
});
});
}
},
},
mounted
()
{
this
.
renderGFM
();
this
.
initTaskList
();
},
},
handleFormUpdate
()
{
updated
()
{
this
.
formUpdateHandler
({
this
.
initTaskList
();
note
:
this
.
$refs
.
noteForm
.
note
,
});
},
},
},
};
mounted
()
{
this
.
renderGFM
();
this
.
initTaskList
();
},
updated
()
{
this
.
initTaskList
();
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/notes/components/issue_note_edited_text.vue
View file @
ffef1669
<
script
>
<
script
>
import
timeAgoTooltip
from
'
../../vue_shared/components/time_ago_tooltip.vue
'
;
import
timeAgoTooltip
from
'
../../vue_shared/components/time_ago_tooltip.vue
'
;
export
default
{
export
default
{
props
:
{
props
:
{
actionText
:
{
actionText
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
},
editedAt
:
{
type
:
String
,
required
:
true
,
},
editedBy
:
{
type
:
Object
,
required
:
true
,
},
className
:
{
type
:
String
,
required
:
false
,
default
:
'
edited-text
'
,
},
},
},
editedAt
:
{
components
:
{
type
:
String
,
timeAgoTooltip
,
required
:
true
,
},
},
editedBy
:
{
};
type
:
Object
,
required
:
true
,
},
className
:
{
type
:
String
,
required
:
false
,
default
:
'
edited-text
'
,
},
},
components
:
{
timeAgoTooltip
,
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -38,6 +38,7 @@ export default {
...
@@ -38,6 +38,7 @@ export default {
</a>
</a>
<time-ago-tooltip
<time-ago-tooltip
:time=
"editedAt"
:time=
"editedAt"
tooltip-placement=
"bottom"
/>
tooltip-placement=
"bottom"
/>
</div>
</div>
</
template
>
</
template
>
app/assets/javascripts/notes/components/issue_note_form.vue
View file @
ffef1669
<
script
>
<
script
>
import
markdownField
from
'
../../vue_shared/components/markdown/field.vue
'
;
import
markdownField
from
'
../../vue_shared/components/markdown/field.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
export
default
{
props
:
{
props
:
{
noteBody
:
{
noteBody
:
{
type
:
String
,
type
:
String
,
required
:
false
,
required
:
false
,
default
:
''
,
default
:
''
,
},
noteId
:
{
type
:
Number
,
required
:
false
,
},
updateHandler
:
{
type
:
Function
,
required
:
true
,
},
cancelHandler
:
{
type
:
Function
,
required
:
true
,
},
saveButtonTitle
:
{
type
:
String
,
required
:
false
,
default
:
'
Save comment
'
,
},
},
},
noteId
:
{
data
()
{
type
:
Number
,
return
{
required
:
false
,
initialNote
:
this
.
noteBody
,
note
:
this
.
noteBody
,
markdownPreviewUrl
:
gl
.
issueData
.
preview_note_path
,
markdownDocsUrl
:
''
,
conflictWhileEditing
:
false
,
};
},
},
updateHandler
:
{
components
:
{
type
:
Function
,
markdownField
,
required
:
true
,
},
},
cancelHandler
:
{
computed
:
{
type
:
Function
,
isDirty
()
{
required
:
true
,
return
this
.
initialNote
!==
this
.
note
;
},
noteHash
()
{
return
`#note_
${
this
.
noteId
}
`
;
},
},
},
saveButtonTitle
:
{
methods
:
{
type
:
String
,
handleUpdate
()
{
required
:
false
,
this
.
updateHandler
({
default
:
'
Save comment
'
,
note
:
this
.
note
,
},
});
},
},
data
()
{
editMyLastNote
()
{
return
{
if
(
this
.
note
===
''
)
{
initialNote
:
this
.
noteBody
,
const
discussion
=
$
(
this
.
$el
).
closest
(
'
.discussion-notes
'
);
note
:
this
.
noteBody
,
const
myLastNoteId
=
discussion
.
find
(
'
.js-my-note
'
).
last
().
attr
(
'
id
'
);
markdownPreviewUrl
:
gl
.
issueData
.
preview_note_path
,
markdownDocsUrl
:
''
,
conflictWhileEditing
:
false
,
};
},
components
:
{
markdownField
,
},
computed
:
{
isDirty
()
{
return
this
.
initialNote
!==
this
.
note
;
},
noteHash
()
{
return
`#note_
${
this
.
noteId
}
`
;
},
},
methods
:
{
handleUpdate
()
{
this
.
updateHandler
({
note
:
this
.
note
,
});
},
editMyLastNote
()
{
if
(
this
.
note
===
''
)
{
const
discussion
=
$
(
this
.
$el
).
closest
(
'
.discussion-notes
'
);
const
myLastNoteId
=
discussion
.
find
(
'
.js-my-note
'
).
last
().
attr
(
'
id
'
);
if
(
myLastNoteId
)
{
if
(
myLastNoteId
)
{
eventHub
.
$emit
(
'
enterEditMode
'
,
{
eventHub
.
$emit
(
'
enterEditMode
'
,
{
noteId
:
parseInt
(
myLastNoteId
.
replace
(
'
note_
'
,
''
),
10
),
noteId
:
parseInt
(
myLastNoteId
.
replace
(
'
note_
'
,
''
),
10
),
});
});
}
}
}
}
}
,
},
},
},
mounted
()
{
mounted
()
{
const
issuableDataEl
=
document
.
getElementById
(
'
js-issuable-app-initial-data
'
);
const
issuableDataEl
=
document
.
getElementById
(
'
js-issuable-app-initial-data
'
);
const
issueData
=
JSON
.
parse
(
issuableDataEl
.
innerHTML
.
replace
(
/"/g
,
'
"
'
));
const
issueData
=
JSON
.
parse
(
issuableDataEl
.
innerHTML
.
replace
(
/"/g
,
'
"
'
));
this
.
markdownDocsUrl
=
issueData
.
markdownDocs
;
this
.
markdownDocsUrl
=
issueData
.
markdownDocs
;
this
.
$refs
.
textarea
.
focus
();
this
.
$refs
.
textarea
.
focus
();
},
},
watch
:
{
watch
:
{
noteBody
()
{
noteBody
()
{
if
(
this
.
note
===
this
.
initialNote
)
{
if
(
this
.
note
===
this
.
initialNote
)
{
this
.
note
=
this
.
noteBody
;
this
.
note
=
this
.
noteBody
;
}
else
{
}
else
{
this
.
conflictWhileEditing
=
true
;
this
.
conflictWhileEditing
=
true
;
}
}
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/notes/components/issue_note_header.vue
View file @
ffef1669
<
script
>
<
script
>
import
timeAgoTooltip
from
'
../../vue_shared/components/time_ago_tooltip.vue
'
;
import
{
mapMutations
}
from
'
vuex
'
;
import
timeAgoTooltip
from
'
../../vue_shared/components/time_ago_tooltip.vue
'
;
import
*
as
types
from
'
../stores/mutation_types
'
;
export
default
{
export
default
{
props
:
{
props
:
{
author
:
{
author
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
createdAt
:
{
type
:
String
,
required
:
true
,
},
actionText
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
actionTextHtml
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
noteId
:
{
type
:
Number
,
required
:
true
,
},
includeToggle
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
toggleHandler
:
{
type
:
Function
,
required
:
false
,
},
},
},
createdAt
:
{
data
()
{
type
:
String
,
return
{
required
:
true
,
isExpanded
:
true
,
};
},
},
actionText
:
{
components
:
{
type
:
String
,
timeAgoTooltip
,
required
:
false
,
default
:
''
,
},
},
actionTextHtml
:
{
computed
:
{
type
:
String
,
toggleChevronClass
()
{
required
:
false
,
return
this
.
isExpanded
?
'
fa-chevron-up
'
:
'
fa-chevron-down
'
;
default
:
''
,
},
noteTimestampLink
()
{
return
`#note_
${
this
.
noteId
}
`
;
},
},
},
noteId
:
{
methods
:
{
type
:
Number
,
...
mapMutations
({
required
:
true
,
setTargetNoteHash
:
types
.
SET_TARGET_NOTE_HASH
,
}),
handleToggle
()
{
this
.
isExpanded
=
!
this
.
isExpanded
;
this
.
toggleHandler
();
},
updateTargetNoteHash
()
{
this
.
setTargetNoteHash
(
this
.
noteTimestampLink
);
},
},
},
includeToggle
:
{
};
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
toggleHandler
:
{
type
:
Function
,
required
:
false
,
},
},
data
()
{
return
{
isExpanded
:
true
,
};
},
components
:
{
timeAgoTooltip
,
},
computed
:
{
toggleChevronClass
()
{
return
this
.
isExpanded
?
'
fa-chevron-up
'
:
'
fa-chevron-down
'
;
},
noteTimestampLink
()
{
return
`#note_
${
this
.
noteId
}
`
;
},
},
methods
:
{
handleToggle
()
{
this
.
isExpanded
=
!
this
.
isExpanded
;
this
.
toggleHandler
();
},
updateTargetNoteHash
()
{
this
.
$store
.
commit
(
'
setTargetNoteHash
'
,
this
.
noteTimestampLink
);
},
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -81,13 +86,15 @@ export default {
...
@@ -81,13 +86,15 @@ export default {
<span
<span
v-if=
"actionTextHtml"
v-if=
"actionTextHtml"
v-html=
"actionTextHtml"
v-html=
"actionTextHtml"
class=
"system-note-message"
></span>
class=
"system-note-message"
>
</span>
<a
<a
:href=
"noteTimestampLink"
:href=
"noteTimestampLink"
@
click=
"updateTargetNoteHash"
>
@
click=
"updateTargetNoteHash"
>
<time-ago-tooltip
<time-ago-tooltip
:time=
"createdAt"
:time=
"createdAt"
tooltipPlacement=
"bottom"
/>
tooltipPlacement=
"bottom"
/>
</a>
</a>
</span>
</span>
</span>
</span>
...
@@ -101,7 +108,8 @@ export default {
...
@@ -101,7 +108,8 @@ export default {
<i
<i
:class=
"toggleChevronClass"
:class=
"toggleChevronClass"
class=
"fa"
class=
"fa"
aria-hidden=
"true"
></i>
aria-hidden=
"true"
>
</i>
Toggle discussion
Toggle discussion
</button>
</button>
</div>
</div>
...
...
app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue
View file @
ffef1669
<
script
>
<
script
>
export
default
{
export
default
{
data
()
{
data
()
{
return
{
return
{
signInLink
:
'
#
'
,
signInLink
:
'
#
'
,
};
};
},
},
mounted
()
{
mounted
()
{
const
wrapper
=
document
.
querySelector
(
'
.js-notes-wrapper
'
);
const
wrapper
=
document
.
querySelector
(
'
.js-notes-wrapper
'
);
if
(
wrapper
)
{
if
(
wrapper
)
{
this
.
signInLink
=
wrapper
.
dataset
.
newSessionPath
;
this
.
signInLink
=
wrapper
.
dataset
.
newSessionPath
;
}
}
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/notes/components/issue_notes.vue
View file @
ffef1669
<
script
>
<
script
>
/* global Flash */
/* global Flash */
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
mapGetters
,
mapActions
,
mapMutations
}
from
'
vuex
'
;
import
VueResource
from
'
vue-resource
'
;
import
store
from
'
../stores/
'
;
import
storeOptions
from
'
../stores/issue_notes_store
'
;
import
*
as
constants
from
'
../constants
'
import
eventHub
from
'
../event_hub
'
;
import
*
as
types
from
'
../stores/mutation_types
'
;
import
issueNote
from
'
./issue_note.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
issueDiscussion
from
'
./issue_discussion.vue
'
;
import
issueNote
from
'
./issue_note.vue
'
;
import
issueSystemNote
from
'
./issue_system_note.vue
'
;
import
issueDiscussion
from
'
./issue_discussion.vue
'
;
import
issueCommentForm
from
'
./issue_comment_form.vue
'
;
import
issueSystemNote
from
'
./issue_system_note.vue
'
;
import
placeholderNote
from
'
./issue_placeholder_note.vue
'
;
import
issueCommentForm
from
'
./issue_comment_form.vue
'
;
import
placeholderSystemNote
from
'
./issue_placeholder_system_note.vue
'
;
import
placeholderNote
from
'
./issue_placeholder_note.vue
'
;
import
store
from
'
./store
'
;
import
placeholderSystemNote
from
'
./issue_placeholder_system_note.vue
'
;
import
loadingIcon
from
'
../../vue_shared/components/loading_icon.vue
'
;
export
default
{
export
default
{
name
:
'
IssueNotes
'
,
name
:
'
IssueNotes
'
,
store
,
store
,
data
()
{
data
()
{
return
{
return
{
isLoading
:
true
,
isLoading
:
true
,
};
};
},
components
:
{
issueNote
,
issueDiscussion
,
issueSystemNote
,
issueCommentForm
,
placeholderNote
,
placeholderSystemNote
,
},
computed
:
{
...
Vuex
.
mapGetters
([
'
notes
'
,
'
notesById
'
,
]),
},
methods
:
{
componentName
(
note
)
{
if
(
note
.
isPlaceholderNote
)
{
if
(
note
.
placeholderType
===
'
systemNote
'
)
{
return
placeholderSystemNote
;
}
return
placeholderNote
;
}
else
if
(
note
.
individual_note
)
{
return
note
.
notes
[
0
].
system
?
issueSystemNote
:
issueNote
;
}
return
issueDiscussion
;
},
},
componentData
(
note
)
{
components
:
{
return
note
.
individual_note
?
note
.
notes
[
0
]
:
note
;
issueNote
,
issueDiscussion
,
issueSystemNote
,
issueCommentForm
,
loadingIcon
,
placeholderNote
,
placeholderSystemNote
,
},
},
fetchNotes
()
{
computed
:
{
const
{
discussionsPath
}
=
this
.
$el
.
parentNode
.
dataset
;
...
mapGetters
([
'
notes
'
,
'
notesById
'
,
]),
},
methods
:
{
...
mapActions
({
actionFetchNotes
:
'
fetchNotes
'
,
}),
...
mapActions
([
'
poll
'
,
'
toggleAward
'
,
'
scrollToNoteIfNeeded
'
,
]),
...
mapMutations
({
setLastFetchedAt
:
types
.
SET_LAST_FETCHED_AT
,
setTargetNoteHash
:
types
.
SET_TARGET_NOTE_HASH
,
}),
getComponentName
(
note
)
{
if
(
note
.
isPlaceholderNote
)
{
if
(
note
.
placeholderType
===
constants
.
SYSTEM_NOTE
)
{
return
placeholderSystemNote
;
}
return
placeholderNote
;
}
else
if
(
note
.
individual_note
)
{
return
note
.
notes
[
0
].
system
?
issueSystemNote
:
issueNote
;
}
this
.
$store
.
dispatch
(
'
fetchNotes
'
,
discussionsPath
)
return
issueDiscussion
;
.
then
(()
=>
{
},
this
.
isLoading
=
false
;
getComponentData
(
note
)
{
return
note
.
individual_note
?
note
.
notes
[
0
]
:
note
;
},
fetchNotes
()
{
const
{
discussionsPath
}
=
this
.
$el
.
parentNode
.
dataset
;
// Scroll to note if we have hash fragment in the page URL
this
.
actionFetchNotes
(
discussionsPath
)
Vue
.
nextTick
(()
=>
{
.
then
(()
=>
{
this
.
checkLocationHash
();
this
.
isLoading
=
false
;
});
})
.
catch
(()
=>
{
Flash
(
'
Something went wrong while fetching issue comments. Please try again.
'
);
});
},
initPolling
()
{
const
{
lastFetchedAt
}
=
$
(
'
.js-notes-wrapper
'
)[
0
].
dataset
;
this
.
$store
.
commit
(
'
setLastFetchedAt
'
,
lastFetchedAt
);
// FIXME: @fatihacet Implement real polling mechanism
// Scroll to note if we have hash fragment in the page URL
setInterval
(()
=>
{
Vue
.
nextTick
(()
=>
{
this
.
$store
.
dispatch
(
'
poll
'
)
this
.
checkLocationHash
();
.
then
((
res
)
=>
{
});
this
.
$store
.
commit
(
'
setLastFetchedAt
'
,
res
.
lastFetchedAt
);
})
})
.
catch
(()
=>
{
.
catch
(()
=>
{
Flash
(
'
Something went wrong while fetching
latest comments
.
'
);
Flash
(
'
Something went wrong while fetching
issue comments. Please try again
.
'
);
});
});
},
15000
);
},
},
initPolling
()
{
bindEventHubListeners
()
{
const
{
lastFetchedAt
}
=
$
(
'
.js-notes-wrapper
'
)[
0
].
dataset
;
eventHub
.
$on
(
'
toggleAward
'
,
(
data
)
=>
{
this
.
setLastFetchedAt
(
lastFetchedAt
);
const
{
awardName
,
noteId
}
=
data
;
const
endpoint
=
this
.
notesById
[
noteId
].
toggle_award_path
;
this
.
$store
.
dispatch
(
'
toggleAward
'
,
{
endpoint
,
awardName
,
noteId
})
// FIXME: @fatihacet Implement real polling mechanism
.
catch
(()
=>
{
setInterval
(()
=>
{
Flash
(
'
Something went wrong on our end.
'
);
this
.
poll
()
});
.
then
((
res
)
=>
{
});
this
.
setLastFetchedAt
(
res
.
lastFetchedAt
);
})
.
catch
(()
=>
{
Flash
(
'
Something went wrong while fetching latest comments.
'
);
});
},
15000
);
},
bindEventHubListeners
()
{
eventHub
.
$on
(
'
toggleAward
'
,
(
data
)
=>
{
const
{
awardName
,
noteId
}
=
data
;
const
endpoint
=
this
.
notesById
[
noteId
].
toggle_award_path
;
$
(
document
).
on
(
'
issuable:change
'
,
(
e
,
isClosed
)
=>
{
this
.
toggleAward
({
endpoint
,
awardName
,
noteId
})
eventHub
.
$emit
(
'
issueStateChanged
'
,
isClosed
);
.
catch
(()
=>
{
new
Flash
(
'
Something went wrong on our end.
'
)});
});
});
},
checkLocationHash
()
{
const
hash
=
gl
.
utils
.
getLocationHash
();
const
$el
=
$
(
`#
${
hash
}
`
);
if
(
hash
&&
$el
)
{
$
(
document
).
on
(
'
issuable:change
'
,
(
e
,
isClosed
)
=>
{
this
.
$store
.
commit
(
'
setTargetNoteHash
'
,
hash
);
eventHub
.
$emit
(
'
issueStateChanged
'
,
isClosed
);
this
.
$store
.
dispatch
(
'
scrollToNoteIfNeeded
'
,
$el
);
});
}
},
checkLocationHash
()
{
const
hash
=
gl
.
utils
.
getLocationHash
();
const
$el
=
$
(
`#
${
hash
}
`
);
if
(
hash
&&
$el
)
{
this
.
setTargetNoteHash
(
hash
);
this
.
scrollToNoteIfNeeded
(
$el
);
}
},
},
mounted
()
{
this
.
fetchNotes
();
this
.
initPolling
();
this
.
bindEventHubListeners
();
},
},
},
};
mounted
()
{
this
.
fetchNotes
();
this
.
initPolling
();
this
.
bindEventHubListeners
();
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -121,9 +133,7 @@ export default {
...
@@ -121,9 +133,7 @@ export default {
<div
<div
v-if=
"isLoading"
v-if=
"isLoading"
class=
"loading"
>
class=
"loading"
>
<i
<loading-icon
/>
class=
"fa fa-spinner fa-spin"
aria-hidden=
"true"
></i>
</div>
</div>
<ul
<ul
v-if=
"!isLoading"
v-if=
"!isLoading"
...
@@ -131,9 +141,10 @@ export default {
...
@@ -131,9 +141,10 @@ export default {
class=
"notes main-notes-list timeline"
>
class=
"notes main-notes-list timeline"
>
<component
<component
v-for=
"note in notes"
v-for=
"note in notes"
:is=
"componentName(note)"
:is=
"getComponentName(note)"
:note=
"componentData(note)"
:note=
"getComponentData(note)"
:key=
"note.id"
/>
:key=
"note.id"
/>
</ul>
</ul>
<issue-comment-form
v-if=
"!isLoading"
/>
<issue-comment-form
v-if=
"!isLoading"
/>
</div>
</div>
...
...
app/assets/javascripts/notes/components/issue_placeholder_note.vue
View file @
ffef1669
<
script
>
<
script
>
export
default
{
export
default
{
props
:
{
props
:
{
note
:
{
note
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
},
},
data
()
{
data
()
{
return
{
return
{
currentUser
:
window
.
gl
.
currentUserData
,
currentUser
:
window
.
gl
.
currentUserData
,
};
};
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -21,7 +21,8 @@ export default {
...
@@ -21,7 +21,8 @@ export default {
<a
:href=
"currentUser.path"
>
<a
:href=
"currentUser.path"
>
<img
<img
:src=
"currentUser.avatar_url"
:src=
"currentUser.avatar_url"
class=
"avatar s40"
/>
class=
"avatar s40"
/>
</a>
</a>
</div>
</div>
<div
<div
...
...
app/assets/javascripts/notes/components/issue_placeholder_system_note.vue
View file @
ffef1669
<
script
>
<
script
>
export
default
{
export
default
{
props
:
{
props
:
{
note
:
{
note
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/notes/components/issue_system_note.vue
View file @
ffef1669
<
script
>
<
script
>
import
{
mapGetters
}
from
'
vuex
'
;
import
{
mapGetters
}
from
'
vuex
'
;
import
iconsMap
from
'
./issue_note_icons
'
;
import
iconsMap
from
'
./issue_note_icons
'
;
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
import
issueNoteHeader
from
'
./issue_note_header.vue
'
;
export
default
{
export
default
{
props
:
{
props
:
{
note
:
{
note
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
},
},
data
()
{
data
()
{
return
{
return
{
svg
:
iconsMap
[
this
.
note
.
system_note_icon_name
],
svg
:
iconsMap
[
this
.
note
.
system_note_icon_name
],
};
};
},
components
:
{
issueNoteHeader
,
},
computed
:
{
...
mapGetters
([
'
targetNoteHash
'
,
]),
noteAnchorId
()
{
return
`note_
${
this
.
note
.
id
}
`
;
},
},
isTargetNote
()
{
components
:
{
return
this
.
targetNoteHash
===
this
.
noteAnchorId
;
issueNoteHeader
,
},
},
},
computed
:
{
};
...
mapGetters
([
'
targetNoteHash
'
,
]),
noteAnchorId
()
{
return
`note_
${
this
.
note
.
id
}
`
;
},
isTargetNote
()
{
return
this
.
targetNoteHash
===
this
.
noteAnchorId
;
},
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/notes/constants.js
View file @
ffef1669
...
@@ -5,4 +5,4 @@ export const SYSTEM_NOTE = 'systemNote';
...
@@ -5,4 +5,4 @@ export const SYSTEM_NOTE = 'systemNote';
export
const
COMMENT
=
'
comment
'
;
export
const
COMMENT
=
'
comment
'
;
export
const
OPENED
=
'
opened
'
;
export
const
OPENED
=
'
opened
'
;
export
const
REOPENED
=
'
reopened
'
;
export
const
REOPENED
=
'
reopened
'
;
export
const
CLOSED
=
'
closed
'
;
export
const
CLOSED
=
'
closed
'
;
\ No newline at end of file
app/assets/javascripts/notes/stores/actions.js
View file @
ffef1669
...
@@ -138,8 +138,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
...
@@ -138,8 +138,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
export
const
poll
=
({
commit
,
state
,
getters
})
=>
{
export
const
poll
=
({
commit
,
state
,
getters
})
=>
{
const
{
notesPath
}
=
$
(
'
.js-notes-wrapper
'
)[
0
].
dataset
;
const
{
notesPath
}
=
$
(
'
.js-notes-wrapper
'
)[
0
].
dataset
;
return
service
return
service
.
poll
(
`
${
notesPath
}
?full_data=1`
,
state
.
lastFetchedAt
)
.
poll
(
`
${
notesPath
}
?full_data=1`
,
state
.
lastFetchedAt
)
.
then
(
res
=>
res
.
json
())
.
then
(
res
=>
res
.
json
())
.
then
((
res
)
=>
{
.
then
((
res
)
=>
{
if
(
res
.
notes
.
length
)
{
if
(
res
.
notes
.
length
)
{
...
@@ -188,8 +187,8 @@ export const toggleAward = ({ commit, getters, dispatch }, data) => {
...
@@ -188,8 +187,8 @@ export const toggleAward = ({ commit, getters, dispatch }, data) => {
});
});
if
(
amIAwarded
)
{
if
(
amIAwarded
)
{
Object
.
assign
(
data
,
{
awardName
:
counterAward
})
;
data
.
awardName
=
counterAward
;
Object
.
assign
(
data
,
{
skipMutalityCheck
:
true
})
;
data
.
skipMutalityCheck
=
true
;
dispatch
(
types
.
TOGGLE_AWARD
,
data
);
dispatch
(
types
.
TOGGLE_AWARD
,
data
);
}
}
...
...
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