diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index fcb68dc..6224c5f 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -27,11 +27,7 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha // we request animation frame here because we need an existing DOM-element at the moment we render the pod window.requestAnimationFrame(() => { // TODO: switch / case pod type - const pod = new ChartwerkGaugePod( - (chartContainer as any).current, - series, - chartwerkOptions - ); + const pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkOptions); pod.render(); }); return ( diff --git a/src/components/editors/IconsEditor.tsx b/src/components/editors/IconsEditor.tsx index 391a0e4..740e942 100644 --- a/src/components/editors/IconsEditor.tsx +++ b/src/components/editors/IconsEditor.tsx @@ -1,7 +1,16 @@ import { IconPosition } from 'types'; import { GrafanaTheme, SelectableValue, StandardEditorProps } from '@grafana/data'; -import { Button, HorizontalGroup, IconButton, Input, RadioButtonGroup, Slider, stylesFactory, ThemeContext } from '@grafana/ui'; +import { + Button, + HorizontalGroup, + IconButton, + Input, + RadioButtonGroup, + Slider, + stylesFactory, + ThemeContext, +} from '@grafana/ui'; import { FieldNamePicker } from '../../grafana/MatchersUI/FieldNamePicker'; import { css } from 'emotion'; @@ -9,7 +18,6 @@ import React from 'react'; import * as _ from 'lodash'; - type IconConfig = { position: IconPosition; url: string; @@ -17,7 +25,7 @@ type IconConfig = { conditions: Condition[]; values: number[]; size: number; -} +}; enum Condition { EQUAL = '=', @@ -27,7 +35,6 @@ enum Condition { LESS_OR_EQUAL = '<=', } - const positionOptions: Array> = [ { label: 'Upper-Left', @@ -73,7 +80,7 @@ const DEFAULT_ICON: IconConfig = { metrics: [], conditions: [], values: [], -} +}; const fieldNamePickerSettings = { settings: { width: 24 }, @@ -83,18 +90,14 @@ export function IconsEditor({ onChange, value, context }: StandardEditorProps { - onChange( - _.concat(icons, _.cloneDeep(DEFAULT_ICON)) - ); + onChange(_.concat(icons, _.cloneDeep(DEFAULT_ICON))); }; const removeIcon = (idx: number) => { - onChange( - _.filter(icons, (icon, iconIdx) => iconIdx !== idx) - ); + onChange(_.filter(icons, (icon, iconIdx) => iconIdx !== idx)); }; - const addCondition = (iconIdx:number) => { + const addCondition = (iconIdx: number) => { icons[iconIdx].conditions.push(Condition.GREATER_OR_EQUAL); icons[iconIdx].metrics.push(''); icons[iconIdx].values.push(0); @@ -118,7 +121,7 @@ export function IconsEditor({ onChange, value, context }: StandardEditorProps { - console.log(value) + console.log(value); // @ts-ignore icons[iconIdx][field][conditionIdx] = value; @@ -128,72 +131,76 @@ export function IconsEditor({ onChange, value, context }: StandardEditorProps {(theme) => { - const styles = getStyles(theme.v1); - return ( -
-
- { - icons.map((icon, iconIdx) => { - return ( -
- removeIcon(iconIdx)}> - onIconFieldChange(iconIdx, 'url', (evt.target as any).value)} - /> - onIconFieldChange(iconIdx, 'position', newVal)} - /> - onIconFieldChange(iconIdx, 'size', newVal)} - /> - - { - icon.conditions.map((condition, conditionIdx) => { - return ( - - onConditionChange(iconIdx, conditionIdx, 'metrics', newVal) } - item={fieldNamePickerSettings} - /> - onConditionChange(iconIdx, conditionIdx, 'conditions', newVal)} - /> - onConditionChange(iconIdx, conditionIdx, 'values', (evt.target as any).value)} - /> - removeCondition(iconIdx, conditionIdx)}> - - ) - }) - } - -
- ) - }) - } -
- + const styles = getStyles(theme.v1); + return ( +
+
+ {icons.map((icon, iconIdx) => { + return ( +
+ removeIcon(iconIdx)}> + onIconFieldChange(iconIdx, 'url', (evt.target as any).value)} + /> + onIconFieldChange(iconIdx, 'position', newVal)} + /> + onIconFieldChange(iconIdx, 'size', newVal)} + /> + + {icon.conditions.map((condition, conditionIdx) => { + return ( + + onConditionChange(iconIdx, conditionIdx, 'metrics', newVal)} + item={fieldNamePickerSettings} + /> + onConditionChange(iconIdx, conditionIdx, 'conditions', newVal)} + /> + + onConditionChange(iconIdx, conditionIdx, 'values', (evt.target as any).value) + } + /> + removeCondition(iconIdx, conditionIdx)} + > + + ); + })} + +
+ ); + })}
- ) - } - } + +
+ ); + }} - ) + ); } interface IconsEditorStyles { @@ -218,5 +225,5 @@ const getStyles = stylesFactory((theme: GrafanaTheme): IconsEditorStyles => { margin-bottom: 0; } `, - } + }; }); diff --git a/src/components/editors/ThresholdsEditor.tsx b/src/components/editors/ThresholdsEditor.tsx index 4ff18f8..efe072a 100644 --- a/src/components/editors/ThresholdsEditor.tsx +++ b/src/components/editors/ThresholdsEditor.tsx @@ -1,17 +1,25 @@ import { FieldNamePicker } from '../../grafana/MatchersUI/FieldNamePicker'; import { StandardEditorProps } from '@grafana/data'; -import { Button, ColorPicker, HorizontalGroup, IconButton, InlineField, InlineSwitch, Input, ThemeContext } from '@grafana/ui'; +import { + Button, + ColorPicker, + HorizontalGroup, + IconButton, + InlineField, + InlineSwitch, + Input, + ThemeContext, +} from '@grafana/ui'; import React from 'react'; import * as _ from 'lodash'; - interface Props { - defaultColor: string, - arcBackground: string, - thresholds: Array + defaultColor: string; + arcBackground: string; + thresholds: Array; } type ThresholdConfig = { @@ -19,13 +27,13 @@ type ThresholdConfig = { useMetric: boolean; value?: number; metricName?: string; -} +}; const DEFAULT_THRESHOLD: ThresholdConfig = { color: '#378372d', useMetric: false, - value: 0 -} + value: 0, +}; const fieldNamePickerSettings = { settings: { width: 24 }, @@ -37,17 +45,17 @@ export function ThresholdsEditor({ onChange, value, context }: StandardEditorPro const addThreshold = () => { config.thresholds.push(_.cloneDeep(DEFAULT_THRESHOLD)); onChange(config); - } + }; const removeThreshold = (idx: number) => { config.thresholds.splice(idx, 1); onChange(config); - } + }; const onFieldChange = (field: keyof Props, value: any) => { config[field] = value; onChange(config); - } + }; const onThresholdFieldChange = (thresholdIdx: number, field: keyof ThresholdConfig, value: any) => { // @ts-ignore @@ -57,87 +65,85 @@ export function ThresholdsEditor({ onChange, value, context }: StandardEditorPro return ( - { - () => { - // const styles = getStyles(theme.v1); - return ( -
- - onFieldChange('defaultColor', val)} - enableNamedColors={true} + {() => { + // const styles = getStyles(theme.v1); + return ( +
+ + onFieldChange('defaultColor', val)} + enableNamedColors={true} + /> +
+ } + /> + + onFieldChange('arcBackground', val)} + enableNamedColors={true} + /> +
+ } + /> + {config.thresholds.map((threshold, thresholdIdx) => { + return ( + + + onThresholdFieldChange(thresholdIdx, 'color', newVal)} + enableNamedColors={true} + /> +
+ } + /> + + onThresholdFieldChange(thresholdIdx, 'useMetric', (evt.target as any).checked)} /> - - } - /> - - onFieldChange('arcBackground', val) } - enableNamedColors={true} + + {threshold.useMetric ? ( + onThresholdFieldChange(thresholdIdx, 'metricName', newVal)} + item={fieldNamePickerSettings} /> - - } - /> - { - config.thresholds.map((threshold, thresholdIdx) => { - return ( - - - onThresholdFieldChange(thresholdIdx, 'color', newVal)} - enableNamedColors={true} - /> - - } - /> - - onThresholdFieldChange(thresholdIdx, 'useMetric', (evt.target as any).checked)} - /> - - { - threshold.useMetric ? - onThresholdFieldChange(thresholdIdx, 'metricName', newVal)} - item={fieldNamePickerSettings} - /> : - onThresholdFieldChange(thresholdIdx, 'value', (evt.target as any).value)} - /> - } - removeThreshold(thresholdIdx)}> - - ) - }) - } - - - ) - } - } + ) : ( + onThresholdFieldChange(thresholdIdx, 'value', (evt.target as any).value)} + /> + )} + removeThreshold(thresholdIdx)}> + + ); + })} + + + ); + }} - ) + ); } diff --git a/src/models/options.ts b/src/models/options.ts index bf572f9..673c0e4 100644 --- a/src/models/options.ts +++ b/src/models/options.ts @@ -13,11 +13,15 @@ export class Options { } private _setMin(): any { - if(!this.grafanaOptions.gauge.min.metricName) { + if (!this.grafanaOptions.gauge.min.metricName) { this.minValue = this.grafanaOptions.gauge.min.value; return; } - const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, this.grafanaOptions.gauge.min.metricName, 'Min'); + const filteredSeries = filterMetricListByAlias( + this.grafanaSeriesList, + this.grafanaOptions.gauge.min.metricName, + 'Min' + ); const serie = filteredSeries[0]; // Last value for now const aggregatedValue = getAggregatedValueFromSerie(serie, Aggregation.LAST); @@ -25,11 +29,15 @@ export class Options { } private _setMax(): any { - if(!this.grafanaOptions.gauge.max.metricName) { + if (!this.grafanaOptions.gauge.max.metricName) { this.maxValue = this.grafanaOptions.gauge.max.value; return; } - const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, this.grafanaOptions.gauge.max.metricName, 'Max'); + const filteredSeries = filterMetricListByAlias( + this.grafanaSeriesList, + this.grafanaOptions.gauge.max.metricName, + 'Max' + ); const serie = filteredSeries[0]; // Last value for now const aggregatedValue = getAggregatedValueFromSerie(serie, Aggregation.LAST); diff --git a/src/models/series.ts b/src/models/series.ts index 95cd99a..f358bac 100644 --- a/src/models/series.ts +++ b/src/models/series.ts @@ -1,18 +1,16 @@ - import { ValueOptions } from 'types'; import { filterMetricListByAlias } from '../utils'; import * as _ from 'lodash'; - // Convert Grafana series into Chartwerk series export class Series { private _seriesList; private _selectedSerieName; constructor(grafanaSeriesList: any, private gaugeValueOptions: ValueOptions) { - if(_.isEmpty(this.gaugeValueOptions.metricName)) { + if (_.isEmpty(this.gaugeValueOptions.metricName)) { throw new Error(`Value: metric is not selected. [See options: Extremum -> Value]`); } this._selectedSerieName = this.gaugeValueOptions.metricName; diff --git a/src/module.ts b/src/module.ts index 8f08043..e366a4a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -6,7 +6,6 @@ import { ThresholdsEditor } from './components/editors/ThresholdsEditor'; import { PanelPlugin } from '@grafana/data'; - export const plugin = new PanelPlugin(Panel).setPanelOptions((builder) => { return builder .addRadio({ @@ -39,7 +38,7 @@ export const plugin = new PanelPlugin(Panel).setPanelOptions((buil name: 'Value', path: 'gauge.value.metricName', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE + showIf: (config) => config.visualizationType === Pod.GAUGE, }) .addNumberInput({ @@ -106,9 +105,9 @@ export const plugin = new PanelPlugin(Panel).setPanelOptions((buil defaultValue: { defaultColor: '#37872d', arcBackground: 'rgba(38, 38, 38, 0.1)', - thresholds: [] + thresholds: [], }, showIf: (config) => config.visualizationType === Pod.GAUGE, editor: ThresholdsEditor as any, - }) + }); }); diff --git a/src/types.ts b/src/types.ts index f0427d2..923853c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,16 +12,16 @@ export type ExtremumOptions = { useMetric: false; value?: number; metricName?: string; -} +}; export type ValueOptions = { - metricName?: string -} + metricName?: string; +}; export enum IconPosition { UPPER_LEFT = 'Upper left', MIDDLE = 'Middle', - UPPER_RIGHT = 'Upper right' + UPPER_RIGHT = 'Upper right', } export enum Pod { @@ -33,5 +33,5 @@ export enum Pod { export enum Aggregation { MIN = 'min', MAX = 'max', - LAST = 'last' + LAST = 'last', } diff --git a/src/utils.ts b/src/utils.ts index 2075909..2548df8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,11 +3,11 @@ import { Aggregation } from './types'; import * as _ from 'lodash'; export function filterMetricListByAlias(list: any[], alias: string | undefined, option: string): any[] { - const filteredSeries = _.filter(list, serie => serie.alias === alias); - if(filteredSeries.length === 0) { + const filteredSeries = _.filter(list, (serie) => serie.alias === alias); + if (filteredSeries.length === 0) { throw new Error(`${option}: Can't find metric for ${alias} name.`); } - if(filteredSeries.length > 1) { + if (filteredSeries.length > 1) { throw new Error(`${option}: Get ${filteredSeries.length} metrics for ${alias} name. Please choose one.`); } return filteredSeries; @@ -15,19 +15,19 @@ export function filterMetricListByAlias(list: any[], alias: string | undefined, export function getAggregatedValueFromSerie(serie: any, aggregation = Aggregation.LAST): number | null { // series types { datapoints: [number, number][]} - if(serie === undefined) { + if (serie === undefined) { return null; } - if(serie.datapoints.length === 0) { + if (serie.datapoints.length === 0) { return null; } - switch(aggregation) { + switch (aggregation) { case Aggregation.LAST: - const lastRow = _.last((serie.datapoints as [number, number][])); + const lastRow = _.last(serie.datapoints as [number, number][]); // [0] because it is Grafan series. So 0 idx for values, 1 idx for timestamps // @ts-ignore return !_.isEmpty(lastRow) ? lastRow[0] : null; default: - throw new Error(`Unknown aggregation type: ${aggregation}`) + throw new Error(`Unknown aggregation type: ${aggregation}`); } }