aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorPascal Mugnier <pascal.mugnier@sonarsource.com>2018-07-30 14:49:25 +0200
committerSonarTech <sonartech@sonarsource.com>2018-08-02 20:21:32 +0200
commitd0242b05cdd2c419055a162d56fc6f95c930cca8 (patch)
tree118c1b5e9430c10018d63a8520cb6dd4aabb69d2 /server/sonar-web
parent2d10f95a8da89ea498eab5a7fe5a38ed9af23849 (diff)
downloadsonarqube-d0242b05cdd2c419055a162d56fc6f95c930cca8.tar.gz
sonarqube-d0242b05cdd2c419055a162d56fc6f95c930cca8.zip
SONAR-9178 Make spinner noticeable on loading projects issues or measure
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js3
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js5
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js18
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap57
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/App.tsx59
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/ModuleFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/ResolutionFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/StatusFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/AssigneeFacet-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/AssigneeFacet-test.tsx.snap16
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/StandardFacet-test.tsx.snap16
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx70
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap140
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap3
-rw-r--r--server/sonar-web/src/main/js/components/search-navigator.css5
33 files changed, 276 insertions, 204 deletions
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
index a7cd534be4c..e3843c8bcd0 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
@@ -35,6 +35,7 @@ import { enhanceComponent, isFileType, isViewType } from '../utils';
import { getProjectUrl } from '../../../helpers/urls';
import { isDiffMetric } from '../../../helpers/measures';
import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
/*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */
/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
@@ -319,7 +320,6 @@ export default class MeasureContent extends React.PureComponent {
)}
<PageActions
current={selectedIdx != null && view !== 'treemap' ? selectedIdx + 1 : null}
- loading={this.props.loading}
isFile={isFile}
paging={this.state.paging}
totalLoadedComponents={this.state.components.length}
@@ -343,7 +343,9 @@ export default class MeasureContent extends React.PureComponent {
metric={metric}
secondaryMeasure={this.props.secondaryMeasure}
/>
- {isFileType(component) ? this.renderCode() : this.renderMeasure()}
+ <DeferredSpinner loading={this.props.loading}>
+ {isFileType(component) ? this.renderCode() : this.renderMeasure()}
+ </DeferredSpinner>
</div>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js
index 77cb425f7a9..83e59016ccb 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js
@@ -28,6 +28,7 @@ import SourceViewer from '../../../components/SourceViewer/SourceViewer';
import { getComponentLeaves } from '../../../api/components';
import { enhanceComponent, getBubbleMetrics, isFileType } from '../utils';
import { getBranchLikeQuery } from '../../../helpers/branches';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
/*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
@@ -163,7 +164,6 @@ export default class MeasureOverview extends React.PureComponent {
<PageActions
current={this.state.components.length}
isFile={isFile}
- loading={this.props.loading}
paging={this.state.paging}
/>
</div>
@@ -175,6 +175,7 @@ export default class MeasureOverview extends React.PureComponent {
<LeakPeriodLegend className="pull-right" component={component} period={leakPeriod} />
)}
</div>
+ <DeferredSpinner loading={this.props.loading} />
{!this.props.loading && this.renderContent()}
</div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js b/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js
index c68d7090f13..4b26994fa81 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js
@@ -20,13 +20,11 @@
// @flow
import React from 'react';
import FilesCounter from './FilesCounter';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
import { translate } from '../../../helpers/l10n';
/*:: import type { Paging } from '../types'; */
/*:: type Props = {|
current: ?number,
- loading: boolean,
isFile: ?boolean,
paging: ?Paging,
totalLoadedComponents?: number,
@@ -41,9 +39,6 @@ export default function PageActions(props /*: Props */) {
{!isFile && showShortcuts && renderShortcuts()}
{isFile && paging && renderFileShortcuts()}
<div className="measure-details-page-actions">
- <DeferredSpinner loading={props.loading}>
- <i className="spinner-placeholder" />
- </DeferredSpinner>
{paging != null && (
<FilesCounter
className="spacer-left"
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js
index 36a0b3eb152..067ecb4d78d 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js
@@ -23,14 +23,12 @@ import PageActions from '../PageActions';
it('should display correctly for a project', () => {
expect(
- shallow(<PageActions loading={true} isFile={false} view="list" totalLoadedComponents={20} />)
+ shallow(<PageActions isFile={false} totalLoadedComponents={20} view="list" />)
).toMatchSnapshot();
});
it('should display correctly for a file', () => {
- const wrapper = shallow(
- <PageActions loading={false} isFile={true} view="tree" totalLoadedComponents={10} />
- );
+ const wrapper = shallow(<PageActions isFile={true} totalLoadedComponents={10} view="tree" />);
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ paging: { total: 100 } });
expect(wrapper).toMatchSnapshot();
@@ -38,7 +36,7 @@ it('should display correctly for a file', () => {
it('should not display shortcuts for treemap', () => {
expect(
- shallow(<PageActions loading={true} isFile={false} view="treemap" totalLoadedComponents={20} />)
+ shallow(<PageActions isFile={false} totalLoadedComponents={20} view="treemap" />)
).toMatchSnapshot();
});
@@ -47,11 +45,10 @@ it('should display the total of files', () => {
shallow(
<PageActions
current={12}
- loading={true}
isFile={false}
- view="treemap"
- totalLoadedComponents={20}
paging={{ total: 120 }}
+ totalLoadedComponents={20}
+ view="treemap"
/>
)
).toMatchSnapshot();
@@ -59,11 +56,10 @@ it('should display the total of files', () => {
shallow(
<PageActions
current={12}
- loading={false}
isFile={true}
- view="list"
- totalLoadedComponents={20}
paging={{ total: 120 }}
+ totalLoadedComponents={20}
+ view="list"
/>
)
).toMatchSnapshot();
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap
index c33278f92af..9849310b4c2 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap
@@ -6,16 +6,7 @@ exports[`should display correctly for a file 1`] = `
>
<div
className="measure-details-page-actions"
- >
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
- </div>
+ />
</div>
`;
@@ -43,14 +34,6 @@ exports[`should display correctly for a file 2`] = `
<div
className="measure-details-page-actions"
>
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
<FilesCounter
className="spacer-left"
total={10}
@@ -97,16 +80,7 @@ exports[`should display correctly for a project 1`] = `
</span>
<div
className="measure-details-page-actions"
- >
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
- </div>
+ />
</div>
`;
@@ -117,14 +91,6 @@ exports[`should display the total of files 1`] = `
<div
className="measure-details-page-actions"
>
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
<FilesCounter
className="spacer-left"
current={12}
@@ -158,14 +124,6 @@ exports[`should display the total of files 2`] = `
<div
className="measure-details-page-actions"
>
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
<FilesCounter
className="spacer-left"
current={12}
@@ -181,15 +139,6 @@ exports[`should not display shortcuts for treemap 1`] = `
>
<div
className="measure-details-page-actions"
- >
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <i
- className="spinner-placeholder"
- />
- </DeferredSpinner>
- </div>
+ />
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.tsx b/server/sonar-web/src/main/js/apps/issues/components/App.tsx
index 384faec119a..dd2288d8346 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/App.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import Helmet from 'react-helmet';
import * as key from 'keymaster';
-import { keyBy, union, without } from 'lodash';
+import { keyBy, omit, union, without } from 'lodash';
import * as PropTypes from 'prop-types';
import BulkChangeModal from './BulkChangeModal';
import ComponentBreadcrumbs from './ComponentBreadcrumbs';
@@ -75,6 +75,7 @@ import DropdownIcon from '../../../components/icons-components/DropdownIcon';
import { isSonarCloud } from '../../../helpers/system';
import '../../../components/search-navigator.css';
import '../styles.css';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface FetchIssuesPromise {
components: ReferencedComponent[];
@@ -104,6 +105,7 @@ export interface State {
issues: Issue[];
lastChecked?: string;
loading: boolean;
+ loadingFacets: { [key: string]: boolean };
locationsNavigator: boolean;
myIssues: boolean;
openFacets: { [facet: string]: boolean };
@@ -136,6 +138,7 @@ export default class App extends React.PureComponent<Props, State> {
facets: {},
issues: [],
loading: true,
+ loadingFacets: {},
locationsNavigator: false,
myIssues: props.myIssues || areMyIssuesSelected(props.location.query),
openFacets: { severities: true, types: true },
@@ -571,16 +574,21 @@ export default class App extends React.PureComponent<Props, State> {
fetchFacet = (facet: string) => {
const requestOrganizations = facet === 'projects';
+ this.setState(state => ({ loadingFacets: { ...state.loadingFacets, [facet]: true } }));
return this.fetchIssues({ ps: 1, facets: mapFacet(facet) }, false, requestOrganizations).then(
({ facets, ...other }) => {
if (this.mounted) {
this.setState(state => ({
facets: { ...state.facets, ...parseFacets(facets) },
+ loadingFacets: omit(state.loadingFacets, facet),
referencedComponents: {
...state.referencedComponents,
...keyBy(other.components, 'uuid')
},
- referencedLanguages: { ...state.referencedLanguages, ...keyBy(other.languages, 'key') },
+ referencedLanguages: {
+ ...state.referencedLanguages,
+ ...keyBy(other.languages, 'key')
+ },
referencedRules: { ...state.referencedRules, ...keyBy(other.rules, 'key') },
referencedUsers: { ...state.referencedUsers, ...keyBy(other.users, 'login') }
}));
@@ -869,6 +877,7 @@ export default class App extends React.PureComponent<Props, State> {
component={component}
facets={this.state.facets}
loading={this.state.loading}
+ loadingFacets={this.state.loadingFacets}
myIssues={this.state.myIssues}
onFacetToggle={this.handleFacetToggle}
onFilterChange={this.handleFilterChange}
@@ -1004,6 +1013,31 @@ export default class App extends React.PureComponent<Props, State> {
);
}
+ renderPage() {
+ const { openIssue } = this.state;
+ return (
+ <div className="layout-page-main-inner">
+ <DeferredSpinner loading={this.state.loading}>
+ {openIssue ? (
+ <IssuesSourceViewer
+ branchLike={fillBranchLike(openIssue.branch, openIssue.pullRequest)}
+ loadIssues={this.fetchIssuesForComponent}
+ locationsNavigator={this.state.locationsNavigator}
+ onIssueChange={this.handleIssueChange}
+ onIssueSelect={this.openIssue}
+ onLocationSelect={this.selectLocation}
+ openIssue={openIssue}
+ selectedFlowIndex={this.state.selectedFlowIndex}
+ selectedLocationIndex={this.state.selectedLocationIndex}
+ />
+ ) : (
+ this.renderList()
+ )}
+ </DeferredSpinner>
+ </div>
+ );
+ }
+
render() {
const { component } = this.props;
const { openIssue, paging } = this.state;
@@ -1038,7 +1072,6 @@ export default class App extends React.PureComponent<Props, State> {
!this.props.component &&
(!isSonarCloud() || this.props.myIssues)
)}
- loading={this.state.loading}
onReload={this.handleReload}
paging={paging}
selectedIndex={selectedIndex}
@@ -1049,25 +1082,7 @@ export default class App extends React.PureComponent<Props, State> {
</div>
</div>
- <div className="layout-page-main-inner">
- <div>
- {openIssue ? (
- <IssuesSourceViewer
- branchLike={fillBranchLike(openIssue.branch, openIssue.pullRequest)}
- loadIssues={this.fetchIssuesForComponent}
- locationsNavigator={this.state.locationsNavigator}
- onIssueChange={this.handleIssueChange}
- onIssueSelect={this.openIssue}
- onLocationSelect={this.selectLocation}
- openIssue={openIssue}
- selectedFlowIndex={this.state.selectedFlowIndex}
- selectedLocationIndex={this.state.selectedLocationIndex}
- />
- ) : (
- this.renderList()
- )}
- </div>
- </div>
+ {this.renderPage()}
</div>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx b/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx
index 38e0821b0e9..330409caa95 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx
@@ -21,14 +21,12 @@ import * as React from 'react';
import IssuesCounter from './IssuesCounter';
import ReloadButton from './ReloadButton';
import { HomePageType, Paging } from '../../../app/types';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
import HomePageSelect from '../../../components/controls/HomePageSelect';
import { translate } from '../../../helpers/l10n';
import { isSonarCloud } from '../../../helpers/system';
interface Props {
canSetHome: boolean;
- loading: boolean;
onReload: () => void;
paging: Paging | undefined;
selectedIndex: number | undefined;
@@ -61,9 +59,7 @@ export default class PageActions extends React.PureComponent<Props> {
{this.renderShortcuts()}
<div className="issues-page-actions">
- <DeferredSpinner className="issues-main-header-spinner" loading={this.props.loading}>
- <ReloadButton onClick={this.props.onReload} />
- </DeferredSpinner>
+ <ReloadButton onClick={this.props.onReload} />
{paging != null && (
<IssuesCounter className="spacer-left" current={selectedIndex} total={paging.total} />
)}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx
index 7e671e03616..73c22e1498e 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx
@@ -28,11 +28,13 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import Avatar from '../../../components/ui/Avatar';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
export interface Props {
assigned: boolean;
assignees: string[];
component: Component | undefined;
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -201,6 +203,7 @@ export default class AssigneeFacet extends React.PureComponent<Props> {
values={this.getValues()}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
{this.props.open && this.renderFooter()}
</FacetBox>
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx
index 9ea5200d8d5..a163c43c363 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx
@@ -25,8 +25,10 @@ import FacetHeader from '../../../components/facet/FacetHeader';
import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -107,6 +109,7 @@ export default class AuthorFacet extends React.PureComponent<Props> {
values={this.props.authors}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
index 7d242ebf048..db6e7f6eff1 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
@@ -33,6 +33,7 @@ import DateRangeInput from '../../../components/controls/DateRangeInput';
import { isSameDay, parseDate } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
component: Component | undefined;
@@ -40,6 +41,7 @@ interface Props {
createdAt: string;
createdBefore: Date | undefined;
createdInLast: string;
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -290,6 +292,7 @@ export default class CreationDateFacet extends React.PureComponent<Props> {
values={this.getValues()}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderInner()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx
index 248418cee17..b2aa50d02f5 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx
@@ -27,8 +27,10 @@ import FacetItemsList from '../../../components/facet/FacetItemsList';
import QualifierIcon from '../../../components/icons-components/QualifierIcon';
import { translate } from '../../../helpers/l10n';
import { collapsePath } from '../../../helpers/path';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
directories: string[];
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
@@ -125,6 +127,7 @@ export default class DirectoryFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx
index 28a798a2429..86063f1be60 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx
@@ -27,8 +27,10 @@ import FacetItemsList from '../../../components/facet/FacetItemsList';
import QualifierIcon from '../../../components/icons-components/QualifierIcon';
import { translate } from '../../../helpers/l10n';
import { collapsePath } from '../../../helpers/path';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
files: string[];
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
@@ -126,6 +128,7 @@ export default class FileFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx
index 2c63c463044..81585ed2f97 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx
@@ -26,8 +26,10 @@ import FacetHeader from '../../../components/facet/FacetHeader';
import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
languages: string[];
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
@@ -130,6 +132,7 @@ export default class LanguageFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
{this.props.open && this.renderFooter()}
</FacetBox>
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/ModuleFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/ModuleFacet.tsx
index faf97f7d5ae..3f4ec1fb9a4 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/ModuleFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/ModuleFacet.tsx
@@ -26,8 +26,10 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import QualifierIcon from '../../../components/icons-components/QualifierIcon';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
modules: string[];
onChange: (changes: Partial<Query>) => void;
@@ -124,6 +126,7 @@ export default class ModuleFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx
index c684af5b1cd..5163f9683f0 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx
@@ -30,10 +30,12 @@ import FacetFooter from '../../../components/facet/FacetFooter';
import Organization from '../../../components/shared/Organization';
import QualifierIcon from '../../../components/icons-components/QualifierIcon';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
component: Component | undefined;
loading?: boolean;
+ fetching: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
@@ -192,7 +194,7 @@ export default class ProjectFacet extends React.PureComponent<Props> {
open={this.props.open}
values={values}
/>
-
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
{this.props.open && this.renderFooter()}
</FacetBox>
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/ResolutionFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/ResolutionFacet.tsx
index 1a6163d9124..1ad489a6e29 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/ResolutionFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/ResolutionFacet.tsx
@@ -25,8 +25,10 @@ import FacetHeader from '../../../components/facet/FacetHeader';
import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -124,6 +126,7 @@ export default class ResolutionFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && <FacetItemsList>{resolutions.map(this.renderItem)}</FacetItemsList>}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
index e2db449dc3c..46f58bd9e4d 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
@@ -27,8 +27,10 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import FacetFooter from '../../../components/facet/FacetFooter';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
languages: string[];
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
@@ -144,6 +146,7 @@ export default class RuleFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
{this.props.open && this.renderFooter()}
</FacetBox>
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx
index 5d2e61b5e58..dba8a5366bf 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx
@@ -26,8 +26,10 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -104,6 +106,7 @@ export default class SeverityFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && <FacetItemsList>{severities.map(this.renderItem)}</FacetItemsList>}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
index 906e9245842..ace5779f36b 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
@@ -47,6 +47,7 @@ export interface Props {
component: Component | undefined;
facets: { [facet: string]: Facet };
loading?: boolean;
+ loadingFacets: { [key: string]: boolean };
myIssues: boolean;
onFacetToggle: (property: string) => void;
onFilterChange: (changes: Partial<Query>) => void;
@@ -77,6 +78,7 @@ export default class Sidebar extends React.PureComponent<Props> {
return (
<div className="search-navigator-facets-list">
<TypeFacet
+ fetching={this.props.loadingFacets.types === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -85,6 +87,7 @@ export default class Sidebar extends React.PureComponent<Props> {
types={query.types}
/>
<SeverityFacet
+ fetching={this.props.loadingFacets.severities === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -93,6 +96,7 @@ export default class Sidebar extends React.PureComponent<Props> {
stats={facets.severities}
/>
<ResolutionFacet
+ fetching={this.props.loadingFacets.resolutions === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -102,6 +106,7 @@ export default class Sidebar extends React.PureComponent<Props> {
stats={facets.resolutions}
/>
<StatusFacet
+ fetching={this.props.loadingFacets.statuses === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -115,6 +120,7 @@ export default class Sidebar extends React.PureComponent<Props> {
createdAt={query.createdAt}
createdBefore={query.createdBefore}
createdInLast={query.createdInLast}
+ fetching={this.props.loadingFacets.createdAt === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -123,6 +129,7 @@ export default class Sidebar extends React.PureComponent<Props> {
stats={facets.createdAt}
/>
<LanguageFacet
+ fetching={this.props.loadingFacets.languages === true}
languages={query.languages}
loading={this.props.loading}
onChange={this.props.onFilterChange}
@@ -132,6 +139,7 @@ export default class Sidebar extends React.PureComponent<Props> {
stats={facets.languages}
/>
<RuleFacet
+ fetching={this.props.loadingFacets.rules === true}
languages={query.languages}
loading={this.props.loading}
onChange={this.props.onFilterChange}
@@ -146,6 +154,9 @@ export default class Sidebar extends React.PureComponent<Props> {
cwe={query.cwe}
cweOpen={!!openFacets.cwe}
cweStats={facets.cwe}
+ fetchingCwe={this.props.loadingFacets.cwe === true}
+ fetchingOwaspTop10={this.props.loadingFacets.owaspTop10 === true}
+ fetchingSansTop25={this.props.loadingFacets.sansTop25 === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -159,6 +170,7 @@ export default class Sidebar extends React.PureComponent<Props> {
/>
<TagFacet
component={component}
+ fetching={this.props.loadingFacets.tags === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -170,6 +182,7 @@ export default class Sidebar extends React.PureComponent<Props> {
{displayProjectsFacet && (
<ProjectFacet
component={component}
+ fetching={this.props.loadingFacets.projects === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -182,6 +195,7 @@ export default class Sidebar extends React.PureComponent<Props> {
)}
{displayModulesFacet && (
<ModuleFacet
+ fetching={this.props.loadingFacets.modules === true}
loading={this.props.loading}
modules={query.modules}
onChange={this.props.onFilterChange}
@@ -194,6 +208,7 @@ export default class Sidebar extends React.PureComponent<Props> {
{displayDirectoriesFacet && (
<DirectoryFacet
directories={query.directories}
+ fetching={this.props.loadingFacets.directories === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -204,6 +219,7 @@ export default class Sidebar extends React.PureComponent<Props> {
)}
{displayFilesFacet && (
<FileFacet
+ fetching={this.props.loadingFacets.files === true}
files={query.files}
loading={this.props.loading}
onChange={this.props.onFilterChange}
@@ -218,6 +234,7 @@ export default class Sidebar extends React.PureComponent<Props> {
assigned={query.assigned}
assignees={query.assignees}
component={component}
+ fetching={this.props.loadingFacets.assignees === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
@@ -230,6 +247,7 @@ export default class Sidebar extends React.PureComponent<Props> {
{displayAuthorFacet && (
<AuthorFacet
authors={query.authors}
+ fetching={this.props.loadingFacets.authors === true}
loading={this.props.loading}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx
index febd7e1cbdd..9670921d9e1 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx
@@ -32,11 +32,15 @@ import {
renderCWECategory,
Standards
} from '../../securityReports/utils';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
export interface Props {
cwe: string[];
cweOpen: boolean;
cweStats: { [x: string]: number } | undefined;
+ fetchingOwaspTop10: boolean;
+ fetchingSansTop25: boolean;
+ fetchingCwe: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -260,6 +264,7 @@ export default class StandardFacet extends React.PureComponent<Props, State> {
renderOwaspTop10Category(this.state.standards, item)
)}
/>
+ <DeferredSpinner loading={this.props.fetchingOwaspTop10} />
{this.props.owaspTop10Open && this.renderOwaspTop10List()}
</FacetBox>
<FacetBox className="is-inner" property="sansTop25">
@@ -271,6 +276,7 @@ export default class StandardFacet extends React.PureComponent<Props, State> {
renderSansTop25Category(this.state.standards, item)
)}
/>
+ <DeferredSpinner loading={this.props.fetchingSansTop25} />
{this.props.sansTop25Open && this.renderSansTop25List()}
</FacetBox>
<FacetBox className="is-inner" property="cwe">
@@ -280,6 +286,7 @@ export default class StandardFacet extends React.PureComponent<Props, State> {
open={this.props.cweOpen}
values={this.props.cwe.map(item => renderCWECategory(this.state.standards, item))}
/>
+ <DeferredSpinner loading={this.props.fetchingCwe} />
{this.props.cweOpen && this.renderCWEList()}
{this.props.cweOpen && this.renderCWESearch()}
</FacetBox>
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/StatusFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/StatusFacet.tsx
index dea89105567..1eb4e060fc2 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/StatusFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/StatusFacet.tsx
@@ -26,8 +26,10 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import StatusHelper from '../../../components/shared/StatusHelper';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -104,6 +106,7 @@ export default class StatusFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && <FacetItemsList>{statuses.map(this.renderItem)}</FacetItemsList>}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx
index 2db0f5c9118..c4a804d0e69 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx
@@ -30,9 +30,11 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import TagsIcon from '../../../components/icons-components/TagsIcon';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
component: Component | undefined;
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -143,8 +145,8 @@ export default class TagFacet extends React.PureComponent<Props> {
values={this.props.tags}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && this.renderList()}
-
{this.props.open && this.renderFooter()}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx
index 62900a529a3..6246b462078 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx
@@ -26,8 +26,10 @@ import FacetItem from '../../../components/facet/FacetItem';
import FacetItemsList from '../../../components/facet/FacetItemsList';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import { translate } from '../../../helpers/l10n';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface Props {
+ fetching: boolean;
loading?: boolean;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
@@ -118,6 +120,7 @@ export default class TypeFacet extends React.PureComponent<Props> {
values={values}
/>
+ <DeferredSpinner loading={this.props.fetching} />
{this.props.open && <FacetItemsList>{types.map(this.renderItem)}</FacetItemsList>}
</FacetBox>
);
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/AssigneeFacet-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/AssigneeFacet-test.tsx
index efed16ca848..64217b4de0b 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/AssigneeFacet-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/AssigneeFacet-test.tsx
@@ -29,6 +29,7 @@ const renderAssigneeFacet = (props?: Partial<Props>) =>
assigned={true}
assignees={[]}
component={undefined}
+ fetching={false}
onChange={jest.fn()}
onToggle={jest.fn()}
open={true}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx
index cbffca5d94c..7b658ae3db0 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx
@@ -29,6 +29,7 @@ const renderSidebar = (props?: Partial<Props>) =>
<Sidebar
component={undefined}
facets={{}}
+ loadingFacets={{}}
myIssues={false}
onFacetToggle={jest.fn()}
onFilterChange={jest.fn()}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx
index f36d3c29176..815d6b03f93 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx
@@ -153,6 +153,9 @@ function shallowRender(props: Partial<Props> = {}) {
cwe={[]}
cweOpen={false}
cweStats={{}}
+ fetchingCwe={false}
+ fetchingOwaspTop10={false}
+ fetchingSansTop25={false}
onChange={jest.fn()}
onToggle={jest.fn()}
open={false}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/AssigneeFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/AssigneeFacet-test.tsx.snap
index e28401150f4..406c6d77188 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/AssigneeFacet-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/AssigneeFacet-test.tsx.snap
@@ -11,6 +11,10 @@ exports[`should render 1`] = `
open={true}
values={Array []}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={false}
@@ -101,6 +105,10 @@ exports[`should render without stats 1`] = `
open={true}
values={Array []}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
</FacetBox>
`;
@@ -119,6 +127,10 @@ exports[`should select unassigned 1`] = `
]
}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={true}
@@ -201,6 +213,10 @@ exports[`should select user 1`] = `
]
}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={false}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/StandardFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/StandardFacet-test.tsx.snap
index 1982863f389..42bf996ded1 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/StandardFacet-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/StandardFacet-test.tsx.snap
@@ -25,6 +25,10 @@ exports[`should render empty sub-facet 1`] = `
open={true}
values={Array []}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<div
className="search-navigator-facet-empty little-spacer-top"
>
@@ -65,6 +69,10 @@ exports[`should render sub-facets 1`] = `
]
}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={false}
@@ -106,6 +114,10 @@ exports[`should render sub-facets 1`] = `
]
}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={false}
@@ -147,6 +159,10 @@ exports[`should render sub-facets 1`] = `
]
}
/>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
<FacetItemsList>
<FacetItem
active={true}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
index a97b447e3a1..e0b234e235d 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
@@ -39,6 +39,7 @@ import { parseUrlQuery, Query, hasFilterParams, hasVisualizationParams } from '.
import { isSonarCloud } from '../../../helpers/system';
import '../../../components/search-navigator.css';
import '../styles.css';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
export interface Props {
currentUser: CurrentUser;
@@ -277,40 +278,45 @@ export default class AllProjects extends React.PureComponent<Props, State> {
</div>
);
- renderMain = () =>
- this.getView() === 'visualizations' ? (
- <div className="layout-page-main-inner">
- {this.state.projects && (
- <Visualizations
- displayOrganizations={!this.props.organization && this.props.organizationsEnabled}
- projects={this.state.projects}
- sort={this.state.query.sort}
- total={this.state.total}
- visualization={this.getVisualization()}
- />
- )}
- </div>
- ) : (
- <div className="layout-page-main-inner">
- {this.state.projects && (
- <ProjectsList
- cardType={this.getView()}
- currentUser={this.props.currentUser}
- isFavorite={this.props.isFavorite}
- isFiltered={hasFilterParams(this.state.query)}
- organization={this.props.organization}
- projects={this.state.projects}
- query={this.state.query}
- />
+ renderMain = () => {
+ return (
+ <DeferredSpinner loading={this.state.loading}>
+ {this.getView() === 'visualizations' ? (
+ <div className="layout-page-main-inner">
+ {this.state.projects && (
+ <Visualizations
+ displayOrganizations={!this.props.organization && this.props.organizationsEnabled}
+ projects={this.state.projects}
+ sort={this.state.query.sort}
+ total={this.state.total}
+ visualization={this.getVisualization()}
+ />
+ )}
+ </div>
+ ) : (
+ <div className="layout-page-main-inner">
+ {this.state.projects && (
+ <ProjectsList
+ cardType={this.getView()}
+ currentUser={this.props.currentUser}
+ isFavorite={this.props.isFavorite}
+ isFiltered={hasFilterParams(this.state.query)}
+ organization={this.props.organization}
+ projects={this.state.projects}
+ query={this.state.query}
+ />
+ )}
+ <ListFooter
+ count={this.state.projects !== undefined ? this.state.projects.length : 0}
+ loadMore={this.fetchMoreProjects}
+ ready={!this.state.loading}
+ total={this.state.total !== undefined ? this.state.total : 0}
+ />
+ </div>
)}
- <ListFooter
- count={this.state.projects !== undefined ? this.state.projects.length : 0}
- loadMore={this.fetchMoreProjects}
- ready={!this.state.loading}
- total={this.state.total !== undefined ? this.state.total : 0}
- />
- </div>
+ </DeferredSpinner>
);
+ };
render() {
return (
diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
index 17c584fdc52..c29cc32f56c 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
@@ -93,8 +93,6 @@ export default function PageHeader(props: Props) {
className={classNames('projects-topbar-item', 'is-last', {
'is-loading': loading
})}>
- {loading && <i className="spinner spacer-right" />}
-
{total != null && (
<span>
<strong id="projects-total">{total}</strong> {translate('projects._projects')}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
index e2dca712a6e..c4ba6c754a1 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
@@ -79,58 +79,63 @@ exports[`renders 1`] = `
</div>
</div>
</div>
- <div
- className="layout-page-main-inner"
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
>
- <ProjectsList
- cardType="overall"
- currentUser={
- Object {
- "isLoggedIn": true,
+ <div
+ className="layout-page-main-inner"
+ >
+ <ProjectsList
+ cardType="overall"
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ }
}
- }
- isFavorite={false}
- isFiltered={false}
- projects={
- Array [
+ isFavorite={false}
+ isFiltered={false}
+ projects={
+ Array [
+ Object {
+ "key": "foo",
+ "measures": Object {},
+ "name": "Foo",
+ },
+ ]
+ }
+ query={
Object {
- "key": "foo",
- "measures": Object {},
- "name": "Foo",
- },
- ]
- }
- query={
- Object {
- "coverage": undefined,
- "duplications": undefined,
- "gate": undefined,
- "languages": undefined,
- "maintainability": undefined,
- "new_coverage": undefined,
- "new_duplications": undefined,
- "new_lines": undefined,
- "new_maintainability": undefined,
- "new_reliability": undefined,
- "new_security": undefined,
- "reliability": undefined,
- "search": undefined,
- "security": undefined,
- "size": undefined,
- "sort": undefined,
- "tags": undefined,
- "view": undefined,
- "visualization": undefined,
+ "coverage": undefined,
+ "duplications": undefined,
+ "gate": undefined,
+ "languages": undefined,
+ "maintainability": undefined,
+ "new_coverage": undefined,
+ "new_duplications": undefined,
+ "new_lines": undefined,
+ "new_maintainability": undefined,
+ "new_reliability": undefined,
+ "new_security": undefined,
+ "reliability": undefined,
+ "search": undefined,
+ "security": undefined,
+ "size": undefined,
+ "sort": undefined,
+ "tags": undefined,
+ "view": undefined,
+ "visualization": undefined,
+ }
}
- }
- />
- <ListFooter
- count={1}
- loadMore={[Function]}
- ready={true}
- total={0}
- />
- </div>
+ />
+ <ListFooter
+ count={1}
+ loadMore={[Function]}
+ ready={true}
+ total={0}
+ />
+ </div>
+ </DeferredSpinner>
</div>
</div>
`;
@@ -196,24 +201,29 @@ exports[`renders 2`] = `
</div>
</div>
</div>
- <div
- className="layout-page-main-inner"
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
>
- <Visualizations
- displayOrganizations={false}
- projects={
- Array [
- Object {
- "key": "foo",
- "measures": Object {},
- "name": "Foo",
- },
- ]
- }
- total={0}
- visualization="risk"
- />
- </div>
+ <div
+ className="layout-page-main-inner"
+ >
+ <Visualizations
+ displayOrganizations={false}
+ projects={
+ Array [
+ Object {
+ "key": "foo",
+ "measures": Object {},
+ "name": "Foo",
+ },
+ ]
+ }
+ total={0}
+ visualization="risk"
+ />
+ </div>
+ </DeferredSpinner>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
index 5b8486ad3ec..057c6048368 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
@@ -75,9 +75,6 @@ exports[`should render correctly while loading 1`] = `
<div
className="projects-topbar-item is-last is-loading"
>
- <i
- className="spinner spacer-right"
- />
<span>
<strong
id="projects-total"
diff --git a/server/sonar-web/src/main/js/components/search-navigator.css b/server/sonar-web/src/main/js/components/search-navigator.css
index c9ab518bf00..a8205a593ba 100644
--- a/server/sonar-web/src/main/js/components/search-navigator.css
+++ b/server/sonar-web/src/main/js/components/search-navigator.css
@@ -85,6 +85,11 @@
color: var(--secondFontColor);
}
+.search-navigator-facet-box > .spinner {
+ float: right;
+ margin-top: -24px;
+}
+
.search-navigator-facet {
position: relative;
display: inline-block;