From ad31ff822027745cf785f857613b24b775d0ba99 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Tue, 20 Jun 2017 15:28:20 +0200 Subject: [PATCH] SONAR-9402 Filter activity list based on a date range in the project activity page --- .../__snapshots__/actions-test.js.snap | 14 ++++----- .../projectActivity/__tests__/actions-test.js | 6 ++-- .../components/ProjectActivityApp.js | 12 +++++--- .../components/ProjectActivityAppContainer.js | 8 ++++- .../__tests__/ProjectActivityApp-test.js | 20 ++++++++++--- .../components/__tests__/StaticGraphs-test.js | 6 ++-- .../ProjectActivityApp-test.js.snap | 30 +++++++++++++------ .../src/main/js/apps/projectActivity/types.js | 6 ++-- .../src/main/js/apps/projectActivity/utils.js | 20 ++++++++++--- .../__snapshots__/query-test.js.snap | 2 ++ .../main/js/helpers/__tests__/query-test.js | 18 +++++++++++ server/sonar-web/src/main/js/helpers/query.js | 14 +++++++++ 12 files changed, 119 insertions(+), 37 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/actions-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/actions-test.js.snap index 2e1d7d96c09..10cb48ebfeb 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/actions-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/actions-test.js.snap @@ -2,7 +2,7 @@ exports[`addCustomEvent should correctly add a custom event 1`] = ` Object { - "date": "2016-10-27T12:21:15+0200", + "date": 2016-10-27T10:21:15.000Z, "events": Array [ Object { "category": "Custom", @@ -16,7 +16,7 @@ Object { exports[`changeEvent should correctly update an event 1`] = ` Object { - "date": "2016-10-27T16:33:50+0200", + "date": 2016-10-27T14:33:50.000Z, "events": Array [ Object { "category": "VERSION", @@ -31,12 +31,12 @@ Object { exports[`deleteAnalysis should correctly delete an analyses 1`] = ` Array [ Object { - "date": "2016-10-27T12:21:15+0200", + "date": 2016-10-27T10:21:15.000Z, "events": Array [], "key": "A2", }, Object { - "date": "2016-10-26T12:17:29+0200", + "date": 2016-10-26T10:17:29.000Z, "events": Array [ Object { "category": "OTHER", @@ -56,7 +56,7 @@ Array [ exports[`deleteEvent should correctly remove an event 1`] = ` Object { - "date": "2016-10-27T16:33:50+0200", + "date": 2016-10-27T14:33:50.000Z, "events": Array [], "key": "A1", } @@ -64,7 +64,7 @@ Object { exports[`deleteEvent should correctly remove an event 2`] = ` Object { - "date": "2016-10-27T12:21:15+0200", + "date": 2016-10-27T10:21:15.000Z, "events": Array [], "key": "A2", } @@ -72,7 +72,7 @@ Object { exports[`deleteEvent should correctly remove an event 3`] = ` Object { - "date": "2016-10-26T12:17:29+0200", + "date": 2016-10-26T10:17:29.000Z, "events": Array [ Object { "category": "OTHER", diff --git a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js index c725c76d22c..c28dfae5210 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/__tests__/actions-test.js @@ -23,7 +23,7 @@ import * as actions from '../actions'; const ANALYSES = [ { key: 'A1', - date: '2016-10-27T16:33:50+0200', + date: new Date('2016-10-27T16:33:50+0200'), events: [ { key: 'E1', @@ -34,12 +34,12 @@ const ANALYSES = [ }, { key: 'A2', - date: '2016-10-27T12:21:15+0200', + date: new Date('2016-10-27T12:21:15+0200'), events: [] }, { key: 'A3', - date: '2016-10-26T12:17:29+0200', + date: new Date('2016-10-26T12:17:29+0200'), events: [ { key: 'E2', diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js index 266a7bf55fa..5419cf50e10 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js @@ -70,12 +70,16 @@ export default class ProjectActivityApp extends React.PureComponent { } filterAnalyses = (analyses: Array, query: Query): Array => { - if (!query.category) { + if (!query.category && !query.from && !query.to) { return analyses; } - return analyses.filter( - analysis => analysis.events.find(event => event.category === query.category) != null - ); + return analyses.filter(analysis => { + const isAfterFrom = !query.from || analysis.date >= query.from; + const isBeforeTo = !query.to || analysis.date <= query.to; + const hasSelectedCategoryEvents = + !query.category || analysis.events.find(event => event.category === query.category) != null; + return isAfterFrom && isBeforeTo && hasSelectedCategoryEvents; + }); }; getMetricType = () => { diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js index b6f96b945cf..22f52f533e5 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js @@ -137,7 +137,13 @@ class ProjectActivityAppContainer extends React.PureComponent { } ): Promise<{ analyses: Array, paging: Paging }> => { const parameters = { project, p, ps }; - return api.getProjectActivity({ ...parameters, ...additional }).catch(throwGlobalError); + return api.getProjectActivity({ ...parameters, ...additional }).then( + ({ analyses, paging }) => ({ + analyses: analyses.map(analysis => ({ ...analysis, date: moment(analysis.date).toDate() })), + paging + }), + throwGlobalError + ); }; fetchMeasuresHistory = (metrics: Array): Promise> => diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js index d1a695af5da..e6122763349 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js @@ -24,7 +24,7 @@ import ProjectActivityApp from '../ProjectActivityApp'; const ANALYSES = [ { key: 'A1', - date: '2016-10-27T16:33:50+0200', + date: new Date('2016-10-27T16:33:50+0200'), events: [ { key: 'E1', @@ -35,12 +35,12 @@ const ANALYSES = [ }, { key: 'A2', - date: '2016-10-27T12:21:15+0200', + date: new Date('2016-10-27T12:21:15+0200'), events: [] }, { key: 'A3', - date: '2016-10-26T12:17:29+0200', + date: new Date('2016-10-26T12:17:29+0200'), events: [ { key: 'E2', @@ -86,8 +86,20 @@ it('should render correctly', () => { expect(shallow()).toMatchSnapshot(); }); -it('should correctly filter analyses', () => { +it('should correctly filter analyses by category', () => { const wrapper = mount(); wrapper.setProps({ query: { ...DEFAULT_PROPS.query, category: 'VERSION' } }); expect(wrapper.state()).toMatchSnapshot(); }); + +it('should correctly filter analyses by date range', () => { + const wrapper = mount(); + wrapper.setProps({ + query: { + ...DEFAULT_PROPS.query, + from: new Date('2016-10-27T12:21:15+0200'), + to: new Date('2016-10-27T12:21:15+0200') + } + }); + expect(wrapper.state()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js index ae7a7fcd09e..47984030882 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js @@ -24,7 +24,7 @@ import StaticGraphs from '../StaticGraphs'; const ANALYSES = [ { key: 'A1', - date: '2016-10-27T16:33:50+0200', + date: new Date('2016-10-27T16:33:50+0200'), events: [ { key: 'E1', @@ -35,12 +35,12 @@ const ANALYSES = [ }, { key: 'A2', - date: '2016-10-27T12:21:15+0200', + date: new Date('2016-10-27T12:21:15+0200'), events: [] }, { key: 'A3', - date: '2016-10-26T12:17:29+0200', + date: new Date('2016-10-26T12:17:29+0200'), events: [ { key: 'E2', diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap index 34a8cc87852..c34ab47e81c 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should correctly filter analyses 1`] = ` +exports[`should correctly filter analyses by category 1`] = ` Object { "filteredAnalyses": Array [ Object { - "date": "2016-10-27T16:33:50+0200", + "date": 2016-10-27T14:33:50.000Z, "events": Array [ Object { "category": "VERSION", @@ -15,7 +15,7 @@ Object { "key": "A1", }, Object { - "date": "2016-10-26T12:17:29+0200", + "date": 2016-10-26T10:17:29.000Z, "events": Array [ Object { "category": "VERSION", @@ -34,6 +34,18 @@ Object { } `; +exports[`should correctly filter analyses by date range 1`] = ` +Object { + "filteredAnalyses": Array [ + Object { + "date": 2016-10-27T10:21:15.000Z, + "events": Array [], + "key": "A2", + }, + ], +} +`; + exports[`should render correctly 1`] = `
}; @@ -50,6 +50,8 @@ export type Paging = { export type Query = { category: string, + from?: Date, graph: string, - project: string + project: string, + to?: Date }; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/utils.js b/server/sonar-web/src/main/js/apps/projectActivity/utils.js index d24e209c645..c4d1b9239fa 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/utils.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/utils.js @@ -18,7 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // @flow -import { cleanQuery, parseAsString, serializeString } from '../../helpers/query'; +import { + cleanQuery, + parseAsDate, + parseAsString, + serializeDate, + serializeString +} from '../../helpers/query'; import { translate } from '../../helpers/l10n'; import type { MeasureHistory, Query } from './types'; import type { RawQuery } from '../../helpers/query'; @@ -41,8 +47,10 @@ const serializeGraph = (value: string): string => (value === 'overview' ? '' : v export const parseQuery = (urlQuery: RawQuery): Query => ({ category: parseAsString(urlQuery['category']), + from: parseAsDate(urlQuery['from']), graph: parseGraph(urlQuery['graph']), - project: parseAsString(urlQuery['id']) + project: parseAsString(urlQuery['id']), + to: parseAsDate(urlQuery['to']) }); export const serializeQuery = (query: Query): RawQuery => @@ -54,13 +62,17 @@ export const serializeQuery = (query: Query): RawQuery => export const serializeUrlQuery = (query: Query): RawQuery => { return cleanQuery({ category: serializeString(query.category), + from: serializeDate(query.from), graph: serializeGraph(query.graph), - id: serializeString(query.project) + id: serializeString(query.project), + to: serializeDate(query.to) }); }; export const activityQueryChanged = (prevQuery: Query, nextQuery: Query): boolean => - prevQuery.category !== nextQuery.category; + prevQuery.category !== nextQuery.category || + prevQuery.from !== nextQuery.from || + prevQuery.to !== nextQuery.to; export const historyQueryChanged = (prevQuery: Query, nextQuery: Query): boolean => prevQuery.graph !== nextQuery.graph; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap index 55b274979e3..4f0b5538ba8 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap +++ b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap @@ -7,3 +7,5 @@ Object { "e": 0, } `; + +exports[`parseAsDate should parse string date correctly 1`] = `2016-06-20T13:09:48.256Z`; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js b/server/sonar-web/src/main/js/helpers/__tests__/query-test.js index 5a60b4a52c3..6ef12860f00 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js +++ b/server/sonar-web/src/main/js/helpers/__tests__/query-test.js @@ -69,6 +69,24 @@ describe('parseAsArray', () => { }); }); +describe('parseAsDate', () => { + it('should parse string date correctly', () => { + expect(query.parseAsDate('2016-06-20T13:09:48.256Z')).toMatchSnapshot(); + expect(query.parseAsDate('')).toBeFalsy(); + expect(query.parseAsDate()).toBeFalsy(); + }); +}); + +describe('serializeDate', () => { + it('should serialize string correctly', () => { + expect(query.serializeDate(new Date('2016-06-20T13:09:48.256Z'))).toBe( + '2016-06-20T13:09:48.256Z' + ); + expect(query.serializeDate('')).toBeUndefined(); + expect(query.serializeDate()).toBeUndefined(); + }); +}); + describe('serializeString', () => { it('should serialize string correctly', () => { expect(query.serializeString('foo')).toBe('foo'); diff --git a/server/sonar-web/src/main/js/helpers/query.js b/server/sonar-web/src/main/js/helpers/query.js index 6e7746d4b08..37663f2cd49 100644 --- a/server/sonar-web/src/main/js/helpers/query.js +++ b/server/sonar-web/src/main/js/helpers/query.js @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { isNil, omitBy } from 'lodash'; +import moment from 'moment'; export type RawQuery = { [string]: string }; @@ -54,6 +55,13 @@ export const cleanQuery = (query: { [string]: ?string }): RawQuery => omitBy(que export const parseAsBoolean = (value: ?string, defaultValue: boolean = true): boolean => (value === 'false' ? false : value === 'true' ? true : defaultValue); +export const parseAsDate = (value: ?string): ?Date => { + const date = moment(value); + if (value && date) { + return date.toDate(); + } +}; + export const parseAsFacetMode = (facetMode: string) => (facetMode === 'debt' || facetMode === 'effort' ? 'effort' : 'count'); @@ -62,6 +70,12 @@ export const parseAsString = (value: ?string): string => value || ''; export const parseAsArray = (value: ?string, itemParser: string => T): Array => (value ? value.split(',').map(itemParser) : []); +export const serializeDate = (value: ?Date): ?string => { + if (value != null && value.toISOString) { + return value.toISOString(); + } +}; + export const serializeString = (value: string): ?string => value || undefined; export const serializeStringArray = (value: ?Array): ?string => -- 2.39.5