Browse Source
Pass options to chartwerk 2 See merge request chartwerk/grafana-chartwerk-panel!7merge-requests/8/merge
Alexander Velikiy
3 years ago
10 changed files with 324 additions and 198 deletions
@ -1,5 +1,5 @@ |
|||||||
import React from 'react'; |
import React from 'react'; |
||||||
|
|
||||||
export function NotSupportedText() { |
export function NotSupportedText() { |
||||||
return <div>To be supported soon...</div> |
return <div>To be supported soon...</div>; |
||||||
} |
} |
||||||
|
@ -1,69 +1,165 @@ |
|||||||
import { PanelOptions, Aggregation } from 'types'; |
import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types'; |
||||||
|
|
||||||
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../utils'; |
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../utils'; |
||||||
|
|
||||||
|
import { getValueFormat } from '@grafana/data'; |
||||||
|
|
||||||
|
import _ from 'lodash'; |
||||||
|
|
||||||
// Convert Grafana options into Chartwerk Gauge options
|
// Convert Grafana options into Chartwerk Gauge options
|
||||||
export class Options { |
export class Options { |
||||||
private minValue: number | undefined; |
private minValue: number | undefined; |
||||||
private maxValue: number | undefined; |
private maxValue: number | undefined; |
||||||
|
private thresholds: Array<{ value: number; color: string }> = []; |
||||||
|
private icons: Array<{ src: string; position: string; size: number }> = []; |
||||||
|
|
||||||
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) { |
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) { |
||||||
this._setMin(); |
this._setMin(); |
||||||
this._setMax(); |
this._setMax(); |
||||||
|
this._setThresholds(); |
||||||
|
this._setIcons(); |
||||||
} |
} |
||||||
|
|
||||||
private _setMin(): any { |
private _setMin(): void { |
||||||
if (!this.grafanaOptions.gauge.min.metricName) { |
if (!this.grafanaOptions.gauge.min.useMetric) { |
||||||
this.minValue = this.grafanaOptions.gauge.min.value; |
this.minValue = this.grafanaOptions.gauge.min.value; |
||||||
return; |
return; |
||||||
} |
} |
||||||
const filteredSeries = filterMetricListByAlias( |
const aggregatedValue = this.getLastValueFromMetrics(this.grafanaOptions.gauge.min.metricName, 'Min'); |
||||||
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; |
this.minValue = aggregatedValue ? aggregatedValue : undefined; |
||||||
} |
} |
||||||
|
|
||||||
private _setMax(): any { |
private _setMax(): void { |
||||||
if (!this.grafanaOptions.gauge.max.metricName) { |
if (!this.grafanaOptions.gauge.max.useMetric) { |
||||||
this.maxValue = this.grafanaOptions.gauge.max.value; |
this.maxValue = this.grafanaOptions.gauge.max.value; |
||||||
return; |
return; |
||||||
} |
} |
||||||
const filteredSeries = filterMetricListByAlias( |
const aggregatedValue = this.getLastValueFromMetrics(this.grafanaOptions.gauge.max.metricName, 'Max'); |
||||||
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; |
this.maxValue = aggregatedValue ? aggregatedValue : undefined; |
||||||
} |
} |
||||||
|
|
||||||
|
private _setThresholds(): void { |
||||||
|
if (_.isEmpty(this.grafanaOptions.gauge.thresholds.thresholds)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (let [idx, threshold] of this.grafanaOptions.gauge.thresholds.thresholds.entries()) { |
||||||
|
this._setThreshold(threshold, idx); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private _setThreshold(threshold: Threshold, idx: number): void { |
||||||
|
const value = threshold.useMetric |
||||||
|
? this.getLastValueFromMetrics(threshold.metricName, `Threshold ${idx + 1}`) |
||||||
|
: threshold.value; |
||||||
|
if (value === null || value === undefined) { |
||||||
|
// TODO: may be throw an error
|
||||||
|
return; |
||||||
|
} |
||||||
|
this.thresholds.push({ |
||||||
|
value, |
||||||
|
color: threshold.color, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private _valueFormatter(value: number): string { |
||||||
|
const suffix = getValueFormat(this.grafanaOptions.gauge.unit)(0)?.suffix || ''; |
||||||
|
const decimals = _.isNumber(this.grafanaOptions.gauge.decimals) ? this.grafanaOptions.gauge.decimals : 2; |
||||||
|
return `${value.toFixed(decimals)} ${suffix}`; |
||||||
|
} |
||||||
|
|
||||||
|
private _setIcons(): void { |
||||||
|
if (_.isEmpty(this.grafanaOptions.gauge.icons)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (let [idx, icon] of this.grafanaOptions.gauge.icons.entries()) { |
||||||
|
this._setIcon(icon, idx); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private _setIcon(icon: Icon, idx: number): void { |
||||||
|
if (!this._areIconConditionsFulfilled(icon, idx)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
this.icons.push({ |
||||||
|
src: icon.url, |
||||||
|
size: icon.size, |
||||||
|
position: this._getChartwerkIconPosition(icon.position), |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean { |
||||||
|
if (_.isEmpty(icon.metrics)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// check each condition and return false if something goes wrong
|
||||||
|
for (let [conditionIdx, metric] of icon.metrics.entries()) { |
||||||
|
const value = this.getLastValueFromMetrics(metric, `Icon ${iconIdx + 1}, Condition ${conditionIdx + 1}`); |
||||||
|
if (value === null || value === undefined) { |
||||||
|
// TODO: may be throw an error
|
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!this.checkIconCondition(value, icon.values[conditionIdx], icon.conditions[conditionIdx])) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private checkIconCondition(metricValue: number, inputValue: number, condition: Condition): boolean { |
||||||
|
if (inputValue === undefined || inputValue === null) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
switch (condition) { |
||||||
|
case Condition.EQUAL: |
||||||
|
return metricValue === inputValue; |
||||||
|
case Condition.GREATER: |
||||||
|
return metricValue > inputValue; |
||||||
|
case Condition.GREATER_OR_EQUAL: |
||||||
|
return metricValue >= inputValue; |
||||||
|
case Condition.LESS: |
||||||
|
return metricValue < inputValue; |
||||||
|
case Condition.LESS_OR_EQUAL: |
||||||
|
return metricValue <= inputValue; |
||||||
|
default: |
||||||
|
throw new Error(`Unknown condition: ${condition}`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private _getChartwerkIconPosition(position: IconPosition): string { |
||||||
|
// TODO: use chartwerk types
|
||||||
|
switch (position) { |
||||||
|
case IconPosition.MIDDLE: |
||||||
|
return 'middle'; |
||||||
|
case IconPosition.UPPER_LEFT: |
||||||
|
return 'left'; |
||||||
|
case IconPosition.UPPER_RIGHT: |
||||||
|
return 'right'; |
||||||
|
default: |
||||||
|
throw new Error(`Unknown Icon Position ${position}`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
getChartwerkOptions(): any { |
getChartwerkOptions(): any { |
||||||
console.log('opt', this.maxValue, this.minValue); |
|
||||||
return { |
return { |
||||||
maxValue: this.maxValue, |
maxValue: this.maxValue, |
||||||
minValue: this.minValue, |
minValue: this.minValue, |
||||||
valueFormatter: (val: any) => val.toFixed(2), |
valueFormatter: (val: number) => this._valueFormatter(val), |
||||||
defaultColor: 'green', |
defaultColor: this.grafanaOptions.gauge.thresholds.defaultColor, |
||||||
|
valueArcBackgroundColor: this.grafanaOptions.gauge.thresholds.arcBackground, |
||||||
reversed: this.grafanaOptions.gauge.reversed, |
reversed: this.grafanaOptions.gauge.reversed, |
||||||
stops: [ |
stops: this.thresholds, |
||||||
{ |
valueFontSize: this.grafanaOptions.gauge.valueSize, |
||||||
color: 'green', |
icons: this.icons, |
||||||
value: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
color: 'orange', |
|
||||||
value: 140, |
|
||||||
}, |
|
||||||
], |
|
||||||
// @ts-ignore
|
|
||||||
icons: [{ src: 'https://cityhost.ua/upload_img/blog5ef308ea5529c_trash2-01.jpg', position: 'middle', size: 30 }], |
|
||||||
}; |
}; |
||||||
} |
} |
||||||
|
|
||||||
|
getLastValueFromMetrics(metricName: string | undefined, optionName: string): number | null { |
||||||
|
// optionName -> helper in Error, mb use option path instead
|
||||||
|
const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, metricName, optionName); |
||||||
|
const serie = filteredSeries[0]; |
||||||
|
// Last value for now
|
||||||
|
return getAggregatedValueFromSerie(serie, Aggregation.LAST); |
||||||
|
} |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue