Browse Source

SONAR-8550 Make the analysis version sticky in the project activity list

tags/6.5-M2
Grégoire Aubert 7 years ago
parent
commit
3a2e4d3af7

+ 0
- 1
server/sonar-web/src/main/js/apps/projectActivity/components/Events.js View File

@@ -20,7 +20,6 @@
// @flow
import React from 'react';
import Event from './Event';
import './projectActivity.css';
import type { Event as EventType } from '../types';

type Props = {

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

@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
import classNames from 'classnames';
import moment from 'moment';
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
import FormattedDate from '../../../components/ui/FormattedDate';
@@ -39,28 +40,80 @@ type Props = {
loading: boolean
};

export default function ProjectActivityAnalysesList(props: Props) {
if (props.analyses.length === 0) {
return (
<div className={props.className}>
{props.loading
? <div className="text-center"><i className="spinner" /></div>
: <span className="note">{translate('no_results')}</span>}
</div>
);
export default class ProjectActivityAnalysesList extends React.PureComponent {
scrollContainer: HTMLElement;
badges: HTMLCollection<HTMLElement>;
props: Props;

componentDidMount() {
this.badges = document.getElementsByClassName('project-activity-version-badge');
}

componentDidUpdate(prevProps: Props) {
if (prevProps.analysis !== this.props.analyses && this.scrollContainer) {
this.scrollContainer.scrollTop = 0;
for (let i = 1; i < this.badges.length; i++) {
this.badges[i].removeAttribute('originOffsetTop');
this.badges[i].classList.remove('sticky');
}
this.handleScroll();
}
}

const firstAnalysisKey = props.analyses[0].key;
const byVersionByDay = getAnalysesByVersionByDay(props.analyses);
return (
<div className={props.className}>
<ul className="project-activity-versions-list">
handleScroll = () => {
if (this.scrollContainer && this.badges) {
const scrollTop = this.scrollContainer.scrollTop;
if (scrollTop != null) {
let newScrollTop;
for (let i = 1; i < this.badges.length; i++) {
const badge = this.badges[i];
let originOffsetTop = badge.getAttribute('originOffsetTop');
if (originOffsetTop == null) {
originOffsetTop = badge.offsetTop;
badge.setAttribute('originOffsetTop', originOffsetTop.toString());
}
if (Number(originOffsetTop) < scrollTop + 18 + i * 2) {
if (!badge.classList.contains('sticky')) {
newScrollTop = originOffsetTop;
}
badge.classList.add('sticky');
} else {
badge.classList.remove('sticky');
}
}
if (newScrollTop != null) {
this.scrollContainer.scrollTop = newScrollTop - 6;
}
}
}
};

render() {
if (this.props.analyses.length === 0) {
return (
<div className={this.props.className}>
{this.props.loading
? <div className="text-center"><i className="spinner" /></div>
: <span className="note">{translate('no_results')}</span>}
</div>
);
}

const firstAnalysisKey = this.props.analyses[0].key;
const byVersionByDay = getAnalysesByVersionByDay(this.props.analyses);
return (
<ul
className={classNames('project-activity-versions-list', this.props.className)}
onScroll={this.handleScroll}
ref={element => (this.scrollContainer = element)}>
{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>}
<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
@@ -74,13 +127,13 @@ export default function ProjectActivityAnalysesList(props: Props) {
{version.byDay[day] != null &&
version.byDay[day].map(analysis => (
<ProjectActivityAnalysis
addCustomEvent={props.addCustomEvent}
addVersion={props.addVersion}
addCustomEvent={this.props.addCustomEvent}
addVersion={this.props.addVersion}
analysis={analysis}
canAdmin={props.canAdmin}
changeEvent={props.changeEvent}
deleteAnalysis={props.deleteAnalysis}
deleteEvent={props.deleteEvent}
canAdmin={this.props.canAdmin}
changeEvent={this.props.changeEvent}
deleteAnalysis={this.props.deleteAnalysis}
deleteEvent={this.props.deleteEvent}
isFirst={analysis.key === firstAnalysisKey}
key={analysis.key}
version={version.version}
@@ -92,8 +145,8 @@ export default function ProjectActivityAnalysesList(props: Props) {
</ul>
</li>
))}
{props.analysesLoading && <li className="text-center"><i className="spinner" /></li>}
{this.props.analysesLoading && <li className="text-center"><i className="spinner" /></li>}
</ul>
</div>
);
);
}
}

+ 2
- 2
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js View File

@@ -41,7 +41,7 @@ type Props = {
export default function ProjectActivityAnalysis(props: Props) {
const { date, events } = props.analysis;
const { isFirst, canAdmin } = props;
const analysisTitle = translate('project_activity.analysis');
return (
<li className="project-activity-analysis clearfix">
<div className="project-activity-time spacer-right">
@@ -49,7 +49,7 @@ export default function ProjectActivityAnalysis(props: Props) {
</div>
<div
className="project-activity-analysis-icon little-spacer-top big-spacer-right"
title={translate('project_activity.analysis')}
title={analysisTitle}
/>

{canAdmin &&

+ 33
- 5
server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css View File

@@ -4,9 +4,12 @@
}

.project-activity-page-side-outer {
position: relative;
width: 400px;
overflow: auto;
margin-bottom: 0;
display: flex;
flex-direction: row;
align-items: stretch;
}

.project-activity-page-side-outer > .boxed-group-inner {
@@ -31,8 +34,13 @@
align-items: stretch;
}

.project-activity-list {
.project-activity-versions-list {
max-width: 400px;
box-sizing: border-box;
overflow: auto;
flex-grow: 1;
flex-shrink: 0;
padding-top: 52px;
}

.project-activity-graph-container {
@@ -57,7 +65,8 @@
.project-activity-days-list {}

.project-activity-day {
margin-bottom: 32px;
margin-top: 8px;
margin-bottom: 24px;
}

.project-activity-day:last-child {
@@ -169,9 +178,28 @@
}

.project-activity-version-badge {
margin-left: -12px;
padding-top: 8px;
padding-bottom: 8px;
background-color: white;
}

.project-activity-version-badge.sticky, .project-activity-version-badge.first {
position: absolute;
top: 0;
left: 12px;
right: 20px;
padding-top: 24px;
z-index: 100;
}

.project-activity-version-badge.sticky + .project-activity-days-list {
padding-top: 36px;
}

.project-activity-version-badge .badge {
vertical-align: middle;
padding: 4px 14px 4px 16px;
margin-left: -14px;
padding: 4px 14px 4px 14px;
border-radius: 2px;
font-weight: bold;
font-size: 12px;

Loading…
Cancel
Save