123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import React from 'react';
- import { gte, lt, valid } from 'semver';
- import { DataSourceSettings, SelectableValue } from '@grafana/data';
- import { FieldSet, InlineField, Input, Select, InlineSwitch } from '@grafana/ui';
- import { ElasticsearchOptions, Interval } from '../types';
- import { isTruthy } from './utils';
- const indexPatternTypes: Array<SelectableValue<'none' | Interval>> = [
- { label: 'No pattern', value: 'none' },
- { label: 'Hourly', value: 'Hourly', example: '[logstash-]YYYY.MM.DD.HH' },
- { label: 'Daily', value: 'Daily', example: '[logstash-]YYYY.MM.DD' },
- { label: 'Weekly', value: 'Weekly', example: '[logstash-]GGGG.WW' },
- { label: 'Monthly', value: 'Monthly', example: '[logstash-]YYYY.MM' },
- { label: 'Yearly', value: 'Yearly', example: '[logstash-]YYYY' },
- ];
- const esVersions: SelectableValue[] = [
- { label: '7.10+', value: '7.10.0' },
- {
- label: '8.0+',
- value: '8.0.0',
- description: 'support for Elasticsearch 8 is currently experimental',
- },
- ];
- type Props = {
- value: DataSourceSettings<ElasticsearchOptions>;
- onChange: (value: DataSourceSettings<ElasticsearchOptions>) => void;
- };
- export const ElasticDetails = ({ value, onChange }: Props) => {
- const currentVersion = esVersions.find((version) => version.value === value.jsonData.esVersion);
- const customOption =
- !currentVersion && valid(value.jsonData.esVersion)
- ? {
- label: value.jsonData.esVersion,
- value: value.jsonData.esVersion,
- }
- : undefined;
- return (
- <>
- <FieldSet label="Elasticsearch details">
- <InlineField label="Index name" labelWidth={26}>
- <Input
- id="es_config_indexName"
- value={value.database || ''}
- onChange={changeHandler('database', value, onChange)}
- width={24}
- placeholder="es-index-name"
- required
- />
- </InlineField>
- <InlineField label="Pattern" labelWidth={26}>
- <Select
- inputId="es_config_indexPattern"
- value={indexPatternTypes.find(
- (pattern) => pattern.value === (value.jsonData.interval === undefined ? 'none' : value.jsonData.interval)
- )}
- options={indexPatternTypes}
- onChange={intervalHandler(value, onChange)}
- width={24}
- />
- </InlineField>
- <InlineField label="Time field name" labelWidth={26}>
- <Input
- id="es_config_timeField"
- value={value.jsonData.timeField || ''}
- onChange={jsonDataChangeHandler('timeField', value, onChange)}
- width={24}
- placeholder="@timestamp"
- required
- />
- </InlineField>
- <InlineField label="ElasticSearch version" labelWidth={26}>
- <Select
- inputId="es_config_version"
- options={[customOption, ...esVersions].filter(isTruthy)}
- onChange={(option) => {
- const maxConcurrentShardRequests = getMaxConcurrenShardRequestOrDefault(
- value.jsonData.maxConcurrentShardRequests,
- option.value!
- );
- onChange({
- ...value,
- jsonData: {
- ...value.jsonData,
- esVersion: option.value!,
- maxConcurrentShardRequests,
- },
- });
- }}
- value={currentVersion || customOption}
- width={24}
- />
- </InlineField>
- {gte(value.jsonData.esVersion, '5.6.0') && (
- <InlineField label="Max concurrent Shard Requests" labelWidth={26}>
- <Input
- id="es_config_shardRequests"
- value={value.jsonData.maxConcurrentShardRequests || ''}
- onChange={jsonDataChangeHandler('maxConcurrentShardRequests', value, onChange)}
- width={24}
- />
- </InlineField>
- )}
- <InlineField
- label="Min time interval"
- labelWidth={26}
- tooltip={
- <>
- A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '}
- <code>1m</code> if your data is written every minute.
- </>
- }
- error="Value is not valid, you can use number with time unit specifier: y, M, w, d, h, m, s"
- invalid={!!value.jsonData.timeInterval && !/^\d+(ms|[Mwdhmsy])$/.test(value.jsonData.timeInterval)}
- >
- <Input
- id="es_config_minTimeInterval"
- value={value.jsonData.timeInterval || ''}
- onChange={jsonDataChangeHandler('timeInterval', value, onChange)}
- width={24}
- placeholder="10s"
- />
- </InlineField>
- <InlineField label="X-Pack enabled" labelWidth={26}>
- <InlineSwitch
- id="es_config_xpackEnabled"
- checked={value.jsonData.xpack || false}
- onChange={jsonDataSwitchChangeHandler('xpack', value, onChange)}
- />
- </InlineField>
- {gte(value.jsonData.esVersion, '6.6.0') && value.jsonData.xpack && (
- <InlineField label="Include Frozen Indices" labelWidth={26}>
- <InlineSwitch
- id="es_config_frozenIndices"
- checked={value.jsonData.includeFrozen ?? false}
- onChange={jsonDataSwitchChangeHandler('includeFrozen', value, onChange)}
- />
- </InlineField>
- )}
- </FieldSet>
- </>
- );
- };
- // TODO: Use change handlers from @grafana/data
- const changeHandler =
- (key: keyof DataSourceSettings<ElasticsearchOptions>, value: Props['value'], onChange: Props['onChange']) =>
- (event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>) => {
- onChange({
- ...value,
- [key]: event.currentTarget.value,
- });
- };
- // TODO: Use change handlers from @grafana/data
- const jsonDataChangeHandler =
- (key: keyof ElasticsearchOptions, value: Props['value'], onChange: Props['onChange']) =>
- (event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>) => {
- onChange({
- ...value,
- jsonData: {
- ...value.jsonData,
- [key]: event.currentTarget.value,
- },
- });
- };
- const jsonDataSwitchChangeHandler =
- (key: keyof ElasticsearchOptions, value: Props['value'], onChange: Props['onChange']) =>
- (event: React.SyntheticEvent<HTMLInputElement>) => {
- onChange({
- ...value,
- jsonData: {
- ...value.jsonData,
- [key]: event.currentTarget.checked,
- },
- });
- };
- const intervalHandler =
- (value: Props['value'], onChange: Props['onChange']) => (option: SelectableValue<Interval | 'none'>) => {
- const { database } = value;
- // If option value is undefined it will send its label instead so we have to convert made up value to undefined here.
- const newInterval = option.value === 'none' ? undefined : option.value;
- if (!database || database.length === 0 || database.startsWith('[logstash-]')) {
- let newDatabase = '';
- if (newInterval !== undefined) {
- const pattern = indexPatternTypes.find((pattern) => pattern.value === newInterval);
- if (pattern) {
- newDatabase = pattern.example ?? '';
- }
- }
- onChange({
- ...value,
- database: newDatabase,
- jsonData: {
- ...value.jsonData,
- interval: newInterval,
- },
- });
- } else {
- onChange({
- ...value,
- jsonData: {
- ...value.jsonData,
- interval: newInterval,
- },
- });
- }
- };
- function getMaxConcurrenShardRequestOrDefault(maxConcurrentShardRequests: number | undefined, version: string): number {
- if (maxConcurrentShardRequests === 5 && lt(version, '7.0.0')) {
- return 256;
- }
- if (maxConcurrentShardRequests === 256 && gte(version, '7.0.0')) {
- return 5;
- }
- return maxConcurrentShardRequests || defaultMaxConcurrentShardRequests(version);
- }
- export function defaultMaxConcurrentShardRequests(version: string) {
- return gte(version, '7.0.0') ? 5 : 256;
- }
|