Browse Source

link fixes

merge-requests/7/head
vargburz 2 years ago
parent
commit
1983d31aec
  1. 5
      src/components/Panel.tsx
  2. 11
      src/components/editors/IconsEditor.tsx
  3. 2
      src/components/editors/NotSupportedText.tsx
  4. 3
      src/components/editors/ThresholdsEditor.tsx
  5. 12
      src/components/editors/UseMetricEditor.tsx
  6. 24
      src/models/options.ts
  7. 241
      src/module.ts
  8. 2
      src/types.ts
  9. 6
      src/utils.ts

5
src/components/Panel.tsx

@ -33,11 +33,10 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha
const isLinkActive = !_.isEmpty(options.gauge.link);
const chartClickHandler = (event: React.MouseEvent<HTMLDivElement>) => {
event.preventDefault();
console.log('click', options);
if (!isLinkActive) {
return;
}
window.open(options.gauge.link, "_self");
window.open(options.gauge.link, '_self');
};
return (
@ -46,7 +45,7 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha
className={css`
width: ${width}px;
height: ${height}px;
cursor: ${isLinkActive ? 'pointer' : 'default'}
cursor: ${isLinkActive ? 'pointer' : 'default'};
`}
onClick={chartClickHandler}
></div>

11
src/components/editors/IconsEditor.tsx

@ -120,11 +120,7 @@ export function IconsEditor({ onChange, value, context }: StandardEditorProps<Ic
{icons.map((icon, iconIdx) => {
return (
<div key={iconIdx} className={styles.icon}>
<IconButton
name="trash-alt"
onClick={() => removeIcon(iconIdx)}
tooltip="Delete Icon"
></IconButton>
<IconButton name="trash-alt" onClick={() => removeIcon(iconIdx)} tooltip="Delete Icon"></IconButton>
<div className={styles.row}>
<Input
type="url"
@ -150,8 +146,8 @@ export function IconsEditor({ onChange, value, context }: StandardEditorProps<Ic
{icon.conditions.map((condition, conditionIdx) => {
return (
<div className={styles.condition}>
<HorizontalGroup key={conditionIdx} >
<div key={conditionIdx} className={styles.condition}>
<HorizontalGroup key={conditionIdx}>
<FieldNamePicker
context={context}
value={icon.metrics[conditionIdx]}
@ -230,5 +226,4 @@ const getStyles = stylesFactory((theme: GrafanaTheme): IconsEditorStyles => {
margin-bottom: ${theme.spacing.sm};
`,
};
});

2
src/components/editors/NotSupportedText.tsx

@ -1,5 +1,5 @@
import React from 'react';
export function NotSupportedText() {
return <div>To be supported soon...</div>
return <div>To be supported soon...</div>;
}

3
src/components/editors/ThresholdsEditor.tsx

@ -19,7 +19,6 @@ import React from 'react';
import { css } from 'emotion';
import * as _ from 'lodash';
interface Props {
defaultColor: string;
arcBackground: string;
@ -156,7 +155,7 @@ interface ThresholdsEditorStyles {
const getStyles = stylesFactory((theme: GrafanaTheme): ThresholdsEditorStyles => {
return {
deleteButton: css`
margin-right: 0px!important;
margin-right: 0px !important;
`,
};
});

12
src/components/editors/UseMetricEditor.tsx

@ -1,18 +1,12 @@
import { FieldNamePicker } from '../../grafana/MatchersUI/FieldNamePicker';
import { StandardEditorProps } from '@grafana/data';
import {
HorizontalGroup,
InlineField,
InlineSwitch,
Input,
} from '@grafana/ui';
import { HorizontalGroup, InlineField, InlineSwitch, Input } from '@grafana/ui';
import React from 'react';
import * as _ from 'lodash';
type UseMetricConfig = {
useMetric: boolean;
value?: number;
@ -31,7 +25,7 @@ export function UseMetricEditor({ onChange, value, context }: StandardEditorProp
config[field] = value;
onChange(config);
}
};
return (
<HorizontalGroup>
@ -59,5 +53,5 @@ export function UseMetricEditor({ onChange, value, context }: StandardEditorProp
)}
</InlineField>
</HorizontalGroup>
)
);
}

24
src/models/options.ts

@ -6,14 +6,12 @@ import { getValueFormat } from '@grafana/data';
import _ from 'lodash';
// Convert Grafana options into Chartwerk Gauge options
export class Options {
private minValue: number | undefined;
private maxValue: number | undefined;
private thresholds: { value: number, color: string }[] = [];
private icons: { src: string, position: string, size: number}[] = [];
private thresholds: Array<{ value: number; color: string }> = [];
private icons: Array<{ src: string; position: string; size: number }> = [];
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) {
this._setMin();
@ -50,14 +48,16 @@ export class Options {
}
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) {
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
color: threshold.color,
});
}
@ -88,14 +88,14 @@ export class Options {
}
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean {
if(_.isEmpty(icon.metrics)) {
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) {
if (value === null || value === undefined) {
// TODO: may be throw an error
return false;
}
@ -157,11 +157,7 @@ export class Options {
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 filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, metricName, optionName);
const serie = filteredSeries[0];
// Last value for now
return getAggregatedValueFromSerie(serie, Aggregation.LAST);

241
src/module.ts

@ -9,130 +9,131 @@ import { UseMetricEditor } from './components/editors/UseMetricEditor';
import { PanelPlugin } from '@grafana/data';
export const plugin = new PanelPlugin<PanelOptions>(Panel).setPanelOptions((builder) => {
return builder
.addRadio({
path: 'visualizationType',
name: 'Pod',
category: ['Visualization'],
defaultValue: Pod.GAUGE,
settings: {
options: [
{
label: 'Gauge',
value: Pod.GAUGE,
},
{
label: 'Line',
value: Pod.LINE,
},
{
label: 'Bar',
value: Pod.BAR,
},
],
},
})
.addCustomEditor({
id: 'notSupportedText',
name: 'This visualization is not supported',
category: ['Visualization'],
path: '',
showIf: (config) => config.visualizationType !== Pod.GAUGE,
editor: NotSupportedText as any,
})
return (
builder
.addRadio({
path: 'visualizationType',
name: 'Pod',
category: ['Visualization'],
defaultValue: Pod.GAUGE,
settings: {
options: [
{
label: 'Gauge',
value: Pod.GAUGE,
},
{
label: 'Line',
value: Pod.LINE,
},
{
label: 'Bar',
value: Pod.BAR,
},
],
},
})
.addCustomEditor({
id: 'notSupportedText',
name: 'This visualization is not supported',
category: ['Visualization'],
path: '',
showIf: (config) => config.visualizationType !== Pod.GAUGE,
editor: NotSupportedText as any,
})
.addFieldNamePicker({
name: 'Value',
path: 'gauge.value.metricName',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
// TODO: defaults?
.addCustomEditor({
id: 'min',
name: 'Min',
path: 'gauge.min',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any,
}).
addCustomEditor({
id: 'max',
name: 'Max',
path: 'gauge.max',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any,
})
.addFieldNamePicker({
name: 'Value',
path: 'gauge.value.metricName',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
// TODO: defaults?
.addCustomEditor({
id: 'min',
name: 'Min',
path: 'gauge.min',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any,
})
.addCustomEditor({
id: 'max',
name: 'Max',
path: 'gauge.max',
category: ['Extremum'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any,
})
// note: `gauge.unit` will contain unit name, not it's string representation
// to format value with unit, use `getValueFormat` function from `@grafana/data`
.addUnitPicker({
path: 'gauge.unit',
name: 'Unit',
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addNumberInput({
path: 'gauge.decimals',
name: 'Decimals',
settings: {
placeholder: 'auto',
min: 0,
max: 5,
},
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addSliderInput({
path: 'gauge.valueSize',
defaultValue: 20,
name: 'Size (px)',
settings: {
min: 1,
max: 50,
},
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
// note: `gauge.unit` will contain unit name, not it's string representation
// to format value with unit, use `getValueFormat` function from `@grafana/data`
.addUnitPicker({
path: 'gauge.unit',
name: 'Unit',
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addNumberInput({
path: 'gauge.decimals',
name: 'Decimals',
settings: {
placeholder: 'auto',
min: 0,
max: 5,
},
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addSliderInput({
path: 'gauge.valueSize',
defaultValue: 20,
name: 'Size (px)',
settings: {
min: 1,
max: 50,
},
category: ['Value Format'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
.addBooleanSwitch({
path: 'gauge.reversed',
name: 'Reversed',
defaultValue: false,
category: ['Direction'],
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',
name: 'Icons',
category: ['Icons'],
defaultValue: [],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: IconsEditor as any,
})
.addCustomEditor({
id: 'icons',
path: 'gauge.icons',
name: 'Icons',
category: ['Icons'],
defaultValue: [],
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: IconsEditor as any,
})
.addCustomEditor({
id: 'thresholds',
path: 'gauge.thresholds',
name: 'Thresholds',
category: ['Thresholds'],
defaultValue: {
defaultColor: '#37872d',
arcBackground: 'rgba(38, 38, 38, 0.1)',
thresholds: [],
},
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: ThresholdsEditor as any,
})
.addTextInput({
path: 'gauge.link',
name: '',
category: ['Link'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
});
.addCustomEditor({
id: 'thresholds',
path: 'gauge.thresholds',
name: 'Thresholds',
category: ['Thresholds'],
defaultValue: {
defaultColor: '#37872d',
arcBackground: 'rgba(38, 38, 38, 0.1)',
thresholds: [],
},
showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: ThresholdsEditor as any,
})
.addTextInput({
path: 'gauge.link',
name: '',
category: ['Link'],
showIf: (config) => config.visualizationType === Pod.GAUGE,
})
);
});

2
src/types.ts

@ -51,7 +51,7 @@ export type Threshold = {
value: number;
metricName: string;
color: string;
}
};
export type Icon = {
conditions: Condition[];

6
src/utils.ts

@ -13,7 +13,11 @@ export function filterMetricListByAlias(list: any[], alias: string | undefined,
return filteredSeries;
}
export function getAggregatedValueFromSerie(serie: any, aggregation = Aggregation.LAST, valueIdx: 0 | 1 = 0): number | null {
export function getAggregatedValueFromSerie(
serie: any,
aggregation = Aggregation.LAST,
valueIdx: 0 | 1 = 0
): number | null {
// series types { datapoints: [number, number][]}
// valueIdx === 0 for Grafana series, valueIdx === 1 for Chartwerk series
if (serie === undefined) {

Loading…
Cancel
Save