From: Stas Vilchik Date: Thu, 9 Mar 2017 16:31:40 +0000 (+0100) Subject: SONAR-8452 open the last state of projects page (#1760) X-Git-Tag: 6.4-RC1~790 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=64256992734c3e8184db370f42797e34ddc6339d;p=sonarqube.git SONAR-8452 open the last state of projects page (#1760) --- diff --git a/it/it-tests/src/test/java/it/projectSearch/ProjectsPageTest.java b/it/it-tests/src/test/java/it/projectSearch/ProjectsPageTest.java index c2eb20d497c..70c9f708f4a 100644 --- a/it/it-tests/src/test/java/it/projectSearch/ProjectsPageTest.java +++ b/it/it-tests/src/test/java/it/projectSearch/ProjectsPageTest.java @@ -78,4 +78,27 @@ public class ProjectsPageTest { page.shouldHaveTotal(1); } + @Test + public void should_open_default_page() { + // default page can be "All Projects" or "Favorite Projects" depending on your last choice + ProjectsPage page = nav.openProjects(); + + // all projects for anonymous user + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + + // all projects by default for logged in user + page = nav.logIn().asAdmin().openProjects(); + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + + // select favorite + page.selectFavoriteProjects(); + page = nav.openProjects(); + page.shouldHaveTotal(0).shouldDisplayFavoriteProjects(); + + // select all + page.selectAllProjects(); + page = nav.openProjects(); + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + } + } diff --git a/it/it-tests/src/test/java/it/uiExtension/UiExtensionsTest.java b/it/it-tests/src/test/java/it/uiExtension/UiExtensionsTest.java index 2e7e2aa20ce..867f8d75afe 100644 --- a/it/it-tests/src/test/java/it/uiExtension/UiExtensionsTest.java +++ b/it/it-tests/src/test/java/it/uiExtension/UiExtensionsTest.java @@ -81,9 +81,8 @@ public class UiExtensionsTest { @Test public void project_page() { - nav.open("/projects"); + nav.open("/dashboard?id=sample"); - $(By.linkText("Sample")).click(); $("#component-navigation-more").click(); $(By.linkText("Project Page")).click(); @@ -93,9 +92,8 @@ public class UiExtensionsTest { @Test public void project_admin_page() { - nav.logIn().asAdmin().open("/projects"); + nav.logIn().asAdmin().open("/dashboard?id=sample"); - $(By.linkText("Sample")).click(); $("#component-navigation-admin").click(); $(By.linkText("Project Admin Page")).click(); diff --git a/it/it-tests/src/test/java/pageobjects/projects/ProjectsPage.java b/it/it-tests/src/test/java/pageobjects/projects/ProjectsPage.java index ac7aa737957..0cc1b638a11 100644 --- a/it/it-tests/src/test/java/pageobjects/projects/ProjectsPage.java +++ b/it/it-tests/src/test/java/pageobjects/projects/ProjectsPage.java @@ -27,6 +27,8 @@ import static com.codeborne.selenide.Condition.text; import static com.codeborne.selenide.Condition.visible; import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; +import static com.codeborne.selenide.WebDriverRunner.url; +import static org.assertj.core.api.Assertions.assertThat; public class ProjectsPage { @@ -57,4 +59,24 @@ public class ProjectsPage { $("#projects-total").shouldHave(text(String.valueOf(total))); return this; } + + public ProjectsPage shouldDisplayAllProjects() { + assertThat(url()).endsWith("/projects"); + return this; + } + + public ProjectsPage shouldDisplayFavoriteProjects() { + assertThat(url()).endsWith("/projects/favorite"); + return this; + } + + public ProjectsPage selectAllProjects() { + $("#all-projects").click(); + return shouldDisplayAllProjects(); + } + + public ProjectsPage selectFavoriteProjects() { + $("#favorite-projects").click(); + return shouldDisplayFavoriteProjects(); + } } diff --git a/it/it-tests/src/test/resources/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html b/it/it-tests/src/test/resources/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html index 653ec010e23..9345f6e3f75 100644 --- a/it/it-tests/src/test/resources/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html +++ b/it/it-tests/src/test/resources/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html @@ -43,21 +43,6 @@ css=.js-user-authenticated - - open - /projects - - - - waitForText - css=.page-header - *1 projects* - - - assertTextPresent - Sample - - open /project/deletion?id=sample @@ -90,18 +75,13 @@ open - /projects + /dashboard?id=sample - waitForText - css=.page-header - *0 projects* - - - assertTextNotPresent - content - *Sample* + waitForElementPresent + css=.process-spinner-failed + diff --git a/server/sonar-web/src/main/js/app/components/Landing.js b/server/sonar-web/src/main/js/app/components/Landing.js index 2204c53b829..7b4ba1721dc 100644 --- a/server/sonar-web/src/main/js/app/components/Landing.js +++ b/server/sonar-web/src/main/js/app/components/Landing.js @@ -31,7 +31,7 @@ class Landing extends React.Component { componentDidMount () { const { currentUser, router } = this.props; if (currentUser.isLoggedIn) { - router.replace('/projects/favorite'); + router.replace('/projects'); } else { router.replace('/about'); } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js index bb099b964c1..a1f73443ea2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js @@ -40,7 +40,7 @@ class GlobalNavBranding extends React.Component { } render () { - const homeController = this.props.currentUser.isLoggedIn ? '/projects/favorite' : '/about'; + const homeController = this.props.currentUser.isLoggedIn ? '/projects' : '/about'; const homeLinkClassName = 'navbar-brand' + (this.props.customLogoUrl ? ' navbar-brand-custom' : ''); return (
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 3c3272a339c..3693e493fcf 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 @@ -38,10 +38,9 @@ export default class GlobalNavMenu extends React.Component { } renderProjects () { - const pathname = this.props.currentUser.isLoggedIn ? '/projects/favorite' : '/projects'; return (
  • - + {translate('projects.page')}
  • diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap index f212db31949..2f2dc6dd0f3 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap @@ -6,11 +6,7 @@ exports[`test should work with extensions 1`] = ` activeClassName="active" onlyActiveOnIndex={false} style={Object {}} - to={ - Object { - "pathname": "/projects", - } - }> + to="/projects"> projects.page diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.js index d80c910db60..1b71ee0f02d 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.js @@ -49,7 +49,10 @@ class OrganizationProjects extends React.Component {
    - +
    ); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js index f7fbe17c899..b4d8d44a06c 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js @@ -22,6 +22,7 @@ import ProjectsListContainer from './ProjectsListContainer'; import ProjectsListFooterContainer from './ProjectsListFooterContainer'; import PageSidebar from './PageSidebar'; import { parseUrlQuery } from '../store/utils'; +import { saveAll, saveFavorite } from '../utils'; export default class AllProjects extends React.Component { static propTypes = { @@ -35,6 +36,14 @@ export default class AllProjects extends React.Component { }; componentDidMount () { + // do not touch organization-level page + if (!this.props.organization) { + if (this.props.isFavorite) { + saveFavorite(); + } else { + saveAll(); + } + } this.handleQueryChange(); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js index 1230fca10d3..52398e9b340 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js @@ -20,14 +20,5 @@ import { connect } from 'react-redux'; import AllProjects from './AllProjects'; import { fetchProjects } from '../store/actions'; -import { getCurrentUser } from '../../../store/rootReducer'; -const mapStateToProps = state => ({ - user: getCurrentUser(state), - isFavorite: false -}); - -export default connect( - mapStateToProps, - { fetchProjects } -)(AllProjects); +export default connect(null, { fetchProjects })(AllProjects); diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.js b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.js new file mode 100644 index 00000000000..eb487b5eb56 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.js @@ -0,0 +1,59 @@ +/* + * 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 { connect } from 'react-redux'; +import { withRouter } from 'react-router'; +import AllProjectsContainer from './AllProjectsContainer'; +import { getCurrentUser } from '../../../store/rootReducer'; +import { shouldRedirectToFavorite } from '../utils'; + +class DefaultPageSelector extends React.PureComponent { + props: { + currentUser: { isLoggedIn: boolean }, + location: {}, + router: { replace: (path: string) => void } + }; + + componentDidMount () { + if (shouldRedirectToFavorite(this.props.currentUser)) { + this.props.router.replace('/projects/favorite'); + } + } + + render () { + if (shouldRedirectToFavorite(this.props.currentUser)) { + return null; + } else { + return ( + + ); + } + } +} + +const mapStateToProps = state => ({ + currentUser: getCurrentUser(state) +}); + +export default connect(mapStateToProps)(withRouter(DefaultPageSelector)); diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js index 5bc0311bb23..ebf2305ab13 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js @@ -20,6 +20,7 @@ import React from 'react'; import { IndexLink, Link } from 'react-router'; import { translate } from '../../../helpers/l10n'; +import { saveAll } from '../utils'; export default class FavoriteFilter extends React.Component { render () { @@ -27,25 +28,34 @@ export default class FavoriteFilter extends React.Component { return null; } - const pathnameForFavorite = this.props.organization ? - `/organizations/${this.props.organization.key}/projects/favorite` : - '/projects/favorite'; + const pathnameForFavorite = this.props.organization + ? `/organizations/${this.props.organization.key}/projects/favorite` + : '/projects/favorite'; - const pathnameForAll = this.props.organization ? - `/organizations/${this.props.organization.key}/projects` : - '/projects'; + const pathnameForAll = this.props.organization + ? `/organizations/${this.props.organization.key}/projects` + : '/projects'; return ( -
    -
    - - {translate('my_favorites')} - - - {translate('all')} - -
    +
    +
    + + {translate('my_favorites')} + + + {translate('all')} +
    +
    ); } } diff --git a/server/sonar-web/src/main/js/apps/projects/routes.js b/server/sonar-web/src/main/js/apps/projects/routes.js index 4da139e7ad0..4ed8f72a50a 100644 --- a/server/sonar-web/src/main/js/apps/projects/routes.js +++ b/server/sonar-web/src/main/js/apps/projects/routes.js @@ -20,12 +20,12 @@ import React from 'react'; import { Route, IndexRoute } from 'react-router'; import App from './components/App'; -import AllProjectsContainer from './components/AllProjectsContainer'; +import DefaultPageSelector from './components/DefaultPageSelector'; import FavoriteProjectsContainer from './components/FavoriteProjectsContainer'; export default ( - - - - + + + + ); diff --git a/server/sonar-web/src/main/js/apps/projects/utils.js b/server/sonar-web/src/main/js/apps/projects/utils.js new file mode 100644 index 00000000000..598a8cf73c4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/utils.js @@ -0,0 +1,45 @@ +/* + * 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 +const LOCALSTORAGE_KEY = 'sonarqube.projects.default'; +const LOCALSTORAGE_FAVORITE = 'favorite'; +const LOCALSTORAGE_ALL = 'all'; + +const isFavoriteSet = (): boolean => { + const setting = window.localStorage.getItem(LOCALSTORAGE_KEY); + return setting === LOCALSTORAGE_FAVORITE; +}; + +export const shouldRedirectToFavorite = (currentUser: { isLoggedIn: boolean }) => { + return currentUser.isLoggedIn && isFavoriteSet(); +}; + +const save = (value: string) => { + try { + window.localStorage.setItem(LOCALSTORAGE_KEY, value); + } catch (e) { + // usually that means the storage is full + // just do nothing in this case + } +}; + +export const saveAll = () => save(LOCALSTORAGE_ALL); + +export const saveFavorite = () => save(LOCALSTORAGE_FAVORITE);