Commit a021ab46 authored by Simon Knox's avatar Simon Knox

Merge branch...

Merge branch '355978-refactor-issue-description-task-work-item-conversion-using-task-button-2' into 'master'

Replace create task popover with button

See merge request gitlab-org/gitlab!83200
parents cefd430d 750621ed
<script> <script>
import { import { GlSafeHtmlDirective as SafeHtml, GlModal, GlTooltip, GlModalDirective } from '@gitlab/ui';
GlSafeHtmlDirective as SafeHtml,
GlModal,
GlModalDirective,
GlPopover,
GlButton,
} from '@gitlab/ui';
import $ from 'jquery'; import $ from 'jquery';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_WORK_ITEM } from '~/graphql_shared/constants'; import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __, sprintf } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import TaskList from '~/task_list'; import TaskList from '~/task_list';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
...@@ -25,9 +19,8 @@ export default { ...@@ -25,9 +19,8 @@ export default {
}, },
components: { components: {
GlModal, GlModal,
GlPopover,
CreateWorkItem, CreateWorkItem,
GlButton, GlTooltip,
WorkItemDetailModal, WorkItemDetailModal,
}, },
mixins: [animateMixin, glFeatureFlagMixin(), Tracking.mixin()], mixins: [animateMixin, glFeatureFlagMixin(), Tracking.mixin()],
...@@ -216,9 +209,11 @@ export default { ...@@ -216,9 +209,11 @@ export default {
this.taskButtons.push(button.id); this.taskButtons.push(button.id);
button.innerHTML = ` button.innerHTML = `
<svg data-testid="ellipsis_v-icon" role="img" aria-hidden="true" class="dropdown-icon gl-icon s14"> <svg data-testid="ellipsis_v-icon" role="img" aria-hidden="true" class="dropdown-icon gl-icon s14">
<use href="${gon.sprite_icons}#ellipsis_v"></use> <use href="${gon.sprite_icons}#doc-new"></use>
</svg> </svg>
`; `;
button.setAttribute('aria-label', s__('WorkItem|Convert to work item'));
button.addEventListener('click', () => this.openCreateTaskModal(button.id));
item.prepend(button); item.prepend(button);
}); });
}, },
...@@ -246,9 +241,6 @@ export default { ...@@ -246,9 +241,6 @@ export default {
this.$emit('updateDescription', description); this.$emit('updateDescription', description);
this.closeCreateTaskModal(); this.closeCreateTaskModal();
}, },
focusButton() {
this.$refs.convertButton[0].$el.focus();
},
}, },
safeHtmlConfig: { ADD_TAGS: ['gl-emoji', 'copy-code'] }, safeHtmlConfig: { ADD_TAGS: ['gl-emoji', 'copy-code'] },
}; };
...@@ -309,23 +301,9 @@ export default { ...@@ -309,23 +301,9 @@ export default {
@error="handleWorkItemDetailModalError" @error="handleWorkItemDetailModalError"
/> />
<template v-if="workItemsEnabled"> <template v-if="workItemsEnabled">
<gl-popover <gl-tooltip v-for="item in taskButtons" :key="item" :target="item">
v-for="item in taskButtons" {{ s__('WorkItem|Convert to work item') }}
:key="item" </gl-tooltip>
:target="item"
placement="top"
triggers="focus"
@shown="focusButton"
>
<gl-button
ref="convertButton"
variant="link"
data-testid="convert-to-task"
class="gl-text-gray-900! gl-text-decoration-none! gl-outline-0!"
@click="openCreateTaskModal(item)"
>{{ s__('WorkItem|Convert to work item') }}</gl-button
>
</gl-popover>
</template> </template>
</div> </div>
</template> </template>
...@@ -87,10 +87,7 @@ export default { ...@@ -87,10 +87,7 @@ export default {
return this.selectedWorkItemType?.name || s__('WorkItem|Type'); return this.selectedWorkItemType?.name || s__('WorkItem|Type');
}, },
formOptions() { formOptions() {
return [ return [{ value: null, text: s__('WorkItem|Select type') }, ...this.workItemTypes];
{ value: null, text: s__('WorkItem|Please select work item type') },
...this.workItemTypes,
];
}, },
isButtonDisabled() { isButtonDisabled() {
return this.title.trim().length === 0 || !this.selectedWorkItemType; return this.title.trim().length === 0 || !this.selectedWorkItemType;
......
...@@ -311,7 +311,7 @@ ul.related-merge-requests > li gl-emoji { ...@@ -311,7 +311,7 @@ ul.related-merge-requests > li gl-emoji {
.description.work-items-enabled { .description.work-items-enabled {
ul.task-list { ul.task-list {
> li.task-list-item { > li.task-list-item {
padding-inline-start: 2.25rem; padding-inline-start: 2.5rem;
.js-add-task { .js-add-task {
svg { svg {
...@@ -324,7 +324,7 @@ ul.related-merge-requests > li gl-emoji { ...@@ -324,7 +324,7 @@ ul.related-merge-requests > li gl-emoji {
} }
> input.task-list-item-checkbox { > input.task-list-item-checkbox {
left: 0.875rem; left: 1.25rem;
} }
&:hover, &:hover,
......
...@@ -42374,7 +42374,7 @@ msgstr "" ...@@ -42374,7 +42374,7 @@ msgstr ""
msgid "WorkItem|New Task" msgid "WorkItem|New Task"
msgstr "" msgstr ""
msgid "WorkItem|Please select work item type" msgid "WorkItem|Select type"
msgstr "" msgstr ""
msgid "WorkItem|Something went wrong when creating a work item. Please try again" msgid "WorkItem|Something went wrong when creating a work item. Please try again"
......
import $ from 'jquery'; import $ from 'jquery';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import '~/behaviors/markdown/render_gfm'; import '~/behaviors/markdown/render_gfm';
import { GlPopover, GlModal } from '@gitlab/ui'; import { GlTooltip, GlModal } from '@gitlab/ui';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { mockTracking } from 'helpers/tracking_helper'; import { mockTracking } from 'helpers/tracking_helper';
...@@ -29,9 +29,9 @@ describe('Description component', () => { ...@@ -29,9 +29,9 @@ describe('Description component', () => {
const findGfmContent = () => wrapper.find('[data-testid="gfm-content"]'); const findGfmContent = () => wrapper.find('[data-testid="gfm-content"]');
const findTextarea = () => wrapper.find('[data-testid="textarea"]'); const findTextarea = () => wrapper.find('[data-testid="textarea"]');
const findTaskActionButtons = () => wrapper.findAll('.js-add-task'); const findTaskActionButtons = () => wrapper.findAll('.js-add-task');
const findConvertToTaskButton = () => wrapper.find('[data-testid="convert-to-task"]'); const findConvertToTaskButton = () => wrapper.find('.js-add-task');
const findPopovers = () => wrapper.findAllComponents(GlPopover); const findTooltips = () => wrapper.findAllComponents(GlTooltip);
const findModal = () => wrapper.findComponent(GlModal); const findModal = () => wrapper.findComponent(GlModal);
const findCreateWorkItem = () => wrapper.findComponent(CreateWorkItem); const findCreateWorkItem = () => wrapper.findComponent(CreateWorkItem);
const findWorkItemDetailModal = () => wrapper.findComponent(WorkItemDetailModal); const findWorkItemDetailModal = () => wrapper.findComponent(WorkItemDetailModal);
...@@ -51,7 +51,6 @@ describe('Description component', () => { ...@@ -51,7 +51,6 @@ describe('Description component', () => {
hide: hideModal, hide: hideModal,
}, },
}), }),
GlPopover,
}, },
}); });
} }
...@@ -254,9 +253,9 @@ describe('Description component', () => { ...@@ -254,9 +253,9 @@ describe('Description component', () => {
expect(findTaskActionButtons()).toHaveLength(3); expect(findTaskActionButtons()).toHaveLength(3);
}); });
it('renders a list of popovers corresponding to checkboxes in description HTML', () => { it('renders a list of tooltips corresponding to checkboxes in description HTML', () => {
expect(findPopovers()).toHaveLength(3); expect(findTooltips()).toHaveLength(3);
expect(findPopovers().at(0).props('target')).toBe( expect(findTooltips().at(0).props('target')).toBe(
findTaskActionButtons().at(0).attributes('id'), findTaskActionButtons().at(0).attributes('id'),
); );
}); });
...@@ -265,20 +264,18 @@ describe('Description component', () => { ...@@ -265,20 +264,18 @@ describe('Description component', () => {
expect(findModal().props('visible')).toBe(false); expect(findModal().props('visible')).toBe(false);
}); });
it('opens a modal when a button on popover is clicked and displays correct title', async () => { it('opens a modal when a button is clicked and displays correct title', async () => {
findConvertToTaskButton().vm.$emit('click'); await findConvertToTaskButton().trigger('click');
expect(showModal).toHaveBeenCalled();
await nextTick();
expect(findCreateWorkItem().props('initialTitle').trim()).toBe('todo 1'); expect(findCreateWorkItem().props('initialTitle').trim()).toBe('todo 1');
}); });
it('closes the modal on `closeCreateTaskModal` event', () => { it('closes the modal on `closeCreateTaskModal` event', async () => {
findConvertToTaskButton().vm.$emit('click'); await findConvertToTaskButton().trigger('click');
findCreateWorkItem().vm.$emit('closeModal'); findCreateWorkItem().vm.$emit('closeModal');
expect(hideModal).toHaveBeenCalled(); expect(hideModal).toHaveBeenCalled();
}); });
it('emits `updateDescription` on `onCreate` event', async () => { it('emits `updateDescription` on `onCreate` event', () => {
const newDescription = `<p>New description</p>`; const newDescription = `<p>New description</p>`;
findCreateWorkItem().vm.$emit('onCreate', newDescription); findCreateWorkItem().vm.$emit('onCreate', newDescription);
expect(hideModal).toHaveBeenCalled(); expect(hideModal).toHaveBeenCalled();
......
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