Scenes/PanelEditor: Fix panel options search crash (#82003)

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
kay delaney 2024-02-07 14:09:21 +00:00 committed by GitHub
parent 00aa876e46
commit 114e9e90f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 21 deletions

View File

@ -5,7 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { SceneComponentProps, SceneObjectBase, SceneObjectState, sceneGraph } from '@grafana/scenes'; import { SceneComponentProps, SceneObjectBase, SceneObjectState, sceneGraph } from '@grafana/scenes';
import { ButtonGroup, FilterInput, RadioButtonGroup, ToolbarButton, useStyles2 } from '@grafana/ui'; import { ButtonGroup, FilterInput, RadioButtonGroup, ToolbarButton, useStyles2 } from '@grafana/ui';
import { OptionFilter, renderSearchHits } from 'app/features/dashboard/components/PanelEditor/OptionsPaneOptions'; import { OptionFilter, RenderSearchHits } from 'app/features/dashboard/components/PanelEditor/OptionsPaneOptions';
import { getFieldOverrideCategories } from 'app/features/dashboard/components/PanelEditor/getFieldOverrideElements'; import { getFieldOverrideCategories } from 'app/features/dashboard/components/PanelEditor/getFieldOverrideElements';
import { getPanelFrameCategory2 } from 'app/features/dashboard/components/PanelEditor/getPanelFrameOptions'; import { getPanelFrameCategory2 } from 'app/features/dashboard/components/PanelEditor/getPanelFrameOptions';
import { getVisualizationOptions2 } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions'; import { getVisualizationOptions2 } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions';
@ -75,24 +75,29 @@ export class PanelOptionsPane extends SceneObjectBase<PanelOptionsPaneState> {
if (isSearching) { if (isSearching) {
mainBoxElements.push( mainBoxElements.push(
renderSearchHits([panelFrameOptions, ...(visualizationOptions ?? [])], justOverrides, searchQuery) <RenderSearchHits
allOptions={[panelFrameOptions, ...(visualizationOptions ?? [])]}
overrides={justOverrides}
searchQuery={searchQuery}
key="render-search-hits"
/>
); );
} else { } else {
switch (listMode) { switch (listMode) {
case OptionFilter.All: case OptionFilter.All:
mainBoxElements.push(panelFrameOptions.render()); mainBoxElements.push(<panelFrameOptions.Render key="panel-frame-options" />);
for (const item of visualizationOptions ?? []) { for (const item of visualizationOptions ?? []) {
mainBoxElements.push(item.render()); mainBoxElements.push(<item.Render key={item.props.id} />);
} }
for (const item of justOverrides) { for (const item of justOverrides) {
mainBoxElements.push(item.render()); mainBoxElements.push(<item.Render key={item.props.id} />);
} }
break; break;
case OptionFilter.Overrides: case OptionFilter.Overrides:
for (const item of justOverrides) { for (const item of justOverrides) {
mainBoxElements.push(item.render()); mainBoxElements.push(<item.Render key={item.props.id} />);
} }
default: default:
break; break;

View File

@ -52,7 +52,7 @@ export class OptionsPaneCategoryDescriptor {
return sub; return sub;
} }
render(searchQuery?: string) { Render = ({ searchQuery }: { searchQuery?: string }) => {
if (this.props.customRender) { if (this.props.customRender) {
return this.props.customRender(); return this.props.customRender();
} }
@ -60,8 +60,10 @@ export class OptionsPaneCategoryDescriptor {
return ( return (
<OptionsPaneCategory key={this.props.title} {...this.props}> <OptionsPaneCategory key={this.props.title} {...this.props}>
{this.items.map((item) => item.render(searchQuery))} {this.items.map((item) => item.render(searchQuery))}
{this.categories.map((category) => category.render(searchQuery))} {this.categories.map((category) => (
<category.Render key={category.props.id} searchQuery={searchQuery} />
))}
</OptionsPaneCategory> </OptionsPaneCategory>
); );
} };
} }

View File

@ -54,7 +54,14 @@ export const OptionsPaneOptions = (props: OptionPaneRenderProps) => {
: [panelFrameOptions, ...vizOptions]; : [panelFrameOptions, ...vizOptions];
if (isSearching) { if (isSearching) {
mainBoxElements.push(renderSearchHits(allOptions, justOverrides, searchQuery)); mainBoxElements.push(
<RenderSearchHits
key="render-search-hits"
allOptions={allOptions}
overrides={justOverrides}
searchQuery={searchQuery}
/>
);
// If searching for angular panel, then we need to add notice that results are limited // If searching for angular panel, then we need to add notice that results are limited
if (props.plugin.angularPanelCtrl) { if (props.plugin.angularPanelCtrl) {
@ -69,10 +76,10 @@ export const OptionsPaneOptions = (props: OptionPaneRenderProps) => {
case OptionFilter.All: case OptionFilter.All:
if (isPanelModelLibraryPanel(panel)) { if (isPanelModelLibraryPanel(panel)) {
// Library Panel options first // Library Panel options first
mainBoxElements.push(libraryPanelOptions.render()); mainBoxElements.push(<libraryPanelOptions.Render key="library-panel-options" />);
} }
// Panel frame options second // Panel frame options second
mainBoxElements.push(panelFrameOptions.render()); mainBoxElements.push(<panelFrameOptions.Render key="panel-frame-options" />);
// If angular add those options next // If angular add those options next
if (props.plugin.angularPanelCtrl) { if (props.plugin.angularPanelCtrl) {
mainBoxElements.push( mainBoxElements.push(
@ -81,16 +88,16 @@ export const OptionsPaneOptions = (props: OptionPaneRenderProps) => {
} }
// Then add all panel and field defaults // Then add all panel and field defaults
for (const item of vizOptions) { for (const item of vizOptions) {
mainBoxElements.push(item.render()); mainBoxElements.push(<item.Render key={item.props.id} />);
} }
for (const item of justOverrides) { for (const item of justOverrides) {
mainBoxElements.push(item.render()); mainBoxElements.push(<item.Render key={item.props.id} />);
} }
break; break;
case OptionFilter.Overrides: case OptionFilter.Overrides:
for (const override of justOverrides) { for (const override of justOverrides) {
mainBoxElements.push(override.render()); mainBoxElements.push(<override.Render key={override.props.id} />);
} }
break; break;
case OptionFilter.Recent: case OptionFilter.Recent:
@ -150,11 +157,13 @@ export enum OptionFilter {
Recent = 'Recent', Recent = 'Recent',
} }
export function renderSearchHits( interface RenderSearchHitsProps {
allOptions: OptionsPaneCategoryDescriptor[], allOptions: OptionsPaneCategoryDescriptor[];
overrides: OptionsPaneCategoryDescriptor[], overrides: OptionsPaneCategoryDescriptor[];
searchQuery: string searchQuery: string;
) { }
export function RenderSearchHits({ allOptions, overrides, searchQuery }: RenderSearchHitsProps) {
const engine = new OptionSearchEngine(allOptions, overrides); const engine = new OptionSearchEngine(allOptions, overrides);
const { optionHits, totalCount, overrideHits } = engine.search(searchQuery); const { optionHits, totalCount, overrideHits } = engine.search(searchQuery);
@ -168,7 +177,9 @@ export function renderSearchHits(
> >
{optionHits.map((hit) => hit.render(searchQuery))} {optionHits.map((hit) => hit.render(searchQuery))}
</OptionsPaneCategory> </OptionsPaneCategory>
{overrideHits.map((override) => override.render(searchQuery))} {overrideHits.map((override) => (
<override.Render key={override.props.id} searchQuery={searchQuery} />
))}
</div> </div>
); );
} }