Compare commits

...

3 Commits

Author SHA1 Message Date
Ryan McKinley
06f4860e0c remove SearchEditor 2026-01-15 16:40:21 +03:00
Ryan McKinley
667b48fd0c async 2026-01-15 16:37:51 +03:00
Ryan McKinley
9dc02bffe1 experimental loading 2026-01-15 16:00:41 +03:00
4 changed files with 12 additions and 147 deletions

View File

@@ -1,24 +1,16 @@
import { lastValueFrom } from 'rxjs';
import { DataQueryRequest, DataFrameView } from '@grafana/data';
import { config } from '@grafana/runtime';
import { getGrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
import { GrafanaQuery, GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
import { Playlist } from '../../api/clients/playlist/v0alpha1';
import { getGrafanaSearcher } from '../search/service/searcher';
import { DashboardQueryResult, SearchQuery } from '../search/service/types';
import { SearchQuery } from '../search/service/types';
import { PlaylistItemUI } from './types';
/** Returns a copy with the dashboards loaded */
export async function loadDashboards(items: PlaylistItemUI[]): Promise<PlaylistItemUI[]> {
let idx = 0;
if (!items?.length) {
return [];
}
const targets: GrafanaQuery[] = [];
const targets: SearchQuery[] = [];
for (const item of items) {
const query: SearchQuery = {
query: '*',
@@ -38,35 +30,20 @@ export async function loadDashboards(items: PlaylistItemUI[]): Promise<PlaylistI
query.tags = [item.value];
break;
}
targets.push({
refId: `${idx++}`,
queryType: GrafanaQueryType.Search,
search: query,
});
targets.push(query);
}
// The SQL based store can only execute individual queries
if (!config.featureToggles.panelTitleSearch) {
const searcher = getGrafanaSearcher();
const res: PlaylistItemUI[] = [];
for (let i = 0; i < targets.length; i++) {
const view = (await searcher.search(targets[i].search!)).view;
res.push({ ...items[i], dashboards: view.map((v) => ({ ...v })) });
}
return res;
const searcher = getGrafanaSearcher();
const results = await Promise.allSettled(targets.map((target) => searcher.search(target)));
const res: PlaylistItemUI[] = [];
for (let i = 0; i < results.length; i++) {
const result = results[i];
const dashboards = result.status === 'fulfilled' ? result.value.view.map((v) => ({ ...v })) : [];
res.push({ ...items[i], dashboards });
}
// The bluge backend can execute multiple queries in a single request
const ds = await getGrafanaDatasource();
// eslint-disable-next-line
const rsp = await lastValueFrom(ds.query({ targets } as unknown as DataQueryRequest<GrafanaQuery>));
if (rsp.data.length !== items.length) {
throw new Error('unexpected result size');
}
return items.map((item, idx) => {
const view = new DataFrameView<DashboardQueryResult>(rsp.data[idx]);
return { ...item, dashboards: view.map((v) => ({ ...v })) };
});
return res;
}
export function getDefaultPlaylist(): Playlist {

View File

@@ -14,7 +14,6 @@ import {
Stack,
InlineLabel,
} from '@grafana/ui';
import { hasAlphaPanels } from 'app/core/config';
import { getManagedChannelInfo } from 'app/features/live/info';
import { SearchQuery } from 'app/features/search/service/types';
@@ -22,7 +21,6 @@ import { GrafanaDatasource } from '../datasource';
import { defaultQuery, GrafanaQuery, GrafanaQueryType } from '../types';
import { RandomWalkEditor } from './RandomWalkEditor';
import SearchEditor from './SearchEditor';
interface Props extends QueryEditorProps<GrafanaDatasource, GrafanaQuery>, Themeable2 {}
@@ -57,21 +55,6 @@ export class UnthemedQueryEditor extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
if (config.featureToggles.panelTitleSearch && hasAlphaPanels) {
this.queryTypes.push({
label: 'Search',
value: GrafanaQueryType.Search,
description: 'Search for grafana resources',
});
}
if (config.featureToggles.unifiedStorageSearchUI) {
this.queryTypes.push({
label: 'Search (experimental)',
value: GrafanaQueryType.SearchNext,
description: 'Search for grafana resources',
});
}
}
loadChannelInfo() {
@@ -391,12 +374,6 @@ export class UnthemedQueryEditor extends React.PureComponent<Props, State> {
return (
<>
{queryType === GrafanaQueryType.Search && (
<Alert title="Grafana Search" severity="info">
Using this datasource to call the new search system is experimental, and subject to change at any time
without notice.
</Alert>
)}
<InlineFieldRow>
<InlineField label="Query type" grow={true} labelWidth={labelWidth}>
<Select
@@ -412,12 +389,6 @@ export class UnthemedQueryEditor extends React.PureComponent<Props, State> {
{queryType === GrafanaQueryType.LiveMeasurements && this.renderMeasurementsQuery()}
{queryType === GrafanaQueryType.List && this.renderListPublicFiles()}
{queryType === GrafanaQueryType.Snapshot && this.renderSnapshotQuery()}
{queryType === GrafanaQueryType.Search && (
<SearchEditor value={query.search ?? {}} onChange={this.onSearchChange} />
)}
{queryType === GrafanaQueryType.SearchNext && (
<SearchEditor value={query.searchNext ?? {}} onChange={this.onSearchNextChange} />
)}
</>
);
}

View File

@@ -1,81 +0,0 @@
import { useEffect, useState } from 'react';
import * as React from 'react';
import { InlineField, Input, InlineFieldRow, CodeEditor } from '@grafana/ui';
import { SearchQuery } from 'app/features/search/service/types';
interface Props {
value: SearchQuery;
onChange: (value: SearchQuery) => void;
}
export default function SearchEditor({ value, onChange }: Props) {
const [json, setJSON] = useState('');
const [query, setQuery] = useState(value.query ?? '');
useEffect(() => {
const emptySearchQuery: SearchQuery = {
query: '*',
location: '', // general, etc
ds_uid: '',
sort: '',
tags: [],
kind: [],
explain: false,
facet: [{ field: 'kind' }, { field: 'tags' }],
from: 0,
limit: 20,
};
setJSON(JSON.stringify({ ...emptySearchQuery, ...value }, null, 2));
}, [value]);
const handleSearchBlur = () => {
if (query !== value.query) {
onChange({ ...value, query });
}
};
const handleSearchEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key !== 'Enter') {
return;
}
handleSearchBlur();
};
const onSaveSearchJSON = (rawSearchJSON: string) => {
try {
const searchQuery: SearchQuery = JSON.parse(rawSearchJSON);
onChange(searchQuery);
setQuery(searchQuery.query ?? '');
} catch (ex) {
console.log('UNABLE TO parse search', rawSearchJSON, ex);
}
};
return (
<>
<InlineFieldRow>
<InlineField label="Query" grow={true} labelWidth={12}>
<Input
placeholder="Everything"
value={query}
onChange={(e) => setQuery(e.currentTarget.value)}
onKeyDown={handleSearchEnterKey}
onBlur={handleSearchBlur}
spellCheck={false}
/>
</InlineField>
</InlineFieldRow>
<CodeEditor
height={300}
language="json"
value={json}
onBlur={onSaveSearchJSON}
onSave={onSaveSearchJSON}
showMiniMap={false}
showLineNumbers={true}
/>
</>
);
}

View File

@@ -18,8 +18,6 @@ export enum GrafanaQueryType {
RandomWalk = 'randomWalk',
List = 'list',
Read = 'read',
Search = 'search',
SearchNext = 'searchNext',
}
export interface GrafanaQuery extends DataQuery {