From 33fb963df2b706520da3673e0ebd9947b768f681 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Wed, 19 Sep 2018 16:30:22 +0200 Subject: [PATCH] SONAR-11260 Use WS api/ce/analysis_status to display warnings in dashboard --- server/sonar-web/src/main/js/api/ce.ts | 17 ++++++ .../js/app/components/ComponentContainer.tsx | 19 +++++- .../__tests__/ComponentContainer-test.tsx | 1 + .../components/nav/component/ComponentNav.tsx | 3 +- .../nav/component/ComponentNavMeta.tsx | 16 +++-- .../nav/component/ComponentNavWarnings.tsx | 7 +-- .../component/__tests__/ComponentNav-test.tsx | 1 + .../__tests__/ComponentNavMeta-test.tsx | 3 + .../__tests__/ComponentNavWarnings-test.tsx | 2 +- .../__snapshots__/ComponentNav-test.tsx.snap | 1 + .../ComponentNavWarnings-test.tsx.snap | 8 ++- .../common/AnalysisWarningsModal.tsx | 27 +++++---- .../__tests__/AnalysisWarningsModal-test.tsx | 20 +++++-- .../AnalysisWarningsModal-test.tsx.snap | 60 +++++++++++++++++++ 14 files changed, 154 insertions(+), 31 deletions(-) diff --git a/server/sonar-web/src/main/js/api/ce.ts b/server/sonar-web/src/main/js/api/ce.ts index 3762ec76e1c..6b6476a2798 100644 --- a/server/sonar-web/src/main/js/api/ce.ts +++ b/server/sonar-web/src/main/js/api/ce.ts @@ -21,6 +21,23 @@ import { getJSON, post, RequestData } from '../helpers/request'; import throwGlobalError from '../app/utils/throwGlobalError'; import { Task } from '../app/types'; +export function getAnalysisStatus(data: { + component: string; + branch?: string; + pullRequest?: string; +}): Promise<{ + component: { + branch?: string; + key: string; + name: string; + organization?: string; + pullRequest?: string; + warnings: string[]; + }; +}> { + return getJSON('/api/ce/analysis_status', data).catch(throwGlobalError); +} + export function getActivity(data: RequestData): Promise<{ tasks: Task[] }> { return getJSON('/api/ce/activity', data); } diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index f7c488be19a..ef37ea8376e 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -26,7 +26,7 @@ import ComponentNav from './nav/component/ComponentNav'; import { Component, BranchLike, Measure, Task } from '../types'; import handleRequiredAuthorization from '../utils/handleRequiredAuthorization'; import { getBranches, getPullRequests } from '../../api/branches'; -import { getTasksForComponent } from '../../api/ce'; +import { getTasksForComponent, getAnalysisStatus } from '../../api/ce'; import { getComponentData } from '../../api/components'; import { getMeasures } from '../../api/measures'; import { getComponentNavigation } from '../../api/nav'; @@ -58,6 +58,7 @@ interface State { isPending: boolean; loading: boolean; tasksInProgress?: Task[]; + warnings: string[]; } const FETCH_STATUS_WAIT_TIME = 3000; @@ -72,7 +73,7 @@ export class ComponentContainer extends React.PureComponent { constructor(props: Props) { super(props); - this.state = { branchLikes: [], isPending: false, loading: true }; + this.state = { branchLikes: [], isPending: false, loading: true, warnings: [] }; } componentDidMount() { @@ -138,6 +139,7 @@ export class ComponentContainer extends React.PureComponent { loading: false }); this.fetchStatus(component); + this.fetchWarnings(component, branchLike); } }) .catch(onError); @@ -254,6 +256,18 @@ export class ComponentContainer extends React.PureComponent { ); }; + fetchWarnings = (component: Component, branchLike?: BranchLike) => { + getAnalysisStatus({ + component: component.key, + ...getBranchLikeQuery(branchLike) + }).then( + ({ component }) => { + this.setState({ warnings: component.warnings }); + }, + () => {} + ); + }; + getCurrentBranchLike = (branchLikes: BranchLike[]) => { const { query } = this.props.location; return query.pullRequest @@ -341,6 +355,7 @@ export class ComponentContainer extends React.PureComponent { isInProgress={isInProgress} isPending={isPending} location={this.props.location} + warnings={this.state.warnings} /> )} {loading ? ( diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx index 7d5ca616c2f..8e0d69dc235 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx @@ -43,6 +43,7 @@ jest.mock('../../../api/branches', () => ({ })); jest.mock('../../../api/ce', () => ({ + getAnalysisStatus: jest.fn().mockResolvedValue({ component: { warnings: [] } }), getTasksForComponent: jest.fn().mockResolvedValue({ queue: [] }) })); 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 9a1332c4dcd..89561422d42 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 @@ -39,6 +39,7 @@ interface Props { isInProgress?: boolean; isPending?: boolean; location: {}; + warnings: string[]; } export default class ComponentNav extends React.PureComponent { @@ -98,7 +99,7 @@ export default class ComponentNav extends React.PureComponent { branchLike={currentBranchLike} branchMeasures={this.props.branchMeasures} component={component} - currentTask={currentTask} + warnings={this.props.warnings} /> - {currentTask && - Boolean(currentTask.warningCount) && } + {warnings.length > 0 && } {component.analysisDate && (
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx index 192d562afd7..a18d094080c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavWarnings.tsx @@ -21,7 +21,6 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { lazyLoad } from '../../../../components/lazyLoad'; import WarningIcon from '../../../../components/icons-components/WarningIcon'; -import { Task } from '../../../types'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; const AnalysisWarningsModal = lazyLoad(() => @@ -29,7 +28,7 @@ const AnalysisWarningsModal = lazyLoad(() => ); interface Props { - task: Pick; + warnings: string[]; } interface State { @@ -62,7 +61,7 @@ export default class ComponentNavWarnings extends React.PureComponent {translateWithParameters( 'component_navigation.x_warnings', - String(this.props.task.warningCount) + String(this.props.warnings.length) )} ) @@ -70,7 +69,7 @@ export default class ComponentNavWarnings extends React.PureComponent
{this.state.modal && ( - + )} ); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx index b0f633badb5..b06e39767ca 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx @@ -36,6 +36,7 @@ it('renders', () => { component={component} currentBranchLike={undefined} location={{}} + warnings={[]} /> ); wrapper.setState({ isInProgress: true, isPending: true }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx index 74ad5181300..ea2e2016e25 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx @@ -52,6 +52,7 @@ it('renders status of short-living branch', () => { branchMeasures={MEASURES} component={COMPONENT} currentUser={{ isLoggedIn: false }} + warnings={[]} /> ) ).toMatchSnapshot(); @@ -70,6 +71,7 @@ it('renders meta for long-living branch', () => { branchLike={branch} component={COMPONENT} currentUser={{ isLoggedIn: false }} + warnings={[]} /> ) ).toMatchSnapshot(); @@ -90,6 +92,7 @@ it('renders meta for pull request', () => { branchLike={pullRequest} component={COMPONENT} currentUser={{ isLoggedIn: false }} + warnings={[]} /> ) ).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavWarnings-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavWarnings-test.tsx index 9eba3b71968..95c6431ba03 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavWarnings-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavWarnings-test.tsx @@ -22,7 +22,7 @@ import { shallow } from 'enzyme'; import ComponentNavWarnings from '../ComponentNavWarnings'; it('should render', () => { - const wrapper = shallow(); + const wrapper = shallow(); wrapper.setState({ modal: true }); expect(wrapper).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 b95d5c4732b..3e0cf719787 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 @@ -43,6 +43,7 @@ exports[`renders 1`] = ` "qualifier": "TRK", } } + warnings={Array []} /> - component_navigation.x_warnings.undefined + component_navigation.x_warnings.1 , } } @@ -25,7 +25,11 @@ exports[`should render 1`] = ` `; diff --git a/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx b/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx index 97af1814d03..b1fc7698a4f 100644 --- a/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx +++ b/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx @@ -27,7 +27,8 @@ import { getTask } from '../../api/ce'; interface Props { onClose: () => void; - taskId: string; + taskId?: string; + warnings?: string[]; } interface State { @@ -37,19 +38,25 @@ interface State { export default class AnalysisWarningsModal extends React.PureComponent { mounted = false; - state: State = { - loading: true, - warnings: [] - }; + + constructor(props: Props) { + super(props); + this.state = { loading: !props.warnings, warnings: props.warnings || [] }; + } componentDidMount() { this.mounted = true; - this.loadWarnings(); + if (!this.props.warnings && this.props.taskId) { + this.loadWarnings(this.props.taskId); + } } componentDidUpdate(prevProps: Props) { - if (prevProps.taskId !== this.props.taskId) { - this.loadWarnings(); + const { taskId, warnings } = this.props; + if (!warnings && taskId && prevProps.taskId !== taskId) { + this.loadWarnings(taskId); + } else if (warnings && prevProps.warnings !== warnings) { + this.setState({ warnings }); } } @@ -57,9 +64,9 @@ export default class AnalysisWarningsModal extends React.PureComponent { if (this.mounted) { this.setState({ loading: false, warnings }); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/AnalysisWarningsModal-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/AnalysisWarningsModal-test.tsx index 51ffa11a653..017a937588a 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/AnalysisWarningsModal-test.tsx +++ b/server/sonar-web/src/main/js/components/common/__tests__/AnalysisWarningsModal-test.tsx @@ -24,16 +24,26 @@ import { waitAndUpdate } from '../../../helpers/testUtils'; import { getTask } from '../../../api/ce'; jest.mock('../../../api/ce', () => ({ - getTask: jest - .fn() - .mockResolvedValue({ - warnings: ['message foo', 'message-bar', 'multiline message\nsecondline\n third line'] - }) + getTask: jest.fn().mockResolvedValue({ + warnings: ['message foo', 'message-bar', 'multiline message\nsecondline\n third line'] + }) })); +beforeEach(() => { + (getTask as jest.Mock).mockClear(); +}); + it('should fetch warnings and render', async () => { const wrapper = shallow(); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot(); expect(getTask).toBeCalledWith('abcd1234', ['warnings']); }); + +it('should render warnings without fetch', () => { + const wrapper = shallow( + + ); + expect(wrapper).toMatchSnapshot(); + expect(getTask).not.toBeCalled(); +}); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/AnalysisWarningsModal-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/AnalysisWarningsModal-test.tsx.snap index c52023d0b5d..d11642c2553 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/AnalysisWarningsModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/AnalysisWarningsModal-test.tsx.snap @@ -90,3 +90,63 @@ exports[`should fetch warnings and render 1`] = ` `; + +exports[`should render warnings without fetch 1`] = ` + +
+

+ warnings +

+
+
+ +
+ +
+ warning 1 +
+
+
+ +
+ warning 2 +
+
+
+
+ +
+`; -- 2.39.5