diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-08-31 12:03:24 +0200 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-09-13 13:53:58 +0200 |
commit | a1b9bc1ced0bb2dd67e60583254f836cb477ed42 (patch) | |
tree | cc9e362ddf0f623b9d4f0e816591371cf69616a0 /server/sonar-web/src/main/js | |
parent | 1ca69cefbef27f8f772650de4af6e6018ef85351 (diff) | |
download | sonarqube-a1b9bc1ced0bb2dd67e60583254f836cb477ed42.tar.gz sonarqube-a1b9bc1ced0bb2dd67e60583254f836cb477ed42.zip |
SONAR-9375 Infinite loading of a project on the projects page
Diffstat (limited to 'server/sonar-web/src/main/js')
13 files changed, 73 insertions, 167 deletions
diff --git a/server/sonar-web/src/main/js/app/styles/boxed-group.css b/server/sonar-web/src/main/js/app/styles/boxed-group.css index 56c69e066ec..14c5f9753b2 100644 --- a/server/sonar-web/src/main/js/app/styles/boxed-group.css +++ b/server/sonar-web/src/main/js/app/styles/boxed-group.css @@ -59,78 +59,3 @@ margin-right: -20px; padding: 8px 20px; } - -.boxed-group-loading { - position: relative; - transition: border-color 0.25s; -} - -.boxed-group-loading:before, -.boxed-group-loading:after { - position: absolute; - z-index: 1; - border: 2px solid transparent; - box-sizing: border-box; - content: ''; -} - -.boxed-group-loading:before { - width: 100%; - height: 100%; - top: 0; - left: 0; - border-top-color: #4b9fd5; - border-right-color: #4b9fd5; - animation: 3s top-left-border 0s infinite; -} - -.boxed-group-loading:after { - width: 0; - height: 0; - bottom: 0; - right: 0; - border-bottom-color: #4b9fd5; - border-left-color: #4b9fd5; - animation: 3s border-bottom-border 0s infinite; -} - -@keyframes top-left-border { - 0% { - width: 0; - height: 0; - } - - 25% { - width: 100%; - height: 0; - } - - 50%, - 100% { - width: 100%; - height: 100%; - } -} - -@keyframes border-bottom-border { - 0%, - 50% { - width: 0; - height: 0; - border-width: 0; - } - - 51% { - border-width: 2px; - } - - 75% { - width: 100%; - height: 0; - } - - 100% { - width: 100%; - height: 100%; - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx index f0e8fca7d54..89e6dd61c78 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as classNames from 'classnames'; import { Link } from 'react-router'; import DateFromNow from '../../../components/intl/DateFromNow'; import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; @@ -39,22 +38,11 @@ interface Props { export default function ProjectCardLeak({ organization, project }: Props) { const { measures } = project; - const isProjectAnalyzed = project.analysisDate != null; const isPrivate = project.visibility === 'private'; - const hasLeakPeriodStart = project.leakPeriodDate != undefined; const hasTags = project.tags.length > 0; - // check for particular measures because only some measures can be loaded - // if coming from visualizations tab - const areProjectMeasuresLoaded = measures != undefined && measures['new_bugs']; - - const displayQualityGate = areProjectMeasuresLoaded && isProjectAnalyzed; - const className = classNames('boxed-group', 'project-card', { - 'boxed-group-loading': isProjectAnalyzed && hasLeakPeriodStart && !areProjectMeasuresLoaded - }); - return ( - <div data-key={project.key} className={className}> + <div data-key={project.key} className="boxed-group project-card"> <div className="boxed-group-header clearfix"> {project.isFavorite != null && ( <Favorite @@ -67,44 +55,38 @@ export default function ProjectCardLeak({ organization, project }: Props) { {!organization && <ProjectCardOrganization organization={project.organization} />} <Link to={{ pathname: '/dashboard', query: { id: project.key } }}>{project.name}</Link> </h2> - {displayQualityGate && <ProjectCardQualityGate status={measures!['alert_status']} />} + {project.analysisDate && <ProjectCardQualityGate status={measures!['alert_status']} />} <div className="pull-right text-right"> {isPrivate && <PrivateBadge className="spacer-left" tooltipPlacement="left" />} {hasTags && <TagsList tags={project.tags} customClass="spacer-left" />} </div> - {isProjectAnalyzed && - hasLeakPeriodStart && ( + {project.analysisDate && + project.leakPeriodDate && ( <div className="project-card-dates note text-right pull-right"> - {hasLeakPeriodStart && ( - <DateFromNow date={project.leakPeriodDate!}> - {fromNow => ( - <span className="project-card-leak-date pull-right"> - {translateWithParameters('projects.leak_period_x', fromNow)} - </span> - )} - </DateFromNow> - )} - {isProjectAnalyzed && ( - <DateTimeFormatter date={project.analysisDate!}> - {formattedDate => ( - <span> - {translateWithParameters('projects.last_analysis_on_x', formattedDate)} - </span> - )} - </DateTimeFormatter> - )} + <DateFromNow date={project.leakPeriodDate!}> + {fromNow => ( + <span className="project-card-leak-date pull-right"> + {translateWithParameters('projects.leak_period_x', fromNow)} + </span> + )} + </DateFromNow> + <DateTimeFormatter date={project.analysisDate!}> + {formattedDate => ( + <span>{translateWithParameters('projects.last_analysis_on_x', formattedDate)}</span> + )} + </DateTimeFormatter> </div> )} </div> - {isProjectAnalyzed && hasLeakPeriodStart ? ( + {project.analysisDate && project.leakPeriodDate ? ( <div className="boxed-group-inner"> - {areProjectMeasuresLoaded && <ProjectCardLeakMeasures measures={measures} />} + <ProjectCardLeakMeasures measures={measures} /> </div> ) : ( <div className="boxed-group-inner"> <div className="note project-card-not-analyzed"> - {isProjectAnalyzed ? ( + {project.analysisDate ? ( translate('projects.no_leak_period') ) : ( translate('projects.not_analyzed') diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx index 353a0d6ccc9..570ddbe075f 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx @@ -26,14 +26,10 @@ import VulnerabilityIcon from '../../../components/icons-components/Vulnerabilit import { translate } from '../../../helpers/l10n'; interface Props { - measures?: { [key: string]: string }; + measures: { [key: string]: string }; } export default function ProjectCardLeakMeasures({ measures }: Props) { - if (measures == undefined) { - return null; - } - return ( <div className="project-card-leak-measures"> <div className="project-card-measure smaller-card" data-key="new_reliability_rating"> diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx index 75f0f8375d0..135f71c3e35 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as classNames from 'classnames'; import { Link } from 'react-router'; import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; import ProjectCardQualityGate from './ProjectCardQualityGate'; @@ -38,24 +37,11 @@ interface Props { export default function ProjectCardOverall({ organization, project }: Props) { const { measures } = project; - const isProjectAnalyzed = project.analysisDate != undefined; const isPrivate = project.visibility === 'private'; const hasTags = project.tags.length > 0; - // check for particular measures because only some measures can be loaded - // if coming from visualizations tab - const areProjectMeasuresLoaded = - measures != undefined && - measures['reliability_rating'] != undefined && - measures['sqale_rating'] != undefined; - - const displayQualityGate = areProjectMeasuresLoaded && isProjectAnalyzed; - const className = classNames('boxed-group', 'project-card', { - 'boxed-group-loading': isProjectAnalyzed && !areProjectMeasuresLoaded - }); - return ( - <div data-key={project.key} className={className}> + <div data-key={project.key} className="boxed-group project-card"> <div className="boxed-group-header clearfix"> {project.isFavorite != undefined && ( <Favorite @@ -68,7 +54,7 @@ export default function ProjectCardOverall({ organization, project }: Props) { {!organization && <ProjectCardOrganization organization={project.organization} />} <Link to={{ pathname: '/dashboard', query: { id: project.key } }}>{project.name}</Link> </h2> - {displayQualityGate && <ProjectCardQualityGate status={measures!['alert_status']} />} + {project.analysisDate && <ProjectCardQualityGate status={measures['alert_status']} />} <div className="pull-right text-right"> {isPrivate && <PrivateBadge className="spacer-left" tooltipPlacement="left" />} {hasTags && <TagsList tags={project.tags} customClass="spacer-left" />} @@ -86,9 +72,9 @@ export default function ProjectCardOverall({ organization, project }: Props) { )} </div> - {isProjectAnalyzed ? ( + {project.analysisDate ? ( <div className="boxed-group-inner"> - {areProjectMeasuresLoaded && <ProjectCardOverallMeasures measures={measures} />} + {<ProjectCardOverallMeasures measures={measures} />} </div> ) : ( <div className="boxed-group-inner"> diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx index 15c2565cc31..29b76358034 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx @@ -27,7 +27,7 @@ import SizeRating from '../../../components/ui/SizeRating'; import { translate } from '../../../helpers/l10n'; interface Props { - measures?: { [key: string]: string }; + measures: { [key: string]: string | undefined }; } export default function ProjectCardOverallMeasures({ measures }: Props) { diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.tsx index 8a9a75cf1cd..12899cfb047 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.tsx @@ -52,15 +52,6 @@ it('should not display analysis date or leak start date', () => { expect(card.find('.project-card-dates').exists()).toBeFalsy(); }); -it('should display loading', () => { - const measures = { alert_status: 'OK', reliability_rating: '1.0', sqale_rating: '1.0' }; - expect( - shallow(<ProjectCardLeak project={{ ...PROJECT, measures }} />) - .find('.boxed-group') - .hasClass('boxed-group-loading') - ).toBeTruthy(); -}); - it('should display tags', () => { const project = { ...PROJECT, tags: ['foo', 'bar'] }; expect( diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.tsx index 7a3e3bb3baf..7410fcb3711 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.tsx @@ -51,19 +51,6 @@ it('should display analysis date (and not leak period) when defined', () => { ).toBeFalsy(); }); -it('should display loading', () => { - expect( - shallow(<ProjectCardOverall project={{ ...PROJECT, measures: {} }} />) - .find('.boxed-group') - .hasClass('boxed-group-loading') - ).toBeTruthy(); - expect( - shallow(<ProjectCardOverall project={{ ...PROJECT, measures: { sqale_rating: '1.0' } }} />) - .find('.boxed-group') - .hasClass('boxed-group-loading') - ).toBeTruthy(); -}); - it('should not display the quality gate', () => { const project = { ...PROJECT, analysisDate: undefined }; expect( diff --git a/server/sonar-web/src/main/js/components/measure/Measure.tsx b/server/sonar-web/src/main/js/components/measure/Measure.tsx index 35177b49b95..d345aff6cb5 100644 --- a/server/sonar-web/src/main/js/components/measure/Measure.tsx +++ b/server/sonar-web/src/main/js/components/measure/Measure.tsx @@ -35,7 +35,7 @@ export default function Measure({ className, decimals, measure }: Props) { const value = isDiffMetric(metric.key) ? measure.leak : measure.value; if (value == undefined) { - return null; + return <span>{'–'}</span>; } if (metric.type === 'LEVEL') { diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx index 8929a8bc1c5..5eb0a6efa3e 100644 --- a/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx +++ b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx @@ -63,3 +63,8 @@ it('renders unknown RATING', () => { }; expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); }); + +it('renders undefined measure', () => { + const measure = { metric: { key: 'foo', name: 'Foo', type: 'PERCENT' } }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap b/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap index 2988d9210e8..c9ca3a03a7a 100644 --- a/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap @@ -31,6 +31,12 @@ exports[`renders trivial measure 1`] = ` </span> `; +exports[`renders undefined measure 1`] = ` +<span> + – +</span> +`; + exports[`renders unknown RATING 1`] = ` <Rating value="4" diff --git a/server/sonar-web/src/main/js/components/ui/Rating.tsx b/server/sonar-web/src/main/js/components/ui/Rating.tsx index 67abfe61782..183994c7eae 100644 --- a/server/sonar-web/src/main/js/components/ui/Rating.tsx +++ b/server/sonar-web/src/main/js/components/ui/Rating.tsx @@ -26,10 +26,13 @@ interface Props { className?: string; muted?: boolean; small?: boolean; - value: string | number; + value: string | number | undefined; } export default function Rating({ className, muted = false, small = false, value }: Props) { + if (value == undefined) { + return <span>{'–'}</span>; + } const formatted = formatMeasure(value, 'RATING'); return ( <span diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.js b/server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.tsx index 05e24ce63c2..05121774a65 100644 --- a/server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.js +++ b/server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.tsx @@ -17,16 +17,18 @@ * 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 { shallow } from 'enzyme'; -import React from 'react'; import Rating from '../Rating'; -it('should render with numeric value', () => { - const rating = shallow(<Rating value={2} />); - expect(rating.is('.rating-B')).toBe(true); +it('renders numeric value', () => { + expect(shallow(<Rating value={2} />)).toMatchSnapshot(); }); -it('should render with string value', () => { - const rating = shallow(<Rating value="2.0" />); - expect(rating.is('.rating-B')).toBe(true); +it('renders string value', () => { + expect(shallow(<Rating value="2.0" />)).toMatchSnapshot(); +}); + +it('renders undefined value', () => { + expect(shallow(<Rating value={undefined} />)).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap new file mode 100644 index 00000000000..94922c0bf43 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders numeric value 1`] = ` +<span + className="rating rating-B" +> + B +</span> +`; + +exports[`renders string value 1`] = ` +<span + className="rating rating-B" +> + B +</span> +`; + +exports[`renders undefined value 1`] = ` +<span> + – +</span> +`; |