diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-09-28 17:15:43 +0200 |
---|---|---|
committer | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-09-29 17:09:48 +0200 |
commit | ee41573b8b309a123bc23ac623663107cc410af3 (patch) | |
tree | 614ed3244115b9e624c637ffe8017628837e8824 /server | |
parent | bb0c0ee739ec64d81a335284674d10e49786a4ec (diff) | |
download | sonarqube-ee41573b8b309a123bc23ac623663107cc410af3.tar.gz sonarqube-ee41573b8b309a123bc23ac623663107cc410af3.zip |
SONAR-9792 Add background task error notification related to licensing
Diffstat (limited to 'server')
5 files changed, 136 insertions, 95 deletions
diff --git a/server/sonar-web/src/main/js/api/ce.ts b/server/sonar-web/src/main/js/api/ce.ts index 01ed1a7a090..a61b0e2051b 100644 --- a/server/sonar-web/src/main/js/api/ce.ts +++ b/server/sonar-web/src/main/js/api/ce.ts @@ -21,7 +21,6 @@ import { getJSON, post, RequestData } from '../helpers/request'; import throwGlobalError from '../app/utils/throwGlobalError'; export interface PendingTask { - componentId: string; componentKey: string; componentName: string; componentQualifier: string; @@ -37,6 +36,7 @@ export interface PendingTask { export interface Task extends PendingTask { analysisId?: string; errorMessage?: string; + errorType?: string; executionTimeMs: number; executedAt: Date; hasErrorStacktrace: boolean; diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx index a46f417a3ac..8ab6f6b8f40 100644 --- a/server/sonar-web/src/main/js/app/components/App.tsx +++ b/server/sonar-web/src/main/js/app/components/App.tsx @@ -33,21 +33,27 @@ interface Props { interface State { branchesEnabled: boolean; + canAdmin: boolean; loading: boolean; onSonarCloud: boolean; } class App extends React.PureComponent<Props, State> { mounted: boolean; - state: State = { branchesEnabled: false, loading: true, onSonarCloud: false }; + state: State = { branchesEnabled: false, canAdmin: false, loading: true, onSonarCloud: false }; static childContextTypes = { branchesEnabled: PropTypes.bool.isRequired, + canAdmin: PropTypes.bool.isRequired, onSonarCloud: PropTypes.bool }; getChildContext() { - return { branchesEnabled: this.state.branchesEnabled, onSonarCloud: this.state.onSonarCloud }; + return { + branchesEnabled: this.state.branchesEnabled, + canAdmin: this.state.canAdmin, + onSonarCloud: this.state.onSonarCloud + }; } componentDidMount() { @@ -69,7 +75,11 @@ class App extends React.PureComponent<Props, State> { const onSonarCloud = appState.settings != undefined && appState.settings['sonar.lf.sonarqube.com.enabled'] === 'true'; - this.setState({ branchesEnabled: appState.branchesEnabled, onSonarCloud }); + this.setState({ + branchesEnabled: appState.branchesEnabled, + canAdmin: appState.canAdmin, + onSonarCloud + }); } }); }; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx index 7869f9a6710..732b7ea3170 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx @@ -18,12 +18,15 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { Link } from 'react-router'; +import { FormattedMessage } from 'react-intl'; +import * as PropTypes from 'prop-types'; import NavBarNotif from '../../../../components/nav/NavBarNotif'; import PendingIcon from '../../../../components/icons-components/PendingIcon'; import { Component } from '../../../types'; import { STATUSES } from '../../../../apps/background-tasks/constants'; import { getComponentBackgroundTaskUrl } from '../../../../helpers/urls'; -import { translate, translateWithParameters } from '../../../../helpers/l10n'; +import { hasMessage, translate } from '../../../../helpers/l10n'; import { Task } from '../../../../api/ce'; interface Props { @@ -33,54 +36,73 @@ interface Props { isPending?: boolean; } -export default function ComponentNavBgTaskNotif({ - component, - currentTask, - isInProgress, - isPending -}: Props) { - const canSeeBackgroundTasks = - component.configuration != undefined && component.configuration.showBackgroundTasks; - const url = getComponentBackgroundTaskUrl(component.key); +export default class ComponentNavBgTaskNotif extends React.PureComponent<Props> { + static contextTypes = { + canAdmin: PropTypes.bool.isRequired + }; - if (isInProgress) { - return ( - <NavBarNotif className="alert alert-info"> - <i className="spinner spacer-right" /> - <span - dangerouslySetInnerHTML={{ - __html: canSeeBackgroundTasks - ? translateWithParameters('component_navigation.status.in_progress.admin', url) - : translate('component_navigation.status.in_progress') - }} - /> - </NavBarNotif> - ); - } else if (isPending) { - return ( - <NavBarNotif className="alert alert-info"> - <PendingIcon className="spacer-right" /> - <span - dangerouslySetInnerHTML={{ - __html: canSeeBackgroundTasks - ? translateWithParameters('component_navigation.status.pending.admin', url) - : translate('component_navigation.status.pending') - }} - /> - </NavBarNotif> - ); - } else if (currentTask && currentTask.status === STATUSES.FAILED) { - return ( - <NavBarNotif className="alert alert-danger"> - <span - dangerouslySetInnerHTML={{ - __html: canSeeBackgroundTasks - ? translateWithParameters('component_navigation.status.failed.admin', url) - : translate('component_navigation.status.failed') + renderMessage(messageKey: string) { + const { component } = this.props; + const canSeeBackgroundTasks = + component.configuration != undefined && component.configuration.showBackgroundTasks; + const bgTaskUrl = getComponentBackgroundTaskUrl(component.key); + + if (canSeeBackgroundTasks) { + return ( + <FormattedMessage + defaultMessage={translate(messageKey, 'admin')} + id={messageKey + '.admin'} + values={{ + url: <Link to={bgTaskUrl}>{translate('background_tasks.page')}</Link> }} /> - </NavBarNotif> - ); + ); + } + + return <span>{translate(messageKey)}</span>; + } + + render() { + const { currentTask, isInProgress, isPending } = this.props; + + if (isInProgress) { + return ( + <NavBarNotif className="alert alert-info"> + <i className="spinner spacer-right text-bottom" /> + {this.renderMessage('component_navigation.status.in_progress')} + </NavBarNotif> + ); + } else if (isPending) { + return ( + <NavBarNotif className="alert alert-info"> + <PendingIcon className="spacer-right" /> + {this.renderMessage('component_navigation.status.pending')} + </NavBarNotif> + ); + } else if (currentTask && currentTask.status === STATUSES.FAILED) { + if ( + currentTask.errorType && + currentTask.errorType.includes('LICENSING') && + hasMessage('license.component_navigation.button', currentTask.errorType) + ) { + return ( + <NavBarNotif className="alert alert-danger"> + <span>{currentTask.errorMessage}</span> + {this.context.canAdmin && ( + <Link className="little-spacer-left" to="/admin/extension/license/app"> + {translate('license.component_navigation.button', currentTask.errorType)}. + </Link> + )} + </NavBarNotif> + ); + } + + return ( + <NavBarNotif className="alert alert-danger"> + {this.renderMessage('component_navigation.status.failed')} + </NavBarNotif> + ); + } + return null; } - return null; } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx index 3a06ad1fadb..72e517426cc 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx @@ -17,6 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +jest.mock('../../../../../helpers/l10n', () => { + const l10n = require.requireActual('../../../../../helpers/l10n'); + l10n.hasMessage = jest.fn(() => true); + return l10n; +}); + import * as React from 'react'; import { shallow } from 'enzyme'; import ComponentNavBgTaskNotif from '../ComponentNavBgTaskNotif'; @@ -33,34 +39,30 @@ const component = { }; it('renders background task error correctly', () => { - expect( - shallow( - <ComponentNavBgTaskNotif component={component} currentTask={{ status: 'FAILED' } as Task} /> - ) - ).toMatchSnapshot(); + expect(getWrapper()).toMatchSnapshot(); }); it('renders background task pending info correctly', () => { - expect( - shallow( - <ComponentNavBgTaskNotif - component={component} - isPending={true} - currentTask={{ status: 'FAILED' } as Task} - /> - ) - ).toMatchSnapshot(); + expect(getWrapper({ isPending: true })).toMatchSnapshot(); }); it('renders background task in progress info correctly', () => { + expect(getWrapper({ isInProgress: true, isPending: true })).toMatchSnapshot(); +}); + +it('renders background task license info correctly', () => { expect( - shallow( - <ComponentNavBgTaskNotif - component={component} - isInProgress={true} - isPending={true} - currentTask={{ status: 'FAILED' } as Task} - /> - ) + getWrapper({ currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } }) ).toMatchSnapshot(); }); + +function getWrapper(props = {}) { + return shallow( + <ComponentNavBgTaskNotif + component={component} + currentTask={{ status: 'FAILED' } as Task} + {...props} + />, + { context: { canAdmin: true } } + ); +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap index 423b6a5d618..679067cb000 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap @@ -4,13 +4,9 @@ exports[`renders background task error correctly 1`] = ` <NavBarNotif className="alert alert-danger" > - <span - dangerouslySetInnerHTML={ - Object { - "__html": "component_navigation.status.failed", - } - } - /> + <span> + component_navigation.status.failed + </span> </NavBarNotif> `; @@ -19,15 +15,30 @@ exports[`renders background task in progress info correctly 1`] = ` className="alert alert-info" > <i - className="spinner spacer-right" - /> - <span - dangerouslySetInnerHTML={ - Object { - "__html": "component_navigation.status.in_progress", - } - } + className="spinner spacer-right text-bottom" /> + <span> + component_navigation.status.in_progress + </span> +</NavBarNotif> +`; + +exports[`renders background task license info correctly 1`] = ` +<NavBarNotif + className="alert alert-danger" +> + <span> + Foo + </span> + <Link + className="little-spacer-left" + onlyActiveOnIndex={false} + style={Object {}} + to="/admin/extension/license/app" + > + license.component_navigation.button.LICENSING + . + </Link> </NavBarNotif> `; @@ -38,12 +49,8 @@ exports[`renders background task pending info correctly 1`] = ` <PendingIcon className="spacer-right" /> - <span - dangerouslySetInnerHTML={ - Object { - "__html": "component_navigation.status.pending", - } - } - /> + <span> + component_navigation.status.pending + </span> </NavBarNotif> `; |