mirror of
https://github.com/grafana/grafana.git
synced 2025-08-03 03:13:49 +08:00
Scenes: Add ability to change panel viz type (#78477)
* Scenes: Add ability to change panel viz type --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
@ -4179,9 +4179,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Styles should be written using objects.", "3"],
|
||||
[0, 0, 0, "Styles should be written using objects.", "4"]
|
||||
],
|
||||
"public/app/features/panel/components/VizTypePicker/VizTypePicker.tsx:5381": [
|
||||
[0, 0, 0, "Styles should be written using objects.", "0"]
|
||||
],
|
||||
"public/app/features/panel/panellinks/linkSuppliers.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
@ -4,7 +4,6 @@ import { NavIndex } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import {
|
||||
getUrlSyncManager,
|
||||
SceneFlexItem,
|
||||
SceneFlexLayout,
|
||||
SceneObject,
|
||||
SceneObjectBase,
|
||||
@ -20,6 +19,8 @@ import { getDashboardUrl } from '../utils/urlBuilders';
|
||||
|
||||
import { PanelEditorRenderer } from './PanelEditorRenderer';
|
||||
import { PanelOptionsPane } from './PanelOptionsPane';
|
||||
import { PanelVizTypePicker } from './PanelVizTypePicker';
|
||||
import { VizPanelManager } from './VizPanelManager';
|
||||
|
||||
export interface PanelEditorState extends SceneObjectState {
|
||||
body: SceneObject;
|
||||
@ -32,7 +33,7 @@ export interface PanelEditorState extends SceneObjectState {
|
||||
|
||||
dashboardRef: SceneObjectRef<DashboardScene>;
|
||||
sourcePanelRef: SceneObjectRef<VizPanel>;
|
||||
panelRef: SceneObjectRef<VizPanel>;
|
||||
panelRef: SceneObjectRef<VizPanelManager>;
|
||||
}
|
||||
|
||||
export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
||||
@ -111,12 +112,13 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
||||
|
||||
export function buildPanelEditScene(dashboard: DashboardScene, panel: VizPanel): PanelEditor {
|
||||
const panelClone = panel.clone();
|
||||
const vizPanelMgr = new VizPanelManager(panelClone);
|
||||
const dashboardStateCloned = sceneUtils.cloneSceneObjectState(dashboard.state);
|
||||
|
||||
return new PanelEditor({
|
||||
dashboardRef: dashboard.getRef(),
|
||||
sourcePanelRef: panel.getRef(),
|
||||
panelRef: panelClone.getRef(),
|
||||
panelRef: vizPanelMgr.getRef(),
|
||||
controls: dashboardStateCloned.controls,
|
||||
$variables: dashboardStateCloned.$variables,
|
||||
$timeRange: dashboardStateCloned.$timeRange,
|
||||
@ -124,11 +126,11 @@ export function buildPanelEditScene(dashboard: DashboardScene, panel: VizPanel):
|
||||
direction: 'row',
|
||||
primary: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [panelClone],
|
||||
children: [vizPanelMgr],
|
||||
}),
|
||||
secondary: new SceneFlexItem({
|
||||
width: '300px',
|
||||
body: new PanelOptionsPane(panelClone),
|
||||
secondary: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [new PanelOptionsPane(vizPanelMgr), new PanelVizTypePicker(vizPanelMgr)],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
@ -2,22 +2,25 @@ import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
|
||||
import { Field, Input, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { VizPanelManager } from './VizPanelManager';
|
||||
|
||||
export interface PanelOptionsPaneState extends SceneObjectState {}
|
||||
|
||||
export class PanelOptionsPane extends SceneObjectBase<PanelOptionsPaneState> {
|
||||
public panel: VizPanel;
|
||||
public panelManager: VizPanelManager;
|
||||
|
||||
public constructor(panel: VizPanel) {
|
||||
public constructor(panelMgr: VizPanelManager) {
|
||||
super({});
|
||||
|
||||
this.panel = panel;
|
||||
this.panelManager = panelMgr;
|
||||
}
|
||||
|
||||
static Component = ({ model }: SceneComponentProps<PanelOptionsPane>) => {
|
||||
const { panel } = model;
|
||||
const { panelManager } = model;
|
||||
const { panel } = panelManager.state;
|
||||
const { title } = panel.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
@ -37,9 +40,6 @@ function getStyles(theme: GrafanaTheme2) {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: theme.spacing(2),
|
||||
flexBasis: '100%',
|
||||
flexGrow: 1,
|
||||
minHeight: 0,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
|
||||
import { CustomScrollbar, FilterInput, useStyles2 } from '@grafana/ui';
|
||||
import { VizTypePicker } from 'app/features/panel/components/VizTypePicker/VizTypePicker';
|
||||
|
||||
import { VizPanelManager } from './VizPanelManager';
|
||||
|
||||
export interface PanelVizTypePickerState extends SceneObjectState {}
|
||||
|
||||
export class PanelVizTypePicker extends SceneObjectBase<PanelVizTypePickerState> {
|
||||
public constructor(public panelManager: VizPanelManager) {
|
||||
super({});
|
||||
}
|
||||
|
||||
static Component = ({ model }: SceneComponentProps<PanelVizTypePicker>) => {
|
||||
const { panelManager } = model;
|
||||
const { panel } = panelManager.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
return (
|
||||
<CustomScrollbar autoHeightMin="100%">
|
||||
<div className={styles.wrapper}>
|
||||
<FilterInput value={searchQuery} onChange={setSearchQuery} autoFocus={true} placeholder="Search for..." />
|
||||
<VizTypePicker
|
||||
pluginId={panel.state.pluginId}
|
||||
searchQuery={searchQuery}
|
||||
onChange={(options) => {
|
||||
panelManager.changePluginType(options.pluginId);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
wrapper: css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(1),
|
||||
}),
|
||||
});
|
@ -0,0 +1,77 @@
|
||||
import { FieldConfigSource } from '@grafana/data';
|
||||
import { DeepPartial, SceneQueryRunner, VizPanel } from '@grafana/scenes';
|
||||
|
||||
import { VizPanelManager } from './VizPanelManager';
|
||||
|
||||
describe('VizPanelManager', () => {
|
||||
describe('changePluginType', () => {
|
||||
it('Should successfully change from one viz type to another', () => {
|
||||
const vizPanelManager = getVizPanelManager();
|
||||
expect(vizPanelManager.state.panel.state.pluginId).toBe('table');
|
||||
vizPanelManager.changePluginType('timeseries');
|
||||
expect(vizPanelManager.state.panel.state.pluginId).toBe('timeseries');
|
||||
});
|
||||
|
||||
it('Should clear custom options', () => {
|
||||
const overrides = [
|
||||
{
|
||||
matcher: { id: 'matcherOne' },
|
||||
properties: [{ id: 'custom.propertyOne' }, { id: 'custom.propertyTwo' }, { id: 'standardProperty' }],
|
||||
},
|
||||
];
|
||||
const vizPanelManager = getVizPanelManager(undefined, {
|
||||
defaults: {
|
||||
custom: 'Custom',
|
||||
},
|
||||
overrides,
|
||||
});
|
||||
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.defaults.custom).toBe('Custom');
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.overrides).toBe(overrides);
|
||||
|
||||
vizPanelManager.changePluginType('timeseries');
|
||||
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.defaults.custom).toStrictEqual({});
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.overrides[0].properties).toHaveLength(1);
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.overrides[0].properties[0].id).toBe('standardProperty');
|
||||
});
|
||||
|
||||
it('Should restore cached options/fieldConfig if they exist', () => {
|
||||
const vizPanelManager = getVizPanelManager(
|
||||
{
|
||||
customOption: 'A',
|
||||
},
|
||||
{ defaults: { custom: 'Custom' }, overrides: [] }
|
||||
);
|
||||
|
||||
vizPanelManager.changePluginType('timeseries');
|
||||
//@ts-ignore
|
||||
expect(vizPanelManager.state.panel.state.options['customOption']).toBeUndefined();
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.defaults.custom).toStrictEqual({});
|
||||
|
||||
vizPanelManager.changePluginType('table');
|
||||
|
||||
//@ts-ignore
|
||||
expect(vizPanelManager.state.panel.state.options['customOption']).toBe('A');
|
||||
expect(vizPanelManager.state.panel.state.fieldConfig.defaults.custom).toBe('Custom');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getVizPanelManager(
|
||||
options: {} = {},
|
||||
fieldConfig: FieldConfigSource<DeepPartial<{}>> = { overrides: [], defaults: {} }
|
||||
) {
|
||||
const vizPanel = new VizPanel({
|
||||
title: 'Panel A',
|
||||
key: 'panel-1',
|
||||
pluginId: 'table',
|
||||
$data: new SceneQueryRunner({ key: 'data-query-runner', queries: [{ refId: 'A' }] }),
|
||||
options,
|
||||
fieldConfig,
|
||||
});
|
||||
|
||||
const vizPanelManager = new VizPanelManager(vizPanel);
|
||||
|
||||
return vizPanelManager;
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
FieldConfigSource,
|
||||
PanelModel,
|
||||
filterFieldConfigOverrides,
|
||||
isStandardFieldProp,
|
||||
restoreCustomOverrideRules,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
SceneObjectState,
|
||||
VizPanel,
|
||||
SceneObjectBase,
|
||||
SceneComponentProps,
|
||||
sceneUtils,
|
||||
DeepPartial,
|
||||
} from '@grafana/scenes';
|
||||
import { getPluginVersion } from 'app/features/dashboard/state/PanelModel';
|
||||
|
||||
interface VizPanelManagerState extends SceneObjectState {
|
||||
panel: VizPanel;
|
||||
}
|
||||
|
||||
export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
|
||||
private _cachedPluginOptions: Record<
|
||||
string,
|
||||
{ options: DeepPartial<{}>; fieldConfig: FieldConfigSource<DeepPartial<{}>> } | undefined
|
||||
> = {};
|
||||
|
||||
public constructor(panel: VizPanel) {
|
||||
super({ panel });
|
||||
}
|
||||
|
||||
public changePluginType(pluginType: string) {
|
||||
const {
|
||||
options: prevOptions,
|
||||
fieldConfig: prevFieldConfig,
|
||||
pluginId: prevPluginId,
|
||||
...restOfOldState
|
||||
} = sceneUtils.cloneSceneObjectState(this.state.panel.state);
|
||||
|
||||
// clear custom options
|
||||
let newFieldConfig = { ...prevFieldConfig };
|
||||
newFieldConfig.defaults = {
|
||||
...newFieldConfig.defaults,
|
||||
custom: {},
|
||||
};
|
||||
newFieldConfig.overrides = filterFieldConfigOverrides(newFieldConfig.overrides, isStandardFieldProp);
|
||||
|
||||
this._cachedPluginOptions[prevPluginId] = { options: prevOptions, fieldConfig: prevFieldConfig };
|
||||
const cachedOptions = this._cachedPluginOptions[pluginType]?.options;
|
||||
const cachedFieldConfig = this._cachedPluginOptions[pluginType]?.fieldConfig;
|
||||
if (cachedFieldConfig) {
|
||||
newFieldConfig = restoreCustomOverrideRules(newFieldConfig, cachedFieldConfig);
|
||||
}
|
||||
|
||||
const newPanel = new VizPanel({
|
||||
options: cachedOptions ?? {},
|
||||
fieldConfig: newFieldConfig,
|
||||
pluginId: pluginType,
|
||||
...restOfOldState,
|
||||
});
|
||||
|
||||
const newPlugin = newPanel.getPlugin();
|
||||
const panel: PanelModel = {
|
||||
title: newPanel.state.title,
|
||||
options: newPanel.state.options,
|
||||
fieldConfig: newPanel.state.fieldConfig,
|
||||
id: 1,
|
||||
type: pluginType,
|
||||
};
|
||||
const newOptions = newPlugin?.onPanelTypeChanged?.(panel, prevPluginId, prevOptions, prevFieldConfig);
|
||||
if (newOptions) {
|
||||
newPanel.onOptionsChange(newOptions, true);
|
||||
}
|
||||
|
||||
if (newPlugin?.onPanelMigration) {
|
||||
newPanel.setState({ pluginVersion: getPluginVersion(newPlugin) });
|
||||
}
|
||||
|
||||
this.setState({ panel: newPanel });
|
||||
}
|
||||
|
||||
public static Component = ({ model }: SceneComponentProps<VizPanelManager>) => {
|
||||
const { panel } = model.useState();
|
||||
|
||||
return <panel.Component model={panel} />;
|
||||
};
|
||||
}
|
@ -9,6 +9,7 @@ import {
|
||||
} from '@grafana/scenes';
|
||||
import { initialIntervalVariableModelState } from 'app/features/variables/interval/reducer';
|
||||
|
||||
import { PanelEditor } from '../panel-edit/PanelEditor';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
|
||||
export function getVizPanelKeyForPanelId(panelId: number) {
|
||||
@ -164,6 +165,11 @@ export function getQueryRunnerFor(sceneObject: SceneObject | undefined): SceneQu
|
||||
|
||||
export function getDashboardSceneFor(sceneObject: SceneObject): DashboardScene {
|
||||
const root = sceneObject.getRoot();
|
||||
|
||||
if (root instanceof PanelEditor) {
|
||||
return root.state.dashboardRef.resolve();
|
||||
}
|
||||
|
||||
if (root instanceof DashboardScene) {
|
||||
return root;
|
||||
}
|
||||
|
@ -115,34 +115,14 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
|
||||
<CustomScrollbar autoHeightMin="100%">
|
||||
<div className={styles.scrollContent}>
|
||||
{listMode === VisualizationSelectPaneTab.Visualizations && (
|
||||
<VizTypePicker
|
||||
current={plugin.meta}
|
||||
onChange={onVizChange}
|
||||
searchQuery={searchQuery}
|
||||
data={data}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
<VizTypePicker pluginId={plugin.meta.id} onChange={onVizChange} searchQuery={searchQuery} />
|
||||
)}
|
||||
{listMode === VisualizationSelectPaneTab.Widgets && (
|
||||
<VizTypePicker
|
||||
current={plugin.meta}
|
||||
onChange={onVizChange}
|
||||
searchQuery={searchQuery}
|
||||
data={data}
|
||||
onClose={() => {}}
|
||||
isWidget
|
||||
/>
|
||||
<VizTypePicker pluginId={plugin.meta.id} onChange={onVizChange} searchQuery={searchQuery} isWidget />
|
||||
)}
|
||||
|
||||
{listMode === VisualizationSelectPaneTab.Suggestions && (
|
||||
<VisualizationSuggestions
|
||||
current={plugin.meta}
|
||||
onChange={onVizChange}
|
||||
searchQuery={searchQuery}
|
||||
panel={panel}
|
||||
data={data}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
<VisualizationSuggestions onChange={onVizChange} searchQuery={searchQuery} panel={panel} data={data} />
|
||||
)}
|
||||
{listMode === VisualizationSelectPaneTab.LibraryPanels && (
|
||||
<PanelLibraryOptionsGroup
|
||||
|
@ -694,7 +694,7 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
||||
}
|
||||
}
|
||||
|
||||
function getPluginVersion(plugin: PanelPlugin): string {
|
||||
export function getPluginVersion(plugin: PanelPlugin): string {
|
||||
return plugin && plugin.meta.info.version ? plugin.meta.info.version : config.buildInfo.version;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import { GrafanaTheme2, PanelData, PanelPluginMeta, PanelModel, VisualizationSuggestion } from '@grafana/data';
|
||||
import { GrafanaTheme2, PanelData, PanelModel, VisualizationSuggestion } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { getAllSuggestions } from '../../state/getAllSuggestions';
|
||||
@ -12,15 +12,13 @@ import { VisualizationSuggestionCard } from './VisualizationSuggestionCard';
|
||||
import { VizTypeChangeDetails } from './types';
|
||||
|
||||
export interface Props {
|
||||
current: PanelPluginMeta;
|
||||
searchQuery: string;
|
||||
onChange: (options: VizTypeChangeDetails) => void;
|
||||
data?: PanelData;
|
||||
panel?: PanelModel;
|
||||
onChange: (options: VizTypeChangeDetails) => void;
|
||||
searchQuery: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function VisualizationSuggestions({ onChange, data, panel, searchQuery }: Props) {
|
||||
export function VisualizationSuggestions({ searchQuery, onChange, data, panel }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { value: suggestions } = useAsync(() => getAllSuggestions(data, panel), [data, panel]);
|
||||
const filteredSuggestions = filterSuggestionsBySearch(searchQuery, suggestions);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { GrafanaTheme2, PanelData, PanelPluginMeta } from '@grafana/data';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { EmptySearchResult, useStyles2 } from '@grafana/ui';
|
||||
|
||||
@ -11,29 +11,25 @@ import { VizTypePickerPlugin } from './VizTypePickerPlugin';
|
||||
import { VizTypeChangeDetails } from './types';
|
||||
|
||||
export interface Props {
|
||||
current: PanelPluginMeta;
|
||||
data?: PanelData;
|
||||
onChange: (options: VizTypeChangeDetails) => void;
|
||||
pluginId: string;
|
||||
searchQuery: string;
|
||||
onClose: () => void;
|
||||
onChange: (options: VizTypeChangeDetails) => void;
|
||||
isWidget?: boolean;
|
||||
}
|
||||
|
||||
export function VizTypePicker({ searchQuery, onChange, current, data, isWidget = false }: Props) {
|
||||
export function VizTypePicker({ pluginId, searchQuery, onChange, isWidget = false }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const pluginsList: PanelPluginMeta[] = useMemo(() => {
|
||||
const pluginsList = useMemo(() => {
|
||||
if (config.featureToggles.vizAndWidgetSplit) {
|
||||
if (isWidget) {
|
||||
return getWidgetPluginMeta();
|
||||
}
|
||||
return getVizPluginMeta();
|
||||
return isWidget ? getWidgetPluginMeta() : getVizPluginMeta();
|
||||
}
|
||||
return getAllPanelPluginMeta();
|
||||
}, [isWidget]);
|
||||
|
||||
const filteredPluginTypes = useMemo((): PanelPluginMeta[] => {
|
||||
return filterPluginList(pluginsList, searchQuery, current);
|
||||
}, [current, pluginsList, searchQuery]);
|
||||
const filteredPluginTypes = useMemo(
|
||||
() => filterPluginList(pluginsList, searchQuery, pluginId),
|
||||
[pluginsList, searchQuery, pluginId]
|
||||
);
|
||||
|
||||
if (filteredPluginTypes.length === 0) {
|
||||
return <EmptySearchResult>Could not find anything matching your query</EmptySearchResult>;
|
||||
@ -41,16 +37,16 @@ export function VizTypePicker({ searchQuery, onChange, current, data, isWidget =
|
||||
|
||||
return (
|
||||
<div className={styles.grid}>
|
||||
{filteredPluginTypes.map((plugin, index) => (
|
||||
{filteredPluginTypes.map((plugin) => (
|
||||
<VizTypePickerPlugin
|
||||
disabled={false}
|
||||
key={plugin.id}
|
||||
isCurrent={plugin.id === current.id}
|
||||
isCurrent={plugin.id === pluginId}
|
||||
plugin={plugin}
|
||||
onClick={(e) =>
|
||||
onChange({
|
||||
pluginId: plugin.id,
|
||||
withModKey: Boolean(e.metaKey || e.ctrlKey || e.altKey),
|
||||
withModKey: e.metaKey || e.ctrlKey || e.altKey,
|
||||
})
|
||||
}
|
||||
/>
|
||||
@ -59,16 +55,14 @@ export function VizTypePicker({ searchQuery, onChange, current, data, isWidget =
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
grid: css`
|
||||
max-width: 100%;
|
||||
display: grid;
|
||||
grid-gap: ${theme.spacing(0.5)};
|
||||
`,
|
||||
heading: css({
|
||||
...theme.typography.h5,
|
||||
margin: theme.spacing(0, 0.5, 1),
|
||||
}),
|
||||
};
|
||||
};
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
grid: css({
|
||||
maxWidth: '100%',
|
||||
display: 'grid',
|
||||
gridGap: theme.spacing(0.5),
|
||||
}),
|
||||
heading: css({
|
||||
...theme.typography.h5,
|
||||
margin: theme.spacing(0, 0.5, 1),
|
||||
}),
|
||||
});
|
||||
|
@ -21,12 +21,12 @@ export function getVizPluginMeta(): PanelPluginMeta[] {
|
||||
export function filterPluginList(
|
||||
pluginsList: PanelPluginMeta[],
|
||||
searchQuery: string, // Note: this will be an escaped regex string as it comes from `FilterInput`
|
||||
current?: PanelPluginMeta
|
||||
pluginId?: string
|
||||
): PanelPluginMeta[] {
|
||||
if (!searchQuery.length) {
|
||||
return pluginsList.filter((p) => {
|
||||
if (p.state === PluginState.deprecated) {
|
||||
return current?.id === p.id;
|
||||
return pluginId === p.id;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@ -38,7 +38,7 @@ export function filterPluginList(
|
||||
const isGraphQuery = 'graph'.startsWith(query);
|
||||
|
||||
for (const item of pluginsList) {
|
||||
if (item.state === PluginState.deprecated && current?.id !== item.id) {
|
||||
if (item.state === PluginState.deprecated && pluginId !== item.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ describe('panel state utils', () => {
|
||||
{ id: 'timeseries', name: 'Graph (old)' },
|
||||
{ id: 'timeline', name: 'Timeline' },
|
||||
] as PanelPluginMeta[];
|
||||
const found = filterPluginList(pluginsList, escapeStringForRegex('gra'), { id: 'xyz' } as PanelPluginMeta);
|
||||
const found = filterPluginList(pluginsList, escapeStringForRegex('gra'), 'xyz');
|
||||
expect(found.map((v) => v.id)).toEqual(['graph', 'timeseries']);
|
||||
});
|
||||
|
||||
@ -20,7 +20,7 @@ describe('panel state utils', () => {
|
||||
{ id: 'timeline', name: 'Timeline' },
|
||||
{ id: 'panelwithdashes', name: 'Panel-With-Dashes' },
|
||||
] as PanelPluginMeta[];
|
||||
const found = filterPluginList(pluginsList, escapeStringForRegex('panel-'), { id: 'xyz' } as PanelPluginMeta);
|
||||
const found = filterPluginList(pluginsList, escapeStringForRegex('panel-'), 'xyz');
|
||||
expect(found.map((v) => v.id)).toEqual(['panelwithdashes']);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user