diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx index 1f20a550608..9e0e23c5cb5 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx @@ -3,8 +3,9 @@ import React, { useMemo, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes'; +import { SceneComponentProps, SceneObjectBase, SceneObjectState, sceneGraph } from '@grafana/scenes'; import { ButtonGroup, FilterInput, RadioButtonGroup, ToolbarButton, useStyles2 } from '@grafana/ui'; +import { getFieldOverrideCategories } from 'app/features/dashboard/components/PanelEditor/getFieldOverrideElements'; import { getPanelFrameCategory2 } from 'app/features/dashboard/components/PanelEditor/getPanelFrameOptions'; import { getVisualizationOptions2 } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions'; import { getAllPanelPluginMeta } from 'app/features/panel/state/util'; @@ -26,9 +27,13 @@ export class PanelOptionsPane extends SceneObjectBase { static Component = ({ model }: SceneComponentProps) => { const { panelManager } = model; const { panel } = panelManager.state; - const { pluginId, options } = panel.useState(); + const dataObject = sceneGraph.getData(panel); + const rawData = dataObject.useState(); + const dataWithFieldConfig = panel.applyFieldConfig(rawData.data!); + const { pluginId, options, fieldConfig } = panel.useState(); const styles = useStyles2(getStyles); const [isVizPickerOpen, setVizPickerOpen] = useState(true); + const [searchQuery, setSearchQuery] = useState(''); const panelFrameOptions = useMemo(() => getPanelFrameCategory2(panel), [panel]); const visualizationOptions = useMemo(() => { @@ -44,9 +49,30 @@ export class PanelOptionsPane extends SceneObjectBase { instanceState: panel.getPanelContext().instanceState!, }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [panel, options]); + }, [panel, options, fieldConfig]); - const mainBoxElements = [panelFrameOptions.render(), ...(visualizationOptions?.map((v) => v.render()) ?? [])]; + const justOverrides = useMemo( + () => + getFieldOverrideCategories( + fieldConfig, + panel.getPlugin()?.fieldConfigRegistry!, + dataWithFieldConfig.series, + searchQuery, + (newConfig) => { + panel.setState({ + fieldConfig: newConfig, + }); + } + ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [searchQuery, panel, fieldConfig] + ); + + const mainBoxElements = [ + panelFrameOptions.render(), + ...(visualizationOptions?.map((v) => v.render()) ?? []), + ...justOverrides.map((v) => v.render()), + ]; return (
@@ -67,9 +93,9 @@ export class PanelOptionsPane extends SceneObjectBase {
{}} + onChange={setSearchQuery} /> { ); const justOverrides = useMemo( - () => getFieldOverrideCategories(props, searchQuery), + () => + getFieldOverrideCategories( + props.panel.fieldConfig, + props.plugin.fieldConfigRegistry, + props.data?.series ?? [], + searchQuery, + props.onFieldConfigsChange + ), // eslint-disable-next-line react-hooks/exhaustive-deps [panel.configRev, props.data, props.instanceState, searchQuery] ); diff --git a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx index b4c63f426f9..eca2153ba77 100644 --- a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx +++ b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx @@ -11,6 +11,8 @@ import { ConfigOverrideRule, GrafanaTheme2, fieldMatchers, + FieldConfigSource, + DataFrame, } from '@grafana/data'; import { fieldMatchersUI, useStyles2, ValuePicker } from '@grafana/ui'; import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv'; @@ -19,31 +21,31 @@ import { DynamicConfigValueEditor } from './DynamicConfigValueEditor'; import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor'; import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor'; import { OverrideCategoryTitle } from './OverrideCategoryTitle'; -import { OptionPaneRenderProps } from './types'; export function getFieldOverrideCategories( - props: OptionPaneRenderProps, - searchQuery: string + fieldConfig: FieldConfigSource, + registry: FieldConfigOptionsRegistry, + data: DataFrame[], + searchQuery: string, + onFieldConfigsChange: (config: FieldConfigSource) => void ): OptionsPaneCategoryDescriptor[] { const categories: OptionsPaneCategoryDescriptor[] = []; - const currentFieldConfig = props.panel.fieldConfig; - const registry = props.plugin.fieldConfigRegistry; - const data = props.data?.series ?? []; + const currentFieldConfig = fieldConfig; - if (registry.isEmpty()) { + if (!registry || registry.isEmpty()) { return []; } const onOverrideChange = (index: number, override: ConfigOverrideRule) => { let overrides = cloneDeep(currentFieldConfig.overrides); overrides[index] = override; - props.onFieldConfigsChange({ ...currentFieldConfig, overrides }); + onFieldConfigsChange({ ...currentFieldConfig, overrides }); }; const onOverrideRemove = (overrideIndex: number) => { let overrides = cloneDeep(currentFieldConfig.overrides); overrides.splice(overrideIndex, 1); - props.onFieldConfigsChange({ ...currentFieldConfig, overrides }); + onFieldConfigsChange({ ...currentFieldConfig, overrides }); }; const onOverrideAdd = (value: SelectableValue) => { @@ -52,7 +54,7 @@ export function getFieldOverrideCategories( return; } - props.onFieldConfigsChange({ + onFieldConfigsChange({ ...currentFieldConfig, overrides: [ ...currentFieldConfig.overrides, @@ -135,7 +137,7 @@ export function getFieldOverrideCategories(