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