Commit a406c5e6 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '35453-issuables-list-refactor-add-query-params-to-issuables-list' into 'master'

Add param update to vue issuables list

Closes #35453

See merge request gitlab-org/gitlab!25502
parents 4b383fa1 33de5d01
<script> <script>
import { omit } from 'lodash'; import { toNumber, omit } from 'lodash';
import { GlEmptyState, GlPagination, GlSkeletonLoading } from '@gitlab/ui'; import { GlEmptyState, GlPagination, GlSkeletonLoading } from '@gitlab/ui';
import flash from '~/flash'; import flash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { scrollToElement, urlParamsToObject } from '~/lib/utils/common_utils'; import {
scrollToElement,
urlParamsToObject,
historyPushState,
getParameterByName,
} from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import initManualOrdering from '~/manual_ordering'; import initManualOrdering from '~/manual_ordering';
import Issuable from './issuable.vue'; import Issuable from './issuable.vue';
...@@ -14,6 +19,7 @@ import { ...@@ -14,6 +19,7 @@ import {
PAGE_SIZE_MANUAL, PAGE_SIZE_MANUAL,
LOADING_LIST_ITEMS_LENGTH, LOADING_LIST_ITEMS_LENGTH,
} from '../constants'; } from '../constants';
import { setUrlParams } from '~/lib/utils/url_utility';
import issueableEventHub from '../eventhub'; import issueableEventHub from '../eventhub';
export default { export default {
...@@ -56,7 +62,10 @@ export default { ...@@ -56,7 +62,10 @@ export default {
isBulkEditing: false, isBulkEditing: false,
issuables: [], issuables: [],
loading: false, loading: false,
page: 1, page:
getParameterByName('page', window.location.href) !== null
? toNumber(getParameterByName('page'))
: 1,
selection: {}, selection: {},
totalItems: 0, totalItems: 0,
}; };
...@@ -189,6 +198,12 @@ export default { ...@@ -189,6 +198,12 @@ export default {
if (newPage === this.page) return; if (newPage === this.page) return;
scrollToElement('#content-body'); scrollToElement('#content-body');
// NOTE: This allows for the params to be updated on pagination
historyPushState(
setUrlParams({ ...this.filters, page: newPage }, window.location.href, true),
);
this.fetchIssuables(newPage); this.fetchIssuables(newPage);
}, },
onSelectAll() { onSelectAll() {
......
...@@ -12,12 +12,21 @@ import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issuables_list ...@@ -12,12 +12,21 @@ import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issuables_list
jest.mock('~/flash', () => jest.fn()); jest.mock('~/flash', () => jest.fn());
jest.mock('~/issuables_list/eventhub'); jest.mock('~/issuables_list/eventhub');
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
scrollToElement: () => {},
}));
const TEST_LOCATION = `${TEST_HOST}/issues`; const TEST_LOCATION = `${TEST_HOST}/issues`;
const TEST_ENDPOINT = '/issues'; const TEST_ENDPOINT = '/issues';
const TEST_CREATE_ISSUES_PATH = '/createIssue'; const TEST_CREATE_ISSUES_PATH = '/createIssue';
const TEST_EMPTY_SVG_PATH = '/emptySvg'; const TEST_EMPTY_SVG_PATH = '/emptySvg';
const setUrl = query => {
window.location.href = `${TEST_LOCATION}${query}`;
window.location.search = query;
};
const MOCK_ISSUES = Array(PAGE_SIZE_MANUAL) const MOCK_ISSUES = Array(PAGE_SIZE_MANUAL)
.fill(0) .fill(0)
.map((_, i) => ({ .map((_, i) => ({
...@@ -267,8 +276,6 @@ describe('Issuables list component', () => { ...@@ -267,8 +276,6 @@ describe('Issuables list component', () => {
}); });
describe('with query params in window.location', () => { describe('with query params in window.location', () => {
const query =
'?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0';
const expectedFilters = { const expectedFilters = {
assignee_username: 'root', assignee_username: 'root',
author_username: 'root', author_username: 'root',
...@@ -284,32 +291,73 @@ describe('Issuables list component', () => { ...@@ -284,32 +291,73 @@ describe('Issuables list component', () => {
sort: 'desc', sort: 'desc',
}; };
beforeEach(() => { describe('when page is not present in params', () => {
window.location.href = `${TEST_LOCATION}${query}`; const query =
window.location.search = query; '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0';
setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
factory({ sortKey: 'milestone_due_desc' });
return waitForPromises();
});
it('applies filters and sorts', () => { beforeEach(() => {
expect(wrapper.vm.hasFilters).toBe(true); setUrl(query);
expect(wrapper.vm.filters).toEqual(expectedFilters);
expect(apiSpy).toHaveBeenCalledWith( setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
expect.objectContaining({ factory({ sortKey: 'milestone_due_desc' });
params: {
...expectedFilters, return waitForPromises();
with_labels_details: true, });
page: 1,
per_page: PAGE_SIZE, afterEach(() => {
}, apiSpy.mockClear();
}), });
);
it('applies filters and sorts', () => {
expect(wrapper.vm.hasFilters).toBe(true);
expect(wrapper.vm.filters).toEqual(expectedFilters);
expect(apiSpy).toHaveBeenCalledWith(
expect.objectContaining({
params: {
...expectedFilters,
with_labels_details: true,
page: 1,
per_page: PAGE_SIZE,
},
}),
);
});
it('passes the base url to issuable', () => {
expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
});
}); });
it('passes the base url to issuable', () => { describe('when page is present in the param', () => {
expect(findFirstIssuable().props('baseUrl')).toEqual(TEST_LOCATION); const query =
'?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0&page=3';
beforeEach(() => {
setUrl(query);
setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
factory({ sortKey: 'milestone_due_desc' });
return waitForPromises();
});
afterEach(() => {
apiSpy.mockClear();
});
it('applies filters and sorts', () => {
expect(apiSpy).toHaveBeenCalledWith(
expect.objectContaining({
params: {
...expectedFilters,
with_labels_details: true,
page: 3,
per_page: PAGE_SIZE,
},
}),
);
});
}); });
}); });
...@@ -322,7 +370,7 @@ describe('Issuables list component', () => { ...@@ -322,7 +370,7 @@ describe('Issuables list component', () => {
}); });
it('passes the base url to issuable', () => { it('passes the base url to issuable', () => {
expect(findFirstIssuable().props('baseUrl')).toEqual(TEST_LOCATION); expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
}); });
}); });
...@@ -402,4 +450,47 @@ describe('Issuables list component', () => { ...@@ -402,4 +450,47 @@ describe('Issuables list component', () => {
}); });
}); });
}); });
describe('when paginates', () => {
const newPage = 3;
beforeEach(() => {
window.history.pushState = jest.fn();
setupApiMock(() => [
200,
MOCK_ISSUES.slice(0, PAGE_SIZE),
{
'x-total': 100,
'x-page': 2,
},
]);
factory();
return waitForPromises();
});
afterEach(() => {
// reset to original value
window.history.pushState.mockRestore();
});
it('calls window.history.pushState one time', () => {
// Trigger pagination
wrapper.find(GlPagination).vm.$emit('input', newPage);
expect(window.history.pushState).toHaveBeenCalledTimes(1);
});
it('sets params in the url', () => {
// Trigger pagination
wrapper.find(GlPagination).vm.$emit('input', newPage);
expect(window.history.pushState).toHaveBeenCalledWith(
{},
'',
`${TEST_LOCATION}?state=opened&order_by=priority&sort=asc&page=${newPage}`,
);
});
});
}); });
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