ConfigEditor.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import React, { FC, useEffect, useState } from 'react';
  2. import { useDebounce } from 'react-use';
  3. import { ConnectionConfig } from '@grafana/aws-sdk';
  4. import {
  5. rangeUtil,
  6. DataSourcePluginOptionsEditorProps,
  7. onUpdateDatasourceJsonDataOption,
  8. updateDatasourcePluginJsonDataOption,
  9. } from '@grafana/data';
  10. import { Input, InlineField } from '@grafana/ui';
  11. import { notifyApp } from 'app/core/actions';
  12. import { createWarningNotification } from 'app/core/copy/appNotification';
  13. import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
  14. import { store } from 'app/store/store';
  15. import { CloudWatchDatasource } from '../datasource';
  16. import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types';
  17. import { XrayLinkConfig } from './XrayLinkConfig';
  18. export type Props = DataSourcePluginOptionsEditorProps<CloudWatchJsonData, CloudWatchSecureJsonData>;
  19. export const ConfigEditor: FC<Props> = (props: Props) => {
  20. const { options } = props;
  21. const datasource = useDatasource(options.name);
  22. useAuthenticationWarning(options.jsonData);
  23. const logsTimeoutError = useTimoutValidation(props.options.jsonData.logsTimeout);
  24. return (
  25. <>
  26. <ConnectionConfig
  27. {...props}
  28. loadRegions={
  29. datasource &&
  30. (() => datasource!.getRegions().then((r) => r.filter((r) => r.value !== 'default').map((v) => v.value)))
  31. }
  32. >
  33. <InlineField label="Namespaces of Custom Metrics" labelWidth={28} tooltip="Namespaces of Custom Metrics.">
  34. <Input
  35. width={60}
  36. placeholder="Namespace1,Namespace2"
  37. value={options.jsonData.customMetricsNamespaces || ''}
  38. onChange={onUpdateDatasourceJsonDataOption(props, 'customMetricsNamespaces')}
  39. />
  40. </InlineField>
  41. </ConnectionConfig>
  42. <h3 className="page-heading">CloudWatch Logs</h3>
  43. <div className="gf-form-group">
  44. <InlineField
  45. label="Timeout"
  46. labelWidth={28}
  47. tooltip='Custom timout for CloudWatch Logs insights queries which have max concurrency limits. Default is 15 minutes. Must be a valid duration string, such as "15m" "30s" "2000ms" etc.'
  48. invalid={Boolean(logsTimeoutError)}
  49. >
  50. <Input
  51. width={60}
  52. placeholder="15m"
  53. value={options.jsonData.logsTimeout || ''}
  54. onChange={onUpdateDatasourceJsonDataOption(props, 'logsTimeout')}
  55. title={'The timeout must be a valid duration string, such as "15m" "30s" "2000ms" etc.'}
  56. />
  57. </InlineField>
  58. </div>
  59. <XrayLinkConfig
  60. onChange={(uid) => updateDatasourcePluginJsonDataOption(props, 'tracingDatasourceUid', uid)}
  61. datasourceUid={options.jsonData.tracingDatasourceUid}
  62. />
  63. </>
  64. );
  65. };
  66. function useAuthenticationWarning(jsonData: CloudWatchJsonData) {
  67. const addWarning = (message: string) => {
  68. store.dispatch(notifyApp(createWarningNotification('CloudWatch Authentication', message)));
  69. };
  70. useEffect(() => {
  71. if (jsonData.authType === 'arn') {
  72. addWarning('Since grafana 7.3 authentication type "arn" is deprecated, falling back to default SDK provider');
  73. } else if (jsonData.authType === 'credentials' && !jsonData.profile && !jsonData.database) {
  74. addWarning(
  75. 'As of grafana 7.3 authentication type "credentials" should be used only for shared file credentials. \
  76. If you don\'t have a credentials file, switch to the default SDK provider for extracting credentials \
  77. from environment variables or IAM roles'
  78. );
  79. }
  80. }, [jsonData.authType, jsonData.database, jsonData.profile]);
  81. }
  82. function useDatasource(datasourceName: string) {
  83. const [datasource, setDatasource] = useState<CloudWatchDatasource>();
  84. useEffect(() => {
  85. getDatasourceSrv()
  86. .loadDatasource(datasourceName)
  87. .then((datasource) => {
  88. // It's really difficult to type .loadDatasource() because it's inherently untyped as it involves two JSON.parse()'s
  89. // So a "as" type assertion here is a necessary evil.
  90. setDatasource(datasource as CloudWatchDatasource);
  91. });
  92. }, [datasourceName]);
  93. return datasource;
  94. }
  95. function useTimoutValidation(value: string | undefined) {
  96. const [err, setErr] = useState<undefined | string>(undefined);
  97. useDebounce(
  98. () => {
  99. if (value) {
  100. try {
  101. rangeUtil.describeInterval(value);
  102. setErr(undefined);
  103. } catch (e) {
  104. setErr(e.toString());
  105. }
  106. } else {
  107. setErr(undefined);
  108. }
  109. },
  110. 350,
  111. [value]
  112. );
  113. return err;
  114. }