Commit a3e15a47 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents ff731313 8011155f
<script> <script>
import { import { GlAlert, GlButton, GlIcon, GlFormCheckbox, GlTooltipDirective } from '@gitlab/ui';
GlAlert,
GlButton,
GlIcon,
GlFormCheckbox,
GlTooltipDirective,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
} from '@gitlab/ui';
import Autosize from 'autosize'; import Autosize from 'autosize';
import $ from 'jquery'; import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
...@@ -34,6 +25,7 @@ import { COMMENT_FORM } from '../i18n'; ...@@ -34,6 +25,7 @@ import { COMMENT_FORM } from '../i18n';
import issuableStateMixin from '../mixins/issuable_state'; import issuableStateMixin from '../mixins/issuable_state';
import CommentFieldLayout from './comment_field_layout.vue'; import CommentFieldLayout from './comment_field_layout.vue';
import CommentTypeDropdown from './comment_type_dropdown.vue';
import discussionLockedWidget from './discussion_locked_widget.vue'; import discussionLockedWidget from './discussion_locked_widget.vue';
import noteSignedOutWidget from './note_signed_out_widget.vue'; import noteSignedOutWidget from './note_signed_out_widget.vue';
...@@ -42,8 +34,6 @@ const { UNPROCESSABLE_ENTITY } = httpStatusCodes; ...@@ -42,8 +34,6 @@ const { UNPROCESSABLE_ENTITY } = httpStatusCodes;
export default { export default {
name: 'CommentForm', name: 'CommentForm',
i18n: COMMENT_FORM, i18n: COMMENT_FORM,
noteTypeComment: constants.COMMENT,
noteTypeDiscussion: constants.DISCUSSION,
components: { components: {
noteSignedOutWidget, noteSignedOutWidget,
discussionLockedWidget, discussionLockedWidget,
...@@ -53,10 +43,8 @@ export default { ...@@ -53,10 +43,8 @@ export default {
TimelineEntryItem, TimelineEntryItem,
GlIcon, GlIcon,
CommentFieldLayout, CommentFieldLayout,
CommentTypeDropdown,
GlFormCheckbox, GlFormCheckbox,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -88,12 +76,6 @@ export default { ...@@ -88,12 +76,6 @@ export default {
'hasDrafts', 'hasDrafts',
]), ]),
...mapState(['isToggleStateButtonLoading']), ...mapState(['isToggleStateButtonLoading']),
isNoteTypeComment() {
return this.noteType === constants.COMMENT;
},
isNoteTypeDiscussion() {
return this.noteType === constants.DISCUSSION;
},
noteableDisplayName() { noteableDisplayName() {
return splitCamelCase(this.noteableType).toLowerCase(); return splitCamelCase(this.noteableType).toLowerCase();
}, },
...@@ -105,15 +87,8 @@ export default { ...@@ -105,15 +87,8 @@ export default {
? this.$options.i18n.comment ? this.$options.i18n.comment
: this.$options.i18n.startThread; : this.$options.i18n.startThread;
}, },
startDiscussionDescription() { discussionsRequireResolution() {
return this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE return this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE;
? this.$options.i18n.discussionThatNeedsResolution
: this.$options.i18n.discussion;
},
commentDescription() {
return sprintf(this.$options.i18n.submitButton.commentHelp, {
noteableDisplayName: this.noteableDisplayName,
});
}, },
isOpen() { isOpen() {
return this.openState === constants.OPENED || this.openState === constants.REOPENED; return this.openState === constants.OPENED || this.openState === constants.REOPENED;
...@@ -314,15 +289,6 @@ export default { ...@@ -314,15 +289,6 @@ export default {
this.autosave.reset(); this.autosave.reset();
}, },
setNoteType(type) {
this.noteType = type;
},
setNoteTypeToComment() {
this.setNoteType(constants.COMMENT);
},
setNoteTypeToDiscussion() {
this.setNoteType(constants.DISCUSSION);
},
editCurrentUserLastNote() { editCurrentUserLastNote() {
if (this.note === '') { if (this.note === '') {
const lastNote = this.getCurrentUserLastNote; const lastNote = this.getCurrentUserLastNote;
...@@ -448,40 +414,15 @@ export default { ...@@ -448,40 +414,15 @@ export default {
class="gl-text-gray-500" class="gl-text-gray-500"
/> />
</gl-form-checkbox> </gl-form-checkbox>
<gl-dropdown <comment-type-dropdown
split v-model="noteType"
:text="commentButtonTitle" class="gl-mr-3"
class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown"
category="primary"
variant="confirm"
:disabled="disableSubmitButton" :disabled="disableSubmitButton"
data-testid="comment-button" :tracking-label="trackingLabel"
data-qa-selector="comment_button" :noteable-display-name="noteableDisplayName"
:data-track-label="trackingLabel" :discussions-require-resolution="discussionsRequireResolution"
data-track-event="click_button" @click="handleSave"
@click="handleSave()" />
>
<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> </template>
<gl-button <gl-button
v-if="canToggleIssueState" v-if="canToggleIssueState"
......
<script>
import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { COMMENT_FORM } from '~/notes/i18n';
import * as constants from '../constants';
export default {
i18n: COMMENT_FORM,
components: {
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
},
model: {
prop: 'noteType',
event: 'change',
},
props: {
disabled: {
type: Boolean,
required: false,
default: false,
},
trackingLabel: {
type: String,
required: false,
default: undefined,
},
discussionsRequireResolution: {
type: Boolean,
required: false,
default: false,
},
noteableDisplayName: {
type: String,
required: true,
},
noteType: {
type: String,
required: true,
},
},
computed: {
isNoteTypeComment() {
return this.noteType === constants.COMMENT;
},
isNoteTypeDiscussion() {
return this.noteType === constants.DISCUSSION;
},
commentButtonTitle() {
return this.noteType === constants.COMMENT
? this.$options.i18n.comment
: this.$options.i18n.startThread;
},
startDiscussionDescription() {
return this.discussionsRequireResolution
? this.$options.i18n.discussionThatNeedsResolution
: this.$options.i18n.discussion;
},
commentDescription() {
return sprintf(this.$options.i18n.submitButton.commentHelp, {
noteableDisplayName: this.noteableDisplayName,
});
},
},
methods: {
handleClick() {
this.$emit('click');
},
setNoteTypeToComment() {
if (this.noteType !== constants.COMMENT) {
this.$emit('change', constants.COMMENT);
}
},
setNoteTypeToDiscussion() {
if (this.noteType !== constants.DISCUSSION) {
this.$emit('change', constants.DISCUSSION);
}
},
},
};
</script>
<template>
<gl-dropdown
split
:text="commentButtonTitle"
class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown"
category="primary"
variant="confirm"
:disabled="disabled"
data-testid="comment-button"
data-qa-selector="comment_button"
:data-track-label="trackingLabel"
data-track-event="click_button"
@click="$emit('click')"
>
<gl-dropdown-item is-check-item :is-checked="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"
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>
...@@ -96,12 +96,14 @@ Example response: ...@@ -96,12 +96,14 @@ Example response:
{ {
"id": 1, "id": 1,
"active": true, "active": true,
"public_key": "glet_aa77551d849c083f76d0bc545ed053a3" "public_key": "glet_aa77551d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
}, },
{ {
"id": 3, "id": 3,
"active": true, "active": true,
"public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3" "public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_0ff98b1d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
} }
] ]
``` ```
...@@ -129,7 +131,8 @@ Example response: ...@@ -129,7 +131,8 @@ Example response:
{ {
"id": 3, "id": 3,
"active": true, "active": true,
"public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3" "public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_0ff98b1d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
} }
``` ```
......
...@@ -15,6 +15,7 @@ module API ...@@ -15,6 +15,7 @@ module API
expose :id expose :id
expose :active expose :active
expose :public_key expose :public_key
expose :sentry_dsn
end end
end end
end end
......
...@@ -14,8 +14,11 @@ module QA ...@@ -14,8 +14,11 @@ module QA
end end
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :comment_button
element :comment_field element :comment_field
end
base.view 'app/assets/javascripts/notes/components/comment_type_dropdown.vue' do
element :comment_button
element :discussion_menu_item element :discussion_menu_item
end end
......
...@@ -10,6 +10,7 @@ import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests ...@@ -10,6 +10,7 @@ import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import CommentForm from '~/notes/components/comment_form.vue'; import CommentForm from '~/notes/components/comment_form.vue';
import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue';
import * as constants from '~/notes/constants'; import * as constants from '~/notes/constants';
import eventHub from '~/notes/event_hub'; import eventHub from '~/notes/event_hub';
import { COMMENT_FORM } from '~/notes/i18n'; import { COMMENT_FORM } from '~/notes/i18n';
...@@ -33,8 +34,8 @@ describe('issue_comment_form component', () => { ...@@ -33,8 +34,8 @@ describe('issue_comment_form component', () => {
const findAddToReviewButton = () => wrapper.findByTestId('add-to-review-button'); const findAddToReviewButton = () => wrapper.findByTestId('add-to-review-button');
const findAddCommentNowButton = () => wrapper.findByTestId('add-comment-now-button'); const findAddCommentNowButton = () => wrapper.findByTestId('add-comment-now-button');
const findConfidentialNoteCheckbox = () => wrapper.findByTestId('confidential-note-checkbox'); const findConfidentialNoteCheckbox = () => wrapper.findByTestId('confidential-note-checkbox');
const findCommentGlDropdown = () => wrapper.findByTestId('comment-button'); const findCommentTypeDropdown = () => wrapper.findComponent(CommentTypeDropdown);
const findCommentButton = () => findCommentGlDropdown().find('button'); const findCommentButton = () => findCommentTypeDropdown().find('button');
const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers; const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers;
async function clickCommentButton({ waitForComponent = true, waitForNetwork = true } = {}) { async function clickCommentButton({ waitForComponent = true, waitForNetwork = true } = {}) {
...@@ -381,7 +382,7 @@ describe('issue_comment_form component', () => { ...@@ -381,7 +382,7 @@ describe('issue_comment_form component', () => {
it('should render comment button as disabled', () => { it('should render comment button as disabled', () => {
mountComponent(); mountComponent();
expect(findCommentGlDropdown().props('disabled')).toBe(true); expect(findCommentTypeDropdown().props('disabled')).toBe(true);
}); });
it('should enable comment button if it has note', async () => { it('should enable comment button if it has note', async () => {
...@@ -389,7 +390,7 @@ describe('issue_comment_form component', () => { ...@@ -389,7 +390,7 @@ describe('issue_comment_form component', () => {
await wrapper.setData({ note: 'Foo' }); await wrapper.setData({ note: 'Foo' });
expect(findCommentGlDropdown().props('disabled')).toBe(false); expect(findCommentTypeDropdown().props('disabled')).toBe(false);
}); });
it('should update buttons texts when it has note', () => { it('should update buttons texts when it has note', () => {
...@@ -624,7 +625,7 @@ describe('issue_comment_form component', () => { ...@@ -624,7 +625,7 @@ describe('issue_comment_form component', () => {
it('when no drafts exist, should not render', () => { it('when no drafts exist, should not render', () => {
mountComponent(); mountComponent();
expect(findCommentGlDropdown().exists()).toBe(true); expect(findCommentTypeDropdown().exists()).toBe(true);
expect(findAddToReviewButton().exists()).toBe(false); expect(findAddToReviewButton().exists()).toBe(false);
expect(findAddCommentNowButton().exists()).toBe(false); expect(findAddCommentNowButton().exists()).toBe(false);
}); });
...@@ -637,7 +638,7 @@ describe('issue_comment_form component', () => { ...@@ -637,7 +638,7 @@ describe('issue_comment_form component', () => {
it('should render', () => { it('should render', () => {
mountComponent(); mountComponent();
expect(findCommentGlDropdown().exists()).toBe(false); expect(findCommentTypeDropdown().exists()).toBe(false);
expect(findAddToReviewButton().exists()).toBe(true); expect(findAddToReviewButton().exists()).toBe(true);
expect(findAddCommentNowButton().exists()).toBe(true); expect(findAddCommentNowButton().exists()).toBe(true);
}); });
......
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue';
import * as constants from '~/notes/constants';
import { COMMENT_FORM } from '~/notes/i18n';
describe('CommentTypeDropdown component', () => {
let wrapper;
const findCommentGlDropdown = () => wrapper.findComponent(GlDropdown);
const findCommentDropdownOption = () => wrapper.findAllComponents(GlDropdownItem).at(0);
const findDiscussionDropdownOption = () => wrapper.findAllComponents(GlDropdownItem).at(1);
const mountComponent = ({ props = {} } = {}) => {
wrapper = extendedWrapper(
mount(CommentTypeDropdown, {
propsData: {
noteableDisplayName: 'issue',
noteType: constants.COMMENT,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
it('Should label action button "Comment" and correct dropdown item checked when selected', () => {
mountComponent({ props: { noteType: constants.COMMENT } });
expect(findCommentGlDropdown().props()).toMatchObject({ text: COMMENT_FORM.comment });
expect(findCommentDropdownOption().props()).toMatchObject({ isChecked: true });
expect(findDiscussionDropdownOption().props()).toMatchObject({ isChecked: false });
});
it('Should label action button "Start Thread" and correct dropdown item option checked when selected', () => {
mountComponent({ props: { noteType: constants.DISCUSSION } });
expect(findCommentGlDropdown().props()).toMatchObject({ text: COMMENT_FORM.startThread });
expect(findCommentDropdownOption().props()).toMatchObject({ isChecked: false });
expect(findDiscussionDropdownOption().props()).toMatchObject({ isChecked: true });
});
it('Should emit `change` event when clicking on an alternate dropdown option', () => {
mountComponent({ props: { noteType: constants.DISCUSSION } });
findCommentDropdownOption().vm.$emit('click');
findDiscussionDropdownOption().vm.$emit('click');
expect(wrapper.emitted('change')[0]).toEqual([constants.COMMENT]);
expect(wrapper.emitted('change').length).toEqual(1);
});
it('Should emit `click` event when clicking on the action button', () => {
mountComponent({ props: { noteType: constants.DISCUSSION } });
findCommentGlDropdown().vm.$emit('click');
expect(wrapper.emitted('click').length > 0).toBe(true);
});
});
...@@ -63,6 +63,7 @@ RSpec.describe API::ErrorTrackingClientKeys do ...@@ -63,6 +63,7 @@ RSpec.describe API::ErrorTrackingClientKeys do
expect(json_response['id']).to eq(new_key.id) expect(json_response['id']).to eq(new_key.id)
expect(json_response['public_key']).to eq(new_key.public_key) expect(json_response['public_key']).to eq(new_key.public_key)
expect(json_response['sentry_dsn']).to eq(new_key.sentry_dsn)
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment