diff --git a/package.json b/package.json index c034db77079..c5b75a0a447 100644 --- a/package.json +++ b/package.json @@ -200,6 +200,7 @@ }, "dependencies": { "@emotion/core": "10.0.27", + "@grafana/aws-sdk": "0.0.2", "@grafana/slate-react": "0.22.9-grafana", "@popperjs/core": "2.5.4", "@reduxjs/toolkit": "1.5.0", diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx index 2320f3c604d..8a2752bace5 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import ConfigEditor, { Props } from './ConfigEditor'; +import { AwsAuthType } from '@grafana/aws-sdk'; +import { ConfigEditor, Props } from './ConfigEditor'; jest.mock('app/features/plugins/datasource_srv', () => ({ getDatasourceSrv: () => ({ @@ -46,7 +47,7 @@ const setup = (propOverrides?: object) => { externalId: '', database: '', customMetricsNamespaces: '', - authType: 'keys', + authType: AwsAuthType.Keys, defaultRegion: 'us-east-2', timeField: '@timestamp', }, diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx index 3df8e6e6e17..8695896fc05 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx @@ -1,339 +1,63 @@ -import React, { PureComponent } from 'react'; -import { InlineFormLabel, LegacyForms, Button } from '@grafana/ui'; -const { Select, Input } = LegacyForms; -import { - AppEvents, - SelectableValue, - DataSourcePluginOptionsEditorProps, - onUpdateDatasourceJsonDataOptionSelect, - onUpdateDatasourceResetOption, - onUpdateDatasourceJsonDataOption, - onUpdateDatasourceSecureJsonDataOption, -} from '@grafana/data'; -import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; -import { CloudWatchDatasource } from '../datasource'; -import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types'; -import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise'; -import { appEvents } from 'app/core/core'; +import React, { FC, useEffect, useState } from 'react'; +import { Input, InlineField } from '@grafana/ui'; +import { DataSourcePluginOptionsEditorProps, onUpdateDatasourceJsonDataOption } from '@grafana/data'; +import { ConnectionConfig } from '@grafana/aws-sdk'; -const authProviderOptions = [ - { label: 'AWS SDK Default', value: 'default' }, - { label: 'Access & secret key', value: 'keys' }, - { label: 'Credentials file', value: 'credentials' }, -] as SelectableValue[]; +import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; +import { store } from 'app/store/store'; +import { notifyApp } from 'app/core/actions'; +import { createWarningNotification } from 'app/core/copy/appNotification'; + +import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types'; +import { CloudWatchDatasource } from '../datasource'; export type Props = DataSourcePluginOptionsEditorProps; -export interface State { - regions: SelectableValue[]; -} +export const ConfigEditor: FC = (props: Props) => { + const [datasource, setDatasource] = useState(); -export class ConfigEditor extends PureComponent { - constructor(props: Props) { - super(props); + const addWarning = (message: string) => { + store.dispatch(notifyApp(createWarningNotification('CloudWatch Authentication', message))); + }; - this.state = { - regions: [], - }; - } + useEffect(() => { + getDatasourceSrv() + .loadDatasource(props.options.name) + .then((datasource: CloudWatchDatasource) => setDatasource(datasource)); - loadRegionsPromise: CancelablePromise | null = null; - - componentDidMount() { - this.loadRegionsPromise = makePromiseCancelable(this.loadRegions()); - this.loadRegionsPromise.promise.catch(({ isCanceled }) => { - if (isCanceled) { - console.warn('Cloud Watch ConfigEditor has unmounted, initialization was canceled'); - } - }); - - if (this.props.options.jsonData.authType === 'arn') { - appEvents.emit(AppEvents.alertWarning, [ - 'Since grafana 7.3 authentication type "arn" is deprecated, falling back to default SDK provider', - ]); + if (props.options.jsonData.authType === 'arn') { + addWarning('Since grafana 7.3 authentication type "arn" is deprecated, falling back to default SDK provider'); } else if ( - this.props.options.jsonData.authType === 'credentials' && - !this.props.options.jsonData.profile && - !this.props.options.jsonData.database + props.options.jsonData.authType === 'credentials' && + !props.options.jsonData.profile && + !props.options.jsonData.database ) { - appEvents.emit(AppEvents.alertWarning, [ + addWarning( 'As of grafana 7.3 authentication type "credentials" should be used only for shared file credentials. \ - If you don\'t have a credentials file, switch to the default SDK provider for extracting credentials \ - from environment variables or IAM roles', - ]); - } - } - - componentWillUnmount() { - if (this.loadRegionsPromise) { - this.loadRegionsPromise.cancel(); - } - } - - async loadRegions() { - await getDatasourceSrv() - .loadDatasource(this.props.options.name) - .then((ds: CloudWatchDatasource) => ds.getRegions()) - .then( - (regions: any) => { - this.setState({ - regions: regions.map((region: any) => { - return { - value: region.value, - label: region.text, - }; - }), - }); - }, - (err: any) => { - const regions = [ - 'af-south-1', - 'ap-east-1', - 'ap-northeast-1', - 'ap-northeast-2', - 'ap-northeast-3', - 'ap-south-1', - 'ap-southeast-1', - 'ap-southeast-2', - 'ca-central-1', - 'cn-north-1', - 'cn-northwest-1', - 'eu-central-1', - 'eu-north-1', - 'eu-south-1', - 'eu-west-1', - 'eu-west-2', - 'eu-west-3', - 'me-south-1', - 'sa-east-1', - 'us-east-1', - 'us-east-2', - 'us-gov-east-1', - 'us-gov-west-1', - 'us-iso-east-1', - 'us-isob-east-1', - 'us-west-1', - 'us-west-2', - ]; - - this.setState({ - regions: regions.map((region: string) => ({ - value: region, - label: region, - })), - }); - - // expected to fail when creating new datasource - // console.error('failed to get latest regions', err); - } + If you don\'t have a credentials file, switch to the default SDK provider for extracting credentials \ + from environment variables or IAM roles' ); - } - - render() { - const { regions } = this.state; - const { options } = this.props; - const secureJsonData = (options.secureJsonData || {}) as CloudWatchSecureJsonData; - let profile = options.jsonData.profile; - if (profile === undefined) { - profile = options.database; } + }, []); - return ( - <> -

CloudWatch Details

-
-
-
- - Authentication Provider - - -
-
-
- )} - {options.jsonData.authType === 'keys' && ( -
- {options.secureJsonFields?.accessKey ? ( -
-
- Access Key ID - -
-
-
- -
-
-
- ) : ( -
-
- Access Key ID -
- -
-
-
- )} - {options.secureJsonFields?.secretKey ? ( -
-
- Secret Access Key - -
-
-
- -
-
-
- ) : ( -
-
- Secret Access Key -
- -
-
-
- )} -
- )} -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- - - ); - } -} - -export default ConfigEditor; + return ( + <> + datasource!.getRegions().then((r) => r.filter((r) => r.value !== 'default').map((v) => v.value))) + } + > + + + + + + ); +}; diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx index c5b68c737e3..91c37df5467 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx @@ -5,12 +5,14 @@ import React, { memo } from 'react'; import { AbsoluteTimeRange, QueryEditorProps } from '@grafana/data'; import { InlineFormLabel } from '@grafana/ui'; import { CloudWatchDatasource } from '../datasource'; -import { CloudWatchLogsQuery, CloudWatchQuery } from '../types'; +import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../types'; import { CloudWatchLogsQueryField } from './LogsQueryField'; import CloudWatchLink from './CloudWatchLink'; import { css } from 'emotion'; -type Props = QueryEditorProps & { allowCustomValue?: boolean }; +type Props = QueryEditorProps & { + allowCustomValue?: boolean; +}; const labelClass = css` margin-left: 3px; diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx index 714156c872c..4badb8f16df 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx @@ -22,7 +22,7 @@ import syntax from '../syntax'; // Types import { AbsoluteTimeRange, AppEvents, ExploreQueryFieldProps, SelectableValue } from '@grafana/data'; -import { CloudWatchLogsQuery, CloudWatchQuery } from '../types'; +import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../types'; import { CloudWatchDatasource } from '../datasource'; import { LanguageMap, languages as prismLanguages } from 'prismjs'; import { CloudWatchLanguageProvider } from '../language_provider'; @@ -32,7 +32,8 @@ import { appEvents } from 'app/core/core'; import { InputActionMeta } from '@grafana/ui/src/components/Select/types'; import { getStatsGroups } from '../utils/query/getStatsGroups'; -export interface CloudWatchLogsQueryFieldProps extends ExploreQueryFieldProps { +export interface CloudWatchLogsQueryFieldProps + extends ExploreQueryFieldProps { absoluteRange: AbsoluteTimeRange; onLabelsRefresh?: () => void; ExtraFieldElement?: ReactNode; diff --git a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.test.tsx index 7dfd6b55f6e..7cf91a3d7dd 100644 --- a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.test.tsx @@ -7,11 +7,12 @@ import { TemplateSrv } from 'app/features/templating/template_srv'; import { MetricsQueryEditor, normalizeQuery, Props } from './MetricsQueryEditor'; import { CloudWatchDatasource } from '../datasource'; import { CustomVariableModel, initialVariableModelState } from '../../../../features/variables/types'; +import { CloudWatchJsonData } from '../types'; const setup = () => { const instanceSettings = { jsonData: { defaultRegion: 'us-east-1' }, - } as DataSourceInstanceSettings; + } as DataSourceInstanceSettings; const templateSrv = new TemplateSrv(); const variable: CustomVariableModel = { diff --git a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.tsx index 0a835e98bc1..857e14cb142 100644 --- a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryEditor.tsx @@ -4,11 +4,11 @@ import isEmpty from 'lodash/isEmpty'; import { ExploreQueryFieldProps } from '@grafana/data'; import { LegacyForms, ValidationEvents, EventsWithValidation, Icon } from '@grafana/ui'; const { Input, Switch } = LegacyForms; -import { CloudWatchQuery, CloudWatchMetricsQuery } from '../types'; +import { CloudWatchQuery, CloudWatchMetricsQuery, CloudWatchJsonData } from '../types'; import { CloudWatchDatasource } from '../datasource'; import { QueryField, Alias, MetricsQueryFieldsEditor } from './'; -export type Props = ExploreQueryFieldProps; +export type Props = ExploreQueryFieldProps; interface State { showMeta: boolean; diff --git a/public/app/plugins/datasource/cloudwatch/components/PanelQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/PanelQueryEditor.tsx index d66fbefdec3..295b4c3ceb4 100644 --- a/public/app/plugins/datasource/cloudwatch/components/PanelQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/PanelQueryEditor.tsx @@ -2,13 +2,13 @@ import React, { PureComponent } from 'react'; import pick from 'lodash/pick'; import { ExploreQueryFieldProps, ExploreMode } from '@grafana/data'; import { Segment } from '@grafana/ui'; -import { CloudWatchQuery } from '../types'; +import { CloudWatchJsonData, CloudWatchQuery } from '../types'; import { CloudWatchDatasource } from '../datasource'; import { QueryInlineField } from './'; import { MetricsQueryEditor } from './MetricsQueryEditor'; import LogsQueryEditor from './LogsQueryEditor'; -export type Props = ExploreQueryFieldProps; +export type Props = ExploreQueryFieldProps; const apiModes = { Metrics: { label: 'CloudWatch Metrics', value: 'Metrics' }, diff --git a/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap b/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap index 47c9f1e9c1a..201c00654e9 100644 --- a/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap +++ b/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap @@ -2,1265 +2,315 @@ exports[`Render should disable access key id field 1`] = ` -

- CloudWatch Details -

-
-
-
- - Authentication Provider - - -
-
-
-
-
- - Secret Access Key - -
- -
-
-
- -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- + + +
`; exports[`Render should render component 1`] = ` -

- CloudWatch Details -

-
-
-
- - Authentication Provider - - -
-
-
-
-
- - Secret Access Key - -
- -
-
-
- -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- + + +
`; exports[`Render should show access key and secret access key fields 1`] = ` -

- CloudWatch Details -

-
-
-
- - Authentication Provider - - -
-
-
-
-
- - Secret Access Key - -
- -
-
-
- -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- + + +
`; exports[`Render should show arn role field 1`] = ` -

- CloudWatch Details -

-
-
-
- - Authentication Provider - - -
-
-
-
-
- - Secret Access Key - -
- -
-
-
- -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- + + +
`; exports[`Render should show credentials profile name field 1`] = ` -

- CloudWatch Details -

-
-
-
- - Authentication Provider - - -
-
-
-
-
- - Secret Access Key - -
- -
-
-
- -
-
- - Assume Role ARN - -
- -
-
-
-
- - External ID - -
- -
-
-
-
-
-
- - Default Region - - -
-
-
-
- - Endpoint - -
- -
-
-
- + + +
`; diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts index 0df067f7c33..afc8ba357be 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts @@ -11,7 +11,13 @@ import { import * as redux from 'app/store/store'; import { CloudWatchDatasource, MAX_ATTEMPTS } from '../datasource'; import { TemplateSrv } from 'app/features/templating/template_srv'; -import { CloudWatchLogsQuery, CloudWatchLogsQueryStatus, CloudWatchMetricsQuery, LogAction } from '../types'; +import { + CloudWatchJsonData, + CloudWatchLogsQuery, + CloudWatchLogsQueryStatus, + CloudWatchMetricsQuery, + LogAction, +} from '../types'; import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__ import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { convertToStoreState } from '../../../../../test/helpers/convertToStoreState'; @@ -46,7 +52,7 @@ function getTestContext({ response = {}, throws = false, templateSrv = new Templ const instanceSettings = { jsonData: { defaultRegion: 'us-east-1' }, name: 'TestDatasource', - } as DataSourceInstanceSettings; + } as DataSourceInstanceSettings; const timeSrv = { time: { from: '2016-12-31 15:00:00Z', to: '2016-12-31 16:00:00Z' }, diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index 0f3e3a7b2f9..136a3999bbc 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -1,4 +1,5 @@ -import { DataQuery, SelectableValue, DataSourceJsonData } from '@grafana/data'; +import { DataQuery, SelectableValue } from '@grafana/data'; +import { AwsAuthDataSourceSecureJsonData, AwsAuthDataSourceJsonData } from '@grafana/aws-sdk'; export interface CloudWatchMetricsQuery extends DataQuery { queryMode?: 'Metrics'; @@ -56,16 +57,14 @@ export interface AnnotationQuery extends CloudWatchMetricsQuery { export type SelectableStrings = Array>; -export interface CloudWatchJsonData extends DataSourceJsonData { +export interface CloudWatchJsonData extends AwsAuthDataSourceJsonData { timeField?: string; - assumeRoleArn?: string; - externalId?: string; database?: string; customMetricsNamespaces?: string; endpoint?: string; } -export interface CloudWatchSecureJsonData { +export interface CloudWatchSecureJsonData extends AwsAuthDataSourceSecureJsonData { accessKey: string; secretKey: string; } diff --git a/yarn.lock b/yarn.lock index 864be15806a..d3b59f3e51b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3431,6 +3431,40 @@ source-map "~0.6.1" typescript "~3.9.7" +"@grafana/aws-sdk@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@grafana/aws-sdk/-/aws-sdk-0.0.2.tgz#dcaa8672158ce12d5e83b10c6d801b718e03e66a" + integrity sha512-nKkFoNJ76NgGolJArdro39Ho7YA769BO3nq8/NeUHai9MeEVmPviuqC5pnswb08Q4QTEKESi0Zo3x8GvfF6cZg== + dependencies: + "@grafana/data" "7.5.0-beta.1" + "@grafana/runtime" "7.5.0-beta.1" + "@grafana/ui" "7.5.0-beta.1" + +"@grafana/data@7.5.0-beta.1": + version "7.5.0-beta.1" + resolved "https://registry.yarnpkg.com/@grafana/data/-/data-7.5.0-beta.1.tgz#4c6dcd07daee713a06e46d230b9c09877fd5f732" + integrity sha512-hYU3XWVp2rsLfSZVwYFM9wL0e+i1ktlNPzELGL66EcSV+ak41orlcjpwEpke4O7Vtht6t5qSoTycYlmj6+aZEw== + dependencies: + "@braintree/sanitize-url" "4.0.0" + "@types/d3-interpolate" "^1.3.1" + apache-arrow "0.16.0" + eventemitter3 "4.0.7" + lodash "4.17.21" + marked "2.0.1" + rxjs "6.6.3" + xss "1.0.6" + +"@grafana/e2e-selectors@7.5.0-beta.1": + version "7.5.0-beta.1" + resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-7.5.0-beta.1.tgz#063734af7a112033d2e78219969619194fca3526" + integrity sha512-zn23xTrkNtCRSI4wg23CatAq2t4R2JWtqwEKvRfP3qWuJTwql2vu1pLJufJUcTkJtn3ImmwSMGvxZ/wI9SPbqQ== + dependencies: + "@grafana/tsconfig" "^1.0.0-rc1" + commander "5.0.0" + execa "4.0.0" + typescript "4.1.2" + yaml "^1.8.3" + "@grafana/eslint-config@2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@grafana/eslint-config/-/eslint-config-2.2.1.tgz#a7c6dd57ae0011fb2535a688e1e17969e621d21a" @@ -3447,6 +3481,16 @@ prettier "2.2.1" typescript "4.1.3" +"@grafana/runtime@7.5.0-beta.1": + version "7.5.0-beta.1" + resolved "https://registry.yarnpkg.com/@grafana/runtime/-/runtime-7.5.0-beta.1.tgz#f0e29a2493d440b7dd6d09def9727c2ce41cb743" + integrity sha512-Cn62/9N1g3TX9vaoGgpD0/bWG2U1nsAoHboLbQnKkztH8tmLoChHqUaZ/5Lsu3s9K5mxI3YA+4PrAxr4NlUPjw== + dependencies: + "@grafana/data" "7.5.0-beta.1" + "@grafana/ui" "7.5.0-beta.1" + systemjs "0.20.19" + systemjs-plugin-css "0.1.37" + "@grafana/slate-react@0.22.9-grafana": version "0.22.9-grafana" resolved "https://registry.yarnpkg.com/@grafana/slate-react/-/slate-react-0.22.9-grafana.tgz#07f35f0ffc018f616b9f82fa6e5ba65fae75c6a0" @@ -3474,6 +3518,64 @@ resolved "https://registry.yarnpkg.com/@grafana/tsconfig/-/tsconfig-1.0.0-rc1.tgz#d07ea16755a50cae21000113f30546b61647a200" integrity sha512-nucKPGyzlSKYSiJk5RA8GzMdVWhdYNdF+Hh65AXxjD9PlY69JKr5wANj8bVdQboag6dgg0BFKqgKPyY+YtV4Iw== +"@grafana/ui@7.5.0-beta.1": + version "7.5.0-beta.1" + resolved "https://registry.yarnpkg.com/@grafana/ui/-/ui-7.5.0-beta.1.tgz#0de30ebe9e51df956fa20f1d0a396d286b3f8c5f" + integrity sha512-/+VeGVRjRtd9bOwhzdwWqk8IVrENlGoMWCuRaNQU0+q2tdPQurXYbE3rmxKVtKysPTYNzbhS5Ox5QzYkPkoriA== + dependencies: + "@emotion/core" "10.0.27" + "@grafana/data" "7.5.0-beta.1" + "@grafana/e2e-selectors" "7.5.0-beta.1" + "@grafana/slate-react" "0.22.9-grafana" + "@grafana/tsconfig" "^1.0.0-rc1" + "@iconscout/react-unicons" "1.1.4" + "@popperjs/core" "2.5.4" + "@sentry/browser" "5.25.0" + "@testing-library/jest-dom" "5.11.9" + "@torkelo/react-select" "3.0.8" + "@types/hoist-non-react-statics" "3.3.1" + "@types/react-beautiful-dnd" "12.1.2" + "@types/react-color" "3.0.1" + "@types/react-select" "3.0.8" + "@types/react-table" "7.0.12" + "@types/slate" "0.47.1" + "@types/slate-react" "0.22.5" + "@visx/event" "1.3.0" + "@visx/gradient" "1.0.0" + "@visx/scale" "1.4.0" + "@visx/shape" "1.4.0" + "@visx/tooltip" "1.3.0" + classnames "2.2.6" + d3 "5.15.0" + emotion "10.0.27" + hoist-non-react-statics "3.3.2" + immutable "3.8.2" + jquery "3.5.1" + lodash "4.17.21" + moment "2.24.0" + monaco-editor "0.20.0" + papaparse "5.3.0" + rc-cascader "1.0.1" + rc-drawer "3.1.3" + rc-slider "9.6.4" + rc-time-picker "^3.7.3" + react "17.0.1" + react-beautiful-dnd "13.0.0" + react-calendar "2.19.2" + react-color "2.18.0" + react-custom-scrollbars "4.2.1" + react-dom "17.0.1" + react-highlight-words "0.16.0" + react-hook-form "5.1.3" + react-monaco-editor "0.36.0" + react-popper "2.2.4" + react-storybook-addon-props-combinations "1.1.0" + react-table "7.0.0" + react-transition-group "4.4.1" + slate "0.47.8" + tinycolor2 "1.4.1" + uplot "1.6.4" + "@icons/material@^0.2.4": version "0.2.4" resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"