XYChart: Config cleanup and refactoring (#79915)
* xy config cleanup * more cleanup * clean up betterer some --------- Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
+1
-16
@@ -6596,22 +6596,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Styles should be written using objects.", "2"]
|
||||
],
|
||||
"public/app/plugins/panel/xychart/ManualEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "8"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "10"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||
[0, 0, 0, "Styles should be written using objects.", "12"],
|
||||
[0, 0, 0, "Styles should be written using objects.", "13"],
|
||||
[0, 0, 0, "Styles should be written using objects.", "14"],
|
||||
[0, 0, 0, "Styles should be written using objects.", "15"]
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/xychart/TooltipView.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
|
||||
@@ -18,14 +18,14 @@ title: XYChartPanelCfg kind
|
||||
|
||||
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-----------------------|--------------------------------|----------|---------|---------------------------------------------------------|
|
||||
| `FieldConfig` | [object](#fieldconfig) | **Yes** | | |
|
||||
| `Options` | [object](#options) | **Yes** | | |
|
||||
| `ScatterSeriesConfig` | [object](#scatterseriesconfig) | **Yes** | | |
|
||||
| `ScatterShow` | string | **Yes** | | Possible values are: `points`, `lines`, `points+lines`. |
|
||||
| `SeriesMapping` | string | **Yes** | | Possible values are: `auto`, `manual`. |
|
||||
| `XYDimensionConfig` | [object](#xydimensionconfig) | **Yes** | | |
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-----------------------|--------------------------------|----------|---------|----------------------------------------------------------------------|
|
||||
| `FieldConfig` | [object](#fieldconfig) | **Yes** | | |
|
||||
| `Options` | [object](#options) | **Yes** | | |
|
||||
| `ScatterSeriesConfig` | [object](#scatterseriesconfig) | **Yes** | | |
|
||||
| `ScatterShow` | string | **Yes** | | Possible values are: `points`, `lines`, `points+lines`. |
|
||||
| `SeriesMapping` | string | **Yes** | | Auto is "table" in the UI<br/>Possible values are: `auto`, `manual`. |
|
||||
| `XYDimensionConfig` | [object](#xydimensionconfig) | **Yes** | | Configuration for the Table/Auto mode |
|
||||
|
||||
### FieldConfig
|
||||
|
||||
@@ -150,11 +150,11 @@ It extends [OptionsWithLegend](#optionswithlegend) and [OptionsWithTooltip](#opt
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-----------------|-----------------------------------------------|----------|---------|----------------------------------------------------------------------------|
|
||||
| `dims` | [XYDimensionConfig](#xydimensionconfig) | **Yes** | | |
|
||||
| `dims` | [XYDimensionConfig](#xydimensionconfig) | **Yes** | | Configuration for the Table/Auto mode |
|
||||
| `legend` | [VizLegendOptions](#vizlegendoptions) | **Yes** | | *(Inherited from [OptionsWithLegend](#optionswithlegend))*<br/>TODO docs |
|
||||
| `series` | [ScatterSeriesConfig](#scatterseriesconfig)[] | **Yes** | | |
|
||||
| `series` | [ScatterSeriesConfig](#scatterseriesconfig)[] | **Yes** | | Manual Mode |
|
||||
| `tooltip` | [VizTooltipOptions](#viztooltipoptions) | **Yes** | | *(Inherited from [OptionsWithTooltip](#optionswithtooltip))*<br/>TODO docs |
|
||||
| `seriesMapping` | string | No | | Possible values are: `auto`, `manual`. |
|
||||
| `seriesMapping` | string | No | | Auto is "table" in the UI<br/>Possible values are: `auto`, `manual`. |
|
||||
|
||||
### OptionsWithLegend
|
||||
|
||||
@@ -228,6 +228,8 @@ It extends [FieldConfig](#fieldconfig).
|
||||
|
||||
### XYDimensionConfig
|
||||
|
||||
Configuration for the Table/Auto mode
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-----------|----------|----------|---------|-----------------------------------|
|
||||
| `frame` | integer | **Yes** | | Constraint: `>=0 & <=2147483647`. |
|
||||
|
||||
@@ -174,6 +174,12 @@ export interface StatsPickerConfigSettings {
|
||||
defaultStat?: string;
|
||||
}
|
||||
|
||||
export enum FieldNamePickerBaseNameMode {
|
||||
IncludeAll = 'all',
|
||||
ExcludeBaseNames = 'exclude',
|
||||
OnlyBaseNames = 'only',
|
||||
}
|
||||
|
||||
export interface FieldNamePickerConfigSettings {
|
||||
/**
|
||||
* Function is a predicate, to test each element of the array.
|
||||
@@ -186,11 +192,16 @@ export interface FieldNamePickerConfigSettings {
|
||||
*/
|
||||
noFieldsMessage?: string;
|
||||
|
||||
/**addFieldNamePicker
|
||||
/**
|
||||
* Sets the width to a pixel value.
|
||||
*/
|
||||
width?: number;
|
||||
|
||||
/**
|
||||
* Exclude names that can match a collection of values
|
||||
*/
|
||||
baseNameMode?: FieldNamePickerBaseNameMode;
|
||||
|
||||
/**
|
||||
* Placeholder text to display when nothing is selected.
|
||||
*/
|
||||
|
||||
+12
@@ -13,6 +13,9 @@ import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "10.3.0-pre";
|
||||
|
||||
/**
|
||||
* Auto is "table" in the UI
|
||||
*/
|
||||
export enum SeriesMapping {
|
||||
Auto = 'auto',
|
||||
Manual = 'manual',
|
||||
@@ -24,6 +27,9 @@ export enum ScatterShow {
|
||||
PointsAndLines = 'points+lines',
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the Table/Auto mode
|
||||
*/
|
||||
export interface XYDimensionConfig {
|
||||
exclude?: Array<string>;
|
||||
frame: number;
|
||||
@@ -57,7 +63,13 @@ export interface ScatterSeriesConfig extends FieldConfig {
|
||||
}
|
||||
|
||||
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip {
|
||||
/**
|
||||
* Table Mode (auto)
|
||||
*/
|
||||
dims: XYDimensionConfig;
|
||||
/**
|
||||
* Manual Mode
|
||||
*/
|
||||
series: Array<ScatterSeriesConfig>;
|
||||
seriesMapping?: SeriesMapping;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type Props = StandardEditorProps<string, FieldNamePickerConfigSettings>;
|
||||
export const FieldNamePicker = ({ value, onChange, context, item }: Props) => {
|
||||
const settings: FieldNamePickerConfigSettings = item.settings ?? {};
|
||||
const names = useFieldDisplayNames(context.data, settings?.filter);
|
||||
const selectOptions = useSelectOptions(names, value);
|
||||
const selectOptions = useSelectOptions(names, value, undefined, undefined, settings.baseNameMode);
|
||||
|
||||
const onSelectChange = useCallback(
|
||||
(selection?: SelectableValue<string>) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { DataFrame, Field, getFieldDisplayName, SelectableValue } from '@grafana/data';
|
||||
import { DataFrame, Field, getFieldDisplayName, SelectableValue, FieldNamePickerBaseNameMode } from '@grafana/data';
|
||||
|
||||
import { getFieldTypeIcon } from '../../types';
|
||||
|
||||
@@ -74,7 +74,8 @@ export function useSelectOptions(
|
||||
displayNames: FrameFieldsDisplayNames,
|
||||
currentName?: string,
|
||||
firstItem?: SelectableValue<string>,
|
||||
fieldType?: string
|
||||
fieldType?: string,
|
||||
baseNameMode?: FieldNamePickerBaseNameMode
|
||||
): Array<SelectableValue<string>> {
|
||||
return useMemo(() => {
|
||||
let found = false;
|
||||
@@ -82,21 +83,8 @@ export function useSelectOptions(
|
||||
if (firstItem) {
|
||||
options.push(firstItem);
|
||||
}
|
||||
for (const name of displayNames.display) {
|
||||
if (!found && name === currentName) {
|
||||
found = true;
|
||||
}
|
||||
const field = displayNames.fields.get(name);
|
||||
if (!fieldType || fieldType === field?.type) {
|
||||
options.push({
|
||||
value: name,
|
||||
label: name,
|
||||
icon: field ? getFieldTypeIcon(field) : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const name of displayNames.raw) {
|
||||
if (!displayNames.display.has(name)) {
|
||||
if (baseNameMode === FieldNamePickerBaseNameMode.OnlyBaseNames) {
|
||||
for (const name of displayNames.raw) {
|
||||
if (!found && name === currentName) {
|
||||
found = true;
|
||||
}
|
||||
@@ -105,6 +93,34 @@ export function useSelectOptions(
|
||||
label: `${name} (base field name)`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (const name of displayNames.display) {
|
||||
if (!found && name === currentName) {
|
||||
found = true;
|
||||
}
|
||||
const field = displayNames.fields.get(name);
|
||||
if (!fieldType || fieldType === field?.type) {
|
||||
options.push({
|
||||
value: name,
|
||||
label: name,
|
||||
icon: field ? getFieldTypeIcon(field) : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (baseNameMode !== FieldNamePickerBaseNameMode.ExcludeBaseNames) {
|
||||
for (const name of displayNames.raw) {
|
||||
if (!displayNames.display.has(name)) {
|
||||
if (!found && name === currentName) {
|
||||
found = true;
|
||||
}
|
||||
options.push({
|
||||
value: name,
|
||||
label: `${name} (base field name)`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentName && !found) {
|
||||
@@ -114,5 +130,5 @@ export function useSelectOptions(
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}, [displayNames, currentName, firstItem, fieldType]);
|
||||
}, [displayNames, currentName, firstItem, fieldType, baseNameMode]);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
|
||||
import { GrafanaTheme2, SelectableValue, StandardEditorProps, FieldNamePickerBaseNameMode } from '@grafana/data';
|
||||
import { ColorDimensionConfig } from '@grafana/schema';
|
||||
import { Select, ColorPicker, useStyles2 } from '@grafana/ui';
|
||||
import { useFieldDisplayNames, useSelectOptions } from '@grafana/ui/src/components/MatchersUI/utils';
|
||||
@@ -11,19 +11,30 @@ const fixedColorOption: SelectableValue<string> = {
|
||||
value: '_____fixed_____',
|
||||
};
|
||||
|
||||
export const ColorDimensionEditor = (props: StandardEditorProps<ColorDimensionConfig>) => {
|
||||
const { value, context, onChange } = props;
|
||||
interface ColorDimensionSettings {
|
||||
isClearable?: boolean;
|
||||
baseNameMode?: FieldNamePickerBaseNameMode;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export const ColorDimensionEditor = (props: StandardEditorProps<ColorDimensionConfig, ColorDimensionSettings>) => {
|
||||
const { value, context, onChange, item } = props;
|
||||
|
||||
const defaultColor = 'dark-green';
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
const fieldName = value?.field;
|
||||
const isFixed = Boolean(!fieldName);
|
||||
const isFixed = value && Boolean(!fieldName) && value?.fixed;
|
||||
const names = useFieldDisplayNames(context.data);
|
||||
const selectOptions = useSelectOptions(names, fieldName, fixedColorOption);
|
||||
const selectOptions = useSelectOptions(names, fieldName, fixedColorOption, undefined, item.settings?.baseNameMode);
|
||||
|
||||
const onSelectChange = useCallback(
|
||||
(selection: SelectableValue<string>) => {
|
||||
if (!selection) {
|
||||
onChange(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const field = selection.value;
|
||||
if (field && field !== fixedColorOption.value) {
|
||||
onChange({
|
||||
@@ -61,10 +72,12 @@ export const ColorDimensionEditor = (props: StandardEditorProps<ColorDimensionCo
|
||||
options={selectOptions}
|
||||
onChange={onSelectChange}
|
||||
noOptionsMessage="No fields found"
|
||||
isClearable={item.settings?.isClearable}
|
||||
placeholder={item.settings?.placeholder}
|
||||
/>
|
||||
{isFixed && (
|
||||
<div className={styles.picker}>
|
||||
<ColorPicker color={value?.fixed ?? defaultColor} onChange={onColorChange} enableNamedColors={true} />
|
||||
<ColorPicker color={value?.fixed} onChange={onColorChange} enableNamedColors={true} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ import { XYDimensionConfig, Options } from './panelcfg.gen';
|
||||
|
||||
interface XYInfo {
|
||||
numberFields: Array<SelectableValue<string>>;
|
||||
xAxis: SelectableValue<string>;
|
||||
xAxis?: SelectableValue<string>;
|
||||
yFields: Array<SelectableValue<boolean>>;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
if (context?.data?.length) {
|
||||
return context.data.map((f, idx) => ({
|
||||
value: idx,
|
||||
label: getFrameDisplayName(f, idx),
|
||||
label: `${getFrameDisplayName(f, idx)} (index: ${idx}, rows: ${f.length})`,
|
||||
}));
|
||||
}
|
||||
return [{ value: 0, label: 'First result' }];
|
||||
@@ -33,19 +33,15 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
const dims = useMemo(() => getXYDimensions(value, context.data), [context.data, value]);
|
||||
|
||||
const info = useMemo(() => {
|
||||
const first = {
|
||||
label: '?',
|
||||
value: undefined, // empty
|
||||
};
|
||||
const v: XYInfo = {
|
||||
numberFields: [first],
|
||||
numberFields: [],
|
||||
yFields: [],
|
||||
xAxis: value?.x
|
||||
? {
|
||||
label: `${value.x} (Not found)`,
|
||||
value: value.x, // empty
|
||||
}
|
||||
: first,
|
||||
: undefined,
|
||||
};
|
||||
const frame = context.data ? context.data[value?.frame ?? 0] : undefined;
|
||||
if (frame) {
|
||||
@@ -58,9 +54,6 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
value: name,
|
||||
};
|
||||
v.numberFields.push(sel);
|
||||
if (first.label === '?') {
|
||||
first.label = `${name} (First)`;
|
||||
}
|
||||
if (value?.x && name === value.x) {
|
||||
v.xAxis = sel;
|
||||
}
|
||||
@@ -79,7 +72,7 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
if (!context.data) {
|
||||
if (!context.data?.length) {
|
||||
return <div>No data...</div>;
|
||||
}
|
||||
|
||||
@@ -87,24 +80,28 @@ export const AutoEditor = ({ value, onChange, context }: StandardEditorProps<XYD
|
||||
<div>
|
||||
<Field label={'Data'}>
|
||||
<Select
|
||||
isClearable={true}
|
||||
options={frameNames}
|
||||
value={frameNames.find((v) => v.value === value?.frame) ?? frameNames[0]}
|
||||
placeholder={frameNames[0].label}
|
||||
value={frameNames.find((v) => v.value === value?.frame)}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
frame: v.value!,
|
||||
frame: v?.value!,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'X Field'}>
|
||||
<Select
|
||||
isClearable={true}
|
||||
options={info.numberFields}
|
||||
value={info.xAxis}
|
||||
placeholder={`${info.numberFields?.[0].label} (First numeric)`}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
x: v.value,
|
||||
x: v?.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { GrafanaTheme2, StandardEditorProps } from '@grafana/data';
|
||||
import { Button, Field, IconButton, useStyles2 } from '@grafana/ui';
|
||||
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
|
||||
import {
|
||||
GrafanaTheme2,
|
||||
StandardEditorProps,
|
||||
FieldNamePickerBaseNameMode,
|
||||
StandardEditorsRegistryItem,
|
||||
} from '@grafana/data';
|
||||
import { Button, IconButton, useStyles2 } from '@grafana/ui';
|
||||
import { LayerName } from 'app/core/components/Layers/LayerName';
|
||||
import { ColorDimensionEditor, ScaleDimensionEditor } from 'app/features/dimensions/editors';
|
||||
|
||||
import { ScatterSeriesEditor } from './ScatterSeriesEditor';
|
||||
import { Options, ScatterSeriesConfig, defaultFieldConfig } from './panelcfg.gen';
|
||||
|
||||
export const ManualEditor = ({
|
||||
value,
|
||||
onChange,
|
||||
context,
|
||||
}: StandardEditorProps<ScatterSeriesConfig[], any, Options>) => {
|
||||
}: StandardEditorProps<ScatterSeriesConfig[], unknown, Options>) => {
|
||||
const [selected, setSelected] = useState(0);
|
||||
const style = useStyles2(getStyles);
|
||||
|
||||
const onFieldChange = (val: any | undefined, index: number, field: string) => {
|
||||
const onFieldChange = (val: unknown | undefined, index: number, field: string) => {
|
||||
onChange(
|
||||
value.map((obj, i) => {
|
||||
if (i === index) {
|
||||
@@ -32,7 +36,7 @@ export const ManualEditor = ({
|
||||
onChange([
|
||||
...value,
|
||||
{
|
||||
pointColor: {} as any,
|
||||
pointColor: undefined,
|
||||
pointSize: defaultFieldConfig.pointSize,
|
||||
},
|
||||
]);
|
||||
@@ -97,77 +101,58 @@ export const ManualEditor = ({
|
||||
</div>
|
||||
|
||||
{selected >= 0 && value[selected] && (
|
||||
<>
|
||||
<div key={`series/${selected}`}>
|
||||
<Field label={'X Field'}>
|
||||
<FieldNamePicker
|
||||
value={value[selected].x ?? ''}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, selected, 'x')}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Y Field'}>
|
||||
<FieldNamePicker
|
||||
value={value[selected].y ?? ''}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, selected, 'y')}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Point color'}>
|
||||
<ColorDimensionEditor
|
||||
value={value[selected].pointColor!}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, selected, 'pointColor')}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Point size'}>
|
||||
<ScaleDimensionEditor
|
||||
value={value[selected].pointSize!}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, selected, 'pointSize')}
|
||||
item={{ settings: { min: 1, max: 100 } } as any}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</>
|
||||
<ScatterSeriesEditor
|
||||
key={`series/${selected}`}
|
||||
baseNameMode={FieldNamePickerBaseNameMode.ExcludeBaseNames}
|
||||
item={{} as StandardEditorsRegistryItem}
|
||||
context={context}
|
||||
value={value[selected]}
|
||||
onChange={(v) => {
|
||||
onChange(
|
||||
value.map((obj, i) => {
|
||||
if (i === selected) {
|
||||
return v!;
|
||||
}
|
||||
return obj;
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
marginBot: css`
|
||||
margin-bottom: 20px;
|
||||
`,
|
||||
row: css`
|
||||
padding: ${theme.spacing(0.5, 1)};
|
||||
border-radius: ${theme.shape.radius.default};
|
||||
background: ${theme.colors.background.secondary};
|
||||
min-height: ${theme.spacing(4)};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 3px;
|
||||
cursor: pointer;
|
||||
marginBot: css({
|
||||
marginBottom: '20px',
|
||||
}),
|
||||
row: css({
|
||||
padding: `${theme.spacing(0.5, 1)}`,
|
||||
borderRadius: `${theme.shape.radius.default}`,
|
||||
background: `${theme.colors.background.secondary}`,
|
||||
minHeight: `${theme.spacing(4)}`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '3px',
|
||||
cursor: 'pointer',
|
||||
|
||||
border: 1px solid ${theme.components.input.borderColor};
|
||||
&:hover {
|
||||
border: 1px solid ${theme.components.input.borderHover};
|
||||
}
|
||||
`,
|
||||
sel: css`
|
||||
border: 1px solid ${theme.colors.primary.border};
|
||||
&:hover {
|
||||
border: 1px solid ${theme.colors.primary.border};
|
||||
}
|
||||
`,
|
||||
actionIcon: css`
|
||||
color: ${theme.colors.text.secondary};
|
||||
&:hover {
|
||||
color: ${theme.colors.text};
|
||||
}
|
||||
`,
|
||||
border: `1px solid ${theme.components.input.borderColor}`,
|
||||
'&:hover': {
|
||||
border: `1px solid ${theme.components.input.borderHover}`,
|
||||
},
|
||||
}),
|
||||
sel: css({
|
||||
border: `1px solid ${theme.colors.primary.border}`,
|
||||
'&:hover': {
|
||||
border: `1px solid ${theme.colors.primary.border}`,
|
||||
},
|
||||
}),
|
||||
actionIcon: css({
|
||||
color: `${theme.colors.text.secondary}`,
|
||||
'&:hover': {
|
||||
color: `${theme.colors.text}`,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
|
||||
import { StandardEditorProps, FieldNamePickerBaseNameMode } from '@grafana/data';
|
||||
import { Field } from '@grafana/ui';
|
||||
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
|
||||
import { ColorDimensionEditor, ScaleDimensionEditor } from 'app/features/dimensions/editors';
|
||||
|
||||
import { Options, ScatterSeriesConfig } from './panelcfg.gen';
|
||||
|
||||
export interface Props extends StandardEditorProps<ScatterSeriesConfig, unknown, Options> {
|
||||
baseNameMode: FieldNamePickerBaseNameMode;
|
||||
}
|
||||
|
||||
export const ScatterSeriesEditor = ({ value, onChange, context, baseNameMode }: Props) => {
|
||||
const onFieldChange = (val: unknown | undefined, field: string) => {
|
||||
onChange({ ...value, [field]: val });
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Field label={'X Field'}>
|
||||
<FieldNamePicker
|
||||
value={value.x ?? ''}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, 'x')}
|
||||
item={{
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
settings: {
|
||||
baseNameMode,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Y Field'}>
|
||||
<FieldNamePicker
|
||||
value={value.y ?? ''}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, 'y')}
|
||||
item={{
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
settings: {
|
||||
baseNameMode,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Point color'}>
|
||||
<ColorDimensionEditor
|
||||
value={value.pointColor!}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, 'pointColor')}
|
||||
item={{
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
settings: {
|
||||
baseNameMode,
|
||||
isClearable: true,
|
||||
placeholder: 'Use standard color scheme',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Point size'}>
|
||||
<ScaleDimensionEditor
|
||||
value={value.pointSize!}
|
||||
context={context}
|
||||
onChange={(field) => onFieldChange(field, 'pointSize')}
|
||||
item={{
|
||||
id: 'x',
|
||||
name: 'x',
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 100,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -17,8 +17,8 @@ export const plugin = new PanelPlugin<Options, FieldConfig>(XYChartPanel2)
|
||||
defaultValue: 'auto',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'auto', label: 'Auto', description: 'No changes to saved model since 8.0' },
|
||||
{ value: 'manual', label: 'Manual' },
|
||||
{ value: 'auto', label: 'Table', description: 'Plot values within a single table result' },
|
||||
{ value: 'manual', label: 'Manual', description: 'Construct values from any result' },
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -25,10 +25,11 @@ composableKinds: PanelCfg: {
|
||||
schemas: [{
|
||||
version: [0, 0]
|
||||
schema: {
|
||||
|
||||
// Auto is "table" in the UI
|
||||
SeriesMapping: "auto" | "manual" @cuetsy(kind="enum")
|
||||
ScatterShow: "points" | "lines" | "points+lines" @cuetsy(kind="enum", memberNames="Points|Lines|PointsAndLines")
|
||||
|
||||
// Configuration for the Table/Auto mode
|
||||
XYDimensionConfig: {
|
||||
frame: int32 & >=0
|
||||
x?: string
|
||||
@@ -66,7 +67,11 @@ composableKinds: PanelCfg: {
|
||||
common.OptionsWithTooltip
|
||||
|
||||
seriesMapping?: SeriesMapping
|
||||
dims: XYDimensionConfig
|
||||
|
||||
// Table Mode (auto)
|
||||
dims: XYDimensionConfig
|
||||
|
||||
// Manual Mode
|
||||
series: [...ScatterSeriesConfig]
|
||||
} @cuetsy(kind="interface")
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
/**
|
||||
* Auto is "table" in the UI
|
||||
*/
|
||||
export enum SeriesMapping {
|
||||
Auto = 'auto',
|
||||
Manual = 'manual',
|
||||
@@ -21,6 +24,9 @@ export enum ScatterShow {
|
||||
PointsAndLines = 'points+lines',
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the Table/Auto mode
|
||||
*/
|
||||
export interface XYDimensionConfig {
|
||||
exclude?: Array<string>;
|
||||
frame: number;
|
||||
@@ -54,7 +60,13 @@ export interface ScatterSeriesConfig extends FieldConfig {
|
||||
}
|
||||
|
||||
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip {
|
||||
/**
|
||||
* Table Mode (auto)
|
||||
*/
|
||||
dims: XYDimensionConfig;
|
||||
/**
|
||||
* Manual Mode
|
||||
*/
|
||||
series: Array<ScatterSeriesConfig>;
|
||||
seriesMapping?: SeriesMapping;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user