]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9253 Remember last selected options on projects page (#2184)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Wed, 21 Jun 2017 06:52:42 +0000 (23:52 -0700)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 21 Jun 2017 06:52:42 +0000 (08:52 +0200)
it/it-tests/src/test/java/it/projectSearch/ProjectsPageTest.java
server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
server/sonar-web/src/main/js/apps/projects/utils.js

index a3c9b0f97938a930aceb79746f029d31922cfa4f..f33f5b14b6ae6a457723920087356bcc78080bed 100644 (file)
@@ -33,6 +33,7 @@ import pageobjects.Navigation;
 import pageobjects.projects.ProjectsPage;
 import util.user.UserRule;
 
+import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage;
 import static com.codeborne.selenide.WebDriverRunner.url;
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.newUserWsClient;
@@ -64,6 +65,7 @@ public class ProjectsPageTest {
   public void before() {
     adminUser = userRule.createAdminUser();
     userAdminWsClient = newUserWsClient(ORCHESTRATOR, adminUser, adminUser);
+    clearBrowserLocalStorage();
   }
 
   @Test
index 93754d095410d04e104df9b67bbb114e72193438..746a6fee39ef14643eb8ab51f02da95204e40e0c 100644 (file)
@@ -27,7 +27,7 @@ import PageSidebar from './PageSidebar';
 import VisualizationsContainer from '../visualizations/VisualizationsContainer';
 import { parseUrlQuery } from '../store/utils';
 import { translate } from '../../../helpers/l10n';
-import { SORTING_SWITCH, parseSorting } from '../utils';
+import * as utils from '../utils';
 import '../styles.css';
 
 type Props = {|
@@ -35,7 +35,10 @@ type Props = {|
   location: { pathname: string, query: { [string]: string } },
   fetchProjects: (query: string, isFavorite: boolean, organization?: {}) => Promise<*>,
   organization?: { key: string },
-  router: { push: ({ pathname: string, query?: {} }) => void },
+  router: {
+    push: ({ pathname: string, query?: {} }) => void,
+    replace: ({ pathname: string, query?: {} }) => void
+  },
   currentUser?: { isLoggedIn: boolean }
 |};
 
@@ -48,14 +51,14 @@ export default class AllProjects extends React.PureComponent {
   state: State = { query: {} };
 
   componentDidMount() {
-    this.handleQueryChange();
+    this.handleQueryChange(true);
     const footer = document.getElementById('footer');
     footer && footer.classList.add('search-navigator-footer');
   }
 
   componentDidUpdate(prevProps: Props) {
     if (prevProps.location.query !== this.props.location.query) {
-      this.handleQueryChange();
+      this.handleQueryChange(false);
     }
   }
 
@@ -72,6 +75,20 @@ export default class AllProjects extends React.PureComponent {
 
   isFiltered = () => Object.keys(this.state.query).some(key => this.state.query[key] != null);
 
+  getSavedOptions = () => {
+    const options = {};
+    if (utils.getSort()) {
+      options.sort = utils.getSort();
+    }
+    if (utils.getView()) {
+      options.view = utils.getView();
+    }
+    if (utils.getVisualization()) {
+      options.visualization = utils.getVisualization();
+    }
+    return options;
+  };
+
   handlePerspectiveChange = ({ view, visualization }: { view: string, visualization?: string }) => {
     const query: { view: ?string, visualization: ?string, sort?: ?string } = {
       view: view === 'overall' ? undefined : view,
@@ -80,24 +97,39 @@ export default class AllProjects extends React.PureComponent {
 
     if (this.state.query.view === 'leak' || view === 'leak') {
       if (this.state.query.sort) {
-        const sort = parseSorting(this.state.query.sort);
-        if (SORTING_SWITCH[sort.sortValue]) {
-          query.sort = (sort.sortDesc ? '-' : '') + SORTING_SWITCH[sort.sortValue];
+        const sort = utils.parseSorting(this.state.query.sort);
+        if (utils.SORTING_SWITCH[sort.sortValue]) {
+          query.sort = (sort.sortDesc ? '-' : '') + utils.SORTING_SWITCH[sort.sortValue];
         }
       }
       this.props.router.push({ pathname: this.props.location.pathname, query });
     } else {
       this.updateLocationQuery(query);
     }
+
+    utils.saveSort(query.sort);
+    utils.saveView(query.view);
+    utils.saveVisualization(visualization);
   };
 
-  handleSortChange = (sort: string, desc: boolean) =>
-    this.updateLocationQuery({ sort: (desc ? '-' : '') + sort });
+  handleSortChange = (sort: string, desc: boolean) => {
+    const asString = (desc ? '-' : '') + sort;
+    this.updateLocationQuery({ sort: asString });
+    utils.saveSort(asString);
+  };
 
-  handleQueryChange() {
+  handleQueryChange(initialMount: boolean) {
     const query = parseUrlQuery(this.props.location.query);
-    this.setState({ query });
-    this.props.fetchProjects(query, this.props.isFavorite, this.props.organization);
+    const savedOptions = this.getSavedOptions();
+    const savedOptionsSet = savedOptions.sort || savedOptions.view || savedOptions.visualization;
+
+    // if there is no filter, but there are saved preferences in the localStorage
+    if (initialMount && !this.isFiltered() && savedOptionsSet) {
+      this.props.router.replace({ pathname: this.props.location.pathname, query: savedOptions });
+    } else {
+      this.setState({ query });
+      this.props.fetchProjects(query, this.props.isFavorite, this.props.organization);
+    }
   }
 
   updateLocationQuery = (newQuery: { [string]: ?string }) => {
index 008bdf5cb6ae3fdde438afb4c4cc3f0e547d240f..68b26f1b41cc73c397bc726c0c0792cf60754983 100644 (file)
 // @flow
 import { translate } from '../../helpers/l10n';
 
-const LOCALSTORAGE_KEY = 'sonarqube.projects.default';
-const LOCALSTORAGE_FAVORITE = 'favorite';
-const LOCALSTORAGE_ALL = 'all';
+const DEFAULT_FILTER = 'sonarqube.projects.default';
+const FAVORITE = 'favorite';
+const ALL = 'all';
+
+const VIEW = 'sonarqube.projects.view';
+const VISUALIZATION = 'sonarqube.projects.visualization';
+const SORT = 'sonarqube.projects.sort';
 
 export const isFavoriteSet = (): boolean => {
-  const setting = window.localStorage.getItem(LOCALSTORAGE_KEY);
-  return setting === LOCALSTORAGE_FAVORITE;
+  const setting = window.localStorage.getItem(DEFAULT_FILTER);
+  return setting === FAVORITE;
 };
 
 export const isAllSet = (): boolean => {
-  const setting = window.localStorage.getItem(LOCALSTORAGE_KEY);
-  return setting === LOCALSTORAGE_ALL;
+  const setting = window.localStorage.getItem(DEFAULT_FILTER);
+  return setting === ALL;
 };
 
-const save = (value: string) => {
+const save = (key: string, value: ?string) => {
   try {
-    window.localStorage.setItem(LOCALSTORAGE_KEY, value);
+    if (value) {
+      window.localStorage.setItem(key, value);
+    } else {
+      window.localStorage.removeItem(key);
+    }
   } catch (e) {
     // usually that means the storage is full
     // just do nothing in this case
   }
 };
 
-export const saveAll = () => save(LOCALSTORAGE_ALL);
+export const saveAll = () => save(DEFAULT_FILTER, ALL);
+
+export const saveFavorite = () => save(DEFAULT_FILTER, FAVORITE);
+
+export const saveView = (view: ?string) => save(VIEW, view);
+export const getView = () => window.localStorage.getItem(VIEW);
+
+export const saveVisualization = (visualization: ?string) => save(VISUALIZATION, visualization);
+export const getVisualization = () => window.localStorage.getItem(VISUALIZATION);
 
-export const saveFavorite = () => save(LOCALSTORAGE_FAVORITE);
+export const saveSort = (sort: ?string) => save(SORT, sort);
+export const getSort = () => window.localStorage.getItem(SORT);
 
 export const SORTING_METRICS = [
   { value: 'name' },