mirror of https://github.com/grafana/grafana
Chore: Remove search_srv (#62964)
* Chore: Remove Search Service * use getSortOptions from grafana searcher * wip * fix library panels search testspull/63065/head
parent
f80bf11782
commit
09637caade
@ -1,177 +0,0 @@ |
|||||||
import { clone, keys, sortBy, take, values } from 'lodash'; |
|
||||||
|
|
||||||
import { contextSrv } from 'app/core/services/context_srv'; |
|
||||||
import impressionSrv from 'app/core/services/impression_srv'; |
|
||||||
import store from 'app/core/store'; |
|
||||||
import { SECTION_STORAGE_KEY } from 'app/features/search/constants'; |
|
||||||
import { |
|
||||||
DashboardSection, |
|
||||||
DashboardSearchItemType, |
|
||||||
DashboardSearchItem, |
|
||||||
SearchLayout, |
|
||||||
} from 'app/features/search/types'; |
|
||||||
import { hasFilters } from 'app/features/search/utils'; |
|
||||||
|
|
||||||
import { backendSrv } from './backend_srv'; |
|
||||||
|
|
||||||
interface Sections { |
|
||||||
[key: string]: Partial<DashboardSection>; |
|
||||||
} |
|
||||||
|
|
||||||
/** @deprecated */ |
|
||||||
export class SearchSrv { |
|
||||||
private getRecentDashboards(sections: DashboardSection[] | any) { |
|
||||||
return this.queryForRecentDashboards().then((result: any[]) => { |
|
||||||
if (result.length > 0) { |
|
||||||
sections['recent'] = { |
|
||||||
title: 'Recent', |
|
||||||
icon: 'clock-nine', |
|
||||||
score: -1, |
|
||||||
expanded: store.getBool(`${SECTION_STORAGE_KEY}.recent`, true), |
|
||||||
items: result, |
|
||||||
type: DashboardSearchItemType.DashFolder, |
|
||||||
}; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
private queryForRecentDashboards(): Promise<DashboardSearchItem[]> { |
|
||||||
return new Promise((resolve) => { |
|
||||||
impressionSrv.getDashboardOpened().then((uids) => { |
|
||||||
const dashUIDs: string[] = take(uids, 30); |
|
||||||
if (dashUIDs.length === 0) { |
|
||||||
return resolve([]); |
|
||||||
} |
|
||||||
|
|
||||||
backendSrv.search({ dashboardUIDs: dashUIDs }).then((result) => { |
|
||||||
return resolve( |
|
||||||
dashUIDs |
|
||||||
.map((orderId) => result.find((result) => result.uid === orderId)) |
|
||||||
.filter((hit) => hit && !hit.isStarred) as DashboardSearchItem[] |
|
||||||
); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
private getStarred(sections: DashboardSection): Promise<any> { |
|
||||||
if (!contextSrv.isSignedIn) { |
|
||||||
return Promise.resolve(); |
|
||||||
} |
|
||||||
|
|
||||||
return backendSrv.search({ starred: true, limit: 30 }).then((result) => { |
|
||||||
if (result.length > 0) { |
|
||||||
(sections as any)['starred'] = { |
|
||||||
title: 'Starred', |
|
||||||
icon: 'star', |
|
||||||
score: -2, |
|
||||||
expanded: store.getBool(`${SECTION_STORAGE_KEY}.starred`, true), |
|
||||||
items: result, |
|
||||||
type: DashboardSearchItemType.DashFolder, |
|
||||||
}; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
search(options: any) { |
|
||||||
const sections: any = {}; |
|
||||||
const promises = []; |
|
||||||
const query = clone(options); |
|
||||||
const filters = hasFilters(options) || query.folderIds?.length > 0; |
|
||||||
|
|
||||||
query.folderIds = query.folderIds || []; |
|
||||||
|
|
||||||
if (query.layout === SearchLayout.List) { |
|
||||||
return backendSrv |
|
||||||
.search({ ...query, type: DashboardSearchItemType.DashDB }) |
|
||||||
.then((results) => (results.length ? [{ title: '', items: results }] : [])); |
|
||||||
} |
|
||||||
|
|
||||||
if (!filters) { |
|
||||||
query.folderIds = [0]; |
|
||||||
} |
|
||||||
|
|
||||||
if (!options.skipRecent && !filters) { |
|
||||||
promises.push(this.getRecentDashboards(sections)); |
|
||||||
} |
|
||||||
|
|
||||||
if (!options.skipStarred && !filters) { |
|
||||||
promises.push(this.getStarred(sections)); |
|
||||||
} |
|
||||||
|
|
||||||
promises.push( |
|
||||||
backendSrv.search(query).then((results) => { |
|
||||||
return this.handleSearchResult(sections, results); |
|
||||||
}) |
|
||||||
); |
|
||||||
|
|
||||||
return Promise.all(promises).then(() => { |
|
||||||
return sortBy(values(sections), 'score'); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
private handleSearchResult(sections: Sections, results: DashboardSearchItem[]): any { |
|
||||||
if (results.length === 0) { |
|
||||||
return sections; |
|
||||||
} |
|
||||||
|
|
||||||
// create folder index
|
|
||||||
for (const hit of results) { |
|
||||||
if (hit.type === 'dash-folder') { |
|
||||||
sections[hit.uid!] = { |
|
||||||
uid: hit.uid, |
|
||||||
title: hit.title, |
|
||||||
expanded: false, |
|
||||||
items: [], |
|
||||||
url: hit.url, |
|
||||||
icon: 'folder', |
|
||||||
score: keys(sections).length, |
|
||||||
type: hit.type, |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (const hit of results) { |
|
||||||
if (hit.type === 'dash-folder') { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
let section = sections[hit.folderUid || 0]; |
|
||||||
if (!section) { |
|
||||||
if (hit.folderUid) { |
|
||||||
section = { |
|
||||||
uid: hit.folderUid, |
|
||||||
title: hit.folderTitle, |
|
||||||
url: hit.folderUrl, |
|
||||||
items: [], |
|
||||||
icon: 'folder-open', |
|
||||||
score: keys(sections).length, |
|
||||||
type: DashboardSearchItemType.DashFolder, |
|
||||||
}; |
|
||||||
} else { |
|
||||||
section = { |
|
||||||
uid: '', |
|
||||||
title: 'General', |
|
||||||
items: [], |
|
||||||
icon: 'folder-open', |
|
||||||
score: keys(sections).length, |
|
||||||
type: DashboardSearchItemType.DashFolder, |
|
||||||
}; |
|
||||||
} |
|
||||||
// add section
|
|
||||||
sections[hit.folderUid || 0] = section; |
|
||||||
} |
|
||||||
|
|
||||||
section.expanded = true; |
|
||||||
section.items && section.items.push(hit); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
getDashboardTags() { |
|
||||||
return backendSrv.get('/api/dashboards/tags'); |
|
||||||
} |
|
||||||
|
|
||||||
getSortOptions() { |
|
||||||
return backendSrv.get('/api/search/sorting'); |
|
||||||
} |
|
||||||
} |
|
@ -1,299 +0,0 @@ |
|||||||
import { contextSrv } from 'app/core/services/context_srv'; |
|
||||||
import impressionSrv from 'app/core/services/impression_srv'; |
|
||||||
import { SearchSrv } from 'app/core/services/search_srv'; |
|
||||||
import { DashboardSearchItem } from 'app/features/search/types'; |
|
||||||
|
|
||||||
import { backendSrv } from '../services/backend_srv'; |
|
||||||
|
|
||||||
jest.mock('app/core/store', () => { |
|
||||||
return { |
|
||||||
getBool: jest.fn(), |
|
||||||
set: jest.fn(), |
|
||||||
getObject: jest.fn(), |
|
||||||
}; |
|
||||||
}); |
|
||||||
|
|
||||||
jest.mock('app/core/services/impression_srv', () => { |
|
||||||
return { |
|
||||||
getDashboardOpened: jest.fn, |
|
||||||
}; |
|
||||||
}); |
|
||||||
|
|
||||||
describe('SearchSrv', () => { |
|
||||||
let searchSrv: SearchSrv; |
|
||||||
const searchMock = jest.spyOn(backendSrv, 'search'); // will use the mock in __mocks__
|
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchSrv = new SearchSrv(); |
|
||||||
|
|
||||||
contextSrv.isSignedIn = true; |
|
||||||
impressionSrv.getDashboardOpened = jest.fn().mockResolvedValue([]); |
|
||||||
jest.clearAllMocks(); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('With recent dashboards', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation((options) => { |
|
||||||
if (options.dashboardUIDs) { |
|
||||||
return Promise.resolve([ |
|
||||||
{ uid: 'DSNdW0gVk', title: 'second but first' }, |
|
||||||
{ uid: 'srx16xR4z', title: 'first but second' }, |
|
||||||
] as DashboardSearchItem[]); |
|
||||||
} |
|
||||||
return Promise.resolve([]); |
|
||||||
}); |
|
||||||
|
|
||||||
impressionSrv.getDashboardOpened = jest.fn().mockResolvedValue(['srx16xR4z', 'DSNdW0gVk']); |
|
||||||
|
|
||||||
return searchSrv.search({ query: '' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should include recent dashboards section', () => { |
|
||||||
expect(results[0].title).toBe('Recent'); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should return order decided by impressions store not api', () => { |
|
||||||
expect(results[0].items[0].title).toBe('first but second'); |
|
||||||
expect(results[0].items[1].title).toBe('second but first'); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('and 3 recent dashboards removed in backend', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation((options) => { |
|
||||||
if (options.dashboardUIDs) { |
|
||||||
return Promise.resolve([ |
|
||||||
{ uid: 'DSNdW0gVk', title: 'two' }, |
|
||||||
{ uid: 'srx16xR4z', title: 'one' }, |
|
||||||
] as DashboardSearchItem[]); |
|
||||||
} |
|
||||||
return Promise.resolve([]); |
|
||||||
}); |
|
||||||
|
|
||||||
impressionSrv.getDashboardOpened = jest |
|
||||||
.fn() |
|
||||||
.mockResolvedValue(['Xrx16x4z', 'CSxdW0gYA', 'srx16xR4z', 'DSNdW0gVk', 'xSxdW0gYA']); |
|
||||||
|
|
||||||
return searchSrv.search({ query: '' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should return 2 dashboards', () => { |
|
||||||
expect(results[0].items.length).toBe(2); |
|
||||||
expect(results[0].items[0].uid).toBe('srx16xR4z'); |
|
||||||
expect(results[0].items[1].uid).toBe('DSNdW0gVk'); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('With starred dashboards', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation((options) => { |
|
||||||
if (options.starred) { |
|
||||||
return Promise.resolve([{ uid: '1', title: 'starred' }] as DashboardSearchItem[]); |
|
||||||
} |
|
||||||
return Promise.resolve([]); |
|
||||||
}); |
|
||||||
|
|
||||||
return searchSrv.search({ query: '' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should include starred dashboards section', () => { |
|
||||||
expect(results[0].title).toBe('Starred'); |
|
||||||
expect(results[0].items.length).toBe(1); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('With starred dashboards and recent', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation((options) => { |
|
||||||
if (options.dashboardUIDs) { |
|
||||||
return Promise.resolve([ |
|
||||||
{ uid: 'srx16xR4z', title: 'starred and recent', isStarred: true }, |
|
||||||
{ uid: 'DSNdW0gVk', title: 'recent' }, |
|
||||||
] as DashboardSearchItem[]); |
|
||||||
} |
|
||||||
return Promise.resolve([{ uid: 'srx16xR4z', title: 'starred and recent' }] as DashboardSearchItem[]); |
|
||||||
}); |
|
||||||
|
|
||||||
impressionSrv.getDashboardOpened = jest.fn().mockResolvedValue(['srx16xR4z', 'DSNdW0gVk']); |
|
||||||
return searchSrv.search({ query: '' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should not show starred in recent', () => { |
|
||||||
expect(results[1].title).toBe('Recent'); |
|
||||||
expect(results[1].items[0].title).toBe('recent'); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should show starred', () => { |
|
||||||
expect(results[0].title).toBe('Starred'); |
|
||||||
expect(results[0].items[0].title).toBe('starred and recent'); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('with no query string and dashboards with folders returned', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation( |
|
||||||
jest |
|
||||||
.fn() |
|
||||||
.mockResolvedValueOnce(Promise.resolve([])) |
|
||||||
.mockResolvedValue( |
|
||||||
Promise.resolve([ |
|
||||||
{ |
|
||||||
title: 'folder1', |
|
||||||
type: 'dash-folder', |
|
||||||
uid: 'folder-1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'dash with no folder', |
|
||||||
type: 'dash-db', |
|
||||||
uid: '2', |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'dash in folder1 1', |
|
||||||
type: 'dash-db', |
|
||||||
uid: '3', |
|
||||||
folderUid: 'folder-1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'dash in folder1 2', |
|
||||||
type: 'dash-db', |
|
||||||
uid: '4', |
|
||||||
folderUid: 'folder-1', |
|
||||||
}, |
|
||||||
]) |
|
||||||
) |
|
||||||
); |
|
||||||
|
|
||||||
return searchSrv.search({ query: '' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should create sections for each folder and root', () => { |
|
||||||
expect(results).toHaveLength(2); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should place folders first', () => { |
|
||||||
expect(results[0].title).toBe('folder1'); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('with query string and dashboards with folders returned', () => { |
|
||||||
let results: any; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation( |
|
||||||
jest.fn().mockResolvedValue([ |
|
||||||
{ |
|
||||||
folderUid: 'dash-with-no-folder-uid', |
|
||||||
title: 'dash with no folder', |
|
||||||
type: 'dash-db', |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'dash in folder1 1', |
|
||||||
type: 'dash-db', |
|
||||||
folderUid: 'uid', |
|
||||||
folderTitle: 'folder1', |
|
||||||
folderUrl: '/dashboards/f/uid/folder1', |
|
||||||
}, |
|
||||||
]) |
|
||||||
); |
|
||||||
|
|
||||||
return searchSrv.search({ query: 'search' }).then((res) => { |
|
||||||
results = res; |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should not specify folder ids', () => { |
|
||||||
expect(searchMock.mock.calls[0][0].folderIds).toHaveLength(0); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should group results by folder', () => { |
|
||||||
expect(results).toHaveLength(2); |
|
||||||
expect(results[0].uid).toEqual('dash-with-no-folder-uid'); |
|
||||||
expect(results[1].uid).toEqual('uid'); |
|
||||||
expect(results[1].title).toEqual('folder1'); |
|
||||||
expect(results[1].url).toEqual('/dashboards/f/uid/folder1'); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('with tags', () => { |
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation(jest.fn().mockResolvedValue(Promise.resolve([]))); |
|
||||||
|
|
||||||
return searchSrv.search({ tag: ['atag'] }).then(() => {}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should send tags query to backend search', () => { |
|
||||||
expect(searchMock.mock.calls[0][0].tag).toHaveLength(1); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('with starred', () => { |
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation(jest.fn().mockResolvedValue(Promise.resolve([]))); |
|
||||||
|
|
||||||
return searchSrv.search({ starred: true }).then(() => {}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should send starred query to backend search', () => { |
|
||||||
expect(searchMock.mock.calls[0][0].starred).toEqual(true); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('when skipping recent dashboards', () => { |
|
||||||
let getRecentDashboardsCalled = false; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation(jest.fn().mockResolvedValue(Promise.resolve([]))); |
|
||||||
|
|
||||||
searchSrv['getRecentDashboards'] = () => { |
|
||||||
getRecentDashboardsCalled = true; |
|
||||||
return Promise.resolve(); |
|
||||||
}; |
|
||||||
|
|
||||||
return searchSrv.search({ skipRecent: true }).then(() => {}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should not fetch recent dashboards', () => { |
|
||||||
expect(getRecentDashboardsCalled).toBeFalsy(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('when skipping starred dashboards', () => { |
|
||||||
let getStarredCalled = false; |
|
||||||
|
|
||||||
beforeEach(() => { |
|
||||||
searchMock.mockImplementation(jest.fn().mockResolvedValue(Promise.resolve([]))); |
|
||||||
impressionSrv.getDashboardOpened = jest.fn().mockResolvedValue([]); |
|
||||||
|
|
||||||
searchSrv['getStarred'] = () => { |
|
||||||
getStarredCalled = true; |
|
||||||
return Promise.resolve({}); |
|
||||||
}; |
|
||||||
|
|
||||||
return searchSrv.search({ skipStarred: true }).then(() => {}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should not fetch starred dashboards', () => { |
|
||||||
expect(getStarredCalled).toBeFalsy(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
Loading…
Reference in new issue