From: Stas Vilchik Date: Tue, 28 Nov 2017 13:32:23 +0000 (+0100) Subject: SONAR-10081 Add Explore space for SonarCloud X-Git-Tag: 7.0-RC1~167 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5038ceecaa7a09b8cf87e7d9f2f27c22e363187d;p=sonarqube.git SONAR-10081 Add Explore space for SonarCloud --- diff --git a/server/sonar-web/src/main/js/app/components/Landing.js b/server/sonar-web/src/main/js/app/components/Landing.js deleted file mode 100644 index f5851ac0a66..00000000000 --- a/server/sonar-web/src/main/js/app/components/Landing.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// @flow -import React from 'react'; -import PropTypes from 'prop-types'; -import { withRouter } from 'react-router'; -import { connect } from 'react-redux'; -import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; - -class Landing extends React.PureComponent { - static propTypes = { - currentUser: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]).isRequired - }; - - componentDidMount() { - const { currentUser, router, onSonarCloud } = this.props; - if (currentUser.isLoggedIn) { - router.replace('/projects'); - } else if (onSonarCloud && onSonarCloud.value === 'true') { - window.location = 'https://about.sonarcloud.io'; - } else { - router.replace('/about'); - } - } - - render() { - return null; - } -} - -const mapStateToProps = state => ({ - currentUser: getCurrentUser(state), - onSonarCloud: getGlobalSettingValue(state, 'sonar.sonarcloud.enabled') -}); - -export default connect(mapStateToProps)(withRouter(Landing)); diff --git a/server/sonar-web/src/main/js/app/components/Landing.tsx b/server/sonar-web/src/main/js/app/components/Landing.tsx new file mode 100644 index 00000000000..792826f1091 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/Landing.tsx @@ -0,0 +1,60 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import * as PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; +import { CurrentUser, isLoggedIn } from '../types'; + +interface Props { + currentUser: CurrentUser; + onSonarCloud: boolean; +} + +class Landing extends React.PureComponent { + static contextTypes = { + router: PropTypes.object.isRequired + }; + + componentDidMount() { + const { currentUser, onSonarCloud } = this.props; + if (isLoggedIn(currentUser)) { + this.context.router.replace('/projects'); + } else if (onSonarCloud) { + window.location.href = 'https://about.sonarcloud.io'; + } else { + this.context.router.replace('/about'); + } + } + + render() { + return null; + } +} + +const mapStateToProps = (state: any) => { + const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); + return { + currentUser: getCurrentUser(state), + onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true') + }; +}; + +export default connect(mapStateToProps)(Landing); diff --git a/server/sonar-web/src/main/js/app/components/help/GlobalHelp.js b/server/sonar-web/src/main/js/app/components/help/GlobalHelp.js index e6c60c0e8bf..a4ec0a4c324 100644 --- a/server/sonar-web/src/main/js/app/components/help/GlobalHelp.js +++ b/server/sonar-web/src/main/js/app/components/help/GlobalHelp.js @@ -32,7 +32,7 @@ type Props = { currentUser: { isLoggedIn: boolean }, onClose: () => void, onTutorialSelect: () => void, - sonarCloud?: boolean + onSonarCloud?: boolean }; */ @@ -62,7 +62,7 @@ export default class GlobalHelp extends React.PureComponent { case 'shortcuts': return ; case 'links': - return this.props.sonarCloud ? ( + return this.props.onSonarCloud ? ( ) : ( diff --git a/server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js b/server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js index 772448f1c3d..571b34fdc0a 100644 --- a/server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js +++ b/server/sonar-web/src/main/js/app/components/help/__tests__/GlobalHelp-test.js @@ -58,7 +58,7 @@ it('display special links page for SonarCloud', () => { currentUser={{ isLoggedIn: false }} onClose={jest.fn()} onTutorialSelect={jest.fn()} - sonarCloud={true} + onSonarCloud={true} /> ); clickOnSection(wrapper, 'links'); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js index 0284617f18a..8823ecd0533 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js @@ -22,6 +22,7 @@ import React from 'react'; import { connect } from 'react-redux'; import GlobalNavBranding from './GlobalNavBranding'; import GlobalNavMenu from './GlobalNavMenu'; +import GlobalNavExplore from './GlobalNavExplore'; import GlobalNavUserContainer from './GlobalNavUserContainer'; import Search from '../../search/Search'; import GlobalHelp from '../../help/GlobalHelp'; @@ -38,8 +39,9 @@ import './GlobalNav.css'; type Props = { appState: { organizationsEnabled: boolean }, currentUser: { isLoggedIn: boolean, showOnboardingTutorial: boolean }, + location: { pathname: string }, skipOnboarding: () => void, - sonarCloud: boolean + onSonarCloud: boolean }; */ @@ -129,12 +131,14 @@ class GlobalNav extends React.PureComponent { + + {this.state.helpOpen && ( )} @@ -152,7 +156,7 @@ const mapStateToProps = state => { return { currentUser: getCurrentUser(state), appState: getAppState(state), - sonarCloud: sonarCloudSetting != null && sonarCloudSetting.value === 'true' + onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true') }; }; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx new file mode 100644 index 00000000000..ea1495c0e1c --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact 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 { Link } from 'react-router'; +import { translate } from '../../../../helpers/l10n'; + +interface Props { + location: { pathname: string }; + onSonarCloud: boolean; +} + +export default function GlobalNavExplore({ location, onSonarCloud }: Props) { + if (!onSonarCloud) { + return null; + } + + const active = location.pathname.startsWith('explore'); + + return ( +
    +
  • + + {translate('explore')} + +
  • +
