mirror of
https://github.com/grafana/grafana.git
synced 2024-12-02 05:29:42 -06:00
SearchV2: add CTA and reporting to new search UI (#50175)
This commit is contained in:
parent
7a614fd8a1
commit
1a324b3330
@ -95,7 +95,7 @@ export const ActionRow: FC<Props> = ({
|
||||
Datasource: {query.datasource}
|
||||
</Button>
|
||||
)}
|
||||
{layout !== SearchLayout.Folders && (
|
||||
{layout !== SearchLayout.Folders && config.featureToggles.panelTitleSearch && (
|
||||
<Checkbox value={includePanels} onChange={() => setIncludePanels(!includePanels)} label="Include panels" />
|
||||
)}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { useAsync, useDebounce } from 'react-use';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { useStyles2, Spinner, Button } from '@grafana/ui';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { TermCount } from 'app/core/components/TagFilter/TagFilter';
|
||||
import { FolderDTO } from 'app/types';
|
||||
|
||||
@ -13,6 +13,7 @@ import { PreviewsSystemRequirements } from '../../components/PreviewsSystemRequi
|
||||
import { useSearchQuery } from '../../hooks/useSearchQuery';
|
||||
import { getGrafanaSearcher, SearchQuery } from '../../service';
|
||||
import { SearchLayout } from '../../types';
|
||||
import { reportDashboardListViewed } from '../reporting';
|
||||
import { newSearchSelection, updateSearchSelection } from '../selection';
|
||||
|
||||
import { ActionRow, getValidQueryLayout } from './ActionRow';
|
||||
@ -80,6 +81,21 @@ export const SearchView = ({
|
||||
return q;
|
||||
}, [query, queryText, folderDTO, includePanels]);
|
||||
|
||||
// Search usage reporting
|
||||
useDebounce(
|
||||
() => {
|
||||
reportDashboardListViewed(folderDTO ? 'manage_dashboards' : 'dashboard_search', {
|
||||
layout: query.layout,
|
||||
starred: query.starred,
|
||||
sortValue: query.sort?.value,
|
||||
query: query.query,
|
||||
tagCount: query.tag?.length,
|
||||
});
|
||||
},
|
||||
1000,
|
||||
[folderDTO, query.layout, query.starred, query.sort?.value, query.query?.length, query.tag?.length]
|
||||
);
|
||||
|
||||
const results = useAsync(() => {
|
||||
return getGrafanaSearcher().search(searchQuery);
|
||||
}, [searchQuery]);
|
||||
@ -97,10 +113,6 @@ export const SearchView = ({
|
||||
[searchSelection]
|
||||
);
|
||||
|
||||
if (!config.featureToggles.panelTitleSearch) {
|
||||
return <div className={styles.unsupported}>Unsupported</div>;
|
||||
}
|
||||
|
||||
// This gets the possible tags from within the query results
|
||||
const getTagOptions = (): Promise<TermCount[]> => {
|
||||
return getGrafanaSearcher().tags(searchQuery);
|
||||
@ -197,8 +209,19 @@ export const SearchView = ({
|
||||
);
|
||||
};
|
||||
|
||||
if (!config.featureToggles.panelTitleSearch) {
|
||||
return <div className={styles.unsupported}>Unsupported</div>;
|
||||
if (folderDTO && !results.loading && !results.value?.totalRows && !queryText.length) {
|
||||
return (
|
||||
<EmptyListCTA
|
||||
title="This folder doesn't have any dashboards yet"
|
||||
buttonIcon="plus"
|
||||
buttonTitle="Create Dashboard"
|
||||
buttonLink={`dashboard/new?folderId=${folderDTO.id}`}
|
||||
proTip="Add/move dashboards to your folder at ->"
|
||||
proTipLink="dashboards"
|
||||
proTipLinkTitle="Manage dashboards"
|
||||
proTipTarget=""
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
26
public/app/features/search/page/reporting.ts
Normal file
26
public/app/features/search/page/reporting.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
|
||||
import { SearchLayout } from '../types';
|
||||
|
||||
export const reportDashboardListViewed = (
|
||||
dashboardListType: 'manage_dashboards' | 'dashboard_search',
|
||||
query: {
|
||||
layout?: SearchLayout;
|
||||
starred?: boolean;
|
||||
sortValue?: string;
|
||||
query?: string;
|
||||
tagCount?: number;
|
||||
}
|
||||
) => {
|
||||
const showPreviews = query.layout === SearchLayout.Grid;
|
||||
const previewsEnabled = Boolean(config.featureToggles.panelTitleSearch);
|
||||
const previews = previewsEnabled ? (showPreviews ? 'on' : 'off') : 'feature_disabled';
|
||||
reportInteraction(`${dashboardListType}_viewed`, {
|
||||
previews,
|
||||
layout: query.layout,
|
||||
starredFilter: query.starred ?? false,
|
||||
sort: query.sortValue ?? '',
|
||||
tagCount: query.tagCount ?? 0,
|
||||
queryLength: query.query?.length ?? 0,
|
||||
});
|
||||
};
|
@ -6,6 +6,8 @@ import { TermCount } from 'app/core/components/TagFilter/TagFilter';
|
||||
import { GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
|
||||
import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
|
||||
|
||||
import { replaceCurrentFolderQuery } from './utils';
|
||||
|
||||
import { DashboardQueryResult, GrafanaSearcher, QueryResponse, SearchQuery, SearchResultMeta } from '.';
|
||||
|
||||
export class BlugeSearcher implements GrafanaSearcher {
|
||||
@ -65,6 +67,7 @@ const firstPageSize = 50;
|
||||
const nextPageSizes = 100;
|
||||
|
||||
async function doSearchQuery(query: SearchQuery): Promise<QueryResponse> {
|
||||
query = await replaceCurrentFolderQuery(query);
|
||||
const ds = (await getDataSourceSrv().get('-- Grafana --')) as GrafanaDatasource;
|
||||
const target = {
|
||||
...query,
|
||||
|
@ -6,6 +6,7 @@ import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSearchHit } from '../types';
|
||||
|
||||
import { LocationInfo } from './types';
|
||||
import { replaceCurrentFolderQuery } from './utils';
|
||||
|
||||
import { DashboardQueryResult, GrafanaSearcher, QueryResponse, SearchQuery } from '.';
|
||||
|
||||
@ -46,6 +47,7 @@ export class SQLSearcher implements GrafanaSearcher {
|
||||
sort: query.sort,
|
||||
};
|
||||
|
||||
query = await replaceCurrentFolderQuery(query);
|
||||
if (query.query === '*') {
|
||||
if (query.kind?.length === 1 && query.kind[0] === 'folder') {
|
||||
q.type = 'dash-folder';
|
||||
|
36
public/app/features/search/service/utils.ts
Normal file
36
public/app/features/search/service/utils.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
|
||||
import { SearchQuery } from './types';
|
||||
|
||||
/** prepare the query replacing folder:current */
|
||||
export async function replaceCurrentFolderQuery(query: SearchQuery): Promise<SearchQuery> {
|
||||
if (query.query && query.query.indexOf('folder:current') >= 0) {
|
||||
query = {
|
||||
...query,
|
||||
location: await getCurrentFolderUID(),
|
||||
query: query.query.replace('folder:current', '').trim(),
|
||||
};
|
||||
if (!query.query?.length) {
|
||||
query.query = '*';
|
||||
}
|
||||
}
|
||||
return Promise.resolve(query);
|
||||
}
|
||||
|
||||
async function getCurrentFolderUID(): Promise<string | undefined> {
|
||||
try {
|
||||
let dash = getDashboardSrv().getCurrent();
|
||||
if (!dash) {
|
||||
await delay(500); // may not be loaded yet
|
||||
dash = getDashboardSrv().getCurrent();
|
||||
}
|
||||
return Promise.resolve(dash?.meta?.folderUid);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
Loading…
Reference in New Issue
Block a user