Options: expose a dashboard picker element (#38955)

This commit is contained in:
Ryan McKinley 2021-09-13 23:30:46 -07:00 committed by GitHub
parent 45e67630e8
commit 98cca6317d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 11 deletions

View File

@ -246,4 +246,14 @@ export class PanelOptionsEditorBuilder<TOptions> extends OptionsUIRegistryBuilde
editor: standardEditorsRegistry.get('field-name').editor as any,
});
}
addDashboardPicker<TSettings = any>(
config: PanelOptionsEditorConfig<TOptions, TSettings & FieldNamePickerConfigSettings, string>
): this {
return this.addCustomEditor({
...config,
id: config.path,
editor: standardEditorsRegistry.get('dashboard-uid').editor as any, // added at runtime
});
}
}

View File

@ -229,6 +229,8 @@ export const getStandardFieldConfigs = () => {
/**
* Returns collection of standard option editors definitions
*
* @internal
*/
export const getStandardOptionEditors = () => {
const number: StandardEditorsRegistryItem<number> = {

View File

@ -31,7 +31,7 @@ import { reportPerformance } from './core/services/echo/EchoSrv';
import { PerformanceBackend } from './core/services/echo/backends/PerformanceBackend';
import 'app/routes/GrafanaCtrl';
import 'app/features/all';
import { getScrollbarWidth, getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui';
import { getScrollbarWidth, getStandardFieldConfigs } from '@grafana/ui';
import { getDefaultVariableAdapters, variableAdapters } from './features/variables/adapters';
import { initDevFeatures } from './dev';
import { getStandardTransformers } from 'app/core/utils/standardTransformers';
@ -49,6 +49,7 @@ import getDefaultMonacoLanguages from '../lib/monaco-languages';
import { contextSrv } from './core/services/context_srv';
import { GAEchoBackend } from './core/services/echo/backends/analytics/GABackend';
import { RudderstackBackend } from './core/services/echo/backends/analytics/RudderstackBackend';
import { getAllOptionEditors } from './core/components/editors/registry';
// add move to lodash for backward compatabilty with plugins
// @ts-ignore
@ -81,7 +82,7 @@ export class GrafanaApp {
initExtensions();
configureStore();
standardEditorsRegistry.setInit(getStandardOptionEditors);
standardEditorsRegistry.setInit(getAllOptionEditors);
standardFieldConfigEditorRegistry.setInit(getStandardFieldConfigs);
standardTransformersRegistry.setInit(getStandardTransformers);
variableAdapters.setInit(getDefaultVariableAdapters);

View File

@ -0,0 +1,63 @@
import React, { FC, useCallback, useState } from 'react';
import debounce from 'debounce-promise';
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { DashboardSearchHit } from 'app/features/search/types';
import { backendSrv } from 'app/core/services/backend_srv';
import { AsyncSelect } from '@grafana/ui';
import { useAsync } from 'react-use';
export interface DashboardPickerOptions {
placeholder?: string;
isClearable?: boolean;
}
const getDashboards = (query = '') => {
return backendSrv.search({ type: 'dash-db', query, limit: 100 }).then((result: DashboardSearchHit[]) => {
return result.map((item: DashboardSearchHit) => ({
value: item.uid,
label: `${item?.folderTitle ?? 'General'}/${item.title}`,
}));
});
};
/** This will return the item UID */
export const DashboardPicker: FC<StandardEditorProps<string, any, any>> = ({ value, onChange, item }) => {
const [current, setCurrent] = useState<SelectableValue<string>>();
// This is required because the async select does not match the raw uid value
// We can not use a simple Select because the dashboard search should not return *everything*
useAsync(async () => {
if (!value) {
setCurrent(undefined);
return;
}
const res = await backendSrv.getDashboardByUid(value);
setCurrent({
value: res.dashboard.uid,
label: `${res.meta?.folderTitle ?? 'General'}/${res.dashboard.title}`,
});
return undefined;
}, [value]);
const onPicked = useCallback(
(sel: SelectableValue<string>) => {
onChange(sel?.value);
},
[onChange]
);
const debouncedSearch = debounce(getDashboards, 300);
const { placeholder, isClearable } = item?.settings ?? {};
return (
<AsyncSelect
menuShouldPortal
isClearable={isClearable}
defaultOptions={true}
loadOptions={debouncedSearch}
onChange={onPicked}
placeholder={placeholder ?? 'Select dashboard'}
noOptionsMessage="No dashboards found"
value={current}
/>
);
};

View File

@ -5,14 +5,19 @@ import { AsyncSelect } from '@grafana/ui';
import { backendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit } from 'app/features/search/types';
export interface DashboardPickerItem extends Pick<DashboardSearchHit, 'uid' | 'id'> {
/**
* @deprecated prefer using dashboard uid rather than id
*/
export interface DashboardPickerItem extends SelectableValue<number> {
id: number;
uid: string;
value: number;
label: string;
}
export interface Props {
interface Props {
onChange: (dashboard: DashboardPickerItem) => void;
value?: SelectableValue;
value?: DashboardPickerItem;
width?: number;
isClearable?: boolean;
invalid?: boolean;
@ -20,7 +25,7 @@ export interface Props {
}
const getDashboards = (query = '') => {
return backendSrv.search({ type: 'dash-db', query }).then((result: DashboardSearchHit[]) => {
return backendSrv.search({ type: 'dash-db', query, limit: 100 }).then((result: DashboardSearchHit[]) => {
return result.map((item: DashboardSearchHit) => ({
id: item.id,
uid: item.uid,
@ -30,7 +35,10 @@ const getDashboards = (query = '') => {
});
};
export const DashboardPicker: FC<Props> = ({ onChange, value, width, isClearable = false, invalid, disabled }) => {
/**
* @deprecated prefer using dashboard uid rather than id
*/
export const DashboardPickerByID: FC<Props> = ({ onChange, value, width, isClearable = false, invalid, disabled }) => {
const debouncedSearch = debounce(getDashboards, 300);
return (

View File

@ -0,0 +1,16 @@
import { DashboardPicker, DashboardPickerOptions } from './DashboardPicker';
import { getStandardOptionEditors } from '@grafana/ui';
import { StandardEditorsRegistryItem } from '@grafana/data';
/**
* Returns collection of standard option editors definitions
*/
export const getAllOptionEditors = () => {
const dashboardPicker: StandardEditorsRegistryItem<string, DashboardPickerOptions> = {
id: 'dashboard-uid',
name: 'Dashboard',
description: 'Select dashboard',
editor: DashboardPicker as any,
};
return [...getStandardOptionEditors(), dashboardPicker];
};

View File

@ -4,11 +4,11 @@ import { Button, Field, Form, HorizontalGroup, Input, LinkButton } from '@grafan
import { selectors } from '@grafana/e2e-selectors';
import { Playlist } from './types';
import { DashboardPicker } from '../../core/components/Select/DashboardPicker';
import { TagFilter } from '../../core/components/TagFilter/TagFilter';
import { SearchSrv } from '../../core/services/search_srv';
import { usePlaylistItems } from './usePlaylistItems';
import { PlaylistTable } from './PlaylistTable';
import { DashboardPickerByID } from 'app/core/components/editors/DashboardPickerByID';
interface PlaylistFormProps {
onSubmit: (playlist: Playlist) => void;
@ -52,7 +52,7 @@ export const PlaylistForm: FC<PlaylistFormProps> = ({ onSubmit, playlist }) => {
<h3 className="page-headering">Add dashboards</h3>
<Field label="Add by title">
<DashboardPicker onChange={addById} isClearable />
<DashboardPickerByID onChange={addById} isClearable />
</Field>
<Field label="Add by tag">

View File

@ -1,14 +1,14 @@
import { DashboardPickerItem } from 'app/core/components/editors/DashboardPickerByID';
import { useCallback, useState } from 'react';
import { PlaylistItem } from './types';
import { DashboardPickerItem } from '../../core/components/Select/DashboardPicker';
export function usePlaylistItems(playlistItems?: PlaylistItem[]) {
const [items, setItems] = useState<PlaylistItem[]>(playlistItems ?? []);
const addById = useCallback(
(dashboard: DashboardPickerItem) => {
if (items.find((item) => item.id === dashboard.id)) {
if (!dashboard || items.find((item) => item.id === dashboard.id)) {
return;
}

View File

@ -33,5 +33,13 @@ export const plugin = new PanelPlugin<DebugPanelOptions>(DebugPanel).useFieldCon
name: 'Schema Changed Count',
defaultValue: true,
showIf: ({ mode }) => mode === DebugMode.Render,
})
.addDashboardPicker({
path: 'dashboardUID',
name: 'Dashboard',
settings: {
placeholder: 'Select dashboard',
isClearable: true,
},
});
});