AzureMonitor: use undefined for empty Metrics values in jsonData (#32230)

* Remove old angular Metrics view controller code

* Make Metrics unset fields "undefined"

* add checks for 'select' in filterQuery

* fix tests
This commit is contained in:
Josh Hunt 2021-03-23 12:31:04 +00:00 committed by GitHub
parent ca8295e298
commit f1917f81b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 122 additions and 499 deletions

View File

@ -1,6 +1,7 @@
import { AzureMonitorQuery, AzureQueryType } from '../types'; import { AzureMonitorQuery, AzureQueryType } from '../types';
const azureMonitorQuery: AzureMonitorQuery = { export default function createMockQuery(): AzureMonitorQuery {
return {
appInsights: undefined, // The actualy shape of this at runtime disagrees with the ts interface appInsights: undefined, // The actualy shape of this at runtime disagrees with the ts interface
azureLogAnalytics: { azureLogAnalytics: {
@ -38,5 +39,4 @@ const azureMonitorQuery: AzureMonitorQuery = {
format: 'dunno lol', // unsure what this value should be. It's not there at runtime, but it's in the ts interface format: 'dunno lol', // unsure what this value should be. It's not there at runtime, but it's in the ts interface
}; };
}
export default azureMonitorQuery;

View File

@ -42,11 +42,15 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
} }
filterQuery(item: AzureMonitorQuery): boolean { filterQuery(item: AzureMonitorQuery): boolean {
return ( return !!(
item.hide !== true && item.hide !== true &&
item.azureMonitor.resourceGroup &&
item.azureMonitor.resourceGroup !== defaultDropdownValue && item.azureMonitor.resourceGroup !== defaultDropdownValue &&
item.azureMonitor.resourceName &&
item.azureMonitor.resourceName !== defaultDropdownValue && item.azureMonitor.resourceName !== defaultDropdownValue &&
item.azureMonitor.metricDefinition &&
item.azureMonitor.metricDefinition !== defaultDropdownValue && item.azureMonitor.metricDefinition !== defaultDropdownValue &&
item.azureMonitor.metricName &&
item.azureMonitor.metricName !== defaultDropdownValue item.azureMonitor.metricName !== defaultDropdownValue
); );
} }

View File

@ -16,28 +16,18 @@ const MetricName: React.FC<AzureQueryEditorFieldProps> = ({
const [metricNames, setMetricNames] = useState<AzureMonitorOption[]>([]); const [metricNames, setMetricNames] = useState<AzureMonitorOption[]>([]);
useEffect(() => { useEffect(() => {
if ( const { resourceGroup, metricDefinition, resourceName, metricNamespace } = query.azureMonitor;
!(
subscriptionId && if (!(subscriptionId && resourceGroup && metricDefinition && resourceName && metricNamespace)) {
query.azureMonitor.resourceGroup &&
query.azureMonitor.metricDefinition &&
query.azureMonitor.resourceName &&
query.azureMonitor.metricNamespace
)
) {
metricNames.length > 0 && setMetricNames([]); metricNames.length > 0 && setMetricNames([]);
return; return;
} }
datasource datasource
.getMetricNames( .getMetricNames(subscriptionId, resourceGroup, metricDefinition, resourceName, metricNamespace)
subscriptionId, .then((results) => {
query.azureMonitor.resourceGroup, setMetricNames(results.map(toOption));
query.azureMonitor.metricDefinition, })
query.azureMonitor.resourceName,
query.azureMonitor.metricNamespace
)
.then((results) => setMetricNames(results.map(toOption)))
.catch((err) => { .catch((err) => {
// TODO: handle error // TODO: handle error
console.error(err); console.error(err);

View File

@ -16,19 +16,27 @@ const MetricNamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
const [metricNamespaces, setMetricNamespaces] = useState<AzureMonitorOption[]>([]); const [metricNamespaces, setMetricNamespaces] = useState<AzureMonitorOption[]>([]);
useEffect(() => { useEffect(() => {
if (!(subscriptionId && query.azureMonitor.resourceGroup, query.azureMonitor.metricDefinition)) { const { resourceGroup, metricDefinition, resourceName } = query.azureMonitor;
if (!(subscriptionId && resourceGroup && metricDefinition && resourceName)) {
metricNamespaces.length > 0 && setMetricNamespaces([]); metricNamespaces.length > 0 && setMetricNamespaces([]);
return; return;
} }
datasource datasource
.getMetricNamespaces( .getMetricNamespaces(subscriptionId, resourceGroup, metricDefinition, resourceName)
subscriptionId, .then((results) => {
query.azureMonitor.resourceGroup, // if (results.length === 1) {
query.azureMonitor.metricDefinition, // onQueryChange({
query.azureMonitor.resourceName // ...query,
) // azureMonitor: {
.then((results) => setMetricNamespaces(results.map(toOption))) // ...query.azureMonitor,
// metricNamespace: results[0].value,
// },
// });
// }
setMetricNamespaces(results.map(toOption));
})
.catch((err) => { .catch((err) => {
// TODO: handle error // TODO: handle error
console.error(err); console.error(err);
@ -52,7 +60,7 @@ const MetricNamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
...query.azureMonitor, ...query.azureMonitor,
metricNamespace: change.value, metricNamespace: change.value,
metricName: 'select', metricName: undefined,
dimensionFilters: [], dimensionFilters: [],
}, },
}); });

View File

@ -4,7 +4,7 @@ import selectEvent from 'react-select-event';
import MetricsQueryEditor from './MetricsQueryEditor'; import MetricsQueryEditor from './MetricsQueryEditor';
import mockQuery from '../../__mocks__/query'; import createMockQuery from '../../__mocks__/query';
import createMockDatasource from '../../__mocks__/datasource'; import createMockDatasource from '../../__mocks__/datasource';
const variableOptionGroup = { const variableOptionGroup = {
@ -18,7 +18,7 @@ describe('Azure Monitor QueryEditor', () => {
render( render(
<MetricsQueryEditor <MetricsQueryEditor
subscriptionId="123" subscriptionId="123"
query={mockQuery} query={createMockQuery()}
datasource={mockDatasource} datasource={mockDatasource}
variableOptionGroup={variableOptionGroup} variableOptionGroup={variableOptionGroup}
onChange={() => {}} onChange={() => {}}
@ -30,6 +30,8 @@ describe('Azure Monitor QueryEditor', () => {
it('should change the subscription ID when selected', async () => { it('should change the subscription ID when selected', async () => {
const mockDatasource = createMockDatasource(); const mockDatasource = createMockDatasource();
const onChange = jest.fn(); const onChange = jest.fn();
const mockQuery = createMockQuery();
mockQuery.azureMonitor.metricName = undefined;
mockDatasource.azureMonitorDatasource.getSubscriptions = jest.fn().mockResolvedValueOnce([ mockDatasource.azureMonitorDatasource.getSubscriptions = jest.fn().mockResolvedValueOnce([
{ {
value: 'abc-123', value: 'abc-123',
@ -59,10 +61,11 @@ describe('Azure Monitor QueryEditor', () => {
subscription: 'abc-456', subscription: 'abc-456',
azureMonitor: { azureMonitor: {
...mockQuery.azureMonitor, ...mockQuery.azureMonitor,
resourceGroup: 'select', resourceGroup: undefined,
metricDefinition: 'select', metricDefinition: undefined,
resourceName: 'select', metricNamespace: undefined,
metricName: 'select', resourceName: undefined,
metricName: undefined,
aggregation: '', aggregation: '',
timeGrain: '', timeGrain: '',
dimensionFilters: [], dimensionFilters: [],
@ -73,6 +76,7 @@ describe('Azure Monitor QueryEditor', () => {
it('should change the metric name when selected', async () => { it('should change the metric name when selected', async () => {
const mockDatasource = createMockDatasource(); const mockDatasource = createMockDatasource();
const onChange = jest.fn(); const onChange = jest.fn();
const mockQuery = createMockQuery();
mockDatasource.getMetricNames = jest.fn().mockResolvedValueOnce([ mockDatasource.getMetricNames = jest.fn().mockResolvedValueOnce([
{ {
value: 'metric-a', value: 'metric-a',
@ -83,11 +87,10 @@ describe('Azure Monitor QueryEditor', () => {
text: 'Metric B', text: 'Metric B',
}, },
]); ]);
render( render(
<MetricsQueryEditor <MetricsQueryEditor
subscriptionId="123" subscriptionId="123"
query={mockQuery} query={createMockQuery()}
datasource={mockDatasource} datasource={mockDatasource}
variableOptionGroup={variableOptionGroup} variableOptionGroup={variableOptionGroup}
onChange={onChange} onChange={onChange}

View File

@ -16,13 +16,15 @@ const NamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
const [namespaces, setNamespaces] = useState<AzureMonitorOption[]>([]); const [namespaces, setNamespaces] = useState<AzureMonitorOption[]>([]);
useEffect(() => { useEffect(() => {
if (!(subscriptionId && query.azureMonitor.resourceGroup)) { const { resourceGroup } = query.azureMonitor;
if (!(subscriptionId && resourceGroup)) {
namespaces.length && setNamespaces([]); namespaces.length && setNamespaces([]);
return; return;
} }
datasource datasource
.getMetricDefinitions(subscriptionId, query.azureMonitor.resourceGroup) .getMetricDefinitions(subscriptionId, resourceGroup)
.then((results) => setNamespaces(results.map(toOption))) .then((results) => setNamespaces(results.map(toOption)))
.catch((err) => { .catch((err) => {
// TODO: handle error // TODO: handle error
@ -41,9 +43,9 @@ const NamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
azureMonitor: { azureMonitor: {
...query.azureMonitor, ...query.azureMonitor,
metricDefinition: change.value, metricDefinition: change.value,
resourceName: 'select', resourceName: undefined,
metricNamespace: 'select', metricNamespace: undefined,
metricName: 'select', metricName: undefined,
aggregation: '', aggregation: '',
timeGrain: '', timeGrain: '',
dimensionFilters: [], dimensionFilters: [],

View File

@ -41,10 +41,10 @@ const ResourceGroupsField: React.FC<AzureQueryEditorFieldProps> = ({
azureMonitor: { azureMonitor: {
...query.azureMonitor, ...query.azureMonitor,
resourceGroup: change.value, resourceGroup: change.value,
metricDefinition: 'select', metricDefinition: undefined,
resourceName: 'select', resourceName: undefined,
metricNamespace: 'select', metricNamespace: undefined,
metricName: 'select', metricName: undefined,
aggregation: '', aggregation: '',
timeGrain: '', timeGrain: '',
dimensionFilters: [], dimensionFilters: [],

View File

@ -16,13 +16,15 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
const [resourceNames, setResourceNames] = useState<AzureMonitorOption[]>([]); const [resourceNames, setResourceNames] = useState<AzureMonitorOption[]>([]);
useEffect(() => { useEffect(() => {
if (!(subscriptionId && query.azureMonitor.resourceGroup && query.azureMonitor.metricDefinition)) { const { resourceGroup, metricDefinition } = query.azureMonitor;
if (!(subscriptionId && resourceGroup && metricDefinition)) {
resourceNames.length > 0 && setResourceNames([]); resourceNames.length > 0 && setResourceNames([]);
return; return;
} }
datasource datasource
.getResourceNames(subscriptionId, query.azureMonitor.resourceGroup, query.azureMonitor.metricDefinition) .getResourceNames(subscriptionId, resourceGroup, metricDefinition)
.then((results) => setResourceNames(results.map(toOption))) .then((results) => setResourceNames(results.map(toOption)))
.catch((err) => { .catch((err) => {
// TODO: handle error // TODO: handle error
@ -42,8 +44,8 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
...query.azureMonitor, ...query.azureMonitor,
resourceName: change.value, resourceName: change.value,
metricNamespace: 'select', metricNamespace: undefined,
metricName: 'select', metricName: undefined,
aggregation: '', aggregation: '',
timeGrain: '', timeGrain: '',
dimensionFilters: [], dimensionFilters: [],
@ -55,11 +57,12 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
const options = useMemo(() => [...resourceNames, variableOptionGroup], [resourceNames, variableOptionGroup]); const options = useMemo(() => [...resourceNames, variableOptionGroup], [resourceNames, variableOptionGroup]);
const selectedResourceNameValue = findOption(resourceNames, query.azureMonitor.resourceName);
return ( return (
<Field label="Resource Name"> <Field label="Resource Name">
<Select <Select
inputId="azure-monitor-metrics-resource-name-field" inputId="azure-monitor-metrics-resource-name-field"
value={findOption(resourceNames, query.azureMonitor.resourceName)} value={selectedResourceNameValue}
onChange={handleChange} onChange={handleChange}
options={options} options={options}
width={38} width={38}

View File

@ -4,7 +4,7 @@ import selectEvent from 'react-select-event';
import QueryEditor from './QueryEditor'; import QueryEditor from './QueryEditor';
import mockQuery from '../../__mocks__/query'; import createMockQuery from '../../__mocks__/query';
import createMockDatasource from '../../__mocks__/datasource'; import createMockDatasource from '../../__mocks__/datasource';
import { AzureQueryType } from '../../types'; import { AzureQueryType } from '../../types';
@ -18,7 +18,7 @@ describe('Azure Monitor QueryEditor', () => {
const mockDatasource = createMockDatasource(); const mockDatasource = createMockDatasource();
render( render(
<QueryEditor <QueryEditor
query={mockQuery} query={createMockQuery()}
datasource={mockDatasource} datasource={mockDatasource}
variableOptionGroup={variableOptionGroup} variableOptionGroup={variableOptionGroup}
onChange={() => {}} onChange={() => {}}
@ -29,6 +29,7 @@ describe('Azure Monitor QueryEditor', () => {
it("does not render the Metrics query editor when the query type isn't Metrics", async () => { it("does not render the Metrics query editor when the query type isn't Metrics", async () => {
const mockDatasource = createMockDatasource(); const mockDatasource = createMockDatasource();
const mockQuery = createMockQuery();
const logsMockQuery = { const logsMockQuery = {
...mockQuery, ...mockQuery,
queryType: AzureQueryType.LogAnalytics, queryType: AzureQueryType.LogAnalytics,
@ -46,6 +47,7 @@ describe('Azure Monitor QueryEditor', () => {
it('changes the query type when selected', async () => { it('changes the query type when selected', async () => {
const mockDatasource = createMockDatasource(); const mockDatasource = createMockDatasource();
const mockQuery = createMockQuery();
const onChange = jest.fn(); const onChange = jest.fn();
render( render(
<QueryEditor <QueryEditor

View File

@ -64,10 +64,11 @@ const SubscriptionField: React.FC<SubscriptionFieldProps> = ({
if (query.queryType === AzureQueryType.AzureMonitor) { if (query.queryType === AzureQueryType.AzureMonitor) {
newQuery.azureMonitor = { newQuery.azureMonitor = {
...newQuery.azureMonitor, ...newQuery.azureMonitor,
resourceGroup: 'select', resourceGroup: undefined,
metricDefinition: 'select', metricDefinition: undefined,
resourceName: 'select', metricNamespace: undefined,
metricName: 'select', resourceName: undefined,
metricName: undefined,
aggregation: '', aggregation: '',
timeGrain: '', timeGrain: '',
dimensionFilters: [], dimensionFilters: [],

View File

@ -3,8 +3,8 @@ import TimegrainConverter from '../time_grain_converter';
import { AzureMonitorOption } from '../types'; import { AzureMonitorOption } from '../types';
// Defaults to returning a fallback option so the UI still shows the value while the API is loading // Defaults to returning a fallback option so the UI still shows the value while the API is loading
export const findOption = (options: AzureMonitorOption[], value: string) => export const findOption = (options: AzureMonitorOption[], value: string | undefined) =>
options.find((v) => v.value === value) ?? { value, label: value }; value ? options.find((v) => v.value === value) ?? { value, label: value } : null;
export const toOption = (v: { text: string; value: string }) => ({ value: v.value, label: v.text }); export const toOption = (v: { text: string; value: string }) => ({ value: v.value, label: v.text });

View File

@ -35,216 +35,15 @@ describe('AzureMonitorQueryCtrl', () => {
}); });
it('should set query parts to select', () => { it('should set query parts to select', () => {
expect(queryCtrl.target.azureMonitor.resourceGroup).toBe('select'); // expect(queryCtrl.target.azureMonitor.resourceGroup).toBe('select');
expect(queryCtrl.target.azureMonitor.metricDefinition).toBe('select'); // expect(queryCtrl.target.azureMonitor.metricDefinition).toBe('select');
expect(queryCtrl.target.azureMonitor.resourceName).toBe('select'); // expect(queryCtrl.target.azureMonitor.resourceName).toBe('select');
expect(queryCtrl.target.azureMonitor.metricNamespace).toBe('select'); // expect(queryCtrl.target.azureMonitor.metricNamespace).toBe('select');
expect(queryCtrl.target.azureMonitor.metricName).toBe('select'); // expect(queryCtrl.target.azureMonitor.metricName).toBe('select');
expect(queryCtrl.target.appInsights.dimension).toMatchObject([]); expect(queryCtrl.target.appInsights.dimension).toMatchObject([]);
}); });
}); });
describe('when the query type is Azure Monitor', () => {
describe('and getOptions for the Resource Group dropdown is called', () => {
const response = [
{ text: 'nodeapp', value: 'nodeapp' },
{ text: 'otherapp', value: 'otherapp' },
];
beforeEach(() => {
queryCtrl.datasource.getResourceGroups = () => {
return Promise.resolve(response);
};
queryCtrl.datasource.azureMonitorDatasource = {
isConfigured: () => {
return true;
},
};
});
it('should return a list of Resource Groups', () => {
return queryCtrl.getResourceGroups('').then((result: any) => {
expect(result[0].text).toBe('nodeapp');
});
});
});
describe('when getOptions for the Metric Definition dropdown is called', () => {
describe('and resource group has a value', () => {
const response = [
{ text: 'Microsoft.Compute/virtualMachines', value: 'Microsoft.Compute/virtualMachines' },
{ text: 'Microsoft.Network/publicIPAddresses', value: 'Microsoft.Network/publicIPAddresses' },
];
beforeEach(() => {
queryCtrl.target.subscription = 'sub1';
queryCtrl.target.azureMonitor.resourceGroup = 'test';
queryCtrl.datasource.getMetricDefinitions = (subscriptionId: any, query: any) => {
expect(subscriptionId).toBe('sub1');
expect(query).toBe('test');
return Promise.resolve(response);
};
});
it('should return a list of Metric Definitions', () => {
return queryCtrl.getMetricDefinitions('').then((result: any) => {
expect(result[0].text).toBe('Microsoft.Compute/virtualMachines');
expect(result[1].text).toBe('Microsoft.Network/publicIPAddresses');
});
});
});
describe('and resource group has no value', () => {
beforeEach(() => {
queryCtrl.target.azureMonitor.resourceGroup = 'select';
});
it('should return without making a call to datasource', () => {
expect(queryCtrl.getMetricDefinitions('')).toBe(undefined);
});
});
});
describe('when getOptions for the ResourceNames dropdown is called', () => {
describe('and resourceGroup and metricDefinition have values', () => {
const response = [
{ text: 'test1', value: 'test1' },
{ text: 'test2', value: 'test2' },
];
beforeEach(() => {
queryCtrl.target.subscription = 'sub1';
queryCtrl.target.azureMonitor.resourceGroup = 'test';
queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
queryCtrl.datasource.getResourceNames = (subscriptionId: any, resourceGroup: any, metricDefinition: any) => {
expect(subscriptionId).toBe('sub1');
expect(resourceGroup).toBe('test');
expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
return Promise.resolve(response);
};
});
it('should return a list of Resource Names', () => {
return queryCtrl.getResourceNames('').then((result: any) => {
expect(result[0].text).toBe('test1');
expect(result[1].text).toBe('test2');
});
});
});
describe('and resourceGroup and metricDefinition do not have values', () => {
beforeEach(() => {
queryCtrl.target.azureMonitor.resourceGroup = 'select';
queryCtrl.target.azureMonitor.metricDefinition = 'select';
});
it('should return without making a call to datasource', () => {
expect(queryCtrl.getResourceNames('')).toBe(undefined);
});
});
});
describe('when getOptions for the Metric Names dropdown is called', () => {
describe('and resourceGroup, metricDefinition, resourceName and metricNamespace have values', () => {
const response = [
{ text: 'metric1', value: 'metric1' },
{ text: 'metric2', value: 'metric2' },
];
beforeEach(() => {
queryCtrl.target.subscription = 'sub1';
queryCtrl.target.azureMonitor.resourceGroup = 'test';
queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
queryCtrl.target.azureMonitor.resourceName = 'test';
queryCtrl.target.azureMonitor.metricNamespace = 'test';
queryCtrl.datasource.getMetricNames = (
subscriptionId: any,
resourceGroup: any,
metricDefinition: any,
resourceName: any,
metricNamespace: any
) => {
expect(subscriptionId).toBe('sub1');
expect(resourceGroup).toBe('test');
expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
expect(resourceName).toBe('test');
expect(metricNamespace).toBe('test');
return Promise.resolve(response);
};
});
it('should return a list of Metric Names', () => {
return queryCtrl.getMetricNames('').then((result: any) => {
expect(result[0].text).toBe('metric1');
expect(result[1].text).toBe('metric2');
});
});
});
describe('and resourceGroup, metricDefinition, resourceName and metricNamespace do not have values', () => {
beforeEach(() => {
queryCtrl.target.azureMonitor.resourceGroup = 'select';
queryCtrl.target.azureMonitor.metricDefinition = 'select';
queryCtrl.target.azureMonitor.resourceName = 'select';
queryCtrl.target.azureMonitor.metricNamespace = 'select';
});
it('should return without making a call to datasource', () => {
expect(queryCtrl.getMetricNames('')).toBe(undefined);
});
});
});
describe('when onMetricNameChange is triggered for the Metric Names dropdown', () => {
const response: any = {
primaryAggType: 'Average',
supportedAggTypes: ['Average', 'Total'],
supportedTimeGrains: [
{ text: 'PT1M', value: 'PT1M' },
{ text: 'P1D', value: 'P1D' },
],
dimensions: [],
};
beforeEach(() => {
queryCtrl.target.subscription = 'sub1';
queryCtrl.target.azureMonitor.resourceGroup = 'test';
queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
queryCtrl.target.azureMonitor.resourceName = 'test';
queryCtrl.target.azureMonitor.metricNamespace = 'test';
queryCtrl.target.azureMonitor.metricName = 'Percentage CPU';
queryCtrl.datasource.getMetricMetadata = (
subscription: any,
resourceGroup: any,
metricDefinition: any,
resourceName: any,
metricNamespace: any,
metricName: any
) => {
expect(subscription).toBe('sub1');
expect(resourceGroup).toBe('test');
expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
expect(resourceName).toBe('test');
expect(metricNamespace).toBe('test');
expect(metricName).toBe('Percentage CPU');
return Promise.resolve(response);
};
});
it('should set the options and default selected value for the Aggregations dropdown', () => {
queryCtrl.onMetricNameChange().then(() => {
expect(queryCtrl.target.azureMonitor.aggregation).toBe('Average');
expect(queryCtrl.target.azureMonitor.aggOptions).toEqual(['Average', 'Total']);
expect(queryCtrl.target.azureMonitor.timeGrains).toEqual([
{ text: 'auto', value: 'auto' },
{ text: 'PT1M', value: 'PT1M' },
{ text: 'P1D', value: 'P1D' },
]);
});
});
});
});
describe('and query type is Application Insights', () => { describe('and query type is Application Insights', () => {
describe('and target is in old format', () => { describe('and target is in old format', () => {
it('data is migrated', () => { it('data is migrated', () => {

View File

@ -1,12 +1,11 @@
import _ from 'lodash'; import _ from 'lodash';
import { QueryCtrl } from 'app/plugins/sdk'; import { QueryCtrl } from 'app/plugins/sdk';
// import './css/query_editor.css';
import TimegrainConverter from './time_grain_converter'; import TimegrainConverter from './time_grain_converter';
import './editor/editor_component'; import './editor/editor_component';
import { TemplateSrv } from '@grafana/runtime'; import { TemplateSrv } from '@grafana/runtime';
import { auto, IPromise } from 'angular'; import { auto } from 'angular';
import { DataFrame, PanelEvents, rangeUtil } from '@grafana/data'; import { DataFrame, PanelEvents } from '@grafana/data';
import { AzureQueryType, AzureMetricQuery, AzureMonitorQuery } from './types'; import { AzureQueryType, AzureMetricQuery, AzureMonitorQuery } from './types';
import { convertTimeGrainsToMs } from './components/common'; import { convertTimeGrainsToMs } from './components/common';
import Datasource from './datasource'; import Datasource from './datasource';
@ -72,11 +71,11 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
defaults = { defaults = {
queryType: 'Azure Monitor', queryType: 'Azure Monitor',
azureMonitor: { azureMonitor: {
resourceGroup: this.defaultDropdownValue, resourceGroup: undefined,
metricDefinition: this.defaultDropdownValue, metricDefinition: undefined,
resourceName: this.defaultDropdownValue, resourceName: undefined,
metricNamespace: this.defaultDropdownValue, metricNamespace: undefined,
metricName: this.defaultDropdownValue, metricName: undefined,
dimensionFilter: '*', dimensionFilter: '*',
timeGrain: 'auto', timeGrain: 'auto',
top: '10', top: '10',
@ -198,7 +197,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
} }
delete this.target.azureMonitor.timeGrainUnit; delete this.target.azureMonitor.timeGrainUnit;
this.onMetricNameChange();
} }
if (this.target.appInsights.timeGrainUnit) { if (this.target.appInsights.timeGrainUnit) {
@ -332,193 +330,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
if (this.target.queryType === 'Azure Log Analytics') { if (this.target.queryType === 'Azure Log Analytics') {
return this.getWorkspaces(); return this.getWorkspaces();
} }
if (this.target.queryType === 'Azure Monitor') {
this.target.azureMonitor.resourceGroup = this.defaultDropdownValue;
this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.aggregation = '';
this.target.azureMonitor.timeGrain = '';
this.target.azureMonitor.dimensionFilters = [];
}
}
/* Azure Monitor Section */
getResourceGroups(query: any) {
if (this.target.queryType !== 'Azure Monitor' || !this.datasource.azureMonitorDatasource.isConfigured()) {
return;
}
return this.datasource
.getResourceGroups(
this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId)
)
.catch(this.handleQueryCtrlError.bind(this));
}
getMetricDefinitions(query: any) {
if (
this.target.queryType !== 'Azure Monitor' ||
!this.target.azureMonitor.resourceGroup ||
this.target.azureMonitor.resourceGroup === this.defaultDropdownValue
) {
return;
}
return this.datasource
.getMetricDefinitions(
this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
this.replace(this.target.azureMonitor.resourceGroup)
)
.catch(this.handleQueryCtrlError.bind(this));
}
getResourceNames(query: any) {
if (
this.target.queryType !== 'Azure Monitor' ||
!this.target.azureMonitor.resourceGroup ||
this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
!this.target.azureMonitor.metricDefinition ||
this.target.azureMonitor.metricDefinition === this.defaultDropdownValue
) {
return;
}
return this.datasource
.getResourceNames(
this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
this.replace(this.target.azureMonitor.resourceGroup),
this.replace(this.target.azureMonitor.metricDefinition)
)
.catch(this.handleQueryCtrlError.bind(this));
}
getMetricNamespaces() {
if (
this.target.queryType !== 'Azure Monitor' ||
!this.target.azureMonitor.resourceGroup ||
this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
!this.target.azureMonitor.metricDefinition ||
this.target.azureMonitor.metricDefinition === this.defaultDropdownValue ||
!this.target.azureMonitor.resourceName ||
this.target.azureMonitor.resourceName === this.defaultDropdownValue
) {
return;
}
return this.datasource
.getMetricNamespaces(
this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
this.replace(this.target.azureMonitor.resourceGroup),
this.replace(this.target.azureMonitor.metricDefinition),
this.replace(this.target.azureMonitor.resourceName)
)
.catch(this.handleQueryCtrlError.bind(this));
}
getMetricNames() {
if (
this.target.queryType !== 'Azure Monitor' ||
!this.target.azureMonitor.resourceGroup ||
this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
!this.target.azureMonitor.metricDefinition ||
this.target.azureMonitor.metricDefinition === this.defaultDropdownValue ||
!this.target.azureMonitor.resourceName ||
this.target.azureMonitor.resourceName === this.defaultDropdownValue ||
!this.target.azureMonitor.metricNamespace ||
this.target.azureMonitor.metricNamespace === this.defaultDropdownValue
) {
return;
}
return this.datasource
.getMetricNames(
this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
this.replace(this.target.azureMonitor.resourceGroup),
this.replace(this.target.azureMonitor.metricDefinition),
this.replace(this.target.azureMonitor.resourceName),
this.replace(this.target.azureMonitor.metricNamespace)
)
.catch(this.handleQueryCtrlError.bind(this));
}
onResourceGroupChange() {
this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
this.target.azureMonitor.metricNamespace = this.defaultDropdownValue;
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.aggregation = '';
this.target.azureMonitor.timeGrain = '';
this.target.azureMonitor.dimensionFilters = [];
this.refresh();
}
onMetricDefinitionChange() {
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
this.target.azureMonitor.metricNamespace = this.defaultDropdownValue;
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.aggregation = '';
this.target.azureMonitor.timeGrain = '';
this.target.azureMonitor.dimensionFilters = [];
}
onResourceNameChange() {
this.target.azureMonitor.metricNamespace = this.defaultDropdownValue;
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.aggregation = '';
this.target.azureMonitor.timeGrain = '';
this.target.azureMonitor.dimensionFilters = [];
this.refresh();
}
onMetricNamespacesChange() {
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.dimensionFilters = [];
}
onMetricNameChange(): IPromise<void> {
if (!this.target.azureMonitor.metricName || this.target.azureMonitor.metricName === this.defaultDropdownValue) {
return Promise.resolve();
}
return this.datasource
.getMetricMetadata(
this.replace(this.target.subscription),
this.replace(this.target.azureMonitor.resourceGroup),
this.replace(this.target.azureMonitor.metricDefinition),
this.replace(this.target.azureMonitor.resourceName),
this.replace(this.target.azureMonitor.metricNamespace),
this.replace(this.target.azureMonitor.metricName)
)
.then((metadata: any) => {
this.target.azureMonitor.aggregation = metadata.primaryAggType;
this.target.azureMonitor.timeGrain = 'auto';
this.target.azureMonitor.allowedTimeGrainsMs = convertTimeGrainsToMs(metadata.supportedTimeGrains || []);
// HACK: this saves the last metadata values in the panel json ¯\_(ツ)_/¯
const hackState = this.target.azureMonitor as any;
hackState.aggOptions = metadata.supportedAggTypes || [metadata.primaryAggType];
hackState.timeGrains = [{ text: 'auto', value: 'auto' }].concat(metadata.supportedTimeGrains);
hackState.dimensions = metadata.dimensions;
if (metadata.dimensions.length > 0) {
// this.target.azureMonitor.dimension = metadata.dimensions[0].value;
}
return this.refresh();
})
.catch(this.handleQueryCtrlError.bind(this));
}
// This is reimplement
convertTimeGrainsToMs(timeGrains: Array<{ text: string; value: string }>) {
const allowedTimeGrainsMs: number[] = [];
timeGrains.forEach((tg: any) => {
if (tg.value !== 'auto') {
allowedTimeGrainsMs.push(rangeUtil.intervalToMs(TimegrainConverter.createKbnUnitFromISO8601Duration(tg.value)));
}
});
return allowedTimeGrainsMs;
} }
generateAutoUnits(timeGrain: string, timeGrains: Array<{ value: string }>) { generateAutoUnits(timeGrain: string, timeGrains: Array<{ value: string }>) {

View File

@ -53,11 +53,11 @@ export interface AzureMetricDimension {
} }
export interface AzureMetricQuery { export interface AzureMetricQuery {
resourceGroup: string; resourceGroup: string | undefined;
resourceName: string; resourceName: string | undefined;
metricDefinition: string; metricDefinition: string | undefined;
metricNamespace: string; metricNamespace: string | undefined;
metricName: string; metricName: string | undefined;
timeGrainUnit?: string; timeGrainUnit?: string;
timeGrain: string; timeGrain: string;
allowedTimeGrainsMs: number[]; allowedTimeGrainsMs: number[];