mirror of
https://github.com/grafana/grafana.git
synced 2025-01-07 22:53:56 -06:00
d04dce6a37
* Search: add search wrapper * Search: add DashboardSearch.tsx * Search: enable search * Search: update types * Search: useReducer for saving search results * Search: use default query * Search: add toggle custom action * Search: add onQueryChange * Search: debounce search * Search: pas dispatch as a prop * Search: add tag filter * Search: Fix types * Search: revert changes * Search: close overlay on esc * Search: enable tag filtering * Search: clear query * Search: add autofocus to search field * Search: Rename close to closeSearch * Search: Add no results message * Search: Add loading state * Search: Remove Select from Forms namespace * Remove Add selectedIndex * Remove Add getFlattenedSections * Remove Enable selecting items * Search: add hasId * Search: preselect first item * Search: Add utils tests * Search: Fix moving selection down * Search: Add findSelected * Search: Add type to section * Search: Handle Enter key press on item highlight * Search: Move reducer et al. to separate files * Search: Remove redundant render check * Search: Close overlay on Esc and ArrowLeft press * Search: Add close button * Search: Document utils * Search: use Icon for remove icon * Search: Add DashboardSearch.test.tsx * Search: Move test data to a separate file * Search: Finalise DashboardSearch.test.tsx * Add search reducer tests * Search: Add search results loading indicator * Search: Remove inline function * Search: Do not mutate item * Search: Tweak utils * Search: Do not clear query on tag clear * Search: Fix folder:current search * Search: Fix results scroll * Search: Update tests * Search: Close overlay on cog icon click * Add mobile styles for close button * Search: Use CustomScrollbar * Search: Memoize TagList.tsx * Search: Fix type errors * Search: More strictNullChecks fixes * Search: Consistent handler names * Search: Fix search items types in test * Search: Fix merge conflicts * Search: Fix strictNullChecks errors
100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
import { DashboardSection, DashboardSectionItem } from './types';
|
|
import { NO_ID_SECTIONS } from './constants';
|
|
import { parse, SearchParserResult } from 'search-query-parser';
|
|
|
|
/**
|
|
* Check if folder has id. Only Recent and Starred folders are the ones without
|
|
* ids so far, as they are created manually after results are fetched from API.
|
|
* @param str
|
|
*/
|
|
export const hasId = (str: string) => {
|
|
return !NO_ID_SECTIONS.includes(str);
|
|
};
|
|
|
|
/**
|
|
* Return ids for folders concatenated with their items ids, if section is expanded.
|
|
* For items the id format is '{folderId}-{itemId}' to allow mapping them to their folders
|
|
* @param sections
|
|
*/
|
|
export const getFlattenedSections = (sections: DashboardSection[]): string[] => {
|
|
return sections.flatMap(section => {
|
|
const id = hasId(section.title) ? String(section.id) : section.title;
|
|
|
|
if (section.expanded && section.items.length) {
|
|
return [id, ...section.items.map(item => `${id}-${item.id}`)];
|
|
}
|
|
return id;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Since Recent and Starred folders don't have id, title field is used as id
|
|
* @param title - title field of the section
|
|
*/
|
|
export const getLookupField = (title: string) => {
|
|
return hasId(title) ? 'id' : 'title';
|
|
};
|
|
|
|
/**
|
|
* Go through all the folders and items in expanded folders and toggle their selected
|
|
* prop according to currently selected index. Used for item highlighting when navigating
|
|
* the search results list using keyboard arrows
|
|
* @param sections
|
|
* @param selectedId
|
|
*/
|
|
export const markSelected = (sections: DashboardSection[], selectedId: string) => {
|
|
return sections.map((result: DashboardSection) => {
|
|
const lookupField = getLookupField(selectedId);
|
|
result = { ...result, selected: String(result[lookupField]) === selectedId };
|
|
|
|
if (result.expanded && result.items.length) {
|
|
return {
|
|
...result,
|
|
items: result.items.map(item => {
|
|
const [sectionId, itemId] = selectedId.split('-');
|
|
const lookup = getLookupField(sectionId);
|
|
return { ...item, selected: String(item.id) === itemId && String(result[lookup]) === sectionId };
|
|
}),
|
|
};
|
|
}
|
|
return result;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Find items with property 'selected' set true in a list of folders and their items.
|
|
* Does recursive search in the items list.
|
|
* @param sections
|
|
*/
|
|
export const findSelected = (sections: any): DashboardSection | DashboardSectionItem | null => {
|
|
let found = null;
|
|
for (const section of sections) {
|
|
if (section.expanded && section.items.length) {
|
|
found = findSelected(section.items);
|
|
}
|
|
if (section.selected) {
|
|
found = section;
|
|
}
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
// TODO check if there are any use cases where query isn't a string
|
|
export const parseQuery = (query: any) => {
|
|
const parsedQuery = parse(query, {
|
|
keywords: ['folder'],
|
|
});
|
|
|
|
if (typeof parsedQuery === 'string') {
|
|
return {
|
|
text: parsedQuery,
|
|
} as SearchParserResult;
|
|
}
|
|
|
|
return parsedQuery;
|
|
};
|