Commit b38e6903 authored by Filipa Lacerda's avatar Filipa Lacerda

Fix open discussions

parent fc9e5743
<script> <script>
/* global Flash, Autosave */ /* global Flash, Autosave */
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore'; import _ from 'underscore';
import '../../autosave'; import '../../autosave';
...@@ -113,7 +112,7 @@ ...@@ -113,7 +112,7 @@
data: { data: {
view: 'full_data', view: 'full_data',
note: { note: {
noteable_type: 'Issue', noteable_type: constants.NOTEABLE_TYPE,
noteable_id: this.getIssueData.id, noteable_id: this.getIssueData.id,
note: this.note, note: this.note,
}, },
...@@ -123,7 +122,6 @@ ...@@ -123,7 +122,6 @@
if (this.noteType === constants.DISCUSSION) { if (this.noteType === constants.DISCUSSION) {
noteData.data.note.type = constants.DISCUSSION_NOTE; noteData.data.note.type = constants.DISCUSSION_NOTE;
} }
this.isSubmitting = true; this.isSubmitting = true;
this.saveNote(noteData) this.saveNote(noteData)
...@@ -150,13 +148,7 @@ ...@@ -150,13 +148,7 @@
} }
if (withIssueAction) { if (withIssueAction) {
if (this.isIssueOpen) { this.issueState = this.isIssueOpen ? constants.CLOSED : constants.REOPENED;
this.issueState = constants.CLOSED;
} else {
this.issueState = constants.REOPENED;
}
this.isIssueOpen = !this.isIssueOpen;
// This is out of scope for the Notes Vue component. // This is out of scope for the Notes Vue component.
// It was the shortest path to update the issue state and relevant places. // It was the shortest path to update the issue state and relevant places.
...@@ -220,9 +212,8 @@ ...@@ -220,9 +212,8 @@
<ul <ul
v-else v-else
class="notes notes-form timeline new-note"> class="notes notes-form timeline new-note">
<li class="timeline-entry" ref="commentForm"> <li class="timeline-entry">
<div class="timeline-entry-inner"> <div class="timeline-entry-inner">
<div class="flash-container timeline-content"></div>
<div class="timeline-icon hidden-xs hidden-sm"> <div class="timeline-icon hidden-xs hidden-sm">
<user-avatar-link <user-avatar-link
v-if="author" v-if="author"
...@@ -234,10 +225,10 @@ ...@@ -234,10 +225,10 @@
</div> </div>
<div > <div >
<form <form
class="js-main-target-form timeline-content timeline-content-form common-note-form" ref="commentForm"
@submit="handleSave(true)"> class="js-main-target-form timeline-content timeline-content-form common-note-form">
<div class="flash-container timeline-content"></div>
<confidentialIssue v-if="isConfidentialIssue" /> <confidentialIssue v-if="isConfidentialIssue" />
<markdown-field <markdown-field
:markdown-preview-url="markdownPreviewUrl" :markdown-preview-url="markdownPreviewUrl"
:markdown-docs="markdownDocsUrl" :markdown-docs="markdownDocsUrl"
...@@ -263,7 +254,7 @@ ...@@ -263,7 +254,7 @@
<button <button
@click="handleSave()" @click="handleSave()"
:disabled="isSubmitButtonDisabled" :disabled="isSubmitButtonDisabled"
class="btn btn-nr btn-create comment-btn js-comment-button js-comment-submit-button" class="btn btn-create comment-btn js-comment-button js-comment-submit-button"
type="button"> type="button">
{{commentButtonTitle}} {{commentButtonTitle}}
</button> </button>
...@@ -319,7 +310,8 @@ ...@@ -319,7 +310,8 @@
</ul> </ul>
</div> </div>
<button <button
type="submit" type="button"
@click="handleSave(true)"
v-if="canUpdateIssue" v-if="canUpdateIssue"
:class="actionButtonClassNames" :class="actionButtonClassNames"
class="btn btn-comment btn-comment-and-close"> class="btn btn-comment btn-comment-and-close">
......
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
:created-at="discussion.created_at" :created-at="discussion.created_at"
:note-id="discussion.id" :note-id="discussion.id"
:include-toggle="true" :include-toggle="true"
:toggle-handler="toggleDiscussionHandler" @toggleHandler="toggleDiscussionHandler"
action-text="started a discussion" action-text="started a discussion"
/> />
<issue-note-edited-text <issue-note-edited-text
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
name: 'issueNoteActions',
props: { props: {
authorId: { authorId: {
type: Number, type: Number,
...@@ -41,13 +42,6 @@ ...@@ -41,13 +42,6 @@
directives: { directives: {
tooltip, tooltip,
}, },
data() {
return {
emojiSmiling,
emojiSmile,
emojiSmiley,
};
},
components: { components: {
loadingIcon, loadingIcon,
}, },
...@@ -76,6 +70,11 @@ ...@@ -76,6 +70,11 @@
this.$emit('deleteHandler'); this.$emit('deleteHandler');
}, },
}, },
created() {
this.emojiSmiling = emojiSmiling;
this.emojiSmile = emojiSmile;
this.emojiSmiley = emojiSmiley;
}
}; };
</script> </script>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
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 * as Emoji from '../../emoji'; import { glEmojiTag } from '../../emoji';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
'toggleAwardRequest', 'toggleAwardRequest',
]), ]),
getAwardHTML(name) { getAwardHTML(name) {
return Emoji.glEmojiTag(name); return glEmojiTag(name);
}, },
getAwardClassBindings(awardList, awardName) { getAwardClassBindings(awardList, awardName) {
return { return {
......
<script> <script>
/* global Autosave */
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';
......
...@@ -31,11 +31,6 @@ ...@@ -31,11 +31,6 @@
required: false, required: false,
default: false, default: false,
}, },
toggleHandler: {
type: Function,
required: false,
default: () => {},
},
}, },
data() { data() {
return { return {
...@@ -59,7 +54,7 @@ ...@@ -59,7 +54,7 @@
]), ]),
handleToggle() { handleToggle() {
this.isExpanded = !this.isExpanded; this.isExpanded = !this.isExpanded;
this.toggleHandler(); this.$emit('toggleHandler');
}, },
updateTargetNoteHash() { updateTargetNoteHash() {
this.setTargetNoteHash(this.noteTimestampLink); this.setTargetNoteHash(this.noteTimestampLink);
......
...@@ -79,16 +79,15 @@ ...@@ -79,16 +79,15 @@
}, },
fetchNotes() { fetchNotes() {
return this.actionFetchNotes(this.getNotesDataByProp('discussionsPath')) return this.actionFetchNotes(this.getNotesDataByProp('discussionsPath'))
.then(() => this.initPolling())
.then(() => { .then(() => {
// Scroll to note if we have hash fragment in the page URL this.isLoading = false;
this.$nextTick(() => {
this.checkLocationHash();
});
}) })
.catch(() => Flash('Something went wrong while fetching issue comments. Please try again.')) .then(() => this.$nextTick())
.then(() => { .then(() => this.checkLocationHash())
.catch(() => {
this.isLoading = false; this.isLoading = false;
this.initPolling(); Flash('Something went wrong while fetching issue comments. Please try again.');
}); });
}, },
initPolling() { initPolling() {
......
<script> <script>
import { mapGetters } 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';
export default { export default {
...@@ -12,10 +13,10 @@ ...@@ -12,10 +13,10 @@
components: { components: {
userAvatarLink, userAvatarLink,
}, },
data() { computed: {
return { ...mapGetters([
currentUser: this.$store.getters.getUserData, 'getUserData',
}; ]),
}, },
}; };
</script> </script>
...@@ -25,9 +26,9 @@ ...@@ -25,9 +26,9 @@
<div class="timeline-entry-inner"> <div class="timeline-entry-inner">
<div class="timeline-icon"> <div class="timeline-icon">
<user-avatar-link <user-avatar-link
:link-href="currentUser.path" :link-href="getUserData.path"
:img-src="currentUser.avatar_url" :img-src="getUserData.avatar_url"
:size="40" :img-size="40"
/> />
</div> </div>
<div <div
...@@ -35,9 +36,9 @@ ...@@ -35,9 +36,9 @@
class="timeline-content"> class="timeline-content">
<div class="note-header"> <div class="note-header">
<div class="note-header-info"> <div class="note-header-info">
<a :href="currentUser.path"> <a :href="getUserData.path">
<span class="hidden-xs">{{currentUser.name}}</span> <span class="hidden-xs">{{getUserData.name}}</span>
<span class="note-headline-light">@{{currentUser.username}}</span> <span class="note-headline-light">@{{getUserData.username}}</span>
</a> </a>
</div> </div>
</div> </div>
......
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
required: true, required: true,
}, },
}, },
data() {
return {
svg: iconsMap[this.note.system_note_icon_name],
};
},
components: { components: {
issueNoteHeader, issueNoteHeader,
}, },
...@@ -30,6 +25,9 @@ ...@@ -30,6 +25,9 @@
return this.targetNoteHash === this.noteAnchorId; return this.targetNoteHash === this.noteAnchorId;
}, },
}, },
created() {
this.svg = iconsMap[this.note.system_note_icon_name];
},
}; };
</script> </script>
......
...@@ -8,3 +8,4 @@ export const REOPENED = 'reopened'; ...@@ -8,3 +8,4 @@ export const REOPENED = 'reopened';
export const CLOSED = 'closed'; export const CLOSED = 'closed';
export const EMOJI_THUMBSUP = 'thumbsup'; export const EMOJI_THUMBSUP = 'thumbsup';
export const EMOJI_THUMBSDOWN = 'thumbsdown'; export const EMOJI_THUMBSDOWN = 'thumbsdown';
export const NOTEABLE_TYPE = 'Issue';
...@@ -25,9 +25,6 @@ document.addEventListener('DOMContentLoaded', () => new Vue({ ...@@ -25,9 +25,6 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
}, },
render(createElement) { render(createElement) {
return createElement('issue-notes-app', { return createElement('issue-notes-app', {
attrs: {
ref: 'notes',
},
props: { props: {
issueData: this.issueData, issueData: this.issueData,
notesData: this.notesData, notesData: this.notesData,
......
...@@ -18,11 +18,14 @@ export const notesById = state => state.notes.reduce((acc, note) => { ...@@ -18,11 +18,14 @@ export const notesById = state => state.notes.reduce((acc, note) => {
}, {}); }, {});
const reverseNotes = array => array.slice(0).reverse(); const reverseNotes = array => array.slice(0).reverse();
const isLastNote = (note, state) => !note.system && note.author.id === state.userData.id; const isLastNote = (note, state) => !note.system &&
state.userData &&
export const getCurrentUserLastNote = state => _.flatten(reverseNotes(state.notes) note.author.id === state.userData.id;
.map(note => note.notes))
.find(el => isLastNote(el, state)); export const getCurrentUserLastNote = state => _.flatten(
reverseNotes(state.notes)
.map(note => reverseNotes(note.notes)),
).find(el => isLastNote(el, state));
export const getDiscussionLastNote = state => discussion => reverseNotes(discussion.notes) export const getDiscussionLastNote = state => discussion => reverseNotes(discussion.notes)
.find(el => isLastNote(el, state)); .find(el => isLastNote(el, state));
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
import markdownHeader from './header.vue'; import markdownHeader from './header.vue';
import markdownToolbar from './toolbar.vue'; import markdownToolbar from './toolbar.vue';
const REFERENCED_USERS_THRESHOLD = 10;
export default { export default {
props: { props: {
markdownPreviewUrl: { markdownPreviewUrl: {
...@@ -41,7 +39,8 @@ ...@@ -41,7 +39,8 @@
}, },
computed: { computed: {
shouldShowReferencedUsers() { shouldShowReferencedUsers() {
return this.referencedUsers.length >= REFERENCED_USERS_THRESHOLD; const referencedUsersThreshold = 10;
return this.referencedUsers.length >= referencedUsersThreshold;
}, },
}, },
methods: { methods: {
......
...@@ -16,3 +16,5 @@ ...@@ -16,3 +16,5 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'notes' = webpack_bundle_tag 'notes'
= render "layouts/init_auto_complete"
\ No newline at end of file
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
.timeline-content.timeline-content-form .timeline-content.timeline-content-form
= render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete = render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete
- elsif !current_user - elsif !current_user
.disabled-comment.text-center.prepend-top-default.js-disabled-comment .disabled-comment.text-center.prepend-top-default
Please Please
= link_to "register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'js-register-link' = link_to "register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'js-register-link'
or or
......
...@@ -46,6 +46,7 @@ Feature: Project Issues ...@@ -46,6 +46,7 @@ Feature: Project Issues
Given I visit issue page "Release 0.4" Given I visit issue page "Release 0.4"
And I leave a comment like "XML attached" And I leave a comment like "XML attached"
Then I should see comment "XML attached" Then I should see comment "XML attached"
And I should see an error alert section within the comment form
@javascript @javascript
Scenario: Visiting Issues after being sorted the list Scenario: Visiting Issues after being sorted the list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment