Commit 0e505c3c authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'mw-productivity-analytics-daterange-picker' into 'master'

Productivity Analytics: Replace timeframe dropdown with daterange picker

See merge request gitlab-org/gitlab!16493
parents 604bb3e1 f0184781
<script>
import { mapState, mapActions } from 'vuex';
import { GlDaterangePicker } from '@gitlab/ui';
import { getDateInPast } from '~/lib/utils/datetime_utility';
import { defaultDaysInPast } from '../constants';
export default {
components: {
GlDaterangePicker,
},
computed: {
...mapState('filters', ['groupNamespace', 'startDate', 'endDate']),
dateRange: {
get() {
return { startDate: this.startDate, endDate: this.endDate };
},
set({ startDate, endDate }) {
this.setDateRange({ startDate, endDate });
},
},
},
mounted() {
this.initDateRange();
},
methods: {
...mapActions('filters', ['setDateRange']),
initDateRange() {
const endDate = new Date(Date.now());
const startDate = new Date(getDateInPast(endDate, defaultDaysInPast));
// let's not fetch data since we might not have a groupNamespace selected yet
// this just populates the store with the initial data and waits for a groupNamespace to be set
this.setDateRange({ skipFetch: true, startDate, endDate });
},
},
};
</script>
<template>
<div
v-if="groupNamespace"
class="daterange-container d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-end"
>
<gl-daterange-picker
v-model="dateRange"
class="d-flex flex-column flex-lg-row"
:default-start-date="startDate"
:default-end-date="endDate"
theme="animate-picker"
start-picker-class="d-flex flex-column flex-lg-row align-items-lg-center mr-lg-2 mb-2 mb-md-0"
end-picker-class="d-flex flex-column flex-lg-row align-items-lg-center"
/>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import DateRangeDropdown from '../../shared/components/date_range_dropdown.vue';
export default {
components: {
DateRangeDropdown,
},
computed: {
...mapState('filters', ['groupNamespace', 'daysInPast']),
},
methods: {
...mapActions('filters', ['setDaysInPast']),
},
};
</script>
<template>
<div
v-if="groupNamespace"
class="dropdown-container d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-end"
>
<label class="mb-0 mr-1">{{ s__('Analytics|Timeframe') }}</label>
<date-range-dropdown :default-selected="daysInPast" @selected="setDaysInPast" />
</div>
</template>
...@@ -91,5 +91,5 @@ export const columnHighlightStyle = { color: '#418cd8', opacity: 0.8 }; ...@@ -91,5 +91,5 @@ export const columnHighlightStyle = { color: '#418cd8', opacity: 0.8 };
export const scatterPlotAddonQueryDays = 30; export const scatterPlotAddonQueryDays = 30;
export const accessLevelReporter = 20; export const accessLevelReporter = 20;
export const projectsPerPage = 50; export const projectsPerPage = 50;
export const defaultDaysInPast = 90;
import Vue from 'vue'; import Vue from 'vue';
import store from './store'; import store from './store';
import FilterDropdowns from './components/filter_dropdowns.vue'; import FilterDropdowns from './components/filter_dropdowns.vue';
import TimeFrameDropdown from './components/timeframe_dropdown.vue'; import DateRange from './components/daterange.vue';
import ProductivityAnalyticsApp from './components/app.vue'; import ProductivityAnalyticsApp from './components/app.vue';
import FilteredSearchProductivityAnalytics from './filtered_search_productivity_analytics'; import FilteredSearchProductivityAnalytics from './filtered_search_productivity_analytics';
import { getLabelsEndpoint, getMilestonesEndpoint } from './utils'; import { getLabelsEndpoint, getMilestonesEndpoint } from './utils';
...@@ -71,7 +71,7 @@ export default () => { ...@@ -71,7 +71,7 @@ export default () => {
el: timeframeContainer, el: timeframeContainer,
store, store,
render(h) { render(h) {
return h(TimeFrameDropdown, {}); return h(DateRange, {});
}, },
}); });
......
import _ from 'underscore'; import _ from 'underscore';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { getDateInPast } from '~/lib/utils/datetime_utility';
import { import {
chartKeys, chartKeys,
metricTypes, metricTypes,
...@@ -54,6 +53,7 @@ export const getColumnChartData = state => chartKey => { ...@@ -54,6 +53,7 @@ export const getColumnChartData = state => chartKey => {
}; };
export const chartHasData = state => chartKey => !_.isEmpty(state.charts[chartKey].data); export const chartHasData = state => chartKey => !_.isEmpty(state.charts[chartKey].data);
/** /**
* Creates a series array of main data for the scatterplot chart. * Creates a series array of main data for the scatterplot chart.
* *
...@@ -72,13 +72,10 @@ export const chartHasData = state => chartKey => !_.isEmpty(state.charts[chartKe ...@@ -72,13 +72,10 @@ export const chartHasData = state => chartKey => !_.isEmpty(state.charts[chartKe
* ["2019-07-10T11:13:23.557Z", 139], * ["2019-07-10T11:13:23.557Z", 139],
* ] * ]
* *
* It eliminates items which were merged before today minus the selected daysInPast. * It eliminates items which were merged before the startDate (minus an additional days offset).
*/ */
export const getScatterPlotMainData = (state, getters, rootState) => { export const getScatterPlotMainData = (state, getters, rootState) =>
const { data } = state.charts.scatterplot; getScatterPlotData(state.charts.scatterplot.data, rootState.filters.startDate);
const dateInPast = getDateInPast(new Date(), rootState.filters.daysInPast);
return getScatterPlotData(data, dateInPast);
};
/** /**
* Creates a series array of median data for the scatterplot chart. * Creates a series array of median data for the scatterplot chart.
......
...@@ -53,8 +53,10 @@ export const setPath = ({ commit, dispatch }, path) => { ...@@ -53,8 +53,10 @@ export const setPath = ({ commit, dispatch }, path) => {
}); });
}; };
export const setDaysInPast = ({ commit, dispatch }, days) => { export const setDateRange = ({ commit, dispatch }, { skipFetch = false, startDate, endDate }) => {
commit(types.SET_DAYS_IN_PAST, days); commit(types.SET_DATE_RANGE, { startDate, endDate });
if (skipFetch) return false;
dispatch( dispatch(
'charts/updateSelectedItems', 'charts/updateSelectedItems',
......
import dateFormat from 'dateformat';
import { urlParamsToObject } from '~/lib/utils/common_utils'; import { urlParamsToObject } from '~/lib/utils/common_utils';
import { getDateInPast } from '~/lib/utils/datetime_utility';
import { chartKeys, scatterPlotAddonQueryDays } from '../../../constants'; import { chartKeys, scatterPlotAddonQueryDays } from '../../../constants';
import { dateFormats } from '../../../../shared/constants';
/** /**
* Returns an object of common filter parameters based on the filter's state * Returns an object of common filter parameters based on the filter's state
...@@ -12,19 +15,23 @@ import { chartKeys, scatterPlotAddonQueryDays } from '../../../constants'; ...@@ -12,19 +15,23 @@ import { chartKeys, scatterPlotAddonQueryDays } from '../../../constants';
* author_username: 'author', * author_username: 'author',
* milestone_title: 'my milestone', * milestone_title: 'my milestone',
* label_name: ['my label', 'yet another label'], * label_name: ['my label', 'yet another label'],
* merged_at_after: '2019-05-09T16:20:18.393Z' * merged_at_after: '2019-06-11'
* merged_at_before: '2019-09-09'
* } * }
* *
*/ */
export const getCommonFilterParams = state => chartKey => { export const getCommonFilterParams = state => chartKey => {
const { groupNamespace, projectPath, filters } = state; const { groupNamespace, projectPath, filters, startDate, endDate } = state;
const { author_username, milestone_title, label_name } = urlParamsToObject(filters); const { author_username, milestone_title, label_name } = urlParamsToObject(filters);
// for the scatterplot we need to add additional 30 days to the desired date in the past // for the scatterplot we need to remove 30 days from the state's merged_at_after date
const daysInPast = const mergedAtAfterDate =
chartKey && chartKey === chartKeys.scatterplot chartKey && chartKey === chartKeys.scatterplot
? state.daysInPast + scatterPlotAddonQueryDays ? dateFormat(
: state.daysInPast; new Date(getDateInPast(new Date(startDate), scatterPlotAddonQueryDays)),
dateFormats.isoDate,
)
: dateFormat(startDate, dateFormats.isoDate);
return { return {
group_id: groupNamespace, group_id: groupNamespace,
...@@ -32,7 +39,8 @@ export const getCommonFilterParams = state => chartKey => { ...@@ -32,7 +39,8 @@ export const getCommonFilterParams = state => chartKey => {
author_username, author_username,
milestone_title, milestone_title,
label_name, label_name,
merged_at_after: `${daysInPast}days`, merged_at_after: mergedAtAfterDate,
merged_at_before: dateFormat(endDate, dateFormats.isoDate),
}; };
}; };
......
export const SET_GROUP_NAMESPACE = 'SET_GROUP_NAMESPACE'; export const SET_GROUP_NAMESPACE = 'SET_GROUP_NAMESPACE';
export const SET_PROJECT_PATH = 'SET_PROJECT_PATH'; export const SET_PROJECT_PATH = 'SET_PROJECT_PATH';
export const SET_PATH = 'SET_PATH'; export const SET_PATH = 'SET_PATH';
export const SET_DAYS_IN_PAST = 'SET_DAYS_IN_PAST'; export const SET_DATE_RANGE = 'SET_DATE_RANGE';
...@@ -11,7 +11,8 @@ export default { ...@@ -11,7 +11,8 @@ export default {
[types.SET_PATH](state, path) { [types.SET_PATH](state, path) {
state.filters = path; state.filters = path;
}, },
[types.SET_DAYS_IN_PAST](state, daysInPast) { [types.SET_DATE_RANGE](state, { startDate, endDate }) {
state.daysInPast = daysInPast; state.startDate = startDate;
state.endDate = endDate;
}, },
}; };
...@@ -2,5 +2,6 @@ export default () => ({ ...@@ -2,5 +2,6 @@ export default () => ({
groupNamespace: null, groupNamespace: null,
projectPath: null, projectPath: null,
filters: '', filters: '',
daysInPast: 90, startDate: null,
endDate: null,
}); });
...@@ -52,12 +52,12 @@ export const getMilestonesEndpoint = (namespacePath, projectPathWithNamespace) = ...@@ -52,12 +52,12 @@ export const getMilestonesEndpoint = (namespacePath, projectPathWithNamespace) =
* ] * ]
* *
* @param {Object} data The raw data which will be transformed * @param {Object} data The raw data which will be transformed
* @param {String} dateInPast Date string in ISO format * @param {Date} dateInPast Date in the past
* @returns {Array} The transformed data array sorted by date ascending * @returns {Array} The transformed data array sorted by date ascending
*/ */
export const getScatterPlotData = (data, dateInPast) => export const getScatterPlotData = (data, dateInPast) =>
Object.keys(data) Object.keys(data)
.filter(key => new Date(data[key].merged_at) >= new Date(dateInPast)) .filter(key => new Date(data[key].merged_at) >= dateInPast)
.map(key => [data[key].merged_at, data[key].metric]) .map(key => [data[key].merged_at, data[key].metric])
.sort((a, b) => new Date(a[0]) - new Date(b[0])); .sort((a, b) => new Date(a[0]) - new Date(b[0]));
......
<script> <script>
import dateFormat from 'dateformat'; import dateFormat from 'dateformat';
import { GlDiscreteScatterChart } from '@gitlab/ui/dist/charts'; import { GlDiscreteScatterChart } from '@gitlab/ui/dist/charts';
import { scatterChartLineProps, defaultDateFormat, defaultDateTimeFormat } from '../constants'; import { scatterChartLineProps, dateFormats } from '../constants';
export default { export default {
components: { components: {
...@@ -33,7 +33,7 @@ export default { ...@@ -33,7 +33,7 @@ export default {
chartOption: { chartOption: {
xAxis: { xAxis: {
axisLabel: { axisLabel: {
formatter: date => dateFormat(date, defaultDateFormat), formatter: date => dateFormat(date, dateFormats.defaultDate),
}, },
}, },
dataZoom: [ dataZoom: [
...@@ -69,7 +69,7 @@ export default { ...@@ -69,7 +69,7 @@ export default {
renderTooltip({ data }) { renderTooltip({ data }) {
const [xValue, yValue] = data; const [xValue, yValue] = data;
this.tooltipTitle = yValue; this.tooltipTitle = yValue;
this.tooltipContent = dateFormat(xValue, defaultDateTimeFormat); this.tooltipContent = dateFormat(xValue, dateFormats.defaultDateTime);
}, },
}, },
}; };
......
export const defaultDateFormat = 'mmm d, yyyy'; export const dateFormats = {
export const defaultDateTimeFormat = 'mmm d, yyyy h:MMtt'; isoDate: 'yyyy-mm-dd',
defaultDate: 'mmm d, yyyy',
defaultDateTime: 'mmm d, yyyy h:MMtt',
};
/** /**
* #1f78d1 --> $blue-500 (see variables.scss) * #1f78d1 --> $blue-500 (see variables.scss)
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
} }
.filter-container { .filter-container {
flex: 1 1 50%; flex: 1 1 35%;
width: 50%; width: 35%;
@include media-breakpoint-down(md) { @include media-breakpoint-down(md) {
width: 100%; width: 100%;
...@@ -38,6 +38,32 @@ ...@@ -38,6 +38,32 @@
} }
} }
.daterange-container {
flex: 1 1 30%;
width: 30%;
@include media-breakpoint-down(md) {
width: 100%;
}
.gl-daterange-picker {
.gl-datepicker-input {
width: 140px;
@include media-breakpoint-down(md) {
width: 100%;
}
}
label {
@include media-breakpoint-up(lg) {
margin-bottom: 0;
margin-right: $gl-padding-4;
}
}
}
}
.metric-dropdown { .metric-dropdown {
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
width: 100%; width: 100%;
......
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import AxiosMockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Daterange from 'ee/analytics/productivity_analytics/components/daterange.vue';
import store from 'ee/analytics/productivity_analytics/store';
import { GlDaterangePicker } from '@gitlab/ui';
import resetStore from '../helpers';
const localVue = createLocalVue();
localVue.use(Vuex);
const startDate = new Date(2019, 8, 1);
const endDate = new Date(2019, 8, 11);
const groupNamespace = 'gitlab-org';
describe('Daterange component', () => {
let wrapper;
let axiosMock;
const actionSpies = {
setDateRange: jest.fn(),
};
const factory = (props = {}) => {
wrapper = shallowMount(localVue.extend(Daterange), {
localVue,
store,
sync: false,
propsData: { ...props },
methods: {
...actionSpies,
},
});
};
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
axiosMock.onGet(store.state.endpoint).reply(200);
jest.spyOn(global.Date, 'now').mockImplementation(() => new Date('2019-09-25T00:00:00Z'));
factory();
});
afterEach(() => {
wrapper.destroy();
resetStore(store);
axiosMock.restore();
});
const findDaterangePicker = () => wrapper.find(GlDaterangePicker);
describe('template', () => {
describe('when there is no groupNamespace set', () => {
it('does not render the daterange picker', () => {
expect(findDaterangePicker().exists()).toBe(false);
});
});
describe('when a groupNamespace is set', () => {
beforeEach(() => {
store.state.filters.groupNamespace = groupNamespace;
});
it('renders the daterange picker', () => {
expect(findDaterangePicker().exists()).toBe(true);
});
});
});
describe('mounted', () => {
describe('initDateRange', () => {
it('dispatches setDateRange with skipFetch=true', () => {
expect(actionSpies.setDateRange).toHaveBeenCalledWith({
skipFetch: true,
startDate: new Date('2019-06-27T00:00:00.000Z'),
endDate: new Date('2019-09-25T00:00:00.000Z'),
});
});
});
});
describe('computed', () => {
beforeEach(() => {
store.state.filters.groupNamespace = groupNamespace;
});
describe('dateRange', () => {
describe('set', () => {
it('calls `setDateRange` with an object containing startDate and endDate', () => {
wrapper.vm.dateRange = { startDate, endDate };
expect(actionSpies.setDateRange).toHaveBeenCalledWith({ startDate, endDate });
});
});
describe('get', () => {
beforeEach(() => {
store.state.filters.startDate = startDate;
store.state.filters.endDate = endDate;
});
it("returns value of dateRange from state's startDate and endDate", () => {
expect(wrapper.vm.dateRange).toEqual({ startDate, endDate });
});
});
});
});
});
...@@ -11,9 +11,6 @@ import { getScatterPlotData, getMedianLineData } from 'ee/analytics/productivity ...@@ -11,9 +11,6 @@ import { getScatterPlotData, getMedianLineData } from 'ee/analytics/productivity
import { mockHistogramData, mockScatterplotData } from '../../../mock_data'; import { mockHistogramData, mockScatterplotData } from '../../../mock_data';
jest.mock('ee/analytics/productivity_analytics/utils'); jest.mock('ee/analytics/productivity_analytics/utils');
jest.mock('~/lib/utils/datetime_utility', () => ({
getDateInPast: jest.fn().mockReturnValue('2019-07-16T00:00:00.00Z'),
}));
describe('Productivity analytics chart getters', () => { describe('Productivity analytics chart getters', () => {
let state; let state;
...@@ -61,16 +58,13 @@ describe('Productivity analytics chart getters', () => { ...@@ -61,16 +58,13 @@ describe('Productivity analytics chart getters', () => {
const rootState = { const rootState = {
filters: { filters: {
daysInPast: 30, startDate: '2019-07-16',
}, },
}; };
getters.getScatterPlotMainData(state, null, rootState); getters.getScatterPlotMainData(state, null, rootState);
expect(getScatterPlotData).toHaveBeenCalledWith( expect(getScatterPlotData).toHaveBeenCalledWith(mockScatterplotData, '2019-07-16');
mockScatterplotData,
'2019-07-16T00:00:00.00Z',
);
}); });
}); });
......
...@@ -3,18 +3,23 @@ import * as types from 'ee/analytics/productivity_analytics/store/modules/filter ...@@ -3,18 +3,23 @@ import * as types from 'ee/analytics/productivity_analytics/store/modules/filter
import { chartKeys } from 'ee/analytics/productivity_analytics/constants'; import { chartKeys } from 'ee/analytics/productivity_analytics/constants';
describe('Productivity analytics filter actions', () => { describe('Productivity analytics filter actions', () => {
let store;
const currentYear = new Date().getFullYear();
const startDate = new Date(currentYear, 8, 1);
const endDate = new Date(currentYear, 8, 7);
const groupNamespace = 'gitlab-org'; const groupNamespace = 'gitlab-org';
const projectPath = 'gitlab-org/gitlab-test'; const projectPath = 'gitlab-org/gitlab-test';
const path = 'author_username=root'; const path = 'author_username=root';
const daysInPast = 90;
beforeEach(() => {
store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
};
});
describe('setGroupNamespace', () => { describe('setGroupNamespace', () => {
it('commits the SET_GROUP_NAMESPACE mutation', done => { it('commits the SET_GROUP_NAMESPACE mutation', done => {
const store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
};
actions actions
.setGroupNamespace(store, groupNamespace) .setGroupNamespace(store, groupNamespace)
.then(() => { .then(() => {
...@@ -47,11 +52,6 @@ describe('Productivity analytics filter actions', () => { ...@@ -47,11 +52,6 @@ describe('Productivity analytics filter actions', () => {
describe('setProjectPath', () => { describe('setProjectPath', () => {
it('commits the SET_PROJECT_PATH mutation', done => { it('commits the SET_PROJECT_PATH mutation', done => {
const store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
};
actions actions
.setProjectPath(store, projectPath) .setProjectPath(store, projectPath)
.then(() => { .then(() => {
...@@ -84,11 +84,6 @@ describe('Productivity analytics filter actions', () => { ...@@ -84,11 +84,6 @@ describe('Productivity analytics filter actions', () => {
describe('setPath', () => { describe('setPath', () => {
it('commits the SET_PATH mutation', done => { it('commits the SET_PATH mutation', done => {
const store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
};
actions actions
.setPath(store, path) .setPath(store, path)
.then(() => { .then(() => {
...@@ -119,17 +114,12 @@ describe('Productivity analytics filter actions', () => { ...@@ -119,17 +114,12 @@ describe('Productivity analytics filter actions', () => {
}); });
}); });
describe('setDaysInPast', () => { describe('setDateRange', () => {
it('commits the SET_DAYS_IN_PAST mutation', done => { it('commits the SET_DATE_RANGE mutation and fetches data by default', done => {
const store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
};
actions actions
.setDaysInPast(store, daysInPast) .setPath(store, { startDate, endDate })
.then(() => { .then(() => {
expect(store.commit).toHaveBeenCalledWith(types.SET_DAYS_IN_PAST, daysInPast); expect(store.commit).toHaveBeenCalledWith(types.SET_PATH, { startDate, endDate });
expect(store.dispatch.mock.calls[0]).toEqual([ expect(store.dispatch.mock.calls[0]).toEqual([
'charts/updateSelectedItems', 'charts/updateSelectedItems',
...@@ -154,5 +144,19 @@ describe('Productivity analytics filter actions', () => { ...@@ -154,5 +144,19 @@ describe('Productivity analytics filter actions', () => {
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it("commits the SET_DATE_RANGE mutation and doesn't fetch data when fetchData=false", done => {
actions
.setPath(store, { fetchData: false, startDate, endDate })
.then(() => {
expect(store.commit).toHaveBeenCalledWith(types.SET_PATH, {
fetchData: false,
startDate,
endDate,
});
})
.then(done)
.catch(done.fail);
});
}); });
}); });
...@@ -4,6 +4,9 @@ import { chartKeys } from 'ee/analytics/productivity_analytics/constants'; ...@@ -4,6 +4,9 @@ import { chartKeys } from 'ee/analytics/productivity_analytics/constants';
describe('Productivity analytics filter getters', () => { describe('Productivity analytics filter getters', () => {
let state; let state;
const currentYear = new Date().getFullYear();
const startDate = new Date(currentYear, 8, 1);
const endDate = new Date(currentYear, 8, 7);
beforeEach(() => { beforeEach(() => {
state = createState(); state = createState();
...@@ -15,7 +18,8 @@ describe('Productivity analytics filter getters', () => { ...@@ -15,7 +18,8 @@ describe('Productivity analytics filter getters', () => {
groupNamespace: 'gitlab-org', groupNamespace: 'gitlab-org',
projectPath: 'gitlab-org/gitlab-test', projectPath: 'gitlab-org/gitlab-test',
filters: '?author_username=root&milestone_title=foo&label_name[]=labelxyz', filters: '?author_username=root&milestone_title=foo&label_name[]=labelxyz',
daysInPast: 30, startDate,
endDate,
}; };
}); });
...@@ -25,7 +29,8 @@ describe('Productivity analytics filter getters', () => { ...@@ -25,7 +29,8 @@ describe('Productivity analytics filter getters', () => {
author_username: 'root', author_username: 'root',
group_id: 'gitlab-org', group_id: 'gitlab-org',
label_name: ['labelxyz'], label_name: ['labelxyz'],
merged_at_after: '30days', merged_at_after: '2019-09-01',
merged_at_before: '2019-09-07',
milestone_title: 'foo', milestone_title: 'foo',
project_id: 'gitlab-org/gitlab-test', project_id: 'gitlab-org/gitlab-test',
}; };
...@@ -37,12 +42,13 @@ describe('Productivity analytics filter getters', () => { ...@@ -37,12 +42,13 @@ describe('Productivity analytics filter getters', () => {
}); });
describe('when chart is scatterplot', () => { describe('when chart is scatterplot', () => {
it('returns an object with common filter params and adds additional days to the merged_at_after property', () => { it('returns an object with common filter params and subtracts 30 days from the merged_at_after date', () => {
const expected = { const expected = {
author_username: 'root', author_username: 'root',
group_id: 'gitlab-org', group_id: 'gitlab-org',
label_name: ['labelxyz'], label_name: ['labelxyz'],
merged_at_after: '60days', merged_at_after: '2019-08-02',
merged_at_before: '2019-09-07',
milestone_title: 'foo', milestone_title: 'foo',
project_id: 'gitlab-org/gitlab-test', project_id: 'gitlab-org/gitlab-test',
}; };
......
...@@ -36,12 +36,15 @@ describe('Productivity analytics filter mutations', () => { ...@@ -36,12 +36,15 @@ describe('Productivity analytics filter mutations', () => {
}); });
}); });
describe(types.SET_DAYS_IN_PAST, () => { describe(types.SET_DATE_RANGE, () => {
it('sets the daysInPast', () => { it('sets the startDate and endDate', () => {
const daysInPast = 14; const currentYear = new Date().getFullYear();
mutations[types.SET_DAYS_IN_PAST](state, daysInPast); const startDate = new Date(currentYear, 8, 1);
const endDate = new Date(currentYear, 8, 7);
expect(state.daysInPast).toBe(daysInPast); mutations[types.SET_DATE_RANGE](state, { startDate, endDate });
expect(state.startDate).toBe(startDate);
expect(state.endDate).toBe(endDate);
}); });
}); });
}); });
...@@ -37,7 +37,7 @@ describe('Productivity Analytics utils', () => { ...@@ -37,7 +37,7 @@ describe('Productivity Analytics utils', () => {
describe('getScatterPlotData', () => { describe('getScatterPlotData', () => {
it('filters out data before given "dateInPast", transforms the data and sorts by date ascending', () => { it('filters out data before given "dateInPast", transforms the data and sorts by date ascending', () => {
const dateInPast = '2019-08-09T22:00:00.000Z'; const dateInPast = new Date(2019, 7, 9); // '2019-08-09T22:00:00.000Z';
const result = getScatterPlotData(mockScatterplotData, dateInPast); const result = getScatterPlotData(mockScatterplotData, dateInPast);
const expected = [ const expected = [
['2019-08-09T22:00:00.000Z', 44], ['2019-08-09T22:00:00.000Z', 44],
......
...@@ -1617,9 +1617,6 @@ msgstr "" ...@@ -1617,9 +1617,6 @@ msgstr ""
msgid "Analytics" msgid "Analytics"
msgstr "" msgstr ""
msgid "Analytics|Timeframe"
msgstr ""
msgid "Ancestors" msgid "Ancestors"
msgstr "" msgstr ""
......
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