Files
grafana-zabbix/src/datasource/components/AnnotationQueryEditor.tsx
Alexander Zobnin e3e896742b Build plugin with grafana toolkit (#1539)
* Use grafana toolkit template for building plugin

* Fix linter and type errors

* Update styles building

* Fix sass deprecation warning

* Remove empty js files produced by webpack building sass

* Fix signing script

* Replace classnames with cx

* Fix data source config page

* Use custom webpack config instead of overriding original one

* Use gpx_ prefix for plugin executable

* Remove unused configs

* Roll back react hooks dependencies usage

* Move plugin-specific ts config to root config file

* Temporary do not use rst2html for function description tooltip

* Remove unused code

* remove unused dependencies

* update react table dependency

* Migrate tests to typescript

* remove unused dependencies

* Remove old webpack configs

* Add sign target to makefile

* Add magefile

* Update CI test job

* Update go packages

* Update build instructions

* Downgrade go version to 1.18

* Fix go version in ci

* Fix metric picker

* Add comment to webpack config

* remove angular mocks

* update bra config

* Rename datasource-zabbix to datasource (fix mage build)

* Add instructions for building backend with mage

* Fix webpack targets

* Fix ci backend tests

* Add initial e2e tests

* Fix e2e ci tests

* Update docker compose for cypress tests

* build grafana docker image

* Fix docker stop task

* CI: add Grafana compatibility check
2022-12-09 14:14:34 +03:00

196 lines
6.4 KiB
TypeScript

import _ from 'lodash';
import React, { useEffect, FormEvent } from 'react';
import { useAsyncFn } from 'react-use';
import { AnnotationQuery, SelectableValue } from '@grafana/data';
import { InlineField, InlineSwitch, Input, Select } from '@grafana/ui';
import { ZabbixMetricsQuery } from '../types';
import { ZabbixQueryEditorProps } from './QueryEditor';
import { QueryEditorRow } from './QueryEditor/QueryEditorRow';
import { MetricPicker } from '../../components';
import { getVariableOptions } from './QueryEditor/utils';
import { prepareAnnotation } from '../migrations';
const severityOptions: Array<SelectableValue<number>> = [
{ value: 0, label: 'Not classified' },
{ value: 1, label: 'Information' },
{ value: 2, label: 'Warning' },
{ value: 3, label: 'Average' },
{ value: 4, label: 'High' },
{ value: 5, label: 'Disaster' },
];
type Props = ZabbixQueryEditorProps & {
annotation?: AnnotationQuery<ZabbixMetricsQuery>;
onAnnotationChange?: (annotation: AnnotationQuery<ZabbixMetricsQuery>) => void;
};
export const AnnotationQueryEditor = ({ annotation, onAnnotationChange, datasource }: Props) => {
annotation = prepareAnnotation(annotation);
const query = annotation.target;
const loadGroupOptions = async () => {
const groups = await datasource.zabbix.getAllGroups();
const options = groups?.map((group) => ({
value: group.name,
label: group.name,
}));
options.unshift(...getVariableOptions());
return options;
};
const [{ loading: groupsLoading, value: groupsOptions }, fetchGroups] = useAsyncFn(async () => {
const options = await loadGroupOptions();
return options;
}, []);
const loadHostOptions = async (group: string) => {
const groupFilter = datasource.replaceTemplateVars(group);
const hosts = await datasource.zabbix.getAllHosts(groupFilter);
let options: Array<SelectableValue<string>> = hosts?.map((host) => ({
value: host.name,
label: host.name,
}));
options = _.uniqBy(options, (o) => o.value);
options.unshift({ value: '/.*/' });
options.unshift(...getVariableOptions());
return options;
};
const [{ loading: hostsLoading, value: hostOptions }, fetchHosts] = useAsyncFn(async () => {
const options = await loadHostOptions(query.group.filter);
return options;
}, [query.group.filter]);
const loadAppOptions = async (group: string, host: string) => {
const groupFilter = datasource.replaceTemplateVars(group);
const hostFilter = datasource.replaceTemplateVars(host);
const apps = await datasource.zabbix.getAllApps(groupFilter, hostFilter);
let options: Array<SelectableValue<string>> = apps?.map((app) => ({
value: app.name,
label: app.name,
}));
options = _.uniqBy(options, (o) => o.value);
options.unshift(...getVariableOptions());
return options;
};
const [{ loading: appsLoading, value: appOptions }, fetchApps] = useAsyncFn(async () => {
const options = await loadAppOptions(query.group.filter, query.host.filter);
return options;
}, [query.group.filter, query.host.filter]);
// Update suggestions on every metric change
const groupFilter = datasource.replaceTemplateVars(query.group?.filter);
const hostFilter = datasource.replaceTemplateVars(query.host?.filter);
useEffect(() => {
fetchGroups();
}, []);
useEffect(() => {
fetchHosts();
}, [groupFilter]);
useEffect(() => {
fetchApps();
}, [groupFilter, hostFilter]);
const onChange = (query: any) => {
onAnnotationChange({
...annotation,
target: query,
});
};
const onFilterChange = (prop: string) => {
return (value: string) => {
if (value !== null) {
onChange({ ...query, [prop]: { filter: value } });
}
};
};
const onTextFilterChange = (prop: string) => {
return (v: FormEvent<HTMLInputElement>) => {
const newValue = v?.currentTarget?.value;
if (newValue !== null) {
onChange({ ...query, [prop]: { filter: newValue } });
}
};
};
const onMinSeverityChange = (option: SelectableValue) => {
if (option.value !== null) {
onChange({ ...query, options: { ...query.options, minSeverity: option.value } });
}
};
const onOptionSwitch = (prop: string) => () => {
onChange({ ...query, options: { ...query.options, [prop]: !query.options[prop] } });
};
return (
<>
<QueryEditorRow>
<InlineField label="Group" labelWidth={12}>
<MetricPicker
width={24}
value={query.group?.filter}
options={groupsOptions}
isLoading={groupsLoading}
onChange={onFilterChange('group')}
/>
</InlineField>
<InlineField label="Host" labelWidth={12}>
<MetricPicker
width={24}
value={query.host?.filter}
options={hostOptions}
isLoading={hostsLoading}
onChange={onFilterChange('host')}
/>
</InlineField>
</QueryEditorRow>
<QueryEditorRow>
<InlineField label="Application" labelWidth={12}>
<MetricPicker
width={24}
value={query.application?.filter}
options={appOptions}
isLoading={appsLoading}
onChange={onFilterChange('application')}
/>
</InlineField>
<InlineField label="Problem" labelWidth={12}>
<Input
width={24}
defaultValue={query.trigger?.filter}
placeholder="Problem name"
onBlur={onTextFilterChange('trigger')}
/>
</InlineField>
</QueryEditorRow>
<>
<InlineField label="Min severity" labelWidth={12}>
<Select
isSearchable={false}
width={24}
value={query.options?.minSeverity}
options={severityOptions}
onChange={onMinSeverityChange}
/>
</InlineField>
<InlineField label="Show OK events" labelWidth={24}>
<InlineSwitch value={query.options.showOkEvents} onChange={onOptionSwitch('showOkEvents')} />
</InlineField>
<InlineField label="Hide acknowledged events" labelWidth={24}>
<InlineSwitch value={query.options.hideAcknowledged} onChange={onOptionSwitch('hideAcknowledged')} />
</InlineField>
<InlineField label="Show hostname" labelWidth={24}>
<InlineSwitch value={query.options.showHostname} onChange={onOptionSwitch('showHostname')} />
</InlineField>
</>
</>
);
};