aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-09-28 17:15:43 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-09-29 17:09:48 +0200
commitee41573b8b309a123bc23ac623663107cc410af3 (patch)
tree614ed3244115b9e624c637ffe8017628837e8824 /server
parentbb0c0ee739ec64d81a335284674d10e49786a4ec (diff)
downloadsonarqube-ee41573b8b309a123bc23ac623663107cc410af3.tar.gz
sonarqube-ee41573b8b309a123bc23ac623663107cc410af3.zip
SONAR-9792 Add background task error notification related to licensing
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/ce.ts2
-rw-r--r--server/sonar-web/src/main/js/app/components/App.tsx16
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx116
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap51
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>
`;