summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/notes/components/comment_form.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/notes/components/comment_form.vue')
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue550
1 files changed, 282 insertions, 268 deletions
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index b85c1a6ad72..90dcafd75b7 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -1,297 +1,311 @@
<script>
- import { mapActions, mapGetters } from 'vuex';
- import _ from 'underscore';
- import Autosize from 'autosize';
- import { __, sprintf } from '~/locale';
- import Flash from '../../flash';
- import Autosave from '../../autosave';
- import TaskList from '../../task_list';
- import { capitalizeFirstCharacter, convertToCamelCase } from '../../lib/utils/text_utility';
- import * as constants from '../constants';
- import eventHub from '../event_hub';
- import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
- import markdownField from '../../vue_shared/components/markdown/field.vue';
- import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
- import loadingButton from '../../vue_shared/components/loading_button.vue';
- import noteSignedOutWidget from './note_signed_out_widget.vue';
- import discussionLockedWidget from './discussion_locked_widget.vue';
- import issuableStateMixin from '../mixins/issuable_state';
+import $ from 'jquery';
+import { mapActions, mapGetters, mapState } from 'vuex';
+import _ from 'underscore';
+import Autosize from 'autosize';
+import { __, sprintf } from '~/locale';
+import Flash from '../../flash';
+import Autosave from '../../autosave';
+import TaskList from '../../task_list';
+import {
+ capitalizeFirstCharacter,
+ convertToCamelCase,
+} from '../../lib/utils/text_utility';
+import * as constants from '../constants';
+import eventHub from '../event_hub';
+import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
+import markdownField from '../../vue_shared/components/markdown/field.vue';
+import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import loadingButton from '../../vue_shared/components/loading_button.vue';
+import noteSignedOutWidget from './note_signed_out_widget.vue';
+import discussionLockedWidget from './discussion_locked_widget.vue';
+import issuableStateMixin from '../mixins/issuable_state';
- export default {
- name: 'CommentForm',
- components: {
- issueWarning,
- noteSignedOutWidget,
- discussionLockedWidget,
- markdownField,
- userAvatarLink,
- loadingButton,
+export default {
+ name: 'CommentForm',
+ components: {
+ issueWarning,
+ noteSignedOutWidget,
+ discussionLockedWidget,
+ markdownField,
+ userAvatarLink,
+ loadingButton,
+ },
+ mixins: [issuableStateMixin],
+ props: {
+ noteableType: {
+ type: String,
+ required: true,
},
- mixins: [
- issuableStateMixin,
- ],
- props: {
- noteableType: {
- type: String,
- required: true,
- },
+ },
+ data() {
+ return {
+ note: '',
+ noteType: constants.COMMENT,
+ isSubmitting: false,
+ isSubmitButtonDisabled: true,
+ };
+ },
+ computed: {
+ ...mapGetters([
+ 'getCurrentUserLastNote',
+ 'getUserData',
+ 'getNoteableData',
+ 'getNotesData',
+ 'openState',
+ ]),
+ ...mapState(['isToggleStateButtonLoading']),
+ noteableDisplayName() {
+ return this.noteableType.replace(/_/g, ' ');
},
- data() {
- return {
- note: '',
- noteType: constants.COMMENT,
- isSubmitting: false,
- isSubmitButtonDisabled: true,
- };
+ isLoggedIn() {
+ return this.getUserData.id;
+ },
+ commentButtonTitle() {
+ return this.noteType === constants.COMMENT
+ ? 'Comment'
+ : 'Start discussion';
+ },
+ isOpen() {
+ return (
+ this.openState === constants.OPENED ||
+ this.openState === constants.REOPENED
+ );
},
- computed: {
- ...mapGetters([
- 'getCurrentUserLastNote',
- 'getUserData',
- 'getNoteableData',
- 'getNotesData',
- 'openState',
- ]),
- noteableDisplayName() {
- return this.noteableType.replace(/_/g, ' ');
- },
- isLoggedIn() {
- return this.getUserData.id;
- },
- commentButtonTitle() {
- return this.noteType === constants.COMMENT ? 'Comment' : 'Start discussion';
- },
- isOpen() {
- return this.openState === constants.OPENED || this.openState === constants.REOPENED;
- },
- canCreateNote() {
- return this.getNoteableData.current_user.can_create_note;
- },
- issueActionButtonTitle() {
- const openOrClose = this.isOpen ? 'close' : 'reopen';
+ canCreateNote() {
+ return this.getNoteableData.current_user.can_create_note;
+ },
+ issueActionButtonTitle() {
+ const openOrClose = this.isOpen ? 'close' : 'reopen';
- if (this.note.length) {
- return sprintf(
- __('%{actionText} & %{openOrClose} %{noteable}'),
- {
- actionText: this.commentButtonTitle,
- openOrClose,
- noteable: this.noteableDisplayName,
- },
- );
- }
+ if (this.note.length) {
+ return sprintf(__('%{actionText} & %{openOrClose} %{noteable}'), {
+ actionText: this.commentButtonTitle,
+ openOrClose,
+ noteable: this.noteableDisplayName,
+ });
+ }
- return sprintf(
- __('%{openOrClose} %{noteable}'),
- {
- openOrClose: capitalizeFirstCharacter(openOrClose),
- noteable: this.noteableDisplayName,
- },
- );
- },
- actionButtonClassNames() {
- return {
- 'btn-reopen': !this.isOpen,
- 'btn-close': this.isOpen,
- 'js-note-target-close': this.isOpen,
- 'js-note-target-reopen': !this.isOpen,
- };
- },
- markdownDocsPath() {
- return this.getNotesData.markdownDocsPath;
- },
- quickActionsDocsPath() {
- return this.getNotesData.quickActionsDocsPath;
- },
- markdownPreviewPath() {
- return this.getNoteableData.preview_note_path;
- },
- author() {
- return this.getUserData;
- },
- canUpdateIssue() {
- return this.getNoteableData.current_user.can_update;
- },
- endpoint() {
- return this.getNoteableData.create_note_path;
- },
+ return sprintf(__('%{openOrClose} %{noteable}'), {
+ openOrClose: capitalizeFirstCharacter(openOrClose),
+ noteable: this.noteableDisplayName,
+ });
},
- watch: {
- note(newNote) {
- this.setIsSubmitButtonDisabled(newNote, this.isSubmitting);
- },
- isSubmitting(newValue) {
- this.setIsSubmitButtonDisabled(this.note, newValue);
- },
+ actionButtonClassNames() {
+ return {
+ 'btn-reopen': !this.isOpen,
+ 'btn-close': this.isOpen,
+ 'js-note-target-close': this.isOpen,
+ 'js-note-target-reopen': !this.isOpen,
+ };
},
- mounted() {
- // jQuery is needed here because it is a custom event being dispatched with jQuery.
- $(document).on('issuable:change', (e, isClosed) => {
- this.toggleIssueLocalState(isClosed ? constants.CLOSED : constants.REOPENED);
- });
+ markdownDocsPath() {
+ return this.getNotesData.markdownDocsPath;
+ },
+ quickActionsDocsPath() {
+ return this.getNotesData.quickActionsDocsPath;
+ },
+ markdownPreviewPath() {
+ return this.getNoteableData.preview_note_path;
+ },
+ author() {
+ return this.getUserData;
+ },
+ canUpdateIssue() {
+ return this.getNoteableData.current_user.can_update;
+ },
+ endpoint() {
+ return this.getNoteableData.create_note_path;
+ },
+ },
+ watch: {
+ note(newNote) {
+ this.setIsSubmitButtonDisabled(newNote, this.isSubmitting);
+ },
+ isSubmitting(newValue) {
+ this.setIsSubmitButtonDisabled(this.note, newValue);
+ },
+ },
+ mounted() {
+ // jQuery is needed here because it is a custom event being dispatched with jQuery.
+ $(document).on('issuable:change', (e, isClosed) => {
+ this.toggleIssueLocalState(
+ isClosed ? constants.CLOSED : constants.REOPENED,
+ );
+ });
- this.initAutoSave();
- this.initTaskList();
+ this.initAutoSave();
+ this.initTaskList();
+ },
+ methods: {
+ ...mapActions([
+ 'saveNote',
+ 'stopPolling',
+ 'restartPolling',
+ 'removePlaceholderNotes',
+ 'closeIssue',
+ 'reopenIssue',
+ 'toggleIssueLocalState',
+ 'toggleStateButtonLoading',
+ ]),
+ setIsSubmitButtonDisabled(note, isSubmitting) {
+ if (!_.isEmpty(note) && !isSubmitting) {
+ this.isSubmitButtonDisabled = false;
+ } else {
+ this.isSubmitButtonDisabled = true;
+ }
},
- methods: {
- ...mapActions([
- 'saveNote',
- 'stopPolling',
- 'restartPolling',
- 'removePlaceholderNotes',
- 'closeIssue',
- 'reopenIssue',
- 'toggleIssueLocalState',
- ]),
- setIsSubmitButtonDisabled(note, isSubmitting) {
- if (!_.isEmpty(note) && !isSubmitting) {
- this.isSubmitButtonDisabled = false;
- } else {
- this.isSubmitButtonDisabled = true;
- }
- },
- handleSave(withIssueAction) {
- this.isSubmitting = true;
+ handleSave(withIssueAction) {
+ this.isSubmitting = true;
- if (this.note.length) {
- const noteData = {
- endpoint: this.endpoint,
- flashContainer: this.$el,
- data: {
- note: {
- noteable_type: this.noteableType,
- noteable_id: this.getNoteableData.id,
- note: this.note,
- },
+ if (this.note.length) {
+ const noteData = {
+ endpoint: this.endpoint,
+ flashContainer: this.$el,
+ data: {
+ note: {
+ noteable_type: this.noteableType,
+ noteable_id: this.getNoteableData.id,
+ note: this.note,
},
- };
+ },
+ };
- if (this.noteType === constants.DISCUSSION) {
- noteData.data.note.type = constants.DISCUSSION_NOTE;
- }
- this.note = ''; // Empty textarea while being requested. Repopulate in catch
- this.resizeTextarea();
- this.stopPolling();
+ if (this.noteType === constants.DISCUSSION) {
+ noteData.data.note.type = constants.DISCUSSION_NOTE;
+ }
- this.saveNote(noteData)
- .then((res) => {
- this.isSubmitting = false;
- this.restartPolling();
+ this.note = ''; // Empty textarea while being requested. Repopulate in catch
+ this.resizeTextarea();
+ this.stopPolling();
- if (res.errors) {
- if (res.errors.commands_only) {
- this.discard();
- } else {
- Flash(
- 'Something went wrong while adding your comment. Please try again.',
- 'alert',
- this.$refs.commentForm,
- );
- }
- } else {
+ this.saveNote(noteData)
+ .then(res => {
+ this.enableButton();
+ this.restartPolling();
+
+ if (res.errors) {
+ if (res.errors.commands_only) {
this.discard();
+ } else {
+ Flash(
+ 'Something went wrong while adding your comment. Please try again.',
+ 'alert',
+ this.$refs.commentForm,
+ );
}
+ } else {
+ this.discard();
+ }
- if (withIssueAction) {
- this.toggleIssueState();
- }
- })
- .catch(() => {
- this.isSubmitting = false;
- this.discard(false);
- const msg =
- `Your comment could not be submitted!
+ if (withIssueAction) {
+ this.toggleIssueState();
+ }
+ })
+ .catch(() => {
+ this.enableButton();
+ this.discard(false);
+ const msg = `Your comment could not be submitted!
Please check your network connection and try again.`;
- Flash(msg, 'alert', this.$el);
- this.note = noteData.data.note.note; // Restore textarea content.
- this.removePlaceholderNotes();
- });
- } else {
- this.toggleIssueState();
- }
- },
- enableButton() {
- this.isSubmitting = false;
- },
- toggleIssueState() {
- if (this.isOpen) {
- this.closeIssue()
- .then(() => this.enableButton())
- .catch(() => {
- this.enableButton();
- Flash(
- sprintf(
- __('Something went wrong while closing the %{issuable}. Please try again later'),
- { issuable: this.noteableDisplayName },
+ Flash(msg, 'alert', this.$el);
+ this.note = noteData.data.note.note; // Restore textarea content.
+ this.removePlaceholderNotes();
+ });
+ } else {
+ this.toggleIssueState();
+ }
+ },
+ enableButton() {
+ this.isSubmitting = false;
+ },
+ toggleIssueState() {
+ if (this.isOpen) {
+ this.closeIssue()
+ .then(() => this.enableButton())
+ .catch(() => {
+ this.enableButton();
+ this.toggleStateButtonLoading(false);
+ Flash(
+ sprintf(
+ __(
+ 'Something went wrong while closing the %{issuable}. Please try again later',
),
- );
- });
- } else {
- this.reopenIssue()
- .then(() => this.enableButton())
- .catch(() => {
- this.enableButton();
- Flash(
- sprintf(
- __('Something went wrong while reopening the %{issuable}. Please try again later'),
- { issuable: this.noteableDisplayName },
+ { issuable: this.noteableDisplayName },
+ ),
+ );
+ });
+ } else {
+ this.reopenIssue()
+ .then(() => this.enableButton())
+ .catch(() => {
+ this.enableButton();
+ this.toggleStateButtonLoading(false);
+ Flash(
+ sprintf(
+ __(
+ 'Something went wrong while reopening the %{issuable}. Please try again later',
),
- );
- });
- }
- },
- discard(shouldClear = true) {
- // `blur` is needed to clear slash commands autocomplete cache if event fired.
- // `focus` is needed to remain cursor in the textarea.
- this.$refs.textarea.blur();
- this.$refs.textarea.focus();
+ { issuable: this.noteableDisplayName },
+ ),
+ );
+ });
+ }
+ },
+ discard(shouldClear = true) {
+ // `blur` is needed to clear slash commands autocomplete cache if event fired.
+ // `focus` is needed to remain cursor in the textarea.
+ this.$refs.textarea.blur();
+ this.$refs.textarea.focus();
- if (shouldClear) {
- this.note = '';
- this.resizeTextarea();
- this.$refs.markdownField.previewMarkdown = false;
- }
+ if (shouldClear) {
+ this.note = '';
+ this.resizeTextarea();
+ this.$refs.markdownField.previewMarkdown = false;
+ }
- this.autosave.reset();
- },
- setNoteType(type) {
- this.noteType = type;
- },
- editCurrentUserLastNote() {
- if (this.note === '') {
- const lastNote = this.getCurrentUserLastNote;
+ this.autosave.reset();
+ },
+ setNoteType(type) {
+ this.noteType = type;
+ },
+ editCurrentUserLastNote() {
+ if (this.note === '') {
+ const lastNote = this.getCurrentUserLastNote;
- if (lastNote) {
- eventHub.$emit('enterEditMode', {
- noteId: lastNote.id,
- });
- }
+ if (lastNote) {
+ eventHub.$emit('enterEditMode', {
+ noteId: lastNote.id,
+ });
}
- },
- initAutoSave() {
- if (this.isLoggedIn) {
- const noteableType = capitalizeFirstCharacter(convertToCamelCase(this.noteableType));
+ }
+ },
+ initAutoSave() {
+ if (this.isLoggedIn) {
+ const noteableType = capitalizeFirstCharacter(
+ convertToCamelCase(this.noteableType),
+ );
- this.autosave = new Autosave(
- $(this.$refs.textarea),
- ['Note', noteableType, this.getNoteableData.id],
- );
- }
- },
- initTaskList() {
- return new TaskList({
- dataType: 'note',
- fieldName: 'note',
- selector: '.notes',
- });
- },
- resizeTextarea() {
- this.$nextTick(() => {
- Autosize.update(this.$refs.textarea);
- });
- },
+ this.autosave = new Autosave($(this.$refs.textarea), [
+ 'Note',
+ noteableType,
+ this.getNoteableData.id,
+ ]);
+ }
+ },
+ initTaskList() {
+ return new TaskList({
+ dataType: 'note',
+ fieldName: 'note',
+ selector: '.notes',
+ });
},
- };
+ resizeTextarea() {
+ this.$nextTick(() => {
+ Autosize.update(this.$refs.textarea);
+ });
+ },
+ },
+};
</script>
<template>
@@ -418,13 +432,13 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
<loading-button
v-if="canUpdateIssue"
- :loading="isSubmitting"
+ :loading="isToggleStateButtonLoading"
@click="handleSave(true)"
:container-class="[
actionButtonClassNames,
'btn btn-comment btn-comment-and-close js-action-button'
]"
- :disabled="isSubmitting"
+ :disabled="isToggleStateButtonLoading || isSubmitting"
:label="issueActionButtonTitle"
/>