diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.test.tsx new file mode 100644 index 00000000000..7fbd74de615 --- /dev/null +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricNamespaceField.test.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import MetricNamespaceField from './MetricNamespaceField'; +import createMockQuery from '../../__mocks__/query'; +import createMockDatasource from '../../__mocks__/datasource'; +import { AzureMonitorOption } from '../../types'; + +const props = { + metricNamespaces: [], + query: createMockQuery(), + datasource: createMockDatasource(), + variableOptionGroup: { label: 'Templates', options: [] }, + onQueryChange: jest.fn(), + setError: jest.fn(), +}; + +describe('Azure Monitor QueryEditor', () => { + it('should render the current value', async () => { + const metricNamespaces: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }]; + const query = { + ...props.query, + azureMonitor: { + metricNamespace: 'foo', + }, + }; + render(); + expect(screen.queryByText('foo')).toBeInTheDocument(); + }); + + it('should render the current value even if it is not in the list of options', async () => { + const metricNamespaces: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }]; + const query = { + ...props.query, + azureMonitor: { + metricNamespace: 'bar', + }, + }; + render(); + expect(screen.queryByText('bar')).toBeInTheDocument(); + expect(screen.queryByText('foo')).not.toBeInTheDocument(); + }); +}); 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 99f2a365e8f..7d7992045c5 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 @@ -29,6 +29,11 @@ const MetricNamespaceField: React.FC = ({ ); const options = useMemo(() => [...metricNamespaces, variableOptionGroup], [metricNamespaces, variableOptionGroup]); + const optionValues = metricNamespaces.map((m) => m.value).concat(variableOptionGroup.options.map((p) => p.value)); + const value = query.azureMonitor?.metricNamespace; + if (value && !optionValues.includes(value)) { + options.push({ label: value, value }); + } return ( diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts index 22a9af6cabb..e47ff20776f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts @@ -5,6 +5,7 @@ import { updateSubscriptions, useAsyncState, useMetricNames, + useMetricNamespaces, useResourceGroups, useResourceNames, useResourceTypes, @@ -93,7 +94,7 @@ interface TestScenario { invalidQueryPartial: AzureMetricQuery; templateVariableQueryPartial: AzureMetricQuery; - expectedClearedQueryPartial: AzureMetricQuery; + expectedClearedQueryPartial?: AzureMetricQuery; expectedOptions: AzureMonitorOption[]; } @@ -253,6 +254,47 @@ describe('AzureMonitor: metrics dataHooks', () => { metricName: undefined, }, }, + + { + name: 'useMetricNamespaces', + hook: useMetricNamespaces, + emptyQueryPartial: { + resourceGroup: 'web-app-development', + metricDefinition: 'azure/vm', + resourceName: 'web-server', + metricNamespace: 'azure/vm', + }, + validQueryPartial: { + resourceGroup: 'web-app-development', + metricDefinition: 'azure/vm', + resourceName: 'web-server', + metricNamespace: 'azure/vm', + }, + invalidQueryPartial: { + resourceGroup: 'web-app-development', + metricDefinition: 'azure/vm', + resourceName: 'web-server', + metricNamespace: 'azure/vm', + metricName: 'invalid-metric', + }, + templateVariableQueryPartial: { + resourceGroup: 'web-app-development', + metricDefinition: 'azure/vm', + resourceName: 'web-server', + metricNamespace: 'azure/vm', + metricName: '$variable', + }, + expectedOptions: [ + { + label: 'Compute Virtual Machine', + value: 'azure/vmc', + }, + { + label: 'Database NS', + value: 'azure/dbns', + }, + ], + }, ]; let datasource: MockedObjectDeep; @@ -284,8 +326,11 @@ describe('AzureMonitor: metrics dataHooks', () => { datasource.getMetricNames = jest .fn() .mockResolvedValue([opt('Percentage CPU', 'percentage-cpu'), opt('Free memory', 'free-memory')]); - }); + datasource.getMetricNamespaces = jest + .fn() + .mockResolvedValue([opt('Compute Virtual Machine', 'azure/vmc'), opt('Database NS', 'azure/dbns')]); + }); describe.each(testTable)('scenario %#: $name', (scenario) => { it('returns values', async () => { const query = { @@ -339,14 +384,18 @@ describe('AzureMonitor: metrics dataHooks', () => { const { waitForNextUpdate } = renderHook(() => scenario.hook(query, datasource, onChange, setError)); await waitForNextUpdate(WAIT_OPTIONS); - expect(onChange).toHaveBeenCalledWith({ - ...query, - azureMonitor: { - ...scenario.expectedClearedQueryPartial, - dimensionFilters: [], - timeGrain: '', - }, - }); + if (scenario.expectedClearedQueryPartial) { + expect(onChange).toHaveBeenCalledWith({ + ...query, + azureMonitor: { + ...scenario.expectedClearedQueryPartial, + dimensionFilters: [], + timeGrain: '', + }, + }); + } else { + expect(onChange).not.toHaveBeenCalled(); + } }); }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.ts index 0977360cec1..7a6d1c1458f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.ts @@ -193,8 +193,6 @@ export const useMetricNamespaces: DataHook = (query, datasource, onChange, setEr // Do some cleanup of the query state if need be if (!metricNamespace && options.length) { onChange(setMetricNamespace(query, options[0].value)); - } else if (options[0] && isInvalidOption(metricNamespace, options, datasource.getVariables())) { - onChange(setMetricNamespace(query, options[0].value)); } return options;