aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2017-08-31 12:03:24 +0200
committerStas Vilchik <stas.vilchik@sonarsource.com>2017-09-13 13:53:58 +0200
commita1b9bc1ced0bb2dd67e60583254f836cb477ed42 (patch)
treecc9e362ddf0f623b9d4f0e816591371cf69616a0 /server
parent1ca69cefbef27f8f772650de4af6e6018ef85351 (diff)
downloadsonarqube-a1b9bc1ced0bb2dd67e60583254f836cb477ed42.tar.gz
sonarqube-a1b9bc1ced0bb2dd67e60583254f836cb477ed42.zip
SONAR-9375 Infinite loading of a project on the projects page
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/app/styles/boxed-group.css75
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx22
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardLeak-test.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCardOverall-test.tsx13
-rw-r--r--server/sonar-web/src/main/js/components/measure/Measure.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx5
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/components/ui/Rating.tsx5
-rw-r--r--server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.tsx (renamed from server/sonar-web/src/main/js/components/ui/__tests__/Rating-test.js)16
-rw-r--r--server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap23
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>
+`;