Search: Include panel_type in query (#63229)
This commit is contained in:
+1
-3
@@ -4090,9 +4090,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/features/search/state/SearchStateManager.ts:5381": [
|
"public/app/features/search/state/SearchStateManager.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
|
||||||
[0, 0, 0, "Do not use any type assertions.", "2"]
|
|
||||||
],
|
],
|
||||||
"public/app/features/search/types.ts:5381": [
|
"public/app/features/search/types.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ func getDashboardPanelDocs(dash dashboard, location string) []*bluge.Document {
|
|||||||
AddField(bluge.NewKeywordField(documentFieldLocation, location).Aggregatable().StoreValue()).
|
AddField(bluge.NewKeywordField(documentFieldLocation, location).Aggregatable().StoreValue()).
|
||||||
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindPanel)).Aggregatable().StoreValue()) // likely want independent index for this
|
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindPanel)).Aggregatable().StoreValue()) // likely want independent index for this
|
||||||
|
|
||||||
for _, ref := range dash.summary.References {
|
for _, ref := range panel.References {
|
||||||
switch ref.Family {
|
switch ref.Family {
|
||||||
case entity.StandardKindDashboard:
|
case entity.StandardKindDashboard:
|
||||||
if ref.Type != "" {
|
if ref.Type != "" {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { FC, FormEvent } from 'react';
|
import React, { FormEvent } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
@@ -36,6 +36,7 @@ interface Props {
|
|||||||
getSortOptions: () => Promise<SelectableValue[]>;
|
getSortOptions: () => Promise<SelectableValue[]>;
|
||||||
sortPlaceholder?: string;
|
sortPlaceholder?: string;
|
||||||
onDatasourceChange: (ds?: string) => void;
|
onDatasourceChange: (ds?: string) => void;
|
||||||
|
onPanelTypeChange: (pt?: string) => void;
|
||||||
includePanels: boolean;
|
includePanels: boolean;
|
||||||
onSetIncludePanels: (v: boolean) => void;
|
onSetIncludePanels: (v: boolean) => void;
|
||||||
state: SearchState;
|
state: SearchState;
|
||||||
@@ -59,7 +60,7 @@ export function getValidQueryLayout(q: SearchState): SearchLayout {
|
|||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionRow: FC<Props> = ({
|
export const ActionRow = ({
|
||||||
onLayoutChange,
|
onLayoutChange,
|
||||||
onSortChange,
|
onSortChange,
|
||||||
onStarredFilterChange = () => {},
|
onStarredFilterChange = () => {},
|
||||||
@@ -68,16 +69,17 @@ export const ActionRow: FC<Props> = ({
|
|||||||
getSortOptions,
|
getSortOptions,
|
||||||
sortPlaceholder,
|
sortPlaceholder,
|
||||||
onDatasourceChange,
|
onDatasourceChange,
|
||||||
|
onPanelTypeChange,
|
||||||
onSetIncludePanels,
|
onSetIncludePanels,
|
||||||
state,
|
state,
|
||||||
showStarredFilter,
|
showStarredFilter,
|
||||||
hideLayout,
|
hideLayout,
|
||||||
}) => {
|
}: Props) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const layout = getValidQueryLayout(state);
|
const layout = getValidQueryLayout(state);
|
||||||
|
|
||||||
// Disabled folder layout option when query is present
|
// Disabled folder layout option when query is present
|
||||||
const disabledOptions = state.query ? [SearchLayout.Folders] : [];
|
const disabledOptions = state.query || state.datasource || state.panel_type ? [SearchLayout.Folders] : [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.actionRow}>
|
<div className={styles.actionRow}>
|
||||||
@@ -109,6 +111,11 @@ export const ActionRow: FC<Props> = ({
|
|||||||
</Trans>
|
</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
{state.panel_type && (
|
||||||
|
<Button icon="times" variant="secondary" onClick={() => onPanelTypeChange(undefined)}>
|
||||||
|
Panel: {state.panel_type}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</HorizontalGroup>
|
</HorizontalGroup>
|
||||||
|
|
||||||
<div className={styles.rowContainer}>
|
<div className={styles.rowContainer}>
|
||||||
|
|||||||
@@ -78,20 +78,7 @@ export const SearchView = ({ showManage, folderDTO, hidePseudoFolders, keyboardE
|
|||||||
<div className={styles.noResults}>
|
<div className={styles.noResults}>
|
||||||
<div>No results found for your query.</div>
|
<div>No results found for your query.</div>
|
||||||
<br />
|
<br />
|
||||||
<Button
|
<Button variant="secondary" onClick={stateManager.onClearSearchAndFilters}>
|
||||||
variant="secondary"
|
|
||||||
onClick={() => {
|
|
||||||
if (state.query) {
|
|
||||||
stateManager.onQueryChange('');
|
|
||||||
}
|
|
||||||
if (state.tag?.length) {
|
|
||||||
stateManager.onTagFilterChange([]);
|
|
||||||
}
|
|
||||||
if (state.datasource) {
|
|
||||||
stateManager.onDatasourceChange(undefined);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Clear search and filters
|
Clear search and filters
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -189,6 +176,7 @@ export const SearchView = ({ showManage, folderDTO, hidePseudoFolders, keyboardE
|
|||||||
getSortOptions={getGrafanaSearcher().getSortOptions}
|
getSortOptions={getGrafanaSearcher().getSortOptions}
|
||||||
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
|
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
|
||||||
onDatasourceChange={stateManager.onDatasourceChange}
|
onDatasourceChange={stateManager.onDatasourceChange}
|
||||||
|
onPanelTypeChange={stateManager.onPanelTypeChange}
|
||||||
state={state}
|
state={state}
|
||||||
includePanels={state.includePanels!}
|
includePanels={state.includePanels!}
|
||||||
onSetIncludePanels={stateManager.onSetIncludePanels}
|
onSetIncludePanels={stateManager.onSetIncludePanels}
|
||||||
|
|||||||
@@ -170,7 +170,10 @@ export const generateColumns = (
|
|||||||
return (
|
return (
|
||||||
<div {...p.cellProps} className={cx(styles.locationCellStyle)}>
|
<div {...p.cellProps} className={cx(styles.locationCellStyle)}>
|
||||||
{parts.map((p) => {
|
{parts.map((p) => {
|
||||||
const info = meta.locationInfo[p];
|
let info = meta.locationInfo[p];
|
||||||
|
if (!info && p === 'general') {
|
||||||
|
info = { kind: 'folder', url: '/dashboards', name: 'General' };
|
||||||
|
}
|
||||||
return info ? (
|
return info ? (
|
||||||
<a key={p} href={info.url} className={styles.locationItem}>
|
<a key={p} href={info.url} className={styles.locationItem}>
|
||||||
<Icon name={getIconForKind(info.kind)} /> {info.name}
|
<Icon name={getIconForKind(info.kind)} /> {info.name}
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
initStateFromUrl(folderUid?: string) {
|
initStateFromUrl(folderUid?: string) {
|
||||||
const stateFromUrl = parseRouteParams(locationService.getSearchObject());
|
const stateFromUrl = parseRouteParams(locationService.getSearchObject());
|
||||||
|
|
||||||
|
// Force list view when conditions are specified from the URL
|
||||||
|
if (stateFromUrl.query || stateFromUrl.datasource || stateFromUrl.panel_type) {
|
||||||
|
stateFromUrl.layout = SearchLayout.List;
|
||||||
|
}
|
||||||
|
|
||||||
stateManager.setState({
|
stateManager.setState({
|
||||||
...stateFromUrl,
|
...stateFromUrl,
|
||||||
folderUid: folderUid,
|
folderUid: folderUid,
|
||||||
@@ -63,6 +68,7 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
query: this.state.query.length === 0 ? null : this.state.query,
|
query: this.state.query.length === 0 ? null : this.state.query,
|
||||||
tag: this.state.tag,
|
tag: this.state.tag,
|
||||||
datasource: this.state.datasource,
|
datasource: this.state.datasource,
|
||||||
|
panel_type: this.state.panel_type,
|
||||||
starred: this.state.starred ? this.state.starred : null,
|
starred: this.state.starred ? this.state.starred : null,
|
||||||
sort: this.state.sort,
|
sort: this.state.sort,
|
||||||
});
|
});
|
||||||
@@ -79,6 +85,16 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onClearSearchAndFilters = () => {
|
||||||
|
this.setStateAndDoSearch({
|
||||||
|
query: '',
|
||||||
|
datasource: undefined,
|
||||||
|
tag: [],
|
||||||
|
panel_type: undefined,
|
||||||
|
starred: undefined,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onQueryChange = (query: string) => {
|
onQueryChange = (query: string) => {
|
||||||
this.setStateAndDoSearch({ query });
|
this.setStateAndDoSearch({ query });
|
||||||
};
|
};
|
||||||
@@ -103,6 +119,10 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
this.setStateAndDoSearch({ datasource });
|
this.setStateAndDoSearch({ datasource });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onPanelTypeChange = (panel_type?: string) => {
|
||||||
|
this.setStateAndDoSearch({ panel_type });
|
||||||
|
};
|
||||||
|
|
||||||
onStarredFilterChange = (e: FormEvent<HTMLInputElement>) => {
|
onStarredFilterChange = (e: FormEvent<HTMLInputElement>) => {
|
||||||
const starred = e.currentTarget.checked;
|
const starred = e.currentTarget.checked;
|
||||||
this.setStateAndDoSearch({ starred });
|
this.setStateAndDoSearch({ starred });
|
||||||
@@ -142,14 +162,15 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
hasSearchFilters() {
|
hasSearchFilters() {
|
||||||
return this.state.query || this.state.tag.length || this.state.starred;
|
return this.state.query || this.state.tag.length || this.state.starred || this.state.panel_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSearchQuery() {
|
getSearchQuery() {
|
||||||
const q: SearchQuery = {
|
const q: SearchQuery = {
|
||||||
query: this.state.query,
|
query: this.state.query,
|
||||||
tags: this.state.tag as string[],
|
tags: this.state.tag,
|
||||||
ds_uid: this.state.datasource as string,
|
ds_uid: this.state.datasource,
|
||||||
|
panel_type: this.state.panel_type,
|
||||||
location: this.state.folderUid, // This will scope all results to the prefix
|
location: this.state.folderUid, // This will scope all results to the prefix
|
||||||
sort: this.state.sort,
|
sort: this.state.sort,
|
||||||
explain: this.state.explain,
|
explain: this.state.explain,
|
||||||
@@ -173,6 +194,10 @@ export class SearchStateManager extends StateManagerBase<SearchState> {
|
|||||||
q.kind = ['dashboard', 'folder']; // skip panels
|
q.kind = ['dashboard', 'folder']; // skip panels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (q.panel_type?.length) {
|
||||||
|
q.kind = ['panel'];
|
||||||
|
}
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export interface SearchState {
|
|||||||
starred: boolean;
|
starred: boolean;
|
||||||
explain?: boolean; // adds debug info
|
explain?: boolean; // adds debug info
|
||||||
datasource?: string;
|
datasource?: string;
|
||||||
|
panel_type?: string;
|
||||||
sort?: string;
|
sort?: string;
|
||||||
prevSort?: string; // Save sorting data between layouts
|
prevSort?: string; // Save sorting data between layouts
|
||||||
layout: SearchLayout;
|
layout: SearchLayout;
|
||||||
|
|||||||
Reference in New Issue
Block a user