diff --git a/packages/grafana-ui/src/components/MatchersUI/utils.ts b/packages/grafana-ui/src/components/MatchersUI/utils.ts index 913994a10f0..ccbf9545081 100644 --- a/packages/grafana-ui/src/components/MatchersUI/utils.ts +++ b/packages/grafana-ui/src/components/MatchersUI/utils.ts @@ -68,7 +68,8 @@ export function useFieldDisplayNames(data: DataFrame[], filter?: (field: Field) export function useSelectOptions( displayNames: FrameFieldsDisplayNames, currentName?: string, - firstItem?: SelectableValue + firstItem?: SelectableValue, + fieldType?: string ): Array> { return useMemo(() => { let found = false; @@ -81,11 +82,13 @@ export function useSelectOptions( found = true; } const field = displayNames.fields.get(name); - options.push({ - value: name, - label: name, - icon: field ? getFieldTypeIcon(field) : undefined, - }); + if (!fieldType || fieldType === field?.type) { + options.push({ + value: name, + label: name, + icon: field ? getFieldTypeIcon(field) : undefined, + }); + } } for (const name of displayNames.raw) { if (!displayNames.display.has(name)) { @@ -106,5 +109,5 @@ export function useSelectOptions( }); } return options; - }, [displayNames, currentName, firstItem]); + }, [displayNames, currentName, firstItem, fieldType]); } diff --git a/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx new file mode 100644 index 00000000000..8d26be77018 --- /dev/null +++ b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx @@ -0,0 +1,110 @@ +import React, { FC, useCallback } from 'react'; +import { FieldType, GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data'; +import { ScalarDimensionConfig, ScalarDimensionMode, ScalarDimensionOptions } from '../types'; +import { InlineField, InlineFieldRow, RadioButtonGroup, Select, useStyles2 } from '@grafana/ui'; +import { useFieldDisplayNames, useSelectOptions } from '@grafana/ui/src/components/MatchersUI/utils'; +import { NumberInput } from './NumberInput'; +import { css } from '@emotion/css'; + +const fixedValueOption: SelectableValue = { + label: 'Fixed value', + value: '_____fixed_____', +}; + +const scalarOptions = [ + { label: 'Mod', value: ScalarDimensionMode.Mod, description: 'Use field values, mod from max' }, + { label: 'Clamped', value: ScalarDimensionMode.Clamped, description: 'Use field values, clamped to max and min' }, +]; + +export const ScalarDimensionEditor: FC> = ( + props +) => { + const { value, context, onChange } = props; + + const DEFAULT_VALUE = 0; + + const fieldName = value?.field; + const isFixed = Boolean(!fieldName); + const names = useFieldDisplayNames(context.data); + const selectOptions = useSelectOptions(names, fieldName, fixedValueOption, FieldType.number); + + const styles = useStyles2(getStyles); + + const onSelectChange = useCallback( + (selection: SelectableValue) => { + const field = selection.value; + if (field && field !== fixedValueOption.value) { + onChange({ + ...value, + field, + }); + } else { + const fixed = value.fixed ?? DEFAULT_VALUE; + onChange({ + ...value, + field: undefined, + fixed, + }); + } + }, + [onChange, value] + ); + + const onModeChange = useCallback( + (mode) => { + onChange({ + ...value, + mode, + }); + }, + [onChange, value] + ); + + const onValueChange = useCallback( + (v: number | undefined) => { + onChange({ + ...value, + field: undefined, + fixed: v ?? DEFAULT_VALUE, + }); + }, + [onChange, value] + ); + + const val = value ?? {}; + const mode = value?.mode ?? ScalarDimensionMode.Mod; + const selectedOption = isFixed ? fixedValueOption : selectOptions.find((v) => v.value === fieldName); + return ( + <> +
+ + + + + +