mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Remove unused code (#50399)
This commit is contained in:
parent
6da4feb2a9
commit
9703c9211e
@ -1,10 +1,20 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
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';
|
||||
import createMockQuery from '../../__mocks__/query';
|
||||
import {
|
||||
createMockResourceGroupsBySubscription,
|
||||
createMockSubscriptions,
|
||||
mockResourcesByResourceGroup,
|
||||
} from '../../__mocks__/resourcePickerRows';
|
||||
import ResourcePickerData from '../../resourcePicker/resourcePickerData';
|
||||
|
||||
import MetricsQueryEditor from './MetricsQueryEditor';
|
||||
|
||||
@ -13,259 +23,238 @@ const variableOptionGroup = {
|
||||
options: [],
|
||||
};
|
||||
|
||||
describe('Azure Monitor QueryEditor', () => {
|
||||
const mockPanelData = createMockPanelData();
|
||||
it('should render', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
});
|
||||
const tests = [
|
||||
{
|
||||
id: 'azure-monitor-metrics-query-editor-with-resource-picker',
|
||||
},
|
||||
{
|
||||
id: 'azure-monitor-metrics-query-editor-with-experimental-ui',
|
||||
},
|
||||
];
|
||||
|
||||
it('should change the subscription ID when selected', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
(mockQuery.azureMonitor ?? {}).metricName = undefined;
|
||||
mockDatasource.azureMonitorDatasource.getSubscriptions = jest.fn().mockResolvedValueOnce([
|
||||
{
|
||||
value: 'abc-123',
|
||||
text: 'Primary Subscription',
|
||||
},
|
||||
{
|
||||
value: 'abc-456',
|
||||
text: 'Another Subscription',
|
||||
},
|
||||
]);
|
||||
export function createMockResourcePickerData() {
|
||||
const mockDatasource = new ResourcePickerData(createMockInstanceSetttings());
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
mockDatasource.getSubscriptions = jest.fn().mockResolvedValue(createMockSubscriptions());
|
||||
mockDatasource.getResourceGroupsBySubscriptionId = jest
|
||||
.fn()
|
||||
.mockResolvedValue(createMockResourceGroupsBySubscription());
|
||||
mockDatasource.getResourcesForResourceGroup = jest.fn().mockResolvedValue(mockResourcesByResourceGroup());
|
||||
mockDatasource.getResourceURIFromWorkspace = jest.fn().mockReturnValue('');
|
||||
mockDatasource.getResourceURIDisplayProperties = jest.fn().mockResolvedValue({});
|
||||
|
||||
const subscriptions = await screen.findByLabelText('Subscription');
|
||||
await selectOptionInTest(subscriptions, 'Another Subscription');
|
||||
return mockDatasource;
|
||||
}
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...mockQuery,
|
||||
subscription: 'abc-456',
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
resourceGroup: undefined,
|
||||
metricDefinition: undefined,
|
||||
metricNamespace: undefined,
|
||||
resourceName: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
for (const t of tests) {
|
||||
describe(`MetricsQueryEditor: ${t.id}`, () => {
|
||||
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;
|
||||
});
|
||||
|
||||
it('should render', async () => {
|
||||
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(await screen.findByTestId(t.id)).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();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={query}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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 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' }));
|
||||
|
||||
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();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={query}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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(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 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' }));
|
||||
|
||||
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(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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: '',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the aggregation type when selected', async () => {
|
||||
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
const aggregation = await screen.findByLabelText('Aggregation');
|
||||
expect(aggregation).toBeInTheDocument();
|
||||
await selectOptionInTest(aggregation, 'Maximum');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
aggregation: 'Maximum',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the resource group when selected', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
mockDatasource.getResourceGroups = jest.fn().mockResolvedValue([
|
||||
{ text: 'grafanastaging', value: 'grafanastaging' },
|
||||
{ text: 'Grafana Prod', value: 'grafanaprod' },
|
||||
]);
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const resourceGroup = await screen.findByLabelText('Resource group');
|
||||
await selectOptionInTest(resourceGroup, 'Grafana Prod');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
resourceUri: '',
|
||||
resourceGroup: 'grafanaprod',
|
||||
metricDefinition: undefined,
|
||||
metricNamespace: undefined,
|
||||
resourceName: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the resource type when selected', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
mockDatasource.getMetricDefinitions = jest.fn().mockResolvedValue([
|
||||
{ text: 'Virtual Machine', value: 'azure/vm' },
|
||||
{ text: 'Database', value: 'azure/db' },
|
||||
]);
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const resourceGroup = await screen.findByLabelText('Resource type');
|
||||
await selectOptionInTest(resourceGroup, 'Virtual Machine');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
resourceUri: '',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: undefined,
|
||||
metricNamespace: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the resource name when selected', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
mockDatasource.getResourceNames = jest.fn().mockResolvedValue([
|
||||
{ text: 'ResourceName1', value: 'resource-name-1' },
|
||||
{ text: 'ResourceName2', value: 'resource-name-2' },
|
||||
]);
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const resourceGroup = await screen.findByLabelText('Resource name');
|
||||
await selectOptionInTest(resourceGroup, 'ResourceName1');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
resourceUri: '',
|
||||
resourceName: 'resource-name-1',
|
||||
metricNamespace: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the metric name when selected', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
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(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Metric');
|
||||
await selectOptionInTest(metrics, 'Metric B');
|
||||
|
||||
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();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
subscriptionId="123"
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const aggregation = await screen.findByLabelText('Aggregation');
|
||||
await selectOptionInTest(aggregation, 'Maximum');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
aggregation: 'Maximum',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,37 +1,31 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { PanelData } from '@grafana/data/src/types';
|
||||
import { InlineFieldRow } from '@grafana/ui';
|
||||
import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { InlineFieldRow, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import Datasource from '../../datasource';
|
||||
import { AzureMonitorQuery, AzureMonitorOption, AzureMonitorErrorish } from '../../types';
|
||||
import SubscriptionField from '../SubscriptionField';
|
||||
import type Datasource from '../../datasource';
|
||||
import type { AzureMonitorQuery, AzureMonitorOption, AzureMonitorErrorish } from '../../types';
|
||||
import ResourceField from '../ResourceField';
|
||||
import { ResourceRowType } from '../ResourcePicker/types';
|
||||
|
||||
import AggregationField from './AggregationField';
|
||||
import DimensionFields from './DimensionFields';
|
||||
import LegendFormatField from './LegendFormatField';
|
||||
import MetricNameField from './MetricNameField';
|
||||
import MetricNamespaceField from './MetricNamespaceField';
|
||||
import ResourceGroupsField from './ResourceGroupsField';
|
||||
import ResourceNameField from './ResourceNameField';
|
||||
import ResourceTypeField from './ResourceTypeField';
|
||||
import NewDimensionFields from './NewDimensionFields';
|
||||
import TimeGrainField from './TimeGrainField';
|
||||
import TopField from './TopField';
|
||||
import {
|
||||
useMetricNames,
|
||||
useMetricNamespaces,
|
||||
useResourceGroups,
|
||||
useResourceNames,
|
||||
useResourceTypes,
|
||||
useSubscriptions,
|
||||
useMetricMetadata,
|
||||
} from './dataHooks';
|
||||
import { useMetricNames, useMetricNamespaces, useMetricMetadata } from './dataHooks';
|
||||
import { setResource } from './setQueryValue';
|
||||
|
||||
interface MetricsQueryEditorProps {
|
||||
data: PanelData | undefined;
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
subscriptionId?: string;
|
||||
onChange: (newQuery: AzureMonitorQuery) => void;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
@ -41,133 +35,194 @@ const MetricsQueryEditor: React.FC<MetricsQueryEditorProps> = ({
|
||||
data,
|
||||
query,
|
||||
datasource,
|
||||
subscriptionId,
|
||||
variableOptionGroup,
|
||||
onChange,
|
||||
setError,
|
||||
}) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const metricsMetadata = useMetricMetadata(query, datasource, onChange);
|
||||
const subscriptions = useSubscriptions(query, datasource, onChange, setError);
|
||||
const resourceGroups = useResourceGroups(query, datasource, onChange, setError);
|
||||
const resourceTypes = useResourceTypes(query, datasource, onChange, setError);
|
||||
const resourceNames = useResourceNames(query, datasource, onChange, setError);
|
||||
const metricNames = useMetricNames(query, datasource, onChange, setError);
|
||||
const metricNamespaces = useMetricNamespaces(query, datasource, onChange, setError);
|
||||
const metricNames = useMetricNames(query, datasource, onChange, setError);
|
||||
if (config.featureToggles.azureMonitorExperimentalUI) {
|
||||
return (
|
||||
<span data-testid="azure-monitor-metrics-query-editor-with-experimental-ui">
|
||||
<EditorRows>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<ResourceField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
selectableEntryTypes={[ResourceRowType.Resource]}
|
||||
setResource={setResource}
|
||||
resourceUri={query.azureMonitor?.resourceUri}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
|
||||
return (
|
||||
<div data-testid="azure-monitor-metrics-query-editor">
|
||||
<InlineFieldRow>
|
||||
<SubscriptionField
|
||||
subscriptions={subscriptions}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<MetricNamespaceField
|
||||
metricNamespaces={metricNamespaces}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<MetricNameField
|
||||
metricNames={metricNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<AggregationField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
aggregationOptions={metricsMetadata?.aggOptions ?? []}
|
||||
isLoading={metricsMetadata.isLoading}
|
||||
/>
|
||||
<TimeGrainField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
timeGrainOptions={metricsMetadata?.timeGrains ?? []}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<NewDimensionFields
|
||||
data={data}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
dimensionOptions={metricsMetadata?.dimensions ?? []}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<TopField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<LegendFormatField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
</EditorRows>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div data-testid="azure-monitor-metrics-query-editor-with-resource-picker">
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<ResourceField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
selectableEntryTypes={[ResourceRowType.Resource]}
|
||||
setResource={setResource}
|
||||
resourceUri={query.azureMonitor?.resourceUri}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
|
||||
<ResourceGroupsField
|
||||
resourceGroups={resourceGroups}
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<MetricNamespaceField
|
||||
metricNamespaces={metricNamespaces}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<MetricNameField
|
||||
metricNames={metricNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<AggregationField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
aggregationOptions={metricsMetadata?.aggOptions ?? []}
|
||||
isLoading={metricsMetadata.isLoading}
|
||||
/>
|
||||
<TimeGrainField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
timeGrainOptions={metricsMetadata?.timeGrains ?? []}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<DimensionFields
|
||||
data={data}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
dimensionOptions={metricsMetadata?.dimensions ?? []}
|
||||
/>
|
||||
<TopField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
|
||||
<InlineFieldRow>
|
||||
<ResourceTypeField
|
||||
resourceTypes={resourceTypes}
|
||||
<LegendFormatField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<ResourceNameField
|
||||
resourceNames={resourceNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
|
||||
<InlineFieldRow>
|
||||
<MetricNamespaceField
|
||||
metricNamespaces={metricNamespaces}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<MetricNameField
|
||||
metricNames={metricNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<AggregationField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
aggregationOptions={metricsMetadata?.aggOptions ?? []}
|
||||
isLoading={metricsMetadata.isLoading}
|
||||
/>
|
||||
<TimeGrainField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
timeGrainOptions={metricsMetadata?.timeGrains ?? []}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<DimensionFields
|
||||
data={data}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
dimensionOptions={metricsMetadata?.dimensions ?? []}
|
||||
/>
|
||||
<TopField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<LegendFormatField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getStyles = () => ({
|
||||
row: css({
|
||||
rowGap: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
export default MetricsQueryEditor;
|
||||
|
@ -1,46 +0,0 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
|
||||
import { Field } from '../Field';
|
||||
|
||||
import { setResourceGroup } from './setQueryValue';
|
||||
|
||||
interface ResourceGroupsFieldProps extends AzureQueryEditorFieldProps {
|
||||
resourceGroups: AzureMonitorOption[];
|
||||
}
|
||||
|
||||
const ResourceGroupsField: React.FC<ResourceGroupsFieldProps> = ({
|
||||
query,
|
||||
resourceGroups,
|
||||
variableOptionGroup,
|
||||
onQueryChange,
|
||||
setError,
|
||||
}) => {
|
||||
const handleChange = useCallback(
|
||||
(change: SelectableValue<string>) => {
|
||||
const newQuery = setResourceGroup(query, change.value);
|
||||
onQueryChange(newQuery);
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
const options = useMemo(() => [...resourceGroups, variableOptionGroup], [resourceGroups, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Resource group">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-group-field"
|
||||
value={query.azureMonitor?.resourceGroup}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
allowCustomValue
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResourceGroupsField;
|
@ -1,46 +0,0 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
|
||||
import { Field } from '../Field';
|
||||
|
||||
import { setResourceName } from './setQueryValue';
|
||||
|
||||
interface ResourceNameFieldProps extends AzureQueryEditorFieldProps {
|
||||
resourceNames: AzureMonitorOption[];
|
||||
}
|
||||
|
||||
const ResourceNameField: React.FC<ResourceNameFieldProps> = ({
|
||||
resourceNames,
|
||||
query,
|
||||
variableOptionGroup,
|
||||
onQueryChange,
|
||||
}) => {
|
||||
const handleChange = useCallback(
|
||||
(change: SelectableValue<string>) => {
|
||||
const newQuery = setResourceName(query, change.value);
|
||||
onQueryChange(newQuery);
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
const options = useMemo(() => [...resourceNames, variableOptionGroup], [resourceNames, variableOptionGroup]);
|
||||
const value = query.azureMonitor?.resourceName ?? null;
|
||||
|
||||
return (
|
||||
<Field label="Resource name">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-name-field"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
allowCustomValue
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResourceNameField;
|
@ -1,50 +0,0 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
|
||||
import { Field } from '../Field';
|
||||
|
||||
import { setResourceType } from './setQueryValue';
|
||||
|
||||
interface NamespaceFieldProps extends AzureQueryEditorFieldProps {
|
||||
resourceTypes: AzureMonitorOption[];
|
||||
}
|
||||
|
||||
const NamespaceField: React.FC<NamespaceFieldProps> = ({
|
||||
resourceTypes,
|
||||
query,
|
||||
variableOptionGroup,
|
||||
onQueryChange,
|
||||
}) => {
|
||||
const handleChange = useCallback(
|
||||
(change: SelectableValue<string>) => {
|
||||
if (!change.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newQuery = setResourceType(query, change.value);
|
||||
onQueryChange(newQuery);
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
const options = useMemo(() => [...resourceTypes, variableOptionGroup], [resourceTypes, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Resource type">
|
||||
{/* It's expected that the label reads Resource type but the property is metricDefinition */}
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-type-field"
|
||||
value={query.azureMonitor?.metricDefinition}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
allowCustomValue
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default NamespaceField;
|
@ -5,17 +5,12 @@ import Datasource from '../../datasource';
|
||||
import { AzureMetricQuery, AzureMonitorOption, AzureMonitorQuery, AzureQueryType } from '../../types';
|
||||
|
||||
import {
|
||||
useMetricNames,
|
||||
useMetricNamespaces,
|
||||
useMetricMetadata,
|
||||
DataHook,
|
||||
MetricMetadata,
|
||||
MetricsMetadataHook,
|
||||
updateSubscriptions,
|
||||
useMetricMetadata,
|
||||
useMetricNames,
|
||||
useMetricNamespaces,
|
||||
useResourceGroups,
|
||||
useResourceNames,
|
||||
useResourceTypes,
|
||||
useSubscriptions,
|
||||
} from './dataHooks';
|
||||
|
||||
const WAIT_OPTIONS = {
|
||||
@ -45,124 +40,17 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
};
|
||||
|
||||
const testTable: TestScenario[] = [
|
||||
{
|
||||
name: 'useSubscriptions',
|
||||
hook: useSubscriptions,
|
||||
emptyQueryPartial: {},
|
||||
topLevelCustomProperties: {
|
||||
subscription: 'subscription-$ENVIRONMENT',
|
||||
},
|
||||
customProperties: {},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'sub-abc-123',
|
||||
value: 'sub-abc-123',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{
|
||||
label: 'sub-abc-123',
|
||||
value: 'sub-abc-123',
|
||||
},
|
||||
{
|
||||
label: 'subscription-$ENVIRONMENT',
|
||||
value: 'subscription-$ENVIRONMENT',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'useResourceGroups',
|
||||
hook: useResourceGroups,
|
||||
emptyQueryPartial: {},
|
||||
customProperties: {
|
||||
resourceGroup: 'resource-group-$ENVIRONMENT',
|
||||
},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'Web App - Production',
|
||||
value: 'web-app-production',
|
||||
},
|
||||
{
|
||||
label: 'Web App - Development',
|
||||
value: 'web-app-development',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{ label: 'Web App - Production', value: 'web-app-production' },
|
||||
{ label: 'Web App - Development', value: 'web-app-development' },
|
||||
{ label: 'resource-group-$ENVIRONMENT', value: 'resource-group-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'useResourceTypes',
|
||||
hook: useResourceTypes,
|
||||
emptyQueryPartial: {
|
||||
resourceGroup: 'web-app-development',
|
||||
},
|
||||
customProperties: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/resource-type-$ENVIRONMENT',
|
||||
},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'Virtual Machine',
|
||||
value: 'azure/vm',
|
||||
},
|
||||
{
|
||||
label: 'Database',
|
||||
value: 'azure/db',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{ label: 'Virtual Machine', value: 'azure/vm' },
|
||||
{ label: 'Database', value: 'azure/db' },
|
||||
{ label: 'azure/resource-type-$ENVIRONMENT', value: 'azure/resource-type-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'useResourceNames',
|
||||
hook: useResourceNames,
|
||||
emptyQueryPartial: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
},
|
||||
customProperties: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'resource-name-$ENVIRONMENT',
|
||||
},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'Web server',
|
||||
value: 'web-server',
|
||||
},
|
||||
{
|
||||
label: 'Job server',
|
||||
value: 'job-server',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{ label: 'Web server', value: 'web-server' },
|
||||
{ label: 'Job server', value: 'job-server' },
|
||||
{ label: 'resource-name-$ENVIRONMENT', value: 'resource-name-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'useMetricNames',
|
||||
hook: useMetricNames,
|
||||
emptyQueryPartial: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'web-server',
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
},
|
||||
customProperties: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'web-server',
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
metricName: 'metric-$ENVIRONMENT',
|
||||
},
|
||||
@ -182,20 +70,17 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
{ label: 'metric-$ENVIRONMENT', value: 'metric-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'useMetricNamespaces',
|
||||
hook: useMetricNamespaces,
|
||||
emptyQueryPartial: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'web-server',
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
},
|
||||
customProperties: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'web-server',
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm-$ENVIRONMENT',
|
||||
metricName: 'metric-name',
|
||||
},
|
||||
@ -307,11 +192,9 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
name: 'useMetricMetadata',
|
||||
hook: useMetricMetadata,
|
||||
emptyQueryPartial: {
|
||||
resourceGroup: 'web-app-development',
|
||||
metricDefinition: 'azure/vm',
|
||||
resourceName: 'web-server',
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
subscription: 'test-sub',
|
||||
metricName: 'Average CPU',
|
||||
},
|
||||
customProperties: {},
|
||||
@ -356,81 +239,3 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AzureMonitor: updateSubscriptions', () => {
|
||||
const bareQuery = {
|
||||
refId: 'A',
|
||||
queryType: AzureQueryType.AzureMonitor,
|
||||
};
|
||||
|
||||
[
|
||||
{
|
||||
description: 'should not update with no subscriptions',
|
||||
query: bareQuery,
|
||||
subscriptionOptions: [],
|
||||
},
|
||||
{
|
||||
description: 'should not update with the subscription as an option',
|
||||
query: { ...bareQuery, subscription: 'foo' },
|
||||
subscriptionOptions: [{ label: 'foo', value: 'foo' }],
|
||||
},
|
||||
{
|
||||
description: 'should not update with a template variable',
|
||||
query: { ...bareQuery, subscription: '$foo' },
|
||||
subscriptionOptions: [],
|
||||
},
|
||||
{
|
||||
description: 'should update with the first subscription',
|
||||
query: { ...bareQuery },
|
||||
subscriptionOptions: [{ label: 'foo', value: 'foo' }],
|
||||
onChangeArgs: {
|
||||
...bareQuery,
|
||||
subscription: 'foo',
|
||||
azureMonitor: {
|
||||
dimensionFilters: [],
|
||||
timeGrain: '',
|
||||
resourceUri: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'should update with the default subscription if the current subsription does not exists',
|
||||
query: { ...bareQuery, subscription: 'bar' },
|
||||
subscriptionOptions: [{ label: 'foo', value: 'foo' }],
|
||||
onChangeArgs: {
|
||||
...bareQuery,
|
||||
subscription: 'foo',
|
||||
azureMonitor: {
|
||||
dimensionFilters: [],
|
||||
timeGrain: '',
|
||||
resourceUri: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'should clean up if neither the default sub nor the current sub exists',
|
||||
query: { ...bareQuery, subscription: 'bar' },
|
||||
subscriptionOptions: [{ label: 'foo', value: 'foo' }],
|
||||
defaultSubscription: 'foobar',
|
||||
onChangeArgs: {
|
||||
...bareQuery,
|
||||
subscription: '',
|
||||
azureMonitor: {
|
||||
dimensionFilters: [],
|
||||
timeGrain: '',
|
||||
resourceUri: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
].forEach((test) => {
|
||||
it(test.description, () => {
|
||||
const onChange = jest.fn();
|
||||
updateSubscriptions(test.query, test.subscriptionOptions, onChange, test.defaultSubscription);
|
||||
if (test.onChangeArgs) {
|
||||
expect(onChange).toHaveBeenCalledWith(test.onChangeArgs);
|
||||
} else {
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -5,24 +5,12 @@ import { rangeUtil } from '@grafana/data';
|
||||
import Datasource from '../../datasource';
|
||||
import TimegrainConverter from '../../time_grain_converter';
|
||||
import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types';
|
||||
import { hasOption, toOption } from '../../utils/common';
|
||||
import { toOption } from '../../utils/common';
|
||||
import { useAsyncState } from '../../utils/useAsyncState';
|
||||
|
||||
import { setMetricNamespace, setSubscriptionID } from './setQueryValue';
|
||||
|
||||
export interface MetricMetadata {
|
||||
aggOptions: AzureMonitorOption[];
|
||||
timeGrains: AzureMonitorOption[];
|
||||
dimensions: AzureMonitorOption[];
|
||||
isLoading: boolean;
|
||||
|
||||
// These two properties are only used within the hook, and not elsewhere
|
||||
supportedAggTypes: string[];
|
||||
primaryAggType: string | undefined;
|
||||
}
|
||||
import { setMetricNamespace } from './setQueryValue';
|
||||
|
||||
type SetErrorFn = (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
type OnChangeFn = (newQuery: AzureMonitorQuery) => void;
|
||||
|
||||
export type DataHook = (
|
||||
query: AzureMonitorQuery,
|
||||
@ -37,138 +25,29 @@ export type MetricsMetadataHook = (
|
||||
onChange: OnChangeFn
|
||||
) => MetricMetadata;
|
||||
|
||||
export const updateSubscriptions = (
|
||||
query: AzureMonitorQuery,
|
||||
subscriptionOptions: AzureMonitorOption[],
|
||||
onChange: OnChangeFn,
|
||||
defaultSubscription?: string
|
||||
) => {
|
||||
const { subscription } = query;
|
||||
export interface MetricMetadata {
|
||||
aggOptions: AzureMonitorOption[];
|
||||
timeGrains: AzureMonitorOption[];
|
||||
dimensions: AzureMonitorOption[];
|
||||
isLoading: boolean;
|
||||
|
||||
// Return early if subscriptions havent loaded, or if the query already has a subscription
|
||||
if (
|
||||
!subscriptionOptions.length ||
|
||||
(subscription && (hasOption(subscriptionOptions, subscription) || subscription.includes('$')))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// These two properties are only used within the hook, and not elsewhere
|
||||
supportedAggTypes: string[];
|
||||
primaryAggType: string | undefined;
|
||||
}
|
||||
|
||||
const defaultSub = defaultSubscription || subscriptionOptions[0].value;
|
||||
|
||||
if (!subscription && defaultSub && hasOption(subscriptionOptions, defaultSub)) {
|
||||
onChange(setSubscriptionID(query, defaultSub));
|
||||
}
|
||||
|
||||
// Check if the current subscription is in the list of subscriptions
|
||||
if (subscription && !hasOption(subscriptionOptions, subscription)) {
|
||||
if (hasOption(subscriptionOptions, defaultSub)) {
|
||||
// Use the default sub if is on theh list
|
||||
onChange(setSubscriptionID(query, defaultSub));
|
||||
} else {
|
||||
// Neither the current subscription nor the defaultSub is on the list, remove it
|
||||
onChange(setSubscriptionID(query, ''));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const useSubscriptions: DataHook = (query, datasource, onChange, setError) => {
|
||||
const defaultSubscription = datasource.azureMonitorDatasource.defaultSubscriptionId;
|
||||
const { subscription } = query;
|
||||
|
||||
const subscriptionOptions = useAsyncState(
|
||||
async () => {
|
||||
const results = await datasource.azureMonitorDatasource.getSubscriptions();
|
||||
const options = formatOptions(results, subscription);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateSubscriptions(query, subscriptionOptions, onChange, defaultSubscription);
|
||||
}, [subscriptionOptions, query, defaultSubscription, onChange]);
|
||||
|
||||
return subscriptionOptions;
|
||||
};
|
||||
|
||||
export const useResourceGroups: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { subscription } = query;
|
||||
const { resourceGroup } = query.azureMonitor ?? {};
|
||||
|
||||
return useAsyncState(
|
||||
async () => {
|
||||
if (!subscription) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.getResourceGroups(subscription);
|
||||
const options = formatOptions(results, resourceGroup);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[subscription]
|
||||
);
|
||||
};
|
||||
|
||||
export const useResourceTypes: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { subscription } = query;
|
||||
const { resourceGroup, metricDefinition } = query.azureMonitor ?? {};
|
||||
|
||||
return useAsyncState(
|
||||
async () => {
|
||||
if (!(subscription && resourceGroup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.getMetricDefinitions(subscription, resourceGroup);
|
||||
const options = formatOptions(results, metricDefinition);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[subscription, resourceGroup]
|
||||
);
|
||||
};
|
||||
|
||||
export const useResourceNames: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { subscription } = query;
|
||||
const { resourceGroup, metricDefinition, resourceName } = query.azureMonitor ?? {};
|
||||
|
||||
return useAsyncState(
|
||||
async () => {
|
||||
if (!(subscription && resourceGroup && metricDefinition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.getResourceNames(subscription, resourceGroup, metricDefinition);
|
||||
const options = formatOptions(results, resourceName);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[subscription, resourceGroup, metricDefinition]
|
||||
);
|
||||
};
|
||||
type OnChangeFn = (newQuery: AzureMonitorQuery) => void;
|
||||
|
||||
export const useMetricNamespaces: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { subscription } = query;
|
||||
const { resourceGroup, metricDefinition, resourceName, metricNamespace } = query.azureMonitor ?? {};
|
||||
const { metricNamespace, resourceUri } = query.azureMonitor ?? {};
|
||||
|
||||
const metricNamespaces = useAsyncState(
|
||||
async () => {
|
||||
if (!(subscription && resourceGroup && metricDefinition && resourceName)) {
|
||||
if (!resourceUri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNamespaces({
|
||||
subscription,
|
||||
resourceGroup,
|
||||
metricDefinition,
|
||||
resourceName,
|
||||
});
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNamespaces({ resourceUri });
|
||||
const options = formatOptions(results, metricNamespace);
|
||||
|
||||
// Do some cleanup of the query state if need be
|
||||
@ -179,67 +58,61 @@ export const useMetricNamespaces: DataHook = (query, datasource, onChange, setEr
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[subscription, resourceGroup, metricDefinition, resourceName]
|
||||
[resourceUri]
|
||||
);
|
||||
|
||||
return metricNamespaces;
|
||||
};
|
||||
|
||||
export const useMetricNames: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { subscription } = query;
|
||||
const { resourceGroup, metricDefinition, resourceName, metricNamespace, metricName } = query.azureMonitor ?? {};
|
||||
const { metricNamespace, metricName, resourceUri } = query.azureMonitor ?? {};
|
||||
|
||||
return useAsyncState(
|
||||
async () => {
|
||||
if (!(subscription && resourceGroup && metricDefinition && resourceName && metricNamespace)) {
|
||||
if (!(metricNamespace && resourceUri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNames({
|
||||
subscription,
|
||||
resourceGroup,
|
||||
metricDefinition,
|
||||
resourceName,
|
||||
metricNamespace,
|
||||
});
|
||||
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNames({ resourceUri, metricNamespace });
|
||||
const options = formatOptions(results, metricName);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[subscription, resourceGroup, metricDefinition, resourceName, metricNamespace]
|
||||
[resourceUri, metricNamespace]
|
||||
);
|
||||
};
|
||||
|
||||
export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasource, onChange: OnChangeFn) => {
|
||||
const [metricMetadata, setMetricMetadata] = useState<MetricMetadata>({
|
||||
aggOptions: [],
|
||||
timeGrains: [],
|
||||
dimensions: [],
|
||||
isLoading: false,
|
||||
supportedAggTypes: [],
|
||||
primaryAggType: undefined,
|
||||
});
|
||||
const defaultMetricMetadata: MetricMetadata = {
|
||||
aggOptions: [],
|
||||
timeGrains: [],
|
||||
dimensions: [],
|
||||
isLoading: false,
|
||||
supportedAggTypes: [],
|
||||
primaryAggType: undefined,
|
||||
};
|
||||
|
||||
const { subscription } = query;
|
||||
const { resourceGroup, metricDefinition, resourceName, metricNamespace, metricName, aggregation, timeGrain } =
|
||||
query.azureMonitor ?? {};
|
||||
export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasource, onChange: OnChangeFn) => {
|
||||
const [metricMetadata, setMetricMetadata] = useState<MetricMetadata>(defaultMetricMetadata);
|
||||
|
||||
const { resourceUri, metricNamespace, metricName, aggregation, timeGrain } = query.azureMonitor ?? {};
|
||||
|
||||
// Fetch new metric metadata when the fields change
|
||||
useEffect(() => {
|
||||
if (!(subscription && resourceGroup && metricDefinition && resourceName && metricNamespace && metricName)) {
|
||||
if (!(resourceUri && metricNamespace && metricName)) {
|
||||
setMetricMetadata(defaultMetricMetadata);
|
||||
return;
|
||||
}
|
||||
|
||||
datasource.azureMonitorDatasource
|
||||
.getMetricMetadata({ subscription, resourceGroup, metricDefinition, resourceName, metricNamespace, metricName })
|
||||
.getMetricMetadata({ resourceUri, metricNamespace, metricName })
|
||||
.then((metadata) => {
|
||||
// TODO: Move the aggregationTypes and timeGrain defaults into `getMetricMetadata`
|
||||
const aggregations = (metadata.supportedAggTypes || [metadata.primaryAggType]).map((v) => ({
|
||||
label: v,
|
||||
value: v,
|
||||
}));
|
||||
|
||||
setMetricMetadata({
|
||||
aggOptions: aggregations,
|
||||
timeGrains: metadata.supportedTimeGrains,
|
||||
@ -249,7 +122,7 @@ export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasour
|
||||
primaryAggType: metadata.primaryAggType,
|
||||
});
|
||||
});
|
||||
}, [datasource, subscription, resourceGroup, metricDefinition, resourceName, metricNamespace, metricName]);
|
||||
}, [datasource, resourceUri, metricNamespace, metricName]);
|
||||
|
||||
// Update the query state in response to the meta data changing
|
||||
useEffect(() => {
|
||||
@ -286,7 +159,7 @@ function formatOptions(
|
||||
const options = rawResults.map(toOption);
|
||||
|
||||
// account for custom values that might have been set in json file like ones crafted with a template variable (ex: "cloud-datasource-resource-$Environment")
|
||||
if (selectedValue && !options.find((option) => option.value === selectedValue)) {
|
||||
if (selectedValue && !options.find((option) => option.value === selectedValue.toLowerCase())) {
|
||||
options.push({ label: selectedValue, value: selectedValue });
|
||||
}
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export { default } from './MetricsQueryEditor';
|
@ -16,95 +16,6 @@ export function setResource(query: AzureMonitorQuery, resourceURI: string | unde
|
||||
};
|
||||
}
|
||||
|
||||
export function setSubscriptionID(query: AzureMonitorQuery, subscriptionID: string): AzureMonitorQuery {
|
||||
if (query.subscription === subscriptionID) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
subscription: subscriptionID,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
resourceUri: '',
|
||||
resourceGroup: undefined,
|
||||
metricDefinition: undefined,
|
||||
metricNamespace: undefined,
|
||||
resourceName: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function setResourceGroup(query: AzureMonitorQuery, resourceGroup: string | undefined): AzureMonitorQuery {
|
||||
if (query.azureMonitor?.resourceGroup === resourceGroup) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
resourceUri: '',
|
||||
resourceGroup: resourceGroup,
|
||||
metricDefinition: undefined,
|
||||
metricNamespace: undefined,
|
||||
resourceName: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// In the query as "metricDefinition" for some reason
|
||||
export function setResourceType(query: AzureMonitorQuery, resourceType: string | undefined): AzureMonitorQuery {
|
||||
if (query.azureMonitor?.metricDefinition === resourceType) {
|
||||
return query;
|
||||
}
|
||||
|
||||
const newQuery = {
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
resourceUri: '',
|
||||
metricDefinition: resourceType,
|
||||
resourceName: undefined,
|
||||
metricNamespace: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
};
|
||||
|
||||
return newQuery;
|
||||
}
|
||||
|
||||
export function setResourceName(query: AzureMonitorQuery, resourceName: string | undefined): AzureMonitorQuery {
|
||||
if (query.azureMonitor?.resourceName === resourceName) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
resourceUri: '',
|
||||
resourceName: resourceName,
|
||||
metricNamespace: undefined,
|
||||
metricName: undefined,
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function setMetricNamespace(query: AzureMonitorQuery, metricNamespace: string | undefined): AzureMonitorQuery {
|
||||
if (query.azureMonitor?.metricNamespace === metricNamespace) {
|
||||
return query;
|
||||
|
@ -1,260 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
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';
|
||||
import createMockQuery from '../../__mocks__/query';
|
||||
import {
|
||||
createMockResourceGroupsBySubscription,
|
||||
createMockSubscriptions,
|
||||
mockResourcesByResourceGroup,
|
||||
} from '../../__mocks__/resourcePickerRows';
|
||||
import ResourcePickerData from '../../resourcePicker/resourcePickerData';
|
||||
|
||||
import MetricsQueryEditor from './MetricsQueryEditor';
|
||||
|
||||
const variableOptionGroup = {
|
||||
label: 'Template variables',
|
||||
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());
|
||||
|
||||
mockDatasource.getSubscriptions = jest.fn().mockResolvedValue(createMockSubscriptions());
|
||||
mockDatasource.getResourceGroupsBySubscriptionId = jest
|
||||
.fn()
|
||||
.mockResolvedValue(createMockResourceGroupsBySubscription());
|
||||
mockDatasource.getResourcesForResourceGroup = jest.fn().mockResolvedValue(mockResourcesByResourceGroup());
|
||||
mockDatasource.getResourceURIFromWorkspace = jest.fn().mockReturnValue('');
|
||||
mockDatasource.getResourceURIDisplayProperties = jest.fn().mockResolvedValue({});
|
||||
|
||||
return mockDatasource;
|
||||
}
|
||||
|
||||
for (const t of tests) {
|
||||
describe(`MetricsQueryEditor: ${t.id}`, () => {
|
||||
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;
|
||||
});
|
||||
|
||||
it('should render', async () => {
|
||||
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(await screen.findByTestId(t.id)).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();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={query}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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 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' }));
|
||||
|
||||
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();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={query}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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(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 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' }));
|
||||
|
||||
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(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
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: '',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the aggregation type when selected', async () => {
|
||||
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
|
||||
render(
|
||||
<MetricsQueryEditor
|
||||
data={mockPanelData}
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
setError={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
const aggregation = await screen.findByLabelText('Aggregation');
|
||||
expect(aggregation).toBeInTheDocument();
|
||||
await selectOptionInTest(aggregation, 'Maximum');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
azureMonitor: {
|
||||
...mockQuery.azureMonitor,
|
||||
aggregation: 'Maximum',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
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';
|
||||
import AggregationField from '../MetricsQueryEditor/AggregationField';
|
||||
import DimensionFields from '../MetricsQueryEditor/DimensionFields';
|
||||
import LegendFormatField from '../MetricsQueryEditor/LegendFormatField';
|
||||
import MetricNameField from '../MetricsQueryEditor/MetricNameField';
|
||||
import MetricNamespaceField from '../MetricsQueryEditor/MetricNamespaceField';
|
||||
import NewDimensionFields from '../MetricsQueryEditor/NewDimensionFields';
|
||||
import TimeGrainField from '../MetricsQueryEditor/TimeGrainField';
|
||||
import TopField from '../MetricsQueryEditor/TopField';
|
||||
import { setResource } from '../MetricsQueryEditor/setQueryValue';
|
||||
import ResourceField from '../ResourceField';
|
||||
import { ResourceRowType } from '../ResourcePicker/types';
|
||||
|
||||
import { useMetricNames, useMetricNamespaces, useMetricMetadata } from './dataHooks';
|
||||
|
||||
interface MetricsQueryEditorProps {
|
||||
data: PanelData | undefined;
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
onChange: (newQuery: AzureMonitorQuery) => void;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
}
|
||||
|
||||
const MetricsQueryEditor: React.FC<MetricsQueryEditorProps> = ({
|
||||
data,
|
||||
query,
|
||||
datasource,
|
||||
variableOptionGroup,
|
||||
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 (
|
||||
<span data-testid="azure-monitor-metrics-query-editor-with-experimental-ui">
|
||||
<EditorRows>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<ResourceField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
selectableEntryTypes={[ResourceRowType.Resource]}
|
||||
setResource={setResource}
|
||||
resourceUri={query.azureMonitor?.resourceUri}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<MetricNamespaceField
|
||||
metricNamespaces={metricNamespaces}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<MetricNameField
|
||||
metricNames={metricNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<AggregationField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
aggregationOptions={metricsMetadata?.aggOptions ?? []}
|
||||
isLoading={metricsMetadata.isLoading}
|
||||
/>
|
||||
<TimeGrainField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
timeGrainOptions={metricsMetadata?.timeGrains ?? []}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<NewDimensionFields
|
||||
data={data}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
dimensionOptions={metricsMetadata?.dimensions ?? []}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<TopField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<LegendFormatField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
</EditorRows>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div data-testid="azure-monitor-metrics-query-editor-with-resource-picker">
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<ResourceField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
selectableEntryTypes={[ResourceRowType.Resource]}
|
||||
setResource={setResource}
|
||||
resourceUri={query.azureMonitor?.resourceUri}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<MetricNamespaceField
|
||||
metricNamespaces={metricNamespaces}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<MetricNameField
|
||||
metricNames={metricNames}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow className={styles.row}>
|
||||
<AggregationField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
aggregationOptions={metricsMetadata?.aggOptions ?? []}
|
||||
isLoading={metricsMetadata.isLoading}
|
||||
/>
|
||||
<TimeGrainField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
timeGrainOptions={metricsMetadata?.timeGrains ?? []}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
<DimensionFields
|
||||
data={data}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
dimensionOptions={metricsMetadata?.dimensions ?? []}
|
||||
/>
|
||||
<TopField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<LegendFormatField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getStyles = () => ({
|
||||
row: css({
|
||||
rowGap: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
export default MetricsQueryEditor;
|
@ -1,235 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
|
||||
import createMockDatasource from '../../__mocks__/datasource';
|
||||
import Datasource from '../../datasource';
|
||||
import { AzureMetricQuery, AzureMonitorOption, AzureMonitorQuery, AzureQueryType } from '../../types';
|
||||
import { DataHook, MetricMetadata, MetricsMetadataHook } from '../MetricsQueryEditor/dataHooks';
|
||||
|
||||
import { useMetricNames, useMetricNamespaces, useMetricMetadata } from './dataHooks';
|
||||
|
||||
const WAIT_OPTIONS = {
|
||||
timeout: 1000,
|
||||
};
|
||||
|
||||
const opt = (text: string, value: string) => ({ text, value });
|
||||
|
||||
interface TestScenario {
|
||||
name: string;
|
||||
hook: DataHook | MetricsMetadataHook;
|
||||
|
||||
// For convenience, only need to define the azureMonitor part of the query for some tests
|
||||
emptyQueryPartial: AzureMetricQuery;
|
||||
customProperties: AzureMetricQuery;
|
||||
topLevelCustomProperties?: Partial<AzureMonitorQuery>;
|
||||
|
||||
expectedCustomPropertyResults?: Array<AzureMonitorOption<string>>;
|
||||
expectedOptions: AzureMonitorOption[] | MetricMetadata;
|
||||
}
|
||||
|
||||
describe('AzureMonitor: metrics dataHooks', () => {
|
||||
const bareQuery = {
|
||||
refId: 'A',
|
||||
queryType: AzureQueryType.AzureMonitor,
|
||||
subscription: 'sub-abc-123',
|
||||
};
|
||||
|
||||
const testTable: TestScenario[] = [
|
||||
{
|
||||
name: 'useMetricNames',
|
||||
hook: useMetricNames,
|
||||
emptyQueryPartial: {
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
},
|
||||
customProperties: {
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
metricName: 'metric-$ENVIRONMENT',
|
||||
},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'Percentage CPU',
|
||||
value: 'percentage-cpu',
|
||||
},
|
||||
{
|
||||
label: 'Free memory',
|
||||
value: 'free-memory',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{ label: 'Percentage CPU', value: 'percentage-cpu' },
|
||||
{ label: 'Free memory', value: 'free-memory' },
|
||||
{ label: 'metric-$ENVIRONMENT', value: 'metric-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'useMetricNamespaces',
|
||||
hook: useMetricNamespaces,
|
||||
emptyQueryPartial: {
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
},
|
||||
customProperties: {
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm-$ENVIRONMENT',
|
||||
metricName: 'metric-name',
|
||||
},
|
||||
expectedOptions: [
|
||||
{
|
||||
label: 'Compute Virtual Machine',
|
||||
value: 'azure/vmc',
|
||||
},
|
||||
{
|
||||
label: 'Database NS',
|
||||
value: 'azure/dbns',
|
||||
},
|
||||
{
|
||||
label: 'azure/vm',
|
||||
value: 'azure/vm',
|
||||
},
|
||||
],
|
||||
expectedCustomPropertyResults: [
|
||||
{ label: 'Compute Virtual Machine', value: 'azure/vmc' },
|
||||
{ label: 'Database NS', value: 'azure/dbns' },
|
||||
{ label: 'azure/vm-$ENVIRONMENT', value: 'azure/vm-$ENVIRONMENT' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
let datasource: Datasource;
|
||||
let onChange: jest.Mock<any, any>;
|
||||
let setError: jest.Mock<any, any>;
|
||||
|
||||
beforeEach(() => {
|
||||
onChange = jest.fn();
|
||||
setError = jest.fn();
|
||||
|
||||
datasource = createMockDatasource();
|
||||
datasource.getVariables = jest.fn().mockReturnValue(['$sub', '$rg', '$rt', '$variable']);
|
||||
|
||||
datasource.azureMonitorDatasource.getSubscriptions = jest
|
||||
.fn()
|
||||
.mockResolvedValue([opt('sub-abc-123', 'sub-abc-123')]);
|
||||
|
||||
datasource.getResourceGroups = jest
|
||||
.fn()
|
||||
.mockResolvedValue([
|
||||
opt('Web App - Production', 'web-app-production'),
|
||||
opt('Web App - Development', 'web-app-development'),
|
||||
]);
|
||||
|
||||
datasource.getMetricDefinitions = jest
|
||||
.fn()
|
||||
.mockResolvedValue([opt('Virtual Machine', 'azure/vm'), opt('Database', 'azure/db')]);
|
||||
|
||||
datasource.getResourceNames = jest
|
||||
.fn()
|
||||
.mockResolvedValue([opt('Web server', 'web-server'), opt('Job server', 'job-server')]);
|
||||
|
||||
datasource.azureMonitorDatasource.getMetricNames = jest
|
||||
.fn()
|
||||
.mockResolvedValue([opt('Percentage CPU', 'percentage-cpu'), opt('Free memory', 'free-memory')]);
|
||||
|
||||
datasource.azureMonitorDatasource.getMetricNamespaces = jest
|
||||
.fn()
|
||||
.mockResolvedValue([opt('Compute Virtual Machine', 'azure/vmc'), opt('Database NS', 'azure/dbns')]);
|
||||
|
||||
datasource.azureMonitorDatasource.getMetricMetadata = jest.fn().mockResolvedValue({
|
||||
primaryAggType: 'Average',
|
||||
supportedAggTypes: ['Average'],
|
||||
supportedTimeGrains: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: '1 minute', value: 'PT1M' },
|
||||
{ label: '5 minutes', value: 'PT5M' },
|
||||
{ label: '15 minutes', value: 'PT15M' },
|
||||
{ label: '30 minutes', value: 'PT30M' },
|
||||
{ label: '1 hour', value: 'PT1H' },
|
||||
{ label: '6 hours', value: 'PT6H' },
|
||||
{ label: '12 hours', value: 'PT12H' },
|
||||
{ label: '1 day', value: 'P1D' },
|
||||
],
|
||||
dimensions: [],
|
||||
});
|
||||
});
|
||||
|
||||
describe.each(testTable)('scenario %#: $name', (scenario) => {
|
||||
it('returns values', async () => {
|
||||
const query = {
|
||||
...bareQuery,
|
||||
azureMonitor: scenario.emptyQueryPartial,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
|
||||
expect(result.current).toEqual(scenario.expectedOptions);
|
||||
});
|
||||
|
||||
it('adds custom properties as a valid option', async () => {
|
||||
const query = {
|
||||
...bareQuery,
|
||||
azureMonitor: scenario.customProperties,
|
||||
...scenario.topLevelCustomProperties,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
|
||||
expect(result.current).toEqual(scenario.expectedCustomPropertyResults);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useMetricsMetadataHook', () => {
|
||||
const metricsMetadataConfig = {
|
||||
name: 'useMetricMetadata',
|
||||
hook: useMetricMetadata,
|
||||
emptyQueryPartial: {
|
||||
resourceUri:
|
||||
'/subscriptions/99999999-cccc-bbbb-aaaa-9106972f9572/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana',
|
||||
metricNamespace: 'azure/vm',
|
||||
metricName: 'Average CPU',
|
||||
},
|
||||
customProperties: {},
|
||||
expectedOptions: {
|
||||
aggOptions: [{ label: 'Average', value: 'Average' }],
|
||||
timeGrains: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: '1 minute', value: 'PT1M' },
|
||||
{ label: '5 minutes', value: 'PT5M' },
|
||||
{ label: '15 minutes', value: 'PT15M' },
|
||||
{ label: '30 minutes', value: 'PT30M' },
|
||||
{ label: '1 hour', value: 'PT1H' },
|
||||
{ label: '6 hours', value: 'PT6H' },
|
||||
{ label: '12 hours', value: 'PT12H' },
|
||||
{ label: '1 day', value: 'P1D' },
|
||||
],
|
||||
dimensions: [],
|
||||
isLoading: false,
|
||||
supportedAggTypes: ['Average'],
|
||||
primaryAggType: 'Average',
|
||||
},
|
||||
};
|
||||
|
||||
it('returns values', async () => {
|
||||
const query = {
|
||||
...bareQuery,
|
||||
azureMonitor: metricsMetadataConfig.emptyQueryPartial,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => metricsMetadataConfig.hook(query, datasource, onChange));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
|
||||
expect(result.current).toEqual(metricsMetadataConfig.expectedOptions);
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
aggregation: result.current.primaryAggType,
|
||||
timeGrain: 'auto',
|
||||
allowedTimeGrainsMs: [60_000, 300_000, 900_000, 1_800_000, 3_600_000, 21_600_000, 43_200_000, 86_400_000],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,152 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { rangeUtil } from '@grafana/data';
|
||||
|
||||
import Datasource from '../../datasource';
|
||||
import TimegrainConverter from '../../time_grain_converter';
|
||||
import { AzureMonitorOption, AzureMonitorQuery } from '../../types';
|
||||
import { toOption } from '../../utils/common';
|
||||
import { useAsyncState } from '../../utils/useAsyncState';
|
||||
import { DataHook } from '../MetricsQueryEditor/dataHooks';
|
||||
import { setMetricNamespace } from '../MetricsQueryEditor/setQueryValue';
|
||||
|
||||
export interface MetricMetadata {
|
||||
aggOptions: AzureMonitorOption[];
|
||||
timeGrains: AzureMonitorOption[];
|
||||
dimensions: AzureMonitorOption[];
|
||||
isLoading: boolean;
|
||||
|
||||
// These two properties are only used within the hook, and not elsewhere
|
||||
supportedAggTypes: string[];
|
||||
primaryAggType: string | undefined;
|
||||
}
|
||||
|
||||
type OnChangeFn = (newQuery: AzureMonitorQuery) => void;
|
||||
|
||||
export const useMetricNamespaces: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { metricNamespace, resourceUri } = query.azureMonitor ?? {};
|
||||
|
||||
const metricNamespaces = useAsyncState(
|
||||
async () => {
|
||||
if (!resourceUri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNamespaces({ resourceUri });
|
||||
const options = formatOptions(results, metricNamespace);
|
||||
|
||||
// Do some cleanup of the query state if need be
|
||||
if (!metricNamespace && options.length) {
|
||||
onChange(setMetricNamespace(query, options[0].value));
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[resourceUri]
|
||||
);
|
||||
|
||||
return metricNamespaces;
|
||||
};
|
||||
|
||||
export const useMetricNames: DataHook = (query, datasource, onChange, setError) => {
|
||||
const { metricNamespace, metricName, resourceUri } = query.azureMonitor ?? {};
|
||||
|
||||
return useAsyncState(
|
||||
async () => {
|
||||
if (!(metricNamespace && resourceUri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await datasource.azureMonitorDatasource.getMetricNames({ resourceUri, metricNamespace });
|
||||
const options = formatOptions(results, metricName);
|
||||
|
||||
return options;
|
||||
},
|
||||
setError,
|
||||
[resourceUri, metricNamespace]
|
||||
);
|
||||
};
|
||||
|
||||
const defaultMetricMetadata: MetricMetadata = {
|
||||
aggOptions: [],
|
||||
timeGrains: [],
|
||||
dimensions: [],
|
||||
isLoading: false,
|
||||
supportedAggTypes: [],
|
||||
primaryAggType: undefined,
|
||||
};
|
||||
|
||||
export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasource, onChange: OnChangeFn) => {
|
||||
const [metricMetadata, setMetricMetadata] = useState<MetricMetadata>(defaultMetricMetadata);
|
||||
|
||||
const { resourceUri, metricNamespace, metricName, aggregation, timeGrain } = query.azureMonitor ?? {};
|
||||
|
||||
// Fetch new metric metadata when the fields change
|
||||
useEffect(() => {
|
||||
if (!(resourceUri && metricNamespace && metricName)) {
|
||||
setMetricMetadata(defaultMetricMetadata);
|
||||
return;
|
||||
}
|
||||
|
||||
datasource.azureMonitorDatasource
|
||||
.getMetricMetadata({ resourceUri, metricNamespace, metricName })
|
||||
.then((metadata) => {
|
||||
// TODO: Move the aggregationTypes and timeGrain defaults into `getMetricMetadata`
|
||||
const aggregations = (metadata.supportedAggTypes || [metadata.primaryAggType]).map((v) => ({
|
||||
label: v,
|
||||
value: v,
|
||||
}));
|
||||
|
||||
setMetricMetadata({
|
||||
aggOptions: aggregations,
|
||||
timeGrains: metadata.supportedTimeGrains,
|
||||
dimensions: metadata.dimensions,
|
||||
isLoading: false,
|
||||
supportedAggTypes: metadata.supportedAggTypes ?? [],
|
||||
primaryAggType: metadata.primaryAggType,
|
||||
});
|
||||
});
|
||||
}, [datasource, resourceUri, metricNamespace, metricName]);
|
||||
|
||||
// Update the query state in response to the meta data changing
|
||||
useEffect(() => {
|
||||
const newAggregation = aggregation || metricMetadata.primaryAggType;
|
||||
const newTimeGrain = timeGrain || 'auto';
|
||||
|
||||
if (newAggregation !== aggregation || newTimeGrain !== timeGrain) {
|
||||
onChange({
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
aggregation: newAggregation,
|
||||
timeGrain: newTimeGrain,
|
||||
allowedTimeGrainsMs: metricMetadata.timeGrains
|
||||
.filter((timeGrain) => timeGrain.value !== 'auto')
|
||||
.map((timeGrain) =>
|
||||
rangeUtil.intervalToMs(TimegrainConverter.createKbnUnitFromISO8601Duration(timeGrain.value))
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [onChange, metricMetadata, aggregation, timeGrain, query]);
|
||||
|
||||
return metricMetadata;
|
||||
};
|
||||
|
||||
function formatOptions(
|
||||
rawResults: Array<{
|
||||
text: string;
|
||||
value: string;
|
||||
}>,
|
||||
selectedValue?: string
|
||||
) {
|
||||
const options = rawResults.map(toOption);
|
||||
|
||||
// account for custom values that might have been set in json file like ones crafted with a template variable (ex: "cloud-datasource-resource-$Environment")
|
||||
if (selectedValue && !options.find((option) => option.value === selectedValue.toLowerCase())) {
|
||||
options.push({ label: selectedValue, value: selectedValue });
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
@ -16,7 +16,7 @@ import {
|
||||
import useLastError from '../../utils/useLastError';
|
||||
import ArgQueryEditor from '../ArgQueryEditor';
|
||||
import LogsQueryEditor from '../LogsQueryEditor';
|
||||
import NewMetricsQueryEditor from '../NewMetricsQueryEditor/MetricsQueryEditor';
|
||||
import NewMetricsQueryEditor from '../MetricsQueryEditor/MetricsQueryEditor';
|
||||
import { QueryHeader } from '../QueryHeader';
|
||||
import { Space } from '../Space';
|
||||
|
||||
@ -157,8 +157,6 @@ const EditorForQueryType: React.FC<EditorForQueryTypeProps> = ({
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default QueryEditor;
|
||||
|
Loading…
Reference in New Issue
Block a user