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))* |
|
||||
| `axisSoftMin` | 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 |
|
||||
| `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`. |
|
||||
|
@ -57,6 +57,7 @@ export const defaultFieldConfig: Partial<FieldConfig> = {
|
||||
};
|
||||
|
||||
export interface ScatterSeriesConfig extends FieldConfig {
|
||||
frame?: number;
|
||||
name?: string;
|
||||
x?: string;
|
||||
y?: string;
|
||||
|
@ -85,7 +85,7 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
<Select
|
||||
isClearable={true}
|
||||
options={frameNames}
|
||||
placeholder={frameNames[0].label}
|
||||
placeholder={'Change filter'}
|
||||
value={frameNames.find((v) => v.value === value?.frame)}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
|
||||
import {
|
||||
GrafanaTheme2,
|
||||
StandardEditorProps,
|
||||
FieldNamePickerBaseNameMode,
|
||||
StandardEditorsRegistryItem,
|
||||
getFrameDisplayName,
|
||||
} 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 { ScatterSeriesEditor } from './ScatterSeriesEditor';
|
||||
@ -18,6 +19,16 @@ export const ManualEditor = ({
|
||||
onChange,
|
||||
context,
|
||||
}: 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 style = useStyles2(getStyles);
|
||||
|
||||
@ -101,23 +112,53 @@ export const ManualEditor = ({
|
||||
</div>
|
||||
|
||||
{selected >= 0 && value[selected] && (
|
||||
<ScatterSeriesEditor
|
||||
key={`series/${selected}`}
|
||||
baseNameMode={FieldNamePickerBaseNameMode.ExcludeBaseNames}
|
||||
item={{} as StandardEditorsRegistryItem}
|
||||
context={context}
|
||||
value={value[selected]}
|
||||
onChange={(v) => {
|
||||
<>
|
||||
{frameNames.length > 1 && (
|
||||
<Field label={'Data'}>
|
||||
<Select
|
||||
isClearable={false}
|
||||
options={frameNames}
|
||||
placeholder={'Change filter'}
|
||||
value={
|
||||
frameNames.find((v) => {
|
||||
return v.value === value[selected].frame;
|
||||
}) ?? 0
|
||||
}
|
||||
onChange={(val) => {
|
||||
onChange(
|
||||
value.map((obj, i) => {
|
||||
if (i === selected) {
|
||||
return v!;
|
||||
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> {
|
||||
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) => {
|
||||
onChange({ ...value, [field]: val });
|
||||
};
|
||||
|
||||
const frame = context.data && frameFilter > -1 ? context.data[frameFilter] : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Field label={'X Field'}>
|
||||
@ -27,7 +30,10 @@ export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }:
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
settings: {
|
||||
filter: (field) =>
|
||||
frame?.fields.some((obj) => obj.state?.displayName === field.state?.displayName) ?? true,
|
||||
baseNameMode,
|
||||
placeholderText: 'select X field',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
@ -38,10 +44,13 @@ export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }:
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, 'y')}
|
||||
item={{
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
id: 'y',
|
||||
name: 'y',
|
||||
settings: {
|
||||
filter: (field) =>
|
||||
frame?.fields.some((obj) => obj.state?.displayName === field.state?.displayName) ?? true,
|
||||
baseNameMode,
|
||||
placeholderText: 'select Y field',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
@ -60,6 +60,7 @@ composableKinds: PanelCfg: {
|
||||
x?: string
|
||||
y?: string
|
||||
name?: string
|
||||
frame?: number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
Options: {
|
||||
|
@ -54,6 +54,7 @@ export const defaultFieldConfig: Partial<FieldConfig> = {
|
||||
};
|
||||
|
||||
export interface ScatterSeriesConfig extends FieldConfig {
|
||||
frame?: number;
|
||||
name?: string;
|
||||
x?: string;
|
||||
y?: string;
|
||||
|
@ -224,6 +224,10 @@ function prepSeries(options: Options, frames: DataFrame[]): ScatterSeries[] {
|
||||
}
|
||||
|
||||
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 xIndex = findFieldIndex(series.x, frame, frames);
|
||||
|
||||
|
@ -64,3 +64,7 @@ export interface ExtraFacets {
|
||||
colorFacetValue: number;
|
||||
sizeFacetValue: number;
|
||||
}
|
||||
|
||||
export interface DataFilterBySeries {
|
||||
frame: number;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user