summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/notes/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/notes/components')
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue137
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue22
-rw-r--r--app/assets/javascripts/notes/components/multiline_comment_utils.js10
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue7
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue9
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) {