From 0d3cf9a08bda76462c822bd99cb4ce4473e3402c Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Tue, 6 Feb 2024 10:44:42 -0800 Subject: [PATCH] CloudWatch: Remove core imports from ConfigEditor (#80837) * CloudWatch: Remove core imports from ConfigEditor * test --- .../ConfigEditor/ConfigEditor.test.tsx | 70 ++++++++++++++++--- .../components/ConfigEditor/ConfigEditor.tsx | 53 ++++++++------ 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx index 71ed190ee57..47cf04e059c 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx @@ -1,19 +1,26 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { Provider } from 'react-redux'; import { AwsAuthType } from '@grafana/aws-sdk'; import { PluginContextProvider, PluginMeta, PluginMetaInfo, PluginType } from '@grafana/data'; import { config } from '@grafana/runtime'; -import { configureStore } from 'app/store/configureStore'; -import { CloudWatchSettings, setupMockedDataSource } from '../../__mocks__/CloudWatchDataSource'; +import { + CloudWatchSettings, + setupMockedDataSource, + setupMockedTemplateService, +} from '../../__mocks__/CloudWatchDataSource'; import { CloudWatchDatasource } from '../../datasource'; -import { ConfigEditor, Props } from './ConfigEditor'; +import { + ConfigEditor, + Props, + ARN_DEPRECATION_WARNING_MESSAGE, + CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE, +} from './ConfigEditor'; -const datasource = new CloudWatchDatasource(CloudWatchSettings); +const datasource = new CloudWatchDatasource(CloudWatchSettings, setupMockedTemplateService()); const loadDataSourceMock = jest.fn(); jest.mock('./XrayLinkConfig', () => ({ @@ -85,7 +92,6 @@ const props: Props = { }; const setup = (optionOverrides?: Partial) => { - const store = configureStore(); const newProps = { ...props, options: { @@ -104,9 +110,7 @@ const setup = (optionOverrides?: Partial) => { return render( - - - + ); }; @@ -152,6 +156,45 @@ describe('Render', () => { await waitFor(async () => expect(screen.getByText('Credentials Profile Name')).toBeInTheDocument()); }); + it('should show a warning if `credentials` auth type is used without a profile or database configured', async () => { + setup({ + jsonData: { + authType: AwsAuthType.Credentials, + profile: undefined, + database: undefined, + }, + }); + await waitFor(async () => + expect(screen.getByText(CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE)).toBeInTheDocument() + ); + }); + + it('should not show a warning if `credentials` auth type is used and a profile is configured', async () => { + setup({ + jsonData: { + authType: AwsAuthType.Credentials, + profile: 'profile', + database: undefined, + }, + }); + await waitFor(async () => + expect(screen.queryByText(CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE)).not.toBeInTheDocument() + ); + }); + + it('should not show a warning if `credentials` auth type is used and a database is configured', async () => { + setup({ + jsonData: { + authType: AwsAuthType.Credentials, + profile: undefined, + database: 'database', + }, + }); + await waitFor(async () => + expect(screen.queryByText(CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE)).not.toBeInTheDocument() + ); + }); + it('should show access key and secret access key fields when the datasource has not been configured before', async () => { setup({ jsonData: { @@ -173,6 +216,15 @@ describe('Render', () => { await waitFor(async () => expect(screen.getByText('Assume Role ARN')).toBeInTheDocument()); }); + it('should show a deprecation warning if `arn` auth type is used', async () => { + setup({ + jsonData: { + authType: AwsAuthType.ARN, + }, + }); + await waitFor(async () => expect(screen.getByText(ARN_DEPRECATION_WARNING_MESSAGE)).toBeInTheDocument()); + }); + it('should display log group selector field', async () => { setup(); await waitFor(async () => expect(screen.getByText('Select log groups')).toBeInTheDocument()); diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx index fc75a08ab0f..c9965ee2022 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx @@ -12,10 +12,7 @@ import { } from '@grafana/data'; import { ConfigSection } from '@grafana/experimental'; import { getAppEvents, usePluginInteractionReporter, getDataSourceSrv, config } from '@grafana/runtime'; -import { Input, InlineField, FieldProps, SecureSocksProxySettings, Field, Divider } from '@grafana/ui'; -import { notifyApp } from 'app/core/actions'; -import { createWarningNotification } from 'app/core/copy/appNotification'; -import { store } from 'app/store/store'; +import { Alert, Input, InlineField, FieldProps, SecureSocksProxySettings, Field, Divider } from '@grafana/ui'; import { CloudWatchDatasource } from '../../datasource'; import { SelectableResourceValue } from '../../resources/types'; @@ -29,11 +26,17 @@ export type Props = DataSourcePluginOptionsEditorProps & { error?: string | null }; +export const ARN_DEPRECATION_WARNING_MESSAGE = + 'Since grafana 7.3 authentication type "arn" is deprecated, falling back to default SDK provider'; +export const CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE = + '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'; + export const ConfigEditor = (props: Props) => { const { options, onOptionsChange } = props; const { defaultLogGroups, logsTimeout, defaultRegion, logGroups } = options.jsonData; const datasource = useDatasource(props); - useAuthenticationWarning(options.jsonData); const logsTimeoutError = useTimoutValidation(logsTimeout); const saved = useDataSourceSavedState(props); const [logGroupFieldState, setLogGroupFieldState] = useState({ @@ -68,8 +71,25 @@ export const ConfigEditor = (props: Props) => { } }, [datasource, externalId]); + const [warning, setWarning] = useState(null); + const dismissWarning = () => { + setWarning(null); + }; + useEffect(() => { + if (options.jsonData.authType === 'arn') { + setWarning(ARN_DEPRECATION_WARNING_MESSAGE); + } else if (options.jsonData.authType === 'credentials' && !options.jsonData.profile && !options.jsonData.database) { + setWarning(CREDENTIALS_AUTHENTICATION_WARNING_MESSAGE); + } + }, [options.jsonData.authType, options.jsonData.database, options.jsonData.profile]); + return newFormStylingEnabled ? (
+ {warning && ( + + {warning} + + )} {
) : ( <> + {warning && ( + + {warning} + + )} { ); }; -function useAuthenticationWarning(jsonData: CloudWatchJsonData) { - const addWarning = (message: string) => { - store.dispatch(notifyApp(createWarningNotification('CloudWatch Authentication', message))); - }; - - useEffect(() => { - if (jsonData.authType === 'arn') { - addWarning('Since grafana 7.3 authentication type "arn" is deprecated, falling back to default SDK provider'); - } else if (jsonData.authType === 'credentials' && !jsonData.profile && !jsonData.database) { - 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' - ); - } - }, [jsonData.authType, jsonData.database, jsonData.profile]); -} - function useDatasource(props: Props) { const [datasource, setDatasource] = useState();