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:
authored and GitHub committed 2023-03-10 14:41:46 +01:00
1 parent 0a4d9f01e8
commit 73ce20ab48
25 files changed
+2259 -1570

No files matched your search

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -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 |
@@ -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
@@ -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.
+4 -2
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
@@ -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;
}
/**
@@ -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
@@ -52,6 +52,7 @@ TableImageCellOptions: {
TableBarGaugeCellOptions: {
type: TableCellDisplayMode & "gauge"
mode?: BarGaugeDisplayMode
valueDisplayMode?: BarGaugeValueMode
} @cuetsy(kind="interface")
// Sparkline cell options
@@ -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?
@@ -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');
});
});
});
@@ -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;
@@ -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>
);
};
@@ -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
+1 -1
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",
@@ -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"
@@ -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,
@@ -49,6 +49,7 @@ export class BarGaugePanel extends PureComponent<BarGaugePanelProps> {
className={targetClassName}
alignmentFactors={count > 1 ? alignmentFactors : undefined}
showUnfilled={options.showUnfilled}
valueDisplayMode={options.valueMode}
/>
);
};
+13 -1
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',
@@ -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
@@ -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,
};
@@ -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),
}),
});
@@ -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' },
];
@@ -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>
);
};
+2 -2
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,