Commit 1715eda1 authored by Coung Ngo's avatar Coung Ngo Committed by Natalia Tepluhina

Add url query when work item modal is open

Add url query `work_item_id` so when visiting the issue show
page with this url query, the work item modal automatically
opens with the work item details.

Behind feature flag `work_items` defaulted off.
parent d31c0d1a
......@@ -4,6 +4,8 @@ import $ from 'jquery';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
import createFlash from '~/flash';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import { getParameterByName, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
import TaskList from '~/task_list';
import Tracking from '~/tracking';
......@@ -65,13 +67,17 @@ export default {
},
},
data() {
const workItemId = getParameterByName('work_item_id');
return {
preAnimation: false,
pulseAnimation: false,
initialUpdate: true,
taskButtons: [],
activeTask: {},
workItemId: null,
workItemId: isPositiveInteger(workItemId)
? convertToGraphQLId(TYPE_WORK_ITEM, workItemId)
: undefined,
};
},
computed: {
......@@ -184,6 +190,7 @@ export default {
taskLink.addEventListener('click', (e) => {
e.preventDefault();
this.workItemId = convertToGraphQLId(TYPE_WORK_ITEM, issue);
this.updateWorkItemIdUrlQuery(issue);
this.track('viewed_work_item_from_modal', {
category: 'workItems:show',
label: 'work_item_view',
......@@ -232,12 +239,19 @@ export default {
this.$refs.modal.hide();
},
closeWorkItemDetailModal() {
this.workItemId = null;
this.workItemId = undefined;
this.updateWorkItemIdUrlQuery(undefined);
},
handleCreateTask(description) {
this.$emit('updateDescription', description);
this.closeCreateTaskModal();
},
updateWorkItemIdUrlQuery(workItemId) {
updateHistory({
url: setUrlParams({ work_item_id: workItemId }),
replace: true,
});
},
},
safeHtmlConfig: { ADD_TAGS: ['gl-emoji', 'copy-code'] },
};
......@@ -281,7 +295,7 @@ export default {
body-class="gl-p-0!"
>
<create-work-item
:is-modal="true"
is-modal
:initial-title="activeTask.title"
:issue-gid="issueGid"
:lock-version="lockVersion"
......
......@@ -2,11 +2,13 @@ import $ from 'jquery';
import { nextTick } from 'vue';
import '~/behaviors/markdown/render_gfm';
import { GlTooltip, GlModal } from '@gitlab/ui';
import setWindowLocation from 'helpers/set_window_location_helper';
import { stubComponent } from 'helpers/stub_component';
import { TEST_HOST } from 'helpers/test_constants';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import Description from '~/issues/show/components/description.vue';
import { updateHistory } from '~/lib/utils/url_utility';
import TaskList from '~/task_list';
import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
import CreateWorkItem from '~/work_items/pages/create_work_item.vue';
......@@ -17,6 +19,10 @@ import {
} from '../mock_data/mock_data';
jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
updateHistory: jest.fn(),
}));
jest.mock('~/task_list');
const showModal = jest.fn();
......@@ -55,6 +61,8 @@ describe('Description component', () => {
}
beforeEach(() => {
setWindowLocation(TEST_HOST);
if (!document.querySelector('.issuable-meta')) {
const metaData = document.createElement('div');
metaData.classList.add('issuable-meta');
......@@ -285,48 +293,86 @@ describe('Description component', () => {
describe('work items detail', () => {
const findTaskLink = () => wrapper.find('a.gfm-issue');
beforeEach(() => {
createComponent({
props: {
descriptionHtml: descriptionHtmlWithTask,
},
provide: {
glFeatures: { workItems: true },
},
describe('when opening and closing', () => {
beforeEach(() => {
createComponent({
props: {
descriptionHtml: descriptionHtmlWithTask,
},
provide: {
glFeatures: { workItems: true },
},
});
return nextTick();
});
return nextTick();
});
it('opens when task button is clicked', async () => {
expect(findWorkItemDetailModal().props('visible')).toBe(false);
it('opens when task button is clicked', async () => {
expect(findWorkItemDetailModal().props('visible')).toBe(false);
await findTaskLink().trigger('click');
await findTaskLink().trigger('click');
expect(findWorkItemDetailModal().props('visible')).toBe(true);
});
expect(findWorkItemDetailModal().props('visible')).toBe(true);
expect(updateHistory).toHaveBeenCalledWith({
url: `${TEST_HOST}/?work_item_id=2`,
replace: true,
});
});
it('closes from an open state', async () => {
await findTaskLink().trigger('click');
it('closes from an open state', async () => {
await findTaskLink().trigger('click');
expect(findWorkItemDetailModal().props('visible')).toBe(true);
expect(findWorkItemDetailModal().props('visible')).toBe(true);
findWorkItemDetailModal().vm.$emit('close');
await nextTick();
findWorkItemDetailModal().vm.$emit('close');
await nextTick();
expect(findWorkItemDetailModal().props('visible')).toBe(false);
});
expect(findWorkItemDetailModal().props('visible')).toBe(false);
expect(updateHistory).toHaveBeenLastCalledWith({
url: `${TEST_HOST}/`,
replace: true,
});
});
it('tracks when opened', async () => {
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
it('tracks when opened', async () => {
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
await findTaskLink().trigger('click');
await findTaskLink().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith('workItems:show', 'viewed_work_item_from_modal', {
category: 'workItems:show',
label: 'work_item_view',
property: 'type_task',
expect(trackingSpy).toHaveBeenCalledWith(
'workItems:show',
'viewed_work_item_from_modal',
{
category: 'workItems:show',
label: 'work_item_view',
property: 'type_task',
},
);
});
});
describe('when url query `work_item_id` exists', () => {
it.each`
behavior | workItemId | visible
${'opens'} | ${'123'} | ${true}
${'does not open'} | ${'123e'} | ${false}
${'does not open'} | ${'12e3'} | ${false}
${'does not open'} | ${'1e23'} | ${false}
${'does not open'} | ${'x'} | ${false}
${'does not open'} | ${'undefined'} | ${false}
`(
'$behavior when url contains `work_item_id=$workItemId`',
async ({ workItemId, visible }) => {
setWindowLocation(`?work_item_id=${workItemId}`);
createComponent({
props: { descriptionHtml: descriptionHtmlWithTask },
provide: { glFeatures: { workItems: true } },
});
expect(findWorkItemDetailModal().props('visible')).toBe(visible);
},
);
});
});
});
});
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