mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
XYChart: Add data filter to manual mode (#81115)
* XYChart: Add data filter to manual mode * Add onChange to data filter for manual editor * Update placeholder for auto editor for consistency * Filter x y fields based on frame * Update frame calc for truthy * Use display name instead for frame filter * Update placeholders * Apply frame filter to series prep * Re run make gen cue * Remove old TODO * Force data filter to be selected * minor cleanup --------- Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
parent
be6efd9518
commit
6fc1a6a54f
@ -214,6 +214,7 @@ It extends [FieldConfig](#fieldconfig).
|
|||||||
| `axisSoftMax` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
| `axisSoftMax` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
||||||
| `axisSoftMin` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
| `axisSoftMin` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
||||||
| `axisWidth` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
| `axisWidth` | number | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
||||||
|
| `frame` | number | No | | |
|
||||||
| `hideFrom` | [HideSeriesConfig](#hideseriesconfig) | No | | *(Inherited from [FieldConfig](#fieldconfig))*<br/>TODO docs |
|
| `hideFrom` | [HideSeriesConfig](#hideseriesconfig) | No | | *(Inherited from [FieldConfig](#fieldconfig))*<br/>TODO docs |
|
||||||
| `labelValue` | [TextDimensionConfig](#textdimensionconfig) | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
| `labelValue` | [TextDimensionConfig](#textdimensionconfig) | No | | *(Inherited from [FieldConfig](#fieldconfig))* |
|
||||||
| `label` | string | No | | *(Inherited from [FieldConfig](#fieldconfig))*<br/>TODO docs<br/>Possible values are: `auto`, `never`, `always`. |
|
| `label` | string | No | | *(Inherited from [FieldConfig](#fieldconfig))*<br/>TODO docs<br/>Possible values are: `auto`, `never`, `always`. |
|
||||||
|
@ -57,6 +57,7 @@ export const defaultFieldConfig: Partial<FieldConfig> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface ScatterSeriesConfig extends FieldConfig {
|
export interface ScatterSeriesConfig extends FieldConfig {
|
||||||
|
frame?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
x?: string;
|
x?: string;
|
||||||
y?: string;
|
y?: string;
|
||||||
|
@ -85,7 +85,7 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
|||||||
<Select
|
<Select
|
||||||
isClearable={true}
|
isClearable={true}
|
||||||
options={frameNames}
|
options={frameNames}
|
||||||
placeholder={frameNames[0].label}
|
placeholder={'Change filter'}
|
||||||
value={frameNames.find((v) => v.value === value?.frame)}
|
value={frameNames.find((v) => v.value === value?.frame)}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
onChange({
|
onChange({
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
GrafanaTheme2,
|
GrafanaTheme2,
|
||||||
StandardEditorProps,
|
StandardEditorProps,
|
||||||
FieldNamePickerBaseNameMode,
|
FieldNamePickerBaseNameMode,
|
||||||
StandardEditorsRegistryItem,
|
StandardEditorsRegistryItem,
|
||||||
|
getFrameDisplayName,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Button, IconButton, useStyles2 } from '@grafana/ui';
|
import { Button, Field, IconButton, Select, useStyles2 } from '@grafana/ui';
|
||||||
import { LayerName } from 'app/core/components/Layers/LayerName';
|
import { LayerName } from 'app/core/components/Layers/LayerName';
|
||||||
|
|
||||||
import { ScatterSeriesEditor } from './ScatterSeriesEditor';
|
import { ScatterSeriesEditor } from './ScatterSeriesEditor';
|
||||||
@ -18,6 +19,16 @@ export const ManualEditor = ({
|
|||||||
onChange,
|
onChange,
|
||||||
context,
|
context,
|
||||||
}: StandardEditorProps<ScatterSeriesConfig[], unknown, Options>) => {
|
}: StandardEditorProps<ScatterSeriesConfig[], unknown, Options>) => {
|
||||||
|
const frameNames = useMemo(() => {
|
||||||
|
if (context?.data?.length) {
|
||||||
|
return context.data.map((frame, index) => ({
|
||||||
|
value: index,
|
||||||
|
label: `${getFrameDisplayName(frame, index)} (index: ${index}, rows: ${frame.length})`,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return [{ value: 0, label: 'First result' }];
|
||||||
|
}, [context.data]);
|
||||||
|
|
||||||
const [selected, setSelected] = useState(0);
|
const [selected, setSelected] = useState(0);
|
||||||
const style = useStyles2(getStyles);
|
const style = useStyles2(getStyles);
|
||||||
|
|
||||||
@ -101,23 +112,53 @@ export const ManualEditor = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selected >= 0 && value[selected] && (
|
{selected >= 0 && value[selected] && (
|
||||||
<ScatterSeriesEditor
|
<>
|
||||||
key={`series/${selected}`}
|
{frameNames.length > 1 && (
|
||||||
baseNameMode={FieldNamePickerBaseNameMode.ExcludeBaseNames}
|
<Field label={'Data'}>
|
||||||
item={{} as StandardEditorsRegistryItem}
|
<Select
|
||||||
context={context}
|
isClearable={false}
|
||||||
value={value[selected]}
|
options={frameNames}
|
||||||
onChange={(v) => {
|
placeholder={'Change filter'}
|
||||||
onChange(
|
value={
|
||||||
value.map((obj, i) => {
|
frameNames.find((v) => {
|
||||||
if (i === selected) {
|
return v.value === value[selected].frame;
|
||||||
return v!;
|
}) ?? 0
|
||||||
}
|
}
|
||||||
return obj;
|
onChange={(val) => {
|
||||||
})
|
onChange(
|
||||||
);
|
value.map((obj, i) => {
|
||||||
}}
|
if (i === selected) {
|
||||||
/>
|
if (val === null) {
|
||||||
|
return { ...value[i], frame: undefined };
|
||||||
|
}
|
||||||
|
return { ...value[i], frame: val?.value!, x: undefined, y: undefined };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
)}
|
||||||
|
<ScatterSeriesEditor
|
||||||
|
key={`series/${selected}`}
|
||||||
|
baseNameMode={FieldNamePickerBaseNameMode.ExcludeBaseNames}
|
||||||
|
item={{} as StandardEditorsRegistryItem}
|
||||||
|
context={context}
|
||||||
|
value={value[selected]}
|
||||||
|
onChange={(val) => {
|
||||||
|
onChange(
|
||||||
|
value.map((obj, i) => {
|
||||||
|
if (i === selected) {
|
||||||
|
return val!;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
frameFilter={value[selected].frame ?? undefined}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -9,13 +9,16 @@ import { Options, ScatterSeriesConfig } from './panelcfg.gen';
|
|||||||
|
|
||||||
export interface Props extends StandardEditorProps<ScatterSeriesConfig, unknown, Options> {
|
export interface Props extends StandardEditorProps<ScatterSeriesConfig, unknown, Options> {
|
||||||
baseNameMode: FieldNamePickerBaseNameMode;
|
baseNameMode: FieldNamePickerBaseNameMode;
|
||||||
|
frameFilter?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }: Props) => {
|
export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode, frameFilter = -1 }: Props) => {
|
||||||
const onFieldChange = (val: unknown | undefined, field: string) => {
|
const onFieldChange = (val: unknown | undefined, field: string) => {
|
||||||
onChange({ ...value, [field]: val });
|
onChange({ ...value, [field]: val });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const frame = context.data && frameFilter > -1 ? context.data[frameFilter] : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Field label={'X Field'}>
|
<Field label={'X Field'}>
|
||||||
@ -27,7 +30,10 @@ export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }:
|
|||||||
id: 'x',
|
id: 'x',
|
||||||
name: 'x',
|
name: 'x',
|
||||||
settings: {
|
settings: {
|
||||||
|
filter: (field) =>
|
||||||
|
frame?.fields.some((obj) => obj.state?.displayName === field.state?.displayName) ?? true,
|
||||||
baseNameMode,
|
baseNameMode,
|
||||||
|
placeholderText: 'select X field',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -38,10 +44,13 @@ export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }:
|
|||||||
context={context}
|
context={context}
|
||||||
onChange={(field) => onFieldChange(field, 'y')}
|
onChange={(field) => onFieldChange(field, 'y')}
|
||||||
item={{
|
item={{
|
||||||
id: 'x',
|
id: 'y',
|
||||||
name: 'x',
|
name: 'y',
|
||||||
settings: {
|
settings: {
|
||||||
|
filter: (field) =>
|
||||||
|
frame?.fields.some((obj) => obj.state?.displayName === field.state?.displayName) ?? true,
|
||||||
baseNameMode,
|
baseNameMode,
|
||||||
|
placeholderText: 'select Y field',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -57,9 +57,10 @@ composableKinds: PanelCfg: {
|
|||||||
|
|
||||||
ScatterSeriesConfig: {
|
ScatterSeriesConfig: {
|
||||||
FieldConfig
|
FieldConfig
|
||||||
x?: string
|
x?: string
|
||||||
y?: string
|
y?: string
|
||||||
name?: string
|
name?: string
|
||||||
|
frame?: number
|
||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
|
|
||||||
Options: {
|
Options: {
|
||||||
|
@ -54,6 +54,7 @@ export const defaultFieldConfig: Partial<FieldConfig> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface ScatterSeriesConfig extends FieldConfig {
|
export interface ScatterSeriesConfig extends FieldConfig {
|
||||||
|
frame?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
x?: string;
|
x?: string;
|
||||||
y?: string;
|
y?: string;
|
||||||
|
@ -224,6 +224,10 @@ function prepSeries(options: Options, frames: DataFrame[]): ScatterSeries[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
|
for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
|
||||||
|
// When a frame filter is applied, only include matching frame index
|
||||||
|
if (series.frame !== undefined && series.frame !== frameIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const frame = frames[frameIndex];
|
const frame = frames[frameIndex];
|
||||||
const xIndex = findFieldIndex(series.x, frame, frames);
|
const xIndex = findFieldIndex(series.x, frame, frames);
|
||||||
|
|
||||||
|
@ -64,3 +64,7 @@ export interface ExtraFacets {
|
|||||||
colorFacetValue: number;
|
colorFacetValue: number;
|
||||||
sizeFacetValue: number;
|
sizeFacetValue: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DataFilterBySeries {
|
||||||
|
frame: number;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user