From 0396b220a362163d780bfb9a491a00726df61186 Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Tue, 12 May 2020 13:51:00 +0300 Subject: [PATCH] Search: Save folder expanded state (#24496) * Search: Save folder expanded state * Search: Remember expanded state on search close --- public/app/core/services/search_srv.ts | 13 +++---------- .../features/search/components/SectionHeader.tsx | 5 ++++- public/app/features/search/constants.ts | 1 + public/app/features/search/utils.ts | 13 ++++++++++++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/public/app/core/services/search_srv.ts b/public/app/core/services/search_srv.ts index ff9d1f8c5f4..57716413ed7 100644 --- a/public/app/core/services/search_srv.ts +++ b/public/app/core/services/search_srv.ts @@ -4,6 +4,7 @@ import impressionSrv from 'app/core/services/impression_srv'; import store from 'app/core/store'; import { contextSrv } from 'app/core/services/context_srv'; import { hasFilters } from 'app/features/search/utils'; +import { SECTION_STORAGE_KEY } from 'app/features/search/constants'; import { DashboardSection, DashboardSearchItemType, DashboardSearchHit, SearchLayout } from 'app/features/search/types'; import { backendSrv } from './backend_srv'; @@ -12,14 +13,6 @@ interface Sections { } export class SearchSrv { - recentIsOpen: boolean; - starredIsOpen: boolean; - - constructor() { - this.recentIsOpen = store.getBool('search.sections.recent', true); - this.starredIsOpen = store.getBool('search.sections.starred', true); - } - private getRecentDashboards(sections: DashboardSection[] | any) { return this.queryForRecentDashboards().then((result: any[]) => { if (result.length > 0) { @@ -27,7 +20,7 @@ export class SearchSrv { title: 'Recent', icon: 'clock-nine', score: -1, - expanded: this.recentIsOpen, + expanded: store.getBool(`${SECTION_STORAGE_KEY}.recent`, true), items: result, type: DashboardSearchItemType.DashFolder, }; @@ -59,7 +52,7 @@ export class SearchSrv { title: 'Starred', icon: 'star', score: -2, - expanded: this.starredIsOpen, + expanded: store.getBool(`${SECTION_STORAGE_KEY}.starred`, true), items: result, type: DashboardSearchItemType.DashFolder, }; diff --git a/public/app/features/search/components/SectionHeader.tsx b/public/app/features/search/components/SectionHeader.tsx index a2c4e597005..6fda6dd7630 100644 --- a/public/app/features/search/components/SectionHeader.tsx +++ b/public/app/features/search/components/SectionHeader.tsx @@ -1,10 +1,11 @@ import React, { FC, useCallback } from 'react'; import { css, cx } from 'emotion'; +import { useLocalStorage } from 'react-use'; import { GrafanaTheme } from '@grafana/data'; import { Icon, IconButton, Spinner, stylesFactory, useTheme } from '@grafana/ui'; import { DashboardSection, OnToggleChecked } from '../types'; import { SearchCheckbox } from './SearchCheckbox'; -import { getSectionIcon } from '../utils'; +import { getSectionIcon, getSectionStorageKey } from '../utils'; interface SectionHeaderProps { editable?: boolean; @@ -21,8 +22,10 @@ export const SectionHeader: FC = ({ }) => { const theme = useTheme(); const styles = getSectionHeaderStyles(theme, section.selected, editable); + const setSectionExpanded = useLocalStorage(getSectionStorageKey(section.title), true)[1]; const onSectionExpand = () => { + setSectionExpanded(!section.expanded); onSectionClick(section); }; diff --git a/public/app/features/search/constants.ts b/public/app/features/search/constants.ts index 6b076ab6b0d..a1e5dca3f07 100644 --- a/public/app/features/search/constants.ts +++ b/public/app/features/search/constants.ts @@ -3,3 +3,4 @@ export const NO_ID_SECTIONS = ['Recent', 'Starred']; export const SEARCH_ITEM_HEIGHT = 48; export const SEARCH_ITEM_MARGIN = 4; export const DEFAULT_SORT = { label: 'A-Z', value: 'alpha-asc' }; +export const SECTION_STORAGE_KEY = 'search.sections'; diff --git a/public/app/features/search/utils.ts b/public/app/features/search/utils.ts index fb32060ad71..305bddec171 100644 --- a/public/app/features/search/utils.ts +++ b/public/app/features/search/utils.ts @@ -1,7 +1,7 @@ import { parse, SearchParserResult } from 'search-query-parser'; import { IconName } from '@grafana/ui'; import { DashboardQuery, DashboardSection, DashboardSectionItem, SearchAction, UidsToDelete } from './types'; -import { NO_ID_SECTIONS } from './constants'; +import { NO_ID_SECTIONS, SECTION_STORAGE_KEY } from './constants'; import { getDashboardSrv } from '../dashboard/services/DashboardSrv'; /** @@ -217,3 +217,14 @@ export const getSectionIcon = (section: DashboardSection): IconName => { return section.expanded ? 'folder-open' : 'folder'; }; + +/** + * Get storage key for a dashboard folder by its title + * @param title + */ +export const getSectionStorageKey = (title: string) => { + if (!title) { + return ''; + } + return `${SECTION_STORAGE_KEY}.${title.toLowerCase()}`; +};