Update datasource config editor
This commit is contained in:
@@ -50,7 +50,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
height: 2rem;
|
||||
background-image: none;
|
||||
background-color: ${actionBlue};
|
||||
border: 1px solid ${theme.colors.gray1 || (theme as any).palette.gray1};
|
||||
border: 1px solid ${theme.palette.gray1};
|
||||
border-radius: 1px;
|
||||
color: ${theme.colors.text};
|
||||
|
||||
|
||||
268
src/datasource-zabbix/components/ConfigEditor.tsx
Normal file
268
src/datasource-zabbix/components/ConfigEditor.tsx
Normal file
@@ -0,0 +1,268 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SelectableValue } from '@grafana/data';
|
||||
import { DataSourceHttpSettings, LegacyForms, Field, Input, Button, InlineFormLabel } from '@grafana/ui';
|
||||
const { Select, FormField, Switch } = LegacyForms;
|
||||
import { ZabbixDSOptions, ZabbixSecureJSONData } from '../types';
|
||||
|
||||
const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb'];
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps<ZabbixDSOptions, ZabbixSecureJSONData>;
|
||||
export const ConfigEditor = (props: Props) => {
|
||||
const { options, onOptionsChange } = props;
|
||||
|
||||
const [selectedDBDatasource, setSelectedDBDatasource] = useState(null);
|
||||
const [currentDSType, setCurrentDSType] = useState('');
|
||||
|
||||
// Apply some defaults on initial render
|
||||
useEffect(() => {
|
||||
onOptionsChange({
|
||||
...options,
|
||||
jsonData: {
|
||||
trends: true,
|
||||
...options.jsonData,
|
||||
},
|
||||
});
|
||||
|
||||
if (options.jsonData.dbConnectionEnable) {
|
||||
if (!options.jsonData.dbConnectionDatasourceId) {
|
||||
const dsName = options.jsonData.dbConnectionDatasourceName;
|
||||
getDataSourceSrv().get(dsName)
|
||||
.then(ds => {
|
||||
if (ds) {
|
||||
const selectedDs = getDirectDBDatasources().find(dsOption => dsOption.id === ds.id);
|
||||
setSelectedDBDatasource({ label: selectedDs.name, value: selectedDs.id });
|
||||
setCurrentDSType(selectedDs.type);
|
||||
onOptionsChange({
|
||||
...options,
|
||||
jsonData: {
|
||||
...options.jsonData,
|
||||
dbConnectionDatasourceId: ds.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const selectedDs = getDirectDBDatasources().find(dsOption => dsOption.id === options.jsonData.dbConnectionDatasourceId);
|
||||
setSelectedDBDatasource({ label: selectedDs.name, value: selectedDs.id });
|
||||
setCurrentDSType(selectedDs.type);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl={'http://localhost:9200'}
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={true}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<h3 className="page-heading">Zabbix API details</h3>
|
||||
<div className="gf-form max-width-25">
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={15}
|
||||
label="Username"
|
||||
value={options.jsonData.username || ''}
|
||||
onChange={jsonDataChangeHandler('username', options, onOptionsChange)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form max-width-25">
|
||||
{options.secureJsonFields?.password ?
|
||||
<>
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={15}
|
||||
label="Password"
|
||||
disabled={true}
|
||||
value=""
|
||||
placeholder="Configured"
|
||||
/>
|
||||
<Button onClick={resetSecureJsonField('password', options, onOptionsChange)}>Reset</Button>
|
||||
</>:
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={15}
|
||||
label="Password"
|
||||
type="password"
|
||||
value={options.secureJsonData?.password || options.jsonData.password || ''}
|
||||
onChange={secureJsonDataChangeHandler('password', options, onOptionsChange)}
|
||||
required
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<Switch
|
||||
label="Trends"
|
||||
labelClass="width-7"
|
||||
checked={options.jsonData.trends}
|
||||
onChange={jsonDataSwitchHandler('trends', options, onOptionsChange)}
|
||||
/>
|
||||
{options.jsonData.trends &&
|
||||
<>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={4}
|
||||
label="After"
|
||||
value={options.jsonData.trendsFrom || ''}
|
||||
placeholder="7d"
|
||||
onChange={jsonDataChangeHandler('trendsFrom', options, onOptionsChange)}
|
||||
tooltip="Time after which trends will be used.
|
||||
Best practice is to set this value to your history storage period (7d, 30d, etc)."
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={4}
|
||||
label="Range"
|
||||
value={options.jsonData.trendsRange || ''}
|
||||
placeholder="4d"
|
||||
onChange={jsonDataChangeHandler('trendsRange', options, onOptionsChange)}
|
||||
tooltip="Time range width after which trends will be used instead of history.
|
||||
It's better to set this value in range of 4 to 7 days to prevent loading large amount of history data."
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
labelWidth={7}
|
||||
inputWidth={4}
|
||||
label="Cache TTL"
|
||||
value={options.jsonData.cacheTTL || ''}
|
||||
placeholder="1h"
|
||||
onChange={jsonDataChangeHandler('cacheTTL', options, onOptionsChange)}
|
||||
tooltip="Zabbix data source caches metric names in memory. Specify how often data will be updated."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<h3 className="page-heading">Direct DB Connection</h3>
|
||||
<Switch
|
||||
label="Enable"
|
||||
labelClass="width-9"
|
||||
checked={options.jsonData.dbConnectionEnable}
|
||||
onChange={jsonDataSwitchHandler('dbConnectionEnable', options, onOptionsChange)}
|
||||
/>
|
||||
{options.jsonData.dbConnectionEnable &&
|
||||
<>
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel width={9}>Data Source</InlineFormLabel>
|
||||
<Select width={16} options={getDirectDBDSOptions()} value={selectedDBDatasource} />
|
||||
</div>
|
||||
{currentDSType === 'influxdb' &&
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
labelWidth={9}
|
||||
inputWidth={16}
|
||||
label="Retention Policy"
|
||||
value={options.jsonData.dbConnectionRetentionPolicy || ''}
|
||||
placeholder="Retention policy name"
|
||||
onChange={jsonDataChangeHandler('dbConnectionRetentionPolicy', options, onOptionsChange)}
|
||||
tooltip="Specify retention policy name for fetching long-term stored data (optional).
|
||||
Leave it blank if only default retention policy used."
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<h3 className="page-heading">Other</h3>
|
||||
<Switch
|
||||
label="Disable acknowledges for read-only users"
|
||||
labelClass="width-20"
|
||||
checked={options.jsonData.disableReadOnlyUsersAck}
|
||||
onChange={jsonDataSwitchHandler('disableReadOnlyUsersAck', options, onOptionsChange)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const jsonDataChangeHandler = (
|
||||
key: keyof ZabbixDSOptions,
|
||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||
onChange: Props['onOptionsChange']
|
||||
) => (
|
||||
event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>
|
||||
) => {
|
||||
onChange({
|
||||
...value,
|
||||
jsonData: {
|
||||
...value.jsonData,
|
||||
[key]: event.currentTarget.value || (event.target as HTMLInputElement).checked,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const jsonDataSwitchHandler = (
|
||||
key: keyof ZabbixDSOptions,
|
||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||
onChange: Props['onOptionsChange']
|
||||
) => (
|
||||
event: React.SyntheticEvent<HTMLInputElement>
|
||||
) => {
|
||||
onChange({
|
||||
...value,
|
||||
jsonData: {
|
||||
...value.jsonData,
|
||||
[key]: (event.target as HTMLInputElement).checked,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const secureJsonDataChangeHandler = (
|
||||
key: keyof ZabbixDSOptions,
|
||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||
onChange: Props['onOptionsChange']
|
||||
) => (
|
||||
event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>
|
||||
) => {
|
||||
onChange({
|
||||
...value,
|
||||
jsonData: {
|
||||
...value.jsonData,
|
||||
password: '',
|
||||
},
|
||||
secureJsonData: {
|
||||
...value.secureJsonData,
|
||||
[key]: event.currentTarget.value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const resetSecureJsonField = (
|
||||
key: keyof ZabbixDSOptions,
|
||||
value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
|
||||
onChange: Props['onOptionsChange']
|
||||
) => (
|
||||
event: React.SyntheticEvent<HTMLButtonElement>
|
||||
) => {
|
||||
onChange({
|
||||
...value,
|
||||
secureJsonFields: {
|
||||
...value.secureJsonFields,
|
||||
[key]: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getDirectDBDatasources = () => {
|
||||
let dsList = (getDataSourceSrv() as any).getAll();
|
||||
dsList = dsList.filter(ds => SUPPORTED_SQL_DS.includes(ds.type));
|
||||
return dsList;
|
||||
};
|
||||
|
||||
const getDirectDBDSOptions = () => {
|
||||
const dsList = getDirectDBDatasources();
|
||||
const dsOpts: Array<SelectableValue<number>> = dsList.map(ds => ({ label: ds.name, value: ds.id }));
|
||||
return dsOpts;
|
||||
};
|
||||
@@ -3,12 +3,7 @@ import { parseLegacyVariableQuery } from '../utils';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { VariableQuery, VariableQueryTypes, VariableQueryProps, VariableQueryData } from '../types';
|
||||
import { ZabbixInput } from './ZabbixInput';
|
||||
|
||||
// FormLabel was renamed to InlineFormLabel in Grafana 7.0
|
||||
import * as grafanaUi from '@grafana/ui';
|
||||
const FormLabel = grafanaUi.FormLabel || (grafanaUi as any).InlineFormLabel;
|
||||
const Select = (grafanaUi as any).LegacyForms?.Select || (grafanaUi as any).Select;
|
||||
const Input = (grafanaUi as any).LegacyForms?.Input || (grafanaUi as any).Input;
|
||||
import { InlineFormLabel, Select, Input } from '@grafana/ui';
|
||||
|
||||
export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
||||
queryTypes: Array<SelectableValue<VariableQueryTypes>> = [
|
||||
@@ -96,7 +91,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
return (
|
||||
<>
|
||||
<div className="gf-form max-width-21">
|
||||
<FormLabel width={10}>Query Type</FormLabel>
|
||||
<InlineFormLabel width={10}>Query Type</InlineFormLabel>
|
||||
<Select
|
||||
width={11}
|
||||
value={selectedQueryType}
|
||||
@@ -106,7 +101,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form max-width-30">
|
||||
<FormLabel width={10}>Group</FormLabel>
|
||||
<InlineFormLabel width={10}>Group</InlineFormLabel>
|
||||
<ZabbixInput
|
||||
value={group}
|
||||
onChange={evt => this.handleQueryUpdate(evt, 'group')}
|
||||
@@ -115,7 +110,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
</div>
|
||||
{selectedQueryType.value !== VariableQueryTypes.Group &&
|
||||
<div className="gf-form max-width-30">
|
||||
<FormLabel width={10}>Host</FormLabel>
|
||||
<InlineFormLabel width={10}>Host</InlineFormLabel>
|
||||
<ZabbixInput
|
||||
value={host}
|
||||
onChange={evt => this.handleQueryUpdate(evt, 'host')}
|
||||
@@ -129,7 +124,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
selectedQueryType.value === VariableQueryTypes.ItemValues) &&
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form max-width-30">
|
||||
<FormLabel width={10}>Application</FormLabel>
|
||||
<InlineFormLabel width={10}>Application</InlineFormLabel>
|
||||
<ZabbixInput
|
||||
value={application}
|
||||
onChange={evt => this.handleQueryUpdate(evt, 'application')}
|
||||
@@ -139,7 +134,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
{(selectedQueryType.value === VariableQueryTypes.Item ||
|
||||
selectedQueryType.value === VariableQueryTypes.ItemValues) &&
|
||||
<div className="gf-form max-width-30">
|
||||
<FormLabel width={10}>Item</FormLabel>
|
||||
<InlineFormLabel width={10}>Item</InlineFormLabel>
|
||||
<ZabbixInput
|
||||
value={item}
|
||||
onChange={evt => this.handleQueryUpdate(evt, 'item')}
|
||||
@@ -152,7 +147,7 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
|
||||
|
||||
{legacyQuery &&
|
||||
<div className="gf-form">
|
||||
<FormLabel width={10} tooltip="Original query string, read-only">Legacy Query</FormLabel>
|
||||
<InlineFormLabel width={10} tooltip="Original query string, read-only">Legacy Query</InlineFormLabel>
|
||||
<Input
|
||||
value={legacyQuery}
|
||||
readOnly={true}
|
||||
|
||||
@@ -11,10 +11,10 @@ const variablePattern = RegExp(`^${variableRegex.source}`);
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({
|
||||
inputRegex: css`
|
||||
color: ${theme.colors.orange || (theme as any).palette.orange}
|
||||
color: ${theme.palette.orange}
|
||||
`,
|
||||
inputVariable: css`
|
||||
color: ${theme.colors.variable || (theme as any).palette.variable}
|
||||
color: ${theme.colors.textBlue}
|
||||
`,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import { migrateDSConfig } from './migrations';
|
||||
|
||||
const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb'];
|
||||
|
||||
const defaultConfig = {
|
||||
trends: false,
|
||||
dbConnectionEnable: false,
|
||||
dbConnectionDatasourceId: null,
|
||||
alerting: false,
|
||||
addThresholds: false,
|
||||
alertingMinSeverity: 3,
|
||||
disableReadOnlyUsersAck: false,
|
||||
};
|
||||
|
||||
export class ZabbixDSConfigController {
|
||||
|
||||
/** @ngInject */
|
||||
constructor() {
|
||||
this.current.jsonData = migrateDSConfig(this.current.jsonData);
|
||||
_.defaults(this.current.jsonData, defaultConfig);
|
||||
|
||||
this.dbConnectionDatasourceId = this.current.jsonData.dbConnectionDatasourceId;
|
||||
this.dbDataSources = this.getSupportedDBDataSources();
|
||||
if (!this.dbConnectionDatasourceId) {
|
||||
this.loadCurrentDBDatasource();
|
||||
}
|
||||
}
|
||||
|
||||
getSupportedDBDataSources() {
|
||||
let datasources = getDataSourceSrv().getAll();
|
||||
return _.filter(datasources, ds => {
|
||||
return _.includes(SUPPORTED_SQL_DS, ds.type);
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentDatasourceType() {
|
||||
const dsId = this.dbConnectionDatasourceId;
|
||||
const currentDs = _.find(this.dbDataSources, { 'id': dsId });
|
||||
return currentDs ? currentDs.type : null;
|
||||
}
|
||||
|
||||
loadCurrentDBDatasource() {
|
||||
const dsName= this.current.jsonData.dbConnectionDatasourceName;
|
||||
getDataSourceSrv().loadDatasource(dsName)
|
||||
.then(ds => {
|
||||
if (ds) {
|
||||
this.dbConnectionDatasourceId = ds.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDBConnectionDatasourceChange() {
|
||||
this.current.jsonData.dbConnectionDatasourceId = this.dbConnectionDatasourceId;
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,11 @@ import responseHandler from './responseHandler';
|
||||
import problemsHandler from './problemsHandler';
|
||||
import { Zabbix } from './zabbix/zabbix';
|
||||
import { ZabbixAPIError } from './zabbix/connectors/zabbix_api/zabbixAPIConnector';
|
||||
import { VariableQueryTypes, ShowProblemTypes } from './types';
|
||||
import { ZabbixMetricsQuery, ZabbixDSOptions, VariableQueryTypes, ShowProblemTypes } from './types';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DataSourceApi, DataSourceInstanceSettings } from '@grafana/data';
|
||||
|
||||
export class ZabbixDatasource extends DataSourceApi {
|
||||
export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDSOptions> {
|
||||
name: string;
|
||||
basicAuth: any;
|
||||
withCredentials: any;
|
||||
@@ -39,7 +39,7 @@ export class ZabbixDatasource extends DataSourceApi {
|
||||
replaceTemplateVars: (target: any, scopedVars?: any) => any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(instanceSettings: DataSourceInstanceSettings, private templateSrv, private zabbixAlertingSrv) {
|
||||
constructor(instanceSettings: DataSourceInstanceSettings<ZabbixDSOptions>, private templateSrv, private zabbixAlertingSrv) {
|
||||
super(instanceSettings);
|
||||
|
||||
this.templateSrv = templateSrv;
|
||||
@@ -503,11 +503,7 @@ export class ZabbixDatasource extends DataSourceApi {
|
||||
*/
|
||||
async testDatasource() {
|
||||
try {
|
||||
const result = await this.doTSDBConnectionTest();
|
||||
/**
|
||||
* @type {ZabbixConnectionInfo}
|
||||
*/
|
||||
const { zabbixVersion, dbConnectorStatus } = result.results["zabbixAPI"].meta;
|
||||
const { zabbixVersion, dbConnectorStatus } = await this.zabbix.testDataSource();
|
||||
let message = `Zabbix API version: ${zabbixVersion}`;
|
||||
if (dbConnectorStatus) {
|
||||
message += `, DB connector type: ${dbConnectorStatus.dsType}`;
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
import { DataSourcePlugin } from '@grafana/data';
|
||||
import { loadPluginCss } from '@grafana/runtime';
|
||||
import { ZabbixDatasource } from './datasource';
|
||||
import { ZabbixQueryController } from './query.controller';
|
||||
import { ZabbixDSConfigController } from './config.controller';
|
||||
import { ZabbixVariableQueryEditor } from './components/VariableQueryEditor';
|
||||
import { ConfigEditor } from './components/ConfigEditor';
|
||||
import './zabbixAlerting.service.js';
|
||||
import './add-metric-function.directive';
|
||||
import './metric-function-editor.directive';
|
||||
|
||||
class ZabbixQueryOptionsController {
|
||||
static templateUrl = 'datasource-zabbix/partials/query.options.html';
|
||||
}
|
||||
|
||||
class ZabbixAnnotationsQueryController {
|
||||
static templateUrl = 'datasource-zabbix/partials/annotations.editor.html';
|
||||
}
|
||||
|
||||
ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';
|
||||
ZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html';
|
||||
|
||||
loadPluginCss({
|
||||
dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',
|
||||
light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'
|
||||
});
|
||||
|
||||
export {
|
||||
ZabbixDatasource as Datasource,
|
||||
ZabbixDSConfigController as ConfigCtrl,
|
||||
ZabbixQueryController as QueryCtrl,
|
||||
ZabbixQueryOptionsController as QueryOptionsCtrl,
|
||||
ZabbixAnnotationsQueryController as AnnotationsQueryCtrl,
|
||||
ZabbixVariableQueryEditor as VariableQueryEditor,
|
||||
};
|
||||
export const plugin = new DataSourcePlugin(ZabbixDatasource)
|
||||
.setConfigEditor(ConfigEditor)
|
||||
.setQueryCtrl(ZabbixQueryController)
|
||||
.setAnnotationQueryCtrl(ZabbixAnnotationsQueryController)
|
||||
.setVariableQueryEditor(ZabbixVariableQueryEditor);
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
<datasource-http-settings current="ctrl.current" suggest-url="http://localhost/zabbix/api_jsonrpc.php">
|
||||
</datasource-http-settings>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<h3 class="page-heading">Zabbix API details</h3>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Username
|
||||
</span>
|
||||
<input class="gf-form-input max-width-21"
|
||||
type="text"
|
||||
ng-model='ctrl.current.jsonData.username'
|
||||
placeholder="user"
|
||||
required>
|
||||
</input>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Password
|
||||
</span>
|
||||
<input class="gf-form-input max-width-21"
|
||||
type="password"
|
||||
ng-model='ctrl.current.jsonData.password'
|
||||
placeholder="password">
|
||||
</input>
|
||||
</div>
|
||||
|
||||
<gf-form-switch class="gf-form" label-class="width-7"
|
||||
label="Trends"
|
||||
checked="ctrl.current.jsonData.trends"
|
||||
switch-class="max-width-5">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form" ng-if="ctrl.current.jsonData.trends">
|
||||
<span class="gf-form-label width-7">
|
||||
After
|
||||
<info-popover mode="right-normal">
|
||||
Time after which trends will be used.
|
||||
Best practice is to set this value to your history storage period (7d, 30d, etc).
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-5"
|
||||
type="text"
|
||||
ng-model='ctrl.current.jsonData.trendsFrom'
|
||||
placeholder="7d">
|
||||
</input>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.current.jsonData.trends">
|
||||
<span class="gf-form-label width-7">
|
||||
Range
|
||||
<info-popover mode="right-normal">
|
||||
Time range width after which trends will be used instead of history.
|
||||
It's better to set this value in range of 4 to 7 days to prevent loading large amount of history data.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-5" type="text" ng-model='ctrl.current.jsonData.trendsRange' placeholder="4d">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-12">
|
||||
Cache TTL
|
||||
<info-popover mode="right-normal">
|
||||
Zabbix data source caches metric names in memory. Specify how often data will be updated.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-7"
|
||||
type="text"
|
||||
ng-model='ctrl.current.jsonData.cacheTTL'
|
||||
placeholder="1h">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<h3 class="page-heading">Direct DB Connection</h3>
|
||||
<gf-form-switch class="gf-form" label-class="width-12"
|
||||
label="Enable"
|
||||
checked="ctrl.current.jsonData.dbConnectionEnable">
|
||||
</gf-form-switch>
|
||||
<div ng-if="ctrl.current.jsonData.dbConnectionEnable">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-12">
|
||||
Data Source
|
||||
<info-popover mode="right-normal">
|
||||
Select Data Source for Zabbix history database.
|
||||
In order to use this feature it should be <a href="/datasources/new" target="_blank">created</a> and
|
||||
configured first. Zabbix plugin uses this data source for querying history data directly from the database.
|
||||
This way usually faster than pulling data from Zabbix API, especially on the wide time ranges, and reduces
|
||||
amount of data transferred.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-16">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.dbConnectionDatasourceId"
|
||||
ng-options="ds.id as ds.name for ds in ctrl.dbDataSources"
|
||||
ng-change="ctrl.onDBConnectionDatasourceChange()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="ctrl.getCurrentDatasourceType() === 'influxdb'">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-12">
|
||||
Retention Policy
|
||||
<info-popover mode="right-normal">
|
||||
Specify retention policy name for fetching long-term stored data (optional).
|
||||
Leave it blank if only default retention policy used.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-16"
|
||||
type="text"
|
||||
ng-model='ctrl.current.jsonData.dbConnectionRetentionPolicy'
|
||||
placeholder="Retention policy name">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<h3 class="page-heading">Alerting</h3>
|
||||
<gf-form-switch class="gf-form" label-class="width-12"
|
||||
label="Enable alerting"
|
||||
checked="ctrl.current.jsonData.alerting">
|
||||
</gf-form-switch>
|
||||
<div ng-if="ctrl.current.jsonData.alerting">
|
||||
<gf-form-switch class="gf-form" label-class="width-12"
|
||||
label="Add thresholds"
|
||||
checked="ctrl.current.jsonData.addThresholds">
|
||||
</gf-form-switch>
|
||||
<div class="gf-form max-width-20">
|
||||
<span class="gf-form-label width-12">Min severity</span>
|
||||
<div class="gf-form-select-wrapper max-width-16">
|
||||
<select class="gf-form-input" ng-model="ctrl.current.jsonData.alertingMinSeverity"
|
||||
ng-options="s.val as s.text for s in [
|
||||
{val: 0, text: 'Not classified'}, {val: 1, text:'Information'},
|
||||
{val: 2, text: 'Warning'}, {val: 3, text: 'Average'},
|
||||
{val: 4, text: 'High'}, {val: 5, text: 'Disaster'}]">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<h3 class="page-heading">Other</h3>
|
||||
<gf-form-switch class="gf-form" label-class="width-20"
|
||||
label="Disable acknowledges for read-only users"
|
||||
checked="ctrl.current.jsonData.disableReadOnlyUsersAck">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
@@ -1,88 +0,0 @@
|
||||
<section class="grafana-metric-options gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-15">
|
||||
<span class="gf-form-label">Max data points</span>
|
||||
<input type="text"
|
||||
class="gf-form-input"
|
||||
ng-model="ctrl.panelCtrl.panel.maxDataPoints"
|
||||
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
||||
data-placement="right"
|
||||
ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"
|
||||
spellcheck='false'
|
||||
placeholder="auto">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
Max data points
|
||||
</a>
|
||||
</span>
|
||||
<span class="gf-form-label width-10">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
IT services
|
||||
</a>
|
||||
</span>
|
||||
<span class="gf-form-label width-12">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
IT service property
|
||||
</a>
|
||||
</span>
|
||||
<span class="gf-form-label width-8">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
Text filter
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left">
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
|
||||
<h5>Max data points</h5>
|
||||
<ul>
|
||||
<li>Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this
|
||||
number
|
||||
</li>
|
||||
<li>If there are more real values, then by default they will be consolidated using averages</li>
|
||||
<li>This could hide real peaks and max values in your series</li>
|
||||
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
|
||||
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
|
||||
<h5>IT services</h5>
|
||||
<ul>
|
||||
<li>Select "IT services" in targets menu to activate IT services mode.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
|
||||
<h5>IT service property</h5>
|
||||
<ul>
|
||||
<li>Zabbix returns the following availability information about IT service</li>
|
||||
<li>Status - current status of the IT service</li>
|
||||
<li>SLA - SLA for the given time interval</li>
|
||||
<li>OK time - time the service was in OK state, in seconds</li>
|
||||
<li>Problem time - time the service was in problem state, in seconds</li>
|
||||
<li>Down time - time the service was in scheduled downtime, in seconds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 4">
|
||||
<h5>Text filter</h5>
|
||||
<ul>
|
||||
<li>Use regex to extract a part of the returned value.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,22 @@
|
||||
import { SelectableValue, DataQuery } from "@grafana/data";
|
||||
import { SelectableValue, DataQuery, DataSourceJsonData } from "@grafana/data";
|
||||
|
||||
export interface ZabbixDSOptions extends DataSourceJsonData {
|
||||
username: string;
|
||||
password?: string;
|
||||
trends: boolean;
|
||||
trendsFrom: string;
|
||||
trendsRange: string;
|
||||
cacheTTL: string;
|
||||
dbConnectionEnable: boolean;
|
||||
dbConnectionDatasourceId?: number;
|
||||
dbConnectionDatasourceName?: string;
|
||||
dbConnectionRetentionPolicy?: string;
|
||||
disableReadOnlyUsersAck: boolean;
|
||||
}
|
||||
|
||||
export interface ZabbixSecureJSONData {
|
||||
password?: string;
|
||||
}
|
||||
|
||||
export interface ZabbixConnectionInfo {
|
||||
zabbixVersion: string;
|
||||
|
||||
@@ -138,37 +138,34 @@ export class Zabbix implements ZabbixConnector {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
// testDataSource() {
|
||||
// let zabbixVersion;
|
||||
// let dbConnectorStatus;
|
||||
// return this.getVersion()
|
||||
// .then(version => {
|
||||
// zabbixVersion = version;
|
||||
// return this.login();
|
||||
// })
|
||||
// .then(() => {
|
||||
// if (this.enableDirectDBConnection) {
|
||||
// return this.dbConnector.testDataSource();
|
||||
// } else {
|
||||
// return Promise.resolve();
|
||||
// }
|
||||
// })
|
||||
// .catch(error => {
|
||||
// if (error instanceof ZabbixNotImplemented) {
|
||||
// return Promise.resolve();
|
||||
// }
|
||||
// return Promise.reject(error);
|
||||
// })
|
||||
// .then(testResult => {
|
||||
// if (testResult) {
|
||||
// dbConnectorStatus = {
|
||||
// dsType: this.dbConnector.datasourceTypeName,
|
||||
// dsName: this.dbConnector.datasourceName
|
||||
// };
|
||||
// }
|
||||
// return { zabbixVersion, dbConnectorStatus };
|
||||
// });
|
||||
// }
|
||||
testDataSource() {
|
||||
let zabbixVersion;
|
||||
let dbConnectorStatus;
|
||||
return this.getVersion()
|
||||
.then(version => {
|
||||
zabbixVersion = version;
|
||||
return this.getAllGroups();
|
||||
})
|
||||
.then(() => {
|
||||
if (this.enableDirectDBConnection) {
|
||||
return this.dbConnector.testDataSource();
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
return Promise.reject(error);
|
||||
})
|
||||
.then(testResult => {
|
||||
if (testResult) {
|
||||
dbConnectorStatus = {
|
||||
dsType: this.dbConnector.datasourceTypeName,
|
||||
dsName: this.dbConnector.datasourceName
|
||||
};
|
||||
}
|
||||
return { zabbixVersion, dbConnectorStatus };
|
||||
});
|
||||
}
|
||||
|
||||
getItemsFromTarget(target, options) {
|
||||
const parts = ['group', 'host', 'application', 'item'];
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { cx, css } from 'emotion';
|
||||
import { ZBX_ACK_ACTION_ADD_MESSAGE, ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_CHANGE_SEVERITY, ZBX_ACK_ACTION_CLOSE } from '../../datasource-zabbix/constants';
|
||||
import { Button, VerticalGroup, Spinner, Modal, Input, Forms, stylesFactory, withTheme, Themeable } from '@grafana/ui';
|
||||
import { Button, VerticalGroup, Spinner, Modal, Input, Checkbox, RadioButtonGroup, stylesFactory, withTheme, Themeable } from '@grafana/ui';
|
||||
import { FAIcon } from '../../components';
|
||||
|
||||
import * as grafanaUi from '@grafana/ui';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
const Checkbox: any = Forms?.Checkbox || (grafanaUi as any).Checkbox;
|
||||
const RadioButtonGroup: any = Forms?.RadioButtonGroup || (grafanaUi as any).RadioButtonGroup;
|
||||
|
||||
const KEYBOARD_ENTER_KEY = 13;
|
||||
const KEYBOARD_ESCAPE_KEY = 27;
|
||||
@@ -239,7 +235,7 @@ export class AckModalUnthemed extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
const red = theme.colors.red || (theme as any).palette.red;
|
||||
const red = theme.palette.red;
|
||||
return {
|
||||
modal: css`
|
||||
width: 500px;
|
||||
@@ -257,7 +253,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
border-color: ${red};
|
||||
border-radius: 2px;
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 2px ${theme.colors.pageBg || (theme as any).colors.bg1}, 0 0 0px 4px ${red};
|
||||
box-shadow: 0 0 0 2px ${theme.colors.bg1}, 0 0 0px 4px ${red};
|
||||
`,
|
||||
inputHint: css`
|
||||
display: inherit;
|
||||
|
||||
Reference in New Issue
Block a user