From a0b5c952715338984dd58e09c70db041702f1fcb Mon Sep 17 00:00:00 2001 From: Kevin Silva Date: Thu, 20 Apr 2023 18:15:37 +0200 Subject: [PATCH] SONAR-19018 - Update the Activity section with MIUI --- .../apps/overview/branches/ActivityPanel.tsx | 91 ++++++++----------- .../js/apps/overview/branches/Analysis.tsx | 22 ++--- .../main/js/apps/overview/branches/Event.tsx | 52 +++++------ .../branches/__tests__/ActivityPanel-it.tsx | 83 +++++++++++++++++ .../src/main/js/apps/overview/styles.css | 2 +- .../js/components/common/ActivityLink.tsx | 12 +-- .../common/__tests__/ActivityLink-test.tsx | 40 ++++++-- .../__snapshots__/ActivityLink-test.tsx.snap | 81 ----------------- .../resources/org/sonar/l10n/core.properties | 4 +- 9 files changed, 194 insertions(+), 193 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-it.tsx delete mode 100644 server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/ActivityLink-test.tsx.snap diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx index 8b1060beeba..f7e410092ba 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - +import { BasicSeparator, Card, DeferredSpinner, PageTitle } from 'design-system'; import * as React from 'react'; import GraphsHeader from '../../../components/activity-graph/GraphsHeader'; import GraphsHistory from '../../../components/activity-graph/GraphsHistory'; @@ -28,7 +28,6 @@ import { splitSeriesInGraphs, } from '../../../components/activity-graph/utils'; import ActivityLink from '../../../components/common/ActivityLink'; -import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { parseDate } from '../../../helpers/dates'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { localizeMetric } from '../../../helpers/measures'; @@ -92,59 +91,43 @@ export function ActivityPanel(props: ActivityPanelProps) { const filteredAnalyses = analyses.filter((a) => a.events.length > 0).slice(0, MAX_ANALYSES_NB); return ( -
-

{translate('overview.activity')}

- -
-
-
-
- - localizeMetric(metricKey)).join(', ') - )} - canShowDataAsTable={false} - graph={graph} - graphs={graphs} - leakPeriodDate={shownLeakPeriodDate} - loading={Boolean(loading)} - measuresHistory={measuresHistory} - series={series} - /> -
- -
- -
-
- -
-
- - {analyses.length === 0 ? ( -

{translate('no_results')}

- ) : ( -
    - {filteredAnalyses.map((analysis) => ( - - ))} -
- )} -
-
-
+
+ + + + localizeMetric(metricKey)).join(', ') + )} + canShowDataAsTable={false} + graph={graph} + graphs={graphs} + leakPeriodDate={shownLeakPeriodDate} + loading={Boolean(loading)} + measuresHistory={measuresHistory} + series={series} + /> + +
+
-
+ + + + {filteredAnalyses.length === 0 ? ( +

{translate('no_results')}

+ ) : ( + filteredAnalyses.map((analysis, index) => ( +
+ + {index !== filteredAnalyses.length - 1 && } +
+ )) + )} +
+
); } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx b/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx index 75025ad9391..8ac5f5204c2 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx @@ -46,23 +46,15 @@ export function Analysis({ analysis, ...props }: AnalysisProps) { : ComponentQualifier.Project; return ( -
  • -
    - - - +
    +
    +
    - {sortedEvents.length > 0 ? ( -
    - {sortedEvents.map((event) => ( - - ))} -
    - ) : ( - {translate('project_activity.analyzed', qualifier)} - )} -
  • + {sortedEvents.length > 0 + ? sortedEvents.map((event) => ) + : translate('project_activity.analyzed', qualifier)} +
    ); } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx b/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx index 71ed8ff5412..147363d190d 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx @@ -17,11 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Badge, QualityGateIndicator } from 'design-system'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { isDefinitionChangeEvent } from '../../../components/activity-graph/DefinitionChangeEventInner'; import { isRichQualityGateEvent } from '../../../components/activity-graph/RichQualityGateEventInner'; -import Level from '../../../components/ui/Level'; import { translate } from '../../../helpers/l10n'; import { AnalysisEvent } from '../../../types/project-activity'; @@ -32,48 +32,48 @@ interface Props { export function Event({ event }: Props) { if (event.category === 'VERSION') { return ( - + {event.name} - + ); } const eventCategory = translate('event.category', event.category); if (isDefinitionChangeEvent(event)) { - return ( -
    - {eventCategory} -
    - ); + return
    {eventCategory}
    ; } if (isRichQualityGateEvent(event)) { return ( -
    - {eventCategory}:{' '} - {event.qualityGate.stillFailing ? ( - }} - /> - ) : ( - - )} +
    + {eventCategory}: +
    + {event.qualityGate.stillFailing ? ( + , + }} + /> + ) : ( + + )} +
    + + {translate(`event.quality_gate.${event.qualityGate.status}`)} +
    ); } return ( -
    - {eventCategory}:{' '} +
    + {eventCategory}: {event.description ? ( - {event.name} + {event.name} ) : ( - {event.name} + {event.name} )}
    ); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-it.tsx new file mode 100644 index 00000000000..9be1f3a82fc --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-it.tsx @@ -0,0 +1,83 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { screen } from '@testing-library/react'; +import * as React from 'react'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { + mockAnalysis, + mockAnalysisEvent, + mockMeasureHistory, +} from '../../../../helpers/mocks/project-activity'; +import { mockMetric } from '../../../../helpers/testMocks'; + +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { + ApplicationAnalysisEventCategory, + DefinitionChangeType, + ProjectAnalysisEventCategory, +} from '../../../../types/project-activity'; +import ActivityPanel, { ActivityPanelProps } from '../ActivityPanel'; + +it('should render correctly', async () => { + renderActivityPanel(); + expect(await screen.findByText('event.quality_gate.ERROR')).toBeInTheDocument(); + expect(screen.getByRole('status', { name: 'v1.0' })).toBeInTheDocument(); + expect(screen.getByText(/event.category.OTHER/)).toBeInTheDocument(); + expect(screen.getByText(/event.category.DEFINITION_CHANGE/)).toBeInTheDocument(); +}); + +function renderActivityPanel(props: Partial = {}) { + const mockedMeasureHistory = [mockMeasureHistory()]; + const mockedMetrics = [mockMetric()]; + const mockedAnalysis = [ + mockAnalysis({ + events: [ + mockAnalysisEvent(), + mockAnalysisEvent({ category: ProjectAnalysisEventCategory.Version, name: 'v1.0' }), + mockAnalysisEvent({ category: ProjectAnalysisEventCategory.Other, name: 'Other' }), + mockAnalysisEvent({ + category: ApplicationAnalysisEventCategory.DefinitionChange, + name: 'DefinitionChange', + definitionChange: { + projects: [ + { + changeType: DefinitionChangeType.Added, + key: 'string', + name: 'string', + }, + ], + }, + }), + ], + }), + mockAnalysis({ key: 'bar' }), + ]; + + const mockedProps: ActivityPanelProps = { + analyses: mockedAnalysis, + measuresHistory: mockedMeasureHistory, + metrics: mockedMetrics, + component: mockComponent(), + onGraphChange: jest.fn(), + loading: false, + }; + + return renderComponent(); +} diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css index fcb69fe9ab0..eb2a2a9a02e 100644 --- a/server/sonar-web/src/main/js/apps/overview/styles.css +++ b/server/sonar-web/src/main/js/apps/overview/styles.css @@ -205,7 +205,7 @@ margin-top: 4px; } -.overview-panel .activity-graph-container { +.activity-graph-container { min-height: 200px; padding-bottom: 0; } diff --git a/server/sonar-web/src/main/js/components/common/ActivityLink.tsx b/server/sonar-web/src/main/js/components/common/ActivityLink.tsx index b61f25d2fa6..c80cd4e18b8 100644 --- a/server/sonar-web/src/main/js/components/common/ActivityLink.tsx +++ b/server/sonar-web/src/main/js/components/common/ActivityLink.tsx @@ -17,15 +17,14 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { StandoutLink } from 'design-system'; import * as React from 'react'; -import HistoryIcon from '../../components/icons/HistoryIcon'; import { translate } from '../../helpers/l10n'; import { getActivityUrl, getMeasureHistoryUrl } from '../../helpers/urls'; import { BranchLike } from '../../types/branch-like'; import { GraphType } from '../../types/project-activity'; import { isCustomGraph } from '../activity-graph/utils'; import './ActivityLink.css'; -import Link from './Link'; export interface ActivityLinkProps { branchLike?: BranchLike; @@ -38,16 +37,15 @@ export interface ActivityLinkProps { export default function ActivityLink(props: ActivityLinkProps) { const { branchLike, component, graph, label, metric } = props; return ( - - - {label || translate('portfolio.activity_link')} - + {label || translate('portfolio.activity_link')} + ); } diff --git a/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx index f4270d3c7fd..c8bd5e4898e 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx +++ b/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx @@ -17,19 +17,43 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; + +import { screen } from '@testing-library/react'; import * as React from 'react'; import { mockBranch } from '../../../helpers/mocks/branch-like'; +import { renderComponent } from '../../../helpers/testReactTestingUtils'; import { GraphType } from '../../../types/project-activity'; import ActivityLink, { ActivityLinkProps } from '../ActivityLink'; -it('renders correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ label: 'Foo', branchLike: mockBranch() })).toMatchSnapshot(); - expect(shallowRender({ graph: GraphType.coverage })).toMatchSnapshot(); - expect(shallowRender({ graph: GraphType.custom, metric: 'new_bugs,bugs' })).toMatchSnapshot(); +it('renders correctly without props', () => { + renderActivityLink(); + expect(screen.getByText('portfolio.activity_link')).toBeInTheDocument(); +}); + +it('renders correctly with props label and branch', () => { + renderActivityLink({ label: 'Foo', branchLike: mockBranch() }); + expect(screen.getByText('Foo')).toBeInTheDocument(); +}); + +it('renders correctly with graph', () => { + renderActivityLink({ graph: GraphType.coverage }); + const anchorElement = screen.getByRole('link'); + + expect(anchorElement).toBeInTheDocument(); + expect(anchorElement).toHaveAttribute('href', '/project/activity?id=foo&graph=coverage'); +}); + +it('renders correctly with graph and metric', () => { + renderActivityLink({ graph: GraphType.custom, metric: 'new_bugs,bugs' }); + const anchorElement = screen.getByRole('link'); + + expect(anchorElement).toBeInTheDocument(); + expect(anchorElement).toHaveAttribute( + 'href', + '/project/activity?id=foo&graph=custom&custom_metrics=new_bugs%2Cbugs' + ); }); -function shallowRender(props: Partial = {}) { - return shallow(); +function renderActivityLink(props: Partial = {}) { + return renderComponent(); } diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/ActivityLink-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/ActivityLink-test.tsx.snap deleted file mode 100644 index 2197632f0f0..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/ActivityLink-test.tsx.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` - - - - portfolio.activity_link - - -`; - -exports[`renders correctly 2`] = ` - - - - Foo - - -`; - -exports[`renders correctly 3`] = ` - - - - portfolio.activity_link - - -`; - -exports[`renders correctly 4`] = ` - - - - portfolio.activity_link - - -`; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index f55eae17eaa..148bc7a18f5 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -511,6 +511,8 @@ event.category.QUALITY_PROFILE=Quality Profile event.category.DEFINITION_CHANGE=Definition Change event.category.OTHER=Other event.quality_gate.still_x=Still {status} +event.quality_gate.ERROR=Failed +event.quality_gate.OK=Passed event.definition_change.added={project} added event.definition_change.removed={project} removed event.definition_change.branch_added={project} {branch} added @@ -4357,7 +4359,7 @@ portfolio.app.no_lines_of_code=All projects in this application are empty portfolio.metric_trend=Metric trend portfolio.lowest_rated_project_branches=Lowest rated project branches portfolio.health_factors=Portfolio health factors -portfolio.activity_link=Activity +portfolio.activity_link=See Full History portfolio.measures_link=Measures portfolio.language_breakdown_link=Language breakdown portfolio.breakdown=Portfolio breakdown -- 2.39.5