diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2022-02-04 17:13:53 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-02-08 20:03:05 +0000 |
commit | caf973b676e322e2f0c5144eb16a39870e90ca5e (patch) | |
tree | c1411e7e7cc3139524c780649531c2462a528a3e /server | |
parent | 89a8e12f5d738da62d0a409f33f12969a7d8e89d (diff) | |
download | sonarqube-caf973b676e322e2f0c5144eb16a39870e90ca5e.tar.gz sonarqube-caf973b676e322e2f0c5144eb16a39870e90ca5e.zip |
SONAR-15999 Drop the visualizations of projects as bubble charts
Diffstat (limited to 'server')
39 files changed, 73 insertions, 2110 deletions
diff --git a/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts index 53b73377297..9661ddc8a29 100644 --- a/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts @@ -85,13 +85,13 @@ describe('formatDuration', () => { describe('fetchProjects', () => { it('correctly converts the passed arguments to the desired query format', async () => { - await utils.fetchProjects({ view: 'visualizations' }, true); + await utils.fetchProjects({}, true); expect(searchProjects).toBeCalledWith({ f: 'analysisDate,leakPeriodDate', facets: utils.FACETS.join(), filter: 'isFavorite', p: undefined, - ps: 99 + ps: 50 }); await utils.fetchProjects({ view: 'leak' }, false, 3); @@ -119,7 +119,7 @@ describe('fetchProjects', () => { ], paging: { total: 2 } }); - await utils.fetchProjects({ view: 'visualizations' }, true).then(r => { + await utils.fetchProjects({}, true).then(r => { expect(r).toEqual({ facets: { new_coverage: { NO_DATA: 0 }, diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx index 812d23ac385..be94169551e 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx @@ -34,11 +34,10 @@ import { get, save } from '../../../helpers/storage'; import { isLoggedIn } from '../../../helpers/users'; import { ComponentQualifier } from '../../../types/component'; import { CurrentUser, RawQuery } from '../../../types/types'; -import { hasFilterParams, hasVisualizationParams, parseUrlQuery, Query } from '../query'; +import { hasFilterParams, hasViewParams, parseUrlQuery, Query } from '../query'; import '../styles.css'; import { Facets, Project } from '../types'; import { fetchProjects, parseSorting, SORTING_SWITCH } from '../utils'; -import Visualizations from '../visualizations/Visualizations'; import PageHeader from './PageHeader'; import PageSidebar from './PageSidebar'; import ProjectsList from './ProjectsList'; @@ -62,7 +61,6 @@ interface State { export const LS_PROJECTS_SORT = 'sonarqube.projects.sort'; export const LS_PROJECTS_VIEW = 'sonarqube.projects.view'; -export const LS_PROJECTS_VISUALIZATION = 'sonarqube.projects.visualization'; export class AllProjects extends React.PureComponent<Props, State> { mounted = false; @@ -131,7 +129,6 @@ export class AllProjects extends React.PureComponent<Props, State> { const options: { sort?: string; view?: string; - visualization?: string; } = {}; if (get(LS_PROJECTS_SORT)) { options.sort = get(LS_PROJECTS_SORT) || undefined; @@ -139,16 +136,11 @@ export class AllProjects extends React.PureComponent<Props, State> { if (get(LS_PROJECTS_VIEW)) { options.view = get(LS_PROJECTS_VIEW) || undefined; } - if (get(LS_PROJECTS_VISUALIZATION)) { - options.visualization = get(LS_PROJECTS_VISUALIZATION) || undefined; - } return options; }; getView = () => this.state.query.view || 'overall'; - getVisualization = () => this.state.query.visualization || 'risk'; - handleClearAll = () => { this.props.router.push({ pathname: this.props.location.pathname }); }; @@ -165,14 +157,12 @@ export class AllProjects extends React.PureComponent<Props, State> { }); }; - handlePerspectiveChange = ({ view, visualization }: { view: string; visualization?: string }) => { + handlePerspectiveChange = ({ view }: { view: string }) => { const query: { view: string | undefined; - visualization: string | undefined; sort?: string | undefined; } = { - view: view === 'overall' ? undefined : view, - visualization + view: view === 'overall' ? undefined : view }; if (this.state.query.view === 'leak' || view === 'leak') { @@ -189,16 +179,14 @@ export class AllProjects extends React.PureComponent<Props, State> { save(LS_PROJECTS_SORT, query.sort); save(LS_PROJECTS_VIEW, query.view); - save(LS_PROJECTS_VISUALIZATION, visualization); }; handleQueryChange(initialMount: boolean) { const query = parseUrlQuery(this.props.location.query); const savedOptions = this.getStorageOptions(); - const savedOptionsSet = savedOptions.sort || savedOptions.view || savedOptions.visualization; + const savedOptionsSet = savedOptions.sort || savedOptions.view; - // if there is no visualization parameters (sort, view, visualization), but there are saved preferences in the localStorage - if (initialMount && !hasVisualizationParams(query) && savedOptionsSet) { + if (initialMount && !hasViewParams(query) && savedOptionsSet) { this.props.router.replace({ pathname: this.props.location.pathname, query: savedOptions }); } else { this.fetchProjects(query); @@ -244,7 +232,6 @@ export class AllProjects extends React.PureComponent<Props, State> { onQueryChange={this.updateLocationQuery} query={this.state.query} view={this.getView()} - visualization={this.getVisualization()} /> </div> </div> @@ -263,12 +250,10 @@ export class AllProjects extends React.PureComponent<Props, State> { onPerspectiveChange={this.handlePerspectiveChange} onQueryChange={this.updateLocationQuery} onSortChange={this.handleSortChange} - projects={this.state.projects} query={this.state.query} selectedSort={this.getSort()} total={this.state.total} view={this.getView()} - visualization={this.getVisualization()} /> </div> </div> @@ -280,18 +265,7 @@ export class AllProjects extends React.PureComponent<Props, State> { return <DeferredSpinner />; } - return this.getView() === 'visualizations' ? ( - <div className="layout-page-main-inner"> - {this.state.projects && ( - <Visualizations - projects={this.state.projects} - sort={this.state.query.sort} - total={this.state.total} - visualization={this.getVisualization()} - /> - )} - </div> - ) : ( + return ( <div className="layout-page-main-inner"> {this.state.projects && ( <ProjectsList diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx index 04b1e10c34e..594cea686cb 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx @@ -20,12 +20,10 @@ import classNames from 'classnames'; import * as React from 'react'; import HomePageSelect from '../../../components/controls/HomePageSelect'; -import Tooltip from '../../../components/controls/Tooltip'; import { translate } from '../../../helpers/l10n'; import { isLoggedIn } from '../../../helpers/users'; import { CurrentUser, RawQuery } from '../../../types/types'; import SearchFilterContainer from '../filters/SearchFilterContainer'; -import { Project } from '../types'; import ApplicationCreation from './ApplicationCreation'; import PerspectiveSelect from './PerspectiveSelect'; import ProjectCreationMenu from './ProjectCreationMenu'; @@ -34,24 +32,19 @@ import ProjectsSortingSelect from './ProjectsSortingSelect'; interface Props { currentUser: CurrentUser; loading: boolean; - onPerspectiveChange: (x: { view: string; visualization?: string }) => void; + onPerspectiveChange: (x: { view: string }) => void; onQueryChange: (change: RawQuery) => void; onSortChange: (sort: string, desc: boolean) => void; - projects?: Project[]; query: RawQuery; selectedSort: string; total?: number; view: string; - visualization?: string; } export default function PageHeader(props: Props) { - const { loading, total, projects, currentUser, view } = props; - const limitReached = projects != null && total != null && projects.length < total; + const { loading, total, currentUser, view } = props; const defaultOption = isLoggedIn(currentUser) ? 'name' : 'analysis_date'; - const sortingDisabled = view === 'visualizations' && !limitReached; - return ( <div className="page-header"> <div className="display-flex-space-between spacer-top"> @@ -81,21 +74,18 @@ export default function PageHeader(props: Props) { <PerspectiveSelect className="projects-topbar-item js-projects-perspective-select" onChange={props.onPerspectiveChange} - view={props.view} - visualization={props.visualization} + view={view} /> - <Tooltip overlay={sortingDisabled ? translate('projects.sort.disabled') : undefined}> - <div className={classNames('projects-topbar-item', { disabled: sortingDisabled })}> - <ProjectsSortingSelect - className="js-projects-sorting-select" - defaultOption={defaultOption} - onChange={props.onSortChange} - selectedSort={props.selectedSort} - view={props.view} - /> - </div> - </Tooltip> + <div className={classNames('projects-topbar-item')}> + <ProjectsSortingSelect + className="js-projects-sorting-select" + defaultOption={defaultOption} + onChange={props.onSortChange} + selectedSort={props.selectedSort} + view={view} + /> + </div> </div> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx index 417b9e7af82..0c487635681 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx @@ -50,11 +50,10 @@ export interface PageSidebarProps { onQueryChange: (change: RawQuery) => void; query: RawQuery; view: string; - visualization: string; } export default function PageSidebar(props: PageSidebarProps) { - const { applicationsEnabled, facets, onQueryChange, query, view, visualization } = props; + const { applicationsEnabled, facets, onQueryChange, query, view } = props; const isFiltered = hasFilterParams(query); const isLeakView = view === 'leak'; const maxFacetValue = getMaxFacetValue(facets); @@ -63,10 +62,6 @@ export default function PageSidebar(props: PageSidebarProps) { let linkQuery: RawQuery | undefined = undefined; if (view !== 'overall') { linkQuery = { view }; - - if (view === 'visualizations') { - linkQuery.visualization = visualization; - } } return ( diff --git a/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx b/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx index 8a9e0a71fee..a9a39b06aa4 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx @@ -21,31 +21,24 @@ import { omit } from 'lodash'; import * as React from 'react'; import { components, OptionProps } from 'react-select'; import Select from '../../../components/controls/Select'; -import BubblesIcon from '../../../components/icons/BubblesIcon'; import ListIcon from '../../../components/icons/ListIcon'; import { translate } from '../../../helpers/l10n'; -import { VIEWS, VISUALIZATIONS } from '../utils'; +import { VIEWS } from '../utils'; interface Props { className?: string; - onChange: (x: { view: string; visualization?: string }) => void; + onChange: (x: { view: string }) => void; view: string; - visualization?: string; } export interface PerspectiveOption { - type: string; value: string; label: string; } export default class PerspectiveSelect extends React.PureComponent<Props> { handleChange = (option: PerspectiveOption) => { - if (option && option.type === 'view') { - this.props.onChange({ view: option.value }); - } else if (option && option.type === 'visualization') { - this.props.onChange({ view: 'visualizations', visualization: option.value }); - } + this.props.onChange({ view: option.value }); }; perspectiveOptionRender = (props: OptionProps<PerspectiveOption, false>) => { @@ -54,26 +47,18 @@ export default class PerspectiveSelect extends React.PureComponent<Props> { <components.Option {...omit(props, ['children', 'className'])} className={`it__projects-perspective-option-${data.value} ${className}`}> - {data.type === 'view' && <ListIcon className="little-spacer-right" />} - {data.type === 'visualization' && <BubblesIcon className="little-spacer-right" />} + <ListIcon className="little-spacer-right" /> {props.children} </components.Option> ); }; render() { - const { view, visualization } = this.props; - const perspective = view === 'visualizations' ? visualization : view; + const { view } = this.props; const options: PerspectiveOption[] = [ ...VIEWS.map(opt => ({ - type: 'view', value: opt.value, label: translate('projects.view', opt.label) - })), - ...VISUALIZATIONS.map(opt => ({ - type: 'visualization', - value: opt, - label: translate('projects.visualization', opt) })) ]; return ( @@ -89,7 +74,7 @@ export default class PerspectiveSelect extends React.PureComponent<Props> { }} options={options} isSearchable={false} - value={options.find(option => option.value === perspective)} + value={options.find(option => option.value === view)} /> </div> ); diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx index 721837c89a5..819e956a14a 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx @@ -22,12 +22,7 @@ import * as React from 'react'; import { get, save } from '../../../../helpers/storage'; import { ComponentQualifier } from '../../../../types/component'; import { Dict } from '../../../../types/types'; -import { - AllProjects, - LS_PROJECTS_SORT, - LS_PROJECTS_VIEW, - LS_PROJECTS_VISUALIZATION -} from '../AllProjects'; +import { AllProjects, LS_PROJECTS_SORT, LS_PROJECTS_VIEW } from '../AllProjects'; jest.mock( '../ProjectsList', @@ -78,8 +73,6 @@ beforeEach(() => { it('renders', () => { const wrapper = shallowRender(); expect(wrapper).toMatchSnapshot(); - wrapper.setState({ query: { view: 'visualizations' } }); - expect(wrapper).toMatchSnapshot(); }); it('fetches projects', () => { @@ -103,8 +96,7 @@ it('fetches projects', () => { size: undefined, sort: undefined, tags: undefined, - view: undefined, - visualization: undefined + view: undefined }, false ); @@ -113,8 +105,7 @@ it('fetches projects', () => { it('redirects to the saved search', () => { const localeStorageMock: Dict<string> = { [LS_PROJECTS_VIEW]: 'leak', - [LS_PROJECTS_SORT]: 'coverage', - [LS_PROJECTS_VISUALIZATION]: 'security' + [LS_PROJECTS_SORT]: 'coverage' }; (get as jest.Mock).mockImplementation((key: string) => localeStorageMock[key]); @@ -125,8 +116,7 @@ it('redirects to the saved search', () => { pathname: '/projects', query: { view: localeStorageMock[LS_PROJECTS_VIEW], - sort: localeStorageMock[LS_PROJECTS_SORT], - visualization: localeStorageMock[LS_PROJECTS_VISUALIZATION] + sort: localeStorageMock[LS_PROJECTS_SORT] } }); }); @@ -145,11 +135,10 @@ it('changes perspective to leak', () => { wrapper.find('PageHeader').prop<Function>('onPerspectiveChange')({ view: 'leak' }); expect(push).lastCalledWith({ pathname: '/projects', - query: { view: 'leak', visualization: undefined } + query: { view: 'leak' } }); expect(save).toHaveBeenCalledWith(LS_PROJECTS_SORT, undefined); expect(save).toHaveBeenCalledWith(LS_PROJECTS_VIEW, 'leak'); - expect(save).toHaveBeenCalledWith(LS_PROJECTS_VISUALIZATION, undefined); }); it('updates sorting when changing perspective from leak', () => { @@ -161,27 +150,10 @@ it('updates sorting when changing perspective from leak', () => { }); expect(push).lastCalledWith({ pathname: '/projects', - query: { sort: 'coverage', view: undefined, visualization: undefined } + query: { sort: 'coverage', view: undefined } }); expect(save).toHaveBeenCalledWith(LS_PROJECTS_SORT, 'coverage'); expect(save).toHaveBeenCalledWith(LS_PROJECTS_VIEW, undefined); - expect(save).toHaveBeenCalledWith(LS_PROJECTS_VISUALIZATION, undefined); -}); - -it('changes perspective to risk visualization', () => { - const push = jest.fn(); - const wrapper = shallowRender({}, push); - wrapper.find('PageHeader').prop<Function>('onPerspectiveChange')({ - view: 'visualizations', - visualization: 'risk' - }); - expect(push).lastCalledWith({ - pathname: '/projects', - query: { view: 'visualizations', visualization: 'risk' } - }); - expect(save).toHaveBeenCalledWith(LS_PROJECTS_SORT, undefined); - expect(save).toHaveBeenCalledWith(LS_PROJECTS_VIEW, 'visualizations'); - expect(save).toHaveBeenCalledWith(LS_PROJECTS_VISUALIZATION, 'risk'); }); it('handles favorite projects', () => { diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx index b563f6d487b..c50803a8740 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx @@ -37,23 +37,11 @@ it('should not render projects total', () => { ).toBe(false); }); -it('should render disabled sorting options for visualizations', () => { - expect( - shallowRender({ - open: true, - total: undefined, - view: 'visualizations', - visualization: 'coverage' - }) - ).toMatchSnapshot(); -}); - it('should render switch the default sorting option for anonymous users', () => { expect( shallowRender({ currentUser: { isLoggedIn: true }, - open: true, - visualization: 'risk' + open: true }).find('ProjectsSortingSelect') ).toMatchSnapshot(); @@ -61,8 +49,7 @@ it('should render switch the default sorting option for anonymous users', () => shallowRender({ currentUser: { isLoggedIn: false }, open: true, - view: 'leak', - visualization: 'risk' + view: 'leak' }).find('ProjectsSortingSelect') ).toMatchSnapshot(); }); @@ -75,7 +62,6 @@ function shallowRender(props?: {}) { onPerspectiveChange={jest.fn()} onQueryChange={jest.fn()} onSortChange={jest.fn()} - projects={[]} query={{ search: 'test' }} selectedSort="size" total={12} diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx index 4a6feb9d70f..2940711cbbc 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx @@ -24,8 +24,7 @@ import PageSidebar, { PageSidebarProps } from '../PageSidebar'; it('should render correctly', () => { const sidebar = shallowRender({ query: { size: '3' }, - view: 'overall', - visualization: 'risk' + view: 'overall' }); expect(sidebar).toMatchSnapshot(); @@ -35,8 +34,7 @@ it('should render correctly with no applications', () => { const sidebar = shallowRender({ applicationsEnabled: false, query: { size: '3' }, - view: 'overall', - visualization: 'risk' + view: 'overall' }); expect(sidebar).toMatchSnapshot(); @@ -45,8 +43,7 @@ it('should render correctly with no applications', () => { it('should render `leak` view correctly', () => { const sidebar = shallowRender({ query: { view: 'leak' }, - view: 'leak', - visualization: 'risk' + view: 'leak' }); expect(sidebar).toMatchSnapshot(); }); @@ -55,33 +52,19 @@ it('should render `leak` view correctly with no applications', () => { const sidebar = shallowRender({ applicationsEnabled: false, query: { view: 'leak' }, - view: 'leak', - visualization: 'risk' + view: 'leak' }); expect(sidebar).toMatchSnapshot(); }); -it('reset function should work correctly with view and visualizations', () => { - const sidebar = shallowRender({ - query: { view: 'visualizations', visualization: 'bugs' }, - view: 'visualizations', - visualization: 'bugs' - }); - - expect(sidebar.find('ClearAll').exists()).toBe(false); - sidebar.setProps({ query: { size: '3' } }); - expect(sidebar.find('ClearAll').exists()).toBe(true); -}); - function shallowRender(overrides: Partial<PageSidebarProps> = {}) { return shallow( <PageSidebar applicationsEnabled={true} onClearAll={jest.fn()} onQueryChange={jest.fn()} - query={{ view: 'visualizations', visualization: 'bugs' }} + query={{ view: 'overall' }} view="overall" - visualization="bugs" {...overrides} /> ); diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PerspectiveSelect-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PerspectiveSelect-test.tsx index 53b6abc36aa..37f00bee449 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PerspectiveSelect-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PerspectiveSelect-test.tsx @@ -19,7 +19,6 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import BubblesIcon from '../../../../components/icons/BubblesIcon'; import ListIcon from '../../../../components/icons/ListIcon'; import { mockReactSelectOptionProps } from '../../../../helpers/mocks/react-select'; import PerspectiveSelect from '../PerspectiveSelect'; @@ -28,37 +27,25 @@ it('should render correctly', () => { expect(shallow(<PerspectiveSelect onChange={jest.fn()} view="overall" />)).toMatchSnapshot(); }); -it('should render with coverage selected', () => { - expect(shallowRender({ view: 'visualizations', visualization: 'coverage' })).toMatchSnapshot(); -}); - it('should render option correctly', () => { const wrapper = shallowRender(); const OptionRender = wrapper.instance().perspectiveOptionRender; - let option = shallow( - <OptionRender {...mockReactSelectOptionProps({ type: 'view', value: 'test', label: 'test' })} /> + const option = shallow( + <OptionRender {...mockReactSelectOptionProps({ value: 'test', label: 'test' })} /> ); - expect(option.find(ListIcon).type).toBeDefined(); - option = shallow( - <OptionRender - {...mockReactSelectOptionProps({ type: 'visualization', value: 'test', label: '' })} - /> - ); - expect(option.find(BubblesIcon).type).toBeDefined(); }); it('should handle perspective change correctly', () => { const onChange = jest.fn(); const instance = shallowRender({ onChange }).instance(); - instance.handleChange({ label: 'overall', value: 'overall', type: 'view' }); - instance.handleChange({ label: 'leak', value: 'leak', type: 'view' }); - instance.handleChange({ label: 'coverage', value: 'coverage', type: 'visualization' }); + instance.handleChange({ label: 'overall', value: 'overall' }); + instance.handleChange({ label: 'leak', value: 'leak' }); expect(onChange.mock.calls).toMatchSnapshot(); }); function shallowRender(overrides: Partial<PerspectiveSelect['props']> = {}) { return shallow<PerspectiveSelect>( - <PerspectiveSelect onChange={jest.fn()} view="visualizations" {...overrides} /> + <PerspectiveSelect onChange={jest.fn()} view="overall" {...overrides} /> ); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap index 566c969e57a..229c1295c61 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap @@ -84,18 +84,6 @@ exports[`renders 1`] = ` onPerspectiveChange={[Function]} onQueryChange={[Function]} onSortChange={[Function]} - projects={ - Array [ - Object { - "key": "foo", - "measures": Object {}, - "name": "Foo", - "qualifier": "TRK", - "tags": Array [], - "visibility": "public", - }, - ] - } query={ Object { "coverage": undefined, @@ -119,13 +107,11 @@ exports[`renders 1`] = ` "sort": undefined, "tags": undefined, "view": undefined, - "visualization": undefined, } } selectedSort="name" total={0} view="overall" - visualization="risk" /> </div> </div> @@ -178,7 +164,6 @@ exports[`renders 1`] = ` "sort": undefined, "tags": undefined, "view": undefined, - "visualization": undefined, } } /> @@ -194,110 +179,3 @@ exports[`renders 1`] = ` </div> </div> `; - -exports[`renders 2`] = ` -<div - className="layout-page projects-page" - id="projects-page" -> - <Suggestions - suggestions="projects" - /> - <Helmet - defer={false} - encodeSpecialCharacters={true} - prioritizeSeoTags={false} - title="projects.page" - /> - <h1 - className="a11y-hidden" - > - projects.page - </h1> - <ScreenPositionHelper - className="layout-page-side-outer" - > - <Component /> - </ScreenPositionHelper> - <div - className="layout-page-main" - > - <A11ySkipTarget - anchor="projects_main" - /> - <div - role="main" - > - <h2 - className="a11y-hidden" - > - list_of_projects - </h2> - <div - className="layout-page-header-panel layout-page-main-header" - > - <div - className="layout-page-header-panel-inner layout-page-main-header-inner" - > - <div - className="layout-page-main-inner" - > - <PageHeader - currentUser={ - Object { - "isLoggedIn": true, - } - } - loading={false} - onPerspectiveChange={[Function]} - onQueryChange={[Function]} - onSortChange={[Function]} - projects={ - Array [ - Object { - "key": "foo", - "measures": Object {}, - "name": "Foo", - "qualifier": "TRK", - "tags": Array [], - "visibility": "public", - }, - ] - } - query={ - Object { - "view": "visualizations", - } - } - selectedSort="name" - total={0} - view="visualizations" - visualization="risk" - /> - </div> - </div> - </div> - <div - className="layout-page-main-inner" - > - <Visualizations - projects={ - Array [ - Object { - "key": "foo", - "measures": Object {}, - "name": "Foo", - "qualifier": "TRK", - "tags": Array [], - "visibility": "public", - }, - ] - } - total={0} - visualization="risk" - /> - </div> - </div> - </div> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap index 31ec1cb22bf..6f89a384375 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap @@ -60,19 +60,17 @@ exports[`should render correctly 1`] = ` onChange={[MockFunction]} view="overall" /> - <Tooltip> - <div - className="projects-topbar-item" - > - <ProjectsSortingSelect - className="js-projects-sorting-select" - defaultOption="analysis_date" - onChange={[MockFunction]} - selectedSort="size" - view="overall" - /> - </div> - </Tooltip> + <div + className="projects-topbar-item" + > + <ProjectsSortingSelect + className="js-projects-sorting-select" + defaultOption="analysis_date" + onChange={[MockFunction]} + selectedSort="size" + view="overall" + /> + </div> </div> </div> </div> @@ -138,88 +136,17 @@ exports[`should render correctly while loading 1`] = ` onChange={[MockFunction]} view="overall" /> - <Tooltip> - <div - className="projects-topbar-item" - > - <ProjectsSortingSelect - className="js-projects-sorting-select" - defaultOption="analysis_date" - onChange={[MockFunction]} - selectedSort="size" - view="overall" - /> - </div> - </Tooltip> - </div> - </div> -</div> -`; - -exports[`should render disabled sorting options for visualizations 1`] = ` -<div - className="page-header" -> - <div - className="display-flex-space-between spacer-top" - > - <SearchFilterContainer - onQueryChange={[MockFunction]} - query={ - Object { - "search": "test", - } - } - /> - <div - className="display-flex-center" - > - <Connect(withCurrentUser(ProjectCreationMenu)) - className="little-spacer-right" - /> - <Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation))))) - className="little-spacer-right" - /> - <Connect(HomePageSelect) - className="spacer-left little-spacer-right" - currentPage={ - Object { - "type": "PROJECTS", - } - } - /> - </div> - </div> - <div - className="big-spacer-top display-flex-space-between" - > - <div - className="display-flex-center" - /> - <div - className="display-flex-center" - > - <PerspectiveSelect - className="projects-topbar-item js-projects-perspective-select" - onChange={[MockFunction]} - view="visualizations" - visualization="coverage" - /> - <Tooltip - overlay="projects.sort.disabled" + <div + className="projects-topbar-item" > - <div - className="projects-topbar-item disabled" - > - <ProjectsSortingSelect - className="js-projects-sorting-select" - defaultOption="analysis_date" - onChange={[MockFunction]} - selectedSort="size" - view="visualizations" - /> - </div> - </Tooltip> + <ProjectsSortingSelect + className="js-projects-sorting-select" + defaultOption="analysis_date" + onChange={[MockFunction]} + selectedSort="size" + view="overall" + /> + </div> </div> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PerspectiveSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PerspectiveSelect-test.tsx.snap index 24bf353513a..2bc12d3f297 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PerspectiveSelect-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PerspectiveSelect-test.tsx.snap @@ -12,12 +12,6 @@ Array [ "view": "leak", }, ], - Array [ - Object { - "view": "visualizations", - "visualization": "coverage", - }, - ], ] `; @@ -44,127 +38,20 @@ exports[`should render correctly 1`] = ` Array [ Object { "label": "projects.view.overall", - "type": "view", "value": "overall", }, Object { "label": "projects.view.new_code", - "type": "view", "value": "leak", }, - Object { - "label": "projects.visualization.risk", - "type": "visualization", - "value": "risk", - }, - Object { - "label": "projects.visualization.reliability", - "type": "visualization", - "value": "reliability", - }, - Object { - "label": "projects.visualization.security", - "type": "visualization", - "value": "security", - }, - Object { - "label": "projects.visualization.maintainability", - "type": "visualization", - "value": "maintainability", - }, - Object { - "label": "projects.visualization.coverage", - "type": "visualization", - "value": "coverage", - }, - Object { - "label": "projects.visualization.duplications", - "type": "visualization", - "value": "duplications", - }, ] } value={ Object { "label": "projects.view.overall", - "type": "view", "value": "overall", } } /> </div> `; - -exports[`should render with coverage selected 1`] = ` -<div> - <label - id="aria-projects-perspective" - > - projects.perspective - : - </label> - <Select - aria-labelledby="aria-projects-perspective" - className="little-spacer-left input-medium it__projects-perspective-select" - components={ - Object { - "Option": [Function], - } - } - isClearable={false} - isSearchable={false} - onChange={[Function]} - options={ - Array [ - Object { - "label": "projects.view.overall", - "type": "view", - "value": "overall", - }, - Object { - "label": "projects.view.new_code", - "type": "view", - "value": "leak", - }, - Object { - "label": "projects.visualization.risk", - "type": "visualization", - "value": "risk", - }, - Object { - "label": "projects.visualization.reliability", - "type": "visualization", - "value": "reliability", - }, - Object { - "label": "projects.visualization.security", - "type": "visualization", - "value": "security", - }, - Object { - "label": "projects.visualization.maintainability", - "type": "visualization", - "value": "maintainability", - }, - Object { - "label": "projects.visualization.coverage", - "type": "visualization", - "value": "coverage", - }, - Object { - "label": "projects.visualization.duplications", - "type": "visualization", - "value": "duplications", - }, - ] - } - value={ - Object { - "label": "projects.visualization.coverage", - "type": "visualization", - "value": "coverage", - } - } - /> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/query.ts b/server/sonar-web/src/main/js/apps/projects/query.ts index 5a457130958..888c45841fb 100644 --- a/server/sonar-web/src/main/js/apps/projects/query.ts +++ b/server/sonar-web/src/main/js/apps/projects/query.ts @@ -19,7 +19,6 @@ */ import { ComponentQualifier } from '../../types/component'; import { Dict, RawQuery } from '../../types/types'; -import { VISUALIZATIONS } from './utils'; type Level = 'ERROR' | 'WARN' | 'OK'; @@ -45,7 +44,6 @@ export interface Query { search?: string; sort?: string; view?: string; - visualization?: string; [x: string]: string | number | string[] | undefined; } @@ -71,8 +69,7 @@ export function parseUrlQuery(urlQuery: RawQuery): Query { qualifier: getAsQualifier(urlQuery['qualifier']), search: getAsString(urlQuery['search']), sort: getAsString(urlQuery['sort']), - view: getView(urlQuery['view']), - visualization: getVisualization(urlQuery['visualization']) + view: getView(urlQuery['view']) }; } @@ -121,17 +118,17 @@ export function convertToFilter(query: Query, isFavorite: boolean): string { return conditions.join(' and '); } -const visualizationParams = ['sort', 'view', 'visualization']; +const viewParems = ['sort', 'view']; export function hasFilterParams(query: Query) { return Object.keys(query) - .filter(key => !visualizationParams.includes(key)) + .filter(key => !viewParems.includes(key)) .some(key => query[key] !== undefined); } -export function hasVisualizationParams(query: Query) { +export function hasViewParams(query: Query) { return Object.keys(query) - .filter(key => visualizationParams.includes(key)) + .filter(key => viewParems.includes(key)) .some(key => query[key] !== undefined); } @@ -172,10 +169,6 @@ function getView(value: any): string | undefined { return typeof value !== 'string' || value === 'overall' ? undefined : value; } -function getVisualization(value: string): string | undefined { - return VISUALIZATIONS.includes(value) ? value : undefined; -} - function convertIssuesRating(metric: string, rating: number): string { if (rating > 1 && rating < 5) { return `${metric} >= ${rating}`; diff --git a/server/sonar-web/src/main/js/apps/projects/styles.css b/server/sonar-web/src/main/js/apps/projects/styles.css index 605f5f16453..e6881bc56a7 100644 --- a/server/sonar-web/src/main/js/apps/projects/styles.css +++ b/server/sonar-web/src/main/js/apps/projects/styles.css @@ -36,15 +36,6 @@ padding-left: 32px; } -.projects-topbar-item.disabled { - cursor: not-allowed; - opacity: 0.4; -} - -.projects-topbar-item.disabled * { - pointer-events: none !important; -} - .projects-topbar-item-search { position: relative; flex: 1; @@ -99,65 +90,6 @@ background-color: var(--blue); } -.projects-visualization { - position: relative; - height: 600px; -} - -.projects-visualization .measure-details-bubble-chart-axis.y { - width: 300px; - left: 15px; - margin-top: 150px; - transform-origin: 0 0; - text-align: center; -} - -.projects-visualizations-footer { - margin-top: 8px; - padding: 15px 60px; - border-top: 1px solid var(--barBorderColor); - font-size: var(--smallFontSize); - line-height: 1.4; - text-align: center; -} - -.projects-visualizations-footer .note { - font-style: italic; -} - -.measure-details-bubble-chart-title { - position: absolute; - left: 20px; -} - -.measure-details-bubble-chart-axis { - position: absolute; - color: var(--secondFontColor); - font-size: var(--smallFontSize); -} - -.measure-details-bubble-chart-axis.x { - left: 50%; - bottom: 16px; - width: 500px; - margin-left: -250px; - text-align: center; -} - -.measure-details-bubble-chart-axis.y { - top: 50%; - left: -20px; - transform: rotate(-90deg); -} - -.measure-details-bubble-chart-axis.size { - display: flex; - align-items: center; - justify-content: space-around; - top: 16px; - width: 100%; -} - .projects-empty-list { padding: calc(4 * var(--gridSize)) 0; text-align: center; diff --git a/server/sonar-web/src/main/js/apps/projects/utils.ts b/server/sonar-web/src/main/js/apps/projects/utils.ts index 91547de10ef..58916044832 100644 --- a/server/sonar-web/src/main/js/apps/projects/utils.ts +++ b/server/sonar-web/src/main/js/apps/projects/utils.ts @@ -84,17 +84,7 @@ export const VIEWS = [ { value: 'leak', label: 'new_code' } ]; -export const VISUALIZATIONS = [ - 'risk', - 'reliability', - 'security', - 'maintainability', - 'coverage', - 'duplications' -]; - const PAGE_SIZE = 50; -const PAGE_SIZE_VISUALIZATIONS = 99; const METRICS = [ MetricKey.alert_status, @@ -129,37 +119,6 @@ const LEAK_METRICS = [ MetricKey.projects ]; -const METRICS_BY_VISUALIZATION: Dict<string[]> = { - risk: [ - MetricKey.reliability_rating, - MetricKey.security_rating, - MetricKey.coverage, - MetricKey.ncloc, - MetricKey.sqale_index - ], - // x, y, size, color - reliability: [ - MetricKey.ncloc, - MetricKey.reliability_remediation_effort, - MetricKey.bugs, - MetricKey.reliability_rating - ], - security: [ - MetricKey.ncloc, - MetricKey.security_remediation_effort, - MetricKey.vulnerabilities, - MetricKey.security_rating - ], - maintainability: [ - MetricKey.ncloc, - MetricKey.sqale_index, - MetricKey.code_smells, - MetricKey.sqale_rating - ], - coverage: [MetricKey.complexity, MetricKey.coverage, MetricKey.uncovered_lines], - duplications: [MetricKey.ncloc, MetricKey.duplicated_lines_density, MetricKey.duplicated_blocks] -}; - export const FACETS = [ 'reliability_rating', 'security_rating', @@ -200,7 +159,7 @@ export function parseSorting(sort: string): { sortValue: string; sortDesc: boole } export function fetchProjects(query: Query, isFavorite: boolean, pageIndex = 1) { - const ps = query.view === 'visualizations' ? PAGE_SIZE_VISUALIZATIONS : PAGE_SIZE; + const ps = PAGE_SIZE; const data = convertToQueryData(query, isFavorite, { p: pageIndex > 1 ? pageIndex : undefined, ps, @@ -233,8 +192,6 @@ export function fetchProjects(query: Query, isFavorite: boolean, pageIndex = 1) function defineMetrics(query: Query): string[] { switch (query.view) { - case 'visualizations': - return METRICS_BY_VISUALIZATION[query.visualization || 'risk']; case 'leak': return LEAK_METRICS; default: diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Coverage.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Coverage.tsx deleted file mode 100644 index b5b7629d8f0..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Coverage.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate } from '../../../helpers/l10n'; -import { Project } from '../types'; -import SimpleBubbleChart from './SimpleBubbleChart'; - -interface Props { - helpText: string; - projects: Project[]; -} - -export default function Coverage(props: Props) { - return ( - <SimpleBubbleChart - {...props} - sizeMetric={{ key: 'uncovered_lines', type: 'SHORT_INT' }} - title={translate('projects.visualization', 'coverage')} - xMetric={{ key: 'complexity', type: 'SHORT_INT' }} - yDomain={[100, 0]} - yMetric={{ key: 'coverage', type: 'PERCENT' }} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Duplications.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Duplications.tsx deleted file mode 100644 index 32cd26b0498..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Duplications.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate } from '../../../helpers/l10n'; -import { Project } from '../types'; -import SimpleBubbleChart from './SimpleBubbleChart'; - -interface Props { - helpText: string; - projects: Project[]; -} - -export default function Duplications(props: Props) { - return ( - <SimpleBubbleChart - {...props} - sizeMetric={{ key: 'duplicated_blocks', type: 'SHORT_INT' }} - title={translate('projects.visualization', 'duplications')} - xMetric={{ key: 'ncloc', type: 'SHORT_INT' }} - yMetric={{ key: 'duplicated_lines_density', type: 'PERCENT' }} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Maintainability.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Maintainability.tsx deleted file mode 100644 index d49d3de2e1b..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Maintainability.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate } from '../../../helpers/l10n'; -import { Project } from '../types'; -import SimpleBubbleChart from './SimpleBubbleChart'; - -interface Props { - helpText: string; - projects: Project[]; -} - -export default function Maintainability(props: Props) { - return ( - <SimpleBubbleChart - {...props} - colorMetric="sqale_rating" - sizeMetric={{ key: 'code_smells', type: 'SHORT_INT' }} - title={translate('projects.visualization', 'maintainability')} - xMetric={{ key: 'ncloc', type: 'SHORT_INT' }} - yMetric={{ key: 'sqale_index', type: 'SHORT_WORK_DUR' }} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Reliability.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Reliability.tsx deleted file mode 100644 index f214cc62472..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Reliability.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate } from '../../../helpers/l10n'; -import { Project } from '../types'; -import SimpleBubbleChart from './SimpleBubbleChart'; - -interface Props { - helpText: string; - projects: Project[]; -} - -export default function Reliability(props: Props) { - return ( - <SimpleBubbleChart - {...props} - colorMetric="reliability_rating" - sizeMetric={{ key: 'bugs', type: 'SHORT_INT' }} - title={translate('projects.visualization', 'reliability')} - xMetric={{ key: 'ncloc', type: 'SHORT_INT' }} - yMetric={{ key: 'reliability_remediation_effort', type: 'SHORT_WORK_DUR' }} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx deleted file mode 100644 index efc148b2cad..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx +++ /dev/null @@ -1,194 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 BubbleChart from '../../../components/charts/BubbleChart'; -import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; -import HelpTooltip from '../../../components/controls/HelpTooltip'; -import QualifierIcon from '../../../components/icons/QualifierIcon'; -import { RATING_COLORS } from '../../../helpers/constants'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { formatMeasure } from '../../../helpers/measures'; -import { isDefined } from '../../../helpers/types'; -import { getProjectUrl } from '../../../helpers/urls'; -import { ComponentQualifier } from '../../../types/component'; -import { Project } from '../types'; - -const X_METRIC = 'sqale_index'; -const X_METRIC_TYPE = 'SHORT_WORK_DUR'; -const Y_METRIC = 'coverage'; -const Y_METRIC_TYPE = 'PERCENT'; -const SIZE_METRIC = 'ncloc'; -const SIZE_METRIC_TYPE = 'SHORT_INT'; -const COLOR_METRIC_1 = 'reliability_rating'; -const COLOR_METRIC_2 = 'security_rating'; -const COLOR_METRIC_TYPE = 'RATING'; - -interface Props { - helpText: string; - projects: Project[]; -} - -interface State { - ratingFilters: { [rating: number]: boolean }; -} - -export default class Risk extends React.PureComponent<Props, State> { - state: State = { - ratingFilters: {} - }; - - getMetricTooltip(metric: { key: string; type: string }, value?: number) { - const name = translate('metric', metric.key, 'name'); - const formattedValue = value != null ? formatMeasure(value, metric.type) : '–'; - return ( - <div> - {name} - {': '} - {formattedValue} - </div> - ); - } - - getTooltip( - project: Project, - x?: number, - y?: number, - size?: number, - color1?: number, - color2?: number - ) { - return ( - <div className="text-left"> - <div className="little-spacer-bottom display-flex-center display-flex-space-between"> - <strong>{project.name}</strong> - - {project.qualifier === ComponentQualifier.Application && ( - <div className="big-spacer-left nowrap"> - <QualifierIcon - className="little-spacer-right" - fill="currentColor" - qualifier={ComponentQualifier.Application} - /> - {translate('qualifier.APP')} - </div> - )} - </div> - {this.getMetricTooltip({ key: COLOR_METRIC_1, type: COLOR_METRIC_TYPE }, color1)} - {this.getMetricTooltip({ key: COLOR_METRIC_2, type: COLOR_METRIC_TYPE }, color2)} - {this.getMetricTooltip({ key: Y_METRIC, type: Y_METRIC_TYPE }, y)} - {this.getMetricTooltip({ key: X_METRIC, type: X_METRIC_TYPE }, x)} - {this.getMetricTooltip({ key: SIZE_METRIC, type: SIZE_METRIC_TYPE }, size)} - </div> - ); - } - - handleRatingFilterClick = (selection: number) => { - this.setState(({ ratingFilters }) => { - return { ratingFilters: { ...ratingFilters, [selection]: !ratingFilters[selection] } }; - }); - }; - - render() { - const { ratingFilters } = this.state; - - const items = this.props.projects - .map(project => { - const x = - project.measures[X_METRIC] != null ? Number(project.measures[X_METRIC]) : undefined; - const y = - project.measures[Y_METRIC] != null ? Number(project.measures[Y_METRIC]) : undefined; - const size = - project.measures[SIZE_METRIC] != null ? Number(project.measures[SIZE_METRIC]) : undefined; - const color1 = - project.measures[COLOR_METRIC_1] != null - ? Number(project.measures[COLOR_METRIC_1]) - : undefined; - const color2 = - project.measures[COLOR_METRIC_2] != null - ? Number(project.measures[COLOR_METRIC_2]) - : undefined; - - const colorRating = - color1 !== undefined && color2 !== undefined ? Math.max(color1, color2) : undefined; - - // Filter out items that match ratingFilters - if (colorRating !== undefined && ratingFilters[colorRating]) { - return undefined; - } - - return { - x: x || 0, - y: y || 0, - size: size || 0, - color: colorRating !== undefined ? RATING_COLORS[colorRating - 1] : undefined, - key: project.key, - tooltip: this.getTooltip(project, x, y, size, color1, color2), - link: getProjectUrl(project.key) - }; - }) - .filter(isDefined); - - const formatXTick = (tick: number) => formatMeasure(tick, X_METRIC_TYPE); - const formatYTick = (tick: number) => formatMeasure(tick, Y_METRIC_TYPE); - - return ( - <div> - <BubbleChart - formatXTick={formatXTick} - formatYTick={formatYTick} - height={600} - items={items} - padding={[80, 20, 60, 100]} - yDomain={[100, 0]} - /> - - <div className="measure-details-bubble-chart-axis x"> - {translate('metric', X_METRIC, 'name')} - </div> - <div className="measure-details-bubble-chart-axis y"> - {translate('metric', Y_METRIC, 'name')} - </div> - <div className="measure-details-bubble-chart-axis size"> - <span className="measure-details-bubble-chart-title"> - <span className="text-middle">{translate('projects.visualization.risk')}</span> - <HelpTooltip className="spacer-left" overlay={this.props.helpText} /> - </span> - <div> - <span className="spacer-right"> - {translateWithParameters( - 'component_measures.legend.color_x', - translate('projects.worse_of_reliablity_and_security') - )} - </span> - {translateWithParameters( - 'component_measures.legend.size_x', - translate('metric', SIZE_METRIC, 'name') - )} - <ColorRatingsLegend - className="big-spacer-top" - filters={ratingFilters} - onRatingClick={this.handleRatingFilterClick} - /> - </div> - </div> - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Security.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Security.tsx deleted file mode 100644 index 1abfc615c77..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Security.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate } from '../../../helpers/l10n'; -import { Project } from '../types'; -import SimpleBubbleChart from './SimpleBubbleChart'; - -interface Props { - helpText: string; - projects: Project[]; -} - -export default function Security(props: Props) { - return ( - <SimpleBubbleChart - {...props} - colorMetric="security_rating" - sizeMetric={{ key: 'vulnerabilities', type: 'SHORT_INT' }} - title={translate('projects.visualization', 'security')} - xMetric={{ key: 'ncloc', type: 'SHORT_INT' }} - yMetric={{ key: 'security_remediation_effort', type: 'SHORT_WORK_DUR' }} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx deleted file mode 100644 index e8376adf59e..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 BubbleChart from '../../../components/charts/BubbleChart'; -import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; -import HelpTooltip from '../../../components/controls/HelpTooltip'; -import QualifierIcon from '../../../components/icons/QualifierIcon'; -import { RATING_COLORS } from '../../../helpers/constants'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { formatMeasure } from '../../../helpers/measures'; -import { isDefined } from '../../../helpers/types'; -import { getProjectUrl } from '../../../helpers/urls'; -import { ComponentQualifier } from '../../../types/component'; -import { Project } from '../types'; - -interface Metric { - key: string; - type: string; -} - -interface Props { - colorMetric?: string; - helpText: string; - projects: Project[]; - sizeMetric: Metric; - title?: string; - xMetric: Metric; - yDomain?: [number, number]; - yMetric: Metric; -} - -interface State { - ratingFilters: { [rating: number]: boolean }; -} - -export default class SimpleBubbleChart extends React.PureComponent<Props, State> { - state: State = { - ratingFilters: {} - }; - - getMetricTooltip(metric: Metric, value?: number) { - const name = translate('metric', metric.key, 'name'); - const formattedValue = value != null ? formatMeasure(value, metric.type) : '–'; - return ( - <div> - {name} - {': '} - {formattedValue} - </div> - ); - } - - getTooltip(project: Project, x?: number, y?: number, size?: number, color?: number) { - return ( - <div className="text-left"> - <div className="little-spacer-bottom display-flex-center display-flex-space-between"> - <strong>{project.name}</strong> - - {project.qualifier === ComponentQualifier.Application && ( - <div className="big-spacer-left nowrap"> - <QualifierIcon - className="little-spacer-right" - fill="currentColor" - qualifier={ComponentQualifier.Application} - /> - {translate('qualifier.APP')} - </div> - )} - </div> - {this.getMetricTooltip(this.props.xMetric, x)} - {this.getMetricTooltip(this.props.yMetric, y)} - {this.getMetricTooltip(this.props.sizeMetric, size)} - {/* if `color` is defined then `this.props.colorMetric` is defined too */} - {color && this.getMetricTooltip({ key: this.props.colorMetric!, type: 'RATING' }, color)} - </div> - ); - } - - handleRatingFilterClick = (selection: number) => { - this.setState(({ ratingFilters }) => { - return { ratingFilters: { ...ratingFilters, [selection]: !ratingFilters[selection] } }; - }); - }; - - render() { - const { xMetric, yMetric, sizeMetric, colorMetric } = this.props; - const { ratingFilters } = this.state; - - const items = this.props.projects - .filter(project => colorMetric == null || project.measures[colorMetric] !== null) - .map(project => { - const x = - project.measures[xMetric.key] != null ? Number(project.measures[xMetric.key]) : undefined; - const y = - project.measures[yMetric.key] != null ? Number(project.measures[yMetric.key]) : undefined; - const size = - project.measures[sizeMetric.key] != null - ? Number(project.measures[sizeMetric.key]) - : undefined; - const color = colorMetric ? Number(project.measures[colorMetric]) : undefined; - - // Filter out items that match ratingFilters - if (color && ratingFilters[color]) { - return undefined; - } - - return { - x: x || 0, - y: y || 0, - size: size || 0, - color: color ? RATING_COLORS[color - 1] : undefined, - key: project.key, - tooltip: this.getTooltip(project, x, y, size, color), - link: getProjectUrl(project.key) - }; - }) - .filter(isDefined); - - const formatXTick = (tick: number) => formatMeasure(tick, xMetric.type); - const formatYTick = (tick: number) => formatMeasure(tick, yMetric.type); - - return ( - <div> - <BubbleChart - formatXTick={formatXTick} - formatYTick={formatYTick} - height={600} - items={items} - padding={[colorMetric ? 80 : 40, 20, 60, 100]} - yDomain={this.props.yDomain} - /> - <div className="measure-details-bubble-chart-axis x"> - {translate('metric', xMetric.key, 'name')} - </div> - <div className="measure-details-bubble-chart-axis y"> - {translate('metric', yMetric.key, 'name')} - </div> - <div className="measure-details-bubble-chart-axis size"> - <span className="measure-details-bubble-chart-title"> - <span className="text-middle">{this.props.title}</span> - <HelpTooltip className="spacer-left" overlay={this.props.helpText} /> - </span> - <div> - {colorMetric != null && ( - <span className="spacer-right"> - {translateWithParameters( - 'component_measures.legend.color_x', - translate('metric', colorMetric, 'name') - )} - </span> - )} - {translateWithParameters( - 'component_measures.legend.size_x', - translate('metric', sizeMetric.key, 'name') - )} - {colorMetric != null && ( - <ColorRatingsLegend - className="big-spacer-top" - filters={ratingFilters} - onRatingClick={this.handleRatingFilterClick} - /> - )} - </div> - </div> - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx deleted file mode 100644 index f25ce4fb271..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Visualizations.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { translate, translateWithParameters } from '../../../helpers/l10n'; -import { Dict } from '../../../types/types'; -import { Project } from '../types'; -import { localizeSorting } from '../utils'; -import Coverage from './Coverage'; -import Duplications from './Duplications'; -import Maintainability from './Maintainability'; -import Reliability from './Reliability'; -import Risk from './Risk'; -import Security from './Security'; - -interface Props { - projects: Project[]; - sort?: string; - total?: number; - visualization: string; -} - -export default class Visualizations extends React.PureComponent<Props> { - renderVisualization(projects: Project[]) { - const visualizationToComponent: Dict<any> = { - risk: Risk, - reliability: Reliability, - security: Security, - maintainability: Maintainability, - coverage: Coverage, - duplications: Duplications - }; - const Component = visualizationToComponent[this.props.visualization]; - - return Component ? ( - <Component - helpText={translate('projects.visualization', this.props.visualization, 'description')} - projects={projects} - /> - ) : null; - } - - renderFooter() { - const { projects, total, sort } = this.props; - - const limitReached = projects != null && total != null && projects.length < total; - - return limitReached ? ( - <footer className="projects-visualizations-footer"> - <p className="note spacer-top"> - {translateWithParameters( - 'projects.limited_set_of_projects', - projects!.length, - localizeSorting(sort) - )} - </p> - </footer> - ) : null; - } - - render() { - const { projects } = this.props; - - return ( - <div className="boxed-group projects-visualizations"> - <main className="projects-visualization"> - {projects != null && this.renderVisualization(projects)} - </main> - {this.renderFooter()} - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Coverage-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Coverage-test.tsx deleted file mode 100644 index 9fa76d3f3d9..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Coverage-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Coverage from '../Coverage'; - -it('renders', () => { - expect(shallow(<Coverage helpText="foobar" projects={[]} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Duplications-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Duplications-test.tsx deleted file mode 100644 index 6fe9cca6eaf..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Duplications-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Duplications from '../Duplications'; - -it('renders', () => { - expect(shallow(<Duplications helpText="foobar" projects={[]} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Maintainability-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Maintainability-test.tsx deleted file mode 100644 index 940d8974c84..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Maintainability-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Maintainability from '../Maintainability'; - -it('renders', () => { - expect(shallow(<Maintainability helpText="foobar" projects={[]} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Reliability-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Reliability-test.tsx deleted file mode 100644 index 56be0e385d3..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Reliability-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Reliability from '../Reliability'; - -it('renders', () => { - expect(shallow(<Reliability helpText="foobar" projects={[]} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Risk-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Risk-test.tsx deleted file mode 100644 index d56b65fa874..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Risk-test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import { mockProject } from '../../../../helpers/mocks/projects'; -import Risk from '../Risk'; - -it('renders', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should handle filtering', () => { - const wrapper = shallowRender(); - - wrapper.instance().handleRatingFilterClick(2); - - expect(wrapper.state().ratingFilters).toEqual({ 2: true }); -}); - -function shallowRender(overrides: Partial<Risk['props']> = {}) { - const project1 = mockProject({ - key: 'foo', - measures: { - complexity: '17.2', - coverage: '53.5', - ncloc: '1734', - sqale_index: '1', - reliability_rating: '3', - security_rating: '2' - }, - name: 'Foo' - }); - const project2 = mockProject({ - key: 'bar', - name: 'Bar', - measures: {} - }); - return shallow<Risk>(<Risk helpText="foobar" projects={[project1, project2]} {...overrides} />); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Security-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Security-test.tsx deleted file mode 100644 index fb3cb5d35e7..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Security-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Security from '../Security'; - -it('renders', () => { - expect(shallow(<Security helpText="foobar" projects={[]} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/SimpleBubbleChart-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/SimpleBubbleChart-test.tsx deleted file mode 100644 index 399d308bcf0..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/SimpleBubbleChart-test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import { mockProject } from '../../../../helpers/mocks/projects'; -import { ComponentQualifier } from '../../../../types/component'; -import SimpleBubbleChart from '../SimpleBubbleChart'; - -it('renders', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should handle filtering', () => { - const wrapper = shallowRender(); - - wrapper.instance().handleRatingFilterClick(2); - - expect(wrapper.state().ratingFilters).toEqual({ 2: true }); -}); - -function shallowRender(overrides: Partial<SimpleBubbleChart['props']> = {}) { - const project1 = mockProject({ - measures: { complexity: '17.2', coverage: '53.5', ncloc: '1734', security_rating: '2' } - }); - const app = mockProject({ - key: 'app', - measures: { complexity: '23.1', coverage: '87.3', ncloc: '32478', security_rating: '1' }, - name: 'App', - qualifier: ComponentQualifier.Application - }); - return shallow<SimpleBubbleChart>( - <SimpleBubbleChart - colorMetric="security_rating" - helpText="foobar" - projects={[app, project1]} - sizeMetric={{ key: 'ncloc', type: 'INT' }} - xMetric={{ key: 'complexity', type: 'INT' }} - yMetric={{ key: 'coverage', type: 'PERCENT' }} - {...overrides} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Visualizations-test.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Visualizations-test.tsx deleted file mode 100644 index 37815b9f1ad..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/Visualizations-test.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import Visualizations from '../Visualizations'; - -it('renders', () => { - expect(shallow(<Visualizations projects={[]} visualization="coverage" />)).toMatchSnapshot(); -}); - -it('renders when limit is reached', () => { - expect( - shallow(<Visualizations projects={[]} total={1000} visualization="coverage" />) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Coverage-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Coverage-test.tsx.snap deleted file mode 100644 index 469481fc92f..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Coverage-test.tsx.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<SimpleBubbleChart - helpText="foobar" - projects={Array []} - sizeMetric={ - Object { - "key": "uncovered_lines", - "type": "SHORT_INT", - } - } - title="projects.visualization.coverage" - xMetric={ - Object { - "key": "complexity", - "type": "SHORT_INT", - } - } - yDomain={ - Array [ - 100, - 0, - ] - } - yMetric={ - Object { - "key": "coverage", - "type": "PERCENT", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Duplications-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Duplications-test.tsx.snap deleted file mode 100644 index 67fba43c178..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Duplications-test.tsx.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<SimpleBubbleChart - helpText="foobar" - projects={Array []} - sizeMetric={ - Object { - "key": "duplicated_blocks", - "type": "SHORT_INT", - } - } - title="projects.visualization.duplications" - xMetric={ - Object { - "key": "ncloc", - "type": "SHORT_INT", - } - } - yMetric={ - Object { - "key": "duplicated_lines_density", - "type": "PERCENT", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Maintainability-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Maintainability-test.tsx.snap deleted file mode 100644 index e69496b58a5..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Maintainability-test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<SimpleBubbleChart - colorMetric="sqale_rating" - helpText="foobar" - projects={Array []} - sizeMetric={ - Object { - "key": "code_smells", - "type": "SHORT_INT", - } - } - title="projects.visualization.maintainability" - xMetric={ - Object { - "key": "ncloc", - "type": "SHORT_INT", - } - } - yMetric={ - Object { - "key": "sqale_index", - "type": "SHORT_WORK_DUR", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Reliability-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Reliability-test.tsx.snap deleted file mode 100644 index e018ca736b8..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Reliability-test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<SimpleBubbleChart - colorMetric="reliability_rating" - helpText="foobar" - projects={Array []} - sizeMetric={ - Object { - "key": "bugs", - "type": "SHORT_INT", - } - } - title="projects.visualization.reliability" - xMetric={ - Object { - "key": "ncloc", - "type": "SHORT_INT", - } - } - yMetric={ - Object { - "key": "reliability_remediation_effort", - "type": "SHORT_WORK_DUR", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap deleted file mode 100644 index e62a6b6a11e..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap +++ /dev/null @@ -1,179 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<div> - <BubbleChart - displayXGrid={true} - displayXTicks={true} - displayYGrid={true} - displayYTicks={true} - formatXTick={[Function]} - formatYTick={[Function]} - height={600} - items={ - Array [ - Object { - "color": "#eabe06", - "key": "foo", - "link": Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "foo", - }, - }, - "size": 1734, - "tooltip": <div - className="text-left" - > - <div - className="little-spacer-bottom display-flex-center display-flex-space-between" - > - <strong> - Foo - </strong> - </div> - <div> - metric.reliability_rating.name - : - C - </div> - <div> - metric.security_rating.name - : - B - </div> - <div> - metric.coverage.name - : - 53.5% - </div> - <div> - metric.sqale_index.name - : - work_duration.x_minutes.1 - </div> - <div> - metric.ncloc.name - : - 1.7short_number_suffix.k - </div> - </div>, - "x": 1, - "y": 53.5, - }, - Object { - "color": undefined, - "key": "bar", - "link": Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "bar", - }, - }, - "size": 0, - "tooltip": <div - className="text-left" - > - <div - className="little-spacer-bottom display-flex-center display-flex-space-between" - > - <strong> - Bar - </strong> - </div> - <div> - metric.reliability_rating.name - : - – - </div> - <div> - metric.security_rating.name - : - – - </div> - <div> - metric.coverage.name - : - – - </div> - <div> - metric.sqale_index.name - : - – - </div> - <div> - metric.ncloc.name - : - – - </div> - </div>, - "x": 0, - "y": 0, - }, - ] - } - padding={ - Array [ - 80, - 20, - 60, - 100, - ] - } - sizeRange={ - Array [ - 5, - 45, - ] - } - yDomain={ - Array [ - 100, - 0, - ] - } - /> - <div - className="measure-details-bubble-chart-axis x" - > - metric.sqale_index.name - </div> - <div - className="measure-details-bubble-chart-axis y" - > - metric.coverage.name - </div> - <div - className="measure-details-bubble-chart-axis size" - > - <span - className="measure-details-bubble-chart-title" - > - <span - className="text-middle" - > - projects.visualization.risk - </span> - <HelpTooltip - className="spacer-left" - overlay="foobar" - /> - </span> - <div> - <span - className="spacer-right" - > - component_measures.legend.color_x.projects.worse_of_reliablity_and_security - </span> - component_measures.legend.size_x.metric.ncloc.name - <ColorRatingsLegend - className="big-spacer-top" - filters={Object {}} - onRatingClick={[Function]} - /> - </div> - </div> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Security-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Security-test.tsx.snap deleted file mode 100644 index 17e548978ec..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Security-test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<SimpleBubbleChart - colorMetric="security_rating" - helpText="foobar" - projects={Array []} - sizeMetric={ - Object { - "key": "vulnerabilities", - "type": "SHORT_INT", - } - } - title="projects.visualization.security" - xMetric={ - Object { - "key": "ncloc", - "type": "SHORT_INT", - } - } - yMetric={ - Object { - "key": "security_remediation_effort", - "type": "SHORT_WORK_DUR", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap deleted file mode 100644 index bc2daa21d57..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap +++ /dev/null @@ -1,171 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<div> - <BubbleChart - displayXGrid={true} - displayXTicks={true} - displayYGrid={true} - displayYTicks={true} - formatXTick={[Function]} - formatYTick={[Function]} - height={600} - items={ - Array [ - Object { - "color": "#00aa00", - "key": "app", - "link": Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "app", - }, - }, - "size": 32478, - "tooltip": <div - className="text-left" - > - <div - className="little-spacer-bottom display-flex-center display-flex-space-between" - > - <strong> - App - </strong> - <div - className="big-spacer-left nowrap" - > - <QualifierIcon - className="little-spacer-right" - fill="currentColor" - qualifier="APP" - /> - qualifier.APP - </div> - </div> - <div> - metric.complexity.name - : - 23 - </div> - <div> - metric.coverage.name - : - 87.3% - </div> - <div> - metric.ncloc.name - : - 32,478 - </div> - <div> - metric.security_rating.name - : - A - </div> - </div>, - "x": 23.1, - "y": 87.3, - }, - Object { - "color": "#b0d513", - "key": "foo", - "link": Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "foo", - }, - }, - "size": 1734, - "tooltip": <div - className="text-left" - > - <div - className="little-spacer-bottom display-flex-center display-flex-space-between" - > - <strong> - Foo - </strong> - </div> - <div> - metric.complexity.name - : - 17 - </div> - <div> - metric.coverage.name - : - 53.5% - </div> - <div> - metric.ncloc.name - : - 1,734 - </div> - <div> - metric.security_rating.name - : - B - </div> - </div>, - "x": 17.2, - "y": 53.5, - }, - ] - } - padding={ - Array [ - 80, - 20, - 60, - 100, - ] - } - sizeRange={ - Array [ - 5, - 45, - ] - } - /> - <div - className="measure-details-bubble-chart-axis x" - > - metric.complexity.name - </div> - <div - className="measure-details-bubble-chart-axis y" - > - metric.coverage.name - </div> - <div - className="measure-details-bubble-chart-axis size" - > - <span - className="measure-details-bubble-chart-title" - > - <span - className="text-middle" - /> - <HelpTooltip - className="spacer-left" - overlay="foobar" - /> - </span> - <div> - <span - className="spacer-right" - > - component_measures.legend.color_x.metric.security_rating.name - </span> - component_measures.legend.size_x.metric.ncloc.name - <ColorRatingsLegend - className="big-spacer-top" - filters={Object {}} - onRatingClick={[Function]} - /> - </div> - </div> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Visualizations-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Visualizations-test.tsx.snap deleted file mode 100644 index a74c4bec92d..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Visualizations-test.tsx.snap +++ /dev/null @@ -1,40 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<div - className="boxed-group projects-visualizations" -> - <main - className="projects-visualization" - > - <Coverage - helpText="projects.visualization.coverage.description" - projects={Array []} - /> - </main> -</div> -`; - -exports[`renders when limit is reached 1`] = ` -<div - className="boxed-group projects-visualizations" -> - <main - className="projects-visualization" - > - <Coverage - helpText="projects.visualization.coverage.description" - projects={Array []} - /> - </main> - <footer - className="projects-visualizations-footer" - > - <p - className="note spacer-top" - > - projects.limited_set_of_projects.0.projects.sort.name - </p> - </footer> -</div> -`; |