Scenes: Add support for panel overrides (#81470)

This commit is contained in:
kay delaney 2024-01-30 19:29:46 +00:00 committed by GitHub
parent 80afc8202d
commit 0f6380b76a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 18 deletions

View File

@ -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<PanelOptionsPaneState> {
static Component = ({ model }: SceneComponentProps<PanelOptionsPane>) => {
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<PanelOptionsPaneState> {
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 (
<div className={styles.wrapper}>
@ -67,9 +93,9 @@ export class PanelOptionsPane extends SceneObjectBase<PanelOptionsPaneState> {
<div className={styles.top}>
<FilterInput
className={styles.searchOptions}
value={''}
value={searchQuery}
placeholder="Search options"
onChange={() => {}}
onChange={setSearchQuery}
/>
<RadioButtonGroup
options={[

View File

@ -33,7 +33,14 @@ export const OptionsPaneOptions = (props: OptionPaneRenderProps) => {
);
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]
);

View File

@ -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<string>) => {
@ -52,7 +54,7 @@ export function getFieldOverrideCategories(
return;
}
props.onFieldConfigsChange({
onFieldConfigsChange({
...currentFieldConfig,
overrides: [
...currentFieldConfig.overrides,
@ -135,7 +137,7 @@ export function getFieldOverrideCategories(
<matcherUi.component
id={`${matcherUi.matcher.id}-${idx}`}
matcher={matcherUi.matcher}
data={props.data?.series ?? []}
data={data ?? []}
options={override.matcher.options}
onChange={onMatcherConfigChange}
/>