diff --git a/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx b/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx index 0d899f8362a..d69daf2e95d 100644 --- a/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx @@ -1,15 +1,14 @@ import React, { FC, useCallback } from 'react'; import { StandardEditorProps, StandardEditorsRegistryItem } from '@grafana/data'; -import { ComparisonOperation, FeatureStyleConfig } from '../types'; +import { FeatureStyleConfig } from '../types'; import { Button } from '@grafana/ui'; import { DEFAULT_STYLE_RULE } from '../layers/data/geojsonLayer'; import { StyleRuleEditor, StyleRuleEditorSettings } from './StyleRuleEditor'; export const GeomapStyleRulesEditor: FC> = (props) => { - const { value, onChange, context } = props; - - const OPTIONS = getComparisonOperatorOptions(); + const { value, onChange, context, item } = props; + const settings = item.settings; const onAddRule = useCallback(() => { onChange([...value, DEFAULT_STYLE_RULE]); }, [onChange, value]); @@ -32,7 +31,7 @@ export const GeomapStyleRulesEditor: FC { const itemSettings: StandardEditorsRegistryItem = { - settings: { options: OPTIONS }, + settings, } as any; return ( @@ -55,11 +54,3 @@ export const GeomapStyleRulesEditor: FC ); }; - -const getComparisonOperatorOptions = () => { - const options = []; - for (const value of Object.values(ComparisonOperation)) { - options.push({ value: value, label: value }); - } - return options; -}; diff --git a/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx b/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx index 848032170fa..94a6fae3738 100644 --- a/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx @@ -1,35 +1,61 @@ -import React, { ChangeEvent, FC, useCallback } from 'react'; +import React, { FC, useCallback, useMemo } from 'react'; import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data'; import { ComparisonOperation, FeatureStyleConfig } from '../types'; -import { Button, InlineField, InlineFieldRow, Input, Select, useStyles2 } from '@grafana/ui'; +import { Button, InlineField, InlineFieldRow, Select, useStyles2 } from '@grafana/ui'; import { css } from '@emotion/css'; import { StyleEditor } from '../layers/data/StyleEditor'; import { defaultStyleConfig, StyleConfig } from '../style/types'; import { DEFAULT_STYLE_RULE } from '../layers/data/geojsonLayer'; +import { Observable } from 'rxjs'; +import { useObservable } from 'react-use'; +import { getUniqueFeatureValues, LayerContentInfo } from '../utils/getFeatures'; +import { FeatureLike } from 'ol/Feature'; +import { getSelectionInfo } from '../utils/selection'; +import { NumberInput } from 'app/features/dimensions/editors/NumberInput'; +import { isNumber } from 'lodash'; export interface StyleRuleEditorSettings { - options: SelectableValue[]; + features: Observable; + layerInfo: Observable; } +const comparators = [ + { label: '==', value: ComparisonOperation.EQ }, + { label: '>', value: ComparisonOperation.GT }, + { label: '>=', value: ComparisonOperation.GTE }, + { label: '<', value: ComparisonOperation.LT }, + { label: '<=', value: ComparisonOperation.LTE }, +]; + export const StyleRuleEditor: FC> = ( props ) => { const { value, onChange, item, context } = props; const settings: StyleRuleEditorSettings = item.settings; + const { features, layerInfo } = settings; + + const propertyOptions = useObservable(layerInfo); + const feats = useObservable(features); + + const uniqueSelectables = useMemo(() => { + const key = value?.check?.property; + if (key && feats && value.check?.operation === ComparisonOperation.EQ) { + return getUniqueFeatureValues(feats, key).map((v) => ({ value: v, label: v })); + } + return []; + }, [feats, value]); const styles = useStyles2(getStyles); const LABEL_WIDTH = 10; - const onChangeComparisonProperty = useCallback( - (e: ChangeEvent) => { + const onChangeProperty = useCallback( + (selection?: SelectableValue) => { onChange({ ...value, check: { - ...value.check, - property: e.currentTarget.value, - operation: value.check?.operation ?? ComparisonOperation.EQ, - value: value.check?.value ?? '', + ...value.check!, + property: selection?.value, }, }); }, @@ -41,25 +67,34 @@ export const StyleRuleEditor: FC) => { + const onChangeValue = useCallback( + (selection?: SelectableValue) => { onChange({ ...value, check: { - ...value.check, - value: e.currentTarget.value, - operation: value.check?.operation ?? ComparisonOperation.EQ, - property: value.check?.property ?? '', + ...value.check!, + value: selection?.value, + }, + }); + }, + [onChange, value] + ); + + const onChangeNumericValue = useCallback( + (v?: number) => { + onChange({ + ...value, + check: { + ...value.check!, + value: v!, }, }); }, @@ -78,36 +113,57 @@ export const StyleRuleEditor: FC - - - v.value === check.operation)} + options={comparators} onChange={onChangeComparison} aria-label={'Comparison operator'} + width={6} /> - + <> + {check.operation === ComparisonOperation.EQ && ( +