Search v2: encode query in url (#47078)

This commit is contained in:
Nathan Marrs
2022-03-30 13:00:40 -07:00
committed by GitHub
parent abeb08bc98
commit 85286a5182
3 changed files with 43 additions and 16 deletions
+18 -8
View File
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { Input, useStyles2, Spinner } from '@grafana/ui';
import { config } from '@grafana/runtime';
@@ -11,6 +11,7 @@ import { getGrafanaSearcher, QueryFilters } from '../service';
import { Table } from './table/Table';
import { TagFilter, TermCount } from 'app/core/components/TagFilter/TagFilter';
import { getTermCounts } from '../service/backend';
import { useSearchQuery } from '../hooks/useSearchQuery';
const node: NavModelItem = {
id: 'search',
@@ -21,15 +22,16 @@ const node: NavModelItem = {
export default function SearchPage() {
const styles = useStyles2(getStyles);
const [query, setQuery] = useState('');
const [tags, setTags] = useState<string[]>([]);
const { query, onQueryChange, onTagFilterChange } = useSearchQuery({});
const results = useAsync(() => {
const { query: searchQuery, tag: tags } = query;
const filters: QueryFilters = {
tags,
};
return getGrafanaSearcher().search(query, tags.length ? filters : undefined);
}, [query, tags]);
return getGrafanaSearcher().search(searchQuery, tags.length ? filters : undefined);
}, [query]);
if (!config.featureToggles.panelTitleSearch) {
return <div className={styles.unsupported}>Unsupported</div>;
@@ -44,20 +46,28 @@ export default function SearchPage() {
return Promise.resolve([]);
};
const onSearchQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onQueryChange(event.currentTarget.value);
};
const onTagChange = (tags: string[]) => {
onTagFilterChange(tags);
};
return (
<Page navModel={{ node: node, main: node }}>
<Page.Contents>
<Input value={query} onChange={(e) => setQuery(e.currentTarget.value)} autoFocus spellCheck={false} />
<Input value={query.query} onChange={onSearchQueryChange} autoFocus spellCheck={false} />
<br />
{results.loading && <Spinner />}
{results.value?.body && (
<div>
<TagFilter isClearable tags={tags} tagOptions={getTagOptions} onChange={setTags} /> <br />
<TagFilter isClearable tags={query.tag} tagOptions={getTagOptions} onChange={onTagChange} /> <br />
<AutoSizer style={{ width: '100%', height: '2000px' }}>
{({ width }) => {
return (
<>
<Table data={results.value!.body} width={width} />
<Table data={results.value!.body} width={width} tags={query.tag} onTagFilterChange={onTagChange} />
</>
);
}}
@@ -13,6 +13,8 @@ import { generateColumns } from './columns';
type Props = {
data: DataFrame;
width: number;
tags: string[];
onTagFilterChange: (tags: string[]) => void;
};
export type TableColumn = Column & {
@@ -34,7 +36,7 @@ export interface FieldAccess {
datasource: DataSourceRef[];
}
export const Table = ({ data, width }: Props) => {
export const Table = ({ data, width, tags, onTagFilterChange }: Props) => {
const styles = useStyles2(getStyles);
const tableStyles = useStyles2(getTableStyles);
@@ -52,8 +54,8 @@ export const Table = ({ data, width }: Props) => {
const access = useMemo(() => new DataFrameView<FieldAccess>(data), [data]);
const memoizedColumns = useMemo(() => {
const isDashboardList = data.meta?.type === DataFrameType.DirectoryListing;
return generateColumns(access, isDashboardList, width, styles);
}, [data.meta?.type, access, width, styles]);
return generateColumns(access, isDashboardList, width, styles, tags, onTagFilterChange);
}, [data.meta?.type, access, width, styles, tags, onTagFilterChange]);
const options: TableOptions<{}> = useMemo(
() => ({
@@ -75,7 +77,7 @@ export const Table = ({ data, width }: Props) => {
return (
<div {...row.getRowProps({ style })} className={styles.rowContainer}>
{row.cells.map((cell: Cell, index: number) => {
if (cell.column.id === 'column-checkbox') {
if (cell.column.id === 'column-checkbox' || cell.column.id === 'column-tags') {
return (
<div key={index} className={styles.cellWrapper}>
<TableCell
@@ -218,6 +220,7 @@ const getStyles = (theme: GrafanaTheme2) => {
`,
tagList: css`
justify-content: flex-start;
pointer-events: auto;
`,
};
};
@@ -12,7 +12,9 @@ export const generateColumns = (
data: DataFrameView<FieldAccess>,
isDashboardList: boolean,
availableWidth: number,
styles: { [key: string]: string }
styles: { [key: string]: string },
tags: string[],
onTagFilterChange: (tags: string[]) => void
): TableColumn[] => {
const columns: TableColumn[] = [];
const urlField = data.fields.url!;
@@ -143,7 +145,7 @@ export const generateColumns = (
// Show tags if we have any
if (access.tags && hasFieldValue(access.tags)) {
width = Math.max(availableWidth, 250);
columns.push(makeTagsColumn(access.tags, width, styles.tagList));
columns.push(makeTagsColumn(access.tags, width, styles.tagList, tags, onTagFilterChange));
}
return columns;
@@ -260,7 +262,19 @@ function makeTypeColumn(
};
}
function makeTagsColumn(field: Field<string[]>, width: number, tagListClass: string): TableColumn {
function makeTagsColumn(
field: Field<string[]>,
width: number,
tagListClass: string,
currentTagFilter: string[],
onTagFilterChange: (tags: string[]) => void
): TableColumn {
const updateTagFilter = (tag: string) => {
if (!currentTagFilter.includes(tag)) {
onTagFilterChange([...currentTagFilter, tag]);
}
};
return {
Cell: DefaultCell,
id: `column-tags`,
@@ -269,7 +283,7 @@ function makeTagsColumn(field: Field<string[]>, width: number, tagListClass: str
accessor: (row: any, i: number) => {
const tags = field.values.get(i);
if (tags) {
return <TagList className={tagListClass} tags={tags} onClick={(v) => alert('CLICKED TAG: ' + v)} />;
return <TagList className={tagListClass} tags={tags} onClick={updateTagFilter} />;
}
return null;
},