/* * SonarQube * Copyright (C) 2009-2019 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 * as React from 'react'; import * as classNames from 'classnames'; import CountUp from 'react-countup'; import { throttle } from 'lodash'; import { FeaturedProject } from '../utils'; import CoverageRating from '../../../../components/ui/CoverageRating'; import DuplicationsRating from '../../../../components/ui/DuplicationsRating'; import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; import ProjectCardLanguagesContainer from '../../../projects/components/ProjectCardLanguagesContainer'; import Rating from '../../../../components/ui/Rating'; import { formatMeasure } from '../../../../helpers/measures'; import { getMetricName } from '../../../overview/utils'; import { getProjectUrl, getBaseUrl, getPathUrlAsString } from '../../../../helpers/urls'; import './FeaturedProjects.css'; interface Props { projects: FeaturedProject[]; } interface State { reversing: boolean; slides: Array<{ order: number; project: FeaturedProject; }>; sliding: boolean; viewable: boolean; } export default class FeaturedProjects extends React.PureComponent { container?: HTMLElement | null; mounted = false; constructor(props: Props) { super(props); this.state = { reversing: false, slides: this.orderProjectsFromProps(), sliding: false, viewable: false }; this.handleScroll = throttle(this.handleScroll, 10); } componentDidMount() { this.mounted = true; document.addEventListener('scroll', this.handleScroll, true); } componentDidUpdate(prevProps: Props) { if (prevProps.projects !== this.props.projects) { this.setState({ slides: this.orderProjectsFromProps() }); } } componentWillUnmount() { this.mounted = false; document.removeEventListener('scroll', this.handleScroll, true); } handleScroll = () => { if (this.container) { const rect = this.container.getBoundingClientRect(); const windowHeight = window.innerHeight || (document.documentElement ? document.documentElement.clientHeight : 0); if (rect.top <= windowHeight && rect.top + rect.height >= 0) { this.setState({ viewable: true }); } } }; orderProjectsFromProps = () => { const { projects } = this.props; if (projects.length === 0) { return []; } // Last element should be put at the begining for proper carousel animation return [projects.pop(), ...projects].map((project: FeaturedProject, id) => { return { order: id, project }; }); }; handlePrevClick = () => { this.setState(({ slides }) => ({ reversing: true, sliding: true, slides: slides.map(slide => { slide.order = slide.order === slides.length - 1 ? 0 : slide.order + 1; return slide; }) })); setTimeout(() => { if (this.mounted) { this.setState({ sliding: false }); } }, 50); }; handleNextClick = () => { this.setState(({ slides }) => ({ reversing: false, sliding: true, slides: slides.map(slide => { slide.order = slide.order === 0 ? slides.length - 1 : slide.order - 1; return slide; }) })); setTimeout(() => { this.setState({ sliding: false }); }, 50); }; render() { const { reversing, sliding, viewable } = this.state; return (
(this.container = node)}>
{this.state.slides.map(slide => ( ))}
); } } interface ProjectCardProps { order: number; project: FeaturedProject; viewable: boolean; } export function ProjectCard({ project, order, viewable }: ProjectCardProps) { return (

{project.organizationName}

{project.name}
  • {getMetricName('coverage')} {project.coverage !== undefined ? (
    {viewable && ( {(data: { countUpRef?: React.RefObject }) => (
    0
    )}
    )}
    ) : ( )}
  • {getMetricName('duplications')}
    {viewable && ( {(data: { countUpRef?: React.RefObject }) => (
    0
    )}
    )}
{formatMeasure(project.ncloc, 'SHORT_INT')} lines of code /{' '}
); } interface ProjectIssues { metricKey: string; metric: number; ratingMetric: number; viewable: boolean; } export function ProjectIssues({ metric, metricKey, ratingMetric, viewable }: ProjectIssues) { const formattedValue = formatMeasure(metric, 'SHORT_INT'); const value = parseFloat(formattedValue); const suffix = formattedValue.replace(value.toString(), ''); return (
  • {getMetricName(metricKey)}
    {viewable && ( {(data: { countUpRef?: React.RefObject }) => (
    0
    )}
    )}
  • ); }