aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-07-11 08:07:28 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-07-13 14:34:17 +0200
commit8746fbda0290c691705208caad6a7c2590191673 (patch)
treef5dcf2fcf5affb17e572928a87bec1d1b0f0eac5 /server
parentf0da51dc6ad711b31f92af91050357d41187eb5b (diff)
downloadsonarqube-8746fbda0290c691705208caad6a7c2590191673.tar.gz
sonarqube-8746fbda0290c691705208caad6a7c2590191673.zip
SONAR-9410 Add date selectors to the project activity page
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js7
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js72
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js28
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js18
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js34
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js8
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.js.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css2
-rw-r--r--server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js6
10 files changed, 194 insertions, 18 deletions
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 d982bc837cc..59c9485d937 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
@@ -100,7 +100,12 @@ export default class ProjectActivityApp extends React.PureComponent {
<div id="project-activity" className="page page-limited">
<Helmet title={translate('project_activity.page')} />
- <ProjectActivityPageHeader category={query.category} updateQuery={this.props.updateQuery} />
+ <ProjectActivityPageHeader
+ category={query.category}
+ from={query.from}
+ to={query.to}
+ updateQuery={this.props.updateQuery}
+ />
<div className="layout-page project-activity-page">
<div className="layout-page-side-outer project-activity-page-side-outer boxed-group">
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js
new file mode 100644
index 00000000000..82aa95a96c2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.js
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+// @flow
+import React from 'react';
+import moment from 'moment';
+import DateInput from '../../../components/controls/DateInput';
+import { parseAsDate } from '../../../helpers/query';
+import { translate } from '../../../helpers/l10n';
+import type { RawQuery } from '../../../helpers/query';
+
+type Props = {
+ from: ?Date,
+ to: ?Date,
+ onChange: RawQuery => void
+};
+
+export default class ProjectActivityDateInput extends React.PureComponent {
+ props: Props;
+
+ handleFromDateChange = (from: string) => this.props.onChange({ from: parseAsDate(from) });
+
+ handleToDateChange = (to: string) => this.props.onChange({ to: parseAsDate(to) });
+
+ handleResetClick = () => this.props.onChange({ from: null, to: null });
+
+ formatDate = (date: ?Date) => (date ? moment(date).format('YYYY-MM-DD') : null);
+
+ render() {
+ return (
+ <div>
+ <DateInput
+ className="little-spacer-right"
+ name="from"
+ value={this.formatDate(this.props.from)}
+ placeholder={translate('from')}
+ onChange={this.handleFromDateChange}
+ />
+ {'—'}
+ <DateInput
+ className="little-spacer-left"
+ name="to"
+ value={this.formatDate(this.props.to)}
+ placeholder={translate('to')}
+ onChange={this.handleToDateChange}
+ />
+ <button
+ className="spacer-left"
+ onClick={this.handleResetClick}
+ disabled={this.props.from == null && this.props.to == null}>
+ {translate('reset_verb')}
+ </button>
+ </div>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
index d6b96f42f42..8f48ceaf91e 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
@@ -69,26 +69,42 @@ export default class ProjectActivityGraphs extends React.PureComponent {
}
componentWillReceiveProps(nextProps: Props) {
+ let newSeries;
if (
nextProps.measuresHistory !== this.props.measuresHistory ||
historyQueryChanged(this.props.query, nextProps.query)
) {
- const series = generateSeries(
+ newSeries = generateSeries(
nextProps.measuresHistory,
nextProps.query.graph,
nextProps.metricsType,
getDisplayedHistoryMetrics(nextProps.query.graph, nextProps.query.customMetrics)
);
- const newDates = this.getStateZoomDates(this.props, nextProps, series);
+ }
+
+ const newDates = this.getStateZoomDates(
+ this.props,
+ nextProps,
+ newSeries ? newSeries : this.state.series
+ );
+
+ if (newSeries || newDates) {
+ let newState = {};
+ if (newSeries) {
+ newState.series = newSeries;
+ }
if (newDates) {
- this.setState({ series, ...newDates });
- } else {
- this.setState({ series });
+ newState = { ...newState, ...newDates };
}
+ this.setState(newState);
}
}
- getStateZoomDates = (props: ?Props, nextProps: Props, series: Array<Serie>) => {
+ getStateZoomDates = (
+ props: ?Props,
+ nextProps: Props,
+ series: Array<Serie>
+ ): ?{ graphEndDate: ?Date, graphStartDate: ?Date } => {
const newDates = { from: nextProps.query.from || null, to: nextProps.query.to || null };
if (props && datesQueryChanged(props.query, nextProps.query)) {
return { graphEndDate: newDates.to, graphStartDate: newDates.from };
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js
index e2f8a8569fa..ebbce83df7c 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js
@@ -22,13 +22,16 @@ import React from 'react';
import Select from 'react-select';
import ProjectActivityEventSelectOption from './ProjectActivityEventSelectOption';
import ProjectActivityEventSelectValue from './ProjectActivityEventSelectValue';
+import ProjectActivityDateInput from './ProjectActivityDateInput';
import { EVENT_TYPES } from '../utils';
import { translate } from '../../../helpers/l10n';
import type { RawQuery } from '../../../helpers/query';
type Props = {
- updateQuery: RawQuery => void,
- category?: string
+ category?: string,
+ from: ?Date,
+ to: ?Date,
+ updateQuery: RawQuery => void
};
export default class ProjectActivityPageHeader extends React.PureComponent {
@@ -43,15 +46,14 @@ export default class ProjectActivityPageHeader extends React.PureComponent {
}));
}
- handleCategoryChange = (option: ?{ value: string }) => {
+ handleCategoryChange = (option: ?{ value: string }) =>
this.props.updateQuery({ category: option ? option.value : '' });
- };
render() {
return (
<header className="page-header">
<Select
- className="input-medium"
+ className="input-medium pull-left spacer-right"
placeholder={translate('project_activity.filter_events') + '...'}
clearable={true}
searchable={false}
@@ -61,6 +63,12 @@ export default class ProjectActivityPageHeader extends React.PureComponent {
options={this.options}
onChange={this.handleCategoryChange}
/>
+ <ProjectActivityDateInput
+ className="pull-left"
+ from={this.props.from}
+ to={this.props.to}
+ onChange={this.props.updateQuery}
+ />
</header>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js
new file mode 100644
index 00000000000..fa199664561
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityDateInput-test.js
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import ProjectActivityDateInput from '../ProjectActivityDateInput';
+
+it('should render correctly the date inputs', () => {
+ expect(
+ shallow(
+ <ProjectActivityDateInput
+ from={new Date('2016-10-27T12:21:15+0000')}
+ to={new Date('2016-12-27T12:21:15+0000')}
+ onChange={() => {}}
+ />
+ )
+ ).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js
index e0925df3ff0..9fe17ba339a 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.js
@@ -23,6 +23,12 @@ import ProjectActivityPageHeader from '../ProjectActivityPageHeader';
it('should render correctly the list of series', () => {
expect(
- shallow(<ProjectActivityPageHeader category="" updateQuery={() => {}} />)
+ shallow(
+ <ProjectActivityPageHeader
+ category=""
+ from={new Date('2016-10-27T12:21:15+0200')}
+ updateQuery={() => {}}
+ />
+ )
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap
new file mode 100644
index 00000000000..438df209b7f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly the date inputs 1`] = `
+<div>
+ <DateInput
+ className="little-spacer-right"
+ format="yy-mm-dd"
+ name="from"
+ onChange={[Function]}
+ placeholder="from"
+ value="2016-10-27"
+ />
+ —
+ <DateInput
+ className="little-spacer-left"
+ format="yy-mm-dd"
+ name="to"
+ onChange={[Function]}
+ placeholder="to"
+ value="2016-12-27"
+ />
+ <button
+ className="spacer-left"
+ disabled={false}
+ onClick={[Function]}
+ >
+ reset_verb
+ </button>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.js.snap
index 19fc3e8375b..a185ef12c0c 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.js.snap
@@ -10,7 +10,7 @@ exports[`should render correctly the list of series 1`] = `
autosize={true}
backspaceRemoves={true}
backspaceToRemoveMessage="Press backspace to remove {label}"
- className="input-medium"
+ className="input-medium pull-left spacer-right"
clearAllText="Clear all"
clearValueText="Clear value"
clearable={true}
@@ -66,5 +66,10 @@ exports[`should render correctly the list of series 1`] = `
valueComponent={[Function]}
valueKey="value"
/>
+ <ProjectActivityDateInput
+ className="pull-left"
+ from={2016-10-27T10:21:15.000Z}
+ onChange={[Function]}
+ />
</header>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
index 740aef24ba3..5833f26d7ce 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
@@ -239,7 +239,7 @@
left: 12px;
right: 16px;
padding-top: 24px;
- z-index: 100;
+ z-index: 1;
}
.project-activity-version-badge.sticky + .project-activity-days-list {
diff --git a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
index 2f657229c61..692a2406ba2 100644
--- a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
+++ b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
@@ -131,10 +131,10 @@ export default class AdvancedTimeline extends React.PureComponent {
}
};
- getXScale = (props: Props, availableWidth: number, flatData: Array<Point>) => {
+ getXScale = ({ startDate, endDate }: Props, availableWidth: number, flatData: Array<Point>) => {
const dateRange = extent(flatData, d => d.x);
- const start = props.startDate ? props.startDate : dateRange[0];
- const end = props.endDate ? props.endDate : dateRange[1];
+ const start = startDate && startDate > dateRange[0] ? startDate : dateRange[0];
+ const end = endDate && endDate < dateRange[1] ? endDate : dateRange[1];
const xScale = scaleTime().domain(sortBy([start, end])).range([0, availableWidth]).clamp(false);
return {
xScale,