diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-15 00:09:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-15 00:09:09 +0300 |
commit | e30d680b42eff52d9eb2a79ff7ed40bd8bb88d21 (patch) | |
tree | b34a1a9e596281dc8ef8d5c88553e9cf79ab21d7 /app | |
parent | 844e3ef899c87d9e04cf8b89c8690afb013ba425 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
5 files changed, 128 insertions, 57 deletions
diff --git a/app/assets/javascripts/batch_comments/components/preview_item.vue b/app/assets/javascripts/batch_comments/components/preview_item.vue index 756bcfdb3d0..753608cf6f7 100644 --- a/app/assets/javascripts/batch_comments/components/preview_item.vue +++ b/app/assets/javascripts/batch_comments/components/preview_item.vue @@ -41,13 +41,17 @@ export default { titleText() { const file = this.discussion ? this.discussion.diff_file : this.draft; - if (file) { + if (file?.file_path) { return file.file_path; } - return sprintf(__("%{authorsName}'s thread"), { - authorsName: this.discussion.notes.find((note) => !note.system).author.name, - }); + if (this.discussion) { + return sprintf(__("%{authorsName}'s thread"), { + authorsName: this.discussion.notes.find((note) => !note.system).author.name, + }); + } + + return __('Your new comment'); }, linePosition() { if (this.position?.position_type === IMAGE_DIFF_POSITION_TYPE) { @@ -94,7 +98,7 @@ export default { <span class="review-preview-item-header"> <gl-icon class="flex-shrink-0" :name="iconName" /> <span class="bold text-nowrap gl-align-items-center"> - <span class="review-preview-item-header-text block-truncated"> + <span class="review-preview-item-header-text block-truncated gl-ml-2"> {{ titleText }} </span> <template v-if="showLinePosition"> diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index a47501801b4..79d8ce78329 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -84,6 +84,7 @@ export default { 'getNoteableDataByProp', 'getNotesData', 'openState', + 'hasDrafts', ]), ...mapState(['isToggleStateButtonLoading']), isNoteTypeComment() { @@ -171,6 +172,9 @@ export default { endpoint() { return this.getNoteableData.create_note_path; }, + draftEndpoint() { + return this.getNotesData.draftsPath; + }, issuableTypeTitle() { return this.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE ? this.$options.i18n.mergeRequest @@ -214,12 +218,15 @@ export default { this.errors = [this.$options.i18n.GENERIC_UNSUBMITTABLE_NETWORK]; } }, - handleSave(withIssueAction) { + handleSaveDraft() { + this.handleSave({ isDraft: true }); + }, + handleSave({ withIssueAction = false, isDraft = false } = {}) { this.errors = []; if (this.note.length) { const noteData = { - endpoint: this.endpoint, + endpoint: isDraft ? this.draftEndpoint : this.endpoint, data: { note: { noteable_type: this.noteableType, @@ -229,6 +236,7 @@ export default { }, merge_request_diff_head_sha: this.getNoteableData.diff_head_sha, }, + isDraft, }; if (this.noteType === constants.DISCUSSION) { @@ -392,62 +400,82 @@ export default { </markdown-field> </comment-field-layout> <div class="note-form-actions"> - <gl-form-checkbox - v-if="confidentialNotesEnabled && canSetConfidential" - v-model="noteIsConfidential" - class="gl-mb-6" - data-testid="confidential-note-checkbox" - > - {{ $options.i18n.confidential }} - <gl-icon - v-gl-tooltip:tooltipcontainer.bottom - name="question" - :size="16" - :title="$options.i18n.confidentialVisibility" - class="gl-text-gray-500" - /> - </gl-form-checkbox> - <gl-dropdown - split - :text="commentButtonTitle" - class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown" - category="primary" - variant="confirm" - :disabled="disableSubmitButton" - data-testid="comment-button" - data-qa-selector="comment_button" - :data-track-label="trackingLabel" - data-track-event="click_button" - @click="handleSave()" - > - <gl-dropdown-item - is-check-item - :is-checked="isNoteTypeComment" - :selected="isNoteTypeComment" - @click="setNoteTypeToComment" + <template v-if="hasDrafts"> + <gl-button + :disabled="disableSubmitButton" + data-testid="add-to-review-button" + type="submit" + category="primary" + variant="success" + @click.prevent="handleSaveDraft()" + >{{ __('Add to review') }}</gl-button + > + <gl-button + :disabled="disableSubmitButton" + data-testid="add-comment-now-button" + category="secondary" + @click.prevent="handleSave()" + >{{ __('Add comment now') }}</gl-button + > + </template> + <template v-else> + <gl-form-checkbox + v-if="confidentialNotesEnabled && canSetConfidential" + v-model="noteIsConfidential" + class="gl-mb-6" + data-testid="confidential-note-checkbox" > - <strong>{{ $options.i18n.submitButton.comment }}</strong> - <p class="gl-m-0">{{ commentDescription }}</p> - </gl-dropdown-item> - <gl-dropdown-divider /> - <gl-dropdown-item - is-check-item - :is-checked="isNoteTypeDiscussion" - :selected="isNoteTypeDiscussion" - data-qa-selector="discussion_menu_item" - @click="setNoteTypeToDiscussion" + {{ $options.i18n.confidential }} + <gl-icon + v-gl-tooltip:tooltipcontainer.bottom + name="question" + :size="16" + :title="$options.i18n.confidentialVisibility" + class="gl-text-gray-500" + /> + </gl-form-checkbox> + <gl-dropdown + split + :text="commentButtonTitle" + class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown" + category="primary" + variant="confirm" + :disabled="disableSubmitButton" + data-testid="comment-button" + data-qa-selector="comment_button" + :data-track-label="trackingLabel" + data-track-event="click_button" + @click="handleSave()" > - <strong>{{ $options.i18n.submitButton.startThread }}</strong> - <p class="gl-m-0">{{ startDiscussionDescription }}</p> - </gl-dropdown-item> - </gl-dropdown> + <gl-dropdown-item + is-check-item + :is-checked="isNoteTypeComment" + :selected="isNoteTypeComment" + @click="setNoteTypeToComment" + > + <strong>{{ $options.i18n.submitButton.comment }}</strong> + <p class="gl-m-0">{{ commentDescription }}</p> + </gl-dropdown-item> + <gl-dropdown-divider /> + <gl-dropdown-item + is-check-item + :is-checked="isNoteTypeDiscussion" + :selected="isNoteTypeDiscussion" + data-qa-selector="discussion_menu_item" + @click="setNoteTypeToDiscussion" + > + <strong>{{ $options.i18n.submitButton.startThread }}</strong> + <p class="gl-m-0">{{ startDiscussionDescription }}</p> + </gl-dropdown-item> + </gl-dropdown> + </template> <gl-button v-if="canToggleIssueState" :loading="isToggleStateButtonLoading" :class="[actionButtonClassNames, 'btn-comment btn-comment-and-close']" :disabled="isSubmitting" data-testid="close-reopen-button" - @click="handleSave(true)" + @click="handleSave({ withIssueAction: true })" >{{ issueActionButtonTitle }}</gl-button > </div> diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index 58cfd150659..433f75a752d 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -3,8 +3,10 @@ import { mapGetters, mapActions } from 'vuex'; import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user'; import { __ } from '~/locale'; import initUserPopovers from '~/user_popovers'; +import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; import OrderedLayout from '~/vue_shared/components/ordered_layout.vue'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import draftNote from '../../batch_comments/components/draft_note.vue'; import { deprecatedCreateFlash as Flash } from '../../flash'; import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility'; import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; @@ -32,6 +34,8 @@ export default { discussionFilterNote, OrderedLayout, SidebarSubscription, + draftNote, + TimelineEntryItem, }, mixins: [glFeatureFlagsMixin()], props: { @@ -276,6 +280,9 @@ export default { <ul id="notes-list" class="notes main-notes-list timeline"> <template v-for="discussion in allDiscussions"> <skeleton-loading-container v-if="discussion.isSkeletonNote" :key="discussion.id" /> + <timeline-entry-item v-else-if="discussion.isDraft" :key="discussion.id"> + <draft-note :draft="discussion" /> + </timeline-entry-item> <template v-else-if="discussion.isPlaceholderNote"> <placeholder-system-note v-if="discussion.placeholderType === $options.systemNote" diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index 43d99937b8d..8d2d9d1d9f6 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -2,7 +2,23 @@ import { flattenDeep, clone } from 'lodash'; import * as constants from '../constants'; import { collapseSystemNotes } from './collapse_utils'; -export const discussions = (state) => { +const getDraftComments = (state) => { + if (!state.batchComments) { + return []; + } + + return state.batchComments.drafts + .filter((draft) => !draft.line_code && !draft.discussion_id) + .map((x) => ({ + ...x, + // Treat a top-level draft note as individual_note so it's not included in + // expand/collapse threads + individual_note: true, + })) + .sort((a, b) => a.id - b.id); +}; + +export const discussions = (state, getters, rootState) => { let discussionsInState = clone(state.discussions); // NOTE: not testing bc will be removed when backend is finished. @@ -22,11 +38,15 @@ export const discussions = (state) => { .sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); } + discussionsInState = collapseSystemNotes(discussionsInState); + + discussionsInState = discussionsInState.concat(getDraftComments(rootState)); + if (state.discussionSortOrder === constants.DESC) { discussionsInState = discussionsInState.reverse(); } - return collapseSystemNotes(discussionsInState); + return discussionsInState; }; export const convertedDisscussionIds = (state) => state.convertedDisscussionIds; @@ -257,3 +277,6 @@ export const commentsDisabled = (state) => state.commentsDisabled; export const suggestionsCount = (state, getters) => Object.values(getters.notesById).filter((n) => n.suggestions.length).length; + +export const hasDrafts = (state, getters, rootState, rootGetters) => + Boolean(rootGetters['batchComments/hasDrafts']); diff --git a/app/assets/stylesheets/components/feature_highlight.scss b/app/assets/stylesheets/components/feature_highlight.scss new file mode 100644 index 00000000000..08706951967 --- /dev/null +++ b/app/assets/stylesheets/components/feature_highlight.scss @@ -0,0 +1,9 @@ +.gl-badge.feature-highlight-badge { + background-color: $purple-light; + color: $purple; + + &, + &.sm { + padding: 0.25rem; + } +} |