Table Panel: Add ability to use text color for value or hide value in gauge cell (#61477)

* BarGauge: New value options

* Fix typings for cell options, add new value mode option for bar gauge cells

* Add BarGauge panel option, tests, and update test dashboard

* Updated

* Added default

* Goodbye trusty console.log

* Update

* Merge changes from main

* Update docs

* Add valuemode doc changes

* Update gdev dashboard

* Update valueMode symbol name to valueDisplayMode

* Use Enums as Opposed to literals, don't calculate values when hidden

* Remove double import

* Fix tests

* One more test fix

* Remove erroneous targets field, fix type of maxDataPoints

* Strip nulls and add index field to Thresholds

* Gen cue

* remove bad targets again

* Fixes

---------

Co-authored-by: Kyle Cunningham <kyle@codeincarnate.com>
Co-authored-by: sam boyer <sdboyer@grafana.com>
This commit is contained in:
Torkel Ödegaard
2023-03-10 14:41:46 +01:00
committed by GitHub
parent 0a4d9f01e8
commit 73ce20ab48
25 changed files with 2259 additions and 1570 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@ It extends [SingleStatBaseOptions](#singlestatbaseoptions).
| `minVizHeight` | uint32 | **Yes** | Default: `10`. |
| `minVizWidth` | uint32 | **Yes** | Default: `0`. |
| `showUnfilled` | boolean | **Yes** | Default: `true`. |
| `valueMode` | string | **Yes** | Allows for the table cell gauge display type to set the gauge mode.<br/>Possible values are: `color`, `text`, `hidden`. |
| `orientation` | string | No | *(Inherited from [SingleStatBaseOptions](#singlestatbaseoptions))*<br/>TODO docs<br/>Possible values are: `auto`, `vertical`, `horizontal`. |
| `reduceOptions` | [ReduceDataOptions](#reducedataoptions) | No | *(Inherited from [SingleStatBaseOptions](#singlestatbaseoptions))*<br/>TODO docs |
| `text` | [VizTextDisplayOptions](#viztextdisplayoptions) | No | *(Inherited from [SingleStatBaseOptions](#singlestatbaseoptions))*<br/>TODO docs |

View File

@@ -195,11 +195,12 @@ TODO docs
TODO docs
| Property | Type | Required | Description |
|----------|--------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| `color` | string | **Yes** | TODO docs |
| `state` | string | No | TODO docs<br/>TODO are the values here enumerable into a disjunction?<br/>Some seem to be listed in typescript comment |
| `value` | number | No | TODO docs<br/>FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON |
| Property | Type | Required | Description |
|----------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| `color` | string | **Yes** | TODO docs |
| `index` | integer | No | Threshold index, an old property that is not needed an should only appear in older dashboards |
| `state` | string | No | TODO docs<br/>TODO are the values here enumerable into a disjunction?<br/>Some seem to be listed in typescript comment |
| `value` | number | No | TODO docs<br/>FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON |
### ValueMapping

View File

@@ -108,6 +108,22 @@ The gauge is split up in small cells that are lit or unlit.
{{< figure src="/static/img/docs/tables/lcd-gauge.png" max-width="500px" caption="LCD gauge" class="docs-image--no-shadow" >}}
#### Label Options
Additionally, labels displayed alongside of the gauges can be set to be colored by value, match the theme text color, or be hidden.
**Value Color**
{{< figure src="/static/img/docs/tables/value-color-mode.png" max-width="500px" caption="Color Label by Value" class="docs-image--no-shadow" >}}
**Text Color**
{{< figure src="/static/img/docs/tables/text-color-mode.png" max-width="500px" caption="Color Label by theme color" class="docs-image--no-shadow" >}}
**Hidden**
{{< figure src="/static/img/docs/tables/hidden-mode.png" max-width="500px" caption="Hide Label" class="docs-image--no-shadow" >}}
### JSON view
Shows value formatted as code. If a value is an object the JSON view allowing browsing the JSON object will appear on hover.

View File

@@ -25,8 +25,8 @@ lineage: seqs: [
// Description of dashboard.
description?: string
// This property should only be used in dashboards defined by plugins. It is a quick check
// to see if the version has changed since the last time. Unclear why using the version property
// is insufficient.
// to see if the version has changed since the last time. Unclear why using the version property
// is insufficient.
revision?: int64 @grafanamaturity(NeedsExpertReview)
// For dashboards imported from the https://grafana.com/grafana/dashboards/ portal
gnetId?: string @grafanamaturity(NeedsExpertReview)
@@ -220,6 +220,8 @@ lineage: seqs: [
value?: number @grafanamaturity(NeedsExpertReview)
// TODO docs
color: string @grafanamaturity(NeedsExpertReview)
// Threshold index, an old property that is not needed an should only appear in older dashboards
index?: int32 @grafanamaturity(NeedsExpertReview)
// TODO docs
// TODO are the values here enumerable into a disjunction?
// Some seem to be listed in typescript comment

View File

@@ -593,6 +593,15 @@ export enum BarGaugeDisplayMode {
Lcd = 'lcd',
}
/**
* Allows for the table cell gauge display type to set the gauge mode.
*/
export enum BarGaugeValueMode {
Color = 'color',
Hidden = 'hidden',
Text = 'text',
}
/**
* TODO docs
*/
@@ -697,6 +706,7 @@ export interface TableImageCellOptions {
export interface TableBarGaugeCellOptions {
mode?: BarGaugeDisplayMode;
type: TableCellDisplayMode.Gauge;
valueDisplayMode?: BarGaugeValueMode;
}
/**

View File

@@ -242,6 +242,9 @@ VizLegendOptions: {
// for the bar gauge component of Grafana UI
BarGaugeDisplayMode: "basic" | "lcd" | "gradient" @cuetsy(kind="enum")
// Allows for the table cell gauge display type to set the gauge mode.
BarGaugeValueMode: "color" | "text" | "hidden" @cuetsy(kind="enum")
// TODO docs
VizTooltipOptions: {
mode: TooltipDisplayMode

View File

@@ -52,6 +52,7 @@ TableImageCellOptions: {
TableBarGaugeCellOptions: {
type: TableCellDisplayMode & "gauge"
mode?: BarGaugeDisplayMode
valueDisplayMode?: BarGaugeValueMode
} @cuetsy(kind="interface")
// Sparkline cell options

View File

@@ -238,6 +238,10 @@ export interface Threshold {
* TODO docs
*/
color: string;
/**
* Threshold index, an old property that is not needed an should only appear in older dashboards
*/
index?: number;
/**
* TODO docs
* TODO are the values here enumerable into a disjunction?

View File

@@ -11,18 +11,18 @@ import {
getDisplayProcessor,
createTheme,
} from '@grafana/data';
import { BarGaugeDisplayMode } from '@grafana/schema';
import { BarGaugeDisplayMode, BarGaugeValueMode } from '@grafana/schema';
import {
BarGauge,
Props,
getCellColor,
getValueColor,
getTextValueColor,
getBasicAndGradientStyles,
getBarGradient,
getTitleStyles,
getValuePercent,
calculateBarAndValueDimensions,
getCellColor,
} from './BarGauge';
const green = '#73BF69';
@@ -63,7 +63,7 @@ function getProps(propOverrides?: Partial<Props>): Props {
}
function getValue(value: number, title?: string): DisplayValue {
return { numeric: value, text: value.toString(), title: title };
return { numeric: value, text: value.toString(), title: title, color: '#FF0000' };
}
describe('BarGauge', () => {
@@ -134,12 +134,12 @@ describe('BarGauge', () => {
it('should get the threshold color if value is same as a threshold', () => {
const props = getProps();
props.value = props.display!(70);
expect(getValueColor(props)).toEqual(orange);
expect(getTextValueColor(props)).toEqual(orange);
});
it('should get the base threshold', () => {
const props = getProps();
props.value = props.display!(-10);
expect(getValueColor(props)).toEqual(green);
expect(getTextValueColor(props)).toEqual(green);
});
});
@@ -325,5 +325,46 @@ describe('BarGauge', () => {
);
expect(result.valueWidth).toBe(21);
});
it('valueWidth be zero if valueMode is hideen', () => {
const result = calculateBarAndValueDimensions(
getProps({
height: 30,
width: 100,
value: getValue(1, 'AA'),
orientation: VizOrientation.Horizontal,
valueDisplayMode: BarGaugeValueMode.Hidden,
})
);
expect(result.valueWidth).toBe(0);
});
});
describe('With valueMode set to text color', () => {
it('should color value using text color', () => {
const props = getProps({
width: 150,
value: getValue(100),
orientation: VizOrientation.Vertical,
valueDisplayMode: BarGaugeValueMode.Text,
});
const styles = getBasicAndGradientStyles(props);
expect(styles.bar.background).toBe('rgba(255, 0, 0, 0.35)');
expect(styles.value.color).toBe('rgb(204, 204, 220)');
});
});
describe('With valueMode set to text value', () => {
it('should color value value color', () => {
const props = getProps({
width: 150,
value: getValue(100),
orientation: VizOrientation.Vertical,
valueDisplayMode: BarGaugeValueMode.Color,
});
const styles = getBasicAndGradientStyles(props);
expect(styles.bar.background).toBe('rgba(255, 0, 0, 0.35)');
expect(styles.value.color).toBe('#FF0000');
});
});
});

View File

@@ -20,7 +20,7 @@ import {
VizOrientation,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { BarGaugeDisplayMode, VizTextDisplayOptions } from '@grafana/schema';
import { BarGaugeDisplayMode, BarGaugeValueMode, VizTextDisplayOptions } from '@grafana/schema';
import { Themeable2 } from '../../types';
import { calculateFontSize, measureText } from '../../utils/measureText';
@@ -49,6 +49,7 @@ export interface Props extends Themeable2 {
className?: string;
showUnfilled?: boolean;
alignmentFactors?: DisplayValueAlignmentFactors;
valueDisplayMode?: BarGaugeValueMode;
}
export class BarGauge extends PureComponent<Props> {
@@ -111,17 +112,19 @@ export class BarGauge extends PureComponent<Props> {
}
renderBasicAndGradientBars(): ReactNode {
const { value, showUnfilled } = this.props;
const { value, showUnfilled, valueDisplayMode } = this.props;
const styles = getBasicAndGradientStyles(this.props);
return (
<div style={styles.wrapper}>
<FormattedValueDisplay
data-testid={selectors.components.Panels.Visualization.BarGauge.valueV2}
value={value}
style={styles.value}
/>
{valueDisplayMode !== BarGaugeValueMode.Hidden && (
<FormattedValueDisplay
data-testid={selectors.components.Panels.Visualization.BarGauge.valueV2}
value={value}
style={styles.value}
/>
)}
{showUnfilled && <div style={styles.emptyBar} />}
<div style={styles.bar} />
</div>
@@ -129,7 +132,8 @@ export class BarGauge extends PureComponent<Props> {
}
renderRetroBars(): ReactNode {
const { display, field, value, itemSpacing, alignmentFactors, orientation, lcdCellWidth, text } = this.props;
const { display, field, value, itemSpacing, alignmentFactors, orientation, lcdCellWidth, text, valueDisplayMode } =
this.props;
const { valueHeight, valueWidth, maxBarHeight, maxBarWidth, wrapperWidth, wrapperHeight } =
calculateBarAndValueDimensions(this.props);
const minValue = field.min ?? GAUGE_DEFAULT_MINIMUM;
@@ -141,7 +145,7 @@ export class BarGauge extends PureComponent<Props> {
const cellSpacing = itemSpacing!;
const cellCount = Math.floor(maxSize / lcdCellWidth!);
const cellSize = Math.floor((maxSize - cellSpacing * cellCount) / cellCount);
const valueColor = getValueColor(this.props);
const valueColor = getTextValueColor(this.props);
const valueToBaseSizeOn = alignmentFactors ? alignmentFactors : value;
const valueStyles = getValueStyles(valueToBaseSizeOn, valueColor, valueWidth, valueHeight, orientation, text);
@@ -192,11 +196,13 @@ export class BarGauge extends PureComponent<Props> {
return (
<div style={containerStyles}>
{cells}
<FormattedValueDisplay
data-testid={selectors.components.Panels.Visualization.BarGauge.valueV2}
value={value}
style={valueStyles}
/>
{valueDisplayMode !== BarGaugeValueMode.Hidden && (
<FormattedValueDisplay
data-testid={selectors.components.Panels.Visualization.BarGauge.valueV2}
value={value}
style={valueStyles}
/>
)}
</div>
);
}
@@ -338,7 +344,7 @@ interface BarAndValueDimensions {
* Only exported for unit tests
**/
export function calculateBarAndValueDimensions(props: Props): BarAndValueDimensions {
const { height, width, orientation, text, alignmentFactors } = props;
const { height, width, orientation, text, alignmentFactors, valueDisplayMode } = props;
const titleDim = calculateTitleDimensions(props);
const value = alignmentFactors ?? props.value;
const valueString = formattedValueToString(value);
@@ -363,13 +369,25 @@ export function calculateBarAndValueDimensions(props: Props): BarAndValueDimensi
}
valueWidth = width;
if (valueDisplayMode === BarGaugeValueMode.Hidden) {
valueHeight = 0;
valueWidth = 0;
}
maxBarHeight = height - (titleDim.height + valueHeight);
maxBarWidth = width;
wrapperWidth = width;
wrapperHeight = height - titleDim.height;
} else {
valueHeight = height - titleDim.height;
valueWidth = Math.max(Math.min(width * 0.2, MAX_VALUE_WIDTH), realValueWidth);
// Calculate the width and the height of the given values
if (valueDisplayMode === BarGaugeValueMode.Hidden) {
valueHeight = 0;
valueWidth = 0;
} else {
valueHeight = height - titleDim.height;
valueWidth = Math.max(Math.min(width * 0.2, MAX_VALUE_WIDTH), realValueWidth);
}
maxBarHeight = height - titleDim.height;
maxBarWidth = width - valueWidth - titleDim.width;
@@ -447,10 +465,11 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles
const minValue = field.min ?? GAUGE_DEFAULT_MINIMUM;
const maxValue = field.max ?? GAUGE_DEFAULT_MAXIMUM;
const valuePercent = getValuePercent(value.numeric, minValue, maxValue);
const valueColor = getValueColor(props);
const textColor = getTextValueColor(props);
const barColor = value.color ?? FALLBACK_COLOR;
const valueToBaseSizeOn = alignmentFactors ? alignmentFactors : value;
const valueStyles = getValueStyles(valueToBaseSizeOn, valueColor, valueWidth, valueHeight, orientation, text);
const valueStyles = getValueStyles(valueToBaseSizeOn, textColor, valueWidth, valueHeight, orientation, text);
const isBasic = displayMode === 'basic';
const wrapperStyles: CSSProperties = {
@@ -491,8 +510,8 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles
if (isBasic) {
// Basic styles
barStyles.background = `${tinycolor(valueColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderTop = `2px solid ${valueColor}`;
barStyles.background = `${tinycolor(barColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderTop = `2px solid ${barColor}`;
} else {
// Gradient styles
barStyles.background = getBarGradient(props, maxBarHeight);
@@ -517,8 +536,8 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles
if (isBasic) {
// Basic styles
barStyles.background = `${tinycolor(valueColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderRight = `2px solid ${valueColor}`;
barStyles.background = `${tinycolor(barColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderRight = `2px solid ${barColor}`;
} else {
// Gradient styles
barStyles.background = getBarGradient(props, maxBarWidth);
@@ -598,7 +617,11 @@ export function getBarGradient(props: Props, maxSize: number): string {
/**
* Only exported to for unit test
*/
export function getValueColor(props: Props): string {
export function getTextValueColor(props: Props): string {
if (props.valueDisplayMode === 'text') {
return props.theme.colors.text.primary;
}
const { value } = props;
if (value.color) {
return value.color;

View File

@@ -2,7 +2,7 @@ import { isFunction } from 'lodash';
import React, { FC } from 'react';
import { ThresholdsConfig, ThresholdsMode, VizOrientation, getFieldConfigWithMinMax } from '@grafana/data';
import { BarGaugeDisplayMode } from '@grafana/schema';
import { BarGaugeDisplayMode, BarGaugeValueMode } from '@grafana/schema';
import { BarGauge } from '../BarGauge/BarGauge';
import { DataLinksContextMenu, DataLinksContextMenuApi } from '../DataLinks/DataLinksContextMenu';
@@ -26,6 +26,8 @@ const defaultScale: ThresholdsConfig = {
export const BarGaugeCell: FC<TableCellProps> = (props) => {
const { field, innerWidth, tableStyles, cell, cellProps, row } = props;
const displayValue = field.display!(cell.value);
const cellOptions = getCellOptions(field);
let config = getFieldConfigWithMinMax(field, false);
if (!config.thresholds) {
@@ -35,14 +37,15 @@ export const BarGaugeCell: FC<TableCellProps> = (props) => {
};
}
const displayValue = field.display!(cell.value);
// Set default display mode
// Set default display mode and update if defined
// and update the valueMode if defined
let barGaugeMode: BarGaugeDisplayMode = BarGaugeDisplayMode.Gradient;
let valueDisplayMode: BarGaugeValueMode | undefined = undefined;
const cellOptions = getCellOptions(field);
if (cellOptions.type === TableCellDisplayMode.Gauge) {
barGaugeMode = cellOptions.mode ?? BarGaugeDisplayMode.Gradient;
valueDisplayMode =
cellOptions.valueDisplayMode !== undefined ? cellOptions.valueDisplayMode : BarGaugeValueMode.Text;
}
const getLinks = () => {
@@ -73,6 +76,7 @@ export const BarGaugeCell: FC<TableCellProps> = (props) => {
itemSpacing={1}
lcdCellWidth={8}
displayMode={barGaugeMode}
valueDisplayMode={valueDisplayMode}
/>
);
};
@@ -84,21 +88,7 @@ export const BarGaugeCell: FC<TableCellProps> = (props) => {
{(api) => renderComponent(api)}
</DataLinksContextMenu>
)}
{!hasLinks && (
<BarGauge
width={innerWidth}
height={tableStyles.cellHeightInner}
field={config}
display={field.display}
text={{ valueSize: 14 }}
value={displayValue}
orientation={VizOrientation.Horizontal}
theme={tableStyles.theme}
itemSpacing={1}
lcdCellWidth={8}
displayMode={barGaugeMode}
/>
)}
{!hasLinks && renderComponent({})}
</div>
);
};

View File

@@ -701,6 +701,9 @@ type Threshold struct {
// TODO docs
Color string `json:"color"`
// Threshold index, an old property that is not needed an should only appear in older dashboards
Index *int32 `json:"index,omitempty"`
// TODO docs
// TODO are the values here enumerable into a disjunction?
// Some seem to be listed in typescript comment

View File

@@ -296,7 +296,7 @@
0
],
"description": "A Grafana dashboard.",
"grafanaMaturityCount": 139,
"grafanaMaturityCount": 140,
"lineageIsGroup": false,
"links": {
"docs": "https://grafana.com/docs/grafana/next/developers/kinds/core/dashboard/schema-reference",

View File

@@ -12,12 +12,11 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/expr"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"

View File

@@ -4,7 +4,7 @@ import React from 'react';
import { dateMath, dateTime, EventBus, LoadingState, TimeRange, toDataFrame, VizOrientation } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { BarGaugeDisplayMode } from '@grafana/schema';
import { BarGaugeDisplayMode, BarGaugeValueMode } from '@grafana/schema';
import { BarGaugePanel, BarGaugePanelProps } from './BarGaugePanel';
@@ -101,6 +101,7 @@ function buildPanelData(overrideValues?: Partial<BarGaugePanelProps>): BarGaugeP
showUnfilled: true,
minVizHeight: 10,
minVizWidth: 0,
valueMode: BarGaugeValueMode.Color,
},
transparent: false,
timeRange,

View File

@@ -49,6 +49,7 @@ export class BarGaugePanel extends PureComponent<BarGaugePanelProps> {
className={targetClassName}
alignmentFactors={count > 1 ? alignmentFactors : undefined}
showUnfilled={options.showUnfilled}
valueDisplayMode={options.valueMode}
/>
);
};

View File

@@ -1,5 +1,5 @@
import { PanelPlugin, VizOrientation } from '@grafana/data';
import { BarGaugeDisplayMode } from '@grafana/schema';
import { BarGaugeDisplayMode, BarGaugeValueMode } from '@grafana/schema';
import { commonOptionsBuilder, sharedSingleStatPanelChangedHandler } from '@grafana/ui';
import { addOrientationOption, addStandardDataReduceOptions } from '../stat/common';
@@ -29,6 +29,18 @@ export const plugin = new PanelPlugin<PanelOptions>(BarGaugePanel)
},
defaultValue: defaultPanelOptions.displayMode,
})
.addRadio({
path: 'valueMode',
name: 'Value display',
settings: {
options: [
{ value: BarGaugeValueMode.Color, label: 'Value color' },
{ value: BarGaugeValueMode.Text, label: 'Text color' },
{ value: BarGaugeValueMode.Hidden, label: 'Hidden' },
],
},
defaultValue: defaultPanelOptions.valueMode,
})
.addBooleanSwitch({
path: 'showUnfilled',
name: 'Show unfilled area',

View File

@@ -29,6 +29,7 @@ composableKinds: PanelCfg: {
PanelOptions: {
common.SingleStatBaseOptions
displayMode: common.BarGaugeDisplayMode | *"gradient"
valueMode: common.BarGaugeValueMode | *"color"
showUnfilled: bool | *true
minVizWidth: uint32 | *0
minVizHeight: uint32 | *10

View File

@@ -17,6 +17,7 @@ export interface PanelOptions extends common.SingleStatBaseOptions {
minVizHeight: number;
minVizWidth: number;
showUnfilled: boolean;
valueMode: common.BarGaugeValueMode;
}
export const defaultPanelOptions: Partial<PanelOptions> = {
@@ -24,4 +25,5 @@ export const defaultPanelOptions: Partial<PanelOptions> = {
minVizHeight: 10,
minVizWidth: 0,
showUnfilled: true,
valueMode: common.BarGaugeValueMode.Color,
};

View File

@@ -1,10 +1,11 @@
import { css } from '@emotion/css';
import { merge } from 'lodash';
import React, { useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
import { TableCellOptions } from '@grafana/schema';
import { Field, Select, TableCellDisplayMode } from '@grafana/ui';
import { Field, Select, TableCellDisplayMode, useStyles2 } from '@grafana/ui';
import { BarGaugeCellOptionsEditor } from './cells/BarGaugeCellOptionsEditor';
import { ColorBackgroundCellOptionsEditor } from './cells/ColorBackgroundCellOptionsEditor';
@@ -25,8 +26,8 @@ interface Props {
export const TableCellOptionEditor = ({ value, onChange }: Props) => {
const cellType = value.type;
const styles = useStyles2(getStyles);
const currentMode = cellDisplayModeOptions.find((o) => o.value!.type === cellType)!;
let [settingCache, setSettingCache] = useState<Record<string, TableCellOptions>>({});
// Update display mode on change
@@ -56,7 +57,7 @@ export const TableCellOptionEditor = ({ value, onChange }: Props) => {
// Setup and inject editor
return (
<>
<div className={styles.fixBottomMargin}>
<Field>
<Select options={cellDisplayModeOptions} value={currentMode} onChange={onCellTypeChange} />
</Field>
@@ -69,7 +70,7 @@ export const TableCellOptionEditor = ({ value, onChange }: Props) => {
{cellType === TableCellDisplayMode.Sparkline && (
<SparklineCellOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />
)}
</>
</div>
);
};
@@ -87,3 +88,9 @@ const cellDisplayModeOptions: Array<SelectableValue<TableCellOptions>> = [
{ value: { type: TableCellDisplayMode.JSONView }, label: 'JSON View' },
{ value: { type: TableCellDisplayMode.Image }, label: 'Image' },
];
const getStyles = (theme: GrafanaTheme2) => ({
fixBottomMargin: css({
marginBottom: theme.spacing(-2),
}),
});

View File

@@ -1,32 +1,46 @@
import React from 'react';
import { SelectableValue } from '@grafana/data';
import { BarGaugeDisplayMode, TableBarGaugeCellOptions } from '@grafana/schema';
import { Field, HorizontalGroup, Select } from '@grafana/ui';
import { Stack } from '@grafana/experimental';
import { BarGaugeDisplayMode, BarGaugeValueMode, TableBarGaugeCellOptions } from '@grafana/schema';
import { Field, RadioButtonGroup, Select } from '@grafana/ui';
import { TableCellEditorProps } from '../TableCellOptionEditor';
type Props = TableCellEditorProps<TableBarGaugeCellOptions>;
export function BarGaugeCellOptionsEditor({ cellOptions, onChange }: Props) {
// Set the display mode on change
const onCellOptionsChange = (v: SelectableValue) => {
cellOptions.mode = v.value;
onChange(cellOptions);
};
const onValueModeChange = (v: BarGaugeValueMode) => {
cellOptions.valueDisplayMode = v;
onChange(cellOptions);
};
return (
<Stack direction="column" gap={0}>
<Field label="Gauge display mode">
<Select value={cellOptions?.mode} onChange={onCellOptionsChange} options={barGaugeOpts} />
</Field>
<Field label="Value display">
<RadioButtonGroup value={cellOptions?.valueDisplayMode} onChange={onValueModeChange} options={valueModes} />
</Field>
</Stack>
);
}
const barGaugeOpts: SelectableValue[] = [
{ value: BarGaugeDisplayMode.Basic, label: 'Basic' },
{ value: BarGaugeDisplayMode.Gradient, label: 'Gradient' },
{ value: BarGaugeDisplayMode.Lcd, label: 'Retro LCD' },
];
export const BarGaugeCellOptionsEditor = ({
cellOptions,
onChange,
}: TableCellEditorProps<TableBarGaugeCellOptions>) => {
// Set the display mode on change
const onCellOptionsChange = (v: SelectableValue) => {
cellOptions.mode = v.value;
onChange(cellOptions);
};
return (
<HorizontalGroup>
<Field label="Gauge Display Mode">
<Select value={cellOptions?.mode} onChange={onCellOptionsChange} options={barGaugeOpts} />
</Field>
</HorizontalGroup>
);
};
const valueModes: SelectableValue[] = [
{ value: BarGaugeValueMode.Color, label: 'Value color' },
{ value: BarGaugeValueMode.Text, label: 'Text color' },
{ value: BarGaugeValueMode.Hidden, label: 'Hidden' },
];

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { SelectableValue } from '@grafana/data';
import { TableCellBackgroundDisplayMode, TableColoredBackgroundCellOptions } from '@grafana/schema';
import { HorizontalGroup, Select, Field } from '@grafana/ui';
import { Select, Field } from '@grafana/ui';
import { TableCellEditorProps } from '../TableCellOptionEditor';
@@ -22,10 +22,8 @@ export const ColorBackgroundCellOptionsEditor = ({
};
return (
<HorizontalGroup>
<Field label="Background display mode">
<Select value={cellOptions?.mode} onChange={onCellOptionsChange} options={colorBackgroundOpts} />
</Field>
</HorizontalGroup>
<Field label="Background display mode">
<Select value={cellOptions?.mode} onChange={onCellOptionsChange} options={colorBackgroundOpts} />
</Field>
);
};

View File

@@ -23,7 +23,7 @@ import { PanelOptions, defaultPanelOptions } from './panelcfg.gen';
import { TableSuggestionsSupplier } from './suggestions';
const footerCategory = 'Table footer';
const cellCategory = ['Cell Options'];
const cellCategory = ['Cell options'];
export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePanel)
.setPanelChangeHandler(tablePanelChangedHandler)
@@ -70,7 +70,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
.addCustomEditor<void, TableCellOptions>({
id: 'cellOptions',
path: 'cellOptions',
name: 'Cell Type',
name: 'Cell type',
editor: TableCellOptionEditor,
override: TableCellOptionEditor,
defaultValue: defaultTableFieldOptions.cellOptions,