diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index a1f0aeaa049..4b1ab6703d0 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -49,7 +49,6 @@ export interface FeatureToggles { commandPalette?: boolean; cloudWatchDynamicLabels?: boolean; datasourceQueryMultiStatus?: boolean; - azureMonitorExperimentalUI?: boolean; traceToMetrics?: boolean; prometheusStreamingJSONParser?: boolean; validateDashboardsOnSave?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index f224ab0c434..2dd5610fd8f 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -187,12 +187,6 @@ var ( Description: "Introduce HTTP 207 Multi Status for api/ds/query", State: FeatureStateAlpha, }, - { - Name: "azureMonitorExperimentalUI", - Description: "Use grafana-experimental UI in Azure Monitor", - State: FeatureStateAlpha, - FrontendOnly: true, - }, { Name: "traceToMetrics", Description: "Enable trace to metrics links", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 7437de560fa..f8f43947430 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -139,10 +139,6 @@ const ( // Introduce HTTP 207 Multi Status for api/ds/query FlagDatasourceQueryMultiStatus = "datasourceQueryMultiStatus" - // FlagAzureMonitorExperimentalUI - // Use grafana-experimental UI in Azure Monitor - FlagAzureMonitorExperimentalUI = "azureMonitorExperimentalUI" - // FlagTraceToMetrics // Enable trace to metrics links FlagTraceToMetrics = "traceToMetrics" diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx index 60ef2fde091..4b43b435f50 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx @@ -1,8 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental'; -import { config } from '@grafana/runtime'; -import { InlineFieldRow } from '@grafana/ui'; import Datasource from '../../datasource'; import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types'; @@ -54,62 +52,34 @@ const ArgQueryEditor: React.FC = ({ .catch((err) => setError(ERROR_SOURCE, err)); }, [datasource, onChange, query, setError]); - if (config.featureToggles.azureMonitorExperimentalUI) { - return ( - - - - - - - - - - - ); - } else { - return ( -
- - - - - -
- ); - } + return ( + + + + + + + + + + + ); }; export default ArgQueryEditor; 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 61318cf8527..b139b377686 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,7 +1,6 @@ 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'; @@ -16,7 +15,7 @@ const DEFAULT_LABEL_WIDTH = 18; export const Field = (props: Props) => { const { labelWidth, inlineField, ...remainingProps } = props; - if (config.featureToggles.azureMonitorExperimentalUI && !inlineField) { + if (!inlineField) { return ; } else { return ; 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 a55d8585355..881f72dacd7 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 { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental'; -import { config } from '@grafana/runtime'; import { Alert } from '@grafana/ui'; import Datasource from '../../datasource'; @@ -35,81 +34,32 @@ const LogsQueryEditor: React.FC = ({ }) => { const migrationError = useMigrations(datasource, query, onChange); - if (config.featureToggles.azureMonitorExperimentalUI) { - return ( - - - - - - - - - - - {!hideFormatAs && ( - - )} - - {migrationError && {migrationError.message}} - - - - - ); - } else { - return ( -
- - + return ( + + + + + + + = ({ onQueryChange={onChange} setError={setError} /> + + + {!hideFormatAs && ( + + )} - {!hideFormatAs && ( - - )} - - {migrationError && {migrationError.message}} -
- ); - } + {migrationError && {migrationError.message}} + + + + + ); }; export default LogsQueryEditor; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/AggregationField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/AggregationField.tsx index 546dce7abcd..b71bdd152ed 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/AggregationField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/AggregationField.tsx @@ -44,7 +44,6 @@ const AggregationField: React.FC = ({ value={query.azureMonitor?.aggregation} onChange={handleChange} options={options} - width={38} isLoading={isLoading} /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.test.tsx index 702f806fa9e..6fc76be570d 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.test.tsx @@ -9,7 +9,6 @@ import createMockPanelData from '../../__mocks__/panelData'; import createMockQuery from '../../__mocks__/query'; import DimensionFields from './DimensionFields'; -import NewDimensionFields from './NewDimensionFields'; import { appendDimensionFilter, setDimensionFilterValue } from './setQueryValue'; const variableOptionGroup = { @@ -18,365 +17,346 @@ const variableOptionGroup = { }; const user = userEvent.setup(); -const tests = [ - { - component: DimensionFields, - label: 'Dimension Fields', - addDimension: async () => { - const addDimension = await screen.findByText('Add new dimension'); - await user.click(addDimension); - }, - }, - { - component: NewDimensionFields, - label: 'Dimension Fields experimental UI', - addDimension: async () => { - const addDimension = await screen.findByLabelText('Add'); - await user.click(addDimension); - }, - }, -]; +describe(`Azure Monitor QueryEditor`, () => { + const mockDatasource = createMockDatasource(); -for (const t of tests) { - describe(`Azure Monitor QueryEditor: ${t.label}`, () => { - const mockDatasource = createMockDatasource(); + it('should render a dimension filter', async () => { + let mockQuery = createMockQuery(); + const mockPanelData = createMockPanelData(); + const onQueryChange = jest.fn(); + const dimensionOptions = [ + { label: 'Test Dimension 1', value: 'TestDimension1' }, + { label: 'Test Dimension 2', value: 'TestDimension2' }, + ]; + const { rerender } = render( + {}} + dimensionOptions={dimensionOptions} + /> + ); - it('should render a dimension filter', async () => { - let mockQuery = createMockQuery(); - const mockPanelData = createMockPanelData(); - const onQueryChange = jest.fn(); - const dimensionOptions = [ - { label: 'Test Dimension 1', value: 'TestDimension1' }, - { label: 'Test Dimension 2', value: 'TestDimension2' }, - ]; - const { rerender } = render( - {}} - dimensionOptions={dimensionOptions} - /> - ); + const addDimension = await screen.findByLabelText('Add'); + await user.click(addDimension); - await t.addDimension(); - - mockQuery = appendDimensionFilter(mockQuery); - expect(onQueryChange).toHaveBeenCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - dimensionFilters: [{ dimension: '', operator: 'eq', filters: [] }], - }, - }); - rerender( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const dimensionSelect = await screen.findByText('Field'); - await selectOptionInTest(dimensionSelect, 'Test Dimension 1'); - expect(onQueryChange).toHaveBeenCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], - }, - }); - expect(screen.queryByText('Test Dimension 1')).toBeInTheDocument(); - expect(screen.queryByText('==')).toBeInTheDocument(); + mockQuery = appendDimensionFilter(mockQuery); + expect(onQueryChange).toHaveBeenCalledWith({ + ...mockQuery, + azureMonitor: { + ...mockQuery.azureMonitor, + dimensionFilters: [{ dimension: '', operator: 'eq', filters: [] }], + }, }); - - it('correctly filters out dimensions when selected', async () => { - let mockQuery = createMockQuery(); - const mockPanelData = createMockPanelData(); - mockQuery.azureMonitor = { + rerender( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const dimensionSelect = await screen.findByText('Field'); + await selectOptionInTest(dimensionSelect, 'Test Dimension 1'); + expect(onQueryChange).toHaveBeenCalledWith({ + ...mockQuery, + azureMonitor: { ...mockQuery.azureMonitor, dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], - }; - const onQueryChange = jest.fn(); - const dimensionOptions = [ - { label: 'Test Dimension 1', value: 'TestDimension1' }, - { label: 'Test Dimension 2', value: 'TestDimension2' }, - ]; - const { rerender } = render( - {}} - dimensionOptions={dimensionOptions} - /> - ); - - await t.addDimension(); - - mockQuery = appendDimensionFilter(mockQuery); - rerender( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const dimensionSelect = await screen.findByText('Field'); - await user.click(dimensionSelect); - const options = await screen.findAllByLabelText('Select option'); - expect(options).toHaveLength(1); - expect(options[0]).toHaveTextContent('Test Dimension 2'); + }, }); + expect(screen.queryByText('Test Dimension 1')).toBeInTheDocument(); + expect(screen.queryByText('==')).toBeInTheDocument(); + }); - it('correctly displays dimension labels', async () => { - let mockQuery = createMockQuery(); - const mockPanelData = createMockPanelData(); - mockQuery.azureMonitor = { + it('correctly filters out dimensions when selected', async () => { + let mockQuery = createMockQuery(); + const mockPanelData = createMockPanelData(); + mockQuery.azureMonitor = { + ...mockQuery.azureMonitor, + dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], + }; + const onQueryChange = jest.fn(); + const dimensionOptions = [ + { label: 'Test Dimension 1', value: 'TestDimension1' }, + { label: 'Test Dimension 2', value: 'TestDimension2' }, + ]; + const { rerender } = render( + {}} + dimensionOptions={dimensionOptions} + /> + ); + + const addDimension = await screen.findByLabelText('Add'); + await user.click(addDimension); + + mockQuery = appendDimensionFilter(mockQuery); + rerender( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const dimensionSelect = await screen.findByText('Field'); + await user.click(dimensionSelect); + const options = await screen.findAllByLabelText('Select option'); + expect(options).toHaveLength(1); + expect(options[0]).toHaveTextContent('Test Dimension 2'); + }); + + it('correctly displays dimension labels', async () => { + let mockQuery = createMockQuery(); + const mockPanelData = createMockPanelData(); + mockQuery.azureMonitor = { + ...mockQuery.azureMonitor, + dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], + }; + + mockPanelData.series = [ + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel' }, + }, + ], + }, + ]; + const onQueryChange = jest.fn(); + const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; + render( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const labelSelect = await screen.findByText('Select value(s)'); + await user.click(labelSelect); + const options = await screen.findAllByLabelText('Select option'); + expect(options).toHaveLength(1); + expect(options[0]).toHaveTextContent('testlabel'); + }); + + it('correctly updates dimension labels', async () => { + let mockQuery = createMockQuery(); + const mockPanelData = createMockPanelData(); + mockQuery.azureMonitor = { + ...mockQuery.azureMonitor, + dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: ['testlabel'] }], + }; + + mockPanelData.series = [ + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel' }, + }, + ], + }, + ]; + const onQueryChange = jest.fn(); + const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; + const { rerender } = render( + {}} + dimensionOptions={dimensionOptions} + /> + ); + await screen.findByText('testlabel'); + const labelClear = await screen.findByLabelText('Remove testlabel'); + await user.click(labelClear); + mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', []); + expect(onQueryChange).toHaveBeenCalledWith({ + ...mockQuery, + azureMonitor: { ...mockQuery.azureMonitor, dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], - }; - - mockPanelData.series = [ - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel' }, - }, - ], - }, - ]; - const onQueryChange = jest.fn(); - const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; - render( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const labelSelect = await screen.findByText('Select value(s)'); - await user.click(labelSelect); - const options = await screen.findAllByLabelText('Select option'); - expect(options).toHaveLength(1); - expect(options[0]).toHaveTextContent('testlabel'); + }, }); + mockPanelData.series = [ + ...mockPanelData.series, + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel2' }, + }, + ], + }, + ]; + rerender( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const labelSelect = screen.getByLabelText('dimension-labels-select'); + await openMenu(labelSelect); + const options = await screen.findAllByLabelText('Select option'); + expect(options).toHaveLength(2); + expect(options[0]).toHaveTextContent('testlabel'); + expect(options[1]).toHaveTextContent('testlabel2'); + }); - it('correctly updates dimension labels', async () => { - let mockQuery = createMockQuery(); - const mockPanelData = createMockPanelData(); - mockQuery.azureMonitor = { + it('correctly selects multiple dimension labels', async () => { + let mockQuery = createMockQuery(); + const mockPanelData = createMockPanelData(); + mockPanelData.series = [ + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel' }, + }, + ], + }, + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel2' }, + }, + ], + }, + ]; + const onQueryChange = jest.fn(); + const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; + mockQuery = appendDimensionFilter(mockQuery, 'TestDimension1'); + const { rerender } = render( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const labelSelect = screen.getByLabelText('dimension-labels-select'); + await user.click(labelSelect); + await openMenu(labelSelect); + screen.getByText('testlabel'); + screen.getByText('testlabel2'); + await selectOptionInTest(labelSelect, 'testlabel'); + mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', ['testlabel']); + expect(onQueryChange).toHaveBeenCalledWith({ + ...mockQuery, + azureMonitor: { ...mockQuery.azureMonitor, dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: ['testlabel'] }], - }; - - mockPanelData.series = [ - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel' }, - }, - ], - }, - ]; - const onQueryChange = jest.fn(); - const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; - const { rerender } = render( - {}} - dimensionOptions={dimensionOptions} - /> - ); - await screen.findByText('testlabel'); - const labelClear = await screen.findByLabelText('Remove testlabel'); - await user.click(labelClear); - mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', []); - expect(onQueryChange).toHaveBeenCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: [] }], - }, - }); - mockPanelData.series = [ - ...mockPanelData.series, - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel2' }, - }, - ], - }, - ]; - rerender( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const labelSelect = screen.getByLabelText('dimension-labels-select'); - await openMenu(labelSelect); - const options = await screen.findAllByLabelText('Select option'); - expect(options).toHaveLength(2); - expect(options[0]).toHaveTextContent('testlabel'); - expect(options[1]).toHaveTextContent('testlabel2'); + }, }); - - it('correctly selects multiple dimension labels', async () => { - let mockQuery = createMockQuery(); - const mockPanelData = createMockPanelData(); - mockPanelData.series = [ - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel' }, - }, - ], - }, - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel2' }, - }, - ], - }, - ]; - const onQueryChange = jest.fn(); - const dimensionOptions = [{ label: 'Test Dimension 1', value: 'TestDimension1' }]; - mockQuery = appendDimensionFilter(mockQuery, 'TestDimension1'); - const { rerender } = render( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const labelSelect = screen.getByLabelText('dimension-labels-select'); - await user.click(labelSelect); - await openMenu(labelSelect); - screen.getByText('testlabel'); - screen.getByText('testlabel2'); - await selectOptionInTest(labelSelect, 'testlabel'); - mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', ['testlabel']); - expect(onQueryChange).toHaveBeenCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: ['testlabel'] }], - }, - }); - mockPanelData.series = [ - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel' }, - }, - ], - }, - ]; - rerender( - {}} - dimensionOptions={dimensionOptions} - /> - ); - const labelSelect2 = screen.getByLabelText('dimension-labels-select'); - await openMenu(labelSelect2); - const refreshedOptions = await screen.findAllByLabelText('Select options menu'); - expect(refreshedOptions).toHaveLength(1); - expect(refreshedOptions[0]).toHaveTextContent('testlabel2'); - await selectOptionInTest(labelSelect2, 'testlabel2'); - mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', ['testlabel', 'testlabel2']); - expect(onQueryChange).toHaveBeenCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: ['testlabel', 'testlabel2'] }], - }, - }); - mockPanelData.series = [ - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel' }, - }, - ], - }, - { - ...mockPanelData.series[0], - fields: [ - { - ...mockPanelData.series[0].fields[0], - name: 'Test Dimension 1', - labels: { testdimension1: 'testlabel2' }, - }, - ], - }, - ]; + mockPanelData.series = [ + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel' }, + }, + ], + }, + ]; + rerender( + {}} + dimensionOptions={dimensionOptions} + /> + ); + const labelSelect2 = screen.getByLabelText('dimension-labels-select'); + await openMenu(labelSelect2); + const refreshedOptions = await screen.findAllByLabelText('Select options menu'); + expect(refreshedOptions).toHaveLength(1); + expect(refreshedOptions[0]).toHaveTextContent('testlabel2'); + await selectOptionInTest(labelSelect2, 'testlabel2'); + mockQuery = setDimensionFilterValue(mockQuery, 0, 'filters', ['testlabel', 'testlabel2']); + expect(onQueryChange).toHaveBeenCalledWith({ + ...mockQuery, + azureMonitor: { + ...mockQuery.azureMonitor, + dimensionFilters: [{ dimension: 'TestDimension1', operator: 'eq', filters: ['testlabel', 'testlabel2'] }], + }, }); + mockPanelData.series = [ + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel' }, + }, + ], + }, + { + ...mockPanelData.series[0], + fields: [ + { + ...mockPanelData.series[0].fields[0], + name: 'Test Dimension 1', + labels: { testdimension1: 'testlabel2' }, + }, + ], + }, + ]; }); -} +}); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.tsx index 110fdcc2837..dc73e3389bb 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/DimensionFields.tsx @@ -1,12 +1,13 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { SelectableValue, DataFrame, PanelData } from '@grafana/data'; -import { Button, Select, HorizontalGroup, VerticalGroup, MultiSelect } from '@grafana/ui'; +import { SelectableValue, DataFrame, PanelData, Labels } from '@grafana/data'; +import { AccessoryButton, EditorList } from '@grafana/experimental'; +import { Select, HorizontalGroup, MultiSelect } from '@grafana/ui'; import { AzureMetricDimension, AzureMonitorOption, AzureMonitorQuery, AzureQueryEditorFieldProps } from '../../types'; import { Field } from '../Field'; -import { appendDimensionFilter, removeDimensionFilter, setDimensionFilterValue } from './setQueryValue'; +import { setDimensionFilters } from './setQueryValue'; interface DimensionFieldsProps extends AzureQueryEditorFieldProps { dimensionOptions: AzureMonitorOption[]; @@ -28,16 +29,14 @@ const useDimensionLabels = (data: PanelData | undefined, query: AzureMonitorQuer const labels = fields .map((fields) => fields.labels) .flat() - .filter((item) => item!); + .filter((item): item is Labels => item !== null && item !== undefined); for (const label of labels) { // Labels only exist for series that have a dimension selected - if (label) { - for (const [dimension, value] of Object.entries(label)) { - if (labelsObj[dimension]) { - labelsObj[dimension].add(value); - } else { - labelsObj[dimension] = new Set([value]); - } + for (const [dimension, value] of Object.entries(label)) { + if (labelsObj[dimension]) { + labelsObj[dimension].add(value); + } else { + labelsObj[dimension] = new Set([value]); } } } @@ -87,24 +86,14 @@ const DimensionFields: React.FC = ({ data, query, dimensio return t; }, [dimensionFilters, dimensionOptions]); - const addFilter = () => { - onQueryChange(appendDimensionFilter(query)); - }; - - const removeFilter = (index: number) => { - onQueryChange(removeDimensionFilter(query, index)); - }; - const onFieldChange = ( - filterIndex: number, fieldName: Key, - value: AzureMetricDimension[Key] + item: Partial, + value: AzureMetricDimension[Key], + onChange: (item: Partial) => void ) => { - onQueryChange(setDimensionFilterValue(query, filterIndex, fieldName, value)); - }; - - const onFilterInputChange = (index: number, v: SelectableValue | null) => { - onFieldChange(index, 'filters', [v?.value ?? '']); + item[fieldName] = value; + onChange(item); }; const getValidDimensionOptions = (selectedDimension: string) => { @@ -133,7 +122,6 @@ const DimensionFields: React.FC = ({ data, query, dimensio } return labelOptions; }; - const getValidOperators = (selectedOperator: string) => { if (dimensionOperators.find((operator: SelectableValue) => operator.value === selectedOperator)) { return dimensionOperators; @@ -141,70 +129,76 @@ const DimensionFields: React.FC = ({ data, query, dimensio return [...dimensionOperators, ...(selectedOperator ? [{ label: selectedOperator, value: selectedOperator }] : [])]; }; - const onMultiSelectFilterChange = (index: number, v: Array>) => { - onFieldChange( - index, - 'filters', - v.map((item) => item.value || '') + const changedFunc = (changed: Array>) => { + const properData: AzureMetricDimension[] = changed.map((x) => { + return { + dimension: x.dimension ?? '', + operator: x.operator ?? 'eq', + filters: x.filters ?? [], + }; + }); + onQueryChange(setDimensionFilters(query, properData)); + }; + + const renderFilters = ( + item: Partial, + onChange: (item: Partial) => void, + onDelete: () => void + ) => { + return ( + + onFieldChange('operator', item, e.value ?? '', onChange)} + allowCustomValue + /> + {item.operator === 'eq' || item.operator === 'ne' ? ( + + onFieldChange( + 'filters', + item, + e.map((x) => x.value ?? ''), + onChange + ) + } + aria-label={'dimension-labels-select'} + allowCustomValue + /> + ) : ( + // The API does not currently allow for multiple "starts with" clauses to be used. + onFieldChange(index, 'dimension', v.value ?? '')} - width={38} - /> - onFilterInputChange(index, v)} - isClearable - /> - )} - - - ))} - - - + + ); }; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNameField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNameField.tsx index 8bea29bfcb2..0148ded08d6 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNameField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNameField.tsx @@ -34,7 +34,6 @@ const MetricNameField: React.FC = ({ metricNames, query, variab value={query.azureMonitor?.metricName ?? null} onChange={handleChange} options={options} - width={38} allowCustomValue /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.tsx index 72a81ef6a69..94a62c07735 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.tsx @@ -46,7 +46,6 @@ const MetricNamespaceField: React.FC = ({ value={query.azureMonitor?.metricNamespace} onChange={handleChange} options={options} - width={38} allowCustomValue /> 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 0a0f60ebaa2..b42d4e11741 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 '@grafana/runtime'; - import createMockDatasource from '../../__mocks__/datasource'; import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings'; import createMockPanelData from '../../__mocks__/panelData'; @@ -23,15 +21,6 @@ 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()); @@ -46,215 +35,210 @@ export function createMockResourcePickerData() { return mockDatasource; } -for (const t of tests) { - describe(`MetricsQueryEditor: ${t.id}`, () => { - const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; - const mockPanelData = createMockPanelData(); +describe('MetricsQueryEditor', () => { + const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; + const mockPanelData = createMockPanelData(); - 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; - }); + beforeEach(() => { + window.HTMLElement.prototype.scrollIntoView = function () {}; + }); + afterEach(() => { + window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView; + }); - it('should render', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + it('should render', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - render( - {}} - setError={() => {}} - /> - ); + render( + {}} + setError={() => {}} + /> + ); - expect(await screen.findByTestId(t.id)).toBeInTheDocument(); - }); + expect(await screen.findByTestId('azure-monitor-metrics-query-editor-with-experimental-ui')).toBeInTheDocument(); + }); - 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(); + 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(); - render( - {}} - /> - ); + render( + {}} + /> + ); - 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 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 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 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 resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - expect(resourceGroupButton).toBeInTheDocument(); - expect(screen.queryByLabelText('web-server')).not.toBeInTheDocument(); - resourceGroupButton.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 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 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' })); - 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', - }), - }) - ); - }); + 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', + }), + }) + ); + }); - 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(); + 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(); - render( - {}} - /> - ); + render( + {}} + /> + ); - const resourcePickerButton = await screen.findByRole('button', { name: /grafana/ }); + const resourcePickerButton = await screen.findByRole('button', { name: /grafana/ }); - expect(screen.getByText('Microsoft.Compute/virtualMachines')).toBeInTheDocument(); - expect(screen.getByText('Metric A')).toBeInTheDocument(); - expect(screen.getByText('Average')).toBeInTheDocument(); + expect(screen.getByText('Microsoft.Compute/virtualMachines')).toBeInTheDocument(); + expect(screen.getByText('Metric A')).toBeInTheDocument(); + expect(screen.getByText('Average')).toBeInTheDocument(); - expect(resourcePickerButton).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); - resourcePickerButton.click(); + expect(resourcePickerButton).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Expand Primary Subscription' })).not.toBeInTheDocument(); + resourcePickerButton.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 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 resourceGroupButton = await screen.findByRole('button', { name: 'Expand Development 3' }); - expect(resourceGroupButton).toBeInTheDocument(); - expect(screen.queryByLabelText('db-server')).not.toBeInTheDocument(); - resourceGroupButton.click(); + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand Development 3' }); + expect(resourceGroupButton).toBeInTheDocument(); + expect(screen.queryByLabelText('db-server')).not.toBeInTheDocument(); + resourceGroupButton.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 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', + 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 aggregation type when selected', async () => { - const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); - const onChange = jest.fn(); - const mockQuery = createMockQuery(); + 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( - {}} - /> - ); + render( + {}} + /> + ); - const aggregation = await screen.findByLabelText('Aggregation'); - expect(aggregation).toBeInTheDocument(); - await selectOptionInTest(aggregation, 'Maximum'); + const metrics = await screen.findByLabelText('Metric'); + expect(metrics).toBeInTheDocument(); + await selectOptionInTest(metrics, 'Metric B'); - expect(onChange).toHaveBeenLastCalledWith({ - ...mockQuery, - azureMonitor: { - ...mockQuery.azureMonitor, - aggregation: 'Maximum', - }, - }); + expect(onChange).toHaveBeenLastCalledWith({ + ...mockQuery, + azureMonitor: { + ...mockQuery.azureMonitor, + metricName: 'metric-b', + aggregation: undefined, + timeGrain: '', + }, }); }); -} + + 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/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx index 528b8c74b66..e500304d34b 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 @@ -1,10 +1,7 @@ -import { css } from '@emotion/css'; 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, useStyles2 } from '@grafana/ui'; import type Datasource from '../../datasource'; import type { AzureMonitorQuery, AzureMonitorOption, AzureMonitorErrorish } from '../../types'; @@ -16,7 +13,6 @@ import DimensionFields from './DimensionFields'; import LegendFormatField from './LegendFormatField'; import MetricNameField from './MetricNameField'; import MetricNamespaceField from './MetricNamespaceField'; -import NewDimensionFields from './NewDimensionFields'; import TimeGrainField from './TimeGrainField'; import TopField from './TopField'; import { useMetricNames, useMetricNamespaces, useMetricMetadata } from './dataHooks'; @@ -39,187 +35,94 @@ const MetricsQueryEditor: React.FC = ({ onChange, setError, }) => { - const styles = useStyles2(getStyles); - const metricsMetadata = useMetricMetadata(query, datasource, onChange); const metricNamespaces = useMetricNamespaces(query, datasource, onChange, setError); const metricNames = useMetricNames(query, datasource, onChange, setError); - if (config.featureToggles.azureMonitorExperimentalUI) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } else { - return ( -
- - - - - - - - - - - - - - - -
- ); - } + return ( + + + + + + + + + + + + + + + + + + + + + + + + + ); }; -const getStyles = () => ({ - row: css({ - rowGap: 0, - }), -}); - export default MetricsQueryEditor; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/NewDimensionFields.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/NewDimensionFields.tsx deleted file mode 100644 index 8531fcd3457..00000000000 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/NewDimensionFields.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; - -import { SelectableValue, DataFrame, PanelData, Labels } from '@grafana/data'; -import { AccessoryButton, EditorList } from '@grafana/experimental'; -import { Select, HorizontalGroup, MultiSelect } from '@grafana/ui'; - -import { AzureMetricDimension, AzureMonitorOption, AzureMonitorQuery, AzureQueryEditorFieldProps } from '../../types'; -import { Field } from '../Field'; - -import { setDimensionFilters } from './setQueryValue'; - -interface DimensionFieldsProps extends AzureQueryEditorFieldProps { - dimensionOptions: AzureMonitorOption[]; -} - -interface DimensionLabels { - [key: string]: Set; -} - -const useDimensionLabels = (data: PanelData | undefined, query: AzureMonitorQuery) => { - const [dimensionLabels, setDimensionLabels] = useState({}); - useEffect(() => { - let labelsObj: DimensionLabels = {}; - if (data?.series?.length) { - // Identify which series' in the dataframe are relevant to the current query - const series: DataFrame[] = data.series.flat().filter((series) => series.refId === query.refId); - const fields = series.flatMap((series) => series.fields); - // Retrieve labels for series fields - const labels = fields - .map((fields) => fields.labels) - .flat() - .filter((item): item is Labels => item !== null && item !== undefined); - for (const label of labels) { - // Labels only exist for series that have a dimension selected - for (const [dimension, value] of Object.entries(label)) { - if (labelsObj[dimension]) { - labelsObj[dimension].add(value); - } else { - labelsObj[dimension] = new Set([value]); - } - } - } - } - setDimensionLabels((prevLabels) => { - const newLabels: DimensionLabels = {}; - const currentLabels = Object.keys(labelsObj); - if (currentLabels.length === 0) { - return prevLabels; - } - for (const label of currentLabels) { - if (prevLabels[label] && labelsObj[label].size < prevLabels[label].size) { - newLabels[label] = prevLabels[label]; - } else { - newLabels[label] = labelsObj[label]; - } - } - return newLabels; - }); - }, [data?.series, query.refId]); - return dimensionLabels; -}; - -const NewDimensionFields: React.FC = ({ data, query, dimensionOptions, onQueryChange }) => { - const dimensionFilters = useMemo( - () => query.azureMonitor?.dimensionFilters ?? [], - [query.azureMonitor?.dimensionFilters] - ); - - const dimensionLabels = useDimensionLabels(data, query); - - const dimensionOperators: Array> = [ - { label: '==', value: 'eq' }, - { label: '!=', value: 'ne' }, - { label: 'starts with', value: 'sw' }, - ]; - - const validDimensionOptions = useMemo(() => { - // We filter out any dimensions that have already been used in a filter as the API doesn't support having multiple filters with the same dimension name. - // The Azure portal also doesn't support this feature so it makes sense for consistency. - let t = dimensionOptions; - if (dimensionFilters.length) { - t = dimensionOptions.filter( - (val) => !dimensionFilters.some((dimensionFilter) => dimensionFilter.dimension === val.value) - ); - } - return t; - }, [dimensionFilters, dimensionOptions]); - - const onFieldChange = ( - fieldName: Key, - item: Partial, - value: AzureMetricDimension[Key], - onChange: (item: Partial) => void - ) => { - item[fieldName] = value; - onChange(item); - }; - - const getValidDimensionOptions = (selectedDimension: string) => { - return validDimensionOptions.concat(dimensionOptions.filter((item) => item.value === selectedDimension)); - }; - - const getValidFilterOptions = (selectedFilter: string | undefined, dimension: string) => { - const dimensionFilters = Array.from(dimensionLabels[dimension.toLowerCase()] ?? []); - if (dimensionFilters.find((filter) => filter === selectedFilter)) { - return dimensionFilters.map((filter) => ({ value: filter, label: filter })); - } - return [...dimensionFilters, ...(selectedFilter && selectedFilter !== '*' ? [selectedFilter] : [])].map((item) => ({ - value: item, - label: item, - })); - }; - - const getValidMultiSelectOptions = (selectedFilters: string[] | undefined, dimension: string) => { - const labelOptions = getValidFilterOptions(undefined, dimension); - if (selectedFilters) { - for (const filter of selectedFilters) { - if (!labelOptions.find((label) => label.value === filter)) { - labelOptions.push({ value: filter, label: filter }); - } - } - } - return labelOptions; - }; - const getValidOperators = (selectedOperator: string) => { - if (dimensionOperators.find((operator: SelectableValue) => operator.value === selectedOperator)) { - return dimensionOperators; - } - return [...dimensionOperators, ...(selectedOperator ? [{ label: selectedOperator, value: selectedOperator }] : [])]; - }; - - const changedFunc = (changed: Array>) => { - const properData: AzureMetricDimension[] = changed.map((x) => { - return { - dimension: x.dimension ?? '', - operator: x.operator ?? 'eq', - filters: x.filters ?? [], - }; - }); - onQueryChange(setDimensionFilters(query, properData)); - }; - - const renderFilters = ( - item: Partial, - onChange: (item: Partial) => void, - onDelete: () => void - ) => { - return ( - - onFieldChange('operator', item, e.value ?? '', onChange)} - allowCustomValue - /> - {item.operator === 'eq' || item.operator === 'ne' ? ( - - onFieldChange( - 'filters', - item, - e.map((x) => x.value ?? ''), - onChange - ) - } - aria-label={'dimension-labels-select'} - allowCustomValue - /> - ) : ( - // The API does not currently allow for multiple "starts with" clauses to be used. - - - ); -}; - -export default QueryTypeField;