diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index 171e0e8109e..a39eefcec4b 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -3,7 +3,7 @@ import React, { PureComponent } from 'react'; import { FormLabel, Select } from '@grafana/ui'; import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv'; -import { DashboardSearchHit } from 'app/types'; +import { DashboardSearchHit, DashboardSearchHitType } from 'app/types'; export interface Props { resourceUri: string; @@ -41,6 +41,21 @@ export class SharedPreferences extends PureComponent { async componentDidMount() { const prefs = await this.backendSrv.get(`/api/${this.props.resourceUri}/preferences`); const dashboards = await this.backendSrv.search({ starred: true }); + const defaultDashboardHit: DashboardSearchHit = { + id: 0, + title: 'Default', + tags: [], + type: '' as DashboardSearchHitType, + uid: '', + uri: '', + url: '', + folderId: 0, + folderTitle: '', + folderUid: '', + folderUrl: '', + isStarred: false, + slug: '', + }; if (prefs.homeDashboardId > 0 && !dashboards.find(d => d.id === prefs.homeDashboardId)) { const missing = await this.backendSrv.search({ dashboardIds: [prefs.homeDashboardId] }); @@ -53,7 +68,7 @@ export class SharedPreferences extends PureComponent { homeDashboardId: prefs.homeDashboardId, theme: prefs.theme, timezone: prefs.timezone, - dashboards: [{ id: 0, title: 'Default', tags: [], type: '', uid: '', uri: '', url: '' }, ...dashboards], + dashboards: [defaultDashboardHit, ...dashboards], }); } diff --git a/public/app/core/components/manage_dashboards/manage_dashboards.ts b/public/app/core/components/manage_dashboards/manage_dashboards.ts index 3f6dacd311d..5b5e299b1af 100644 --- a/public/app/core/components/manage_dashboards/manage_dashboards.ts +++ b/public/app/core/components/manage_dashboards/manage_dashboards.ts @@ -11,7 +11,8 @@ export interface Section { id: number; uid: string; title: string; - expanded: false; + expanded: boolean; + removable: boolean; items: any[]; url: string; icon: string; diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index c73cc7661f5..0d7d098dcea 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -3,6 +3,7 @@ import coreModule from 'app/core/core_module'; import appEvents from 'app/core/app_events'; import config from 'app/core/config'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; +import { DashboardSearchHit } from 'app/types/search'; export class BackendSrv { private inFlightRequests = {}; @@ -237,7 +238,7 @@ export class BackendSrv { return this.request({ url: '/api/login/ping', method: 'GET', retry: 1 }); } - search(query) { + search(query): Promise { return this.get('/api/search', query); } diff --git a/public/app/core/services/search_srv.ts b/public/app/core/services/search_srv.ts index 22d33921ebd..068fe3ffbc3 100644 --- a/public/app/core/services/search_srv.ts +++ b/public/app/core/services/search_srv.ts @@ -1,21 +1,32 @@ +// @ts-ignore import _ from 'lodash'; +// @ts-ignore +import { IQService } from 'angular'; + import coreModule from 'app/core/core_module'; import impressionSrv from 'app/core/services/impression_srv'; import store from 'app/core/store'; import { contextSrv } from 'app/core/services/context_srv'; +import { BackendSrv } from './backend_srv'; +import { Section } from '../components/manage_dashboards/manage_dashboards'; +import { DashboardSearchHit } from 'app/types/search'; + +interface Sections { + [key: string]: Partial
; +} export class SearchSrv { recentIsOpen: boolean; starredIsOpen: boolean; /** @ngInject */ - constructor(private backendSrv, private $q) { + constructor(private backendSrv: BackendSrv, private $q: IQService) { this.recentIsOpen = store.getBool('search.sections.recent', true); this.starredIsOpen = store.getBool('search.sections.starred', true); } - private getRecentDashboards(sections) { - return this.queryForRecentDashboards().then(result => { + private getRecentDashboards(sections: Sections) { + return this.queryForRecentDashboards().then((result: any[]) => { if (result.length > 0) { sections['recent'] = { title: 'Recent', @@ -30,8 +41,8 @@ export class SearchSrv { }); } - private queryForRecentDashboards() { - const dashIds = _.take(impressionSrv.getDashboardOpened(), 30); + private queryForRecentDashboards(): Promise { + const dashIds: number[] = _.take(impressionSrv.getDashboardOpened(), 30); if (dashIds.length === 0) { return Promise.resolve([]); } @@ -45,7 +56,7 @@ export class SearchSrv { }); } - private toggleRecent(section) { + private toggleRecent(section: Section) { this.recentIsOpen = section.expanded = !section.expanded; store.set('search.sections.recent', this.recentIsOpen); @@ -59,13 +70,13 @@ export class SearchSrv { }); } - private toggleStarred(section) { + private toggleStarred(section: Section) { this.starredIsOpen = section.expanded = !section.expanded; store.set('search.sections.starred', this.starredIsOpen); return Promise.resolve(section); } - private getStarred(sections) { + private getStarred(sections: Sections) { if (!contextSrv.isSignedIn) { return Promise.resolve(); } @@ -84,7 +95,7 @@ export class SearchSrv { }); } - search(options) { + search(options: any) { const sections: any = {}; const promises = []; const query = _.clone(options); @@ -118,7 +129,7 @@ export class SearchSrv { }); } - private handleSearchResult(sections, results) { + private handleSearchResult(sections: Sections, results: DashboardSearchHit[]): any { if (results.length === 0) { return sections; } @@ -177,7 +188,7 @@ export class SearchSrv { } } - private toggleFolder(section) { + private toggleFolder(section: Section) { section.expanded = !section.expanded; section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder'; diff --git a/public/app/core/specs/manage_dashboards.test.ts b/public/app/core/specs/manage_dashboards.test.ts index ef5e240fd36..5e94d26ea89 100644 --- a/public/app/core/specs/manage_dashboards.test.ts +++ b/public/app/core/specs/manage_dashboards.test.ts @@ -16,6 +16,7 @@ const mockSection = (overides?: object): Section => { items: [], checked: false, expanded: false, + removable: false, hideHeader: false, icon: '', score: 0, diff --git a/public/app/core/specs/search_srv.test.ts b/public/app/core/specs/search_srv.test.ts index 550d11bbf9e..6566224c613 100644 --- a/public/app/core/specs/search_srv.test.ts +++ b/public/app/core/specs/search_srv.test.ts @@ -1,8 +1,12 @@ +// @ts-ignore +import { IQService } from 'angular'; + import { SearchSrv } from 'app/core/services/search_srv'; import { BackendSrvMock } from 'test/mocks/backend_srv'; import impressionSrv from 'app/core/services/impression_srv'; import { contextSrv } from 'app/core/services/context_srv'; import { beforeEach } from 'test/lib/common'; +import { BackendSrv } from '../services/backend_srv'; jest.mock('app/core/store', () => { return { @@ -18,18 +22,18 @@ jest.mock('app/core/services/impression_srv', () => { }); describe('SearchSrv', () => { - let searchSrv, backendSrvMock; + let searchSrv: SearchSrv, backendSrvMock: BackendSrvMock; beforeEach(() => { backendSrvMock = new BackendSrvMock(); - searchSrv = new SearchSrv(backendSrvMock, Promise); + searchSrv = new SearchSrv(backendSrvMock as BackendSrv, (Promise as any) as IQService); contextSrv.isSignedIn = true; impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]); }); describe('With recent dashboards', () => { - let results; + let results: any; beforeEach(() => { backendSrvMock.search = jest @@ -56,7 +60,7 @@ describe('SearchSrv', () => { }); describe('and 3 recent dashboards removed in backend', () => { - let results; + let results: any; beforeEach(() => { backendSrvMock.search = jest @@ -80,7 +84,7 @@ describe('SearchSrv', () => { }); describe('With starred dashboards', () => { - let results; + let results: any; beforeEach(() => { backendSrvMock.search = jest.fn().mockReturnValue(Promise.resolve([{ id: 1, title: 'starred' }])); @@ -97,7 +101,7 @@ describe('SearchSrv', () => { }); describe('With starred dashboards and recent', () => { - let results; + let results: any; beforeEach(() => { backendSrvMock.search = jest @@ -125,7 +129,7 @@ describe('SearchSrv', () => { }); describe('with no query string and dashboards with folders returned', () => { - let results; + let results: any; beforeEach(() => { backendSrvMock.search = jest @@ -173,12 +177,10 @@ describe('SearchSrv', () => { }); describe('with query string and dashboards with folders returned', () => { - let results; + let results: any; beforeEach(() => { - backendSrvMock.search = jest.fn(); - - backendSrvMock.search.mockReturnValue( + backendSrvMock.search = jest.fn().mockReturnValue( Promise.resolve([ { id: 2, @@ -249,8 +251,9 @@ describe('SearchSrv', () => { backendSrvMock.search = jest.fn(); backendSrvMock.search.mockReturnValue(Promise.resolve([])); - searchSrv.getRecentDashboards = () => { + searchSrv['getRecentDashboards'] = () => { getRecentDashboardsCalled = true; + return Promise.resolve(); }; return searchSrv.search({ skipRecent: true }).then(() => {}); @@ -269,8 +272,9 @@ describe('SearchSrv', () => { backendSrvMock.search.mockReturnValue(Promise.resolve([])); impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]); - searchSrv.getStarred = () => { + searchSrv['getStarred'] = () => { getStarredCalled = true; + return Promise.resolve(); }; return searchSrv.search({ skipStarred: true }).then(() => {}); diff --git a/public/app/types/search.ts b/public/app/types/search.ts index e5e17288de1..e15797f41a3 100644 --- a/public/app/types/search.ts +++ b/public/app/types/search.ts @@ -1,9 +1,20 @@ +export enum DashboardSearchHitType { + DashHitDB = 'dash-db', + DashHitHome = 'dash-home', + DashHitFolder = 'dash-folder', +} export interface DashboardSearchHit { id: number; - tags: string[]; - title: string; - type: string; uid: string; + title: string; uri: string; url: string; + slug: string; + type: DashboardSearchHitType; + tags: string[]; + isStarred: boolean; + folderId: number; + folderUid: string; + folderTitle: string; + folderUrl: string; }