Commit 378790eb authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Extract helpers for filter and pagination params

Extracts some shared helpers for retrieving
filter and pagination data from query parameters
parent 6bb96f42
import dateFormat from 'dateformat';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { dateFormats } from './constants';
export const filterBySearchTerm = (data = [], searchTerm = '', filterByKey = 'name') => {
......@@ -7,3 +8,45 @@ export const filterBySearchTerm = (data = [], searchTerm = '', filterByKey = 'na
};
export const toYmd = (date) => dateFormat(date, dateFormats.isoDate);
/**
* Takes a url and extracts query parameters used for the shared
* filter bar
*
* @param {string} url The URL to extract query parameters from
* @returns {Object}
*/
export const extractFilterQueryParameters = (url = '') => {
const {
source_branch_name = null,
target_branch_name = null,
author_username = null,
milestone_title = null,
assignee_username = [],
label_name = [],
} = urlQueryToFilter(url);
return {
selectedSourceBranch: source_branch_name,
selectedTargetBranch: target_branch_name,
selectedAuthor: author_username,
selectedMilestone: milestone_title,
selectedAssigneeList: assignee_username,
selectedLabelList: label_name,
};
};
/**
* Takes a url and extracts sorting and pagination query parameters into an object
*
* @param {string} url The URL to extract query parameters from
* @returns {Object}
*/
export const extractPaginationQueryParameters = (url = '') => {
const { sort, direction, page } = urlQueryToFilter(url);
return {
sort: sort?.value || null,
direction: direction?.value || null,
page: page?.value || null,
};
};
import Vue from 'vue';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { extractFilterQueryParameters } from '~/analytics/shared/utils';
import CodeAnalyticsApp from './components/app.vue';
import store from './store';
......@@ -20,11 +20,11 @@ export default () => {
labelsEndpoint: labelsPath,
projectEndpoint: projectPath,
});
const { milestone_title = null, label_name = [] } = urlQueryToFilter(window.location.search);
store.dispatch('filters/initialize', {
selectedMilestone: milestone_title,
selectedLabelList: label_name,
});
const { selectedMilestone, selectedLabelList } = extractFilterQueryParameters(
window.location.search,
);
store.dispatch('filters/initialize', { selectedMilestone, selectedLabelList });
// eslint-disable-next-line no-new
new Vue({
......
......@@ -2,7 +2,10 @@ import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import {
extractFilterQueryParameters,
extractPaginationQueryParameters,
} from '~/analytics/shared/utils';
import { buildCycleAnalyticsInitialData } from '../shared/utils';
import CycleAnalytics from './components/base.vue';
import createStore from './store';
......@@ -20,27 +23,21 @@ export default () => {
const initialData = buildCycleAnalyticsInitialData(el.dataset);
const store = createStore();
const pagination = extractPaginationQueryParameters(window.location.search);
const {
author_username = null,
milestone_title = null,
assignee_username = [],
label_name = [],
sort,
direction,
page,
} = urlQueryToFilter(window.location.search);
selectedAuthor,
selectedMilestone,
selectedAssigneeList,
selectedLabelList,
} = extractFilterQueryParameters(window.location.search);
store.dispatch('initializeCycleAnalytics', {
...initialData,
selectedAuthor: author_username,
selectedMilestone: milestone_title,
selectedAssigneeList: assignee_username,
selectedLabelList: label_name,
pagination: {
sort: sort?.value || null,
direction: direction?.value || null,
page: page?.value || null,
},
selectedAuthor,
selectedMilestone,
selectedAssigneeList,
selectedLabelList,
pagination,
});
return new Vue({
......
......@@ -3,7 +3,7 @@ import VueApollo from 'vue-apollo';
import { ITEM_TYPE } from '~/groups/constants';
import createDefaultClient from '~/lib/graphql';
import { getParameterValues } from '~/lib/utils/url_utility';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { extractFilterQueryParameters } from '~/analytics/shared/utils';
import MergeRequestAnalyticsApp from './components/app.vue';
import createStore from './store';
import { parseAndValidateDates } from './utils';
......@@ -28,21 +28,23 @@ export default () => {
groupEndpoint: type === ITEM_TYPE.GROUP ? fullPath : null,
projectEndpoint: type === ITEM_TYPE.PROJECT ? fullPath : null,
});
const {
source_branch_name = null,
target_branch_name = null,
assignee_username = null,
author_username = null,
milestone_title = null,
label_name = [],
} = urlQueryToFilter(window.location.search);
selectedSourceBranch,
selectedTargetBranch,
selectedAssignee,
selectedAuthor,
selectedMilestone,
selectedLabelList,
} = extractFilterQueryParameters(window.location.search);
store.dispatch('filters/initialize', {
selectedSourceBranch: source_branch_name,
selectedTargetBranch: target_branch_name,
selectedAssignee: assignee_username,
selectedAuthor: author_username,
selectedMilestone: milestone_title,
selectedLabelList: label_name,
selectedSourceBranch,
selectedTargetBranch,
selectedAssignee,
selectedAuthor,
selectedMilestone,
selectedLabelList,
});
const { startDate, endDate } = parseAndValidateDates(
......
import { filterBySearchTerm } from '~/analytics/shared/utils';
import {
filterBySearchTerm,
extractFilterQueryParameters,
extractPaginationQueryParameters,
} from '~/analytics/shared/utils';
import { objectToQuery } from '~/lib/utils/url_utility';
describe('filterBySearchTerm', () => {
const data = [
......@@ -22,3 +27,102 @@ describe('filterBySearchTerm', () => {
expect(filterBySearchTerm(data, 'ne', 'title')).toEqual([data[0]]);
});
});
describe('extractFilterQueryParameters', () => {
const selectedAuthor = 'Author 1';
const selectedMilestone = 'Milestone 1.0';
const selectedSourceBranch = 'main';
const selectedTargetBranch = 'feature-1';
const selectedAssigneeList = ['Alice', 'Bob'];
const selectedLabelList = ['Label 1', 'Label 2'];
const queryParamsString = objectToQuery({
source_branch_name: selectedSourceBranch,
target_branch_name: selectedTargetBranch,
author_username: selectedAuthor,
milestone_title: selectedMilestone,
assignee_username: selectedAssigneeList,
label_name: selectedLabelList,
});
it('extracts the correct filter parameters from a url', () => {
const result = extractFilterQueryParameters(queryParamsString);
const operator = '=';
const expectedFilters = {
selectedAssigneeList: { operator, value: selectedAssigneeList.join(',') },
selectedLabelList: { operator, value: selectedLabelList.join(',') },
selectedAuthor: { operator, value: selectedAuthor },
selectedMilestone: { operator, value: selectedMilestone },
selectedSourceBranch: { operator, value: selectedSourceBranch },
selectedTargetBranch: { operator, value: selectedTargetBranch },
};
expect(result).toMatchObject(expectedFilters);
});
it('returns null for missing parameters', () => {
const result = extractFilterQueryParameters('');
const expectedFilters = {
selectedAuthor: null,
selectedMilestone: null,
selectedSourceBranch: null,
selectedTargetBranch: null,
};
expect(result).toMatchObject(expectedFilters);
});
it('only returns the parameters we expect', () => {
const result = extractFilterQueryParameters('foo="one"&bar="two"');
const resultKeys = Object.keys(result);
['foo', 'bar'].forEach((key) => {
expect(resultKeys).not.toContain(key);
});
[
'selectedAuthor',
'selectedMilestone',
'selectedSourceBranch',
'selectedTargetBranch',
'selectedAssigneeList',
'selectedLabelList',
].forEach((key) => {
expect(resultKeys).toContain(key);
});
});
it('returns an empty array for missing list parameters', () => {
const result = extractFilterQueryParameters('');
const expectedFilters = { selectedAssigneeList: [], selectedLabelList: [] };
expect(result).toMatchObject(expectedFilters);
});
});
describe('extractPaginationQueryParameters', () => {
const sort = 'title';
const direction = 'asc';
const page = '1';
const queryParamsString = objectToQuery({ sort, direction, page });
it('extracts the correct filter parameters from a url', () => {
const result = extractPaginationQueryParameters(queryParamsString);
const expectedFilters = { sort, page, direction };
expect(result).toMatchObject(expectedFilters);
});
it('returns null for missing parameters', () => {
const result = extractPaginationQueryParameters('');
const expectedFilters = { sort: null, direction: null, page: null };
expect(result).toMatchObject(expectedFilters);
});
it('only returns the parameters we expect', () => {
const result = extractPaginationQueryParameters('foo="one"&bar="two"&qux="three"');
const resultKeys = Object.keys(result);
['foo', 'bar', 'qux'].forEach((key) => {
expect(resultKeys).not.toContain(key);
});
['sort', 'page', 'direction'].forEach((key) => {
expect(resultKeys).toContain(key);
});
});
});
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