Browse Source

SONAR-9605 Fix infinite spinner on issues page

tags/6.6-RC1
Grégoire Aubert 6 years ago
parent
commit
eae2f0df4e

+ 61
- 40
server/sonar-web/src/main/js/apps/issues/components/App.js View File

@@ -67,7 +67,6 @@ export type Props = {
currentUser: CurrentUser,
fetchIssues: (query: RawQuery) => Promise<*>,
location: { pathname: string, query: RawQuery },
onRequestFail: Error => void,
organization?: { key: string },
router: {
push: ({ pathname: string, query?: RawQuery }) => void,
@@ -381,27 +380,35 @@ export default class App extends React.PureComponent {

fetchFirstIssues() {
this.setState({ checked: [], loading: true });
return this.fetchIssues({}, true).then(({ facets, issues, paging, ...other }) => {
if (this.mounted) {
const openIssue = this.getOpenIssue(this.props, issues);
this.setState({
facets: parseFacets(facets),
loading: false,
issues,
openIssue,
paging,
referencedComponents: keyBy(other.components, 'uuid'),
referencedLanguages: keyBy(other.languages, 'key'),
referencedRules: keyBy(other.rules, 'key'),
referencedUsers: keyBy(other.users, 'login'),
selected:
issues.length > 0 ? (openIssue != null ? openIssue.key : issues[0].key) : undefined,
selectedFlowIndex: null,
selectedLocationIndex: null
});
return this.fetchIssues({}, true).then(
({ facets, issues, paging, ...other }) => {
if (this.mounted) {
const openIssue = this.getOpenIssue(this.props, issues);
this.setState({
facets: parseFacets(facets),
loading: false,
issues,
openIssue,
paging,
referencedComponents: keyBy(other.components, 'uuid'),
referencedLanguages: keyBy(other.languages, 'key'),
referencedRules: keyBy(other.rules, 'key'),
referencedUsers: keyBy(other.users, 'login'),
selected:
issues.length > 0 ? (openIssue != null ? openIssue.key : issues[0].key) : undefined,
selectedFlowIndex: null,
selectedLocationIndex: null
});
}
return issues;
},
() => {
if (this.mounted) {
this.setState({ loading: false });
}
return Promise.reject();
}
return issues;
});
);
}

fetchIssuesPage = (p /*: number */) => {
@@ -433,15 +440,22 @@ export default class App extends React.PureComponent {
const p = paging.pageIndex + 1;

this.setState({ loading: true });
this.fetchIssuesPage(p).then(response => {
if (this.mounted) {
this.setState(state => ({
loading: false,
issues: [...state.issues, ...response.issues],
paging: response.paging
}));
this.fetchIssuesPage(p).then(
response => {
if (this.mounted) {
this.setState(state => ({
loading: false,
issues: [...state.issues, ...response.issues],
paging: response.paging
}));
}
},
() => {
if (this.mounted) {
this.setState({ loading: false });
}
}
});
);
};

fetchIssuesForComponent = (component /*: string */, from /*: number */, to /*: number */) => {
@@ -469,16 +483,24 @@ export default class App extends React.PureComponent {
}

this.setState({ loading: true });
return this.fetchIssuesUntil(paging.pageIndex + 1, done).then(response => {
const nextIssues = [...issues, ...response.issues];

this.setState({
issues: nextIssues,
loading: false,
paging: response.paging
});
return nextIssues.filter(isSameComponent);
});
return this.fetchIssuesUntil(paging.pageIndex + 1, done).then(
response => {
const nextIssues = [...issues, ...response.issues];
if (this.mounted) {
this.setState({
issues: nextIssues,
loading: false,
paging: response.paging
});
}
return nextIssues.filter(isSameComponent);
},
() => {
if (this.mounted) {
this.setState({ loading: false });
}
}
);
};

fetchFacet = (facet /*: string */) => {
@@ -671,7 +693,6 @@ export default class App extends React.PureComponent {
fetchIssues={bulkChange === 'all' ? this.fetchIssues : this.getCheckedIssues}
onClose={this.closeBulkChange}
onDone={this.handleBulkChangeDone}
onRequestFail={this.props.onRequestFail}
organization={this.props.organization}
/>}
</div>

+ 4
- 7
server/sonar-web/src/main/js/apps/issues/components/AppContainer.js View File

@@ -23,7 +23,7 @@ import { withRouter } from 'react-router';
/*:: import type { Dispatch } from 'redux'; */
import { uniq } from 'lodash';
import App from './App';
import { onFail } from '../../../store/rootActions';
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { getComponent, getCurrentUser } from '../../../store/rootReducer';
import { getOrganizations } from '../../../api/organizations';
import { receiveOrganizations } from '../../../store/organizations/duck';
@@ -46,7 +46,7 @@ const fetchIssueOrganizations = issues => dispatch => {
const organizationKeys = uniq(issues.map(issue => issue.organization));
return getOrganizations(organizationKeys).then(
response => dispatch(receiveOrganizations(response.organizations)),
onFail(dispatch)
throwGlobalError
);
};

@@ -59,11 +59,8 @@ const fetchIssues = (query /*: RawQuery */) => dispatch =>
return { ...response, issues: parsedIssues };
})
.then(response => dispatch(fetchIssueOrganizations(response.issues)).then(() => response))
.catch(onFail(dispatch));
.catch(throwGlobalError);

const onRequestFail = (error /*: Error */) => (dispatch /*: Dispatch<*> */) =>
onFail(dispatch)(error);

const mapDispatchToProps = { fetchIssues, onRequestFail };
const mapDispatchToProps = { fetchIssues };

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(App));

+ 2
- 2
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.js View File

@@ -29,6 +29,7 @@ import MarkdownTips from '../../../components/common/MarkdownTips';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import Avatar from '../../../components/ui/Avatar';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { searchIssueTags, bulkChangeIssues } from '../../../api/issues';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { searchAssignees } from '../utils';
@@ -42,7 +43,6 @@ type Props = {|
fetchIssues: ({}) => Promise<*>,
onClose: () => void,
onDone: () => void,
onRequestFail: Error => void,
organization?: { key: string }
|};
*/
@@ -200,7 +200,7 @@ export default class BulkChangeModal extends React.PureComponent {
},
(error /*: Error */) => {
this.setState({ submitting: false });
this.props.onRequestFail(error);
throwGlobalError(error);
}
);
};

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/components/IssuesCounter.js View File

@@ -24,13 +24,14 @@ import { formatMeasure } from '../../../helpers/measures';

/*::
type Props = {
className? : string,
current: ?number,
total: number
};
*/

const IssuesCounter = (props /*: Props */) =>
<span>
<span className={props.className}>
<strong>
{props.current != null &&
<span>

+ 6
- 4
server/sonar-web/src/main/js/apps/issues/components/PageActions.js View File

@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import IssuesCounter from './IssuesCounter';
import ReloadButton from './ReloadButton';
/*:: import type { Paging } from '../utils'; */
@@ -62,10 +63,11 @@ export default class PageActions extends React.PureComponent {
{this.renderShortcuts()}

<div className="issues-page-actions">
{this.props.loading
? <i className="issues-main-header-spinner spinner spacer-right" />
: <ReloadButton className="spacer-right" onClick={this.props.onReload} />}
{paging != null && <IssuesCounter current={selectedIndex} total={paging.total} />}
<DeferredSpinner className="issues-main-header-spinner" loading={this.props.loading}>
<ReloadButton onClick={this.props.onReload} />
</DeferredSpinner>
{paging != null &&
<IssuesCounter className="spacer-left" current={selectedIndex} total={paging.total} />}
</div>
</div>
);

+ 4
- 0
server/sonar-web/src/main/js/apps/issues/styles.css View File

@@ -2,6 +2,10 @@
line-height: 24px;
}

.issues-main-header-spinner {
margin-right: 2px;
}

.concise-issues-list-header,
.concise-issues-list-header-inner {
}

Loading…
Cancel
Save