mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Update ARG Subscription selection (#66890)
* Update ARG Subscription selection - Filter out queries that do not contain at least one subscription - Refactor SubscriptionField component - Display error if no subscriptions are selected - Update tests * Fix test
This commit is contained in:
parent
3c0e896282
commit
f3dbb7b34a
@ -12,7 +12,7 @@ export default class AzureResourceGraphDatasource extends DataSourceWithBackend<
|
|||||||
AzureDataSourceJsonData
|
AzureDataSourceJsonData
|
||||||
> {
|
> {
|
||||||
filterQuery(item: AzureMonitorQuery): boolean {
|
filterQuery(item: AzureMonitorQuery): boolean {
|
||||||
return !!item.azureResourceGraph?.query;
|
return !!item.azureResourceGraph?.query && !!item.subscriptions && item.subscriptions.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen, waitFor } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import createMockDatasource from '../../__mocks__/datasource';
|
import createMockDatasource from '../../__mocks__/datasource';
|
||||||
@ -118,4 +119,67 @@ describe('ArgQueryEditor', () => {
|
|||||||
).toHaveTextContent('$test');
|
).toHaveTextContent('$test');
|
||||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['$test'] }));
|
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['$test'] }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should display an error if no subscription is selected', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const datasource = createMockDatasource({
|
||||||
|
getSubscriptions: jest.fn().mockResolvedValue([]),
|
||||||
|
});
|
||||||
|
const query = createMockQuery({
|
||||||
|
subscriptions: [],
|
||||||
|
});
|
||||||
|
render(
|
||||||
|
<ArgQueryEditor
|
||||||
|
{...defaultProps}
|
||||||
|
datasource={datasource}
|
||||||
|
onChange={onChange}
|
||||||
|
query={query}
|
||||||
|
variableOptionGroup={{ label: 'Template Variables', options: [] }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await waitFor(() => screen.getByText('At least one subscription must be chosen.'))).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an error if subscriptions are cleared', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const datasource = createMockDatasource({
|
||||||
|
getSubscriptions: jest.fn().mockResolvedValue([{ text: 'foo', value: 'test-subscription-value' }]),
|
||||||
|
});
|
||||||
|
const query = createMockQuery({
|
||||||
|
subscription: undefined,
|
||||||
|
subscriptions: ['test-subscription-value'],
|
||||||
|
});
|
||||||
|
const { rerender } = render(
|
||||||
|
<ArgQueryEditor
|
||||||
|
{...defaultProps}
|
||||||
|
query={query}
|
||||||
|
datasource={datasource}
|
||||||
|
onChange={onChange}
|
||||||
|
variableOptionGroup={{ label: 'Template Variables', options: [] }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(datasource.getSubscriptions).toHaveBeenCalled();
|
||||||
|
expect(await waitFor(() => onChange)).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ subscriptions: ['test-subscription-value'] })
|
||||||
|
);
|
||||||
|
expect(await waitFor(() => screen.findByText('foo'))).toBeInTheDocument();
|
||||||
|
|
||||||
|
const clear = screen.getByLabelText('select-clear-value');
|
||||||
|
await userEvent.click(clear);
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: [] }));
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<ArgQueryEditor
|
||||||
|
{...defaultProps}
|
||||||
|
datasource={datasource}
|
||||||
|
onChange={onChange}
|
||||||
|
query={{ ...query, subscriptions: [] }}
|
||||||
|
variableOptionGroup={{ label: 'Template Variables', options: [] }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(await waitFor(() => screen.getByText('At least one subscription must be chosen.'))).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,9 +6,9 @@ import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental';
|
|||||||
import Datasource from '../../datasource';
|
import Datasource from '../../datasource';
|
||||||
import { selectors } from '../../e2e/selectors';
|
import { selectors } from '../../e2e/selectors';
|
||||||
import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types';
|
import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types';
|
||||||
import SubscriptionField from '../SubscriptionField';
|
|
||||||
|
|
||||||
import QueryField from './QueryField';
|
import QueryField from './QueryField';
|
||||||
|
import SubscriptionField from './SubscriptionField';
|
||||||
|
|
||||||
interface ArgQueryEditorProps {
|
interface ArgQueryEditorProps {
|
||||||
query: AzureMonitorQuery;
|
query: AzureMonitorQuery;
|
||||||
@ -81,7 +81,6 @@ const ArgQueryEditor = ({
|
|||||||
<EditorRow>
|
<EditorRow>
|
||||||
<EditorFieldGroup>
|
<EditorFieldGroup>
|
||||||
<SubscriptionField
|
<SubscriptionField
|
||||||
multiSelect
|
|
||||||
subscriptions={subscriptions}
|
subscriptions={subscriptions}
|
||||||
query={query}
|
query={query}
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import { SelectableValue } from '@grafana/data';
|
||||||
|
import { FieldValidationMessage, MultiSelect } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { selectors } from '../../e2e/selectors';
|
||||||
|
import { AzureMonitorQuery, AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
|
||||||
|
import { findOptions } from '../../utils/common';
|
||||||
|
import { Field } from '../Field';
|
||||||
|
|
||||||
|
interface SubscriptionFieldProps extends AzureQueryEditorFieldProps {
|
||||||
|
onQueryChange: (newQuery: AzureMonitorQuery) => void;
|
||||||
|
subscriptions: AzureMonitorOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubscriptionField = ({ query, subscriptions, variableOptionGroup, onQueryChange }: SubscriptionFieldProps) => {
|
||||||
|
const [error, setError] = useState<boolean>(false);
|
||||||
|
const [values, setValues] = useState<Array<SelectableValue<string>>>([]);
|
||||||
|
const options = useMemo(() => [...subscriptions, variableOptionGroup], [subscriptions, variableOptionGroup]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (query.subscriptions && query.subscriptions.length > 0) {
|
||||||
|
setValues(findOptions([...subscriptions, ...variableOptionGroup.options], query.subscriptions));
|
||||||
|
setError(false);
|
||||||
|
} else {
|
||||||
|
setError(true);
|
||||||
|
}
|
||||||
|
}, [query.subscriptions, subscriptions, variableOptionGroup.options]);
|
||||||
|
|
||||||
|
const onChange = (change: Array<SelectableValue<string>>) => {
|
||||||
|
if (!change || change.length === 0) {
|
||||||
|
setValues([]);
|
||||||
|
onQueryChange({
|
||||||
|
...query,
|
||||||
|
subscriptions: [],
|
||||||
|
});
|
||||||
|
setError(true);
|
||||||
|
} else {
|
||||||
|
const newSubs = change.map((c) => c.value ?? '');
|
||||||
|
onQueryChange({
|
||||||
|
...query,
|
||||||
|
subscriptions: newSubs,
|
||||||
|
});
|
||||||
|
setValues(findOptions([...subscriptions, ...variableOptionGroup.options], newSubs));
|
||||||
|
setError(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Field label="Subscriptions" data-testid={selectors.components.queryEditor.argsQueryEditor.subscriptions.input}>
|
||||||
|
<>
|
||||||
|
<MultiSelect
|
||||||
|
isClearable
|
||||||
|
value={values}
|
||||||
|
inputId="azure-monitor-subscriptions-field"
|
||||||
|
onChange={onChange}
|
||||||
|
options={options}
|
||||||
|
width={38}
|
||||||
|
/>
|
||||||
|
{error ? <FieldValidationMessage>At least one subscription must be chosen.</FieldValidationMessage> : null}
|
||||||
|
</>
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SubscriptionField;
|
@ -1,94 +0,0 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { SelectableValue } from '@grafana/data';
|
|
||||||
import { Select, MultiSelect } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { selectors } from '../e2e/selectors';
|
|
||||||
import { AzureMonitorQuery, AzureQueryEditorFieldProps, AzureMonitorOption, AzureQueryType } from '../types';
|
|
||||||
import { findOptions } from '../utils/common';
|
|
||||||
|
|
||||||
import { Field } from './Field';
|
|
||||||
|
|
||||||
interface SubscriptionFieldProps extends AzureQueryEditorFieldProps {
|
|
||||||
onQueryChange: (newQuery: AzureMonitorQuery) => void;
|
|
||||||
subscriptions: AzureMonitorOption[];
|
|
||||||
multiSelect?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SubscriptionField = ({
|
|
||||||
query,
|
|
||||||
subscriptions,
|
|
||||||
variableOptionGroup,
|
|
||||||
onQueryChange,
|
|
||||||
multiSelect = false,
|
|
||||||
}: SubscriptionFieldProps) => {
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(change: SelectableValue<string>) => {
|
|
||||||
if (!change.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newQuery: AzureMonitorQuery = {
|
|
||||||
...query,
|
|
||||||
subscription: change.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (query.queryType === AzureQueryType.AzureMonitor) {
|
|
||||||
newQuery.azureMonitor = {
|
|
||||||
...newQuery.azureMonitor,
|
|
||||||
resources: undefined,
|
|
||||||
metricNamespace: undefined,
|
|
||||||
metricName: undefined,
|
|
||||||
aggregation: undefined,
|
|
||||||
timeGrain: '',
|
|
||||||
dimensionFilters: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onQueryChange(newQuery);
|
|
||||||
},
|
|
||||||
[query, onQueryChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSubscriptionsChange = useCallback(
|
|
||||||
(change: Array<SelectableValue<string>>) => {
|
|
||||||
if (!change) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onQueryChange({
|
|
||||||
...query,
|
|
||||||
subscriptions: change.map((c) => c.value ?? ''),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[query, onQueryChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
const options = useMemo(() => [...subscriptions, variableOptionGroup], [subscriptions, variableOptionGroup]);
|
|
||||||
|
|
||||||
return multiSelect ? (
|
|
||||||
<Field label="Subscriptions" data-testid={selectors.components.queryEditor.argsQueryEditor.subscriptions.input}>
|
|
||||||
<MultiSelect
|
|
||||||
isClearable
|
|
||||||
value={findOptions([...subscriptions, ...variableOptionGroup.options], query.subscriptions)}
|
|
||||||
inputId="azure-monitor-subscriptions-field"
|
|
||||||
onChange={onSubscriptionsChange}
|
|
||||||
options={options}
|
|
||||||
width={38}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
) : (
|
|
||||||
<Field label="Subscription" data-testid={selectors.components.queryEditor.argsQueryEditor.subscriptions.input}>
|
|
||||||
<Select
|
|
||||||
value={query.subscription}
|
|
||||||
inputId="azure-monitor-subscriptions-field"
|
|
||||||
onChange={handleChange}
|
|
||||||
options={options}
|
|
||||||
width={38}
|
|
||||||
allowCustomValue
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SubscriptionField;
|
|
@ -100,7 +100,7 @@ describe('VariableEditor:', () => {
|
|||||||
it('should render', async () => {
|
it('should render', async () => {
|
||||||
render(<VariableEditor {...ARGqueryProps} />);
|
render(<VariableEditor {...ARGqueryProps} />);
|
||||||
await waitFor(() => screen.queryByTestId('mockeditor'));
|
await waitFor(() => screen.queryByTestId('mockeditor'));
|
||||||
expect(screen.queryByLabelText('Subscriptions')).toBeInTheDocument();
|
await waitFor(() => screen.queryByLabelText('Subscriptions'));
|
||||||
expect(screen.queryByText('Resource Graph')).toBeInTheDocument();
|
expect(screen.queryByText('Resource Graph')).toBeInTheDocument();
|
||||||
expect(screen.queryByLabelText('Select subscription')).not.toBeInTheDocument();
|
expect(screen.queryByLabelText('Select subscription')).not.toBeInTheDocument();
|
||||||
expect(screen.queryByLabelText('Select query type')).not.toBeInTheDocument();
|
expect(screen.queryByLabelText('Select query type')).not.toBeInTheDocument();
|
||||||
|
Loading…
Reference in New Issue
Block a user