From 6d230d95ebadd3516e3cac0787c132baa5742fc6 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Mon, 30 Jan 2023 17:19:03 +0100 Subject: [PATCH] Azure Monitor: Enable multiple resource queries (#62467) --- .../feature-toggles/index.md | 28 ++-- e2e/cloud-plugins-suite/azure-monitor.spec.ts | 5 +- .../src/types/featureToggles.gen.ts | 2 - pkg/services/featuremgmt/registry.go | 12 -- pkg/services/featuremgmt/toggles_gen.go | 8 - .../LogsQueryEditor/LogsQueryEditor.test.tsx | 45 +++++- .../LogsQueryEditor/LogsQueryEditor.tsx | 11 +- .../MetricsQueryEditor.test.tsx | 96 +++++++++++- .../MetricsQueryEditor/MetricsQueryEditor.tsx | 7 +- .../ResourcePicker/Advanced.test.tsx | 44 ------ .../components/ResourcePicker/Advanced.tsx | 146 ------------------ .../ResourcePicker/ResourcePicker.test.tsx | 79 ---------- .../ResourcePicker/ResourcePicker.tsx | 18 +-- .../VariableEditor/VariableEditor.tsx | 6 +- .../grafanaTemplateVariableFns.ts | 2 +- .../grafanaTemplateVariables.test.ts | 2 +- 16 files changed, 159 insertions(+), 352 deletions(-) delete mode 100644 public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.test.tsx delete mode 100644 public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.tsx diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index a404c8b6f33..449086347e2 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -98,24 +98,22 @@ Alpha features might be changed or removed without prior notice. | `sessionRemoteCache` | Enable using remote cache for user sessions | | `alertingBacktesting` | Rule backtesting API for alerting | | `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files | -| `azureMultipleResourcePicker` | Azure multiple resource picker | | `logsContextDatasourceUi` | Allow datasource to provide custom UI for context view | ## Development feature toggles The following toggles require explicitly setting Grafana's [app mode]({{< relref "../_index.md/#app_mode" >}}) to 'development' before you can enable this feature toggle. These features tend to be experimental. -| Feature toggle name | Description | -| -------------------------------------- | ----------------------------------------------------------------------- | -| `dashboardPreviewsAdmin` | Manage the dashboard previews crawler process from the UI | -| `showFeatureFlagsInUI` | Show feature flags in the settings UI | -| `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails | -| `k8s` | Explore native k8s integrations | -| `k8sDashboards` | Save dashboards via k8s | -| `dashboardsFromStorage` | Load dashboards from the generic storage interface | -| `export` | Export grafana instance (to git, etc) | -| `azureMonitorResourcePickerForMetrics` | New UI for Azure Monitor Metrics Query | -| `grpcServer` | Run GRPC server | -| `entityStore` | SQL-based entity store (requires storage flag also) | -| `queryLibrary` | Reusable query library | -| `nestedFolders` | Enable folder nesting | +| Feature toggle name | Description | +| ------------------------------ | ----------------------------------------------------------------------- | +| `dashboardPreviewsAdmin` | Manage the dashboard previews crawler process from the UI | +| `showFeatureFlagsInUI` | Show feature flags in the settings UI | +| `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails | +| `k8s` | Explore native k8s integrations | +| `k8sDashboards` | Save dashboards via k8s | +| `dashboardsFromStorage` | Load dashboards from the generic storage interface | +| `export` | Export grafana instance (to git, etc) | +| `grpcServer` | Run GRPC server | +| `entityStore` | SQL-based entity store (requires storage flag also) | +| `queryLibrary` | Reusable query library | +| `nestedFolders` | Enable folder nesting | diff --git a/e2e/cloud-plugins-suite/azure-monitor.spec.ts b/e2e/cloud-plugins-suite/azure-monitor.spec.ts index 178b3a4bed0..84fb21421ae 100644 --- a/e2e/cloud-plugins-suite/azure-monitor.spec.ts +++ b/e2e/cloud-plugins-suite/azure-monitor.spec.ts @@ -248,6 +248,8 @@ e2e.scenario({ .parent() .find('input') .type('microsoft.storage/storageaccounts{downArrow}{enter}'); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('region').parent().find('button').click(); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('region').parent().find('input').type('uk south{downArrow}{enter}'); e2e.pages.Dashboard.SubMenu.submenuItemLabels('resource').parent().find('button').click(); e2e.pages.Dashboard.SubMenu.submenuItemLabels('resource') .parent() @@ -262,8 +264,7 @@ e2e.scenario({ e2eSelectors.queryEditor.resourcePicker.advanced.subscription.input().find('input').type('$subscription'); e2eSelectors.queryEditor.resourcePicker.advanced.resourceGroup.input().find('input').type('$resourceGroups'); e2eSelectors.queryEditor.resourcePicker.advanced.namespace.input().find('input').type('$namespaces'); - // TODO: Enable this input once multiple resources feature flag is removed - // e2eSelectors.queryEditor.resourcePicker.advanced.region.input().find('input').type('$region'); + e2eSelectors.queryEditor.resourcePicker.advanced.region.input().find('input').type('$region'); e2eSelectors.queryEditor.resourcePicker.advanced.resource.input().find('input').type('$resource'); e2eSelectors.queryEditor.resourcePicker.apply.button().click(); e2eSelectors.queryEditor.metricsQueryEditor.metricName.input().find('input').type('Transactions{enter}'); diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 467ad96208f..126aebe083f 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -47,7 +47,6 @@ export interface FeatureToggles { supportBundles?: boolean; dashboardsFromStorage?: boolean; export?: boolean; - azureMonitorResourcePickerForMetrics?: boolean; exploreMixedDatasource?: boolean; tracing?: boolean; commandPalette?: boolean; @@ -90,7 +89,6 @@ export interface FeatureToggles { alertingBacktesting?: boolean; editPanelCSVDragAndDrop?: boolean; alertingNoNormalState?: boolean; - azureMultipleResourcePicker?: boolean; topNavCommandPalette?: boolean; logsSampleInExplore?: boolean; logsContextDatasourceUi?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index e27478fa809..4910a8c9d3c 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -177,13 +177,6 @@ var ( State: FeatureStateAlpha, RequiresDevMode: true, }, - { - Name: "azureMonitorResourcePickerForMetrics", - Description: "New UI for Azure Monitor Metrics Query", - State: FeatureStateAlpha, - RequiresDevMode: true, - FrontendOnly: true, - }, { Name: "exploreMixedDatasource", Description: "Enable mixed datasource in Explore", @@ -416,11 +409,6 @@ var ( State: FeatureStateBeta, RequiresRestart: false, }, - { - Name: "azureMultipleResourcePicker", - Description: "Azure multiple resource picker", - State: FeatureStateAlpha, - }, { Name: "topNavCommandPalette", Description: "Launch the Command Palette from the top navigation search box", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 737d8483c0e..7301eb570ba 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -131,10 +131,6 @@ const ( // Export grafana instance (to git, etc) FlagExport = "export" - // FlagAzureMonitorResourcePickerForMetrics - // New UI for Azure Monitor Metrics Query - FlagAzureMonitorResourcePickerForMetrics = "azureMonitorResourcePickerForMetrics" - // FlagExploreMixedDatasource // Enable mixed datasource in Explore FlagExploreMixedDatasource = "exploreMixedDatasource" @@ -303,10 +299,6 @@ const ( // Stop maintaining state of alerts that are not firing FlagAlertingNoNormalState = "alertingNoNormalState" - // FlagAzureMultipleResourcePicker - // Azure multiple resource picker - FlagAzureMultipleResourcePicker = "azureMultipleResourcePicker" - // FlagTopNavCommandPalette // Launch the Command Palette from the top navigation search box FlagTopNavCommandPalette = "topNavCommandPalette" diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx index 32c4b44c92e..5bf10d93801 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx @@ -2,8 +2,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import config from 'app/core/config'; - import createMockDatasource from '../../__mocks__/datasource'; import createMockQuery from '../../__mocks__/query'; import { createMockResourcePickerData } from '../MetricsQueryEditor/MetricsQueryEditor.test'; @@ -24,10 +22,6 @@ const variableOptionGroup = { options: [], }; -beforeEach(() => { - config.featureToggles.azureMultipleResourcePicker = true; -}); - describe('LogsQueryEdiutor', () => { const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; @@ -151,4 +145,43 @@ describe('LogsQueryEdiutor', () => { expect(await screen.findByText('You may only choose items of the same resource type.')).toBeInTheDocument(); }); + + it('should call onApply with a new subscription uri when a user types it in the selection box', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.subscription; + delete query?.azureLogAnalytics?.resources; + const onChange = jest.fn(); + + render( + {}} + /> + ); + + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + resourcePickerButton.click(); + + const advancedSection = screen.getByText('Advanced'); + advancedSection.click(); + + const advancedInput = await screen.findByTestId('input-advanced-resource-picker-1'); + // const advancedInput = await screen.findByLabelText('Resource URI(s)'); + await userEvent.type(advancedInput, '/subscriptions/def-123'); + + const applyButton = screen.getByRole('button', { name: 'Apply' }); + applyButton.click(); + + expect(onChange).toBeCalledWith( + expect.objectContaining({ + azureLogAnalytics: expect.objectContaining({ + resources: ['/subscriptions/def-123'], + }), + }) + ); + }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx index f29bb2c41e8..ed9bedc34f6 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental'; -import { config } from '@grafana/runtime'; import { Alert } from '@grafana/ui'; import Datasource from '../../datasource'; @@ -40,10 +39,6 @@ const LogsQueryEditor: React.FC = ({ // Only if there is some resource(s) selected we should disable rows return false; } - // Disable multiple selection until the feature is ready - if (!config.featureToggles.azureMultipleResourcePicker) { - return true; - } const rowResourceNS = parseResourceDetails(row.uri, row.location).metricNamespace?.toLowerCase(); const selectedRowSampleNs = parseResourceDetails( selectedRows[0].uri, @@ -82,11 +77,7 @@ const LogsQueryEditor: React.FC = ({ // eslint-disable-next-line )} - selectionNotice={() => - config.featureToggles.azureMultipleResourcePicker - ? 'You may only choose items of the same resource type.' - : '' - } + selectionNotice={() => 'You may only choose items of the same resource type.'} /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx index 01cb3db99cf..debb4c68082 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx @@ -3,8 +3,6 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { selectOptionInTest } from 'test/helpers/selectOptionInTest'; -import config from 'app/core/config'; - import createMockDatasource from '../../__mocks__/datasource'; import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings'; import createMockPanelData from '../../__mocks__/panelData'; @@ -33,10 +31,6 @@ const variableOptionGroup = { options: [], }; -beforeEach(() => { - config.featureToggles.azureMultipleResourcePicker = true; -}); - export function createMockResourcePickerData() { const mockDatasource = createMockDatasource(); const mockResourcePicker = new ResourcePickerData( @@ -378,4 +372,94 @@ describe('MetricsQueryEditor', () => { }, }); }); + + it('should show unselect a resource if the value is manually edited', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.subscription; + delete query?.azureMonitor?.resources; + delete query?.azureMonitor?.metricNamespace; + const onChange = jest.fn(); + + render( + {}} + /> + ); + + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + resourcePickerButton.click(); + + const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); + subscriptionButton.click(); + + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); + resourceGroupButton.click(); + + const checkbox = await screen.findByLabelText('web-server'); + await userEvent.click(checkbox); + expect(checkbox).toBeChecked(); + + const advancedSection = screen.getByText('Advanced'); + advancedSection.click(); + + const advancedInput = await screen.findByLabelText('Subscription'); + await userEvent.type(advancedInput, 'def-123'); + + const updatedCheckboxes = await screen.findAllByLabelText('web-server'); + expect(updatedCheckboxes.length).toBe(1); + expect(updatedCheckboxes[0]).not.toBeChecked(); + }); + + it('should call onApply with a new subscription when a user types it in the selection box', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.subscription; + delete query?.azureMonitor?.resources; + delete query?.azureMonitor?.metricNamespace; + const onChange = jest.fn(); + + render( + {}} + /> + ); + + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + resourcePickerButton.click(); + + const advancedSection = screen.getByText('Advanced'); + advancedSection.click(); + + const advancedInput = await screen.findByLabelText('Subscription'); + await userEvent.type(advancedInput, 'def-123'); + const nsInput = await screen.findByLabelText('Namespace'); + await userEvent.type(nsInput, 'ns'); + const rgInput = await screen.findByLabelText('Resource Group'); + await userEvent.type(rgInput, 'rg'); + const rnInput = await screen.findByLabelText('Resource Name'); + await userEvent.type(rnInput, 'rn'); + + const applyButton = screen.getByRole('button', { name: 'Apply' }); + applyButton.click(); + + expect(onChange).toBeCalledTimes(1); + expect(onChange).toBeCalledWith( + expect.objectContaining({ + azureMonitor: expect.objectContaining({ + resources: [{ subscription: 'def-123', metricNamespace: 'ns', resourceGroup: 'rg', resourceName: 'rn' }], + }), + }) + ); + }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx index 4358ab8422d..d4ad986b58d 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { PanelData } from '@grafana/data/src/types'; import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental'; -import { config } from '@grafana/runtime'; import { multiResourceCompatibleTypes } from '../../azureMetadata'; import type Datasource from '../../datasource'; @@ -59,10 +58,6 @@ const MetricsQueryEditor: React.FC = ({ // Only if there is some resource(s) selected we should disable rows return false; } - if (!config.featureToggles.azureMultipleResourcePicker) { - // Disable multiple selection until the feature is ready - return true; - } const rowResource = parseResourceDetails(row.uri, row.location); const selectedRowSample = parseResourceDetails(selectedRows[0].uri, selectedRows[0].location); @@ -80,7 +75,7 @@ const MetricsQueryEditor: React.FC = ({ }; const selectionNotice = (selectedRows: ResourceRowGroup) => { - if (selectedRows.length === 0 || !config.featureToggles.azureMultipleResourcePicker) { + if (selectedRows.length === 0) { return ''; } const selectedRowSample = parseResourceDetails(selectedRows[0].uri, selectedRows[0].location); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.test.tsx deleted file mode 100644 index f4f55d70b0d..00000000000 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import Advanced from './Advanced'; - -describe('AzureMonitor ResourcePicker', () => { - it('should set a parameter as an object', async () => { - const onChange = jest.fn(); - const { rerender } = render(); - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - const subsInput = await screen.findByLabelText('Subscription'); - await userEvent.type(subsInput, 'd'); - expect(onChange).toHaveBeenCalledWith([{ subscription: 'd' }]); - - rerender(); - expect(screen.getByLabelText('Subscription').outerHTML).toMatch('value="def-123"'); - }); - - it('should set a parameter as uri', async () => { - const onChange = jest.fn(); - const { rerender } = render(); - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - const subsInput = await screen.findByLabelText('Resource URI'); - await userEvent.type(subsInput, '/'); - expect(onChange).toHaveBeenCalledWith(['/']); - - rerender(); - expect(screen.getByLabelText('Resource URI').outerHTML).toMatch('value="/subscriptions/sub"'); - }); - - it('should render multiple resources', async () => { - render(); - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - expect(screen.getByDisplayValue('/subscriptions/sub1')).toBeInTheDocument(); - expect(screen.getByDisplayValue('/subscriptions/sub2')).toBeInTheDocument(); - }); -}); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.tsx deleted file mode 100644 index fd12b294a6f..00000000000 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Advanced.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React, { useState } from 'react'; - -import { Icon, Input, Tooltip, Collapse, Label, InlineField } from '@grafana/ui'; - -import { selectors } from '../../e2e/selectors'; -import { AzureMetricResource } from '../../types'; -import { Space } from '../Space'; - -interface ResourcePickerProps { - resources: T[]; - onChange: (resources: T[]) => void; -} - -const Advanced = ({ resources, onChange }: ResourcePickerProps) => { - const [isAdvancedOpen, setIsAdvancedOpen] = useState(!!resources.length && JSON.stringify(resources).includes('$')); - - const onResourceChange = (resource: string | AzureMetricResource, index: number) => { - const newResources = [...resources]; - newResources[index] = resource; - onChange(newResources); - }; - - return ( -
- setIsAdvancedOpen(!isAdvancedOpen)} - > - {(resources.length ? resources : [{}]).map((resource, index) => ( -
- {typeof resource === 'string' ? ( - <> - - onResourceChange(event.currentTarget.value, index)} - placeholder="ex: /subscriptions/$subId" - /> - - ) : ( - <> - - - onResourceChange({ ...resource, subscription: event.currentTarget.value }, index) - } - placeholder="aaaaaaaa-bbbb-cccc-dddd-eeeeeeee" - /> - - - - onResourceChange({ ...resource, resourceGroup: event.currentTarget.value }, index) - } - placeholder="resource-group" - /> - - - - onResourceChange({ ...resource, metricNamespace: event.currentTarget.value }, index) - } - placeholder="Microsoft.Insights/metricNamespaces" - /> - - - - onResourceChange({ ...resource, resourceName: event.currentTarget.value }, index) - } - placeholder="name" - /> - - - )} -
- ))} - -
-
- ); -}; - -export default Advanced; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.test.tsx index 3bad6927b27..6b4b330882e 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.test.tsx @@ -232,85 +232,6 @@ describe('AzureMonitor ResourcePicker', () => { expect(onApply).toBeCalledWith([]); }); - it('should call onApply with a new subscription uri when a user types it in the selection box', async () => { - const onApply = jest.fn(); - render(); - const subscriptionCheckbox = await screen.findByLabelText('Primary Subscription'); - expect(subscriptionCheckbox).toBeInTheDocument(); - expect(subscriptionCheckbox).not.toBeChecked(); - - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - const advancedInput = await screen.findByLabelText('Resource URI'); - await userEvent.type(advancedInput, '/subscriptions/def-123'); - - const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); - - expect(onApply).toBeCalledTimes(1); - expect(onApply).toBeCalledWith(['/subscriptions/def-123']); - }); - - it('should call onApply with a new subscription when a user types it in the selection box', async () => { - const onApply = jest.fn(); - render(); - const subscriptionCheckbox = await screen.findByLabelText('Primary Subscription'); - expect(subscriptionCheckbox).toBeInTheDocument(); - expect(subscriptionCheckbox).not.toBeChecked(); - - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - const advancedInput = await screen.findByLabelText('Subscription'); - await userEvent.type(advancedInput, 'def-123'); - const nsInput = await screen.findByLabelText('Namespace'); - await userEvent.type(nsInput, 'ns'); - const rgInput = await screen.findByLabelText('Resource Group'); - await userEvent.type(rgInput, 'rg'); - const rnInput = await screen.findByLabelText('Resource Name'); - await userEvent.type(rnInput, 'rn'); - - const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); - - expect(onApply).toBeCalledTimes(1); - expect(onApply).toBeCalledWith([ - { subscription: 'def-123', metricNamespace: 'ns', resourceGroup: 'rg', resourceName: 'rn' }, - ]); - }); - - it('should show unselect a subscription if the value is manually edited', async () => { - render( - - ); - const checkboxes = await screen.findAllByLabelText('web-server'); - expect(checkboxes.length).toBe(2); - expect(checkboxes[0]).toBeChecked(); - expect(checkboxes[1]).toBeChecked(); - - const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); - - const advancedInput = await screen.findByLabelText('Subscription'); - await userEvent.type(advancedInput, 'def-123'); - - const updatedCheckboxes = await screen.findAllByLabelText('web-server'); - expect(updatedCheckboxes.length).toBe(1); - expect(updatedCheckboxes[0]).not.toBeChecked(); - }); - it('renders a search field which show search results when there are results', async () => { render(); const searchRow1 = screen.queryByLabelText('search-result'); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx index 93d04ba6ff6..475215e0383 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx @@ -2,7 +2,6 @@ import { cx } from '@emotion/css'; import React, { useCallback, useEffect, useState } from 'react'; import { useEffectOnce } from 'react-use'; -import { config } from '@grafana/runtime'; import { Alert, Button, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; import { selectors } from '../../e2e/selectors'; @@ -11,7 +10,6 @@ import { AzureMetricResource } from '../../types'; import messageFromError from '../../utils/messageFromError'; import { Space } from '../Space'; -import Advanced from './Advanced'; import AdvancedMulti from './AdvancedMulti'; import NestedRow from './NestedRow'; import Search from './Search'; @@ -123,7 +121,7 @@ const ResourcePicker = ({ if (isSelected) { const newRes = queryType === 'logs' ? row.uri : parseMultipleResourceDetails([row.uri], row.location)[0]; const newSelected = internalSelected ? internalSelected.concat(newRes) : [newRes]; - setInternalSelected(newSelected); + setInternalSelected(newSelected.filter((r) => isValid(r))); } else { const newInternalSelected = internalSelected?.filter((r) => { return !matchURI(resourceToString(r), row.uri); @@ -252,15 +250,11 @@ const ResourcePicker = ({ )} - {config.featureToggles.azureMultipleResourcePicker ? ( - setInternalSelected(r)} - renderAdvanced={renderAdvanced} - /> - ) : ( - setInternalSelected(r)} /> - )} + setInternalSelected(r)} + renderAdvanced={renderAdvanced} + /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.tsx index 9ada46d6676..c0716cb2ed9 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.tsx @@ -1,4 +1,4 @@ -import { get } from 'lodash'; +import { get, isEqual } from 'lodash'; import React, { useEffect, useState } from 'react'; import { useEffectOnce } from 'react-use'; @@ -65,7 +65,9 @@ const VariableEditor = (props: Props) => { useEffect(() => { migrateQuery(query, { datasource: datasource }).then((migratedQuery) => { - onChange(migratedQuery); + if (!isEqual(query, migratedQuery)) { + onChange(migratedQuery); + } }); }, [query, datasource, onChange]); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariableFns.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariableFns.ts index 0ed9de7dd36..1b7578ee774 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariableFns.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariableFns.ts @@ -246,7 +246,7 @@ const createLogAnalyticsTemplateVariableQuery = async ( queryType: AzureQueryType.LogAnalytics, azureLogAnalytics: { query: rawQuery, - resources: [resource], + resources: resource ? [resource] : [], }, subscription: defaultSubscriptionId, }; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts index 07e78821810..88b6dbd5fa3 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts @@ -219,7 +219,7 @@ describe('migrateStringQueriesToObjectQueries', () => { queryType: AzureQueryType.LogAnalytics, azureLogAnalytics: { query: 'some kind of kql query', - resources: [''], + resources: [], }, subscription: 'defaultSubscriptionId', },