Browse Source

Merge branch 'reversed-gauge' into 'main'

Reversed gauge and min/max support metrics

See merge request chartwerk/grafana-chartwerk-panel!4
merge-requests/5/merge
rozetko 2 years ago
parent
commit
67cd75f527
  1. 16
      src/components/Panel.tsx
  2. 44
      src/models/options.ts
  3. 23
      src/models/series.ts
  4. 8
      src/module.ts
  5. 7
      src/types.ts
  6. 33
      src/utils.ts

16
src/components/Panel.tsx

@ -3,9 +3,12 @@ import { Series } from '../models/series';
import { PanelOptions } from '../types';
import { DataProcessor } from '../grafana/data_processor';
import { ChartwerkGaugePod } from '@chartwerk/gauge-pod';
import { PanelProps } from '@grafana/data';
import { PanelData, TimeRange } from '@grafana/data';
import React, { useRef } from 'react';
import { css } from 'emotion';
@ -15,9 +18,10 @@ interface Props extends PanelProps<PanelOptions> {}
export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) {
console.log('options', options);
const series = new Series(data, timeRange, options.gauge.value).getChartwerkSeries();
const grafanaSeriesList = getGrafanaSeriesList(data, timeRange);
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries();
console.log('series', series);
const chartwerkOptions = new Options(options).getChartwerkOptions();
const chartwerkOptions = new Options(grafanaSeriesList, options).getChartwerkOptions();
let chartContainer = useRef(null);
// we request animation frame here because we need an existing DOM-element at the moment we render the pod
@ -40,3 +44,11 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha
></div>
);
}
function getGrafanaSeriesList(grafanaData: PanelData, timeRange: TimeRange): any[] {
const processor = new DataProcessor({});
return processor.getSeriesList({
dataList: grafanaData.series,
range: timeRange,
});
}

44
src/models/options.ts

@ -1,15 +1,49 @@
import { PanelOptions } from 'types';
import { PanelOptions, Aggregation } from 'types';
// Convert Grafana options into Chartwerk options
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../utils';
// Convert Grafana options into Chartwerk Gauge options
export class Options {
constructor(private grafanaOptions: PanelOptions) {}
private minValue: number | undefined;
private maxValue: number | undefined;
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) {
this._setMin();
this._setMax();
}
private _setMin(): any {
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 serie = filteredSeries[0];
// Last value for now
const aggregatedValue = getAggregatedValueFromSerie(serie, Aggregation.LAST);
this.minValue = aggregatedValue ? aggregatedValue : undefined;
}
private _setMax(): any {
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 serie = filteredSeries[0];
// Last value for now
const aggregatedValue = getAggregatedValueFromSerie(serie, Aggregation.LAST);
this.maxValue = aggregatedValue ? aggregatedValue : undefined;
}
public getChartwerkOptions(): any {
console.log('opt', this.maxValue, this.minValue);
return {
maxValue: this.grafanaOptions.gauge.max.value || 0,
minValue: this.grafanaOptions.gauge.min.value || 0,
maxValue: this.maxValue,
minValue: this.minValue,
valueFormatter: (val: any) => val.toFixed(2),
defaultColor: 'green',
reversed: this.grafanaOptions.gauge.reversed,
stops: [
{
color: 'green',

23
src/models/series.ts

@ -1,36 +1,23 @@
import { PanelData, TimeRange } from '@grafana/data';
import { DataProcessor } from '../grafana/data_processor';
import { ValueOptions } from 'types';
import { filterMetricListByAlias } from '../utils';
import * as _ from 'lodash';
// Convert Grafana series into Chartwerk series
export class Series {
private processor;
private _seriesList;
private _selectedSerieName;
constructor(grafanaData: PanelData, timeRange: TimeRange, private gaugeValueOptions: ValueOptions) {
constructor(grafanaSeriesList: any, private gaugeValueOptions: ValueOptions) {
if(_.isEmpty(this.gaugeValueOptions.metricName)) {
throw new Error(`Value or metric is not selected.`);
throw new Error(`Value: metric is not selected. [See options: Extremum -> Value]`);
}
this._selectedSerieName = this.gaugeValueOptions.metricName;
this.processor = new DataProcessor({});
const seriesList = this.processor.getSeriesList({
dataList: grafanaData.series,
range: timeRange,
});
const filteredSeries = _.filter(seriesList, serie => serie.alias === this._selectedSerieName);
if(filteredSeries.length === 0) {
throw new Error(`Can't find metric for ${this._selectedSerieName} name`);
}
if(filteredSeries.length > 1) {
throw new Error(`Get ${filteredSeries.length} metrics for ${this._selectedSerieName} name. Please choose one`);
}
const filteredSeries = filterMetricListByAlias(grafanaSeriesList, this._selectedSerieName, 'Value');
this._seriesList = this._updateSeriesListWithChartwerkParams(filteredSeries);
}

8
src/module.ts

@ -79,7 +79,13 @@ export const plugin = new PanelPlugin<PanelOptions>(Panel).setPanelOptions((buil
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addBooleanSwitch({
path: 'gauge.reversed',
name: 'Reversed',
defaultValue: false,
category: ['Direction'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addCustomEditor({
id: 'icons',
path: 'gauge.icons',

7
src/types.ts

@ -4,6 +4,7 @@ export interface PanelOptions {
min: ExtremumOptions;
max: ExtremumOptions;
value: ExtremumOptions;
reversed: boolean;
};
}
@ -28,3 +29,9 @@ export enum Pod {
BAR = 'Bar',
GAUGE = 'Gauge',
}
export enum Aggregation {
MIN = 'min',
MAX = 'max',
LAST = 'last'
}

33
src/utils.ts

@ -0,0 +1,33 @@
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) {
throw new Error(`${option}: Can't find metric for ${alias} name.`);
}
if(filteredSeries.length > 1) {
throw new Error(`${option}: Get ${filteredSeries.length} metrics for ${alias} name. Please choose one.`);
}
return filteredSeries;
}
export function getAggregatedValueFromSerie(serie: any, aggregation = Aggregation.LAST): number | null {
// series types { datapoints: [number, number][]}
if(serie === undefined) {
return null;
}
if(serie.datapoints.length === 0) {
return null;
}
switch(aggregation) {
case Aggregation.LAST:
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}`)
}
}
Loading…
Cancel
Save