From afa5ca444414f8c4352afb53528b9514d1c22c77 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 1 Apr 2020 16:40:30 +0200 Subject: [PATCH] SONAR-13189 Add qualifier facet to projects --- .../apps/projects/components/AllProjects.tsx | 88 ++------ .../components/AllProjectsContainer.tsx | 5 +- .../apps/projects/components/PageSidebar.tsx | 38 +++- .../components/__tests__/AllProjects-test.tsx | 28 +-- .../components/__tests__/PageSidebar-test.tsx | 78 ++++--- .../__snapshots__/AllProjects-test.tsx.snap | 209 +----------------- .../__snapshots__/PageSidebar-test.tsx.snap | 162 +++++++++----- .../apps/projects/filters/CoverageFilter.tsx | 2 - .../projects/filters/DuplicationsFilter.tsx | 2 - .../main/js/apps/projects/filters/Filter.tsx | 1 - .../js/apps/projects/filters/IssuesFilter.tsx | 2 - .../apps/projects/filters/LanguagesFilter.tsx | 1 - .../filters/MaintainabilityFilter.tsx | 1 - .../apps/projects/filters/NewLinesFilter.tsx | 2 - .../filters/NewMaintainabilityFilter.tsx | 1 - .../projects/filters/NewReliabilityFilter.tsx | 1 - .../projects/filters/NewSecurityFilter.tsx | 1 - .../apps/projects/filters/QualifierFilter.tsx | 67 ++++++ .../projects/filters/QualityGateFilter.tsx | 2 - .../projects/filters/ReliabilityFilter.tsx | 1 - .../apps/projects/filters/SecurityFilter.tsx | 1 - .../projects/filters/SecurityReviewFilter.tsx | 16 +- .../js/apps/projects/filters/SizeFilter.tsx | 2 - .../js/apps/projects/filters/TagsFilter.tsx | 1 - .../filters/__tests__/CoverageFilter-test.tsx | 2 +- .../__tests__/DuplicationsFilter-test.tsx | 2 +- .../filters/__tests__/Filter-test.tsx | 7 +- .../filters/__tests__/IssuesFilter-test.tsx | 4 +- .../__tests__/MaintainabilityFilter-test.tsx | 2 +- .../__tests__/NewCoverageFilter-test.tsx | 2 +- .../__tests__/NewDuplicationsFilter-test.tsx | 2 +- .../filters/__tests__/NewLinesFilter-test.tsx | 2 +- .../NewMaintainabilityFilter-test.tsx | 4 +- .../__tests__/NewReliabilityFilter-test.tsx | 2 +- .../__tests__/NewSecurityFilter-test.tsx | 2 +- .../__tests__/QualifierFilter-test.tsx | 38 ++++ .../__tests__/QualityGateFilter-test.tsx | 2 +- .../__tests__/ReliabilityFilter-test.tsx | 2 +- .../filters/__tests__/SecurityFilter-test.tsx | 2 +- .../__tests__/SecurityReviewFilter-test.tsx | 2 +- .../filters/__tests__/SizeFilter-test.tsx | 2 +- .../CoverageFilter-test.tsx.snap | 1 - .../DuplicationsFilter-test.tsx.snap | 1 - .../__snapshots__/IssuesFilter-test.tsx.snap | 1 - .../LanguagesFilter-test.tsx.snap | 13 -- .../MaintainabilityFilter-test.tsx.snap | 1 - .../NewCoverageFilter-test.tsx.snap | 1 - .../NewDuplicationsFilter-test.tsx.snap | 1 - .../NewLinesFilter-test.tsx.snap | 1 - .../NewMaintainabilityFilter-test.tsx.snap | 1 - .../NewReliabilityFilter-test.tsx.snap | 1 - .../NewSecurityFilter-test.tsx.snap | 1 - .../QualifierFilter-test.tsx.snap | 33 +++ .../QualityGateFilter-test.tsx.snap | 1 - .../ReliabilityFilter-test.tsx.snap | 1 - .../SecurityFilter-test.tsx.snap | 1 - .../SecurityReviewFilter-test.tsx.snap | 1 - .../__snapshots__/SizeFilter-test.tsx.snap | 1 - .../__snapshots__/TagsFilter-test.tsx.snap | 26 --- .../src/main/js/apps/projects/query.ts | 12 +- .../src/main/js/apps/projects/utils.ts | 9 +- .../component/ws/SearchProjectsAction.java | 21 +- .../resources/org/sonar/l10n/core.properties | 1 + 63 files changed, 386 insertions(+), 535 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx create mode 100644 server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualifierFilter-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap 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 07aee81409d..89e22be3c20 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 @@ -28,13 +28,11 @@ import { addSideBarClass, removeSideBarClass } from 'sonar-ui-common/helpers/pag import { get, save } from 'sonar-ui-common/helpers/storage'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; -import { OnboardingContext } from '../../../app/components/OnboardingContext'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; import '../../../components/search-navigator.css'; -import { isSonarCloud } from '../../../helpers/system'; import { isLoggedIn } from '../../../helpers/users'; -import OrganizationEmpty from '../../organizations/components/OrganizationEmpty'; +import { ComponentQualifier } from '../../../types/component'; import { hasFilterParams, hasVisualizationParams, parseUrlQuery, Query } from '../query'; import '../styles.css'; import { Facets, Project } from '../types'; @@ -49,13 +47,13 @@ interface Props { isFavorite: boolean; location: Pick; organization: T.Organization | undefined; + qualifiers: ComponentQualifier[]; router: Pick; storageOptionsSuffix?: string; } interface State { facets?: Facets; - initialLoading: boolean; loading: boolean; pageIndex?: number; projects?: Project[]; @@ -72,7 +70,7 @@ export class AllProjects extends React.PureComponent { constructor(props: Props) { super(props); - this.state = { initialLoading: true, loading: true, query: {} }; + this.state = { loading: true, query: {} }; } componentDidMount() { @@ -83,23 +81,13 @@ export class AllProjects extends React.PureComponent { return; } this.handleQueryChange(true); - this.updateFooterClass(); + addSideBarClass(); } componentDidUpdate(prevProps: Props) { if (prevProps.location.query !== this.props.location.query) { this.handleQueryChange(false); } - - if ( - prevProps.organization && - this.props.organization && - prevProps.organization.key !== this.props.organization.key - ) { - this.setState({ initialLoading: true }); - } - - this.updateFooterClass(); } componentWillUnmount() { @@ -113,7 +101,6 @@ export class AllProjects extends React.PureComponent { if (this.mounted) { this.setState({ facets: response.facets, - initialLoading: false, loading: false, pageIndex: 1, projects: response.projects, @@ -232,7 +219,7 @@ export class AllProjects extends React.PureComponent { stopLoading = () => { if (this.mounted) { - this.setState({ initialLoading: false, loading: false }); + this.setState({ loading: false }); } }; @@ -241,19 +228,6 @@ export class AllProjects extends React.PureComponent { this.props.router.push({ pathname: this.props.location.pathname, query }); }; - updateFooterClass = () => { - const { organization } = this.props; - const { initialLoading, projects } = this.state; - const isOrganizationContext = isSonarCloud() && organization; - const isEmpty = projects && projects.length === 0; - - if (isOrganizationContext && (initialLoading || isEmpty)) { - removeSideBarClass(); - } else { - addSideBarClass(); - } - }; - renderSide = () => ( {({ top }) => ( @@ -267,12 +241,12 @@ export class AllProjects extends React.PureComponent { /> @@ -316,7 +290,7 @@ export class AllProjects extends React.PureComponent {
{this.state.projects && ( { }; render() { - const { organization } = this.props; - const { projects } = this.state; - const isOrganizationContext = isSonarCloud() && organization; - const initialLoading = isOrganizationContext && this.state.initialLoading; - const organizationEmpty = - isOrganizationContext && - projects && - projects.length === 0 && - !this.state.loading && - !hasFilterParams(this.state.query); - return (
- {initialLoading ? ( -
- -
- ) : ( - <> - {!organizationEmpty && this.renderSide()} - -
- - - {organizationEmpty && organization ? ( - - {openProjectOnboarding => ( - - )} - - ) : ( - <> - {this.renderHeader()} - {this.renderMain()} - - )} -
- - )} + {this.renderSide()} + +
+ + + {this.renderHeader()} + {this.renderMain()} +
); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx index 09c3f522345..640630d61ed 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx @@ -19,11 +19,12 @@ */ import { connect } from 'react-redux'; import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent'; -import { areThereCustomOrganizations, getCurrentUser, Store } from '../../../store/rootReducer'; +import { getAppState, getCurrentUser, Store } from '../../../store/rootReducer'; +import { ComponentQualifier } from '../../../types/component'; const stateToProps = (state: Store) => ({ currentUser: getCurrentUser(state), - organizationsEnabled: areThereCustomOrganizations(state) + qualifiers: getAppState(state).qualifiers as ComponentQualifier[] }); export default connect(stateToProps)(lazyLoadComponent(() => import('./AllProjects'))); 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 722640090be..b92e20b1e66 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 @@ -30,6 +30,7 @@ import NewLinesFilter from '../filters/NewLinesFilter'; import NewMaintainabilityFilter from '../filters/NewMaintainabilityFilter'; import NewReliabilityFilter from '../filters/NewReliabilityFilter'; import NewSecurityFilter from '../filters/NewSecurityFilter'; +import QualifierFilter from '../filters/QualifierFilter'; import QualityGateFilter from '../filters/QualityGateFilter'; import ReliabilityFilter from '../filters/ReliabilityFilter'; import SecurityFilter from '../filters/SecurityFilter'; @@ -41,23 +42,31 @@ import { Facets } from '../types'; import ClearAll from './ClearAll'; import FavoriteFilterContainer from './FavoriteFilterContainer'; -interface Props { +export interface PageSidebarProps { + applicationsEnabled: boolean; facets?: Facets; onClearAll: () => void; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; query: T.RawQuery; - showFavoriteFilter: boolean; view: string; visualization: string; } -export default function PageSidebar(props: Props) { - const { facets, onQueryChange, query, organization, view, visualization } = props; +export default function PageSidebar(props: PageSidebarProps) { + const { + applicationsEnabled, + facets, + onQueryChange, + query, + organization, + view, + visualization + } = props; const isFiltered = hasFilterParams(query); const isLeakView = view === 'leak'; const maxFacetValue = getMaxFacetValue(facets); - const facetProps = { onQueryChange, maxFacetValue, organization, query }; + const facetProps = { onQueryChange, maxFacetValue, organization }; let linkQuery: T.RawQuery | undefined = undefined; if (view !== 'overall') { @@ -70,9 +79,7 @@ export default function PageSidebar(props: Props) { return (
- {props.showFavoriteFilter && ( - - )} +
{isFiltered && } @@ -161,9 +168,22 @@ export default function PageSidebar(props: Props) { - + {applicationsEnabled && ( + + )} +
); } 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 3add3f6bbcb..438e519eb61 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 @@ -20,8 +20,6 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { get, save } from 'sonar-ui-common/helpers/storage'; -import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import { isSonarCloud } from '../../../../helpers/system'; import { ComponentQualifier } from '../../../../types/component'; import { AllProjects } from '../AllProjects'; @@ -57,14 +55,11 @@ jest.mock('sonar-ui-common/helpers/storage', () => ({ save: jest.fn() })); -jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); - const fetchProjects = require('../../utils').fetchProjects as jest.Mock; beforeEach(() => { (get as jest.Mock).mockImplementation(() => null); (save as jest.Mock).mockClear(); - (isSonarCloud as jest.Mock).mockReturnValue(false); fetchProjects.mockClear(); }); @@ -166,28 +161,6 @@ it('changes perspective to risk visualization', () => { expect(save).toHaveBeenCalledWith('sonarqube.projects.visualization', 'risk', undefined); }); -it('renders correctly empty organization', async () => { - (isSonarCloud as jest.Mock).mockReturnValue(true); - const wrapper = shallow( - - ); - expect(wrapper).toMatchSnapshot(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - wrapper.setState({ - loading: false, - projects: [{ key: 'foo', measures: {}, name: 'Foo' }], - total: 0 - }); - expect(wrapper).toMatchSnapshot(); -}); - it('handles favorite projects', () => { const wrapper = shallowRender(); expect(wrapper.state('projects')).toMatchSnapshot(); @@ -207,6 +180,7 @@ function shallowRender( isFavorite={false} location={{ pathname: '/projects', query: {} }} organization={undefined} + qualifiers={[ComponentQualifier.Project, ComponentQualifier.Application]} router={{ push, replace }} {...props} /> 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 197b42b5ea9..fc9969d2363 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 @@ -19,48 +19,70 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import PageSidebar from '../PageSidebar'; +import PageSidebar, { PageSidebarProps } from '../PageSidebar'; it('should render correctly', () => { - const sidebar = shallow( - - ); + const sidebar = shallowRender({ + query: { size: '3' }, + view: 'overall', + visualization: 'risk' + }); + + expect(sidebar).toMatchSnapshot(); +}); + +it('should render correctly with no applications', () => { + const sidebar = shallowRender({ + applicationsEnabled: false, + query: { size: '3' }, + view: 'overall', + visualization: 'risk' + }); + expect(sidebar).toMatchSnapshot(); }); it('should render `leak` view correctly', () => { - const sidebar = shallow( - - ); + const sidebar = shallowRender({ + query: { view: 'leak' }, + view: 'leak', + visualization: 'risk' + }); + expect(sidebar).toMatchSnapshot(); +}); + +it('should render `leak` view correctly with no applications', () => { + const sidebar = shallowRender({ + applicationsEnabled: false, + query: { view: 'leak' }, + view: 'leak', + visualization: 'risk' + }); expect(sidebar).toMatchSnapshot(); }); it('reset function should work correctly with view and visualizations', () => { - const sidebar = shallow( + 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 = {}) { + return shallow( ); - expect(sidebar.find('ClearAll').exists()).toBe(false); - sidebar.setProps({ query: { size: '3' } }); - expect(sidebar.find('ClearAll').exists()).toBe(true); -}); +} 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 58f1e3f2750..dd7306ad88d 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 @@ -97,6 +97,7 @@ exports[`renders 1`] = ` "new_reliability": undefined, "new_security": undefined, "new_security_review_rating": undefined, + "qualifier": undefined, "reliability": undefined, "search": undefined, "security": undefined, @@ -155,6 +156,7 @@ exports[`renders 1`] = ` "new_reliability": undefined, "new_security": undefined, "new_security_review_rating": undefined, + "qualifier": undefined, "reliability": undefined, "search": undefined, "security": undefined, @@ -272,210 +274,3 @@ exports[`renders 2`] = `
`; - -exports[`renders correctly empty organization 1`] = ` -
- - -
- -
-
-`; - -exports[`renders correctly empty organization 2`] = ` -
- - -
- - - - -
-
-`; - -exports[`renders correctly empty organization 3`] = ` -
- - - - - -
- -
-
-
- -
-
-
-
- - -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap index 8c607217185..ac6904b4bc7 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap @@ -18,55 +18,42 @@ exports[`should render \`leak\` view correctly 1`] = ` + + + - + - +`; + +exports[`should render \`leak\` view correctly with no applications 1`] = ` +
+ +
+

+ filters +

+
+ + + + + + + + + + - + +
+`; + +exports[`should render correctly with no applications 1`] = ` +
+ +
+ +

+ filters +

+
+ + + + + + + + void; organization?: { key: string }; property?: string; - query: T.Dict; value?: any; } @@ -55,7 +54,6 @@ export default function CoverageFilter(props: Props) { options={[1, 2, 3, 4, 5, 6]} organization={props.organization} property={property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx index 7b9875cfb14..673a0d5df2a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx @@ -35,7 +35,6 @@ export interface Props { onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; property?: string; - query: T.Dict; value?: any; } @@ -54,7 +53,6 @@ export default function DuplicationsFilter(props: Props) { options={[1, 2, 3, 4, 5, 6]} organization={props.organization} property={property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx index 0c331e76bdd..a76a69d6ceb 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx @@ -30,7 +30,6 @@ interface Props { className?: string; onQueryChange: (change: T.RawQuery) => void; options: Option[]; - query: T.Dict; renderOption: (option: Option, isSelected: boolean) => React.ReactNode; value?: Option | Option[]; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx index 324541f8441..9ff16d6a5a6 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx @@ -33,7 +33,6 @@ interface Props { onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; property: string; - query: T.Dict; value?: any; } @@ -53,7 +52,6 @@ export default function IssuesFilter(props: Props) { options={[1, 2, 3, 4, 5]} organization={props.organization} property={props.property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx index 2c75faaa03a..1a6c9a3ec3a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx @@ -79,7 +79,6 @@ export default class LanguagesFilter extends React.Component { options={this.getSortedOptions(this.props.facet)} organization={this.props.organization} property={property} - query={this.props.query} renderOption={this.renderOption} value={this.props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/MaintainabilityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/MaintainabilityFilter.tsx index a1798e6e98c..7d95f9cf26f 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/MaintainabilityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/MaintainabilityFilter.tsx @@ -30,7 +30,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx index e760076cb0b..93bb00e69da 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx @@ -31,7 +31,6 @@ export interface Props { onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; property?: string; - query: T.Dict; value?: any; } @@ -50,7 +49,6 @@ export default function NewLinesFilter(props: Props) { options={[1, 2, 3, 4, 5]} organization={props.organization} property={property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/NewMaintainabilityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/NewMaintainabilityFilter.tsx index cb326c2ff9f..ae1cf6cec6f 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/NewMaintainabilityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/NewMaintainabilityFilter.tsx @@ -29,7 +29,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/NewReliabilityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/NewReliabilityFilter.tsx index 4000d2837da..d17247295e8 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/NewReliabilityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/NewReliabilityFilter.tsx @@ -29,7 +29,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/NewSecurityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/NewSecurityFilter.tsx index 6c13f553e5e..1cc7f4a768e 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/NewSecurityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/NewSecurityFilter.tsx @@ -29,7 +29,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx new file mode 100644 index 00000000000..4a8ada5c833 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 QualifierIcon from 'sonar-ui-common/components/icons/QualifierIcon'; +import { translate } from 'sonar-ui-common/helpers/l10n'; +import { ComponentQualifier } from '../../../types/component'; +import { Facet } from '../types'; +import Filter from './Filter'; +import FilterHeader from './FilterHeader'; + +export interface QualifierFilterProps { + facet?: Facet; + maxFacetValue?: number; + onQueryChange: (change: T.RawQuery) => void; + organization?: { key: string }; + value: ComponentQualifier | undefined; +} + +const options = [ComponentQualifier.Project, ComponentQualifier.Application]; + +export default function QualifierFilter(props: QualifierFilterProps) { + const { facet, maxFacetValue, organization, value } = props; + + return ( + } + maxFacetValue={maxFacetValue} + onQueryChange={props.onQueryChange} + options={options} + organization={organization} + property="qualifier" + renderOption={renderOption} + value={value} + /> + ); +} + +function renderOption(option: string, selected: boolean) { + return ( + + + {translate('qualifier', option)} + + ); +} diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx index 2bee422e1e9..c93b7714e96 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx @@ -31,7 +31,6 @@ export interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } @@ -48,7 +47,6 @@ export default function QualityGateFilter(props: Props) { options={options} organization={props.organization} property="gate" - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/ReliabilityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/ReliabilityFilter.tsx index fae5e9cc80f..c77839c16ba 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/ReliabilityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/ReliabilityFilter.tsx @@ -30,7 +30,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SecurityFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SecurityFilter.tsx index 0e771cdf8cd..308af85f589 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SecurityFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SecurityFilter.tsx @@ -30,7 +30,6 @@ interface Props { maxFacetValue?: number; onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; - query: T.Dict; value?: any; } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx index 971f5f7a08e..df7a9ad7b39 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx @@ -32,7 +32,6 @@ export interface Props { onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; property?: string; - query: T.Dict; value?: any; } @@ -53,14 +52,12 @@ export default function SecurityReviewFilter(props: Props) { facet={props.facet} header={ - { - - {'( '} - - {translate('metric.security_hotspots.name')} - {' )'} - - } + + {'( '} + + {translate('metric.security_hotspots.name')} + {' )'} + } highlightUnder={1} @@ -69,7 +66,6 @@ export default function SecurityReviewFilter(props: Props) { options={[1, 2, 3, 4, 5]} organization={props.organization} property={property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx index 386ceb7b995..235e6a81904 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx @@ -32,7 +32,6 @@ export interface Props { onQueryChange: (change: T.RawQuery) => void; organization?: { key: string }; property?: string; - query: T.Dict; value?: any; } @@ -51,7 +50,6 @@ export default function SizeFilter(props: Props) { options={[1, 2, 3, 4, 5]} organization={props.organization} property={property} - query={props.query} renderOption={renderOption} value={props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx index d31b017be9b..2fe20cbe45b 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx @@ -121,7 +121,6 @@ export default class TagsFilter extends React.PureComponent { options={this.getSortedOptions(this.props.facet)} organization={this.props.organization} property={property} - query={this.props.query} renderOption={this.renderOption} value={this.props.value} /> diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/CoverageFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/CoverageFilter-test.tsx index e39cbd85d43..573c1e0d69f 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/CoverageFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/CoverageFilter-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import CoverageFilter from '../CoverageFilter'; it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/DuplicationsFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/DuplicationsFilter-test.tsx index 5a72e02355a..c40816fd91a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/DuplicationsFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/DuplicationsFilter-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import DuplicationsFilter from '../DuplicationsFilter'; it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx index 2d25b9691be..d95f494f863 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx @@ -60,15 +60,14 @@ it('renders facet bar chart', () => { ).toMatchSnapshot(); }); -function shallowRender(props?: any) { - return shallow( +function shallowRender(overrides: Partial = {}) { + return shallow( option} - {...props} + {...overrides} /> ); } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/IssuesFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/IssuesFilter-test.tsx index 38608957ba3..6d3ccf1ad84 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/IssuesFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/IssuesFilter-test.tsx @@ -22,9 +22,7 @@ import * as React from 'react'; import IssuesFilter from '../IssuesFilter'; it('renders', () => { - const wrapper = shallow( - - ); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/MaintainabilityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/MaintainabilityFilter-test.tsx index dc4c182f99b..1d5c8a0d3f0 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/MaintainabilityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/MaintainabilityFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import MaintainabilityFilter from '../MaintainabilityFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewCoverageFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewCoverageFilter-test.tsx index 811300cb54d..d23c0d049bf 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewCoverageFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewCoverageFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import NewCoverageFilter from '../NewCoverageFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewDuplicationsFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewDuplicationsFilter-test.tsx index bca7edaf6aa..7e3f9c456eb 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewDuplicationsFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewDuplicationsFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import NewDuplicationsFilter from '../NewDuplicationsFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewLinesFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewLinesFilter-test.tsx index f6b78344090..1afeb0dfe50 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewLinesFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewLinesFilter-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import NewLinesFilter from '../NewLinesFilter'; it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewMaintainabilityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewMaintainabilityFilter-test.tsx index fb8474f0a02..e93f0e37abd 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewMaintainabilityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewMaintainabilityFilter-test.tsx @@ -22,7 +22,5 @@ import * as React from 'react'; import NewMaintainabilityFilter from '../NewMaintainabilityFilter'; it('renders', () => { - expect( - shallow() - ).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewReliabilityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewReliabilityFilter-test.tsx index 8ceb711739f..c415d02831a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewReliabilityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewReliabilityFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import NewReliabilityFilter from '../NewReliabilityFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewSecurityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewSecurityFilter-test.tsx index 99bb0d94389..08fce4a26bf 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewSecurityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/NewSecurityFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import NewSecurityFilter from '../NewSecurityFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualifierFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualifierFilter-test.tsx new file mode 100644 index 00000000000..b0797968910 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualifierFilter-test.tsx @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { ComponentQualifier } from '../../../../types/component'; +import Filter from '../Filter'; +import QualifierFilter, { QualifierFilterProps } from '../QualifierFilter'; + +it('renders', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); + + const { renderOption } = wrapper.find(Filter).props(); + expect(renderOption(ComponentQualifier.Application, false)).toMatchSnapshot( + 'renderOption result' + ); +}); + +function shallowRender(props: Partial = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualityGateFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualityGateFilter-test.tsx index 756a3eac786..6ff157649a1 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualityGateFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualityGateFilter-test.tsx @@ -38,5 +38,5 @@ it('should render with warning facet', () => { }); function shallowRender(props: Partial = {}) { - return shallow(); + return shallow(); } diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/ReliabilityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/ReliabilityFilter-test.tsx index 8232d5cb3b5..005e070025e 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/ReliabilityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/ReliabilityFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import ReliabilityFilter from '../ReliabilityFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityFilter-test.tsx index 56f7d0e9915..387a7ba895f 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityFilter-test.tsx @@ -22,5 +22,5 @@ import * as React from 'react'; import SecurityFilter from '../SecurityFilter'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityReviewFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityReviewFilter-test.tsx index ecd7cc0995d..568c522000a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityReviewFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SecurityReviewFilter-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import SecurityReviewFilter from '../SecurityReviewFilter'; it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SizeFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SizeFilter-test.tsx index 37b42810cd8..c7462eb6d63 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SizeFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SizeFilter-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import SizeFilter from '../SizeFilter'; it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); const renderOption = wrapper.prop('renderOption'); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap index 9ce9bc4f614..9c45a22ef8e 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap @@ -22,7 +22,6 @@ exports[`renders 1`] = ` ] } property="coverage" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap index 2c3c409178a..a0c1acb0b3c 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap @@ -22,7 +22,6 @@ exports[`renders 1`] = ` ] } property="duplications" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap index 25be3053bcd..518429562a1 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap @@ -19,7 +19,6 @@ exports[`renders 1`] = ` ] } property="bugs" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap index 250afc75ced..c366f8e6858 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap @@ -53,14 +53,6 @@ exports[`should render the languages facet with the selected languages 1`] = ` ] } property="languages" - query={ - Object { - "languages": Array [ - "java", - "cs", - ], - } - } renderOption={[Function]} value={ Array [ @@ -242,11 +234,6 @@ exports[`should render the languages without the ones in the facet 1`] = ` ] } property="languages" - query={ - Object { - "languages": null, - } - } renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/MaintainabilityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/MaintainabilityFilter-test.tsx.snap index 5a3cec2fbff..74c863bc426 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/MaintainabilityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/MaintainabilityFilter-test.tsx.snap @@ -17,6 +17,5 @@ exports[`renders 1`] = ` name="Maintainability" onQueryChange={[MockFunction]} property="maintainability" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewCoverageFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewCoverageFilter-test.tsx.snap index 11e95aab04c..893586a9cfc 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewCoverageFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewCoverageFilter-test.tsx.snap @@ -5,6 +5,5 @@ exports[`renders 1`] = ` className="leak-facet-box" onQueryChange={[MockFunction]} property="new_coverage" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewDuplicationsFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewDuplicationsFilter-test.tsx.snap index 91a1620bb86..4fce695bb25 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewDuplicationsFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewDuplicationsFilter-test.tsx.snap @@ -5,6 +5,5 @@ exports[`renders 1`] = ` className="leak-facet-box" onQueryChange={[MockFunction]} property="new_duplications" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap index 1f04f9c5073..6d4b91aa8b8 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap @@ -21,7 +21,6 @@ exports[`renders 1`] = ` ] } property="new_lines" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewMaintainabilityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewMaintainabilityFilter-test.tsx.snap index ff717a23c48..aee66f09413 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewMaintainabilityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewMaintainabilityFilter-test.tsx.snap @@ -18,6 +18,5 @@ exports[`renders 1`] = ` name="Maintainability" onQueryChange={[MockFunction]} property="new_maintainability" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewReliabilityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewReliabilityFilter-test.tsx.snap index 33bac4a52fe..c2a1184a792 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewReliabilityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewReliabilityFilter-test.tsx.snap @@ -18,6 +18,5 @@ exports[`renders 1`] = ` name="Reliability" onQueryChange={[MockFunction]} property="new_reliability" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewSecurityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewSecurityFilter-test.tsx.snap index 9c14c735545..ff165f6d2c7 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewSecurityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewSecurityFilter-test.tsx.snap @@ -18,6 +18,5 @@ exports[`renders 1`] = ` name="Security" onQueryChange={[MockFunction]} property="new_security" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap new file mode 100644 index 00000000000..78a419e37a4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` + + } + onQueryChange={[MockFunction]} + options={ + Array [ + "TRK", + "APP", + ] + } + property="qualifier" + renderOption={[Function]} +/> +`; + +exports[`renders: renderOption result 1`] = ` + + + qualifier.APP + +`; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap index 646483a9a19..f886d4bf11d 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap @@ -15,7 +15,6 @@ exports[`renders 1`] = ` ] } property="gate" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/ReliabilityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/ReliabilityFilter-test.tsx.snap index db4d08b6663..355fccc7ef6 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/ReliabilityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/ReliabilityFilter-test.tsx.snap @@ -17,6 +17,5 @@ exports[`renders 1`] = ` name="Reliability" onQueryChange={[MockFunction]} property="reliability" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityFilter-test.tsx.snap index b2fe4443191..9039e7ab671 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityFilter-test.tsx.snap @@ -17,6 +17,5 @@ exports[`renders 1`] = ` name="Security" onQueryChange={[MockFunction]} property="security" - query={Object {}} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap index 1ca6b42af8d..d035ae827e5 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap @@ -30,7 +30,6 @@ exports[`renders 1`] = ` ] } property="security_review" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap index f956104ccb9..a950d21b0d1 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap @@ -20,7 +20,6 @@ exports[`renders 1`] = ` ] } property="size" - query={Object {}} renderOption={[Function]} /> `; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap index 39ca1365278..8c1830ec284 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap @@ -86,14 +86,6 @@ exports[`should render maximum 10 tags in the searchbox results 1`] = ` ] } property="tags" - query={ - Object { - "languages": Array [ - "java", - "ad", - ], - } - } renderOption={[Function]} value={ Array [ @@ -145,14 +137,6 @@ exports[`should render the tags facet with the selected tags 1`] = ` ] } property="tags" - query={ - Object { - "tags": Array [ - "lang", - "sonar", - ], - } - } renderOption={[Function]} value={ Array [ @@ -292,11 +276,6 @@ exports[`should render the tags without the ones in the facet 1`] = ` ] } property="tags" - query={ - Object { - "tags": null, - } - } renderOption={[Function]} /> `; @@ -354,11 +333,6 @@ exports[`should render the tags without the ones in the facet 2`] = ` ] } property="tags" - query={ - Object { - "tags": null, - } - } renderOption={[Function]} /> `; 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 e40e9c9af0c..727ca3439d2 100644 --- a/server/sonar-web/src/main/js/apps/projects/query.ts +++ b/server/sonar-web/src/main/js/apps/projects/query.ts @@ -17,6 +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 { ComponentQualifier } from '../../types/component'; import { VISUALIZATIONS } from './utils'; type Level = 'ERROR' | 'WARN' | 'OK'; @@ -38,6 +39,7 @@ export interface Query { size?: number; new_lines?: number; languages?: string[]; + qualifier?: ComponentQualifier; tags?: string[]; search?: string; sort?: string; @@ -65,6 +67,7 @@ export function parseUrlQuery(urlQuery: T.RawQuery): Query { new_lines: getAsNumericRating(urlQuery['new_lines']), languages: getAsStringArray(urlQuery['languages']), tags: getAsStringArray(urlQuery['tags']), + qualifier: getAsQualifier(urlQuery['qualifier']), search: getAsString(urlQuery['search']), sort: getAsString(urlQuery['sort']), view: getView(urlQuery['view']), @@ -106,7 +109,7 @@ export function convertToFilter(query: Query, isFavorite: boolean): string { 'new_maintainability' ].forEach(property => pushMetricToArray(query, property, conditions, convertIssuesRating)); - ['languages', 'tags'].forEach(property => + ['languages', 'tags', 'qualifier'].forEach(property => pushMetricToArray(query, property, conditions, convertArrayMetric) ); @@ -160,6 +163,10 @@ function getAsStringArray(value: any): string[] | undefined { return value.split(','); } +function getAsQualifier(value: string | undefined): ComponentQualifier | undefined { + return value ? (value as ComponentQualifier) : undefined; +} + function getView(value: any): string | undefined { return typeof value !== 'string' || value === 'overall' ? undefined : value; } @@ -251,7 +258,8 @@ function mapPropertyToMetric(property?: string): string | undefined { gate: 'alert_status', languages: 'languages', tags: 'tags', - search: 'query' + search: 'query', + qualifier: 'qualifier' }; return property && map[property]; } 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 445c5119601..753a9c457d0 100644 --- a/server/sonar-web/src/main/js/apps/projects/utils.ts +++ b/server/sonar-web/src/main/js/apps/projects/utils.ts @@ -166,7 +166,8 @@ export const FACETS = [ 'ncloc', 'alert_status', 'languages', - 'tags' + 'tags', + 'qualifier' ]; export const LEAK_FACETS = [ @@ -179,7 +180,8 @@ export const LEAK_FACETS = [ 'new_lines', 'alert_status', 'languages', - 'tags' + 'tags', + 'qualifier' ]; const REVERSED_FACETS = ['coverage', 'new_coverage']; @@ -333,7 +335,8 @@ const propertyToMetricMap: T.Dict = { gate: 'alert_status', languages: 'languages', tags: 'tags', - search: 'query' + search: 'query', + qualifier: 'qualifier' }; const metricToPropertyMap = invert(propertyToMetricMap); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java index 7874d771e9b..dc1ec5f7179 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java @@ -108,6 +108,7 @@ public class SearchProjectsAction implements ComponentsWsAction { private static final String ANALYSIS_DATE = "analysisDate"; private static final String LEAK_PERIOD_DATE = "leakPeriodDate"; private static final String METRIC_LEAK_PROJECTS_KEY = "leak_projects"; + private static final String HTML_POSSIBLE_VALUES_TEXT = "The possible values are:"; private static final String HTML_UL_START_TAG = "
    "; private static final String HTML_UL_END_TAG = "
"; private static final Set POSSIBLE_FIELDS = newHashSet(ALL, ORGANIZATIONS, ANALYSIS_DATE, LEAK_PERIOD_DATE); @@ -177,7 +178,7 @@ public class SearchProjectsAction implements ComponentsWsAction { HTML_UL_END_TAG + "
" + "To filter on a rating, provide the corresponding metric key (ex: reliability_rating for reliability rating).
" + - "The possible values are:" + + HTML_POSSIBLE_VALUES_TEXT + HTML_UL_START_TAG + "
  • '1' for rating A
  • " + "
  • '2' for rating B
  • " + @@ -186,7 +187,7 @@ public class SearchProjectsAction implements ComponentsWsAction { "
  • '5' for rating E
  • " + HTML_UL_END_TAG + "To filter on a Quality Gate status use the metric key 'alert_status'. Only the '=' operator can be used.
    " + - "The possible values are:" + + HTML_POSSIBLE_VALUES_TEXT + HTML_UL_START_TAG + "
  • 'OK' for Passed
  • " + "
  • 'WARN' for Warning
  • " + @@ -204,7 +205,7 @@ public class SearchProjectsAction implements ComponentsWsAction { "
  • to filter on several tags you must use tag in (offshore, java)
  • " + HTML_UL_END_TAG + "To filter on a qualifier use key 'qualifier'. Only the '=' operator can be used.
    " + - "The possible values are:" + + HTML_POSSIBLE_VALUES_TEXT + HTML_UL_START_TAG + "
  • TRK - for projects
  • " + "
  • APP - for applications
  • " + @@ -301,20 +302,6 @@ public class SearchProjectsAction implements ComponentsWsAction { } } - private void filterQualifiersBasedOnEdition(ProjectMeasuresQuery query) { - Set availableQualifiers = getQualifiersFromEdition(); - Set requestQualifiers = query.getQualifiers().orElse(availableQualifiers); - - Set resolvedQualifiers = requestQualifiers.stream() - .filter(availableQualifiers::contains) - .collect(Collectors.toSet()); - if (!resolvedQualifiers.isEmpty()) { - query.setQualifiers(resolvedQualifiers); - } else { - throw new IllegalArgumentException("Invalid qualifier, available are: " + String.join(",", availableQualifiers)); - } - } - private Set getQualifiersFromEdition() { Optional edition = editionProvider.get(); 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 bb7182ed15e..7697cd50310 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -944,6 +944,7 @@ projects.facets.quality_gate.warning_help=Warning status is deprecated. This fil projects.facets.languages=Languages projects.facets.new_lines=New Lines projects.facets.tags=Tags +projects.facets.qualifier=Type projects.sort.disabled=Disabled because sorting cannot affect the displayed result with the current project selection. projects.sort.analysis_date=by last analysis date (oldest first) projects.sort.-analysis_date=by last analysis date (latest first) -- 2.39.5