diff --git a/packages/grafana-data/src/field/overrides/processors.ts b/packages/grafana-data/src/field/overrides/processors.ts index a3419affaa1..a4aea5f46b5 100644 --- a/packages/grafana-data/src/field/overrides/processors.ts +++ b/packages/grafana-data/src/field/overrides/processors.ts @@ -1,4 +1,5 @@ -import { DataLink, FieldOverrideContext, SelectableValue, ThresholdsConfig, ValueMapping } from '../../types'; +import { ComponentType } from 'react'; +import { DataLink, Field, FieldOverrideContext, SelectableValue, ThresholdsConfig, ValueMapping } from '../../types'; export const identityOverrideProcessor = (value: T, _context: FieldOverrideContext, _settings: any) => { return value; @@ -158,3 +159,27 @@ export interface StatsPickerConfigSettings { */ defaultStat?: string; } + +interface FieldNamePickerInfoProps { + name?: string; + field?: Field; +} + +export interface FieldNamePickerConfigSettings { + /** + * Function is a predicate, to test each element of the array. + * Return a value that coerces to true to keep the field, or to false otherwise. + */ + filter?: (field: Field) => boolean; + + /** + * Show this text when no values are found + */ + noFieldsMessage?: string; + + /** + * When a field is selected, this component can show aditional + * information, including validation etc + */ + info?: ComponentType | null; +} diff --git a/packages/grafana-data/src/utils/OptionsUIBuilders.ts b/packages/grafana-data/src/utils/OptionsUIBuilders.ts index 32b09db0ae6..a37cc30a871 100644 --- a/packages/grafana-data/src/utils/OptionsUIBuilders.ts +++ b/packages/grafana-data/src/utils/OptionsUIBuilders.ts @@ -15,6 +15,7 @@ import { identityOverrideProcessor, UnitFieldConfigSettings, unitOverrideProcessor, + FieldNamePickerConfigSettings, } from '../field'; /** @@ -235,4 +236,14 @@ export class PanelOptionsEditorBuilder extends OptionsUIRegistryBuilde editor: standardEditorsRegistry.get('unit').editor as any, }); } + + addFieldNamePicker( + config: PanelOptionsEditorConfig + ): this { + return this.addCustomEditor({ + ...config, + id: config.path, + editor: standardEditorsRegistry.get('field-name').editor as any, + }); + } } diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx new file mode 100644 index 00000000000..7511b25c59e --- /dev/null +++ b/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx @@ -0,0 +1,39 @@ +import React, { useCallback } from 'react'; +import { FieldNamePickerConfigSettings, SelectableValue, StandardEditorProps } from '@grafana/data'; +import { Select } from '../Select/Select'; +import { useFieldDisplayNames, useSelectOptions, frameHasName } from './utils'; + +// Pick a field name out of the fulds +export const FieldNamePicker: React.FC> = ({ + value, + onChange, + context, + item, +}) => { + const settings: FieldNamePickerConfigSettings = item.settings ?? {}; + const names = useFieldDisplayNames(context.data, settings?.filter); + const selectOptions = useSelectOptions(names, value); + + const onSelectChange = useCallback( + (selection: SelectableValue) => { + if (!frameHasName(selection.value, names)) { + return; + } + return onChange(selection.value!); + }, + [names, onChange] + ); + + const selectedOption = selectOptions.find((v) => v.value === value); + return ( + <> +