mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Closes #42118
Co-authored-by: kay delaney <kay@grafana.com>
Co-authored-by: Josh Hunt <josh@trtr.co>
Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
(cherry picked from commit df22828d7d
)
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
This commit is contained in:
parent
61df5b04b3
commit
5e74062b4b
@ -2,7 +2,7 @@ import React, { useMemo, useState } from 'react';
|
|||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { CustomScrollbar, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
import { CustomScrollbar, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
||||||
import { getPanelFrameCategory } from './getPanelFrameOptions';
|
import { getPanelFrameCategory } from './getPanelFrameOptions';
|
||||||
import { getVizualizationOptions } from './getVizualizationOptions';
|
import { getVisualizationOptions } from './getVisualizationOptions';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { OptionsPaneCategory } from './OptionsPaneCategory';
|
import { OptionsPaneCategory } from './OptionsPaneCategory';
|
||||||
import { getFieldOverrideCategories } from './getFieldOverrideElements';
|
import { getFieldOverrideCategories } from './getFieldOverrideElements';
|
||||||
@ -21,7 +21,7 @@ export const OptionsPaneOptions: React.FC<OptionPaneRenderProps> = (props) => {
|
|||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
const [panelFrameOptions, vizOptions, libraryPanelOptions] = useMemo(
|
const [panelFrameOptions, vizOptions, libraryPanelOptions] = useMemo(
|
||||||
() => [getPanelFrameCategory(props), getVizualizationOptions(props), getLibraryPanelOptionsCategory(props)],
|
() => [getPanelFrameCategory(props), getVisualizationOptions(props), getLibraryPanelOptionsCategory(props)],
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[panel.configRev, props.data, props.instanceState, searchQuery]
|
[panel.configRev, props.data, props.instanceState, searchQuery]
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
import { EventBusSrv, FieldType, getDefaultTimeRange, LoadingState, toDataFrame } from '@grafana/data';
|
||||||
|
import { getStandardEditorContext } from './getVisualizationOptions';
|
||||||
|
|
||||||
|
describe('getStandardEditorContext', () => {
|
||||||
|
it('defaults the series data to an empty array', () => {
|
||||||
|
const editorContext = getStandardEditorContext({
|
||||||
|
data: undefined,
|
||||||
|
replaceVariables: jest.fn(),
|
||||||
|
options: {},
|
||||||
|
eventBus: new EventBusSrv(),
|
||||||
|
instanceState: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(editorContext.data).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns suggestions for empty data', () => {
|
||||||
|
const editorContext = getStandardEditorContext({
|
||||||
|
data: undefined,
|
||||||
|
replaceVariables: jest.fn(),
|
||||||
|
options: {},
|
||||||
|
eventBus: new EventBusSrv(),
|
||||||
|
instanceState: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(editorContext.getSuggestions).toBeDefined();
|
||||||
|
expect(editorContext.getSuggestions?.()).toEqual([
|
||||||
|
{
|
||||||
|
documentation: 'Name of the series',
|
||||||
|
label: 'Name',
|
||||||
|
origin: 'series',
|
||||||
|
value: '__series.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Field name of the clicked datapoint (in ms epoch)',
|
||||||
|
label: 'Name',
|
||||||
|
origin: 'field',
|
||||||
|
value: '__field.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Adds current variables',
|
||||||
|
label: 'All variables',
|
||||||
|
origin: 'template',
|
||||||
|
value: '__all_variables',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Adds current time range',
|
||||||
|
label: 'Time range',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__url_time_range',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: "Adds current time range's from value",
|
||||||
|
label: 'Time range: from',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__from',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: "Adds current time range's to value",
|
||||||
|
label: 'Time range: to',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__to',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns suggestions for non-empty data', () => {
|
||||||
|
const series = [
|
||||||
|
toDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time },
|
||||||
|
{ name: 'score', type: FieldType.number },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const panelData = {
|
||||||
|
series,
|
||||||
|
timeRange: getDefaultTimeRange(),
|
||||||
|
state: LoadingState.Done,
|
||||||
|
};
|
||||||
|
|
||||||
|
const editorContext = getStandardEditorContext({
|
||||||
|
data: panelData,
|
||||||
|
replaceVariables: jest.fn(),
|
||||||
|
options: {},
|
||||||
|
eventBus: new EventBusSrv(),
|
||||||
|
instanceState: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(editorContext.getSuggestions).toBeDefined();
|
||||||
|
expect(editorContext.getSuggestions?.()).toEqual([
|
||||||
|
{
|
||||||
|
documentation: 'Name of the series',
|
||||||
|
label: 'Name',
|
||||||
|
origin: 'series',
|
||||||
|
value: '__series.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Field name of the clicked datapoint (in ms epoch)',
|
||||||
|
label: 'Name',
|
||||||
|
origin: 'field',
|
||||||
|
value: '__field.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Formatted value for time on the same row',
|
||||||
|
label: 'time',
|
||||||
|
origin: 'fields',
|
||||||
|
value: '__data.fields.time',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Formatted value for score on the same row',
|
||||||
|
label: 'score',
|
||||||
|
origin: 'fields',
|
||||||
|
value: '__data.fields.score',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Enter the field order',
|
||||||
|
label: 'Select by index',
|
||||||
|
origin: 'fields',
|
||||||
|
value: '__data.fields[0]',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'the numeric field value',
|
||||||
|
label: 'Show numeric value',
|
||||||
|
origin: 'fields',
|
||||||
|
value: '__data.fields.score.numeric',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'the text value',
|
||||||
|
label: 'Show text value',
|
||||||
|
origin: 'fields',
|
||||||
|
value: '__data.fields.score.text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Adds current variables',
|
||||||
|
label: 'All variables',
|
||||||
|
origin: 'template',
|
||||||
|
value: '__all_variables',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: 'Adds current time range',
|
||||||
|
label: 'Time range',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__url_time_range',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: "Adds current time range's from value",
|
||||||
|
label: 'Time range: from',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__from',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
documentation: "Adds current time range's to value",
|
||||||
|
label: 'Time range: to',
|
||||||
|
origin: 'built-in',
|
||||||
|
value: '__to',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
@ -1,9 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StandardEditorContext, VariableSuggestionsScope } from '@grafana/data';
|
import {
|
||||||
|
EventBus,
|
||||||
|
InterpolateFunction,
|
||||||
|
PanelData,
|
||||||
|
StandardEditorContext,
|
||||||
|
VariableSuggestionsScope,
|
||||||
|
} from '@grafana/data';
|
||||||
import { get as lodashGet } from 'lodash';
|
import { get as lodashGet } from 'lodash';
|
||||||
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
|
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
|
||||||
import { OptionPaneRenderProps } from './types';
|
import { OptionPaneRenderProps } from './types';
|
||||||
import { updateDefaultFieldConfigValue, setOptionImmutably } from './utils';
|
import { setOptionImmutably, updateDefaultFieldConfigValue } from './utils';
|
||||||
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
|
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
|
||||||
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
|
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
|
||||||
import {
|
import {
|
||||||
@ -16,22 +22,48 @@ import { getOptionOverrides } from './state/getOptionOverrides';
|
|||||||
|
|
||||||
type categoryGetter = (categoryNames?: string[]) => OptionsPaneCategoryDescriptor;
|
type categoryGetter = (categoryNames?: string[]) => OptionsPaneCategoryDescriptor;
|
||||||
|
|
||||||
export function getVizualizationOptions(props: OptionPaneRenderProps): OptionsPaneCategoryDescriptor[] {
|
interface GetStandardEditorContextProps {
|
||||||
|
data: PanelData | undefined;
|
||||||
|
replaceVariables: InterpolateFunction;
|
||||||
|
options: Record<string, unknown>;
|
||||||
|
eventBus: EventBus;
|
||||||
|
instanceState: OptionPaneRenderProps['instanceState'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStandardEditorContext({
|
||||||
|
data,
|
||||||
|
replaceVariables,
|
||||||
|
options,
|
||||||
|
eventBus,
|
||||||
|
instanceState,
|
||||||
|
}: GetStandardEditorContextProps): StandardEditorContext<unknown, unknown> {
|
||||||
|
const dataSeries = data?.series ?? [];
|
||||||
|
|
||||||
|
const context: StandardEditorContext<unknown, unknown> = {
|
||||||
|
data: dataSeries,
|
||||||
|
replaceVariables,
|
||||||
|
options,
|
||||||
|
eventBus,
|
||||||
|
getSuggestions: (scope?: VariableSuggestionsScope) => getDataLinksVariableSuggestions(dataSeries, scope),
|
||||||
|
instanceState,
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVisualizationOptions(props: OptionPaneRenderProps): OptionsPaneCategoryDescriptor[] {
|
||||||
const { plugin, panel, onPanelOptionsChanged, onFieldConfigsChange, data, dashboard, instanceState } = props;
|
const { plugin, panel, onPanelOptionsChanged, onFieldConfigsChange, data, dashboard, instanceState } = props;
|
||||||
const currentOptions = panel.getOptions();
|
const currentOptions = panel.getOptions();
|
||||||
const currentFieldConfig = panel.fieldConfig;
|
const currentFieldConfig = panel.fieldConfig;
|
||||||
const categoryIndex: Record<string, OptionsPaneCategoryDescriptor> = {};
|
const categoryIndex: Record<string, OptionsPaneCategoryDescriptor> = {};
|
||||||
|
|
||||||
const context: StandardEditorContext<any, any> = {
|
const context = getStandardEditorContext({
|
||||||
data: data?.series || [],
|
data,
|
||||||
replaceVariables: panel.replaceVariables,
|
replaceVariables: panel.replaceVariables,
|
||||||
options: currentOptions,
|
options: currentOptions,
|
||||||
eventBus: dashboard.events,
|
eventBus: dashboard.events,
|
||||||
getSuggestions: (scope?: VariableSuggestionsScope) => {
|
|
||||||
return data ? getDataLinksVariableSuggestions(data.series, scope) : [];
|
|
||||||
},
|
|
||||||
instanceState,
|
instanceState,
|
||||||
};
|
});
|
||||||
|
|
||||||
const getOptionsPaneCategory = (categoryNames?: string[]): OptionsPaneCategoryDescriptor => {
|
const getOptionsPaneCategory = (categoryNames?: string[]): OptionsPaneCategoryDescriptor => {
|
||||||
const categoryName = (categoryNames && categoryNames[0]) ?? `${plugin.meta.name}`;
|
const categoryName = (categoryNames && categoryNames[0]) ?? `${plugin.meta.name}`;
|
Loading…
Reference in New Issue
Block a user