*/
// @flow
import React from 'react';
-import { groupBy } from 'lodash';
import moment from 'moment';
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
import FormattedDate from '../../../components/ui/FormattedDate';
import { translate } from '../../../helpers/l10n';
+import { getAnalysesByVersionByDay } from '../utils';
import type { Analysis } from '../types';
type Props = {
);
}
- const firstAnalysis = props.analyses[0];
- const byDay = groupBy(props.analyses, analysis => moment(analysis.date).startOf('day').valueOf());
+ const firstAnalysisKey = props.analyses[0].key;
+ const byVersionByDay = getAnalysesByVersionByDay(props.analyses);
return (
<div className={props.className}>
- <ul className="project-activity-days-list">
- {Object.keys(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">
- {byDay[day] != null &&
- byDay[day].map(analysis => (
- <ProjectActivityAnalysis
- addCustomEvent={props.addCustomEvent}
- addVersion={props.addVersion}
- analysis={analysis}
- canAdmin={props.canAdmin}
- changeEvent={props.changeEvent}
- deleteAnalysis={props.deleteAnalysis}
- deleteEvent={props.deleteEvent}
- isFirst={analysis === firstAnalysis}
- key={analysis.key}
- />
- ))}
+ <ul className="project-activity-versions-list">
+ {byVersionByDay.map((version, idx) => (
+ <li key={idx + version.version}>
+ {version.version &&
+ <span className="badge project-activity-version-badge spacer-top big-spacer-bottom">
+ {version.version}
+ </span>}
+ <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={props.addCustomEvent}
+ addVersion={props.addVersion}
+ analysis={analysis}
+ canAdmin={props.canAdmin}
+ changeEvent={props.changeEvent}
+ deleteAnalysis={props.deleteAnalysis}
+ deleteEvent={props.deleteEvent}
+ isFirst={analysis.key === firstAnalysisKey}
+ key={analysis.key}
+ />
+ ))}
+ </ul>
+ </li>
+ ))}
</ul>
</li>
))}
<div className="project-activity-analysis-actions spacer-left">
<div className="dropdown display-inline-block">
<button
- className="js-analysis-actions button-small dropdown-toggle"
+ className="js-analysis-actions button-small button-compact dropdown-toggle"
data-toggle="dropdown">
<i className="icon-settings" />
{' '}
nextProps.analyses !== this.props.analyses ||
activityQueryChanged(this.props.query, nextProps.query)
) {
- this.setState({
- filteredAnalyses: this.filterAnalyses(nextProps.analyses, nextProps.query)
- });
+ this.setState({ filteredAnalyses: this.filterAnalyses(nextProps.analyses, nextProps.query) });
}
}
render() {
return (
- <a className="js-add-event button-small" href="#" onClick={this.openForm}>
+ <a className="js-add-event" href="#" onClick={this.openForm}>
{translate(this.props.addEventButtonText)}
{this.state.open && this.renderModal()}
</a>
.project-activity-graph {
flex: 1;
- max-height: 500px;
}
.project-activity-graph-legends {
.project-activity-version-badge {
vertical-align: middle;
- padding: 4px 8px;
+ padding: 4px 14px 4px 16px;
+ margin-left: -14px;
border-radius: 2px;
font-weight: bold;
font-size: 12px;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
+import moment from 'moment';
import {
cleanQuery,
parseAsDate,
serializeString
} from '../../helpers/query';
import { translate } from '../../helpers/l10n';
-import type { MeasureHistory, Query } from './types';
+import type { Analysis, MeasureHistory, Query } from './types';
import type { RawQuery } from '../../helpers/query';
export const EVENT_TYPES = ['VERSION', 'QUALITY_GATE', 'QUALITY_PROFILE', 'OTHER'];
};
};
+export const getAnalysesByVersionByDay = (
+ analyses: Array<Analysis>
+): Array<{
+ version: ?string,
+ byDay: { [string]: Array<Analysis> }
+}> =>
+ analyses.reduce((acc, analysis) => {
+ if (acc.length === 0) {
+ acc.push({ version: undefined, byDay: {} });
+ }
+ const currentVersion = acc[acc.length - 1];
+ const day = moment(analysis.date).startOf('day').valueOf().toString();
+ if (!currentVersion.byDay[day]) {
+ currentVersion.byDay[day] = [];
+ }
+ currentVersion.byDay[day].push(analysis);
+ const versionEvent = analysis.events.find(event => event.category === 'VERSION');
+ if (versionEvent) {
+ currentVersion.version = versionEvent.name;
+ acc.push({ version: undefined, byDay: {} });
+ }
+ return acc;
+ }, []);
+
const parseGraph = (value?: string): string => {
const graph = parseAsString(value);
return GRAPH_TYPES.includes(graph) ? graph : 'overview';
}
}
+.button-compact {
+ padding: 0 6px;
+}
+
.button-group {
display: inline-block;
vertical-align: middle;
}
public ProjectAnalysisItem shouldHaveDeleteButton() {
+ elt.find(".js-analysis-actions").click();
elt.find(".js-delete-analysis").shouldBe(visible);
return this;
}
public ProjectAnalysisItem shouldNotHaveDeleteButton() {
+ elt.find(".js-analysis-actions").click();
elt.find(".js-delete-analysis").shouldNotBe(visible);
return this;
}
public void delete() {
+ elt.find(".js-analysis-actions").click();
elt.find(".js-delete-analysis").click();
SelenideElement modal = $(".modal");
}
public ProjectAnalysisItem addCustomEvent(String name) {
- elt.find(".js-create").click();
+ elt.find(".js-analysis-actions").click();
elt.find(".js-add-event").click();
SelenideElement modal = $(".modal");
modal.find("input").setValue(name);
modal.find("button[type=\"submit\"]").click();
- elt.find(".project-activity-event:last-child").shouldHave(text(name));
-
+ elt.find(".project-activity-event:first-child").shouldHave(text(name));
return this;
}
- public ProjectAnalysisItem changeLastEvent(String newName) {
- SelenideElement lastEvent = elt.find(".project-activity-event:last-child");
- lastEvent.find(".js-change-event").click();
+ public ProjectAnalysisItem changeFirstEvent(String newName) {
+ SelenideElement firstEvent = elt.find(".project-activity-event:first-child");
+ firstEvent.find(".js-change-event").click();
SelenideElement modal = $(".modal");
modal.shouldBe(visible);
modal.find("input").setValue(newName);
modal.find("button[type=\"submit\"]").click();
- lastEvent.shouldHave(text(newName));
-
+ firstEvent.shouldHave(text(newName));
return this;
}
- public ProjectAnalysisItem deleteLastEvent() {
+ public ProjectAnalysisItem deleteFirstEvent() {
int eventsCount = elt.findAll(".project-activity-event").size();
- SelenideElement lastEvent = elt.find(".project-activity-event:last-child");
- lastEvent.find(".js-delete-event").click();
+ SelenideElement firstEvent = elt.find(".project-activity-event:first-child");
+ firstEvent.find(".js-delete-event").click();
SelenideElement modal = $(".modal");
modal.shouldBe(visible);
analyzeProject();
openPage().getLastAnalysis()
.addCustomEvent("foo")
- .changeLastEvent("bar")
- .deleteLastEvent();
+ .changeFirstEvent("bar")
+ .deleteFirstEvent();
}
@Test
public void delete_analysis() {
analyzeProject();
analyzeProject();
- openPage().getFirstAnalysis().delete();
+ ProjectActivityPage page = openPage();
+ page.getAnalyses().shouldHaveSize(2);
+ page.getFirstAnalysis().delete();
}
private ProjectActivityPage openPage() {