Commit a03f59d3 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'draft-design-improvements' into 'master'

Improve draft note header design

Closes #7920 and #7905

See merge request gitlab-org/gitlab-ee!8503
parents b60490de 89f0db81
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui'; import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import resolvedStatusMixin from 'ee/batch_comments/mixins/resolved_status';
export default { export default {
name: 'NoteActions', name: 'NoteActions',
...@@ -12,6 +13,7 @@ export default { ...@@ -12,6 +13,7 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [resolvedStatusMixin],
props: { props: {
authorId: { authorId: {
type: Number, type: Number,
...@@ -93,6 +95,8 @@ export default { ...@@ -93,6 +95,8 @@ export default {
return this.getUserDataByProp('id'); return this.getUserDataByProp('id');
}, },
resolveButtonTitle() { resolveButtonTitle() {
if (this.discussionId) return this.resolvedStatusMessage;
let title = 'Mark as resolved'; let title = 'Mark as resolved';
if (this.resolvedBy) { if (this.resolvedBy) {
...@@ -113,6 +117,7 @@ export default { ...@@ -113,6 +117,7 @@ export default {
this.$emit('handleResolve'); this.$emit('handleResolve');
}, },
}, },
showStaysResolved: true,
}; };
</script> </script>
......
<script> <script>
import { mapGetters } from 'vuex';
import $ from 'jquery'; import $ from 'jquery';
import noteEditedText from './note_edited_text.vue'; import noteEditedText from './note_edited_text.vue';
import noteAwardsList from './note_awards_list.vue'; import noteAwardsList from './note_awards_list.vue';
...@@ -30,9 +31,15 @@ export default { ...@@ -30,9 +31,15 @@ export default {
}, },
}, },
computed: { computed: {
...mapGetters(['getDiscussion']),
noteBody() { noteBody() {
return this.note.note; return this.note.note;
}, },
discussion() {
if (!this.note.isDraft) return {};
return this.getDiscussion(this.note.discussion_id);
},
}, },
mounted() { mounted() {
this.renderGFM(); this.renderGFM();
...@@ -56,8 +63,8 @@ export default { ...@@ -56,8 +63,8 @@ export default {
renderGFM() { renderGFM() {
$(this.$refs['note-body']).renderGFM(); $(this.$refs['note-body']).renderGFM();
}, },
handleFormUpdate(note, parentElement, callback) { handleFormUpdate(note, parentElement, callback, resolveDiscussion) {
this.$emit('handleFormUpdate', note, parentElement, callback); this.$emit('handleFormUpdate', note, parentElement, callback, resolveDiscussion);
}, },
formCancelHandler(shouldConfirm, isDirty) { formCancelHandler(shouldConfirm, isDirty) {
this.$emit('cancelForm', shouldConfirm, isDirty); this.$emit('cancelForm', shouldConfirm, isDirty);
...@@ -76,6 +83,8 @@ export default { ...@@ -76,6 +83,8 @@ export default {
:note-body="noteBody" :note-body="noteBody"
:note-id="note.id" :note-id="note.id"
:markdown-version="note.cached_markdown_version" :markdown-version="note.cached_markdown_version"
:discussion="discussion"
:resolve-discussion="note.resolve_discussion"
@handleFormUpdate="handleFormUpdate" @handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler" @cancelForm="formCancelHandler"
/> />
......
...@@ -51,14 +51,19 @@ export default { ...@@ -51,14 +51,19 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
resolveDiscussion: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
updatedNoteBody: this.noteBody, updatedNoteBody: this.noteBody,
conflictWhileEditing: false, conflictWhileEditing: false,
isSubmitting: false, isSubmitting: false,
isResolving: false, isResolving: this.resolveDiscussion,
isUnresolving: false, isUnresolving: !this.resolveDiscussion,
resolveAsThread: true, resolveAsThread: true,
}; };
}, },
...@@ -122,13 +127,19 @@ export default { ...@@ -122,13 +127,19 @@ export default {
const beforeSubmitDiscussionState = this.discussionResolved; const beforeSubmitDiscussionState = this.discussionResolved;
this.isSubmitting = true; this.isSubmitting = true;
this.$emit('handleFormUpdate', this.updatedNoteBody, this.$refs.editNoteForm, () => { this.$emit(
'handleFormUpdate',
this.updatedNoteBody,
this.$refs.editNoteForm,
() => {
this.isSubmitting = false; this.isSubmitting = false;
if (this.shouldToggleResolved(shouldResolve, beforeSubmitDiscussionState)) { if (this.shouldToggleResolved(shouldResolve, beforeSubmitDiscussionState)) {
this.resolveHandler(beforeSubmitDiscussionState); this.resolveHandler(beforeSubmitDiscussionState);
} }
}); },
this.discussionResolved ? !this.isUnresolving : this.isResolving,
);
}, },
editMyLastNote() { editMyLastNote() {
if (this.updatedNoteBody === '') { if (this.updatedNoteBody === '') {
...@@ -153,7 +164,7 @@ export default { ...@@ -153,7 +164,7 @@ export default {
<div ref="editNoteForm" class="note-edit-form current-note-edit-form js-discussion-note-form"> <div ref="editNoteForm" class="note-edit-form current-note-edit-form js-discussion-note-form">
<div v-if="conflictWhileEditing" class="js-conflict-edit-warning alert alert-danger"> <div v-if="conflictWhileEditing" class="js-conflict-edit-warning alert alert-danger">
This comment has changed since you started editing, please review the This comment has changed since you started editing, please review the
<a :href="noteHash" target="_blank" rel="noopener noreferrer"> updated comment </a> to ensure <a :href="noteHash" target="_blank" rel="noopener noreferrer">updated comment</a> to ensure
information is not lost. information is not lost.
</div> </div>
<div class="flash-container timeline-content"></div> <div class="flash-container timeline-content"></div>
...@@ -178,20 +189,17 @@ export default { ...@@ -178,20 +189,17 @@ export default {
v-model="updatedNoteBody" v-model="updatedNoteBody"
:data-supports-quick-actions="!isEditing" :data-supports-quick-actions="!isEditing"
name="note[note]" name="note[note]"
class="note-textarea js-gfm-input js-note-text class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
aria-label="Description" aria-label="Description"
placeholder="Write a comment or drag your files here…" placeholder="Write a comment or drag your files here…"
@keydown.meta.enter="handleUpdate();" @keydown.meta.enter="handleUpdate();"
@keydown.ctrl.enter="handleUpdate();" @keydown.ctrl.enter="handleUpdate();"
@keydown.up="editMyLastNote();" @keydown.up="editMyLastNote();"
@keydown.esc="cancelHandler(true);" @keydown.esc="cancelHandler(true);"
> ></textarea>
</textarea>
</markdown-field> </markdown-field>
<div class="note-form-actions clearfix"> <div class="note-form-actions clearfix">
<template v-if="showBatchCommentsActions"> <p v-if="(discussion && discussion.id) || isDraft">
<p v-if="discussion && discussion.id">
<label> <label>
<template v-if="discussionResolved"> <template v-if="discussionResolved">
<input <input
...@@ -207,19 +215,15 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input" ...@@ -207,19 +215,15 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
</template> </template>
</label> </label>
</p> </p>
<div> <div v-if="showBatchCommentsActions">
<button <button
:disabled="isDisabled" :disabled="isDisabled"
type="button" type="button"
class="btn btn-success qa-start-review" class="btn btn-success qa-start-review"
@click="handleAddToReview();" @click="handleAddToReview"
> >
<template v-if="hasDrafts"> <template v-if="hasDrafts">{{ __('Add to review') }}</template>
{{ __('Add to review') }} <template v-else>{{ __('Start a review') }}</template>
</template>
<template v-else>
{{ __('Start a review') }}
</template>
</button> </button>
<button <button
:disabled="isDisabled" :disabled="isDisabled"
...@@ -237,12 +241,11 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input" ...@@ -237,12 +241,11 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
{{ __('Cancel') }} {{ __('Cancel') }}
</button> </button>
</div> </div>
</template>
<template v-else> <template v-else>
<button <button
:disabled="isDisabled" :disabled="isDisabled"
type="button" type="button"
class="js-vue-issue-save btn btn-success js-comment-button " class="js-vue-issue-save btn btn-success js-comment-button"
@click="handleUpdate();" @click="handleUpdate();"
> >
{{ saveButtonTitle }} {{ saveButtonTitle }}
......
...@@ -69,24 +69,23 @@ export default { ...@@ -69,24 +69,23 @@ export default {
type="button" type="button"
@click="handleToggle" @click="handleToggle"
> >
<i :class="toggleChevronClass" class="fa" aria-hidden="true"> </i> <i :class="toggleChevronClass" class="fa" aria-hidden="true"></i>
{{ __('Toggle discussion') }} {{ __('Toggle discussion') }}
</button> </button>
</div> </div>
<a v-if="hasAuthor" v-once :href="author.path"> <a v-if="hasAuthor" v-once :href="author.path">
<slot name="note-header-info"></slot>
<span class="note-header-author-name">{{ author.name }}</span> <span class="note-header-author-name">{{ author.name }}</span>
<span v-if="author.status_tooltip_html" v-html="author.status_tooltip_html"></span> <span v-if="author.status_tooltip_html" v-html="author.status_tooltip_html"></span>
<span class="note-headline-light"> @{{ author.username }} </span> <span class="note-headline-light">@{{ author.username }}</span>
</a> </a>
<span v-else> {{ __('A deleted user') }} </span> <span v-else>{{ __('A deleted user') }}</span>
<span class="note-headline-light"> <span class="note-headline-light">
<span class="note-headline-meta"> <span class="note-headline-meta">
<span class="system-note-message"> <slot></slot> </span> <span class="system-note-message"> <slot></slot> </span>
<template v-if="createdAt"> <template v-if="createdAt">
<span class="system-note-separator"> <span class="system-note-separator">
<template v-if="actionText"> <template v-if="actionText">{{ actionText }}</template>
{{ actionText }}
</template>
</span> </span>
<a <a
:href="noteTimestampLink" :href="noteTimestampLink"
...@@ -100,8 +99,7 @@ export default { ...@@ -100,8 +99,7 @@ export default {
class="fa fa-spinner fa-spin editing-spinner" class="fa fa-spinner fa-spin editing-spinner"
aria-label="Comment is being updated" aria-label="Comment is being updated"
aria-hidden="true" aria-hidden="true"
> ></i>
</i>
</span> </span>
</span> </span>
</div> </div>
......
...@@ -111,10 +111,11 @@ export default { ...@@ -111,10 +111,11 @@ export default {
this.$refs.noteBody.resetAutoSave(); this.$refs.noteBody.resetAutoSave();
this.$emit('updateSuccess'); this.$emit('updateSuccess');
}, },
formUpdateHandler(noteText, parentElement, callback) { formUpdateHandler(noteText, parentElement, callback, resolveDiscussion) {
this.$emit('handleUpdateNote', { this.$emit('handleUpdateNote', {
note: this.note, note: this.note,
noteText, noteText,
resolveDiscussion,
callback: () => this.updateSuccess(), callback: () => this.updateSuccess(),
}); });
...@@ -198,7 +199,9 @@ export default { ...@@ -198,7 +199,9 @@ export default {
:created-at="note.created_at" :created-at="note.created_at"
:note-id="note.id" :note-id="note.id"
action-text="commented" action-text="commented"
/> >
<slot slot="note-header-info" name="note-header-info"> </slot>
</note-header>
<note-actions <note-actions
:author-id="author.id" :author-id="author.id"
:note-id="note.id" :note-id="note.id"
...@@ -208,12 +211,16 @@ export default { ...@@ -208,12 +211,16 @@ export default {
:can-award-emoji="note.current_user.can_award_emoji" :can-award-emoji="note.current_user.can_award_emoji"
:can-delete="note.current_user.can_edit" :can-delete="note.current_user.can_edit"
:can-report-as-abuse="canReportAsAbuse" :can-report-as-abuse="canReportAsAbuse"
:can-resolve="note.current_user.can_resolve" :can-resolve="
note.current_user.can_resolve || (note.isDraft && note.discussion_id !== null)
"
:report-abuse-path="note.report_abuse_path" :report-abuse-path="note.report_abuse_path"
:resolvable="note.resolvable" :resolvable="note.resolvable || note.isDraft"
:is-resolved="note.resolved" :is-resolved="note.resolved || note.resolve_discussion"
:is-resolving="isResolving" :is-resolving="isResolving"
:resolved-by="note.resolved_by" :resolved-by="note.resolved_by"
:discussion-id="note.isDraft && note.discussion_id"
:resolve-discussion="note.isDraft && note.resolve_discussion"
@handleEdit="editHandler" @handleEdit="editHandler"
@handleDelete="deleteHandler" @handleDelete="deleteHandler"
@handleResolve="resolveHandler" @handleResolve="resolveHandler"
......
...@@ -31,12 +31,16 @@ export default { ...@@ -31,12 +31,16 @@ export default {
}, },
methods: { methods: {
resolveHandler(resolvedState = false) { resolveHandler(resolvedState = false) {
if (this.note && this.note.isDraft) {
return this.$emit('toggleResolveStatus');
}
this.isResolving = true; this.isResolving = true;
const isResolved = this.discussionResolved || resolvedState; const isResolved = this.discussionResolved || resolvedState;
const discussion = this.resolveAsThread; const discussion = this.resolveAsThread;
const endpoint = discussion ? this.discussion.resolve_path : `${this.note.path}/resolve`; const endpoint = discussion ? this.discussion.resolve_path : `${this.note.path}/resolve`;
this.toggleResolveNote({ endpoint, isResolved, discussion }) return this.toggleResolveNote({ endpoint, isResolved, discussion })
.then(() => { .then(() => {
this.isResolving = false; this.isResolving = false;
}) })
......
...@@ -3,7 +3,6 @@ import { mapActions, mapGetters, mapState } from 'vuex'; ...@@ -3,7 +3,6 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import NoteableNote from '~/notes/components/noteable_note.vue'; import NoteableNote from '~/notes/components/noteable_note.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import resolvedStatusMixin from '../mixins/resolved_status';
import PublishButton from './publish_button.vue'; import PublishButton from './publish_button.vue';
export default { export default {
...@@ -13,7 +12,6 @@ export default { ...@@ -13,7 +12,6 @@ export default {
Icon, Icon,
LoadingButton, LoadingButton,
}, },
mixins: [resolvedStatusMixin],
props: { props: {
draft: { draft: {
type: Object, type: Object,
...@@ -43,6 +41,7 @@ export default { ...@@ -43,6 +41,7 @@ export default {
'updateDraft', 'updateDraft',
'publishSingleDraft', 'publishSingleDraft',
'scrollToDraft', 'scrollToDraft',
'toggleResolveDiscussion',
]), ]),
update(data) { update(data) {
this.updateDraft(data); this.updateDraft(data);
...@@ -57,18 +56,10 @@ export default { ...@@ -57,18 +56,10 @@ export default {
this.isEditingDraft = false; this.isEditingDraft = false;
}, },
}, },
showStaysResolved: true,
}; };
</script> </script>
<template> <template>
<article :class="componentClasses" class="draft-note-component note-wrapper"> <article class="draft-note-component note-wrapper">
<header class="draft-note-header">
<strong class="badge draft-pending-label"> {{ __('Pending') }} </strong>
<p v-if="draft.discussion_id" class="draft-note-resolution">
<Icon :size="16" name="status_success" />
{{ __(resolvedStatusMessage) }}
</p>
</header>
<ul class="notes draft-notes"> <ul class="notes draft-notes">
<noteable-note <noteable-note
:note="draft" :note="draft"
...@@ -78,7 +69,12 @@ export default { ...@@ -78,7 +69,12 @@ export default {
@updateSuccess="handleNotEditing" @updateSuccess="handleNotEditing"
@handleDeleteNote="deleteDraft" @handleDeleteNote="deleteDraft"
@handleUpdateNote="update" @handleUpdateNote="update"
/> @toggleResolveStatus="toggleResolveDiscussion(draft.id);"
>
<strong slot="note-header-info" class="badge draft-pending-label append-right-4">
{{ __('Pending') }}
</strong>
</noteable-note>
</ul> </ul>
<template v-if="!isEditingDraft"> <template v-if="!isEditingDraft">
...@@ -88,11 +84,11 @@ export default { ...@@ -88,11 +84,11 @@ export default {
v-html="draftCommands" v-html="draftCommands"
></div> ></div>
<p class="draft-note-actions"> <p class="draft-note-actions d-flex">
<publish-button <publish-button
:show-count="true" :show-count="true"
:should-publish="false" :should-publish="false"
class="btn btn-success btn-inverted" class="btn btn-success btn-inverted append-right-8"
/> />
<loading-button <loading-button
:loading="isPublishingDraft(draft.id) || isPublishing" :loading="isPublishingDraft(draft.id) || isPublishing"
......
import { mapGetters, mapState } from 'vuex'; import { mapGetters, mapState } from 'vuex';
export default { export default {
props: {
isDraft: {
type: Boolean,
required: false,
default: false,
},
},
computed: { computed: {
...mapState({ ...mapState({
withBatchComments: state => state.batchComments && state.batchComments.withBatchComments, withBatchComments: state => state.batchComments && state.batchComments.withBatchComments,
...@@ -21,20 +28,6 @@ export default { ...@@ -21,20 +28,6 @@ export default {
return resolveStatus; return resolveStatus;
}, },
handleUpdate(resolveStatus) {
const beforeSubmitDiscussionState = this.discussionResolved;
this.isSubmitting = true;
const shouldBeResolved = this.shouldBeResolved(resolveStatus) !== beforeSubmitDiscussionState;
this.$emit('handleFormUpdate', this.updatedNoteBody, this.$refs.editNoteForm, () => {
this.isSubmitting = false;
if (resolveStatus || (shouldBeResolved && this.withBatchComments)) {
this.resolveHandler(beforeSubmitDiscussionState); // this will toggle the state
}
});
},
handleAddToReview() { handleAddToReview() {
// check if draft should resolve discussion // check if draft should resolve discussion
const shouldResolve = const shouldResolve =
......
...@@ -2,12 +2,28 @@ import { mapGetters } from 'vuex'; ...@@ -2,12 +2,28 @@ import { mapGetters } from 'vuex';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export default { export default {
props: {
discussionId: {
type: String,
required: false,
default: null,
},
resolveDiscussion: {
type: Boolean,
required: false,
default: false,
},
},
computed: { computed: {
...mapGetters(['isDiscussionResolved']), ...mapGetters(['isDiscussionResolved']),
resolvedStatusMessage() { resolvedStatusMessage() {
let message; let message;
const discussionResolved = this.isDiscussionResolved(this.draft.discussion_id); const discussionResolved = this.isDiscussionResolved(
const discussionToBeResolved = this.draft.resolve_discussion; this.draft ? this.draft.discussion_id : this.discussionId,
);
const discussionToBeResolved = this.draft
? this.draft.resolve_discussion
: this.resolveDiscussion;
if (discussionToBeResolved && discussionResolved && !this.$options.showStaysResolved) { if (discussionToBeResolved && discussionResolved && !this.$options.showStaysResolved) {
return undefined; return undefined;
...@@ -15,22 +31,20 @@ export default { ...@@ -15,22 +31,20 @@ export default {
if (discussionToBeResolved) { if (discussionToBeResolved) {
if (discussionResolved) { if (discussionResolved) {
message = s__('MergeRequests|Discussion stays resolved.'); message = s__('MergeRequests|Discussion stays resolved');
} else { } else {
message = s__('MergeRequests|Discussion will be resolved.'); message = s__('MergeRequests|Discussion will be resolved');
} }
} else if (discussionResolved) { } else if (discussionResolved) {
message = s__('MergeRequests|Discussion will be unresolved.'); message = s__('MergeRequests|Discussion will be unresolved');
} else if (this.$options.showStaysResolved) { } else if (this.$options.showStaysResolved) {
message = s__('MergeRequests|Discussion stays unresolved.'); message = s__('MergeRequests|Discussion stays unresolved');
} }
return message; return message;
}, },
componentClasses() { componentClasses() {
return this.draft.resolve_discussion return this.resolveDiscussion ? 'is-resolving-discussion' : 'is-unresolving-discussion';
? 'is-resolving-discussion'
: 'is-unresolving-discussion';
}, },
}, },
}; };
...@@ -28,7 +28,11 @@ export default { ...@@ -28,7 +28,11 @@ export default {
discard(endpoint) { discard(endpoint) {
return Vue.http.delete(endpoint); return Vue.http.delete(endpoint);
}, },
update(endpoint, { draftId, note }) { update(endpoint, { draftId, note, resolveDiscussion }) {
return Vue.http.put(`${endpoint}/${draftId}`, { draft_note: { note } }, { emulateJSON: true }); return Vue.http.put(
`${endpoint}/${draftId}`,
{ draft_note: { note, resolve_discussion: resolveDiscussion } },
{ emulateJSON: true },
);
}, },
}; };
...@@ -88,9 +88,13 @@ export const discardReview = ({ commit, getters }) => { ...@@ -88,9 +88,13 @@ export const discardReview = ({ commit, getters }) => {
.catch(() => commit(types.RECEIVE_DISCARD_REVIEW_ERROR)); .catch(() => commit(types.RECEIVE_DISCARD_REVIEW_ERROR));
}; };
export const updateDraft = ({ commit, getters }, { note, noteText, callback }) => export const updateDraft = ({ commit, getters }, { note, noteText, resolveDiscussion, callback }) =>
service service
.update(getters.getNotesData.draftsPath, { draftId: note.id, note: noteText }) .update(getters.getNotesData.draftsPath, {
draftId: note.id,
note: noteText,
resolveDiscussion,
})
.then(res => res.json()) .then(res => res.json())
.then(data => commit(types.RECEIVE_DRAFT_UPDATE_SUCCESS, data)) .then(data => commit(types.RECEIVE_DRAFT_UPDATE_SUCCESS, data))
.then(callback) .then(callback)
...@@ -139,5 +143,9 @@ export const expandAllDiscussions = ({ dispatch, state }) => ...@@ -139,5 +143,9 @@ export const expandAllDiscussions = ({ dispatch, state }) =>
dispatch('expandDiscussion', { discussionId: draft.discussion_id }, { root: true }); dispatch('expandDiscussion', { discussionId: draft.discussion_id }, { root: true });
}); });
export const toggleResolveDiscussion = ({ commit }, draftId) => {
commit(types.TOGGLE_RESOLVE_DISCUSSION, draftId);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {}; export default () => {};
...@@ -19,3 +19,5 @@ export const RECEIVE_DRAFT_UPDATE_SUCCESS = 'RECEIVE_DRAFT_UPDATE_SUCCESS'; ...@@ -19,3 +19,5 @@ export const RECEIVE_DRAFT_UPDATE_SUCCESS = 'RECEIVE_DRAFT_UPDATE_SUCCESS';
export const OPEN_REVIEW_DROPDOWN = 'OPEN_REVIEW_DROPDOWN'; export const OPEN_REVIEW_DROPDOWN = 'OPEN_REVIEW_DROPDOWN';
export const CLOSE_REVIEW_DROPDOWN = 'CLOSE_REVIEW_DROPDOWN'; export const CLOSE_REVIEW_DROPDOWN = 'CLOSE_REVIEW_DROPDOWN';
export const TOGGLE_RESOLVE_DISCUSSION = 'TOGGLE_RESOLVE_DISCUSSION';
...@@ -70,4 +70,16 @@ export default { ...@@ -70,4 +70,16 @@ export default {
[types.CLOSE_REVIEW_DROPDOWN](state) { [types.CLOSE_REVIEW_DROPDOWN](state) {
state.showPreviewDropdown = false; state.showPreviewDropdown = false;
}, },
[types.TOGGLE_RESOLVE_DISCUSSION](state, draftId) {
state.drafts = state.drafts.map(draft => {
if (draft.id === draftId) {
return {
...draft,
resolve_discussion: !draft.resolve_discussion,
};
}
return draft;
});
},
}; };
...@@ -47,37 +47,6 @@ button[disabled] { ...@@ -47,37 +47,6 @@ button[disabled] {
} }
} }
.draft-note-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.draft-note-resolution {
padding: 0 $gl-padding;
line-height: 1;
font-size: $label-font-size;
color: $theme-gray-700;
flex-grow: 1;
svg {
vertical-align: text-bottom;
display: inline-block;
}
.is-resolving-discussion & {
svg {
color: $green-600;
}
}
.is-unresolving-discussion & {
svg {
color: $gray-darkest;
}
}
}
.draft-pending-label { .draft-pending-label {
background: $orange-600; background: $orange-600;
color: $white-light; color: $white-light;
...@@ -88,14 +57,10 @@ button[disabled] { ...@@ -88,14 +57,10 @@ button[disabled] {
.diff-file { .diff-file {
.notes .note { .notes .note {
&.draft-note { &.draft-note {
margin: $gl-padding-8 0 $gl-padding; margin: 0 0 $gl-padding;
padding: 0; padding: 0;
border: 0; border: 0;
.note-actions {
margin-top: -26px;
}
&.is-editing { &.is-editing {
margin-bottom: 0; margin-bottom: 0;
} }
......
...@@ -35,58 +35,13 @@ describe('Batch comments draft note component', () => { ...@@ -35,58 +35,13 @@ describe('Batch comments draft note component', () => {
describe('in discussion', () => { describe('in discussion', () => {
beforeEach(done => { beforeEach(done => {
vm.draft.discussion_id = 123; vm.draft.discussion_id = '123';
vm.$nextTick(done); vm.$nextTick(done);
}); });
it('renders resolution status', () => { it('renders resolution status', () => {
expect(vm.$el.querySelector('.draft-note-resolution')).not.toBe(null); expect(vm.$el.querySelector('.line-resolve-btn')).not.toBe(null);
});
describe('resolvedStatusMessage', () => {
describe('resolve discussion', () => {
it('return will be resolved text', () => {
vm.draft.resolve_discussion = true;
expect(vm.resolvedStatusMessage).toBe('Discussion will be resolved.');
});
it('return will be stays resolved text', () => {
spyOnProperty(vm, 'isDiscussionResolved').and.returnValue(() => true);
vm.draft.resolve_discussion = true;
expect(vm.resolvedStatusMessage).toBe('Discussion stays resolved.');
});
});
describe('unresolve discussion', () => {
it('return will be stays unresolved text', () => {
expect(vm.resolvedStatusMessage).toBe('Discussion stays unresolved.');
});
it('return will be unresolved text', () => {
spyOnProperty(vm, 'isDiscussionResolved').and.returnValue(() => true);
vm.$forceUpdate();
expect(vm.resolvedStatusMessage).toBe('Discussion stays unresolved.');
});
});
it('adds resolving class to element', done => {
vm.draft.resolve_discussion = true;
vm.$nextTick(() => {
expect(vm.$el.classList).toContain('is-resolving-discussion');
done();
});
});
it('adds unresolving class to element', () => {
expect(vm.$el.classList).toContain('is-unresolving-discussion');
});
}); });
}); });
...@@ -121,6 +76,7 @@ describe('Batch comments draft note component', () => { ...@@ -121,6 +76,7 @@ describe('Batch comments draft note component', () => {
expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/updateDraft', { expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/updateDraft', {
note: draft, note: draft,
noteText: 'a', noteText: 'a',
resolveDiscussion: false,
callback: jasmine.any(Function), callback: jasmine.any(Function),
}); });
}) })
......
...@@ -5202,16 +5202,16 @@ msgstr "" ...@@ -5202,16 +5202,16 @@ msgstr ""
msgid "MergeRequests|An error occurred while saving the draft comment." msgid "MergeRequests|An error occurred while saving the draft comment."
msgstr "" msgstr ""
msgid "MergeRequests|Discussion stays resolved." msgid "MergeRequests|Discussion stays resolved"
msgstr "" msgstr ""
msgid "MergeRequests|Discussion stays unresolved." msgid "MergeRequests|Discussion stays unresolved"
msgstr "" msgstr ""
msgid "MergeRequests|Discussion will be resolved." msgid "MergeRequests|Discussion will be resolved"
msgstr "" msgstr ""
msgid "MergeRequests|Discussion will be unresolved." msgid "MergeRequests|Discussion will be unresolved"
msgstr "" msgstr ""
msgid "MergeRequests|Resolve this discussion in a new issue" msgid "MergeRequests|Resolve this discussion in a new issue"
......
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