From c4c7908f51368f54a6cdc1efd7fac8106c19b22d Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Wed, 13 Jul 2022 11:16:16 +0200 Subject: [PATCH] AzureMonitor: Add support for Subscriptions template variable (#52086) --- .../GrafanaTemplateVariableFn.tsx | 59 ++++++++++ .../VariableEditor/VariableEditor.test.tsx | 102 ++++++++++-------- .../VariableEditor/VariableEditor.tsx | 76 ++++--------- .../types/query.ts | 2 + .../variables.test.ts | 24 +++++ .../variables.ts | 31 ++++-- 6 files changed, 179 insertions(+), 115 deletions(-) create mode 100644 public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/GrafanaTemplateVariableFn.tsx diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/GrafanaTemplateVariableFn.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/GrafanaTemplateVariableFn.tsx new file mode 100644 index 00000000000..35fd3707468 --- /dev/null +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/GrafanaTemplateVariableFn.tsx @@ -0,0 +1,59 @@ +import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; + +import { InlineField, Input } from '@grafana/ui'; + +import DataSource from '../../datasource'; +import { migrateStringQueriesToObjectQueries } from '../../grafanaTemplateVariableFns'; +import { AzureMonitorQuery, AzureQueryType } from '../../types'; + +const GrafanaTemplateVariableFnInput = ({ + query, + updateQuery, + datasource, +}: { + query: AzureMonitorQuery; + updateQuery: (val: AzureMonitorQuery) => void; + datasource: DataSource; +}) => { + const [inputVal, setInputVal] = useState(''); + + useEffect(() => { + setInputVal(query.grafanaTemplateVariableFn?.rawQuery || ''); + }, [query.grafanaTemplateVariableFn?.rawQuery]); + + const onRunQuery = useCallback( + (newQuery: string) => { + migrateStringQueriesToObjectQueries(newQuery, { datasource }).then((updatedQuery) => { + if (updatedQuery.queryType === AzureQueryType.GrafanaTemplateVariableFn) { + updateQuery(updatedQuery); + } else { + updateQuery({ + ...query, + grafanaTemplateVariableFn: { + kind: 'UnknownQuery', + rawQuery: newQuery, + }, + }); + } + }); + }, + [datasource, query, updateQuery] + ); + + const onChange = (event: ChangeEvent) => { + setInputVal(event.target.value); + }; + + return ( + + onRunQuery(inputVal)} + /> + + ); +}; + +export default GrafanaTemplateVariableFnInput; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.test.tsx index f3e7ada507d..d8b9279bffd 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/VariableEditor/VariableEditor.test.tsx @@ -1,8 +1,9 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { select } from 'react-select-event'; +import { select, openMenu } from 'react-select-event'; +import * as grafanaRuntime from '@grafana/runtime'; import * as ui from '@grafana/ui'; import createMockDatasource from '../../__mocks__/datasource'; @@ -18,23 +19,28 @@ jest.mock('@grafana/ui', () => ({ }, })); +const defaultProps = { + query: { + refId: 'A', + queryType: AzureQueryType.LogAnalytics, + azureLogAnalytics: { + query: 'test query', + }, + subscription: 'id', + }, + onChange: jest.fn(), + datasource: createMockDatasource(), +}; + +const originalConfigValue = grafanaRuntime.config.featureToggles.azTemplateVars; +beforeEach(() => { + // reset config + grafanaRuntime.config.featureToggles.azTemplateVars = originalConfigValue; +}); + describe('VariableEditor:', () => { it('can select a query type', async () => { - const onChange = jest.fn(); - - const props = { - query: { - refId: 'A', - queryType: AzureQueryType.LogAnalytics, - azureLogAnalytics: { - query: 'test query', - }, - subscription: 'id', - }, - onChange, - datasource: createMockDatasource(), - }; - render(); + render(); await waitFor(() => screen.getByLabelText('select query type')); expect(screen.getByLabelText('select query type')).toBeInTheDocument(); screen.getByLabelText('select query type').click(); @@ -46,19 +52,7 @@ describe('VariableEditor:', () => { }); describe('log queries:', () => { it('should render', async () => { - const props = { - query: { - refId: 'A', - queryType: AzureQueryType.LogAnalytics, - azureLogAnalytics: { - query: 'test query', - }, - subscription: 'id', - }, - onChange: () => {}, - datasource: createMockDatasource(), - }; - render(); + render(); await waitFor(() => screen.queryByTestId('mockeditor')); expect(screen.queryByText('Resource')).toBeInTheDocument(); expect(screen.queryByTestId('mockeditor')).toBeInTheDocument(); @@ -75,24 +69,14 @@ describe('VariableEditor:', () => { expect(screen.queryByText('Resource')).toBeInTheDocument(); expect(screen.queryByTestId('mockeditor')).toBeInTheDocument(); }); + it('should call on change if the query changes', async () => { - const props = { - query: { - refId: 'A', - queryType: AzureQueryType.LogAnalytics, - azureLogAnalytics: { - query: 'test query', - }, - subscription: 'id', - }, - onChange: jest.fn(), - datasource: createMockDatasource(), - }; - render(); + const onChange = jest.fn(); + render(); await waitFor(() => screen.queryByTestId('mockeditor')); expect(screen.queryByTestId('mockeditor')).toBeInTheDocument(); await userEvent.type(screen.getByTestId('mockeditor'), '{backspace}'); - expect(props.onChange).toHaveBeenCalledWith({ + expect(onChange).toHaveBeenCalledWith({ azureLogAnalytics: { query: 'test quer', }, @@ -106,6 +90,7 @@ describe('VariableEditor:', () => { describe('grafana template variable fn queries:', () => { it('should render', async () => { const props = { + ...defaultProps, query: { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, @@ -115,8 +100,6 @@ describe('VariableEditor:', () => { }, subscription: 'id', } as AzureMonitorQuery, - onChange: () => {}, - datasource: createMockDatasource(), }; render(); await waitFor(() => screen.queryByText('Grafana template variable function')); @@ -126,6 +109,7 @@ describe('VariableEditor:', () => { it('should call on change if the query changes', async () => { const props = { + ...defaultProps, query: { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, @@ -135,8 +119,6 @@ describe('VariableEditor:', () => { }, subscription: 'subscriptionId', } as AzureMonitorQuery, - onChange: jest.fn(), - datasource: createMockDatasource(), }; render(); await waitFor(() => screen.queryByText('Grafana template variable function')); @@ -155,4 +137,30 @@ describe('VariableEditor:', () => { }); }); }); + + describe('predefined queries:', () => { + it('should show the new query types if feature gate is enabled', async () => { + grafanaRuntime.config.featureToggles.azTemplateVars = true; + render(); + openMenu(screen.getByLabelText('select query type')); + await waitFor(() => expect(screen.getByText('Subscriptions')).toBeInTheDocument()); + }); + + it('should not show the new query types if feature gate is disabled', async () => { + grafanaRuntime.config.featureToggles.azTemplateVars = false; + render(); + openMenu(screen.getByLabelText('select query type')); + await waitFor(() => expect(screen.queryByText('Subscriptions')).not.toBeInTheDocument()); + }); + + it('should run the query if requesting subscriptions', async () => { + grafanaRuntime.config.featureToggles.azTemplateVars = true; + const onChange = jest.fn(); + render(); + openMenu(screen.getByLabelText('select query type')); + screen.getByText('Subscriptions').click(); + await waitFor(() => expect(screen.getByText('Subscriptions')).toBeInTheDocument()); + expect(onChange).toHaveBeenCalledWith({ queryType: AzureQueryType.SubscriptionsQuery, refId: 'A' }); + }); + }); }); 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 7dca2a9fdae..68d9362c221 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,7 +1,8 @@ -import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { SelectableValue } from '@grafana/data'; -import { Alert, InlineField, Input, Select } from '@grafana/ui'; +import { config } from '@grafana/runtime'; +import { Alert, InlineField, Select } from '@grafana/ui'; import DataSource from '../../datasource'; import { migrateStringQueriesToObjectQueries } from '../../grafanaTemplateVariableFns'; @@ -10,59 +11,7 @@ import useLastError from '../../utils/useLastError'; import LogsQueryEditor from '../LogsQueryEditor'; import { Space } from '../Space'; -const AZURE_QUERY_VARIABLE_TYPE_OPTIONS = [ - { label: 'Grafana Query Function', value: AzureQueryType.GrafanaTemplateVariableFn }, - { label: 'Logs', value: AzureQueryType.LogAnalytics }, -]; - -const GrafanaTemplateVariableFnInput = ({ - query, - updateQuery, - datasource, -}: { - query: AzureMonitorQuery; - updateQuery: (val: AzureMonitorQuery) => void; - datasource: DataSource; -}) => { - const [inputVal, setInputVal] = useState(''); - useEffect(() => { - setInputVal(query.grafanaTemplateVariableFn?.rawQuery || ''); - }, [query.grafanaTemplateVariableFn?.rawQuery]); - - const onRunQuery = useCallback( - (newQuery: string) => { - migrateStringQueriesToObjectQueries(newQuery, { datasource }).then((updatedQuery) => { - if (updatedQuery.queryType === AzureQueryType.GrafanaTemplateVariableFn) { - updateQuery(updatedQuery); - } else { - updateQuery({ - ...query, - grafanaTemplateVariableFn: { - kind: 'UnknownQuery', - rawQuery: newQuery, - }, - }); - } - }); - }, - [datasource, query, updateQuery] - ); - - const onChange = (event: ChangeEvent) => { - setInputVal(event.target.value); - }; - - return ( - - onRunQuery(inputVal)} - /> - - ); -}; +import GrafanaTemplateVariableFnInput from './GrafanaTemplateVariableFn'; type Props = { query: AzureMonitorQuery | string; @@ -75,6 +24,14 @@ const VariableEditor = (props: Props) => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, }; + const AZURE_QUERY_VARIABLE_TYPE_OPTIONS = [ + { label: 'Grafana Query Function', value: AzureQueryType.GrafanaTemplateVariableFn }, + { label: 'Logs', value: AzureQueryType.LogAnalytics }, + ]; + if (config.featureToggles.azTemplateVars) { + AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Subscriptions', value: AzureQueryType.SubscriptionsQuery }); + } + const [query, setQuery] = useState(defaultQuery); useEffect(() => { @@ -85,12 +42,15 @@ const VariableEditor = (props: Props) => { const onQueryTypeChange = (selectableValue: SelectableValue) => { if (selectableValue.value) { - setQuery({ + const newQuery = { ...query, queryType: selectableValue.value, - }); + }; + setQuery(newQuery); + props.onChange(newQuery); } }; + const onLogsQueryChange = (queryChange: AzureMonitorQuery) => { setQuery(queryChange); @@ -111,7 +71,7 @@ const VariableEditor = (props: Props) => { return ( <> - +