Browse Source

Fix a bug with the version badges when filtering on an event category

tags/6.5-RC1
Grégoire Aubert 7 years ago
parent
commit
d9f1651b8d

+ 102
- 0
server/sonar-web/src/main/js/apps/projectActivity/__tests__/__snapshots__/utils-test.js.snap View File

@@ -53,6 +53,108 @@ Array [
]
`;

exports[`getAnalysesByVersionByDay should also filter analysis based on the query 1`] = `
Array [
Object {
"byDay": Object {
"2017-4-16": Array [
Object {
"date": 2017-05-16T05:09:59.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "AVyM9oI1HjR_PLDzRciU",
"name": "1.0",
},
Object {
"category": "QUALITY_PROFILE",
"key": "AVwQF7zXl-nNFgFWOJ3W",
"name": "Changes in 'Default - SonarSource conventions' (Java)",
},
],
"key": "AVwQF7kwl-nNFgFWOJ3V",
},
],
"2017-4-18": Array [
Object {
"date": 2017-05-18T12:13:07.000Z,
"events": Array [
Object {
"category": "QUALITY_PROFILE",
"key": "AVxZtC-N7841nF4RNEMJ",
"name": "Changes in 'Default - SonarSource conventions' (Java)",
},
],
"key": "AVxZtCpH7841nF4RNEMI",
},
],
},
"key": "AVyM9oI1HjR_PLDzRciU",
"version": "1.0",
},
Object {
"byDay": Object {},
"key": undefined,
"version": undefined,
},
]
`;

exports[`getAnalysesByVersionByDay should also filter analysis based on the query 2`] = `
Array [
Object {
"byDay": Object {
"2017-5-9": Array [
Object {
"date": 2017-06-09T09:12:27.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "AVyM9oI1HjR_PLDzRciU",
"name": "1.1-SNAPSHOT",
},
],
"key": "AVyM9n3cHjR_PLDzRciT",
},
],
},
"key": "AVyM9oI1HjR_PLDzRciU",
"version": "1.1-SNAPSHOT",
},
Object {
"byDay": Object {
"2017-4-18": Array [
Object {
"date": 2017-05-18T12:13:07.000Z,
"events": Array [
Object {
"category": "QUALITY_PROFILE",
"key": "AVxZtC-N7841nF4RNEMJ",
"name": "Changes in 'Default - SonarSource conventions' (Java)",
},
],
"key": "AVxZtCpH7841nF4RNEMI",
},
],
"2017-5-9": Array [
Object {
"date": 2017-06-09T09:12:27.000Z,
"events": Array [],
"key": "AVyMjlK1HjR_PLDzRbB9",
},
],
},
"key": "AVyM9oI1HjR_PLDzRciU",
"version": "1.0",
},
Object {
"byDay": Object {},
"key": undefined,
"version": undefined,
},
]
`;

exports[`getAnalysesByVersionByDay should correctly map analysis by versions and by days 1`] = `
Array [
Object {

+ 28
- 1
server/sonar-web/src/main/js/apps/projectActivity/__tests__/utils-test.js View File

@@ -108,7 +108,34 @@ describe('generateSeries', () => {

describe('getAnalysesByVersionByDay', () => {
it('should correctly map analysis by versions and by days', () => {
expect(utils.getAnalysesByVersionByDay(ANALYSES)).toMatchSnapshot();
expect(
utils.getAnalysesByVersionByDay(ANALYSES, {
category: '',
customMetrics: [],
graph: 'overview',
project: 'foo'
})
).toMatchSnapshot();
});
it('should also filter analysis based on the query', () => {
expect(
utils.getAnalysesByVersionByDay(ANALYSES, {
category: 'QUALITY_PROFILE',
customMetrics: [],
graph: 'overview',
project: 'foo'
})
).toMatchSnapshot();
expect(
utils.getAnalysesByVersionByDay(ANALYSES, {
category: '',
customMetrics: [],
graph: 'overview',
project: 'foo',
to: new Date('2017-06-09T11:12:27+0200'),
from: new Date('2017-05-18T14:13:07+0200')
})
).toMatchSnapshot();
});
});


+ 91
- 77
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js View File

@@ -65,30 +65,48 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
}

componentDidUpdate(prevProps: Props) {
if (this.scrollContainer) {
const selectedDateChanged = selectedDateQueryChanged(prevProps.query, this.props.query);
if (selectedDateChanged || prevProps.analysis !== this.props.analyses) {
if (selectedDateChanged && this.props.query.selectedDate) {
const selectedDate = this.props.query.selectedDate.valueOf();
for (let i = 1; i < this.analyses.length; i++) {
if (Number(this.analyses[i].getAttribute('data-date')) === selectedDate) {
const containerHeight = this.scrollContainer.offsetHeight - 100;
const scrollDiff = Math.abs(
this.scrollContainer.scrollTop - this.analyses[i].offsetTop
);
// Center only the extremities and the ones outside of the container
if (scrollDiff > containerHeight || scrollDiff < 100) {
this.resetScrollTop(this.analyses[i].offsetTop - containerHeight / 2);
}
break;
}
}
} else if (activityQueryChanged(prevProps.query, this.props.query)) {
this.resetScrollTop(0, true);
if (!this.scrollContainer) {
return;
}
if (
this.props.query.selectedDate &&
(selectedDateQueryChanged(prevProps.query, this.props.query) ||
prevProps.analyses !== this.props.analyses)
) {
this.scrollToDate(this.props.query.selectedDate);
} else if (activityQueryChanged(prevProps.query, this.props.query)) {
this.resetScrollTop(0, true);
}
}

handleScroll = () => this.updateStickyBadges(true);

resetScrollTop = (newScrollTop: number, forceBadgeAlignement?: boolean) => {
this.scrollContainer.scrollTop = newScrollTop;
for (let i = 1; i < this.badges.length; i++) {
this.badges[i].removeAttribute('originOffsetTop');
this.badges[i].classList.remove('sticky');
}
this.updateStickyBadges(forceBadgeAlignement);
};

scrollToDate = (targetDate: ?Date) => {
if (!this.scrollContainer || !targetDate) {
return;
}
const date = targetDate.valueOf();
for (let i = 1; i < this.analyses.length; i++) {
if (Number(this.analyses[i].getAttribute('data-date')) === date) {
const containerHeight = this.scrollContainer.offsetHeight - 100;
const scrollDiff = Math.abs(this.scrollContainer.scrollTop - this.analyses[i].offsetTop);
// Center only the extremities and the ones outside of the container
if (scrollDiff > containerHeight || scrollDiff < 100) {
this.resetScrollTop(this.analyses[i].offsetTop - containerHeight / 2);
}
break;
}
}
}
};

updateStickyBadges = (forceBadgeAlignement?: boolean) => {
if (this.scrollContainer && this.badges) {
@@ -119,23 +137,14 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
}
};

handleScroll = () => this.updateStickyBadges(true);

resetScrollTop = (newScrollTop: number, forceBadgeAlignement?: boolean) => {
this.scrollContainer.scrollTop = newScrollTop;
for (let i = 1; i < this.badges.length; i++) {
this.badges[i].removeAttribute('originOffsetTop');
this.badges[i].classList.remove('sticky');
}
this.updateStickyBadges(forceBadgeAlignement);
};

updateSelectedDate = (date: Date) => {
this.props.updateQuery({ selectedDate: date });
};
updateSelectedDate = (date: Date) => this.props.updateQuery({ selectedDate: date });

render() {
if (this.props.analyses.length === 0) {
const byVersionByDay = getAnalysesByVersionByDay(this.props.analyses, this.props.query);
const hasFilteredData =
byVersionByDay.length > 1 ||
(byVersionByDay.length === 1 && Object.keys(byVersionByDay[0].byDay).length > 0);
if (this.props.analyses.length === 0 || !hasFilteredData) {
return (
<div className={this.props.className}>
{this.props.loading
@@ -146,7 +155,6 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
}

const firstAnalysisKey = this.props.analyses[0].key;
const byVersionByDay = getAnalysesByVersionByDay(this.props.analyses);
const selectedDate = this.props.query.selectedDate
? this.props.query.selectedDate.valueOf()
: null;
@@ -155,46 +163,52 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
className={classNames('project-activity-versions-list', this.props.className)}
onScroll={this.handleScroll}
ref={element => (this.scrollContainer = element)}>
{byVersionByDay.map((version, idx) => (
<li key={version.key || 'noversion'}>
{version.version &&
<div className={classNames('project-activity-version-badge', { first: idx === 0 })}>
<span className="badge">
{version.version}
</span>
</div>}
<ul className="project-activity-days-list">
{Object.keys(version.byDay).map(day => (
<li
key={day}
className="project-activity-day"
data-day={moment(Number(day)).format('YYYY-MM-DD')}>
<div className="project-activity-date">
<FormattedDate date={Number(day)} format="LL" />
</div>
<ul className="project-activity-analyses-list">
{version.byDay[day] != null &&
version.byDay[day].map(analysis => (
<ProjectActivityAnalysis
addCustomEvent={this.props.addCustomEvent}
addVersion={this.props.addVersion}
analysis={analysis}
canAdmin={this.props.canAdmin}
changeEvent={this.props.changeEvent}
deleteAnalysis={this.props.deleteAnalysis}
deleteEvent={this.props.deleteEvent}
isFirst={analysis.key === firstAnalysisKey}
key={analysis.key}
selected={analysis.date.valueOf() === selectedDate}
updateSelectedDate={this.updateSelectedDate}
/>
))}
</ul>
</li>
))}
</ul>
</li>
))}
{byVersionByDay.map((version, idx) => {
const days = Object.keys(version.byDay);
if (days.length <= 0) {
return null;
}
return (
<li key={version.key || 'noversion'}>
{version.version &&
<div className={classNames('project-activity-version-badge', { first: idx === 0 })}>
<span className="badge">
{version.version}
</span>
</div>}
<ul className="project-activity-days-list">
{days.map(day => (
<li
key={day}
className="project-activity-day"
data-day={moment(Number(day)).format('YYYY-MM-DD')}>
<div className="project-activity-date">
<FormattedDate date={Number(day)} format="LL" />
</div>
<ul className="project-activity-analyses-list">
{version.byDay[day] != null &&
version.byDay[day].map(analysis => (
<ProjectActivityAnalysis
addCustomEvent={this.props.addCustomEvent}
addVersion={this.props.addVersion}
analysis={analysis}
canAdmin={this.props.canAdmin}
changeEvent={this.props.changeEvent}
deleteAnalysis={this.props.deleteAnalysis}
deleteEvent={this.props.deleteEvent}
isFirst={analysis.key === firstAnalysisKey}
key={analysis.key}
selected={analysis.date.valueOf() === selectedDate}
updateSelectedDate={this.updateSelectedDate}
/>
))}
</ul>
</li>
))}
</ul>
</li>
);
})}
{this.props.analysesLoading && <li className="text-center"><i className="spinner" /></li>}
</ul>
);

+ 4
- 37
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js View File

@@ -24,7 +24,7 @@ import moment from 'moment';
import ProjectActivityPageHeader from './ProjectActivityPageHeader';
import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
import ProjectActivityGraphs from './ProjectActivityGraphs';
import { getDisplayedHistoryMetrics, activityQueryChanged } from '../utils';
import { getDisplayedHistoryMetrics } from '../utils';
import { translate } from '../../../helpers/l10n';
import './projectActivity.css';
import type { Analysis, MeasureHistory, Metric, Query } from '../types';
@@ -46,40 +46,8 @@ type Props = {
updateQuery: (newQuery: Query) => void
};

type State = {
filteredAnalyses: Array<Analysis>
};

export default class ProjectActivityApp extends React.PureComponent {
props: Props;
state: State;

constructor(props: Props) {
super(props);
this.state = { filteredAnalyses: this.filterAnalyses(props.analyses, props.query) };
}

componentWillReceiveProps(nextProps: Props) {
if (
nextProps.analyses !== this.props.analyses ||
activityQueryChanged(this.props.query, nextProps.query)
) {
this.setState({ filteredAnalyses: this.filterAnalyses(nextProps.analyses, nextProps.query) });
}
}

filterAnalyses = (analyses: Array<Analysis>, query: Query): Array<Analysis> => {
if (!query.category && !query.from && !query.to) {
return analyses;
}
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 = () => {
const historyMetrics = getDisplayedHistoryMetrics(
@@ -92,8 +60,7 @@ export default class ProjectActivityApp extends React.PureComponent {
};

render() {
const { measuresHistory, query } = this.props;
const { filteredAnalyses } = this.state;
const { analyses, measuresHistory, query } = this.props;
const { configuration } = this.props.project;
const canAdmin = configuration ? configuration.showHistory : false;
return (
@@ -113,7 +80,7 @@ export default class ProjectActivityApp extends React.PureComponent {
addCustomEvent={this.props.addCustomEvent}
addVersion={this.props.addVersion}
analysesLoading={this.props.analysesLoading}
analyses={filteredAnalyses}
analyses={analyses}
canAdmin={canAdmin}
className="boxed-group-inner"
changeEvent={this.props.changeEvent}
@@ -126,7 +93,7 @@ export default class ProjectActivityApp extends React.PureComponent {
</div>
<div className="project-activity-layout-page-main">
<ProjectActivityGraphs
analyses={filteredAnalyses}
analyses={analyses}
leakPeriodDate={moment(this.props.project.leakPeriodDate).toDate()}
loading={this.props.graphLoading}
measuresHistory={measuresHistory}

+ 116
- 0
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityAnalysesList-test.js View File

@@ -0,0 +1,116 @@
/*
* 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 ProjectActivityAnalysesList from '../ProjectActivityAnalysesList';

const ANALYSES = [
{
key: 'A1',
date: new Date('2016-10-27T16:33:50+0000'),
events: [
{
key: 'E1',
category: 'VERSION',
name: '6.5-SNAPSHOT'
}
]
},
{
key: 'A2',
date: new Date('2016-10-27T12:21:15+0000'),
events: []
},
{
key: 'A3',
date: new Date('2016-10-26T12:17:29+0000'),
events: [
{
key: 'E2',
category: 'VERSION',
name: '6.4'
},
{
key: 'E3',
category: 'OTHER',
name: 'foo'
}
]
},
{
key: 'A4',
date: new Date('2016-10-24T16:33:50+0000'),
events: [
{
key: 'E1',
category: 'QUALITY_GATE',
name: 'Quality gate changed to red...'
}
]
}
];

const DEFAULT_PROPS = {
addCustomEvent: () => {},
addVersion: () => {},
analyses: ANALYSES,
analysesLoading: false,
canAdmin: false,
changeEvent: () => {},
deleteAnalysis: () => {},
deleteEvent: () => {},
loading: false,
query: { category: '', graph: 'overview', project: 'org.sonarsource.sonarqube:sonarqube' },
updateQuery: () => {}
};

jest.mock('moment', () => date => ({
startOf: () => {
return {
valueOf: () => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`
};
},
toDate: () => new Date(date),
format: format => `Formated.${format}:${date}`
}));

window.Number = val => val;

it('should render correctly', () => {
expect(shallow(<ProjectActivityAnalysesList {...DEFAULT_PROPS} />)).toMatchSnapshot();
});

it('should correctly filter analyses by category', () => {
const wrapper = shallow(<ProjectActivityAnalysesList {...DEFAULT_PROPS} />);
wrapper.setProps({ query: { ...DEFAULT_PROPS.query, category: 'QUALITY_GATE' } });
expect(wrapper).toMatchSnapshot();
});

it('should correctly filter analyses by date range', () => {
const wrapper = shallow(<ProjectActivityAnalysesList {...DEFAULT_PROPS} />);
wrapper.setProps({
query: {
...DEFAULT_PROPS.query,
from: new Date('2016-10-27T16:33:50+0000'),
to: new Date('2016-10-27T16:33:50+0000')
}
});
expect(wrapper).toMatchSnapshot();
});

+ 1
- 19
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-test.js View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import { mount, shallow } from 'enzyme';
import { shallow } from 'enzyme';
import ProjectActivityApp from '../ProjectActivityApp';

const ANALYSES = [
@@ -87,21 +87,3 @@ const DEFAULT_PROPS = {
it('should render correctly', () => {
expect(shallow(<ProjectActivityApp {...DEFAULT_PROPS} />)).toMatchSnapshot();
});

it('should correctly filter analyses by category', () => {
const wrapper = mount(<ProjectActivityApp {...DEFAULT_PROPS} />);
wrapper.setProps({ query: { ...DEFAULT_PROPS.query, category: 'VERSION' } });
expect(wrapper.state()).toMatchSnapshot();
});

it('should correctly filter analyses by date range', () => {
const wrapper = mount(<ProjectActivityApp {...DEFAULT_PROPS} />);
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();
});

+ 336
- 0
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityAnalysesList-test.js.snap View File

@@ -0,0 +1,336 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should correctly filter analyses by category 1`] = `
<ul
className="project-activity-versions-list"
onScroll={[Function]}
>
<li>
<div
className="project-activity-version-badge first"
>
<span
className="badge"
>
6.4
</span>
</div>
<ul
className="project-activity-days-list"
>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-24"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-24"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-24T16:33:50.000Z,
"events": Array [
Object {
"category": "QUALITY_GATE",
"key": "E1",
"name": "Quality gate changed to red...",
},
],
"key": "A4",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={false}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
</ul>
</li>
</ul>
`;

exports[`should correctly filter analyses by date range 1`] = `
<ul
className="project-activity-versions-list"
onScroll={[Function]}
>
<li>
<div
className="project-activity-version-badge first"
>
<span
className="badge"
>
6.5-SNAPSHOT
</span>
</div>
<ul
className="project-activity-days-list"
>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-27"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-27"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-27T16:33:50.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "E1",
"name": "6.5-SNAPSHOT",
},
],
"key": "A1",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={true}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
</ul>
</li>
</ul>
`;

exports[`should render correctly 1`] = `
<ul
className="project-activity-versions-list"
onScroll={[Function]}
>
<li>
<div
className="project-activity-version-badge first"
>
<span
className="badge"
>
6.5-SNAPSHOT
</span>
</div>
<ul
className="project-activity-days-list"
>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-27"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-27"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-27T16:33:50.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "E1",
"name": "6.5-SNAPSHOT",
},
],
"key": "A1",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={true}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
</ul>
</li>
<li>
<div
className="project-activity-version-badge"
>
<span
className="badge"
>
6.4
</span>
</div>
<ul
className="project-activity-days-list"
>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-27"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-27"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-27T12:21:15.000Z,
"events": Array [],
"key": "A2",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={false}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-26"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-26"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-26T12:17:29.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "E2",
"name": "6.4",
},
Object {
"category": "OTHER",
"key": "E3",
"name": "foo",
},
],
"key": "A3",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={false}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
</ul>
</li>
<li>
<ul
className="project-activity-days-list"
>
<li
className="project-activity-day"
data-day="Formated.YYYY-MM-DD:2016-9-24"
>
<div
className="project-activity-date"
>
<FormattedDate
date="2016-9-24"
format="LL"
/>
</div>
<ul
className="project-activity-analyses-list"
>
<ProjectActivityAnalysis
addCustomEvent={[Function]}
addVersion={[Function]}
analysis={
Object {
"date": 2016-10-24T16:33:50.000Z,
"events": Array [
Object {
"category": "QUALITY_GATE",
"key": "E1",
"name": "Quality gate changed to red...",
},
],
"key": "A4",
}
}
canAdmin={false}
changeEvent={[Function]}
deleteAnalysis={[Function]}
deleteEvent={[Function]}
isFirst={false}
selected={false}
updateSelectedDate={[Function]}
/>
</ul>
</li>
</ul>
</li>
</ul>
`;

+ 0
- 46
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap View File

@@ -1,51 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should correctly filter analyses by category 1`] = `
Object {
"filteredAnalyses": Array [
Object {
"date": 2016-10-27T14:33:50.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "E1",
"name": "6.5-SNAPSHOT",
},
],
"key": "A1",
},
Object {
"date": 2016-10-26T10:17:29.000Z,
"events": Array [
Object {
"category": "VERSION",
"key": "E2",
"name": "6.4",
},
Object {
"category": "OTHER",
"key": "E3",
"name": "foo",
},
],
"key": "A3",
},
],
}
`;

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`] = `
<div
className="page page-limited"

+ 20
- 5
server/sonar-web/src/main/js/apps/projectActivity/utils.js View File

@@ -130,7 +130,8 @@ export const generateSeries = (
};

export const getAnalysesByVersionByDay = (
analyses: Array<Analysis>
analyses: Array<Analysis>,
query: Query
): Array<{
version: ?string,
key: ?string,
@@ -142,16 +143,30 @@ export const getAnalysesByVersionByDay = (
}
const currentVersion = acc[acc.length - 1];
const day = moment(analysis.date).startOf('day').valueOf().toString();
if (!currentVersion.byDay[day]) {
currentVersion.byDay[day] = [];

let matchFilters = true;
if (query.category || query.from || query.to) {
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;
matchFilters = isAfterFrom && isBeforeTo && hasSelectedCategoryEvents;
}

if (matchFilters) {
if (!currentVersion.byDay[day]) {
currentVersion.byDay[day] = [];
}
currentVersion.byDay[day].push(analysis);
}
currentVersion.byDay[day].push(analysis);

const versionEvent = analysis.events.find(event => event.category === 'VERSION');
if (versionEvent && versionEvent.category === 'VERSION') {
currentVersion.version = versionEvent.name;
currentVersion.key = versionEvent.key;
acc.push({ version: undefined, key: undefined, byDay: {} });
if (Object.keys(currentVersion.byDay).length > 0) {
acc.push({ version: undefined, key: undefined, byDay: {} });
}
}
return acc;
}, []);

Loading…
Cancel
Save