]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9792 The fail background task status is now more visible
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 28 Sep 2017 12:25:14 +0000 (14:25 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Fri, 29 Sep 2017 15:09:48 +0000 (17:09 +0200)
13 files changed:
server/sonar-web/src/main/js/api/ce.ts
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBgTaskNotif.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBgTaskNotif-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBgTaskNotif-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/components/nav/ContextNavBar.css
server/sonar-web/src/main/js/components/nav/NavBar.css
server/sonar-web/src/main/js/components/nav/NavBar.tsx
server/sonar-web/src/main/js/components/nav/NavBarNotif.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/urls.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index c0146360ada91fe1871f8f9e819c147b5ebe1e68..01ed1a7a090bc769d7178f3c89a9e8f27ba25b2f 100644 (file)
 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 });
 }
 
index 27c39fa2a97f47c644632a15be11c235307cdd96..1a954a26d23692ef4587fac7d008680830025cd3 100644 (file)
  */
 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 (file)
index 0000000..120eb42
--- /dev/null
@@ -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>
+  );
+}
index ea33a7af4f83eba914b5bd0a26bf771b267a1e11..2e0f3f2a5606399e58c8080ae9636581e8750950 100644 (file)
@@ -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 (file)
index 0000000..7a4fe19
--- /dev/null
@@ -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();
+});
index b110b9a507a2e6a21391976b84618f1538a54932..5222368fae86ead203e4f4071ee3335e1c5a6e5e 100644 (file)
@@ -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 (file)
index 0000000..de96026
--- /dev/null
@@ -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>
+`;
index 25f9470753afc781dc21f3e44ab8b37df2274015..0e527545ca26766f0f964968cc9ce36fe80cb876 100644 (file)
@@ -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;
index e37b1188948d66899eab2656e497de94a179eece..fb9393dd02e9a7a2664823e6d522d086c5397b53 100644 (file)
@@ -22,3 +22,9 @@
   padding-left: 20px;
   padding-right: 20px;
 }
+
+.navbar-notif.alert {
+  border-left: none;
+  border-right: none;
+  padding: 6px 0;
+}
index bc760ba35a0c0293d42e9c473a1bc64a0d8cd7e6..e44a3e9d7221328d439fdf10a13a05580be80e7c 100644 (file)
  */
 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 (file)
index 0000000..9004c1b
--- /dev/null
@@ -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>
+    );
+  }
+}
index 773448fad23bc2f097f9695cdf2e8ca23d4691db..b125e48533d9507122c11590a20ba21c2df19597 100644 (file)
@@ -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 } };
 }
index 7bf157dc1393bb429b7a4abbccc0f90c3e19b42f..07154513eba63be341c9cb3c8748cb55a6e416c0 100644 (file)
@@ -2776,7 +2776,7 @@ update_center.status.DEPS_REQUIRE_SYSTEM_UPGRADE=Some of dependencies requires s
 #
 #------------------------------------------------------------------------------
 component_navigation.status.failed=The last analysis has failed.
-component_navigation.status.failed.admin=The last analysis has failed.<br>More details available on the <a href="{0}">Background Tasks</a> page.
+component_navigation.status.failed.admin=The last analysis has failed. More details available on the <a href="{0}">Background Tasks</a> page.
 component_navigation.status.pending=There is a pending analysis.
 component_navigation.status.pending.admin=There is a pending analysis.<br>More details available on the <a href="{0}">Background Tasks</a> page.
 component_navigation.status.in_progress=The analysis is in progress.