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