diff options
Diffstat (limited to 'app/assets/javascripts/notes/components')
6 files changed, 61 insertions, 126 deletions
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 9cc53a320b8..0363173f912 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -3,23 +3,23 @@ import $ from 'jquery'; import { mapActions, mapGetters, mapState } from 'vuex'; import { isEmpty } from 'lodash'; import Autosize from 'autosize'; -import { GlAlert, GlIntersperse, GlLink, GlSprintf, GlButton, GlIcon } from '@gitlab/ui'; +import { GlButton, GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; -import { deprecatedCreateFlash as Flash } from '../../flash'; -import Autosave from '../../autosave'; +import { deprecatedCreateFlash as Flash } from '~/flash'; +import Autosave from '~/autosave'; import { capitalizeFirstCharacter, convertToCamelCase, splitCamelCase, slugifyWithUnderscore, -} from '../../lib/utils/text_utility'; +} from '~/lib/utils/text_utility'; import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; import * as constants from '../constants'; import eventHub from '../event_hub'; -import NoteableWarning from '../../vue_shared/components/notes/noteable_warning.vue'; -import markdownField from '../../vue_shared/components/markdown/field.vue'; -import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; +import NoteableWarning from '~/vue_shared/components/notes/noteable_warning.vue'; +import markdownField from '~/vue_shared/components/markdown/field.vue'; +import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import noteSignedOutWidget from './note_signed_out_widget.vue'; import discussionLockedWidget from './discussion_locked_widget.vue'; import issuableStateMixin from '../mixins/issuable_state'; @@ -34,10 +34,6 @@ export default { userAvatarLink, GlButton, TimelineEntryItem, - GlAlert, - GlIntersperse, - GlLink, - GlSprintf, GlIcon, }, mixins: [issuableStateMixin], @@ -63,9 +59,8 @@ export default { 'getNoteableDataByProp', 'getNotesData', 'openState', - 'getBlockedByIssues', ]), - ...mapState(['isToggleStateButtonLoading', 'isToggleBlockedIssueWarning']), + ...mapState(['isToggleStateButtonLoading']), noteableDisplayName() { return splitCamelCase(this.noteableType).toLowerCase(); }, @@ -143,7 +138,7 @@ export default { ? __('merge request') : __('issue'); }, - isIssueType() { + isIssue() { return this.noteableDisplayName === constants.ISSUE_NOTEABLE_TYPE; }, trackingLabel() { @@ -172,11 +167,9 @@ export default { 'stopPolling', 'restartPolling', 'removePlaceholderNotes', - 'closeIssue', - 'reopenIssue', + 'closeIssuable', + 'reopenIssuable', 'toggleIssueLocalState', - 'toggleStateButtonLoading', - 'toggleBlockedIssueWarning', ]), setIsSubmitButtonDisabled(note, isSubmitting) { if (!isEmpty(note) && !isSubmitting) { @@ -186,8 +179,6 @@ export default { } }, handleSave(withIssueAction) { - this.isSubmitting = true; - if (this.note.length) { const noteData = { endpoint: this.endpoint, @@ -210,9 +201,10 @@ export default { this.resizeTextarea(); this.stopPolling(); + this.isSubmitting = true; + this.saveNote(noteData) .then(() => { - this.enableButton(); this.restartPolling(); this.discard(); @@ -221,7 +213,6 @@ export default { } }) .catch(() => { - this.enableButton(); this.discard(false); const msg = __( 'Your comment could not be submitted! Please check your network connection and try again.', @@ -229,64 +220,27 @@ export default { Flash(msg, 'alert', this.$el); this.note = noteData.data.note.note; // Restore textarea content. this.removePlaceholderNotes(); + }) + .finally(() => { + this.isSubmitting = false; }); } else { this.toggleIssueState(); } }, - enableButton() { - this.isSubmitting = false; - }, toggleIssueState() { - if ( - this.noteableType.toLowerCase() === constants.ISSUE_NOTEABLE_TYPE && - this.isOpen && - this.getBlockedByIssues && - this.getBlockedByIssues.length > 0 - ) { - this.toggleBlockedIssueWarning(true); + if (this.isIssue) { + // We want to invoke the close/reopen logic in the issue header + // since that is where the blocked-by issues modal logic is also defined + eventHub.$emit('toggle.issuable.state'); return; } - if (this.isOpen) { - this.forceCloseIssue(); - } else { - this.reopenIssue() - .then(() => { - this.enableButton(); - refreshUserMergeRequestCounts(); - }) - .catch(({ data }) => { - this.enableButton(); - this.toggleStateButtonLoading(false); - let errorMessage = sprintf( - __('Something went wrong while reopening the %{issuable}. Please try again later'), - { issuable: this.noteableDisplayName }, - ); - if (data) { - errorMessage = Object.values(data).join('\n'); - } + const toggleState = this.isOpen ? this.closeIssuable : this.reopenIssuable; - Flash(errorMessage); - }); - } - }, - forceCloseIssue() { - this.closeIssue() - .then(() => { - this.enableButton(); - refreshUserMergeRequestCounts(); - }) - .catch(() => { - this.enableButton(); - this.toggleStateButtonLoading(false); - Flash( - sprintf( - __('Something went wrong while closing the %{issuable}. Please try again later'), - { issuable: this.noteableDisplayName }, - ), - ); - }); + toggleState() + .then(refreshUserMergeRequestCounts) + .catch(() => Flash(constants.toggleStateErrorMessage[this.noteableType][this.openState])); }, discard(shouldClear = true) { // `blur` is needed to clear slash commands autocomplete cache if event fired. @@ -384,6 +338,7 @@ export default { name="note[note]" class="note-textarea js-vue-comment-form js-note-text js-gfm-input js-autosize markdown-area" data-qa-selector="comment_field" + data-testid="comment-field" data-supports-quick-actions="true" :aria-label="__('Description')" :placeholder="__('Write a comment or drag your files hereā¦')" @@ -392,36 +347,7 @@ export default { @keydown.ctrl.enter="handleSave()" ></textarea> </markdown-field> - <gl-alert - v-if="isToggleBlockedIssueWarning" - class="gl-mt-5" - :title="__('Are you sure you want to close this blocked issue?')" - :primary-button-text="__('Yes, close issue')" - :secondary-button-text="__('Cancel')" - variant="warning" - :dismissible="false" - @primaryAction="toggleBlockedIssueWarning(false) && forceCloseIssue()" - @secondaryAction="toggleBlockedIssueWarning(false) && enableButton()" - > - <p> - <gl-sprintf - :message=" - __('This issue is currently blocked by the following issues: %{issues}.') - " - > - <template #issues> - <gl-intersperse> - <gl-link - v-for="blockingIssue in getBlockedByIssues" - :key="blockingIssue.web_url" - :href="blockingIssue.web_url" - >#{{ blockingIssue.iid }}</gl-link - > - </gl-intersperse> - </template> - </gl-sprintf> - </p> - </gl-alert> + <div class="note-form-actions"> <div class="btn-group gl-mr-3 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" @@ -430,6 +356,7 @@ export default { :disabled="isSubmitButtonDisabled" class="js-comment-button js-comment-submit-button" data-qa-selector="comment_button" + data-testid="comment-button" type="submit" category="primary" variant="success" @@ -488,15 +415,13 @@ export default { </div> <gl-button - v-if="canToggleIssueState && !isToggleBlockedIssueWarning" + v-if="canToggleIssueState" :loading="isToggleStateButtonLoading" category="secondary" :variant="buttonVariant" - :class="[ - actionButtonClassNames, - 'btn-comment btn-comment-and-close js-action-button', - ]" - :disabled="isToggleStateButtonLoading || isSubmitting" + :class="[actionButtonClassNames, 'btn-comment btn-comment-and-close']" + :disabled="isSubmitting" + data-testid="close-reopen-button" @click="handleSave(true)" >{{ issueActionButtonTitle }}</gl-button > diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index 91cf682943e..1580c94658a 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -7,7 +7,7 @@ import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue'; import { getDiffMode } from '~/diffs/store/utils'; import { diffViewerModes } from '~/ide/constants'; -import { isCollapsed } from '../../diffs/diff_file'; +import { isCollapsed } from '../../diffs/utils/diff_file'; const FIRST_CHAR_REGEX = /^(\+|-| )/; @@ -131,14 +131,18 @@ export default { :file-hash="discussion.diff_file.file_hash" :project-path="projectPath" > - <image-diff-overlay - slot="image-overlay" - :discussions="discussion" - :file-hash="discussion.diff_file.file_hash" - :show-comment-icon="true" - :should-toggle-discussion="false" - badge-class="image-comment-badge" - /> + <template #image-overlay="{ renderedWidth, renderedHeight }"> + <image-diff-overlay + v-if="renderedWidth" + :rendered-width="renderedWidth" + :rendered-height="renderedHeight" + :discussions="discussion" + :file-hash="discussion.diff_file.file_hash" + :show-comment-icon="true" + :should-toggle-discussion="false" + badge-class="image-comment-badge gl-text-gray-500" + /> + </template> </diff-viewer> <slot></slot> </div> diff --git a/app/assets/javascripts/notes/components/multiline_comment_utils.js b/app/assets/javascripts/notes/components/multiline_comment_utils.js index dbae10c8f6c..2451400e980 100644 --- a/app/assets/javascripts/notes/components/multiline_comment_utils.js +++ b/app/assets/javascripts/notes/components/multiline_comment_utils.js @@ -103,9 +103,15 @@ export function getCommentedLines(selectedCommentPosition, diffLines) { }; } + const findLineCodeIndex = line => position => { + return [position.line_code, position.left?.line_code, position.right?.line_code].includes( + line.line_code, + ); + }; + const { start, end } = selectedCommentPosition; - const startLine = diffLines.findIndex(l => l.line_code === start.line_code); - const endLine = diffLines.findIndex(l => l.line_code === end.line_code); + const startLine = diffLines.findIndex(findLineCodeIndex(start)); + const endLine = diffLines.findIndex(findLineCodeIndex(end)); return { startLine, endLine }; } diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 43f17c5d65c..84769bfc7c8 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -422,7 +422,7 @@ export default { </button> <button v-if="discussion.resolvable" - class="btn btn-nr btn-default gl-mr-3 js-comment-resolve-button" + class="btn btn-default gl-mr-3 js-comment-resolve-button" @click.prevent="handleUpdate(true)" > {{ resolveButtonTitle }} diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue index cacf209ed81..17a995018d3 100644 --- a/app/assets/javascripts/notes/components/note_header.vue +++ b/app/assets/javascripts/notes/components/note_header.vue @@ -85,7 +85,10 @@ export default { }; }, authorStatus() { - return this.author.status_tooltip_html; + if (this.author?.show_status) { + return this.author.status_tooltip_html; + } + return false; }, authorIsBusy() { const { status } = this.author; @@ -142,7 +145,7 @@ export default { type="button" @click="handleToggle" > - <gl-icon ref="chevronIcon" :name="toggleChevronIconName" aria-hidden="true" /> + <gl-icon ref="chevronIcon" :name="toggleChevronIconName" /> {{ __('Toggle thread') }} </button> </div> diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 9be53fe60f2..5073922e4a4 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -23,6 +23,7 @@ import { commentLineOptions, formatLineRange, } from './multiline_comment_utils'; +import { INLINE_DIFF_LINES_KEY } from '~/diffs/constants'; export default { name: 'NoteableNote', @@ -169,12 +170,8 @@ export default { return this.line && this.startLineNumber !== this.endLineNumber; }, commentLineOptions() { - const sideA = this.line.type === 'new' ? 'right' : 'left'; - const sideB = sideA === 'left' ? 'right' : 'left'; - const lines = this.diffFile.highlighted_diff_lines.length - ? this.diffFile.highlighted_diff_lines - : this.diffFile.parallel_diff_lines.map(l => l[sideA] || l[sideB]); - return commentLineOptions(lines, this.commentLineStart, this.line.line_code, sideA); + const lines = this.diffFile[INLINE_DIFF_LINES_KEY].length; + return commentLineOptions(lines, this.commentLineStart, this.line.line_code); }, diffFile() { if (this.commentLineStart.line_code) { |