Skip to content

Commit

Permalink
Add variable query editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Malte Lehmann authored and Malte Lehmann committed Jan 15, 2023
1 parent 1cade0f commit 39ec413
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 16 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Whether the alerts gathered should be inhibited.

![Parameters](https://raw.githubusercontent.com/camptocamp/grafana-prometheus-alertmanager-datasource/master/img/table.png)

# Variable Query Editor

Additionally, to the query editor options, the `Field` must be filled whose values are used for the variable.

![Parameters](https://raw.githubusercontent.com/camptocamp/grafana-prometheus-alertmanager-datasource/master/img/variablequeryeditor.png)

# Panels

## Stat
Expand Down
Binary file added img/variablequeryeditor.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 45 additions & 7 deletions src/DataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import {
DataSourceApi,
DataSourceInstanceSettings,
FieldType,
MetricFindValue,
MutableDataFrame,
ScopedVars,
} from '@grafana/data';
import { getBackendSrv, getTemplateSrv } from '@grafana/runtime';
import { GenericOptions, CustomQuery, QueryRequest, defaultQuery } from './types';
Expand All @@ -26,8 +28,8 @@ export class AlertmanagerDataSource extends DataSourceApi<CustomQuery, GenericOp
}
}

async query(options: QueryRequest): Promise<DataQueryResponse> {
const promises = options.targets.map((query) => {
async doQuery(queries: CustomQuery[], scopedVars?: ScopedVars): Promise<MutableDataFrame[]> {
const promises = queries.map((query) => {
query = { ...defaultQuery, ...query };
if (query.hide) {
return Promise.resolve(new MutableDataFrame());
Expand All @@ -44,25 +46,61 @@ export class AlertmanagerDataSource extends DataSourceApi<CustomQuery, GenericOp
params.push(`receiver=${query.receiver}`);
}
if (query.filters !== undefined && query.filters.length > 0) {
query.filters = getTemplateSrv().replace(query.filters, options.scopedVars, this.interpolateQueryExpr);
query.filters = getTemplateSrv().replace(query.filters, scopedVars, this.interpolateQueryExpr);
query.filters.split(',').forEach((value) => {
params.push(`filter=${encodeURIComponent(value)}`);
});
}

const request = this.doRequest({
return this.doRequest({
url: `${this.url}/api/v2/alerts?${params.join('&')}`,
method: 'GET',
}).then((data) => lastValueFrom(data));

return request.then((data: any) => this.retrieveData(query, data));
})
.then((data) => lastValueFrom(data))
.then((data) => {
return this.retrieveData(query, data);
})
.catch(() => {
return new MutableDataFrame();
});
});

return Promise.all(promises).then((data) => {
return data;
});
}

async query(options: QueryRequest): Promise<DataQueryResponse> {
return this.doQuery(options.targets, options.scopedVars).then((data) => {
return { data };
});
}

async metricFindQuery(query: CustomQuery, options?: any): Promise<MetricFindValue[]> {
if (typeof query.field === undefined) {
return [];
}
const response = (await this.doQuery([query], options.scopedVars))[0];

let fieldIndex = -1;
response.fields.forEach((field, index) => {
if (field.name === query.field) {
fieldIndex = index;
}
});
if (fieldIndex === -1) {
return [];
}

const values = response.fields[fieldIndex].values.toArray().map((val) => {
return val.toString();
});
const unique = [...new Set(values)];
return unique.map((val) => {
return { text: val };
});
}

async testDatasource() {
return this.doRequest({
url: this.url,
Expand Down
41 changes: 33 additions & 8 deletions src/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,36 @@ export class QueryEditor extends PureComponent<Props> {

onActiveChange = () => {
const { onChange, query, onRunQuery } = this.props;
query.active = !query.active;
onChange({ ...query });
let newQuery = { ...query };
newQuery.active = !query.active;
onChange(newQuery);
onRunQuery();
};

onSilencedChange = () => {
const { onChange, query, onRunQuery } = this.props;
query.silenced = !query.silenced;
onChange({ ...query });
let newQuery = { ...query };
newQuery.silenced = !query.silenced;
onChange(newQuery);
onRunQuery();
};

onInhibitedChange = () => {
const { onChange, query, onRunQuery } = this.props;
query.inhibited = !query.inhibited;
onChange({ ...query });
let newQuery = { ...query };
newQuery.inhibited = !query.inhibited;
onChange(newQuery);
onRunQuery();
};

render() {
const { receiver, filters, active, silenced, inhibited } = { ...defaultQuery, ...this.props.query };
onFieldChange = (event: ChangeEvent<HTMLInputElement>) => {
const { onChange, query, onRunQuery } = this.props;
onChange({ ...query, field: event.target.value });
onRunQuery();
};

baseRender(showField: boolean) {
let { receiver, filters, active, silenced, inhibited, field } = { ...defaultQuery, ...this.props.query };

return (
<>
Expand All @@ -70,6 +79,18 @@ export class QueryEditor extends PureComponent<Props> {
label="Filters (comma separated key=value)"
/>
</div>
{showField && (
<div className="gf-form">
<FormField
value={field}
inputWidth={10}
onChange={this.onFieldChange}
labelWidth={5}
label="Field"
tooltip="Variables are taken from the values of this field in the query result"
/>
</div>
)}
<div className="gf-form">
<Switch label="Active" checked={active} onChange={this.onActiveChange} />
</div>
Expand All @@ -83,4 +104,8 @@ export class QueryEditor extends PureComponent<Props> {
</>
);
}

render() {
return this.baseRender(false);
}
}
7 changes: 7 additions & 0 deletions src/VariableQueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { QueryEditor } from './QueryEditor';

export class CustomVariableQueryEditor extends QueryEditor {
render() {
return super.baseRender(true);
}
}
4 changes: 3 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ConfigEditor } from './ConfigEditor';
import { AlertmanagerDataSource } from './DataSource';
import { QueryEditor } from './QueryEditor';
import { CustomQuery, GenericOptions } from './types';
import { CustomVariableQueryEditor } from './VariableQueryEditor';

class GenericAnnotationsQueryCtrl {
static templateUrl = 'partials/annotations.editor.html';
Expand All @@ -11,4 +12,5 @@ class GenericAnnotationsQueryCtrl {
export const plugin = new DataSourcePlugin<AlertmanagerDataSource, CustomQuery, GenericOptions>(AlertmanagerDataSource)
.setAnnotationQueryCtrl(GenericAnnotationsQueryCtrl)
.setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor);
.setQueryEditor(QueryEditor)
.setVariableQueryEditor(CustomVariableQueryEditor);
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface CustomQuery extends DataQuery {
active: boolean;
silenced: boolean;
inhibited: boolean;
field: string;
}

export const defaultQuery: Partial<CustomQuery> = {
Expand Down

0 comments on commit 39ec413

Please sign in to comment.