2017-06-13 13:01:59 -04:00
|
|
|
<script>
|
2018-03-16 16:16:21 -04:00
|
|
|
import $ from 'jquery';
|
2021-10-27 05:12:12 -04:00
|
|
|
import { GlSafeHtmlDirective } from '@gitlab/ui';
|
2021-02-09 16:09:19 -05:00
|
|
|
import { escape } from 'lodash';
|
2021-02-14 13:09:20 -05:00
|
|
|
import { mapActions, mapGetters, mapState } from 'vuex';
|
2021-02-09 16:09:19 -05:00
|
|
|
|
2022-05-13 11:07:43 -04:00
|
|
|
import { __ } from '~/locale';
|
2019-09-11 12:47:19 -04:00
|
|
|
import '~/behaviors/markdown/render_gfm';
|
2021-02-01 10:08:56 -05:00
|
|
|
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
|
|
|
|
import autosave from '../mixins/autosave';
|
2022-06-06 08:08:32 -04:00
|
|
|
import { INTERNAL_NOTE_CLASSES } from '../constants';
|
2018-03-16 16:16:21 -04:00
|
|
|
import noteAttachment from './note_attachment.vue';
|
2021-02-14 13:09:20 -05:00
|
|
|
import noteAwardsList from './note_awards_list.vue';
|
|
|
|
import noteEditedText from './note_edited_text.vue';
|
2018-03-16 16:16:21 -04:00
|
|
|
import noteForm from './note_form.vue';
|
2017-06-13 22:13:38 -04:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
export default {
|
|
|
|
components: {
|
|
|
|
noteEditedText,
|
|
|
|
noteAwardsList,
|
|
|
|
noteAttachment,
|
|
|
|
noteForm,
|
2018-12-13 14:17:19 -05:00
|
|
|
Suggestions,
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
2021-10-27 05:12:12 -04:00
|
|
|
directives: {
|
|
|
|
SafeHtml: GlSafeHtmlDirective,
|
|
|
|
},
|
2020-06-01 02:08:21 -04:00
|
|
|
mixins: [autosave],
|
2018-03-16 16:16:21 -04:00
|
|
|
props: {
|
|
|
|
note: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
2018-01-04 19:18:35 -05:00
|
|
|
},
|
2018-12-13 14:17:19 -05:00
|
|
|
line: {
|
|
|
|
type: Object,
|
|
|
|
required: false,
|
|
|
|
default: null,
|
|
|
|
},
|
2021-02-09 16:09:19 -05:00
|
|
|
file: {
|
|
|
|
type: Object,
|
|
|
|
required: false,
|
|
|
|
default: null,
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
canEdit: {
|
|
|
|
type: Boolean,
|
|
|
|
required: true,
|
2017-06-13 13:01:59 -04:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
isEditing: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
2017-06-14 19:36:53 -04:00
|
|
|
},
|
2018-12-13 14:17:19 -05:00
|
|
|
helpPagePath: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: '',
|
|
|
|
},
|
2022-06-06 08:08:32 -04:00
|
|
|
isInternalNote: {
|
2022-05-24 08:09:04 -04:00
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
computed: {
|
2021-09-28 08:11:10 -04:00
|
|
|
...mapGetters(['getDiscussion', 'suggestionsCount', 'getSuggestionsFilePaths']),
|
2021-02-09 16:09:19 -05:00
|
|
|
...mapGetters('diffs', ['suggestionCommitMessage']),
|
2022-04-12 08:08:50 -04:00
|
|
|
...mapState({
|
|
|
|
batchSuggestionsInfo: (state) => state.notes.batchSuggestionsInfo,
|
|
|
|
failedToLoadMetadata: (state) => state.page.failedToLoadMetadata,
|
|
|
|
}),
|
2020-06-01 02:08:21 -04:00
|
|
|
discussion() {
|
|
|
|
if (!this.note.isDraft) return {};
|
|
|
|
|
|
|
|
return this.getDiscussion(this.note.discussion_id);
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
noteBody() {
|
|
|
|
return this.note.note;
|
|
|
|
},
|
2022-05-13 11:07:43 -04:00
|
|
|
saveButtonTitle() {
|
|
|
|
return this.note.confidential ? __('Save internal note') : __('Save comment');
|
|
|
|
},
|
2018-12-13 14:17:19 -05:00
|
|
|
hasSuggestion() {
|
|
|
|
return this.note.suggestions && this.note.suggestions.length;
|
|
|
|
},
|
|
|
|
lineType() {
|
|
|
|
return this.line ? this.line.type : null;
|
|
|
|
},
|
2021-02-09 16:09:19 -05:00
|
|
|
commitMessage() {
|
|
|
|
// Please see this issue comment for why these
|
|
|
|
// are hard-coded to 1:
|
|
|
|
// https://gitlab.com/gitlab-org/gitlab/-/issues/291027#note_468308022
|
2021-09-28 08:11:10 -04:00
|
|
|
const suggestionsCount = this.batchSuggestionsInfo.length || 1;
|
|
|
|
const batchFilePaths = this.getSuggestionsFilePaths();
|
|
|
|
const filePaths = batchFilePaths.length ? batchFilePaths : [this.file.file_path];
|
|
|
|
const filesCount = filePaths.length;
|
2021-02-09 16:09:19 -05:00
|
|
|
const suggestion = this.suggestionCommitMessage({
|
|
|
|
file_paths: filePaths.join(', '),
|
|
|
|
suggestions_count: suggestionsCount,
|
|
|
|
files_count: filesCount,
|
|
|
|
});
|
|
|
|
|
|
|
|
return escape(suggestion);
|
|
|
|
},
|
2022-06-06 08:08:32 -04:00
|
|
|
internalNoteContainerClasses() {
|
|
|
|
if (this.isInternalNote && !this.isEditing) {
|
|
|
|
return INTERNAL_NOTE_CLASSES;
|
2022-05-24 08:09:04 -04:00
|
|
|
}
|
|
|
|
return '';
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.renderGFM();
|
|
|
|
|
|
|
|
if (this.isEditing) {
|
2018-06-21 08:22:40 -04:00
|
|
|
this.initAutoSave(this.note);
|
2018-03-16 16:16:21 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
updated() {
|
|
|
|
this.renderGFM();
|
2017-08-21 15:16:41 -04:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
if (this.isEditing) {
|
|
|
|
if (!this.autosave) {
|
2018-06-21 08:22:40 -04:00
|
|
|
this.initAutoSave(this.note);
|
2018-03-16 16:16:21 -04:00
|
|
|
} else {
|
|
|
|
this.setAutoSave();
|
2017-08-03 14:27:33 -04:00
|
|
|
}
|
2018-03-16 16:16:21 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2020-06-08 20:08:47 -04:00
|
|
|
...mapActions([
|
|
|
|
'submitSuggestion',
|
|
|
|
'submitSuggestionBatch',
|
|
|
|
'addSuggestionInfoToBatch',
|
|
|
|
'removeSuggestionInfoFromBatch',
|
|
|
|
]),
|
2018-03-16 16:16:21 -04:00
|
|
|
renderGFM() {
|
|
|
|
$(this.$refs['note-body']).renderGFM();
|
2017-07-12 16:53:48 -04:00
|
|
|
},
|
2021-08-10 11:10:03 -04:00
|
|
|
handleFormUpdate(noteText, parentElement, callback, resolveDiscussion) {
|
|
|
|
this.$emit('handleFormUpdate', { noteText, parentElement, callback, resolveDiscussion });
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
formCancelHandler(shouldConfirm, isDirty) {
|
2021-08-10 11:10:03 -04:00
|
|
|
this.$emit('cancelForm', { shouldConfirm, isDirty });
|
2018-01-04 19:18:35 -05:00
|
|
|
},
|
2021-01-19 07:10:46 -05:00
|
|
|
applySuggestion({ suggestionId, flashContainer, callback = () => {}, message }) {
|
2018-12-13 14:17:19 -05:00
|
|
|
const { discussion_id: discussionId, id: noteId } = this.note;
|
|
|
|
|
2021-01-19 07:10:46 -05:00
|
|
|
return this.submitSuggestion({
|
|
|
|
discussionId,
|
|
|
|
noteId,
|
|
|
|
suggestionId,
|
|
|
|
flashContainer,
|
|
|
|
message,
|
|
|
|
}).then(callback);
|
2018-12-13 14:17:19 -05:00
|
|
|
},
|
2021-09-28 08:11:10 -04:00
|
|
|
applySuggestionBatch({ message, flashContainer }) {
|
|
|
|
return this.submitSuggestionBatch({ message, flashContainer });
|
2020-06-08 20:08:47 -04:00
|
|
|
},
|
|
|
|
addSuggestionToBatch(suggestionId) {
|
|
|
|
const { discussion_id: discussionId, id: noteId } = this.note;
|
|
|
|
|
|
|
|
this.addSuggestionInfoToBatch({ suggestionId, discussionId, noteId });
|
|
|
|
},
|
|
|
|
removeSuggestionFromBatch(suggestionId) {
|
|
|
|
this.removeSuggestionInfoFromBatch(suggestionId);
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
2021-10-27 05:12:12 -04:00
|
|
|
safeHtmlConfig: {
|
2021-12-13 10:12:59 -05:00
|
|
|
ADD_TAGS: ['use', 'gl-emoji', 'copy-code'],
|
2021-10-27 05:12:12 -04:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
};
|
2017-06-13 13:01:59 -04:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2022-05-24 08:09:04 -04:00
|
|
|
<div
|
|
|
|
ref="note-body"
|
|
|
|
:class="{
|
|
|
|
'js-task-list-container': canEdit,
|
|
|
|
}"
|
|
|
|
class="note-body"
|
|
|
|
>
|
2022-06-06 08:08:32 -04:00
|
|
|
<div :class="internalNoteContainerClasses" data-testid="note-internal-container">
|
2022-05-24 08:09:04 -04:00
|
|
|
<suggestions
|
|
|
|
v-if="hasSuggestion && !isEditing"
|
|
|
|
:suggestions="note.suggestions"
|
|
|
|
:suggestions-count="suggestionsCount"
|
|
|
|
:batch-suggestions-info="batchSuggestionsInfo"
|
|
|
|
:note-html="note.note_html"
|
|
|
|
:line-type="lineType"
|
|
|
|
:help-page-path="helpPagePath"
|
|
|
|
:default-commit-message="commitMessage"
|
|
|
|
:failed-to-load-metadata="failedToLoadMetadata"
|
|
|
|
@apply="applySuggestion"
|
|
|
|
@applyBatch="applySuggestionBatch"
|
|
|
|
@addToBatch="addSuggestionToBatch"
|
|
|
|
@removeFromBatch="removeSuggestionFromBatch"
|
|
|
|
/>
|
|
|
|
<div v-else v-safe-html:[$options.safeHtmlConfig]="note.note_html" class="note-text md"></div>
|
|
|
|
<note-form
|
|
|
|
v-if="isEditing"
|
|
|
|
ref="noteForm"
|
|
|
|
:note-body="noteBody"
|
|
|
|
:note-id="note.id"
|
|
|
|
:line="line"
|
|
|
|
:note="note"
|
|
|
|
:save-button-title="saveButtonTitle"
|
|
|
|
:help-page-path="helpPagePath"
|
|
|
|
:discussion="discussion"
|
|
|
|
:resolve-discussion="note.resolve_discussion"
|
|
|
|
@handleFormUpdate="handleFormUpdate"
|
|
|
|
@cancelForm="formCancelHandler"
|
|
|
|
/>
|
|
|
|
<!-- eslint-disable vue/no-mutating-props -->
|
|
|
|
<textarea
|
|
|
|
v-if="canEdit"
|
|
|
|
v-model="note.note"
|
|
|
|
:data-update-url="note.path"
|
|
|
|
class="hidden js-task-list-field"
|
|
|
|
dir="auto"
|
|
|
|
></textarea>
|
|
|
|
<!-- eslint-enable vue/no-mutating-props -->
|
|
|
|
<note-edited-text
|
|
|
|
v-if="note.last_edited_at"
|
|
|
|
:edited-at="note.last_edited_at"
|
|
|
|
:edited-by="note.last_edited_by"
|
|
|
|
action-text="Edited"
|
|
|
|
class="note_edited_ago"
|
|
|
|
/>
|
|
|
|
</div>
|
2017-12-04 11:19:07 -05:00
|
|
|
<note-awards-list
|
2018-10-06 13:16:40 -04:00
|
|
|
v-if="note.award_emoji && note.award_emoji.length"
|
2017-07-20 18:12:44 -04:00
|
|
|
:note-id="note.id"
|
|
|
|
:note-author-id="note.author.id"
|
2017-06-14 20:58:46 -04:00
|
|
|
:awards="note.award_emoji"
|
2017-07-28 07:53:51 -04:00
|
|
|
:toggle-award-path="note.toggle_award_path"
|
2018-04-06 14:19:37 -04:00
|
|
|
:can-award-emoji="note.current_user.can_award_emoji"
|
2018-01-04 19:18:35 -05:00
|
|
|
/>
|
2018-11-16 15:07:38 -05:00
|
|
|
<note-attachment v-if="note.attachment" :attachment="note.attachment" />
|
2017-06-13 13:01:59 -04:00
|
|
|
</div>
|
|
|
|
</template>
|