From a1217ef8dada46ceaa7266f5991b470ce38be96a Mon Sep 17 00:00:00 2001 From: Adam Simpson Date: Wed, 11 May 2022 22:54:43 -0400 Subject: [PATCH] AzureMonitor: begin moving metrics query editor to use @grafana/experimental (#48878) * feat: migrate Azure Metrics Query Editor Field to experimental UI * feat: ensure tests pass with experimental feature flag enabled * feat: avoid duplicate unit tests for experimental MetricsQueryEditor --- .../components/Field.tsx | 11 +- .../MetricsQueryEditor.test.tsx | 374 +++++++++--------- .../MetricsQueryEditor.tsx | 230 ++++++++--- .../QueryEditor/QueryEditor.test.tsx | 12 + 4 files changed, 383 insertions(+), 244 deletions(-) diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/Field.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/Field.tsx index a40992d93a6..52e2fa818bc 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/Field.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/Field.tsx @@ -1,10 +1,19 @@ import React from 'react'; +import { EditorField } from '@grafana/experimental'; +import { config } from '@grafana/runtime'; import { InlineField } from '@grafana/ui'; import { Props as InlineFieldProps } from '@grafana/ui/src/components/Forms/InlineField'; +interface Props extends InlineFieldProps { + label: string; +} + const DEFAULT_LABEL_WIDTH = 18; -export const Field = (props: InlineFieldProps) => { +export const Field = (props: Props) => { + if (config.featureToggles.azureMonitorExperimentalUI) { + return ; + } return ; }; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.test.tsx index 9fa39966131..74dd628c824 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.test.tsx @@ -2,6 +2,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; +import { config } from '@grafana/runtime'; import { selectOptionInTest } from '@grafana/ui'; import createMockDatasource from '../../__mocks__/datasource'; @@ -22,6 +23,15 @@ const variableOptionGroup = { options: [], }; +const tests = [ + { + id: 'azure-monitor-metrics-query-editor-with-resource-picker', + }, + { + id: 'azure-monitor-metrics-query-editor-with-experimental-ui', + }, +]; + export function createMockResourcePickerData() { const mockDatasource = new ResourcePickerData(createMockInstanceSetttings()); @@ -36,209 +46,215 @@ export function createMockResourcePickerData() { return mockDatasource; } -describe('MetricsQueryEditor', () => { - const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; - beforeEach(() => { - window.HTMLElement.prototype.scrollIntoView = function () {}; - }); - afterEach(() => { - window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView; - }); - const mockPanelData = createMockPanelData(); +for (const t of tests) { + describe(`MetricsQueryEditor: ${t.id}`, () => { + const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; + const mockPanelData = createMockPanelData(); - it('should render', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + beforeEach(() => { + window.HTMLElement.prototype.scrollIntoView = function () {}; + config.featureToggles.azureMonitorExperimentalUI = + t.id === 'azure-monitor-metrics-query-editor-with-experimental-ui'; + }); + afterEach(() => { + window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView; + config.featureToggles.azureMonitorExperimentalUI = false; + }); - render( - {}} - setError={() => {}} - /> - ); + it('should render', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - expect(await screen.findByTestId('azure-monitor-metrics-query-editor-with-resource-picker')).toBeInTheDocument(); - }); + render( + {}} + setError={() => {}} + /> + ); - it('should change resource when a resource is selected in the ResourcePicker', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - const query = createMockQuery(); - delete query?.azureMonitor?.resourceUri; - const onChange = jest.fn(); + expect(await screen.findByTestId(t.id)).toBeInTheDocument(); + }); - render( - {}} - /> - ); + it('should change resource when a resource is selected in the ResourcePicker', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.azureMonitor?.resourceUri; + const onChange = jest.fn(); - const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); - expect(resourcePickerButton).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); - resourcePickerButton.click(); + render( + {}} + /> + ); - const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); - expect(subscriptionButton).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Expand A Great Resource Group' })).not.toBeInTheDocument(); - subscriptionButton.click(); + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + expect(resourcePickerButton).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); + resourcePickerButton.click(); - const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - expect(resourceGroupButton).toBeInTheDocument(); - expect(screen.queryByLabelText('web-server')).not.toBeInTheDocument(); - resourceGroupButton.click(); + const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); + expect(subscriptionButton).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Expand A Great Resource Group' })).not.toBeInTheDocument(); + subscriptionButton.click(); - const checkbox = await screen.findByLabelText('web-server'); - expect(checkbox).toBeInTheDocument(); - expect(checkbox).not.toBeChecked(); - await userEvent.click(checkbox); - expect(checkbox).toBeChecked(); - await userEvent.click(await screen.findByRole('button', { name: 'Apply' })); + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); + expect(resourceGroupButton).toBeInTheDocument(); + expect(screen.queryByLabelText('web-server')).not.toBeInTheDocument(); + resourceGroupButton.click(); - expect(onChange).toBeCalledTimes(1); - expect(onChange).toBeCalledWith( - expect.objectContaining({ - azureMonitor: expect.objectContaining({ - resourceUri: - '/subscriptions/def-456/resourceGroups/dev-3/providers/Microsoft.Compute/virtualMachines/web-server', - }), - }) - ); - }); + const checkbox = await screen.findByLabelText('web-server'); + expect(checkbox).toBeInTheDocument(); + expect(checkbox).not.toBeChecked(); + await userEvent.click(checkbox); + expect(checkbox).toBeChecked(); + await userEvent.click(await screen.findByRole('button', { name: 'Apply' })); - it('should reset metric namespace, metric name, and aggregation fields after selecting a new resource when a valid query has already been set', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - const query = createMockQuery(); - const onChange = jest.fn(); + expect(onChange).toBeCalledTimes(1); + expect(onChange).toBeCalledWith( + expect.objectContaining({ + azureMonitor: expect.objectContaining({ + resourceUri: + '/subscriptions/def-456/resourceGroups/dev-3/providers/Microsoft.Compute/virtualMachines/web-server', + }), + }) + ); + }); - render( - {}} - /> - ); + it('should reset metric namespace, metric name, and aggregation fields after selecting a new resource when a valid query has already been set', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + const onChange = jest.fn(); - const resourcePickerButton = await screen.findByRole('button', { name: /grafanastaging/ }); + render( + {}} + /> + ); - expect(screen.getByText('Microsoft.Compute/virtualMachines')).toBeInTheDocument(); - expect(screen.getByText('Metric A')).toBeInTheDocument(); - expect(screen.getByText('Average')).toBeInTheDocument(); + const resourcePickerButton = await screen.findByRole('button', { name: /grafanastaging/ }); - expect(resourcePickerButton).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); - resourcePickerButton.click(); + expect(screen.getByText('Microsoft.Compute/virtualMachines')).toBeInTheDocument(); + expect(screen.getByText('Metric A')).toBeInTheDocument(); + expect(screen.getByText('Average')).toBeInTheDocument(); - const subscriptionButton = await screen.findByRole('button', { name: 'Expand Dev Subscription' }); - expect(subscriptionButton).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Expand Development 3' })).not.toBeInTheDocument(); - subscriptionButton.click(); + expect(resourcePickerButton).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); + resourcePickerButton.click(); - const resourceGroupButton = await screen.findByRole('button', { name: 'Expand Development 3' }); - expect(resourceGroupButton).toBeInTheDocument(); - expect(screen.queryByLabelText('db-server')).not.toBeInTheDocument(); - resourceGroupButton.click(); + const subscriptionButton = await screen.findByRole('button', { name: 'Expand Dev Subscription' }); + expect(subscriptionButton).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Expand Development 3' })).not.toBeInTheDocument(); + subscriptionButton.click(); - const checkbox = await screen.findByLabelText('db-server'); - expect(checkbox).toBeInTheDocument(); - expect(checkbox).not.toBeChecked(); - await userEvent.click(checkbox); - expect(checkbox).toBeChecked(); - await userEvent.click(await screen.findByRole('button', { name: 'Apply' })); + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand Development 3' }); + expect(resourceGroupButton).toBeInTheDocument(); + expect(screen.queryByLabelText('db-server')).not.toBeInTheDocument(); + resourceGroupButton.click(); - expect(onChange).toBeCalledTimes(1); - expect(onChange).toBeCalledWith( - expect.objectContaining({ - azureMonitor: expect.objectContaining({ - resourceUri: - '/subscriptions/def-456/resourceGroups/dev-3/providers/Microsoft.Compute/virtualMachines/db-server', - metricNamespace: undefined, - metricName: undefined, + const checkbox = await screen.findByLabelText('db-server'); + expect(checkbox).toBeInTheDocument(); + expect(checkbox).not.toBeChecked(); + await userEvent.click(checkbox); + expect(checkbox).toBeChecked(); + await userEvent.click(await screen.findByRole('button', { name: 'Apply' })); + + expect(onChange).toBeCalledTimes(1); + expect(onChange).toBeCalledWith( + expect.objectContaining({ + azureMonitor: expect.objectContaining({ + resourceUri: + '/subscriptions/def-456/resourceGroups/dev-3/providers/Microsoft.Compute/virtualMachines/db-server', + metricNamespace: undefined, + metricName: undefined, + aggregation: undefined, + timeGrain: '', + dimensionFilters: [], + }), + }) + ); + }); + + it('should change the metric name when selected', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const onChange = jest.fn(); + const mockQuery = createMockQuery(); + mockDatasource.azureMonitorDatasource.getMetricNames = jest.fn().mockResolvedValue([ + { + value: 'metric-a', + text: 'Metric A', + }, + { + value: 'metric-b', + text: 'Metric B', + }, + ]); + + render( + {}} + /> + ); + + const metrics = await screen.findByLabelText('Metric'); + expect(metrics).toBeInTheDocument(); + await selectOptionInTest(metrics, 'Metric B'); + + expect(onChange).toHaveBeenLastCalledWith({ + ...mockQuery, + azureMonitor: { + ...mockQuery.azureMonitor, + metricName: 'metric-b', aggregation: undefined, timeGrain: '', - dimensionFilters: [], - }), - }) - ); - }); + }, + }); + }); - it('should change the metric name when selected', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - const onChange = jest.fn(); - const mockQuery = createMockQuery(); - mockDatasource.azureMonitorDatasource.getMetricNames = jest.fn().mockResolvedValue([ - { - value: 'metric-a', - text: 'Metric A', - }, - { - value: 'metric-b', - text: 'Metric B', - }, - ]); + it('should change the aggregation type when selected', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const onChange = jest.fn(); + const mockQuery = createMockQuery(); - render( - {}} - /> - ); + render( + {}} + /> + ); - const metrics = await screen.findByLabelText('Metric'); - expect(metrics).toBeInTheDocument(); - await selectOptionInTest(metrics, 'Metric B'); + const aggregation = await screen.findByLabelText('Aggregation'); + expect(aggregation).toBeInTheDocument(); + await selectOptionInTest(aggregation, 'Maximum'); - expect(onChange).toHaveBeenLastCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - metricName: 'metric-b', - aggregation: undefined, - timeGrain: '', - }, + expect(onChange).toHaveBeenLastCalledWith({ + ...mockQuery, + azureMonitor: { + ...mockQuery.azureMonitor, + aggregation: 'Maximum', + }, + }); }); }); - - it('should change the aggregation type when selected', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - const onChange = jest.fn(); - const mockQuery = createMockQuery(); - - render( - {}} - /> - ); - - const aggregation = await screen.findByLabelText('Aggregation'); - expect(aggregation).toBeInTheDocument(); - await selectOptionInTest(aggregation, 'Maximum'); - - expect(onChange).toHaveBeenLastCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - aggregation: 'Maximum', - }, - }); - }); -}); +} diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.tsx index f7693b36585..a0ce1ff4a52 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/NewMetricsQueryEditor/MetricsQueryEditor.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { PanelData } from '@grafana/data/src/types'; +import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental'; +import { config } from '@grafana/runtime'; import { InlineFieldRow } from '@grafana/ui'; import type Datasource from '../../datasource'; @@ -38,83 +40,183 @@ const MetricsQueryEditor: React.FC = ({ const metricsMetadata = useMetricMetadata(query, datasource, onChange); const metricNamespaces = useMetricNamespaces(query, datasource, onChange, setError); const metricNames = useMetricNames(query, datasource, onChange, setError); - return ( -
- - - + if (config.featureToggles.azureMonitorExperimentalUI) { + return ( + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } else { + return ( +
+ + + + + + + + + + + + + + - - - - - - - - - -
- ); +
+ ); + } }; export default MetricsQueryEditor; 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 9b602d04215..766abdc1085 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 @@ -108,4 +108,16 @@ describe('Azure Monitor QueryEditor', () => { config.featureToggles.azureMonitorExperimentalUI = originalConfigValue; }); + + it('should not render the experimental QueryHeader when feature toggle is disabled', async () => { + const mockDatasource = createMockDatasource(); + const mockQuery = { + ...createMockQuery(), + queryType: AzureQueryType.AzureMonitor, + }; + + render( {}} onRunQuery={() => {}} />); + + await waitFor(() => expect(screen.queryByTestId('azure-monitor-experimental-header')).not.toBeInTheDocument()); + }); });