Search v2: encode query in url (#47078)
This commit is contained in:
@@ -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;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user