diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.test.tsx index cdf590e3274..688a560d000 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.test.tsx @@ -1,46 +1,63 @@ +import { render, screen } from '@testing-library/react'; import React from 'react'; -import { shallow } from 'enzyme'; -import ConfigEditor, { Props } from './ConfigEditor'; +import ConfigEditor from './ConfigEditor'; -const setup = () => { - const props: Props = { - options: { - id: 21, - uid: 'y', - orgId: 1, - name: 'Azure Monitor-10-10', - type: 'grafana-azure-monitor-datasource', - typeLogoUrl: '', - typeName: 'Azure', - access: 'proxy', - url: '', - password: '', - user: '', - database: '', - basicAuth: false, - basicAuthUser: '', - basicAuthPassword: '', - withCredentials: false, - isDefault: false, - jsonData: { - subscriptionId: '44987801-6nn6-49he-9b2d-9106972f9789', - azureLogAnalyticsSameAs: true, - cloudName: 'azuremonitor', - }, - secureJsonFields: {}, - version: 1, - readOnly: false, - }, - onOptionsChange: jest.fn(), +describe('AppInsights ConfigEditor', () => { + const baseOptions = { + id: 21, + uid: 'y', + orgId: 1, + name: 'Azure Monitor-10-10', + type: 'grafana-azure-monitor-datasource', + typeLogoUrl: '', + typeName: 'Azure', + access: 'proxy', + url: '', + password: '', + user: '', + database: '', + basicAuth: false, + basicAuthUser: '', + basicAuthPassword: '', + withCredentials: false, + isDefault: false, + jsonData: {}, + secureJsonFields: {}, + version: 1, + readOnly: false, }; - return shallow(); -}; + const jsonData = { + subscriptionId: '44987801-6nn6-49he-9b2d-9106972f9789', + azureLogAnalyticsSameAs: true, + cloudName: 'azuremonitor', + }; -describe('Render', () => { - it('should render component', () => { - const wrapper = setup(); + const onOptionsChange = jest.fn(); - expect(wrapper).toMatchSnapshot(); + it('should not render application insights config for new data sources', () => { + const options = { + ...baseOptions, + jsonData, + }; + render(); + + expect(screen.queryByText('Azure Application Insights')).not.toBeInTheDocument(); + }); + + it('should render application insights config for data sources using application insights', () => { + const options = { + ...baseOptions, + jsonData: { + ...jsonData, + appInsightsAppId: 'abc-123', + }, + secureJsonFields: { + appInsightsApiKey: true, + }, + }; + render(); + + expect(screen.queryByText('Azure Application Insights')).toBeInTheDocument(); }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.tsx index 6ee7bbf07c4..058d11031d1 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.tsx @@ -13,13 +13,14 @@ import { getBackendSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime'; import { InsightsConfig } from './InsightsConfig'; import ResponseParser from '../azure_monitor/response_parser'; import { AzureDataSourceJsonData, AzureDataSourceSecureJsonData, AzureDataSourceSettings } from '../types'; -import { getAzureCloud } from '../credentials'; +import { getAzureCloud, isAppInsightsConfigured } from '../credentials'; import { getLogAnalyticsManagementApiRoute, getManagementApiRoute } from '../api/routes'; export type Props = DataSourcePluginOptionsEditorProps; export interface State { unsaved: boolean; + appInsightsInitiallyConfigured: boolean; } export class ConfigEditor extends PureComponent { @@ -30,6 +31,7 @@ export class ConfigEditor extends PureComponent { this.state = { unsaved: false, + appInsightsInitiallyConfigured: isAppInsightsConfigured(props.options), }; if (this.props.options.id) { @@ -138,12 +140,14 @@ export class ConfigEditor extends PureComponent { getWorkspaces={this.getWorkspaces} /> - + {this.state.appInsightsInitiallyConfigured && ( + + )} ); } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.tsx index 8ec146897ff..12f756b5147 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { InlineFormLabel, Button, LegacyForms } from '@grafana/ui'; +import { InlineFormLabel, Button, LegacyForms, Alert } from '@grafana/ui'; const { Input } = LegacyForms; import { AzureDataSourceSettings, AzureDataSourceJsonData, AzureDataSourceSecureJsonData } from '../types'; @@ -66,6 +66,10 @@ export class InsightsConfig extends PureComponent { + + + Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs. + ); } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryEditor.test.tsx index be9f2fdbc8c..922f4d0535d 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryEditor.test.tsx @@ -133,4 +133,54 @@ describe('Azure Monitor QueryEditor', () => { expect(screen.getByText("The resource namespace 'grafanadev' is invalid.")).toBeInTheDocument(); }); + + it('hides deprecated services', async () => { + const mockDatasource = createMockDatasource(); + const mockQuery = { + ...createMockQuery(), + queryType: AzureQueryType.AzureMonitor, + }; + + render( + {}} + /> + ); + await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument()); + + const metrics = await screen.findByLabelText('Service'); + selectEvent.openMenu(metrics); + + expect(screen.queryByText('Application Insights')).not.toBeInTheDocument(); + }); + + it("shows deprecated services when they're selected", async () => { + const mockDatasource = createMockDatasource(); + const mockQuery = { + ...createMockQuery(), + queryType: AzureQueryType.ApplicationInsights, + }; + + render( + {}} + /> + ); + await waitFor(() => + expect(screen.getByTestId('azure-monitor-application-insights-query-editor')).toBeInTheDocument() + ); + + expect(screen.queryByText('Application Insights')).toBeInTheDocument(); + + const metrics = await screen.findByLabelText('Service'); + await selectEvent.select(metrics, 'Logs'); + + expect(screen.queryByText('Application Insights')).toBeInTheDocument(); + }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryTypeField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryTypeField.tsx index 043030ea2d7..a31aa9a8c3c 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryTypeField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/QueryEditor/QueryTypeField.tsx @@ -1,24 +1,35 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useState } from 'react'; import { Select } from '@grafana/ui'; import { Field } from '../Field'; import { AzureMonitorQuery, AzureQueryType } from '../../types'; import { SelectableValue } from '@grafana/data'; import { findOption } from '../../utils/common'; -const QUERY_TYPES = [ - { value: AzureQueryType.AzureMonitor, label: 'Metrics' }, - { value: AzureQueryType.LogAnalytics, label: 'Logs' }, - { value: AzureQueryType.ApplicationInsights, label: 'Application Insights' }, - { value: AzureQueryType.InsightsAnalytics, label: 'Insights Analytics' }, - { value: AzureQueryType.AzureResourceGraph, label: 'Azure Resource Graph' }, -]; - interface QueryTypeFieldProps { query: AzureMonitorQuery; onQueryChange: (newQuery: AzureMonitorQuery) => void; } const QueryTypeField: React.FC = ({ query, onQueryChange }) => { + // Use useState to capture the initial value on first mount. We're not interested in when it changes + // We only show App Insights and Insights Analytics if they were initially selected. Otherwise, hide them. + const [initialQueryType] = useState(query.queryType); + const showAppInsights = + initialQueryType === AzureQueryType.ApplicationInsights || initialQueryType === AzureQueryType.InsightsAnalytics; + + const queryTypes = [ + { value: AzureQueryType.AzureMonitor, label: 'Metrics' }, + { value: AzureQueryType.LogAnalytics, label: 'Logs' }, + { value: AzureQueryType.AzureResourceGraph, label: 'Azure Resource Graph' }, + ]; + + if (showAppInsights) { + queryTypes.push( + { value: AzureQueryType.ApplicationInsights, label: 'Application Insights' }, + { value: AzureQueryType.InsightsAnalytics, label: 'Insights Analytics' } + ); + } + const handleChange = useCallback( (change: SelectableValue) => { change.value && @@ -34,8 +45,8 @@ const QueryTypeField: React.FC = ({ query, onQueryChange })