mirror of https://github.com/grafana/grafana.git
NewGauge: Adds new feature toggle named newGauge (#112593)
* NewGauge: Feature toggle and fixes * Gauge: New migration test dashboard * Update * Updates * Tweaked default barWidth * Fix multi data links * remove sizing options * merge fix * Update * Restore * Update * Tweaked name font size logic * use file snapshots instead of inline --------- Co-authored-by: Paul Marbach <paul.marbach@grafana.com>
This commit is contained in:
parent
17771e0e1d
commit
7df537c9fc
1105
apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json
vendored
Normal file
1105
apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -38,6 +38,7 @@
|
||||||
"gauge-multi-series": (import '../dev-dashboards/panel-gauge/gauge-multi-series.json'),
|
"gauge-multi-series": (import '../dev-dashboards/panel-gauge/gauge-multi-series.json'),
|
||||||
"gauge_tests": (import '../dev-dashboards/panel-gauge/gauge_tests.json'),
|
"gauge_tests": (import '../dev-dashboards/panel-gauge/gauge_tests.json'),
|
||||||
"gauge_tests_new": (import '../dev-dashboards/panel-gauge/gauge_tests_new.json'),
|
"gauge_tests_new": (import '../dev-dashboards/panel-gauge/gauge_tests_new.json'),
|
||||||
|
"gauge_tests_old_to_new": (import '../dev-dashboards/panel-gauge/gauge_tests_old_to_new.json'),
|
||||||
"geomap-color-field": (import '../dev-dashboards/panel-geomap/geomap-color-field.json'),
|
"geomap-color-field": (import '../dev-dashboards/panel-geomap/geomap-color-field.json'),
|
||||||
"geomap-photo-layer": (import '../dev-dashboards/panel-geomap/geomap-photo-layer.json'),
|
"geomap-photo-layer": (import '../dev-dashboards/panel-geomap/geomap-photo-layer.json'),
|
||||||
"geomap-route-layer": (import '../dev-dashboards/panel-geomap/geomap-route-layer.json'),
|
"geomap-route-layer": (import '../dev-dashboards/panel-geomap/geomap-route-layer.json'),
|
||||||
|
|
|
||||||
|
|
@ -1218,6 +1218,11 @@ export interface FeatureToggles {
|
||||||
*/
|
*/
|
||||||
cdnPluginsUrls?: boolean;
|
cdnPluginsUrls?: boolean;
|
||||||
/**
|
/**
|
||||||
|
* Enable new gauge visualization
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
newGauge?: boolean;
|
||||||
|
/**
|
||||||
* Restrict PanelChrome contents with overflow: hidden;
|
* Restrict PanelChrome contents with overflow: hidden;
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export interface GaugePanelEffects {
|
||||||
|
|
||||||
export const defaultGaugePanelEffects: Partial<GaugePanelEffects> = {
|
export const defaultGaugePanelEffects: Partial<GaugePanelEffects> = {
|
||||||
barGlow: false,
|
barGlow: false,
|
||||||
centerGlow: true,
|
centerGlow: false,
|
||||||
rounded: false,
|
rounded: false,
|
||||||
spotlight: false,
|
spotlight: false,
|
||||||
};
|
};
|
||||||
|
|
@ -39,13 +39,13 @@ export interface Options extends common.SingleStatBaseOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultOptions: Partial<Options> = {
|
export const defaultOptions: Partial<Options> = {
|
||||||
barWidthFactor: 0.4,
|
barWidthFactor: 0.5,
|
||||||
effects: {},
|
effects: {},
|
||||||
gradient: 'none',
|
gradient: 'auto',
|
||||||
segmentCount: 1,
|
segmentCount: 1,
|
||||||
segmentSpacing: 0.3,
|
segmentSpacing: 0.3,
|
||||||
shape: 'gauge',
|
shape: 'gauge',
|
||||||
showThresholdLabels: false,
|
showThresholdLabels: false,
|
||||||
showThresholdMarkers: true,
|
showThresholdMarkers: true,
|
||||||
sparkline: false,
|
sparkline: true,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,12 @@ export class RadialColorDefs {
|
||||||
|
|
||||||
this.defs.push(
|
this.defs.push(
|
||||||
<radialGradient
|
<radialGradient
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
cx={dimensions.centerX}
|
cx={dimensions.centerX}
|
||||||
cy={dimensions.centerY}
|
cy={dimensions.centerY}
|
||||||
r={dimensions.radius + dimensions.barWidth / 2}
|
r={dimensions.radius + dimensions.barWidth / 2}
|
||||||
fr={dimensions.radius - dimensions.barWidth / 2}
|
fr={dimensions.radius - dimensions.barWidth / 2}
|
||||||
id={id}
|
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop offset="0%" stopColor={tinycolor(baseColor).spin(20).lighten(10).toString()} stopOpacity={1} />
|
<stop offset="0%" stopColor={tinycolor(baseColor).spin(20).lighten(10).toString()} stopOpacity={1} />
|
||||||
|
|
@ -85,6 +86,8 @@ export class RadialColorDefs {
|
||||||
<stop offset="100%" stopColor={color1.toString()} stopOpacity={1} />
|
<stop offset="100%" stopColor={color1.toString()} stopOpacity={1} />
|
||||||
</radialGradient>
|
</radialGradient>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return returnColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For fixed / palette based color scales we can create a more fun
|
// For fixed / palette based color scales we can create a more fun
|
||||||
|
|
@ -103,11 +106,12 @@ export class RadialColorDefs {
|
||||||
|
|
||||||
this.defs.push(
|
this.defs.push(
|
||||||
<linearGradient
|
<linearGradient
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
x1="0"
|
x1="0"
|
||||||
y1="0"
|
y1="0"
|
||||||
x2={x2}
|
x2={x2}
|
||||||
y2={y2}
|
y2={y2}
|
||||||
id={id}
|
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
gradientTransform={transform}
|
gradientTransform={transform}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { css } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { isNumber } from 'lodash';
|
import { isNumber } from 'lodash';
|
||||||
import { useId } from 'react';
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
|
@ -64,6 +64,8 @@ export interface RadialGaugeProps {
|
||||||
/** Specify which text should be visible */
|
/** Specify which text should be visible */
|
||||||
textMode?: RadialTextMode;
|
textMode?: RadialTextMode;
|
||||||
showScaleLabels?: boolean;
|
showScaleLabels?: boolean;
|
||||||
|
/** For data links */
|
||||||
|
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RadialGradientMode = 'none' | 'auto';
|
export type RadialGradientMode = 'none' | 'auto';
|
||||||
|
|
@ -87,6 +89,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||||
roundedBars = true,
|
roundedBars = true,
|
||||||
thresholdsBar = false,
|
thresholdsBar = false,
|
||||||
showScaleLabels = false,
|
showScaleLabels = false,
|
||||||
|
onClick,
|
||||||
values,
|
values,
|
||||||
} = props;
|
} = props;
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
|
|
@ -247,13 +250,27 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const body = (
|
||||||
<div className={styles.vizWrapper} style={{ width, height }}>
|
<>
|
||||||
<svg width={width} height={height} role="img" aria-label={t('gauge.category-gauge', 'Gauge')}>
|
<svg width={width} height={height} role="img" aria-label={t('gauge.category-gauge', 'Gauge')}>
|
||||||
<defs>{defs}</defs>
|
<defs>{defs}</defs>
|
||||||
{graphics}
|
{graphics}
|
||||||
</svg>
|
</svg>
|
||||||
{sparklineElement}
|
{sparklineElement}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (onClick) {
|
||||||
|
return (
|
||||||
|
<button onClick={onClick} className={cx(styles.clearButton, styles.vizWrapper)} style={{ width, height }}>
|
||||||
|
{body}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.vizWrapper} style={{ width, height }}>
|
||||||
|
{body}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -281,5 +298,12 @@ function getStyles(theme: GrafanaTheme2) {
|
||||||
filter: theme.isLight ? `drop-shadow(0px 0px 1px #888);` : '',
|
filter: theme.isLight ? `drop-shadow(0px 0px 1px #888);` : '',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
clearButton: css({
|
||||||
|
background: 'transparent',
|
||||||
|
color: theme.colors.text.primary,
|
||||||
|
border: 'none',
|
||||||
|
padding: 0,
|
||||||
|
cursor: 'context-menu',
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export function RadialSparkline({ sparkline, dimensions, theme, color, shape }:
|
||||||
const height = radius / 4;
|
const height = radius / 4;
|
||||||
const widthFactor = shape === 'gauge' ? 1.6 : 1.4;
|
const widthFactor = shape === 'gauge' ? 1.6 : 1.4;
|
||||||
const width = radius * widthFactor - barWidth;
|
const width = radius * widthFactor - barWidth;
|
||||||
const topPos = shape === 'gauge' ? `calc(50% + ${radius / 1.75}px)` : `calc(50% + ${radius / 2.8}px)`;
|
const topPos = shape === 'gauge' ? `${dimensions.gaugeBottomY - height}px` : `calc(50% + ${radius / 2.8}px)`;
|
||||||
|
|
||||||
const styles = css({
|
const styles = css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,9 @@ export function RadialText({
|
||||||
|
|
||||||
// Not sure where this comes from but svg text is not using body line-height
|
// Not sure where this comes from but svg text is not using body line-height
|
||||||
const lineHeight = 1.21;
|
const lineHeight = 1.21;
|
||||||
const valueWidthToRadiusFactor = 0.6;
|
const valueWidthToRadiusFactor = 0.85;
|
||||||
const nameToHeightFactor = 0.3;
|
const nameToHeightFactor = 0.45;
|
||||||
const largeRadiusScalingDecay = 0.92;
|
const largeRadiusScalingDecay = 0.86;
|
||||||
|
|
||||||
// This pow 0.92 factor is to create a decay so the font size does not become rediculously large for very large panels
|
// This pow 0.92 factor is to create a decay so the font size does not become rediculously large for very large panels
|
||||||
let maxValueHeight = valueWidthToRadiusFactor * Math.pow(radius, largeRadiusScalingDecay);
|
let maxValueHeight = valueWidthToRadiusFactor * Math.pow(radius, largeRadiusScalingDecay);
|
||||||
|
|
@ -99,7 +99,8 @@ export function RadialText({
|
||||||
const nameHeight = nameFontSize * lineHeight;
|
const nameHeight = nameFontSize * lineHeight;
|
||||||
|
|
||||||
const valueY = showName ? centerY - nameHeight / 2 : centerY;
|
const valueY = showName ? centerY - nameHeight / 2 : centerY;
|
||||||
const nameY = showValue ? valueY + valueHeight * 0.7 : centerY;
|
const valueNameSpacing = valueHeight / 3.5;
|
||||||
|
const nameY = showValue ? valueY + valueHeight / 2 + valueNameSpacing : centerY;
|
||||||
const nameColor = showValue ? theme.colors.text.secondary : theme.colors.text.primary;
|
const nameColor = showValue ? theme.colors.text.secondary : theme.colors.text.primary;
|
||||||
const suffixShift = (valueFontSize - unitFontSize * 1.2) / 2;
|
const suffixShift = (valueFontSize - unitFontSize * 1.2) / 2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,15 @@ export function ThresholdsBar({
|
||||||
|
|
||||||
for (let i = 1; i < thresholds.length; i++) {
|
for (let i = 1; i < thresholds.length; i++) {
|
||||||
const threshold = thresholds[i];
|
const threshold = thresholds[i];
|
||||||
const valueDeg = ((threshold.value - min) / (max - min)) * angleRange;
|
let valueDeg = ((threshold.value - min) / (max - min)) * angleRange;
|
||||||
const lengthDeg = valueDeg - currentStart + startAngle;
|
|
||||||
|
if (valueDeg > angleRange) {
|
||||||
|
valueDeg = angleRange;
|
||||||
|
} else if (valueDeg < 0) {
|
||||||
|
valueDeg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lengthDeg = valueDeg - currentStart + startAngle;
|
||||||
|
|
||||||
paths.push(
|
paths.push(
|
||||||
<RadialArcPath
|
<RadialArcPath
|
||||||
|
|
|
||||||
|
|
@ -178,5 +178,20 @@ describe('RadialGauge utils', () => {
|
||||||
|
|
||||||
expect(result.angle).toBe(360);
|
expect(result.angle).toBe(360);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle values lower than min', () => {
|
||||||
|
const fieldDisplay = createFieldDisplay(-50, 0, 100);
|
||||||
|
const result = getValueAngleForValue(fieldDisplay, 240, 120);
|
||||||
|
|
||||||
|
expect(result.angle).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle values higher than max', () => {
|
||||||
|
const fieldDisplay = createFieldDisplay(200, 0, 100);
|
||||||
|
const result = getValueAngleForValue(fieldDisplay, 240, 120);
|
||||||
|
|
||||||
|
// Expect the angle to be clamped to the maximum range
|
||||||
|
expect(result.angle).toBe(240);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ export function getValueAngleForValue(fieldDisplay: FieldDisplay, startAngle: nu
|
||||||
|
|
||||||
if (angle > angleRange) {
|
if (angle > angleRange) {
|
||||||
angle = angleRange;
|
angle = angleRange;
|
||||||
|
} else if (angle < 0) {
|
||||||
|
angle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { angleRange, angle };
|
return { angleRange, angle };
|
||||||
|
|
@ -39,6 +41,7 @@ export interface GaugeDimensions {
|
||||||
scaleLabelsFontSize: number;
|
scaleLabelsFontSize: number;
|
||||||
scaleLabelsSpacing: number;
|
scaleLabelsSpacing: number;
|
||||||
scaleLabelsRadius: number;
|
scaleLabelsRadius: number;
|
||||||
|
gaugeBottomY: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateDimensions(
|
export function calculateDimensions(
|
||||||
|
|
@ -119,8 +122,8 @@ export function calculateDimensions(
|
||||||
|
|
||||||
let innerRadius = outerRadius - barWidth / 2;
|
let innerRadius = outerRadius - barWidth / 2;
|
||||||
|
|
||||||
const maxY = maxRadius * Math.sin(toRad(yMaxAngle)) + maxRadius;
|
const belowCenterY = maxRadius * Math.sin(toRad(yMaxAngle));
|
||||||
const rest = height - maxY - margin * 2;
|
const rest = height - belowCenterY - margin * 2 - maxRadius;
|
||||||
const centerX = width / 2;
|
const centerX = width / 2;
|
||||||
const centerY = maxRadius + margin + rest / 2;
|
const centerY = maxRadius + margin + rest / 2;
|
||||||
|
|
||||||
|
|
@ -130,6 +133,7 @@ export function calculateDimensions(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
margin,
|
margin,
|
||||||
|
gaugeBottomY: centerY + belowCenterY,
|
||||||
radius: innerRadius,
|
radius: innerRadius,
|
||||||
centerX,
|
centerX,
|
||||||
centerY,
|
centerY,
|
||||||
|
|
|
||||||
|
|
@ -2110,6 +2110,14 @@ var (
|
||||||
Owner: grafanaPluginsPlatformSquad,
|
Owner: grafanaPluginsPlatformSquad,
|
||||||
Expression: "false",
|
Expression: "false",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "newGauge",
|
||||||
|
Description: "Enable new gauge visualization",
|
||||||
|
Stage: FeatureStageExperimental,
|
||||||
|
FrontendOnly: true,
|
||||||
|
Owner: grafanaDatavizSquad,
|
||||||
|
Expression: "false",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "preventPanelChromeOverflow",
|
Name: "preventPanelChromeOverflow",
|
||||||
Description: "Restrict PanelChrome contents with overflow: hidden;",
|
Description: "Restrict PanelChrome contents with overflow: hidden;",
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,7 @@ pluginContainers,privatePreview,@grafana/plugins-platform-backend,false,true,fal
|
||||||
tempoSearchBackendMigration,GA,@grafana/oss-big-tent,false,true,false
|
tempoSearchBackendMigration,GA,@grafana/oss-big-tent,false,true,false
|
||||||
cdnPluginsLoadFirst,experimental,@grafana/plugins-platform-backend,false,false,false
|
cdnPluginsLoadFirst,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||||
cdnPluginsUrls,experimental,@grafana/plugins-platform-backend,false,false,false
|
cdnPluginsUrls,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||||
|
newGauge,experimental,@grafana/dataviz-squad,false,false,true
|
||||||
preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true
|
preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true
|
||||||
pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false
|
pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||||
onlyStoreActionSets,GA,@grafana/identity-access-team,false,false,false
|
onlyStoreActionSets,GA,@grafana/identity-access-team,false,false,false
|
||||||
|
|
|
||||||
|
|
|
@ -1094,6 +1094,10 @@ const (
|
||||||
// Enable loading plugins via declarative URLs
|
// Enable loading plugins via declarative URLs
|
||||||
FlagCdnPluginsUrls = "cdnPluginsUrls"
|
FlagCdnPluginsUrls = "cdnPluginsUrls"
|
||||||
|
|
||||||
|
// FlagNewGauge
|
||||||
|
// Enable new gauge visualization
|
||||||
|
FlagNewGauge = "newGauge"
|
||||||
|
|
||||||
// FlagPreventPanelChromeOverflow
|
// FlagPreventPanelChromeOverflow
|
||||||
// Restrict PanelChrome contents with overflow: hidden;
|
// Restrict PanelChrome contents with overflow: hidden;
|
||||||
FlagPreventPanelChromeOverflow = "preventPanelChromeOverflow"
|
FlagPreventPanelChromeOverflow = "preventPanelChromeOverflow"
|
||||||
|
|
|
||||||
|
|
@ -2694,6 +2694,20 @@
|
||||||
"expression": "true"
|
"expression": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "newGauge",
|
||||||
|
"resourceVersion": "1760700645318",
|
||||||
|
"creationTimestamp": "2025-10-17T11:30:45Z"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"description": "Enable new gauge visualization",
|
||||||
|
"stage": "experimental",
|
||||||
|
"codeowner": "@grafana/dataviz-squad",
|
||||||
|
"frontend": true,
|
||||||
|
"expression": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "newInfluxDSConfigPageDesign",
|
"name": "newInfluxDSConfigPageDesign",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
|
|
||||||
const cloudwatchPlugin = async () =>
|
const cloudwatchPlugin = async () =>
|
||||||
await import(/* webpackChunkName: "cloudwatchPlugin" */ 'app/plugins/datasource/cloudwatch/module');
|
await import(/* webpackChunkName: "cloudwatchPlugin" */ 'app/plugins/datasource/cloudwatch/module');
|
||||||
const dashboardDSPlugin = async () =>
|
const dashboardDSPlugin = async () =>
|
||||||
|
|
@ -104,7 +106,7 @@ const builtInPlugins: Record<string, System.Module | (() => Promise<System.Modul
|
||||||
'core:plugin/debug': debugPanel,
|
'core:plugin/debug': debugPanel,
|
||||||
'core:plugin/flamegraph': flamegraphPanel,
|
'core:plugin/flamegraph': flamegraphPanel,
|
||||||
'core:plugin/gettingstarted': gettingStartedPanel,
|
'core:plugin/gettingstarted': gettingStartedPanel,
|
||||||
'core:plugin/gauge': gaugePanel,
|
'core:plugin/gauge': config.featureToggles.newGauge ? radialBar : gaugePanel,
|
||||||
'core:plugin/piechart': pieChartPanel,
|
'core:plugin/piechart': pieChartPanel,
|
||||||
'core:plugin/bargauge': barGaugePanel,
|
'core:plugin/bargauge': barGaugePanel,
|
||||||
'core:plugin/barchart': barChartPanel,
|
'core:plugin/barchart': barChartPanel,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,10 @@
|
||||||
"$ref": "#/definitions/DeepPartial<ThemeRichColor>"
|
"$ref": "#/definitions/DeepPartial<ThemeRichColor>"
|
||||||
},
|
},
|
||||||
"mode": {
|
"mode": {
|
||||||
"enum": ["dark", "light"],
|
"enum": [
|
||||||
|
"dark",
|
||||||
|
"light"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
|
|
@ -350,27 +353,63 @@
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName": {
|
"ThemeVizColorShadeName": {
|
||||||
"enum": ["dark-red", "light-red", "red", "semi-dark-red", "super-light-red"],
|
"enum": [
|
||||||
|
"dark-red",
|
||||||
|
"light-red",
|
||||||
|
"red",
|
||||||
|
"semi-dark-red",
|
||||||
|
"super-light-red"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName_1": {
|
"ThemeVizColorShadeName_1": {
|
||||||
"enum": ["dark-orange", "light-orange", "orange", "semi-dark-orange", "super-light-orange"],
|
"enum": [
|
||||||
|
"dark-orange",
|
||||||
|
"light-orange",
|
||||||
|
"orange",
|
||||||
|
"semi-dark-orange",
|
||||||
|
"super-light-orange"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName_2": {
|
"ThemeVizColorShadeName_2": {
|
||||||
"enum": ["dark-yellow", "light-yellow", "semi-dark-yellow", "super-light-yellow", "yellow"],
|
"enum": [
|
||||||
|
"dark-yellow",
|
||||||
|
"light-yellow",
|
||||||
|
"semi-dark-yellow",
|
||||||
|
"super-light-yellow",
|
||||||
|
"yellow"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName_3": {
|
"ThemeVizColorShadeName_3": {
|
||||||
"enum": ["dark-green", "green", "light-green", "semi-dark-green", "super-light-green"],
|
"enum": [
|
||||||
|
"dark-green",
|
||||||
|
"green",
|
||||||
|
"light-green",
|
||||||
|
"semi-dark-green",
|
||||||
|
"super-light-green"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName_4": {
|
"ThemeVizColorShadeName_4": {
|
||||||
"enum": ["blue", "dark-blue", "light-blue", "semi-dark-blue", "super-light-blue"],
|
"enum": [
|
||||||
|
"blue",
|
||||||
|
"dark-blue",
|
||||||
|
"light-blue",
|
||||||
|
"semi-dark-blue",
|
||||||
|
"super-light-blue"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizColorShadeName_5": {
|
"ThemeVizColorShadeName_5": {
|
||||||
"enum": ["dark-purple", "light-purple", "purple", "semi-dark-purple", "super-light-purple"],
|
"enum": [
|
||||||
|
"dark-purple",
|
||||||
|
"light-purple",
|
||||||
|
"purple",
|
||||||
|
"semi-dark-purple",
|
||||||
|
"super-light-purple"
|
||||||
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ThemeVizHue": {
|
"ThemeVizHue": {
|
||||||
|
|
@ -509,3 +548,4 @@
|
||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,56 +88,7 @@ describe('Gauge Panel Migrations', () => {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
expect(result.reduceOptions.overrides).toBeUndefined();
|
expect(result.reduceOptions.overrides).toBeUndefined();
|
||||||
|
|
||||||
expect((panel as PanelModel).fieldConfig).toMatchInlineSnapshot(`
|
expect((panel as PanelModel).fieldConfig).toMatchSnapshot();
|
||||||
{
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "thresholds",
|
|
||||||
},
|
|
||||||
"decimals": 3,
|
|
||||||
"mappings": [
|
|
||||||
{
|
|
||||||
"from": "50",
|
|
||||||
"id": 1,
|
|
||||||
"operator": "",
|
|
||||||
"text": "BIG",
|
|
||||||
"to": "1000",
|
|
||||||
"type": 2,
|
|
||||||
"value": "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"max": "50",
|
|
||||||
"min": "-50",
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"index": 0,
|
|
||||||
"value": -Infinity,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#EAB839",
|
|
||||||
"index": 1,
|
|
||||||
"value": -25,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#6ED0E0",
|
|
||||||
"index": 2,
|
|
||||||
"value": 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"index": 3,
|
|
||||||
"value": 25,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"unit": "accMS2",
|
|
||||||
},
|
|
||||||
"overrides": [],
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('change from angular singlestat to gauge', () => {
|
it('change from angular singlestat to gauge', () => {
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,54 @@ exports[`Gauge Panel Migrations from 6.1.1 1`] = `
|
||||||
"showThresholdMarkers": true,
|
"showThresholdMarkers": true,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Gauge Panel Migrations from 6.1.1 2`] = `
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds",
|
||||||
|
},
|
||||||
|
"decimals": 3,
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"from": "50",
|
||||||
|
"id": 1,
|
||||||
|
"operator": "",
|
||||||
|
"text": "BIG",
|
||||||
|
"to": "1000",
|
||||||
|
"type": 2,
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"max": "50",
|
||||||
|
"min": "-50",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"value": -Infinity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "#EAB839",
|
||||||
|
"index": 1,
|
||||||
|
"value": -25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "#6ED0E0",
|
||||||
|
"index": 2,
|
||||||
|
"value": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"index": 3,
|
||||||
|
"value": 25,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"unit": "accMS2",
|
||||||
|
},
|
||||||
|
"overrides": [],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
import { PanelModel } from '@grafana/data';
|
||||||
|
import { FieldColorModeId } from '@grafana/schema/dist/esm/index.gen';
|
||||||
|
|
||||||
|
import { gaugePanelMigrationHandler, gaugePanelChangedHandler } from './GaugeMigrations';
|
||||||
|
|
||||||
|
describe('Gauge Panel Migrations', () => {
|
||||||
|
it('from old gauge', () => {
|
||||||
|
const panel = {
|
||||||
|
id: 2,
|
||||||
|
options: {
|
||||||
|
reduceOptions: {
|
||||||
|
calcs: ['lastNotNull'],
|
||||||
|
},
|
||||||
|
showThresholdLabels: false,
|
||||||
|
showThresholdMarkers: true,
|
||||||
|
},
|
||||||
|
fieldConfig: {
|
||||||
|
defaults: {
|
||||||
|
color: {
|
||||||
|
mode: FieldColorModeId.Fixed,
|
||||||
|
fixedColor: 'blue',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
overrides: [],
|
||||||
|
},
|
||||||
|
pluginVersion: '12.3.0',
|
||||||
|
type: 'gauge',
|
||||||
|
} as Omit<PanelModel, 'fieldConfig'>;
|
||||||
|
|
||||||
|
const result = gaugePanelMigrationHandler(panel as PanelModel);
|
||||||
|
expect(result.showThresholdMarkers).toBe(false);
|
||||||
|
expect(result.sparkline).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from 6.1.1', () => {
|
||||||
|
const panel = {
|
||||||
|
datasource: '-- Grafana --',
|
||||||
|
gridPos: {
|
||||||
|
h: 9,
|
||||||
|
w: 12,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
options: {
|
||||||
|
maxValue: '50',
|
||||||
|
minValue: '-50',
|
||||||
|
orientation: 'auto',
|
||||||
|
showThresholdLabels: true,
|
||||||
|
showThresholdMarkers: true,
|
||||||
|
thresholds: [
|
||||||
|
{
|
||||||
|
color: 'green',
|
||||||
|
index: 0,
|
||||||
|
value: -Infinity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#EAB839',
|
||||||
|
index: 1,
|
||||||
|
value: -25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#6ED0E0',
|
||||||
|
index: 2,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: 'red',
|
||||||
|
index: 3,
|
||||||
|
value: 25,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
valueMappings: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
operator: '',
|
||||||
|
value: '',
|
||||||
|
text: 'BIG',
|
||||||
|
type: 2,
|
||||||
|
from: '50',
|
||||||
|
to: '1000',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
valueOptions: {
|
||||||
|
decimals: 3,
|
||||||
|
prefix: 'XX',
|
||||||
|
stat: 'last',
|
||||||
|
suffix: 'YY',
|
||||||
|
unit: 'accMS2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pluginVersion: '6.1.6',
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refId: 'B',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refId: 'C',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
timeFrom: null,
|
||||||
|
timeShift: null,
|
||||||
|
title: 'Panel Title',
|
||||||
|
type: 'gauge',
|
||||||
|
} as Omit<PanelModel, 'fieldConfig'>;
|
||||||
|
|
||||||
|
const result = gaugePanelMigrationHandler(panel as PanelModel);
|
||||||
|
|
||||||
|
// Ignored due to the API change
|
||||||
|
//@ts-ignore
|
||||||
|
expect(result.reduceOptions.defaults).toBeUndefined();
|
||||||
|
// Ignored due to the API change
|
||||||
|
//@ts-ignore
|
||||||
|
expect(result.reduceOptions.overrides).toBeUndefined();
|
||||||
|
|
||||||
|
expect((panel as PanelModel).fieldConfig).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change from angular singlestat to gauge', () => {
|
||||||
|
const old = {
|
||||||
|
angular: {
|
||||||
|
format: 'ms',
|
||||||
|
decimals: 7,
|
||||||
|
gauge: {
|
||||||
|
maxValue: 150,
|
||||||
|
minValue: -10,
|
||||||
|
show: true,
|
||||||
|
thresholdLabels: true,
|
||||||
|
thresholdMarkers: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const panel = {} as PanelModel;
|
||||||
|
const newOptions = gaugePanelChangedHandler(panel, 'singlestat', old, { defaults: {}, overrides: [] });
|
||||||
|
expect(panel.fieldConfig.defaults.unit).toBe('ms');
|
||||||
|
expect(panel.fieldConfig.defaults.min).toBe(-10);
|
||||||
|
expect(panel.fieldConfig.defaults.max).toBe(150);
|
||||||
|
expect(panel.fieldConfig.defaults.decimals).toBe(7);
|
||||||
|
expect(newOptions.showThresholdMarkers).toBe(true);
|
||||||
|
expect(newOptions.showThresholdLabels).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { PanelModel, PanelTypeChangedHandler } from '@grafana/data';
|
||||||
|
import { FieldColorModeId } from '@grafana/schema/dist/esm/index.gen';
|
||||||
|
import { sharedSingleStatPanelChangedHandler, sharedSingleStatMigrationHandler } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { Options } from './panelcfg.gen';
|
||||||
|
|
||||||
|
// This is called when the panel first loads
|
||||||
|
export function gaugePanelMigrationHandler(panel: PanelModel<Options>): Partial<Options> {
|
||||||
|
const sharedOptions = sharedSingleStatMigrationHandler(panel);
|
||||||
|
const newOptions: Partial<Options> = { ...sharedOptions };
|
||||||
|
|
||||||
|
const previousVersion = parseFloat(panel.pluginVersion || '8');
|
||||||
|
const fieldConfig = panel.fieldConfig;
|
||||||
|
|
||||||
|
if (previousVersion <= 12.3) {
|
||||||
|
// This option had no effect in old gauge unless color mode was 'From thresholds'
|
||||||
|
if (newOptions.showThresholdMarkers && fieldConfig?.defaults?.color?.mode !== FieldColorModeId.Thresholds) {
|
||||||
|
newOptions.showThresholdMarkers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This option is enabled by default in new gauge but does not exist in old gauge
|
||||||
|
newOptions.sparkline = false;
|
||||||
|
|
||||||
|
// Remove deprecated sizing options
|
||||||
|
if ('sizing' in newOptions) {
|
||||||
|
delete newOptions.sizing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('minVizHeight' in newOptions) {
|
||||||
|
delete newOptions.minVizHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('minVizWidth' in newOptions) {
|
||||||
|
delete newOptions.minVizWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldMigrateGauge(panel: PanelModel): boolean {
|
||||||
|
const previousVersion = parseFloat(panel.pluginVersion ?? '8');
|
||||||
|
return previousVersion <= 12.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the panel changes from another panel
|
||||||
|
export const gaugePanelChangedHandler: PanelTypeChangedHandler<Options> = (
|
||||||
|
panel,
|
||||||
|
prevPluginId: string,
|
||||||
|
prevOptions
|
||||||
|
) => {
|
||||||
|
// This handles most config changes
|
||||||
|
const opts: Options = sharedSingleStatPanelChangedHandler(panel, prevPluginId, prevOptions);
|
||||||
|
|
||||||
|
// Changing from angular singlestat
|
||||||
|
if (prevPluginId === 'singlestat' && prevOptions.angular) {
|
||||||
|
const gauge = prevOptions.angular.gauge;
|
||||||
|
if (gauge) {
|
||||||
|
opts.showThresholdMarkers = gauge.thresholdMarkers;
|
||||||
|
opts.showThresholdLabels = gauge.thresholdLabels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opts;
|
||||||
|
};
|
||||||
|
|
@ -47,6 +47,7 @@ export function RadialBarPanel({
|
||||||
alignmentFactors={valueProps.alignmentFactors}
|
alignmentFactors={valueProps.alignmentFactors}
|
||||||
valueManualFontSize={options.text?.valueSize}
|
valueManualFontSize={options.text?.valueSize}
|
||||||
nameManualFontSize={options.text?.titleSize}
|
nameManualFontSize={options.text?.titleSize}
|
||||||
|
onClick={menuProps.openMenu}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Gauge Panel Migrations from 6.1.1 1`] = `
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds",
|
||||||
|
},
|
||||||
|
"decimals": 3,
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"from": "50",
|
||||||
|
"id": 1,
|
||||||
|
"operator": "",
|
||||||
|
"text": "BIG",
|
||||||
|
"to": "1000",
|
||||||
|
"type": 2,
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"max": "50",
|
||||||
|
"min": "-50",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"value": -Infinity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "#EAB839",
|
||||||
|
"index": 1,
|
||||||
|
"value": -25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "#6ED0E0",
|
||||||
|
"index": 2,
|
||||||
|
"value": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"index": 3,
|
||||||
|
"value": 25,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"unit": "accMS2",
|
||||||
|
},
|
||||||
|
"overrides": [],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
@ -5,6 +5,7 @@ import { commonOptionsBuilder } from '@grafana/ui';
|
||||||
import { addOrientationOption, addStandardDataReduceOptions } from '../stat/common';
|
import { addOrientationOption, addStandardDataReduceOptions } from '../stat/common';
|
||||||
|
|
||||||
import { EffectsEditor } from './EffectsEditor';
|
import { EffectsEditor } from './EffectsEditor';
|
||||||
|
import { gaugePanelChangedHandler, gaugePanelMigrationHandler, shouldMigrateGauge } from './GaugeMigrations';
|
||||||
import { RadialBarPanel } from './RadialBarPanel';
|
import { RadialBarPanel } from './RadialBarPanel';
|
||||||
import { defaultGaugePanelEffects, defaultOptions, Options } from './panelcfg.gen';
|
import { defaultGaugePanelEffects, defaultOptions, Options } from './panelcfg.gen';
|
||||||
import { GaugeSuggestionsSupplier } from './suggestions';
|
import { GaugeSuggestionsSupplier } from './suggestions';
|
||||||
|
|
@ -111,4 +112,6 @@ export const plugin = new PanelPlugin<Options>(RadialBarPanel)
|
||||||
defaultValue: defaultGaugePanelEffects,
|
defaultValue: defaultGaugePanelEffects,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.setSuggestionsSupplier(new GaugeSuggestionsSupplier());
|
.setSuggestionsSupplier(new GaugeSuggestionsSupplier())
|
||||||
|
.setMigrationHandler(gaugePanelMigrationHandler, shouldMigrateGauge)
|
||||||
|
.setPanelChangeHandler(gaugePanelChangedHandler);
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,9 @@
|
||||||
Gauge => new gauge migration notes
|
Gauge => new gauge migration notes
|
||||||
|
|
||||||
Old gauge "Show threshold markers" does nothing when color scheme != From thresholds
|
Old gauge "Show threshold markers" does nothing when color scheme != From thresholds
|
||||||
|
|
||||||
|
Decide what to do with
|
||||||
|
|
||||||
|
sizing: manual & minVizHeight & minVizWidth (do not think this panel should scroll, and minWidth is broken/does not scroll)
|
||||||
|
neutral value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ composableKinds: PanelCfg: {
|
||||||
barGlow?: bool | *false
|
barGlow?: bool | *false
|
||||||
spotlight?: bool | *false
|
spotlight?: bool | *false
|
||||||
rounded?: bool | *false
|
rounded?: bool | *false
|
||||||
centerGlow?: bool | *true
|
centerGlow?: bool | *false
|
||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
|
|
||||||
Options: {
|
Options: {
|
||||||
|
|
@ -38,10 +38,10 @@ composableKinds: PanelCfg: {
|
||||||
showThresholdLabels: bool | *false
|
showThresholdLabels: bool | *false
|
||||||
segmentCount: number | *1
|
segmentCount: number | *1
|
||||||
segmentSpacing: number | *0.3
|
segmentSpacing: number | *0.3
|
||||||
sparkline?: bool | *false
|
sparkline?: bool | *true
|
||||||
shape: "circle" | *"gauge"
|
shape: "circle" | *"gauge"
|
||||||
barWidthFactor: number | *0.4
|
barWidthFactor: number | *0.5
|
||||||
gradient: *"none" | "auto"
|
gradient: "none" | *"auto"
|
||||||
effects: GaugePanelEffects | *{}
|
effects: GaugePanelEffects | *{}
|
||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export interface GaugePanelEffects {
|
||||||
|
|
||||||
export const defaultGaugePanelEffects: Partial<GaugePanelEffects> = {
|
export const defaultGaugePanelEffects: Partial<GaugePanelEffects> = {
|
||||||
barGlow: false,
|
barGlow: false,
|
||||||
centerGlow: true,
|
centerGlow: false,
|
||||||
rounded: false,
|
rounded: false,
|
||||||
spotlight: false,
|
spotlight: false,
|
||||||
};
|
};
|
||||||
|
|
@ -37,13 +37,13 @@ export interface Options extends common.SingleStatBaseOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultOptions: Partial<Options> = {
|
export const defaultOptions: Partial<Options> = {
|
||||||
barWidthFactor: 0.4,
|
barWidthFactor: 0.5,
|
||||||
effects: {},
|
effects: {},
|
||||||
gradient: 'none',
|
gradient: 'auto',
|
||||||
segmentCount: 1,
|
segmentCount: 1,
|
||||||
segmentSpacing: 0.3,
|
segmentSpacing: 0.3,
|
||||||
shape: 'gauge',
|
shape: 'gauge',
|
||||||
showThresholdLabels: false,
|
showThresholdLabels: false,
|
||||||
showThresholdMarkers: true,
|
showThresholdMarkers: true,
|
||||||
sparkline: false,
|
sparkline: true,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue