123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- import { uniqueId } from 'lodash';
- import React, { PureComponent } from 'react';
- import {
- DataSourcePluginOptionsEditorProps,
- SelectableValue,
- onUpdateDatasourceOption,
- updateDatasourcePluginResetOption,
- onUpdateDatasourceJsonDataOption,
- onUpdateDatasourceJsonDataOptionSelect,
- onUpdateDatasourceSecureJsonDataOption,
- updateDatasourcePluginJsonDataOption,
- } from '@grafana/data';
- import { Alert, DataSourceHttpSettings, InfoBox, InlineField, InlineFormLabel, LegacyForms, Select } from '@grafana/ui';
- const { Input, SecretFormField } = LegacyForms;
- import { InfluxOptions, InfluxSecureJsonData, InfluxVersion } from '../types';
- const httpModes = [
- { label: 'GET', value: 'GET' },
- { label: 'POST', value: 'POST' },
- ] as SelectableValue[];
- const versions = [
- {
- label: 'InfluxQL',
- value: InfluxVersion.InfluxQL,
- description: 'The InfluxDB SQL-like query language.',
- },
- {
- label: 'Flux',
- value: InfluxVersion.Flux,
- description: 'Advanced data scripting and query language. Supported in InfluxDB 2.x and 1.8+',
- },
- ] as Array<SelectableValue<InfluxVersion>>;
- export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions>;
- type State = {
- maxSeries: string | undefined;
- };
- export class ConfigEditor extends PureComponent<Props, State> {
- state = {
- maxSeries: '',
- };
- htmlPrefix: string;
- constructor(props: Props) {
- super(props);
- this.state.maxSeries = props.options.jsonData.maxSeries?.toString() || '';
- this.htmlPrefix = uniqueId('influxdb-config');
- }
- // 1x
- onResetPassword = () => {
- updateDatasourcePluginResetOption(this.props, 'password');
- };
- // 2x
- onResetToken = () => {
- updateDatasourcePluginResetOption(this.props, 'token');
- };
- onVersionChanged = (selected: SelectableValue<InfluxVersion>) => {
- const { options, onOptionsChange } = this.props;
- const copy: any = {
- ...options,
- jsonData: {
- ...options.jsonData,
- version: selected.value,
- },
- };
- if (selected.value === InfluxVersion.Flux) {
- copy.access = 'proxy';
- copy.basicAuth = true;
- copy.jsonData.httpMode = 'POST';
- // Remove old 1x configs
- delete copy.user;
- delete copy.database;
- }
- onOptionsChange(copy);
- };
- renderInflux2x() {
- const { options } = this.props;
- const { secureJsonFields } = options;
- const secureJsonData = (options.secureJsonData || {}) as InfluxSecureJsonData;
- const { htmlPrefix } = this;
- return (
- <>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel htmlFor={`${htmlPrefix}-org`} className="width-10">
- Organization
- </InlineFormLabel>
- <div className="width-10">
- <Input
- id={`${htmlPrefix}-org`}
- className="width-20"
- value={options.jsonData.organization || ''}
- onChange={onUpdateDatasourceJsonDataOption(this.props, 'organization')}
- />
- </div>
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <SecretFormField
- isConfigured={(secureJsonFields && secureJsonFields.token) as boolean}
- value={secureJsonData.token || ''}
- label="Token"
- aria-label="Token"
- labelWidth={10}
- inputWidth={20}
- onReset={this.onResetToken}
- onChange={onUpdateDatasourceSecureJsonDataOption(this.props, 'token')}
- />
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel className="width-10">Default Bucket</InlineFormLabel>
- <div className="width-10">
- <Input
- className="width-20"
- placeholder="default bucket"
- value={options.jsonData.defaultBucket || ''}
- onChange={onUpdateDatasourceJsonDataOption(this.props, 'defaultBucket')}
- />
- </div>
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel
- className="width-10"
- tooltip="A lower limit for the auto group by time interval. Recommended to be set to write frequency,
- for example 1m if your data is written every minute."
- >
- Min time interval
- </InlineFormLabel>
- <div className="width-10">
- <Input
- className="width-10"
- placeholder="10s"
- value={options.jsonData.timeInterval || ''}
- onChange={onUpdateDatasourceJsonDataOption(this.props, 'timeInterval')}
- />
- </div>
- </div>
- </div>
- </>
- );
- }
- renderInflux1x() {
- const { options } = this.props;
- const { secureJsonFields } = options;
- const secureJsonData = (options.secureJsonData || {}) as InfluxSecureJsonData;
- const { htmlPrefix } = this;
- return (
- <>
- <InfoBox>
- <h5>Database Access</h5>
- <p>
- Setting the database for this datasource does not deny access to other databases. The InfluxDB query syntax
- allows switching the database in the query. For example:
- <code>SHOW MEASUREMENTS ON _internal</code> or
- <code>SELECT * FROM "_internal".."database" LIMIT 10</code>
- <br />
- <br />
- To support data isolation and security, make sure appropriate permissions are configured in InfluxDB.
- </p>
- </InfoBox>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel htmlFor={`${htmlPrefix}-db`} className="width-10">
- Database
- </InlineFormLabel>
- <div className="width-20">
- <Input
- id={`${htmlPrefix}-db`}
- className="width-20"
- value={options.database || ''}
- onChange={onUpdateDatasourceOption(this.props, 'database')}
- />
- </div>
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel htmlFor={`${htmlPrefix}-user`} className="width-10">
- User
- </InlineFormLabel>
- <div className="width-10">
- <Input
- id={`${htmlPrefix}-user`}
- className="width-20"
- value={options.user || ''}
- onChange={onUpdateDatasourceOption(this.props, 'user')}
- />
- </div>
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <SecretFormField
- isConfigured={(secureJsonFields && secureJsonFields.password) as boolean}
- value={secureJsonData.password || ''}
- label="Password"
- aria-label="Password"
- labelWidth={10}
- inputWidth={20}
- onReset={this.onResetPassword}
- onChange={onUpdateDatasourceSecureJsonDataOption(this.props, 'password')}
- />
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel
- htmlFor={`${htmlPrefix}-http-method`}
- className="width-10"
- tooltip="You can use either GET or POST HTTP method to query your InfluxDB database. The POST
- method allows you to perform heavy requests (with a lots of WHERE clause) while the GET method
- will restrict you and return an error if the query is too large."
- >
- HTTP Method
- </InlineFormLabel>
- <Select
- inputId={`${htmlPrefix}-http-method`}
- className="width-10"
- value={httpModes.find((httpMode) => httpMode.value === options.jsonData.httpMode)}
- options={httpModes}
- defaultValue={options.jsonData.httpMode}
- onChange={onUpdateDatasourceJsonDataOptionSelect(this.props, 'httpMode')}
- />
- </div>
- </div>
- <div className="gf-form-inline">
- <div className="gf-form">
- <InlineFormLabel
- className="width-10"
- tooltip="A lower limit for the auto group by time interval. Recommended to be set to write frequency,
- for example 1m if your data is written every minute."
- >
- Min time interval
- </InlineFormLabel>
- <div className="width-10">
- <Input
- className="width-10"
- placeholder="10s"
- value={options.jsonData.timeInterval || ''}
- onChange={onUpdateDatasourceJsonDataOption(this.props, 'timeInterval')}
- />
- </div>
- </div>
- </div>
- </>
- );
- }
- render() {
- const { options, onOptionsChange } = this.props;
- return (
- <>
- <h3 className="page-heading">Query Language</h3>
- <div className="gf-form-group">
- <div className="gf-form-inline">
- <div className="gf-form">
- <Select
- aria-label="Query language"
- className="width-30"
- value={options.jsonData.version === InfluxVersion.Flux ? versions[1] : versions[0]}
- options={versions}
- defaultValue={versions[0]}
- onChange={this.onVersionChanged}
- />
- </div>
- </div>
- </div>
- {options.jsonData.version === InfluxVersion.Flux && (
- <InfoBox>
- <h5>Support for Flux in Grafana is currently in beta</h5>
- <p>
- Please report any issues to: <br />
- <a href="https://github.com/grafana/grafana/issues/new/choose">
- https://github.com/grafana/grafana/issues
- </a>
- </p>
- </InfoBox>
- )}
- {options.access === 'direct' && (
- <Alert title="Deprecation Notice" severity="warning">
- Browser access mode in the InfluxDB datasource is deprecated and will be removed in a future release.
- </Alert>
- )}
- <DataSourceHttpSettings
- showAccessOptions={true}
- dataSourceConfig={options}
- defaultUrl="http://localhost:8086"
- onChange={onOptionsChange}
- />
- <div className="gf-form-group">
- <div>
- <h3 className="page-heading">InfluxDB Details</h3>
- </div>
- {options.jsonData.version === InfluxVersion.Flux ? this.renderInflux2x() : this.renderInflux1x()}
- <div className="gf-form-inline">
- <InlineField
- labelWidth={20}
- label="Max series"
- tooltip="Limit the number of series/tables that Grafana will process. Lower this number to prevent abuse, and increase it if you have lots of small time series and not all are shown. Defaults to 1000."
- >
- <Input
- placeholder="1000"
- type="number"
- className="width-10"
- value={this.state.maxSeries}
- onChange={(event) => {
- // We duplicate this state so that we allow to write freely inside the input. We don't have
- // any influence over saving so this seems to be only way to do this.
- this.setState({ maxSeries: event.currentTarget.value });
- const val = parseInt(event.currentTarget.value, 10);
- updateDatasourcePluginJsonDataOption(this.props, 'maxSeries', Number.isFinite(val) ? val : undefined);
- }}
- />
- </InlineField>
- </div>
- </div>
- </>
- );
- }
- }
- export default ConfigEditor;
|