StatPanel: ColorMode, GraphMode & JustifyMode changes (#20680)

* StatPanel: Options rethink

* Changed options to string based

* -Fixed tests

* Refactoring moving files

* Refactoring alignment factors

* Added alignment factors

* Added basic test

* Added unit test for layout

* Font size handling

* Font sizing works

* Progress on sizing

* Updated

* Minor update

* Updated

* Updated

* Removed line option

* updated

* Updated

* Updated

* Updated

* Highlight last point

* Fixed tests

* Code refactoring and cleanup

* updated

* Updated snapshot
This commit is contained in:
Torkel Ödegaard
2019-12-01 17:02:44 +01:00
committed by GitHub
parent fcde26e2db
commit 8894e2858c
23 changed files with 942 additions and 728 deletions

View File

@@ -4,36 +4,23 @@ import React, { PureComponent } from 'react';
// Services & Utils
import { config } from 'app/core/config';
import { BarGauge, BarGaugeAlignmentFactors, VizRepeater, DataLinksContextMenu } from '@grafana/ui';
import { BarGauge, VizRepeater, DataLinksContextMenu } from '@grafana/ui';
import { BarGaugeOptions } from './types';
import { getFieldDisplayValues, FieldDisplay, PanelProps } from '@grafana/data';
import {
getFieldDisplayValues,
FieldDisplay,
PanelProps,
getDisplayValueAlignmentFactors,
DisplayValueAlignmentFactors,
} from '@grafana/data';
import { getFieldLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
findMaximumInput = (values: FieldDisplay[], width: number, height: number): BarGaugeAlignmentFactors => {
const info: BarGaugeAlignmentFactors = {
title: '',
text: '',
};
for (let i = 0; i < values.length; i++) {
const v = values[i].display;
if (v.text && v.text.length > info.text.length) {
info.text = v.text;
}
if (v.title && v.title.length > info.title.length) {
info.title = v.title;
}
}
return info;
};
renderValue = (
value: FieldDisplay,
width: number,
height: number,
alignmentFactors: BarGaugeAlignmentFactors
alignmentFactors: DisplayValueAlignmentFactors
): JSX.Element => {
const { options } = this.props;
const { field, display } = value;
@@ -87,7 +74,7 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
return (
<VizRepeater
source={data}
getAlignmentFactors={this.findMaximumInput}
getAlignmentFactors={getDisplayValueAlignmentFactors}
getValues={this.getValues}
renderValue={this.renderValue}
renderCounter={renderCounter}

View File

@@ -15,7 +15,8 @@ import {
import { FieldDisplayOptions, FieldConfig, DataLink, PanelEditorProps } from '@grafana/data';
import { Threshold, ValueMapping } from '@grafana/data';
import { BarGaugeOptions, orientationOptions, displayModes } from './types';
import { BarGaugeOptions, displayModes } from './types';
import { orientationOptions } from '../gauge/types';
import {
getDataLinksVariableSuggestions,
getCalculationValueDataLinksVariableSuggestions,

View File

@@ -12,11 +12,6 @@ export const displayModes: Array<SelectableValue<string>> = [
{ value: 'basic', label: 'Basic' },
];
export const orientationOptions: Array<SelectableValue<VizOrientation>> = [
{ value: VizOrientation.Horizontal, label: 'Horizontal' },
{ value: VizOrientation.Vertical, label: 'Vertical' },
];
export const defaults: BarGaugeOptions = {
displayMode: 'lcd',
orientation: VizOrientation.Horizontal,

View File

@@ -1,4 +1,4 @@
import { VizOrientation, FieldDisplayOptions } from '@grafana/data';
import { VizOrientation, FieldDisplayOptions, SelectableValue } from '@grafana/data';
import { SingleStatBaseOptions } from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
import { standardFieldDisplayOptions } from '../stat/types';
@@ -11,6 +11,12 @@ export const standardGaugeFieldOptions: FieldDisplayOptions = {
...standardFieldDisplayOptions,
};
export const orientationOptions: Array<SelectableValue<VizOrientation>> = [
{ value: VizOrientation.Auto, label: 'Auto' },
{ value: VizOrientation.Horizontal, label: 'Horizontal' },
{ value: VizOrientation.Vertical, label: 'Vertical' },
];
export const defaults: GaugeOptions = {
showThresholdMarkers: true,
showThresholdLabels: false,

View File

@@ -1,23 +0,0 @@
// Libraries
import React, { PureComponent } from 'react';
// Components
import { Switch } from '@grafana/ui';
// Types
import { SparklineOptions } from './types';
interface Props {
options: SparklineOptions;
onChange: (options: SparklineOptions) => void;
}
export class SparklineEditor extends PureComponent<Props> {
onToggleShow = () => this.props.onChange({ ...this.props.options, show: !this.props.options.show });
render() {
const { show } = this.props.options;
return <Switch label="Graph" labelClass="width-8" checked={show} onChange={this.onToggleShow} />;
}
}

View File

@@ -6,22 +6,41 @@ import { config } from 'app/core/config';
// Types
import { StatPanelOptions } from './types';
import { VizRepeater, BigValue, DataLinksContextMenu, BigValueSparkline } from '@grafana/ui';
import { PanelProps, getFieldDisplayValues, FieldDisplay } from '@grafana/data';
import { VizRepeater, BigValue, DataLinksContextMenu, BigValueSparkline, BigValueGraphMode } from '@grafana/ui';
import {
PanelProps,
getFieldDisplayValues,
FieldDisplay,
ReducerID,
getDisplayValueAlignmentFactors,
DisplayValueAlignmentFactors,
VizOrientation,
} from '@grafana/data';
import { getFieldLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
renderValue = (value: FieldDisplay, width: number, height: number): JSX.Element => {
renderValue = (
value: FieldDisplay,
width: number,
height: number,
alignmentFactors: DisplayValueAlignmentFactors
): JSX.Element => {
const { timeRange, options } = this.props;
let sparkline: BigValueSparkline | undefined;
if (value.sparkline) {
sparkline = {
...options.sparkline,
data: value.sparkline,
minX: timeRange.from.valueOf(),
maxX: timeRange.to.valueOf(),
};
const calc = options.fieldOptions.calcs[0];
if (calc === ReducerID.last) {
sparkline.highlightIndex = sparkline.data.length - 1;
}
}
return (
@@ -31,7 +50,10 @@ export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
<BigValue
value={value.display}
sparkline={sparkline}
displayMode={options.displayMode}
colorMode={options.colorMode}
graphMode={options.graphMode}
justifyMode={options.justifyMode}
alignmentFactors={alignmentFactors}
width={width}
height={height}
theme={config.theme}
@@ -52,22 +74,39 @@ export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
replaceVariables,
theme: config.theme,
data: data.series,
sparkline: options.sparkline.show,
sparkline: options.graphMode !== BigValueGraphMode.None,
});
};
render() {
const { height, width, options, data, renderCounter } = this.props;
const { height, options, width, data, renderCounter } = this.props;
return (
<VizRepeater
getValues={this.getValues}
getAlignmentFactors={getDisplayValueAlignmentFactors}
renderValue={this.renderValue}
width={width}
height={height}
source={data}
renderCounter={renderCounter}
orientation={options.orientation}
orientation={getOrientation(width, height, options.orientation)}
/>
);
}
}
/**
* Stat panel custom auto orientation
*/
function getOrientation(width: number, height: number, orientation: VizOrientation): VizOrientation {
if (orientation !== VizOrientation.Auto) {
return orientation;
}
if (width / height > 2) {
return VizOrientation.Vertical;
} else {
return VizOrientation.Horizontal;
}
}

View File

@@ -15,8 +15,9 @@ import {
import { Threshold, ValueMapping, FieldConfig, DataLink, PanelEditorProps, FieldDisplayOptions } from '@grafana/data';
import { StatPanelOptions, SparklineOptions, displayModes } from './types';
import { SparklineEditor } from './SparklineEditor';
import { StatPanelOptions, colorModes, graphModes, justifyModes } from './types';
import { orientationOptions } from '../gauge/types';
import {
getDataLinksVariableSuggestions,
getCalculationValueDataLinksVariableSuggestions,
@@ -45,13 +46,10 @@ export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOpt
fieldOptions,
});
onSparklineChanged = (sparkline: SparklineOptions) =>
this.props.onOptionsChange({
...this.props.options,
sparkline,
});
onDisplayModeChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, displayMode: value });
onColorModeChanged = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, colorMode: value });
onGraphModeChanged = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, graphMode: value });
onJustifyModeChanged = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, justifyMode: value });
onOrientationChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, orientation: value });
onDefaultsChange = (field: FieldConfig) => {
this.onDisplayOptionsChanged({
@@ -81,16 +79,45 @@ export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOpt
<PanelOptionsGroup title="Display">
<FieldDisplayEditor onChange={this.onDisplayOptionsChanged} value={fieldOptions} labelWidth={8} />
<div className="form-field">
<FormLabel width={8}>Display mode</FormLabel>
<FormLabel width={8}>Orientation</FormLabel>
<Select
width={12}
options={displayModes}
defaultValue={displayModes[0]}
onChange={this.onDisplayModeChange}
value={displayModes.find(item => item.value === options.displayMode)}
options={orientationOptions}
defaultValue={orientationOptions[0]}
onChange={this.onOrientationChange}
value={orientationOptions.find(item => item.value === options.orientation)}
/>
</div>
<div className="form-field">
<FormLabel width={8}>Color</FormLabel>
<Select
width={12}
options={colorModes}
defaultValue={colorModes[0]}
onChange={this.onColorModeChanged}
value={colorModes.find(item => item.value === options.colorMode)}
/>
</div>
<div className="form-field">
<FormLabel width={8}>Graph</FormLabel>
<Select
width={12}
options={graphModes}
defaultValue={graphModes[0]}
onChange={this.onGraphModeChanged}
value={graphModes.find(item => item.value === options.graphMode)}
/>
</div>
<div className="form-field">
<FormLabel width={8}>Justify</FormLabel>
<Select
width={12}
options={justifyModes}
defaultValue={justifyModes[0]}
onChange={this.onJustifyModeChanged}
value={justifyModes.find(item => item.value === options.justifyMode)}
/>
</div>
<SparklineEditor options={options.sparkline} onChange={this.onSparklineChanged} />
</PanelOptionsGroup>
<PanelOptionsGroup title="Field">

View File

@@ -1,20 +1,26 @@
import { SingleStatBaseOptions, BigValueDisplayMode } from '@grafana/ui';
import { SingleStatBaseOptions, BigValueColorMode, BigValueGraphMode, BigValueJustifyMode } from '@grafana/ui';
import { VizOrientation, ReducerID, FieldDisplayOptions, SelectableValue } from '@grafana/data';
export interface SparklineOptions {
show: boolean;
}
// Structure copied from angular
export interface StatPanelOptions extends SingleStatBaseOptions {
sparkline: SparklineOptions;
displayMode: BigValueDisplayMode;
graphMode: BigValueGraphMode;
colorMode: BigValueColorMode;
justifyMode: BigValueJustifyMode;
}
export const displayModes: Array<SelectableValue<BigValueDisplayMode>> = [
{ value: BigValueDisplayMode.Classic, label: 'Classic' },
{ value: BigValueDisplayMode.Vibrant, label: 'Vibrant' },
{ value: BigValueDisplayMode.Vibrant2, label: 'Vibrant 2' },
export const colorModes: Array<SelectableValue<BigValueColorMode>> = [
{ value: BigValueColorMode.Value, label: 'Value' },
{ value: BigValueColorMode.Background, label: 'Background' },
];
export const graphModes: Array<SelectableValue<BigValueGraphMode>> = [
{ value: BigValueGraphMode.None, label: 'None' },
{ value: BigValueGraphMode.Area, label: 'Area graph' },
];
export const justifyModes: Array<SelectableValue<BigValueJustifyMode>> = [
{ value: BigValueJustifyMode.Auto, label: 'Auto' },
{ value: BigValueJustifyMode.Center, label: 'Center' },
];
export const standardFieldDisplayOptions: FieldDisplayOptions = {
@@ -33,10 +39,9 @@ export const standardFieldDisplayOptions: FieldDisplayOptions = {
};
export const defaults: StatPanelOptions = {
sparkline: {
show: true,
},
displayMode: BigValueDisplayMode.Vibrant,
graphMode: BigValueGraphMode.Area,
colorMode: BigValueColorMode.Value,
justifyMode: BigValueJustifyMode.Auto,
fieldOptions: standardFieldDisplayOptions,
orientation: VizOrientation.Auto,
};