+ ); +} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js index 27702bf87f7..7cea4c635b2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js @@ -20,6 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; +import { isLoggedIn } from '../../../../app/types'; import { translate } from '../../../../helpers/l10n'; import { getQualityGatesUrl } from '../../../../helpers/urls'; import { isMySet } from '../../../../apps/issues/utils'; @@ -31,7 +32,7 @@ export default class GlobalNavMenu extends React.PureComponent { location: PropTypes.shape({ pathname: PropTypes.string.isRequired }).isRequired, - sonarCloud: PropTypes.bool + onSonarCloud: PropTypes.bool }; static defaultProps = { @@ -44,10 +45,14 @@ export default class GlobalNavMenu extends React.PureComponent { } renderProjects() { + if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) { + return null; + } + return (
  • - {this.props.sonarCloud ? translate('my_projects') : translate('projects.page')} + {this.props.onSonarCloud ? translate('my_projects') : translate('projects.page')}
  • ); @@ -64,9 +69,13 @@ export default class GlobalNavMenu extends React.PureComponent { } renderIssuesLink() { + if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) { + return null; + } + const active = this.props.location.pathname === 'issues'; - if (this.props.sonarCloud) { + if (this.props.onSonarCloud) { return (
  • { + + + + + +
    +

    {translate('explore')}

    +
    + + +
  • + + {translate('projects.page')} + +
  • +
  • + + {translate('issues.page')} + +
  • + + + + {props.children} + + ); +} diff --git a/server/sonar-web/src/main/js/apps/explore/ExploreIssues.tsx b/server/sonar-web/src/main/js/apps/explore/ExploreIssues.tsx new file mode 100644 index 00000000000..9e8b31ef93c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/explore/ExploreIssues.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact 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 AppContainer from '../issues/components/AppContainer'; +import { RawQuery } from '../../helpers/query'; + +interface Props { + location: { pathname: string; query: RawQuery }; +} + +export default function ExploreIssues(props: Props) { + return ; +} diff --git a/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx b/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx new file mode 100644 index 00000000000..c490e7d4d0c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact 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 AllProjectsContainer from '../projects/components/AllProjectsContainer'; +import { RawQuery } from '../../helpers/query'; + +interface Props { + location: { pathname: string; query: RawQuery }; +} + +export default function ExploreProjects(props: Props) { + return ; +} diff --git a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx index 4ff236be004..4208187fe97 100644 --- a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx @@ -22,15 +22,20 @@ import { connect } from 'react-redux'; import AppContainer from './components/AppContainer'; import { CurrentUser, isLoggedIn } from '../../app/types'; import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; +import { RawQuery } from '../../helpers/query'; interface StateProps { currentUser: CurrentUser; onSonarCloud: boolean; } -function IssuesPage({ currentUser, onSonarCloud, ...props }: StateProps) { +interface Props extends StateProps { + location: { pathname: string; query: RawQuery }; +} + +function IssuesPage({ currentUser, location, onSonarCloud }: Props) { const myIssues = (isLoggedIn(currentUser) && onSonarCloud) || undefined; - return ; + return ; } const stateToProps = (state: any) => { diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.js b/server/sonar-web/src/main/js/apps/issues/components/App.js index 46cb1d23952..a7121ced22d 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/App.js +++ b/server/sonar-web/src/main/js/apps/issues/components/App.js @@ -31,6 +31,7 @@ import IssuesList from './IssuesList'; import ComponentBreadcrumbs from './ComponentBreadcrumbs'; import IssuesSourceViewer from './IssuesSourceViewer'; import BulkChangeModal from './BulkChangeModal'; +import NoMyIssues from './NoMyIssues'; import ConciseIssuesList from '../conciseIssuesList/ConciseIssuesList'; import ConciseIssuesListHeader from '../conciseIssuesList/ConciseIssuesListHeader'; import * as actions from '../actions'; @@ -868,7 +869,8 @@ export default class App extends React.PureComponent { )} - {paging.total === 0 && } + {paging.total === 0 && + (this.state.myIssues && !this.isFiltered() ? : )} ); } diff --git a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx index 7747e8aa148..5bcb4a8f4e9 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx @@ -88,6 +88,7 @@ interface DispatchProps { const mapDispatchToProps = { fetchIssues: fetchIssues as any } as DispatchProps; interface OwnProps { + location: { pathname: string; query: RawQuery }; myIssues?: boolean; } diff --git a/server/sonar-web/src/main/js/apps/issues/components/NoMyIssues.tsx b/server/sonar-web/src/main/js/apps/issues/components/NoMyIssues.tsx new file mode 100644 index 00000000000..a16a1f5fe6f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/components/NoMyIssues.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { translate } from '../../../helpers/l10n'; +import '../../../components/common/EmptySearch.css'; + +export default function NoMyIssues() { + return ( +
    +

    {translate('issues.no_my_issues')}

    +
    + ); +} 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 fb4e108e3db..daa3ffa6fa4 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 @@ -20,12 +20,14 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import Helmet from 'react-helmet'; +import { omitBy } from 'lodash'; import PageHeader from './PageHeader'; import ProjectsList from './ProjectsList'; import PageSidebar from './PageSidebar'; import Visualizations from '../visualizations/Visualizations'; import { CurrentUser, isLoggedIn } from '../../../app/types'; import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication'; +import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; import ListFooter from '../../../components/controls/ListFooter'; import { translate } from '../../../helpers/l10n'; import * as storage from '../../../helpers/storage'; @@ -38,7 +40,7 @@ import { parseUrlQuery, Query } from '../query'; export interface Props { currentUser: CurrentUser; isFavorite: boolean; - location: { pathname: string; query: { [x: string]: string } }; + location: { pathname: string; query: RawQuery }; onSonarCloud: boolean; organization?: { key: string }; organizationsEnabled: boolean; @@ -224,35 +226,35 @@ export default class AllProjects extends React.PureComponent { } updateLocationQuery = (newQuery: RawQuery) => { - this.context.router.push({ - pathname: this.props.location.pathname, - query: { - ...this.props.location.query, - ...newQuery - } - }); + const query = omitBy({ ...this.props.location.query, ...newQuery }, x => !x); + this.context.router.push({ pathname: this.props.location.pathname, query }); + }; + + handleClearAll = () => { + this.context.router.push({ pathname: this.props.location.pathname }); }; renderSide = () => ( -
    -
    -
    -
    - + + {({ top }) => ( +
    +
    +
    + +
    -
    -
    + )} + ); renderHeader = () => ( @@ -261,9 +263,9 @@ export default class AllProjects extends React.PureComponent {
    { cardType={this.getView()} isFavorite={this.props.isFavorite} isFiltered={this.isFiltered()} + onSonarCloud={this.props.onSonarCloud} organization={this.props.organization} projects={this.state.projects} query={this.state.query} @@ -319,7 +322,7 @@ export default class AllProjects extends React.PureComponent { {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 5eb37454226..93b794181e0 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 @@ -25,6 +25,7 @@ import { areThereCustomOrganizations, getGlobalSettingValue } from '../../../store/rootReducer'; +import { RawQuery } from '../../../helpers/query'; interface StateProps { currentUser: CurrentUser; @@ -32,6 +33,12 @@ interface StateProps { organizationsEnabled: boolean; } +interface OwnProps { + isFavorite: boolean; + location: { pathname: string; query: RawQuery }; + organization?: { key: string }; +} + const stateToProps = (state: any) => { const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); return { @@ -41,4 +48,6 @@ const stateToProps = (state: any) => { }; }; -export default connect(stateToProps)(lazyLoad(() => import('./AllProjects'))); +export default connect(stateToProps)( + lazyLoad(() => import('./AllProjects')) +); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx b/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx new file mode 100644 index 00000000000..0a449dc36a7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact 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'; + +interface Props { + onClearAll: () => void; +} + +export default class ClearAll extends React.PureComponent { + handleClick = (event: React.SyntheticEvent) => { + event.preventDefault(); + event.currentTarget.blur(); + this.props.onClearAll(); + }; + + render() { + return ( +
    + +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx index 56d148f82b2..80061b3335f 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx @@ -46,6 +46,10 @@ export default class DefaultPageSelector extends React.PureComponent; } const { shouldBeRedirected, shouldForceSorting } = this.state; - if (shouldBeRedirected == null || shouldBeRedirected === true || shouldForceSorting != null) { - return null; - } else { + + if ( + shouldBeRedirected !== undefined && + shouldBeRedirected !== true && + shouldForceSorting === undefined + ) { return ; } + + return null; } } diff --git a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx index effc6ad0dbb..b562b7d46bf 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx @@ -21,13 +21,17 @@ import * as React from 'react'; import { Link } from 'react-router'; import { translate } from '../../../helpers/l10n'; -export default function NoFavoriteProjects() { +interface Props { + onSonarCloud: boolean; +} + +export default function NoFavoriteProjects({ onSonarCloud }: Props) { return (

    {translate('projects.no_favorite_projects')}

    {translate('projects.no_favorite_projects.engagement')}

    - + {translate('projects.explore_projects')}

    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 8b401d2a627..d8de26017fe 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 @@ -30,9 +30,9 @@ import { Project } from '../types'; interface Props { currentUser: CurrentUser; - isFavorite?: boolean; loading: boolean; onPerspectiveChange: (x: { view: string; visualization?: string }) => void; + onQueryChange: (change: RawQuery) => void; onSortChange: (sort: string, desc: boolean) => void; organization?: { key: string }; projects?: Project[]; @@ -80,7 +80,7 @@ export default function PageHeader(props: Props) { )} 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 52315fbefa5..19c51033dac 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 @@ -18,9 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { Link } from 'react-router'; import { flatMap } from 'lodash'; import FavoriteFilterContainer from './FavoriteFilterContainer'; +import ClearAll from './ClearAll'; import LanguagesFilterContainer from '../filters/LanguagesFilterContainer'; import CoverageFilter from '../filters/CoverageFilter'; import DuplicationsFilter from '../filters/DuplicationsFilter'; @@ -42,7 +42,8 @@ import { Facets } from '../types'; interface Props { facets?: Facets; - isFavorite: boolean; + onClearAll: () => void; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: RawQuery; showFavoriteFilter: boolean; @@ -51,15 +52,13 @@ interface Props { } export default function PageSidebar(props: Props) { - const { facets, query, isFavorite, organization, view, visualization } = props; + const { facets, onQueryChange, query, organization, view, visualization } = props; const isFiltered = Object.keys(query) .filter(key => !['view', 'visualization', 'sort'].includes(key)) .some(key => query[key] != null); const isLeakView = view === 'leak'; - const basePathName = organization ? `/organizations/${organization.key}/projects` : '/projects'; - const pathname = basePathName + (isFavorite ? '/favorite' : ''); const maxFacetValue = getMaxFacetValue(facets); - const facetProps = { isFavorite, maxFacetValue, organization, query }; + const facetProps = { onQueryChange, maxFacetValue, organization, query }; let linkQuery: RawQuery | undefined = undefined; if (view !== 'overall') { @@ -77,13 +76,7 @@ export default function PageSidebar(props: Props) { )}
    - {isFiltered && ( -
    - - {translate('clear_all_filters')} - -
    - )} + {isFiltered && }

    {translate('filters')}

    diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx index 21101667187..10800381384 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx @@ -30,6 +30,7 @@ interface Props { cardType?: string; isFavorite: boolean; isFiltered: boolean; + onSonarCloud: boolean; organization?: { key: string }; projects: Project[]; query: Query; @@ -41,7 +42,11 @@ export default class ProjectsList extends React.PureComponent { if (isFiltered) { return isFavorite ? : ; } - return isFavorite ? : ; + return isFavorite ? ( + + ) : ( + + ); } render() { diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx new file mode 100644 index 00000000000..ea4686356d6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import ClearAll from '../ClearAll'; +import { click } from '../../../../helpers/testUtils'; + +it('renders', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('clears all', () => { + const onClearAll = jest.fn(); + const wrapper = shallow(); + click(wrapper.find('button')); + expect(onClearAll).toBeCalled(); +}); diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx index a11013b31d7..3635c476f77 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx @@ -22,5 +22,5 @@ import { shallow } from 'enzyme'; import NoFavoriteProjects from '../NoFavoriteProjects'; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); 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 279297daf13..ec11f741410 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 @@ -73,6 +73,7 @@ function shallowRender(props?: {}) { currentUser={{ isLoggedIn: false }} loading={false} onPerspectiveChange={jest.fn()} + onQueryChange={jest.fn()} onSortChange={jest.fn()} projects={[]} query={{ search: 'test' }} 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 e19492bd40e..70b54d55d9e 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,7 +24,8 @@ import PageSidebar from '../PageSidebar'; it('should render correctly', () => { const sidebar = shallow( { it('should render `leak` view correctly', () => { const sidebar = shallow( { it('reset function should work correctly with view and visualizations', () => { const sidebar = shallow( ); - expect(sidebar.find('.projects-facets-reset').exists()).toBeFalsy(); + expect(sidebar.find('ClearAll').exists()).toBeFalsy(); sidebar.setProps({ query: { size: '3' } }); - expect(sidebar.find('.projects-facets-reset')).toMatchSnapshot(); + expect(sidebar.find('ClearAll').exists()).toBeTruthy(); }); 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 14e6af9b4e5..40a5ea5b647 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 @@ -10,58 +10,11 @@ exports[`renders 1`] = ` encodeSpecialCharacters={true} title="projects.page" /> -
    -
    -
    -
    - -
    -
    -
    -
    + />
    -
    -
    -
    -
    - -
    -
    -
    -
    + />
    + +
    +`; 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 71fc671f68d..75cede0fa15 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 @@ -17,6 +17,7 @@ exports[`should render correctly 1`] = ` view="overall" /> - - clear_all_filters - -
    -`; - exports[`should render \`leak\` view correctly 1`] = `
    -
    - - clear_all_filters - -
    +

    filters

    void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -43,13 +44,13 @@ export default function CoverageFilter(props: Props) { void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -45,13 +46,13 @@ export default function DuplicationsFilter(props: Props) { void; options: Option[]; query: { [x: string]: any }; renderOption: (option: Option, isSelected: boolean) => React.ReactNode; @@ -38,7 +38,6 @@ interface Props { facet?: Facet; maxFacetValue?: number; optionClassName?: string; - isFavorite?: boolean; organization?: { key: string }; getFacetValueForOption?: (facet: Facet, option: Option) => void; @@ -54,7 +53,7 @@ interface Props { export default class Filter extends React.PureComponent { isSelected(option: Option): boolean { const { value } = this.props; - return Array.isArray(value) ? value.includes(option) : option === value; + return Array.isArray(value) ? value.includes(option) : String(option) === String(value); } highlightUnder(option?: Option): boolean { @@ -66,23 +65,28 @@ export default class Filter extends React.PureComponent { ); } - blurOnClick = (event: React.SyntheticEvent) => event.currentTarget.blur(); + handleClick = (event: React.SyntheticEvent) => { + event.preventDefault(); + event.currentTarget.blur(); - getPath(option: Option) { const { property, value } = this.props; + const { key: option } = event.currentTarget.dataset; let urlOption; - if (Array.isArray(value)) { - if (this.isSelected(option)) { - urlOption = value.length > 1 ? value.filter(val => val !== option).join(',') : null; + if (option) { + if (Array.isArray(value)) { + if (this.isSelected(option)) { + urlOption = value.length > 1 ? value.filter(val => val !== option).join(',') : null; + } else { + urlOption = value.concat(option).join(','); + } } else { - urlOption = value.concat(option).join(','); + urlOption = this.isSelected(option) ? null : option; } - } else { - urlOption = this.isSelected(option) ? null : option; + + this.props.onQueryChange({ [property]: urlOption }); } - return getFilterUrl(this.props, { [property]: urlOption }); - } + }; renderOptionBar(facetValue: number | undefined) { if (facetValue === undefined || !this.props.maxFacetValue) { @@ -111,7 +115,6 @@ export default class Filter extends React.PureComponent { this.props.optionClassName ); - const path = this.getPath(option); const facetValue = facet && getFacetValueForOption ? getFacetValueForOption(facet, option) : undefined; @@ -122,12 +125,7 @@ export default class Filter extends React.PureComponent { option > value; return ( - + {this.props.renderOption(option, this.isSelected(option) || isUnderSelectedOption)} @@ -137,7 +135,7 @@ export default class Filter extends React.PureComponent { {this.renderOptionBar(facetValue)} )} - + ); } 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 65539aae09c..47574759b73 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 @@ -23,14 +23,15 @@ import FilterHeader from './FilterHeader'; import Rating from '../../../components/ui/Rating'; import { translate } from '../../../helpers/l10n'; import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; facet?: Facet; headerDetail?: React.ReactNode; - isFavorite?: boolean; maxFacetValue?: number; name: string; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; property: string; query: { [x: string]: any }; @@ -42,13 +43,13 @@ export default function IssuesFilter(props: Props) { void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -68,6 +69,7 @@ export default class LanguagesFilter extends React.Component { return ( { value={this.props.value} facet={this.props.facet} maxFacetValue={this.props.maxFacetValue} - isFavorite={this.props.isFavorite} organization={this.props.organization} getFacetValueForOption={this.getFacetValueForOption} header={} footer={ void; organization?: { key: string }; query: { [x: string]: any }; 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 74d688c564d..56072d54b0d 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 @@ -23,12 +23,13 @@ import FilterHeader from './FilterHeader'; import { translate } from '../../../helpers/l10n'; import { getSizeRatingLabel } from '../../../helpers/ratings'; import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; export interface Props { className?: string; facet?: Facet; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -42,13 +43,13 @@ export default function NewLinesFilter(props: Props) { void; organization?: { key: string }; query: { [x: string]: any }; 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 23eb35a733d..3cb8daecb4c 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 @@ -22,12 +22,13 @@ import BugIcon from '../../../components/icons-components/BugIcon'; import IssuesFilter from './IssuesFilter'; import { translate } from '../../../helpers/l10n'; import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; facet?: Facet; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: { [x: string]: any }; 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 8f09c50130d..36361b66104 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 @@ -22,12 +22,13 @@ import VulnerabilityIcon from '../../../components/icons-components/Vulnerabilit import IssuesFilter from './IssuesFilter'; import { translate } from '../../../helpers/l10n'; import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; facet?: Facet; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: { [x: string]: any }; value?: any; 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 2daf2eb1755..1425153c90b 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 @@ -20,15 +20,16 @@ import * as React from 'react'; import Filter from './Filter'; import FilterHeader from './FilterHeader'; +import { Facet } from '../types'; import Level from '../../../components/ui/Level'; import { translate } from '../../../helpers/l10n'; -import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; export interface Props { className?: string; facet?: Facet; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: { [x: string]: any }; value?: any; @@ -39,12 +40,12 @@ export default function QualityGateFilter(props: Props) { } 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 56f71586862..9917b32817d 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 @@ -22,13 +22,14 @@ import IssuesFilter from './IssuesFilter'; import { Facet } from '../types'; import BugIcon from '../../../components/icons-components/BugIcon'; import { translate } from '../../../helpers/l10n'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; facet?: Facet; headerDetail?: React.ReactNode; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: { [x: string]: any }; value?: any; diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SearchFilterContainer.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SearchFilterContainer.tsx index 4934f7ecaf3..62083ec97a9 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SearchFilterContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SearchFilterContainer.tsx @@ -18,26 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; -import { getFilterUrl } from './utils'; import SearchBox from '../../../components/controls/SearchBox'; import { translate } from '../../../helpers/l10n'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; query: { search?: string }; - isFavorite?: boolean; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; } export default class SearchFilterContainer extends React.PureComponent { - static contextTypes = { - router: PropTypes.object.isRequired - }; - handleSearch = (userQuery?: string) => { - const path = getFilterUrl(this.props, { search: userQuery }); - this.context.router.push(path); + this.props.onQueryChange({ search: userQuery }); }; render() { diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx index c23ca53c3d3..aa09177baba 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; -import { getFilterUrl } from './utils'; import Select from '../../../components/controls/Select'; import { translate } from '../../../helpers/l10n'; +import { RawQuery } from '../../../helpers/query'; interface Props { + onQueryChange: (change: RawQuery) => void; property: string; query: { [x: string]: any }; options: Array<{ label: string; value: string }>; @@ -35,14 +35,9 @@ interface Props { } export default class SearchableFilterFooter extends React.PureComponent { - static contextTypes = { - router: PropTypes.object.isRequired - }; - handleOptionChange = ({ value }: { value: string }) => { const urlOptions = (this.props.query[this.props.property] || []).concat(value).join(','); - const path = getFilterUrl(this.props, { [this.props.property]: urlOptions }); - this.context.router.push(path); + this.props.onQueryChange({ [this.props.property]: urlOptions }); }; render() { 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 4fbad543cf2..f2a93c4ebd8 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 @@ -22,13 +22,14 @@ import IssuesFilter from './IssuesFilter'; import { Facet } from '../types'; import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon'; import { translate } from '../../../helpers/l10n'; +import { RawQuery } from '../../../helpers/query'; interface Props { className?: string; facet?: Facet; headerDetail?: React.ReactNode; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; query: { [x: string]: any }; value?: any; 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 ebf98c8bd87..dc16b3110cc 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 @@ -24,12 +24,13 @@ import SizeRating from '../../../components/ui/SizeRating'; import { translate } from '../../../helpers/l10n'; import { getSizeRatingLabel, getSizeRatingAverageValue } from '../../../helpers/ratings'; import { Facet } from '../types'; +import { RawQuery } from '../../../helpers/query'; export interface Props { className?: string; facet?: Facet; - isFavorite?: boolean; maxFacetValue?: number; + onQueryChange: (change: RawQuery) => void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -43,13 +44,13 @@ export default function SizeFilter(props: Props) { void; organization?: { key: string }; property?: string; query: { [x: string]: any }; @@ -101,6 +102,7 @@ export default class TagsFilter extends React.PureComponent { return ( { value={this.props.value} facet={this.props.facet} maxFacetValue={this.props.maxFacetValue} - isFavorite={this.props.isFavorite} organization={this.props.organization} getFacetValueForOption={this.getFacetValueForOption} header={} footer={ { - 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 2a4588325dc..b036bf91fde 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 { shallow } from 'enzyme'; 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 51c9f5b2b52..d37b5616519 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 @@ -63,6 +63,7 @@ it('renders facet bar chart', () => { function shallowRender(props?: any) { return shallow( { - 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__/LanguagesFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/LanguagesFilter-test.tsx index ff0bf4f8b37..d09423c8217 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/LanguagesFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/LanguagesFilter-test.tsx @@ -34,7 +34,12 @@ const languagesFacet = { java: 39, cs: 4, js: 1 }; it('should render the languages without the ones in the facet', () => { const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); }); @@ -43,8 +48,8 @@ it('should render the languages facet with the selected languages', () => { const wrapper = shallow( @@ -69,8 +74,8 @@ it('should render maximum 10 languages in the searchbox results', () => { const wrapper = shallow( 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 59add14532b..98b867073eb 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 { shallow } from 'enzyme'; 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 69f0855f75e..13426af67d1 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 { shallow } from 'enzyme'; 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 9420d8257be..8fe45022162 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 { shallow } from 'enzyme'; 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 5760a50b122..a60432019f3 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 { shallow } from 'enzyme'; 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 9dc78541994..26bf9cdb24f 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,5 +22,7 @@ import { shallow } from 'enzyme'; 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 2f97df9e72e..b1cb4f189de 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 { shallow } from 'enzyme'; 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 a3771637e92..39c7b886a39 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 { shallow } from 'enzyme'; 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__/QualityGateFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/QualityGateFilter-test.tsx index 02316f2426b..d9c8607f804 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 @@ -22,7 +22,7 @@ import { shallow } from 'enzyme'; import QualityGateFilter from '../QualityGateFilter'; 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__/ReliabilityFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/ReliabilityFilter-test.tsx index 8ca23ed4f50..6dafe35b73d 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 { shallow } from 'enzyme'; 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__/SearchFilterContainer-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchFilterContainer-test.tsx index 3154a9488fd..99d18dbd0d2 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchFilterContainer-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchFilterContainer-test.tsx @@ -22,9 +22,11 @@ import { shallow } from 'enzyme'; import SearchFilterContainer from '../SearchFilterContainer'; it('searches', () => { - const push = jest.fn(); - const wrapper = shallow(, { context: { router: { push } } }); + const onQueryChange = jest.fn(); + const wrapper = shallow(, { + context: { router: { push: jest.fn() } } + }); expect(wrapper).toMatchSnapshot(); wrapper.find('SearchBox').prop('onChange')('foo'); - expect(push).toBeCalledWith({ pathname: '/projects', query: { search: 'foo' } }); + expect(onQueryChange).toBeCalledWith({ search: 'foo' }); }); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx index 2d12621ec21..5f5aee87e1f 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx @@ -30,6 +30,7 @@ const options = [ it('should render items without the ones in the facet', () => { const wrapper = shallow( { }); it('should render items without the ones in the facet', () => { - const push = jest.fn(); + const onQueryChange = jest.fn(); const wrapper = shallow( , - { context: { router: { push } } } + { context: { router: { push: jest.fn() } } } ); (wrapper.find('Select').prop('onChange') as Function)({ value: 'js' }); - expect(push).toBeCalledWith({ - pathname: '/projects', - query: { languages: 'java,js' } - }); + expect(onQueryChange).toBeCalledWith({ languages: 'java,js' }); }); 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 05c83d65c41..1daf55d766f 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 { shallow } from 'enzyme'; 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__/SizeFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SizeFilter-test.tsx index 486594f766d..ee5c83349bb 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 { shallow } from 'enzyme'; 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__/TagsFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/TagsFilter-test.tsx index bfc0790d00c..af3c0fcfe1a 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/TagsFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/TagsFilter-test.tsx @@ -25,7 +25,9 @@ const tags = ['lang', 'sonar', 'csharp', 'dotnet', 'it', 'net']; const tagsFacet = { lang: 4, sonar: 3, csharp: 1 }; it('should render the tags without the ones in the facet', () => { - const wrapper = shallow(); + const wrapper = shallow( + + ); expect(wrapper).toMatchSnapshot(); wrapper.setState({ tags }); expect(wrapper).toMatchSnapshot(); @@ -34,10 +36,10 @@ it('should render the tags without the ones in the facet', () => { it('should render the tags facet with the selected tags', () => { const wrapper = shallow( ); expect(wrapper).toMatchSnapshot(); @@ -47,10 +49,10 @@ it('should render the tags facet with the selected tags', () => { it('should render maximum 10 tags in the searchbox results', () => { const wrapper = shallow( ); wrapper.setState({ tags: [...tags, 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai'] }); 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 da8e061961c..49e49f3c84c 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 @@ -10,6 +10,7 @@ exports[`renders 1`] = ` } highlightUnder={1} highlightUnderMax={5} + onQueryChange={[Function]} options={ Array [ 1, 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 86606f59ac7..f70e42fab8f 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 @@ -10,6 +10,7 @@ exports[`renders 1`] = ` } highlightUnder={1} highlightUnderMax={5} + onQueryChange={[Function]} options={ Array [ 1, diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap index 3c6f588c192..d0d09c08b8c 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap @@ -8,75 +8,48 @@ exports[`highlights under 1`] = `
    - 1 - +
    - 2 - - + 3 - +
    @@ -90,73 +63,48 @@ exports[`hightlights under selected 1`] = `
    - 1 - +
    - 2 - - + 3 - +
    @@ -170,72 +118,45 @@ exports[`renders 1`] = `
    `; @@ -248,21 +169,12 @@ exports[`renders facet bar chart 1`] = `
    -
    - - +
    - - +
    - +
    `; @@ -378,72 +272,45 @@ exports[`renders header and footer 1`] = `