EVOLUTION-MANAGER
Edit File: search.ts
import _, { debounce } from 'lodash'; import coreModule from '../../core_module'; import { SearchSrv } from 'app/core/services/search_srv'; import { contextSrv } from 'app/core/services/context_srv'; import appEvents from 'app/core/app_events'; import { parse, SearchParserOptions, SearchParserResult } from 'search-query-parser'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { CoreEvents } from 'app/types'; export interface SearchQuery { query: string; parsedQuery: SearchParserResult; tags: string[]; starred: boolean; } class SearchQueryParser { config: SearchParserOptions; constructor(config: SearchParserOptions) { this.config = config; } parse(query: string) { const parsedQuery = parse(query, this.config); if (typeof parsedQuery === 'string') { return { text: parsedQuery, } as SearchParserResult; } return parsedQuery; } } interface SelectedIndicies { dashboardIndex?: number; folderIndex?: number; } interface OpenSearchParams { query?: string; } export class SearchCtrl { isOpen: boolean; query: SearchQuery; giveSearchFocus: boolean; selectedIndex: number; results: any; currentSearchId: number; showImport: boolean; dismiss: any; ignoreClose: any; isLoading: boolean; initialFolderFilterTitle: string; isEditor: string; hasEditPermissionInFolders: boolean; queryParser: SearchQueryParser; /** @ngInject */ constructor(private $scope: any, private $location: any, private $timeout: any, private searchSrv: SearchSrv) { appEvents.on(CoreEvents.showDashSearch, this.openSearch.bind(this), $scope); appEvents.on(CoreEvents.hideDashSearch, this.closeSearch.bind(this), $scope); appEvents.on(CoreEvents.searchQuery, debounce(this.search.bind(this), 500), $scope); this.initialFolderFilterTitle = 'All'; this.isEditor = contextSrv.isEditor; this.hasEditPermissionInFolders = contextSrv.hasEditPermissionInFolders; this.onQueryChange = this.onQueryChange.bind(this); this.onKeyDown = this.onKeyDown.bind(this); this.query = { query: '', parsedQuery: { text: '' }, tags: [], starred: false, }; this.queryParser = new SearchQueryParser({ keywords: ['folder'], }); } closeSearch() { this.isOpen = this.ignoreClose; } onQueryChange(query: SearchQuery | string) { if (typeof query === 'string') { this.query = { ...this.query, parsedQuery: this.queryParser.parse(query), query: query, }; } else { this.query = query; } appEvents.emit(CoreEvents.searchQuery); } openSearch(payload: OpenSearchParams = {}) { if (this.isOpen) { this.closeSearch(); return; } this.isOpen = true; this.giveSearchFocus = true; this.selectedIndex = -1; this.results = []; this.query = { query: payload.query ? `${payload.query} ` : '', parsedQuery: this.queryParser.parse(payload.query), tags: [], starred: false, }; this.currentSearchId = 0; this.ignoreClose = true; this.isLoading = true; this.$timeout(() => { this.ignoreClose = false; this.giveSearchFocus = true; this.search(); }, 100); } onKeyDown(evt: KeyboardEvent) { if (evt.keyCode === 27) { this.closeSearch(); } if (evt.keyCode === 40) { this.moveSelection(1); } if (evt.keyCode === 38) { this.moveSelection(-1); } if (evt.keyCode === 13) { const flattenedResult = this.getFlattenedResultForNavigation(); const currentItem = flattenedResult[this.selectedIndex]; if (currentItem) { if (currentItem.dashboardIndex !== undefined) { const selectedDash = this.results[currentItem.folderIndex].items[currentItem.dashboardIndex]; if (selectedDash) { this.$location.search({}); this.$location.path(selectedDash.url); this.closeSearch(); } } else { const selectedFolder = this.results[currentItem.folderIndex]; if (selectedFolder) { selectedFolder.toggle(selectedFolder); } } } } } onFilterboxClick() { this.giveSearchFocus = false; this.preventClose(); } preventClose() { this.ignoreClose = true; this.$timeout(() => { this.ignoreClose = false; }, 100); } moveSelection(direction: number) { if (this.results.length === 0) { return; } const flattenedResult = this.getFlattenedResultForNavigation(); const currentItem = flattenedResult[this.selectedIndex]; if (currentItem) { if (currentItem.dashboardIndex !== undefined) { this.results[currentItem.folderIndex].items[currentItem.dashboardIndex].selected = false; } else { this.results[currentItem.folderIndex].selected = false; } } if (direction === 0) { this.selectedIndex = -1; return; } const max = flattenedResult.length; const newIndex = (this.selectedIndex + direction) % max; this.selectedIndex = newIndex < 0 ? newIndex + max : newIndex; const selectedItem = flattenedResult[this.selectedIndex]; if (selectedItem.dashboardIndex === undefined && this.results[selectedItem.folderIndex].id === 0) { this.moveSelection(direction); return; } if (selectedItem.dashboardIndex !== undefined) { if (!this.results[selectedItem.folderIndex].expanded) { this.moveSelection(direction); return; } this.results[selectedItem.folderIndex].items[selectedItem.dashboardIndex].selected = true; return; } if (this.results[selectedItem.folderIndex].hideHeader) { this.moveSelection(direction); return; } this.results[selectedItem.folderIndex].selected = true; } searchDashboards(folderContext?: string) { this.currentSearchId = this.currentSearchId + 1; const localSearchId = this.currentSearchId; const folderIds = []; const { parsedQuery } = this.query; if (folderContext === 'current') { folderIds.push(getDashboardSrv().getCurrent().meta.folderId); } const query = { ...this.query, query: parsedQuery.text, tag: this.query.tags, folderIds, }; return this.searchSrv .search({ ...query, }) .then(results => { if (localSearchId < this.currentSearchId) { return; } this.results = results || []; this.isLoading = false; this.moveSelection(1); this.$scope.$digest(); }); } queryHasNoFilters() { const query = this.query; return query.query === '' && query.starred === false && query.tags.length === 0; } filterByTag(tag: string) { if (_.indexOf(this.query.tags, tag) === -1) { this.query.tags.push(tag); this.search(); } } removeTag(tag: string, evt: any) { this.query.tags = _.without(this.query.tags, tag); this.search(); this.giveSearchFocus = true; evt.stopPropagation(); evt.preventDefault(); } getTags = () => { return this.searchSrv.getDashboardTags(); }; onTagFiltersChanged = (tags: string[]) => { this.query.tags = tags; this.search(); }; clearSearchFilter() { this.query.query = ''; this.query.tags = []; this.search(); } showStarred() { this.query.starred = !this.query.starred; this.giveSearchFocus = true; this.search(); } search() { this.showImport = false; this.selectedIndex = -1; this.searchDashboards(this.query.parsedQuery['folder']); } folderExpanding() { this.moveSelection(0); } private getFlattenedResultForNavigation(): SelectedIndicies[] { let folderIndex = 0; return _.flatMap(this.results, (s: any) => { let result: SelectedIndicies[] = []; result.push({ folderIndex: folderIndex, }); let dashboardIndex = 0; result = result.concat( _.map(s.items || [], i => { return { folderIndex: folderIndex, dashboardIndex: dashboardIndex++, }; }) ); folderIndex++; return result; }); } } export function searchDirective() { return { restrict: 'E', templateUrl: 'public/app/core/components/search/search.html', controller: SearchCtrl, bindToController: true, controllerAs: 'ctrl', scope: {}, }; } coreModule.directive('dashboardSearch', searchDirective);