Commit 44cb8a74 authored by Tim Zallmann's avatar Tim Zallmann

Merge branch 'boards-querystring-backport' into 'master'

don't add trailing = when in urlParamsToArray function

See merge request gitlab-org/gitlab-ce!21179
parents 3276e88b 8a5121eb
<script> <script>
/* global ListIssue */ /* global ListIssue */
import queryData from '~/boards/utils/query_data'; import { urlParamsToObject } from '~/lib/utils/common_utils';
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import ModalHeader from './header.vue'; import ModalHeader from './header.vue';
import ModalList from './list.vue'; import ModalList from './list.vue';
...@@ -109,13 +109,11 @@ ...@@ -109,13 +109,11 @@
loadIssues(clearIssues = false) { loadIssues(clearIssues = false) {
if (!this.showAddIssuesModal) return false; if (!this.showAddIssuesModal) return false;
return gl.boardService return gl.boardService.getBacklog({
.getBacklog( ...urlParamsToObject(this.filter.path),
queryData(this.filter.path, { page: this.page,
page: this.page, per: this.perPage,
per: this.perPage, })
}),
)
.then(res => res.data) .then(res => res.data)
.then(data => { .then(data => {
if (clearIssues) { if (clearIssues) {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import { __ } from '~/locale'; import { __ } from '~/locale';
import ListLabel from '~/vue_shared/models/label'; import ListLabel from '~/vue_shared/models/label';
import ListAssignee from '~/vue_shared/models/assignee'; import ListAssignee from '~/vue_shared/models/assignee';
import queryData from '../utils/query_data'; import { urlParamsToObject } from '~/lib/utils/common_utils';
const PER_PAGE = 20; const PER_PAGE = 20;
...@@ -115,7 +115,10 @@ class List { ...@@ -115,7 +115,10 @@ class List {
} }
getIssues(emptyIssues = true) { getIssues(emptyIssues = true) {
const data = queryData(gl.issueBoards.BoardsStore.filter.path, { page: this.page }); const data = {
...urlParamsToObject(gl.issueBoards.BoardsStore.filter.path),
page: this.page,
};
if (this.label && data.label_name) { if (this.label && data.label_name) {
data.label_name = data.label_name.filter(label => label !== this.label.title); data.label_name = data.label_name.filter(label => label !== this.label.title);
......
export default (path, extraData) => path.split('&').reduce((dataParam, filterParam) => {
if (filterParam === '') return dataParam;
const data = dataParam;
const paramSplit = filterParam.split('=');
const paramKeyNormalized = paramSplit[0].replace('[]', '');
const isArray = paramSplit[0].indexOf('[]');
const value = decodeURIComponent(paramSplit[1].replace(/\+/g, ' '));
if (isArray !== -1) {
if (!data[paramKeyNormalized]) {
data[paramKeyNormalized] = [];
}
data[paramKeyNormalized].push(value);
} else {
data[paramKeyNormalized] = value;
}
return data;
}, extraData);
...@@ -131,16 +131,43 @@ export const parseUrlPathname = url => { ...@@ -131,16 +131,43 @@ export const parseUrlPathname = url => {
return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : `/${parsedUrl.pathname}`; return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : `/${parsedUrl.pathname}`;
}; };
// We can trust that each param has one & since values containing & will be encoded const splitPath = (path = '') => path
// Remove the first character of search as it is always ? .replace(/^\?/, '')
export const getUrlParamsArray = () => .split('&');
window.location.search
.slice(1) export const urlParamsToArray = (path = '') => splitPath(path)
.split('&') .filter(param => param.length > 0)
.map(param => { .map(param => {
const split = param.split('='); const split = param.split('=');
return [decodeURI(split[0]), split[1]].join('='); return [decodeURI(split[0]), split[1]].join('=');
}); });
export const getUrlParamsArray = () => urlParamsToArray(window.location.search);
export const urlParamsToObject = (path = '') => splitPath(path)
.reduce((dataParam, filterParam) => {
if (filterParam === '') {
return dataParam;
}
const data = dataParam;
let [key, value] = filterParam.split('=');
const isArray = key.includes('[]');
key = key.replace('[]', '');
value = decodeURIComponent(value.replace(/\+/g, ' '));
if (isArray) {
if (!data[key]) {
data[key] = [];
}
data[key].push(value);
} else {
data[key] = value;
}
return data;
}, {});
export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
......
...@@ -27,7 +27,7 @@ export const listObjDuplicate = { ...@@ -27,7 +27,7 @@ export const listObjDuplicate = {
export const BoardsMockData = { export const BoardsMockData = {
GET: { GET: {
'/test/-/boards/1/lists/300/issues?id=300&page=1&=': { '/test/-/boards/1/lists/300/issues?id=300&page=1': {
issues: [ issues: [
{ {
title: 'Testing', title: 'Testing',
......
import queryData from '~/boards/utils/query_data';
describe('queryData', () => {
it('parses path for label with trailing +', () => {
expect(
queryData('label_name[]=label%2B', {}),
).toEqual({
label_name: ['label+'],
});
});
it('parses path for milestone with trailing +', () => {
expect(
queryData('milestone_title=A%2B', {}),
).toEqual({
milestone_title: 'A+',
});
});
it('parses path for search terms with spaces', () => {
expect(
queryData('search=two+words', {}),
).toEqual({
search: 'two words',
});
});
});
...@@ -29,24 +29,46 @@ describe('common_utils', () => { ...@@ -29,24 +29,46 @@ describe('common_utils', () => {
}); });
}); });
describe('getUrlParamsArray', () => { describe('urlParamsToArray', () => {
it('should return params array', () => { it('returns empty array for empty querystring', () => {
expect(commonUtils.getUrlParamsArray() instanceof Array).toBe(true); expect(commonUtils.urlParamsToArray('')).toEqual([]);
});
it('should decode params', () => {
expect(
commonUtils.urlParamsToArray('?label_name%5B%5D=test')[0],
).toBe('label_name[]=test');
}); });
it('should remove the question mark from the search params', () => { it('should remove the question mark from the search params', () => {
const paramsArray = commonUtils.getUrlParamsArray(); const paramsArray = commonUtils.urlParamsToArray('?test=thing');
expect(paramsArray[0][0] !== '?').toBe(true); expect(paramsArray[0][0] !== '?').toBe(true);
}); });
});
it('should decode params', () => { describe('urlParamsToObject', () => {
window.history.pushState('', '', '?label_name%5B%5D=test'); it('parses path for label with trailing +', () => {
expect(
commonUtils.urlParamsToObject('label_name[]=label%2B', {}),
).toEqual({
label_name: ['label+'],
});
});
it('parses path for milestone with trailing +', () => {
expect( expect(
commonUtils.getUrlParamsArray()[0], commonUtils.urlParamsToObject('milestone_title=A%2B', {}),
).toBe('label_name[]=test'); ).toEqual({
milestone_title: 'A+',
});
});
window.history.pushState('', '', '?'); it('parses path for search terms with spaces', () => {
expect(
commonUtils.urlParamsToObject('search=two+words', {}),
).toEqual({
search: 'two words',
});
}); });
}); });
......
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