Browse Source

link fixes

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

11
src/components/editors/IconsEditor.tsx

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

2
src/components/editors/NotSupportedText.tsx

@ -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>;
} }

3
src/components/editors/ThresholdsEditor.tsx

@ -19,7 +19,6 @@ import React from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import * as _ from 'lodash'; import * as _ from 'lodash';
interface Props { interface Props {
defaultColor: string; defaultColor: string;
arcBackground: string; arcBackground: string;
@ -156,7 +155,7 @@ interface ThresholdsEditorStyles {
const getStyles = stylesFactory((theme: GrafanaTheme): ThresholdsEditorStyles => { const getStyles = stylesFactory((theme: GrafanaTheme): ThresholdsEditorStyles => {
return { return {
deleteButton: css` 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 { FieldNamePicker } from '../../grafana/MatchersUI/FieldNamePicker';
import { StandardEditorProps } from '@grafana/data'; import { StandardEditorProps } from '@grafana/data';
import { import { HorizontalGroup, InlineField, InlineSwitch, Input } from '@grafana/ui';
HorizontalGroup,
InlineField,
InlineSwitch,
Input,
} from '@grafana/ui';
import React from 'react'; import React from 'react';
import * as _ from 'lodash'; import * as _ from 'lodash';
type UseMetricConfig = { type UseMetricConfig = {
useMetric: boolean; useMetric: boolean;
value?: number; value?: number;
@ -31,7 +25,7 @@ export function UseMetricEditor({ onChange, value, context }: StandardEditorProp
config[field] = value; config[field] = value;
onChange(config); onChange(config);
} };
return ( return (
<HorizontalGroup> <HorizontalGroup>
@ -59,5 +53,5 @@ export function UseMetricEditor({ onChange, value, context }: StandardEditorProp
)} )}
</InlineField> </InlineField>
</HorizontalGroup> </HorizontalGroup>
) );
} }

24
src/models/options.ts

@ -6,14 +6,12 @@ import { getValueFormat } from '@grafana/data';
import _ from 'lodash'; 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: { value: number, color: string }[] = []; private thresholds: Array<{ value: number; color: string }> = [];
private icons: { src: string, position: string, size: number}[] = []; 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();
@ -50,14 +48,16 @@ export class Options {
} }
private _setThreshold(threshold: Threshold, idx: number): void { private _setThreshold(threshold: Threshold, idx: number): void {
const value = threshold.useMetric ? this.getLastValueFromMetrics(threshold.metricName, `Threshold ${idx + 1}`) : threshold.value; const value = threshold.useMetric
if(value === null || value === undefined) { ? this.getLastValueFromMetrics(threshold.metricName, `Threshold ${idx + 1}`)
: threshold.value;
if (value === null || value === undefined) {
// TODO: may be throw an error // TODO: may be throw an error
return; return;
} }
this.thresholds.push({ this.thresholds.push({
value, value,
color: threshold.color color: threshold.color,
}); });
} }
@ -88,14 +88,14 @@ export class Options {
} }
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean { private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean {
if(_.isEmpty(icon.metrics)) { if (_.isEmpty(icon.metrics)) {
return true; return true;
} }
// check each condition and return false if something goes wrong // check each condition and return false if something goes wrong
for (let [conditionIdx, metric] of icon.metrics.entries()) { for (let [conditionIdx, metric] of icon.metrics.entries()) {
const value = this.getLastValueFromMetrics(metric, `Icon ${iconIdx + 1}, Condition ${conditionIdx + 1}`); 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 // TODO: may be throw an error
return false; return false;
} }
@ -157,11 +157,7 @@ export class Options {
getLastValueFromMetrics(metricName: string | undefined, optionName: string): number | null { getLastValueFromMetrics(metricName: string | undefined, optionName: string): number | null {
// optionName -> helper in Error, mb use option path instead // optionName -> helper in Error, mb use option path instead
const filteredSeries = filterMetricListByAlias( const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, metricName, optionName);
this.grafanaSeriesList,
metricName,
optionName
);
const serie = filteredSeries[0]; const serie = filteredSeries[0];
// Last value for now // Last value for now
return getAggregatedValueFromSerie(serie, Aggregation.LAST); return getAggregatedValueFromSerie(serie, Aggregation.LAST);

241
src/module.ts

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

2
src/types.ts

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

6
src/utils.ts

@ -13,7 +13,11 @@ export function filterMetricListByAlias(list: any[], alias: string | undefined,
return filteredSeries; 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][]} // series types { datapoints: [number, number][]}
// valueIdx === 0 for Grafana series, valueIdx === 1 for Chartwerk series // valueIdx === 0 for Grafana series, valueIdx === 1 for Chartwerk series
if (serie === undefined) { if (serie === undefined) {

Loading…
Cancel
Save