Browse Source

merge master

pull/2/head
rozetko 2 years ago
parent
commit
07bb1392f1
  1. 35
      README.md
  2. 6
      package.json
  3. 2
      src/components/Panel.tsx
  4. 10
      src/components/editors/UseMetricEditor.tsx
  5. 13
      src/grafana/data_processor.ts
  6. 10
      src/models/options/gaugeOptions.ts
  7. 11
      src/models/series.ts
  8. 3
      src/module.ts
  9. 10
      src/plugin.json
  10. 28
      yarn.lock

35
README.md

@ -14,6 +14,35 @@
- Bar Chart (coming soon) - Bar Chart (coming soon)
- Gauge: dynamic thresholds and min / max - Gauge: dynamic thresholds and min / max
- Gauge: conditional icons displaying - Gauge: conditional icons displaying
- Gauge: reversed direction
## How to use
1. Create a new panel and select Chartwerk as the visualization
2. Add queries with unique aliases
3. Go to the Options Tab and setup panel:
- Choose visualization type
- Select metric in the Value -> Metric dropdown (by default, the first metric is used)
## Demo
see [demo](https://grafana.corpglory.com/d/8vGyMypGz/demo-home?orgId=4)
## Options [Gauge]
- Visualization:
- Pod: option to select chart type
- Value:
- Metric: select metric query from dropdown
- Extemum:
- Min:
- type number for static minimum value OR
- enable "Use metric" toggle switch to select metric as minimun
- default value: 0
- Max:
- type number for static maximum OR
- enable "Use metric" toggle switch to select metric as maximum
- default value: maximum of metric query
## Installation ## Installation
@ -27,13 +56,13 @@
- Download Chartwerk panel - Download Chartwerk panel
``` ```
wget https://gitlab.com/chartwerk/grafana-chartwerk-panel/uploads/117d957cd20276826cd092becb62dd30/corpglory-chartwerk-panel-0.4.0.zip wget https://gitlab.com/chartwerk/grafana-chartwerk-panel/uploads/2284215a4dc8fb3bde1fd3b51bd99d3e/corpglory-chartwerk-panel-0.5.0.zip
``` ```
- Unpack downloaded files - Unpack downloaded files
``` ```
unzip -u corpglory-chartwerk-panel-0.4.0.zip -d corpglory-chartwerk-panel unzip -u corpglory-chartwerk-panel-0.4.1.zip -d corpglory-chartwerk-panel
``` ```
- Restart grafana-server - Restart grafana-server
@ -51,6 +80,6 @@ You can install Chartwerk panel to Grafana in Docker passing it as environment v
```bash ```bash
docker run \ docker run \
-p 3000:3000 \ -p 3000:3000 \
-e "GF_INSTALL_PLUGINS=https://gitlab.com/chartwerk/grafana-chartwerk-panel/uploads/117d957cd20276826cd092becb62dd30/corpglory-chartwerk-panel-0.4.0.zip;corpglory-chartwerk-panel" \ -e "GF_INSTALL_PLUGINS=https://gitlab.com/chartwerk/grafana-chartwerk-panel/uploads/2284215a4dc8fb3bde1fd3b51bd99d3e/corpglory-chartwerk-panel-0.5.0.zip;corpglory-chartwerk-panel" \
grafana/grafana grafana/grafana
``` ```

6
package.json

@ -1,6 +1,6 @@
{ {
"name": "grafana-chartwerk-panel", "name": "grafana-chartwerk-panel",
"version": "0.4.1", "version": "0.5.0",
"description": "Chartwerk Panel", "description": "Chartwerk Panel",
"scripts": { "scripts": {
"build": "grafana-toolkit plugin:build", "build": "grafana-toolkit plugin:build",
@ -14,8 +14,8 @@
"author": "CorpGlory Inc.", "author": "CorpGlory Inc.",
"license": "GPL V3", "license": "GPL V3",
"devDependencies": { "devDependencies": {
"@chartwerk/gauge-pod": "0.5.0", "@chartwerk/gauge-pod": "^0.6.2",
"@chartwerk/bar-pod": "0.5.0", "@chartwerk/bar-pod": "^0.6.2",
"@grafana/data": "latest", "@grafana/data": "latest",
"@grafana/toolkit": "latest", "@grafana/toolkit": "latest",
"@grafana/ui": "latest", "@grafana/ui": "latest",

2
src/components/Panel.tsx

@ -19,9 +19,7 @@ import * as _ from 'lodash';
interface Props extends PanelProps<PanelOptions> {} interface Props extends PanelProps<PanelOptions> {}
export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) { export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) {
console.log('panelOptions', options);
const grafanaSeriesList = getGrafanaSeriesList(data, timeRange); const grafanaSeriesList = getGrafanaSeriesList(data, timeRange);
let chartContainer = useRef(null); let chartContainer = useRef(null);
// we request animation frame here because we need an existing DOM-element at the moment we render the pod // we request animation frame here because we need an existing DOM-element at the moment we render the pod
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {

10
src/components/editors/UseMetricEditor.tsx

@ -18,7 +18,7 @@ const fieldNamePickerSettings = {
} as any; } as any;
export function UseMetricEditor({ onChange, value, context }: StandardEditorProps<UseMetricConfig>) { export function UseMetricEditor({ onChange, value, context }: StandardEditorProps<UseMetricConfig>) {
const config = value; let config: UseMetricConfig = value;
const onFieldChange = (field: keyof UseMetricConfig, value: any) => { const onFieldChange = (field: keyof UseMetricConfig, value: any) => {
// @ts-ignore // @ts-ignore
@ -31,22 +31,22 @@ export function UseMetricEditor({ onChange, value, context }: StandardEditorProp
<HorizontalGroup> <HorizontalGroup>
<InlineField label="Use metric"> <InlineField label="Use metric">
<InlineSwitch <InlineSwitch
value={config.useMetric} value={config?.useMetric}
onChange={(evt) => onFieldChange('useMetric', (evt.target as any).checked)} onChange={(evt) => onFieldChange('useMetric', (evt.target as any).checked)}
/> />
</InlineField> </InlineField>
<InlineField> <InlineField>
{config.useMetric ? ( {config?.useMetric ? (
<FieldNamePicker <FieldNamePicker
context={context} context={context}
value={config.metricName as string} value={config?.metricName as string}
onChange={(newVal: any) => onFieldChange('metricName', newVal)} onChange={(newVal: any) => onFieldChange('metricName', newVal)}
item={fieldNamePickerSettings} item={fieldNamePickerSettings}
/> />
) : ( ) : (
<Input <Input
placeholder="value" placeholder="value"
value={config.value} value={config?.value}
width={24} width={24}
onChange={(evt) => onFieldChange('value', (evt.target as any).value)} onChange={(evt) => onFieldChange('value', (evt.target as any).value)}
/> />

13
src/grafana/data_processor.ts

@ -2,16 +2,7 @@ import { applyNullInsertThreshold } from './null_insert';
import { find } from 'lodash'; import { find } from 'lodash';
import { import { DataFrame, dateTime, Field, FieldType, getFieldDisplayName, getTimeField, TimeRange } from '@grafana/data';
DataFrame,
dateTime,
Field,
FieldType,
getColorForTheme,
getFieldDisplayName,
getTimeField,
TimeRange,
} from '@grafana/data';
import { colors } from '@grafana/ui'; import { colors } from '@grafana/ui';
import config from 'grafana/app/core/config'; import config from 'grafana/app/core/config';
import TimeSeries from 'grafana/app/core/time_series2'; import TimeSeries from 'grafana/app/core/time_series2';
@ -91,7 +82,7 @@ export class DataProcessor {
const series = new TimeSeries({ const series = new TimeSeries({
datapoints: datapoints || [], datapoints: datapoints || [],
alias: alias, alias: alias,
color: getColorForTheme(color, config.theme), color: config.theme.visualization.getColorByName(color),
unit: field.config ? field.config.unit : undefined, unit: field.config ? field.config.unit : undefined,
dataFrameIndex, dataFrameIndex,
fieldIndex, fieldIndex,

10
src/models/options/gaugeOptions.ts

@ -21,7 +21,10 @@ export class GaugeOptions {
} }
private _setMin(): void { private _setMin(): void {
if (!this.grafanaOptions.gauge.min.useMetric) { if (!this.grafanaOptions.gauge.min) {
throw new Error(`Min Config is not selected: [See options: Extremum -> Min]`);
}
if (!this.grafanaOptions.gauge.min?.useMetric) {
this.minValue = this.grafanaOptions.gauge.min.value; this.minValue = this.grafanaOptions.gauge.min.value;
return; return;
} }
@ -30,7 +33,10 @@ export class GaugeOptions {
} }
private _setMax(): void { private _setMax(): void {
if (!this.grafanaOptions.gauge.max.useMetric) { if (!this.grafanaOptions.gauge.max) {
throw new Error(`Max Config is not selected: [See options: Extremum -> Max]`);
}
if (!this.grafanaOptions.gauge.max?.useMetric) {
this.maxValue = this.grafanaOptions.gauge.max.value; this.maxValue = this.grafanaOptions.gauge.max.value;
return; return;
} }

11
src/models/series.ts

@ -9,9 +9,14 @@ export class Series {
private _seriesList; private _seriesList;
private _selectedSerieName; private _selectedSerieName;
constructor(grafanaSeriesList: any, private gaugeValueOptions: ValueOptions) { constructor(grafanaSeriesList: any[], private gaugeValueOptions: ValueOptions) {
if (_.isEmpty(this.gaugeValueOptions.metricName)) { if (_.isEmpty(grafanaSeriesList)) {
throw new Error(`Value: metric is not selected. [See options: Value -> Metric]`); throw new Error(`No metrics has been provided`);
}
if (_.isEmpty(this.gaugeValueOptions?.metricName)) {
const serie = _.first(grafanaSeriesList);
this._seriesList = this._updateSeriesListWithChartwerkParams([serie]);
return;
} }
this._selectedSerieName = this.gaugeValueOptions.metricName; this._selectedSerieName = this.gaugeValueOptions.metricName;

3
src/module.ts

@ -49,12 +49,12 @@ export const plugin = new PanelPlugin<PanelOptions>(Panel).setPanelOptions((buil
category: ['Value'], category: ['Value'],
showIf: (config) => config.visualizationType === Pod.GAUGE, showIf: (config) => config.visualizationType === Pod.GAUGE,
}) })
// TODO: defaults?
.addCustomEditor({ .addCustomEditor({
id: 'min', id: 'min',
name: 'Min', name: 'Min',
path: 'gauge.min', path: 'gauge.min',
category: ['Extremum'], category: ['Extremum'],
defaultValue: { useMetric: false, value: 0 },
showIf: (config) => config.visualizationType === Pod.GAUGE, showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any, editor: UseMetricEditor as any,
}) })
@ -63,6 +63,7 @@ export const plugin = new PanelPlugin<PanelOptions>(Panel).setPanelOptions((buil
name: 'Max', name: 'Max',
path: 'gauge.max', path: 'gauge.max',
category: ['Extremum'], category: ['Extremum'],
defaultValue: { useMetric: false },
showIf: (config) => config.visualizationType === Pod.GAUGE, showIf: (config) => config.visualizationType === Pod.GAUGE,
editor: UseMetricEditor as any, editor: UseMetricEditor as any,
}) })

10
src/plugin.json

@ -4,7 +4,7 @@
"name": "Chartwerk", "name": "Chartwerk",
"id": "corpglory-chartwerk-panel", "id": "corpglory-chartwerk-panel",
"info": { "info": {
"description": "", "description": "Chartwerk panel with extended chart customization",
"author": { "author": {
"name": "CorpGlory Inc.", "name": "CorpGlory Inc.",
"url": "https://corpglory.com" "url": "https://corpglory.com"
@ -17,11 +17,15 @@
"links": [ "links": [
{ {
"name": "Website", "name": "Website",
"url": "https://gitlab.com/chartwerk/grafana-chartwerk-panel" "url": "https://chartwerk.io/"
}, },
{ {
"name": "License", "name": "License",
"url": "https://gitlab.com/chartwerk/grafana-chartwerk-panel/blob/main/LICENSE" "url": "https://gitlab.com/chartwerk/grafana-chartwerk-panel/blob/main/LICENSE"
},
{
"name": "Gitlab",
"url": "https://gitlab.com/chartwerk/grafana-chartwerk-panel/"
} }
], ],
"screenshots": [ "screenshots": [
@ -34,7 +38,7 @@
"updated": "%TODAY%" "updated": "%TODAY%"
}, },
"dependencies": { "dependencies": {
"grafanaDependency": ">=7.0.0", "grafanaDependency": ">=8.3.0",
"plugins": [] "plugins": []
} }
} }

28
yarn.lock

@ -902,27 +902,27 @@
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f" resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w== integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
"@chartwerk/bar-pod@0.5.0": "@chartwerk/bar-pod@^0.6.2":
version "0.5.0" version "0.6.2"
resolved "https://registry.yarnpkg.com/@chartwerk/bar-pod/-/bar-pod-0.5.0.tgz#8550800fa33f2ea49285a3a3a36c04a802d14d9b" resolved "https://registry.yarnpkg.com/@chartwerk/bar-pod/-/bar-pod-0.6.2.tgz#780089eed241795ff964639f38305cd2fa7a89d6"
integrity sha512-qZIq0Eq5VDhtcrKusL/gKRRNr4g1tDIRQ0uZd6hGG8LYeT8s5AUG1tYZNNrROutMTKvvaSg56XoQKBY9xvZZaA== integrity sha512-2cmuHjdNRo3230oLI1ZRjLANLKfuI5f299WcBAL0eP/6DF5NB8TNV+WrA/Lw+bt9ySop/CtIFEswKhD3Sy+0dA==
dependencies: dependencies:
"@chartwerk/core" "^0.5.0" "@chartwerk/core" latest
"@chartwerk/core@^0.5.0": "@chartwerk/core@latest":
version "0.5.0" version "0.6.9"
resolved "https://registry.yarnpkg.com/@chartwerk/core/-/core-0.5.0.tgz#7d641a5ee3ec9ca588f5b06a0504659113745636" resolved "https://registry.yarnpkg.com/@chartwerk/core/-/core-0.6.9.tgz#9d63844b5935de8362f6f3440159d85040116c60"
integrity sha512-YFqBJ8WFb83yZO2VR+XVRSMX3+ErGcGcdHy5aLeLzOqBW09gO7NENdzlCWXQLsGSx+f9RK2GcSTM4z0Q7OEDfA== integrity sha512-9vv1LDAoR64iS2Nxdc2YqCmWNEf3tC2bULk20K8KFA6oVQmA1imdgFJSUv4cvm7Y9VVtPxlL1wDzIjGiLzeVcw==
dependencies: dependencies:
d3 "^5.7.2" d3 "^5.7.2"
lodash "^4.14.149" lodash "^4.14.149"
"@chartwerk/gauge-pod@0.5.0": "@chartwerk/gauge-pod@^0.6.2":
version "0.5.0" version "0.6.2"
resolved "https://registry.yarnpkg.com/@chartwerk/gauge-pod/-/gauge-pod-0.5.0.tgz#4bf1022b5ae3b9536ef3a5bcb0f872fbd9c685d4" resolved "https://registry.yarnpkg.com/@chartwerk/gauge-pod/-/gauge-pod-0.6.2.tgz#7725394cd65acaaaa81cabb93a0b03e146c10362"
integrity sha512-x+MK737RB8h3c42GJUZoGDKfOcdtwCP58KLdxctzVzH9b0oHdnEGO+BE5M/EwPuoSq1H5F4DqBg8NCLfIVTlvw== integrity sha512-L26hsvHCJruxfIJjXBsgcw2vszKMcMYcsXLGLy9Gy02hETpHR1pTKosgXPEpQqvQBRz+5WX+aL3x6yao/Elg/Q==
dependencies: dependencies:
"@chartwerk/core" "^0.5.0" "@chartwerk/core" latest
"@cnakazawa/watch@^1.0.3": "@cnakazawa/watch@^1.0.3":
version "1.0.4" version "1.0.4"

Loading…
Cancel
Save