aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-09-28 14:25:14 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-09-29 17:09:48 +0200
commitb0b438b44dc7f1f534fbcbfc58a07c83138957f2 (patch)
treefbded71de7d7002c3dfd9d8953f91d5aeea0a91f /server
parent9730d937b6465116379d183835665deec4c38297 (diff)
downloadsonarqube-b0b438b44dc7f1f534fbcbfc58a07c83138957f2.tar.gz
sonarqube-b0b438b44dc7f1f534fbcbfc58a07c83138957f2.zip
SONAR-9792 The fail background task status is now more visible
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/ce.ts31
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx38
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx46
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx15
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx36
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap15
-rw-r--r--server/sonar-web/src/main/js/components/nav/ContextNavBar.css4
-rw-r--r--server/sonar-web/src/main/js/components/nav/NavBar.css6
-rw-r--r--server/sonar-web/src/main/js/components/nav/NavBar.tsx9
-rw-r--r--server/sonar-web/src/main/js/components/nav/NavBarNotif.tsx39
-rw-r--r--server/sonar-web/src/main/js/helpers/urls.ts4
12 files changed, 212 insertions, 32 deletions
diff --git a/server/sonar-web/src/main/js/api/ce.ts b/server/sonar-web/src/main/js/api/ce.ts
index c0146360ada..01ed1a7a090 100644
--- a/server/sonar-web/src/main/js/api/ce.ts
+++ b/server/sonar-web/src/main/js/api/ce.ts
@@ -20,6 +20,30 @@
import { getJSON, post, RequestData } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';
+export interface PendingTask {
+ componentId: string;
+ componentKey: string;
+ componentName: string;
+ componentQualifier: string;
+ id: string;
+ logs: boolean;
+ organization: string;
+ status: string;
+ submittedAt: Date;
+ submitterLogin?: string;
+ type: string;
+}
+
+export interface Task extends PendingTask {
+ analysisId?: string;
+ errorMessage?: string;
+ executionTimeMs: number;
+ executedAt: Date;
+ hasErrorStacktrace: boolean;
+ hasScannerContext: boolean;
+ startedAt: Date;
+}
+
export function getActivity(data: RequestData): Promise<any> {
return getJSON('/api/ce/activity', data);
}
@@ -44,7 +68,12 @@ export function cancelAllTasks(): Promise<any> {
return post('/api/ce/cancel_all');
}
-export function getTasksForComponent(componentKey: string): Promise<any> {
+export function getTasksForComponent(
+ componentKey: string
+): Promise<{
+ queue: PendingTask[];
+ current: Task;
+}> {
return getJSON('/api/ce/component', { componentKey });
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
index 27c39fa2a97..1a954a26d23 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
@@ -19,14 +19,15 @@
*/
import * as React from 'react';
import ComponentNavFavorite from './ComponentNavFavorite';
+import ComponentNavBranch from './ComponentNavBranch';
import ComponentNavBreadcrumbs from './ComponentNavBreadcrumbs';
import ComponentNavMeta from './ComponentNavMeta';
import ComponentNavMenu from './ComponentNavMenu';
-import ComponentNavBranch from './ComponentNavBranch';
+import ComponentNavBgTaskNotif from './ComponentNavBgTaskNotif';
import RecentHistory from '../../RecentHistory';
import { Branch, Component } from '../../../types';
import ContextNavBar from '../../../../components/nav/ContextNavBar';
-import { getTasksForComponent } from '../../../../api/ce';
+import { getTasksForComponent, PendingTask, Task } from '../../../../api/ce';
import { STATUSES } from '../../../../apps/background-tasks/constants';
import './ComponentNav.css';
@@ -38,7 +39,7 @@ interface Props {
}
interface State {
- isFailed?: boolean;
+ currentTask?: Task;
isInProgress?: boolean;
isPending?: boolean;
}
@@ -54,17 +55,26 @@ export default class ComponentNav extends React.PureComponent<Props, State> {
this.populateRecentHistory();
}
+ componentDidUpdate(prevProps: Props) {
+ if (this.props.component.key !== prevProps.component.key) {
+ this.loadStatus();
+ this.populateRecentHistory();
+ }
+ }
+
componentWillUnmount() {
this.mounted = false;
}
loadStatus = () => {
- getTasksForComponent(this.props.component.key).then((r: any) => {
+ getTasksForComponent(
+ this.props.component.key
+ ).then((r: { queue: PendingTask[]; current: Task }) => {
if (this.mounted) {
this.setState({
- isPending: r.queue.some((task: any) => task.status === STATUSES.PENDING),
- isInProgress: r.queue.some((task: any) => task.status === STATUSES.IN_PROGRESS),
- isFailed: r.current && r.current.status === STATUSES.FAILED
+ currentTask: r.current,
+ isInProgress: r.queue.some(task => task.status === STATUSES.IN_PROGRESS),
+ isPending: r.queue.some(task => task.status === STATUSES.PENDING)
});
}
});
@@ -84,18 +94,23 @@ export default class ComponentNav extends React.PureComponent<Props, State> {
};
render() {
+ const { currentTask } = this.state;
+ const showNotif = currentTask && currentTask.status === STATUSES.FAILED;
return (
- <ContextNavBar id="context-navigation" height={65}>
+ <ContextNavBar
+ id="context-navigation"
+ height={showNotif ? 95 : 65}
+ notif={
+ showNotif ? <ComponentNavBgTaskNotif component={this.props.component} /> : undefined
+ }>
<ComponentNavFavorite
component={this.props.component.key}
favorite={this.props.component.isFavorite}
/>
-
<ComponentNavBreadcrumbs
component={this.props.component}
breadcrumbs={this.props.component.breadcrumbs}
/>
-
{this.props.currentBranch && (
<ComponentNavBranch
branches={this.props.branches}
@@ -105,15 +120,12 @@ export default class ComponentNav extends React.PureComponent<Props, State> {
location={this.props.location}
/>
)}
-
<ComponentNavMeta
branch={this.props.currentBranch}
component={this.props.component}
isInProgress={this.state.isInProgress}
- isFailed={this.state.isFailed}
isPending={this.state.isPending}
/>
-
<ComponentNavMenu
branch={this.props.currentBranch}
component={this.props.component}
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
new file mode 100644
index 00000000000..120eb42ab53
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * 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 NavBarNotif from '../../../../components/nav/NavBarNotif';
+import { Component } from '../../../types';
+import { getComponentBackgroundTaskUrl } from '../../../../helpers/urls';
+import { translate, translateWithParameters } from '../../../../helpers/l10n';
+
+interface Props {
+ component: Component;
+}
+
+export default function ComponentNavBgTaskNotif({ component }: Props) {
+ const canSeeBackgroundTasks =
+ component.configuration != undefined && component.configuration.showBackgroundTasks;
+
+ const message = canSeeBackgroundTasks
+ ? translateWithParameters(
+ 'component_navigation.status.failed.admin',
+ getComponentBackgroundTaskUrl(component.key)
+ )
+ : translate('component_navigation.status.failed');
+
+ return (
+ <NavBarNotif className="alert alert-danger">
+ <span dangerouslySetInnerHTML={{ __html: message }} />
+ </NavBarNotif>
+ );
+}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
index ea33a7af4f8..2e0f3f2a560 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
@@ -30,7 +30,6 @@ interface Props {
branch?: Branch;
component: Component;
isInProgress?: boolean;
- isFailed?: boolean;
isPending?: boolean;
}
@@ -73,20 +72,6 @@ export default function ComponentNavMeta(props: Props) {
</li>
</Tooltip>
);
- } else if (props.isFailed) {
- const tooltip = canSeeBackgroundTasks
- ? translateWithParameters('component_navigation.status.failed.admin', backgroundTasksUrl)
- : translate('component_navigation.status.failed');
- metaList.push(
- <Tooltip
- key="isFailed"
- overlay={<div dangerouslySetInnerHTML={{ __html: tooltip }} />}
- mouseLeaveDelay={2}>
- <li>
- <span className="badge badge-danger">{translate('background_task.status.FAILED')}</span>
- </li>
- </Tooltip>
- );
}
if (props.component.analysisDate) {
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
new file mode 100644
index 00000000000..7a4fe19162b
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * 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 ComponentNavBgTaskNotif from '../ComponentNavBgTaskNotif';
+
+const component = {
+ analysisDate: '2017-01-02T00:00:00.000Z',
+ breadcrumbs: [],
+ key: 'foo',
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+it('renders background task notif correctly', () => {
+ expect(shallow(<ComponentNavBgTaskNotif component={component} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
index b110b9a507a..5222368fae8 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
@@ -50,7 +50,6 @@ exports[`renders 1`] = `
"qualifier": "TRK",
}
}
- isFailed={true}
isInProgress={true}
isPending={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
new file mode 100644
index 00000000000..de960261c68
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders background task notif correctly 1`] = `
+<NavBarNotif
+ className="alert alert-danger"
+>
+ <span
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "component_navigation.status.failed",
+ }
+ }
+ />
+</NavBarNotif>
+`;
diff --git a/server/sonar-web/src/main/js/components/nav/ContextNavBar.css b/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
index 25f9470753a..0e527545ca2 100644
--- a/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
+++ b/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
@@ -9,6 +9,10 @@
border-bottom: 1px solid #e6e6e6;
}
+.navbar-context .navbar-inner-with-notif {
+ border-bottom: none;
+}
+
.navbar-context-header {
float: left;
line-height: 30px;
diff --git a/server/sonar-web/src/main/js/components/nav/NavBar.css b/server/sonar-web/src/main/js/components/nav/NavBar.css
index e37b1188948..fb9393dd02e 100644
--- a/server/sonar-web/src/main/js/components/nav/NavBar.css
+++ b/server/sonar-web/src/main/js/components/nav/NavBar.css
@@ -22,3 +22,9 @@
padding-left: 20px;
padding-right: 20px;
}
+
+.navbar-notif.alert {
+ border-left: none;
+ border-right: none;
+ padding: 6px 0;
+}
diff --git a/server/sonar-web/src/main/js/components/nav/NavBar.tsx b/server/sonar-web/src/main/js/components/nav/NavBar.tsx
index bc760ba35a0..e44a3e9d722 100644
--- a/server/sonar-web/src/main/js/components/nav/NavBar.tsx
+++ b/server/sonar-web/src/main/js/components/nav/NavBar.tsx
@@ -19,19 +19,24 @@
*/
import * as React from 'react';
import * as classNames from 'classnames';
+import NavBarNotif from './NavBarNotif';
import './NavBar.css';
interface Props {
children?: any;
className?: string;
height: number;
+ notif?: React.ReactElement<NavBarNotif>;
}
-export default function NavBar({ children, className, height, ...other }: Props) {
+export default function NavBar({ children, className, height, notif, ...other }: Props) {
return (
<nav {...other} className={classNames('navbar', className)} style={{ height }}>
- <div className="navbar-inner" style={{ height }}>
+ <div
+ className={classNames('navbar-inner', { 'navbar-inner-with-notif': notif != null })}
+ style={{ height }}>
<div className="navbar-limited clearfix">{children}</div>
+ {notif}
</div>
</nav>
);
diff --git a/server/sonar-web/src/main/js/components/nav/NavBarNotif.tsx b/server/sonar-web/src/main/js/components/nav/NavBarNotif.tsx
new file mode 100644
index 00000000000..9004c1b7fe9
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/nav/NavBarNotif.tsx
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * 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 * as classNames from 'classnames';
+
+interface Props {
+ children?: React.ReactNode;
+ className?: string;
+}
+
+export default class NavBarNotif extends React.PureComponent<Props> {
+ render() {
+ if (!this.props.children) {
+ return null;
+ }
+ return (
+ <div className={classNames('navbar-notif', this.props.className)}>
+ <div className="navbar-limited clearfix">{this.props.children}</div>
+ </div>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts
index 773448fad23..b125e48533d 100644
--- a/server/sonar-web/src/main/js/helpers/urls.ts
+++ b/server/sonar-web/src/main/js/helpers/urls.ts
@@ -43,6 +43,10 @@ export function getComponentUrl(componentKey: string, branch?: string): string {
return getBaseUrl() + '/dashboard?id=' + encodeURIComponent(componentKey) + branchQuery;
}
+export function getComponentBackgroundTaskUrl(componentKey: string): string {
+ return getBaseUrl() + '/project/background_tasks?id=' + encodeURIComponent(componentKey);
+}
+
export function getProjectUrl(key: string, branch?: string): Location {
return { pathname: '/dashboard', query: { id: key, branch } };
}