mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Make all query properties optional (#36701)
* start to make all query fields optional * fix other types * fix optional types in fields * Pfeedback! * Clean up types
This commit is contained in:
parent
10c892fa5b
commit
43ee7acecd
@ -13,7 +13,6 @@ export default function createMockQuery(): AzureMonitorQuery {
|
||||
|
||||
azureResourceGraph: {
|
||||
query: 'Resources | summarize count()',
|
||||
resultFormat: 'time_series',
|
||||
},
|
||||
|
||||
azureMonitor: {
|
||||
@ -42,6 +41,5 @@ export default function createMockQuery(): AzureMonitorQuery {
|
||||
refId: 'A',
|
||||
subscription: '99999999-cccc-bbbb-aaaa-9106972f9572',
|
||||
subscriptions: ['99999999-cccc-bbbb-aaaa-9106972f9572'],
|
||||
format: 'dunno lol', // unsure what this value should be. It's not there at runtime, but it's in the ts interface
|
||||
};
|
||||
}
|
||||
|
@ -61,14 +61,18 @@ export default class AppInsightsDatasource extends DataSourceWithBackend<AzureMo
|
||||
};
|
||||
}
|
||||
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
const item = target.appInsights!;
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||
const item = target.appInsights;
|
||||
|
||||
if (!item) {
|
||||
return target;
|
||||
}
|
||||
|
||||
const old: any = item;
|
||||
// fix for timeGrainUnit which is a deprecated/removed field name
|
||||
if (old.timeGrainCount) {
|
||||
item.timeGrain = TimegrainConverter.createISO8601Duration(old.timeGrainCount, item.timeGrainUnit);
|
||||
} else if (item.timeGrainUnit && item.timeGrain !== 'auto') {
|
||||
} else if (item.timeGrain && item.timeGrainUnit && item.timeGrain !== 'auto') {
|
||||
item.timeGrain = TimegrainConverter.createISO8601Duration(item.timeGrain, item.timeGrainUnit);
|
||||
}
|
||||
|
||||
@ -95,9 +99,7 @@ export default class AppInsightsDatasource extends DataSourceWithBackend<AzureMo
|
||||
const templateSrv = getTemplateSrv();
|
||||
|
||||
return {
|
||||
type: 'timeSeriesQuery',
|
||||
refId: target.refId,
|
||||
format: target.format,
|
||||
queryType: AzureQueryType.ApplicationInsights,
|
||||
appInsights: {
|
||||
timeGrain: templateSrv.replace((item.timeGrain || '').toString(), scopedVars),
|
||||
@ -106,7 +108,6 @@ export default class AppInsightsDatasource extends DataSourceWithBackend<AzureMo
|
||||
dimension: item.dimension.map((d) => templateSrv.replace(d, scopedVars)),
|
||||
dimensionFilter: templateSrv.replace(item.dimensionFilter, scopedVars),
|
||||
alias: item.alias,
|
||||
format: target.format,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -112,8 +112,11 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend<
|
||||
return transformMetadataToKustoSchema(metadata, resourceUri);
|
||||
}
|
||||
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||
const item = target.azureLogAnalytics;
|
||||
if (!item) {
|
||||
return target;
|
||||
}
|
||||
|
||||
const templateSrv = getTemplateSrv();
|
||||
const resource = templateSrv.replace(item.resource, scopedVars);
|
||||
@ -123,21 +126,19 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend<
|
||||
workspace = this.defaultOrFirstWorkspace;
|
||||
}
|
||||
|
||||
const subscriptionId = templateSrv.replace(target.subscription || this.defaultSubscriptionId, scopedVars);
|
||||
const query = templateSrv.replace(item.query, scopedVars, this.interpolateVariable);
|
||||
|
||||
return {
|
||||
refId: target.refId,
|
||||
format: target.format,
|
||||
queryType: AzureQueryType.LogAnalytics,
|
||||
subscriptionId: subscriptionId,
|
||||
|
||||
azureLogAnalytics: {
|
||||
resultFormat: item.resultFormat,
|
||||
query: query,
|
||||
query,
|
||||
resource,
|
||||
|
||||
// TODO: Workspace is deprecated and should be migrated to Resources
|
||||
workspace: workspace,
|
||||
// Workspace was removed in Grafana 8, but remains for backwards compat
|
||||
workspace,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
filterQuery(item: AzureMonitorQuery): boolean {
|
||||
return !!(
|
||||
item.hide !== true &&
|
||||
item.azureMonitor &&
|
||||
item.azureMonitor.resourceGroup &&
|
||||
item.azureMonitor.resourceGroup !== defaultDropdownValue &&
|
||||
item.azureMonitor.resourceName &&
|
||||
@ -110,22 +111,24 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
if (res.data) {
|
||||
for (const df of res.data) {
|
||||
const metricQuery = metricQueries[df.refId];
|
||||
if (metricQuery && metricQuery.azureMonitor) {
|
||||
const url = this.buildAzurePortalUrl(
|
||||
metricQuery.azureMonitor,
|
||||
metricQuery.subscription,
|
||||
this.timeSrv.timeRange()
|
||||
);
|
||||
if (!metricQuery.azureMonitor || !metricQuery.subscription) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const field of df.fields) {
|
||||
field.config.links = [
|
||||
{
|
||||
url: url,
|
||||
title: 'View in Azure Portal',
|
||||
targetBlank: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
const url = this.buildAzurePortalUrl(
|
||||
metricQuery.azureMonitor,
|
||||
metricQuery.subscription,
|
||||
this.timeSrv.timeRange()
|
||||
);
|
||||
|
||||
for (const field of df.fields) {
|
||||
field.config.links = [
|
||||
{
|
||||
url: url,
|
||||
title: 'View in Azure Portal',
|
||||
targetBlank: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,11 +175,16 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
return `${this.azurePortalUrl}/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/${timeContext}/ChartDefinition/${chartDef}`;
|
||||
}
|
||||
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||
const item = target.azureMonitor;
|
||||
|
||||
if (!item) {
|
||||
// return target;
|
||||
throw new Error('Query is not a valid Azure Monitor Metrics query');
|
||||
}
|
||||
|
||||
// fix for timeGrainUnit which is a deprecated/removed field name
|
||||
if (item.timeGrainUnit && item.timeGrain !== 'auto') {
|
||||
if (item.timeGrain && item.timeGrainUnit && item.timeGrain !== 'auto') {
|
||||
item.timeGrain = TimegrainConverter.createISO8601Duration(item.timeGrain, item.timeGrainUnit);
|
||||
}
|
||||
|
||||
@ -191,7 +199,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
const aggregation = templateSrv.replace(item.aggregation, scopedVars);
|
||||
const top = templateSrv.replace(item.top || '', scopedVars);
|
||||
|
||||
const dimensionFilters = item.dimensionFilters
|
||||
const dimensionFilters = (item.dimensionFilters ?? [])
|
||||
.filter((f) => f.dimension && f.dimension !== 'None')
|
||||
.map((f) => {
|
||||
const filter = templateSrv.replace(f.filter ?? '', scopedVars);
|
||||
@ -219,7 +227,6 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
dimensionFilters,
|
||||
top: top || '10',
|
||||
alias: item.alias,
|
||||
format: target.format,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ describe('AzureResourceGraphDatasource', () => {
|
||||
};
|
||||
expect(ctx.ds.applyTemplateVariables(target)).toStrictEqual({
|
||||
azureResourceGraph: { query: 'Resources | var1-foo', resultFormat: 'table' },
|
||||
format: undefined,
|
||||
queryType: 'Azure Resource Graph',
|
||||
refId: undefined,
|
||||
subscriptions: undefined,
|
||||
@ -94,7 +93,6 @@ describe('AzureResourceGraphDatasource', () => {
|
||||
query: `resources | where $__contains(name, 'var3-foo','var3-baz')`,
|
||||
resultFormat: 'table',
|
||||
},
|
||||
format: undefined,
|
||||
queryType: 'Azure Resource Graph',
|
||||
refId: undefined,
|
||||
subscriptions: undefined,
|
||||
|
@ -12,16 +12,17 @@ export default class AzureResourceGraphDatasource extends DataSourceWithBackend<
|
||||
return !!item.azureResourceGraph?.query;
|
||||
}
|
||||
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||
const item = target.azureResourceGraph;
|
||||
if (!item) {
|
||||
return target;
|
||||
}
|
||||
|
||||
const templateSrv = getTemplateSrv();
|
||||
|
||||
const query = templateSrv.replace(item.query, scopedVars, this.interpolateVariable);
|
||||
|
||||
return {
|
||||
refId: target.refId,
|
||||
format: target.format,
|
||||
queryType: AzureQueryType.AzureResourceGraph,
|
||||
subscriptions: target.subscriptions,
|
||||
azureResourceGraph: {
|
||||
|
@ -18,7 +18,7 @@ const QueryField: React.FC<AzureQueryEditorFieldProps> = ({ query, onQueryChange
|
||||
|
||||
return (
|
||||
<CodeEditor
|
||||
value={query.azureResourceGraph.query}
|
||||
value={query.azureResourceGraph?.query ?? ''}
|
||||
language="kusto"
|
||||
height={200}
|
||||
width={1000}
|
||||
|
@ -19,7 +19,7 @@ const InsightsAnalyticsEditor: React.FC<InsightsAnalyticsEditorProps> = ({ query
|
||||
<div data-testid="azure-monitor-insights-analytics-query-editor">
|
||||
<CodeEditor
|
||||
language="kusto"
|
||||
value={query.insightsAnalytics.query}
|
||||
value={query.insightsAnalytics?.query ?? ''}
|
||||
height={200}
|
||||
width="100%"
|
||||
readOnly={true}
|
||||
@ -29,7 +29,7 @@ const InsightsAnalyticsEditor: React.FC<InsightsAnalyticsEditorProps> = ({ query
|
||||
<Field label="Format as">
|
||||
<Select
|
||||
inputId="azure-monitor-logs-workspaces-field"
|
||||
value={findOption(FORMAT_OPTIONS, query.insightsAnalytics.resultFormat)}
|
||||
value={findOption(FORMAT_OPTIONS, query.insightsAnalytics?.resultFormat)}
|
||||
disabled={true}
|
||||
options={FORMAT_OPTIONS}
|
||||
onChange={() => {}}
|
||||
|
@ -35,7 +35,7 @@ const FormatAsField: React.FC<AzureQueryEditorFieldProps> = ({ query, variableOp
|
||||
<Field label="Format as">
|
||||
<Select
|
||||
inputId="azure-monitor-logs-workspaces-field"
|
||||
value={findOption(FORMAT_OPTIONS, query.azureLogAnalytics.resultFormat)}
|
||||
value={findOption(FORMAT_OPTIONS, query.azureLogAnalytics?.resultFormat)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -31,7 +31,7 @@ const QueryField: React.FC<AzureQueryEditorFieldProps> = ({ query, datasource, o
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!query.azureLogAnalytics.resource) {
|
||||
if (!query.azureLogAnalytics?.resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ const QueryField: React.FC<AzureQueryEditorFieldProps> = ({ query, datasource, o
|
||||
});
|
||||
});
|
||||
});
|
||||
}, [datasource.azureLogAnalyticsDatasource, query.azureLogAnalytics.resource]);
|
||||
}, [datasource.azureLogAnalyticsDatasource, query.azureLogAnalytics?.resource]);
|
||||
|
||||
const handleEditorMount = useCallback((editor: MonacoEditor, monaco: Monaco) => {
|
||||
monacoPromiseRef.current?.resolve?.({ editor, monaco });
|
||||
@ -75,7 +75,7 @@ const QueryField: React.FC<AzureQueryEditorFieldProps> = ({ query, datasource, o
|
||||
|
||||
return (
|
||||
<CodeEditor
|
||||
value={query.azureLogAnalytics.query}
|
||||
value={query.azureLogAnalytics?.query ?? ''}
|
||||
language="kusto"
|
||||
height={200}
|
||||
width="100%"
|
||||
|
@ -25,7 +25,7 @@ function parseResourceDetails(resourceURI: string) {
|
||||
|
||||
const ResourceField: React.FC<AzureQueryEditorFieldProps> = ({ query, datasource, onQueryChange }) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { resource } = query.azureLogAnalytics;
|
||||
const { resource } = query.azureLogAnalytics ?? {};
|
||||
|
||||
const [pickerIsOpen, setPickerIsOpen] = useState(false);
|
||||
|
||||
@ -58,7 +58,7 @@ const ResourceField: React.FC<AzureQueryEditorFieldProps> = ({ query, datasource
|
||||
<Modal className={styles.modal} title="Select a resource" isOpen={pickerIsOpen} onDismiss={closePicker}>
|
||||
<ResourcePicker
|
||||
resourcePickerData={datasource.resourcePickerData}
|
||||
resourceURI={query.azureLogAnalytics.resource!}
|
||||
resourceURI={resource}
|
||||
templateVariables={templateVariables}
|
||||
onApply={handleApply}
|
||||
onCancel={closePicker}
|
||||
|
@ -1,65 +0,0 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
|
||||
import { findOption, toOption } from '../../utils/common';
|
||||
import { Field } from '../Field';
|
||||
|
||||
const ERROR_SOURCE = 'logs-workspaces';
|
||||
const WorkspaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
query,
|
||||
datasource,
|
||||
subscriptionId,
|
||||
variableOptionGroup,
|
||||
onQueryChange,
|
||||
setError,
|
||||
}) => {
|
||||
const [workspaces, setWorkspaces] = useState<AzureMonitorOption[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!subscriptionId) {
|
||||
workspaces.length > 0 && setWorkspaces([]);
|
||||
return;
|
||||
}
|
||||
|
||||
datasource
|
||||
.getAzureLogAnalyticsWorkspaces(subscriptionId)
|
||||
.then((results) => {
|
||||
setWorkspaces(results.map(toOption));
|
||||
})
|
||||
.catch((err) => setError(ERROR_SOURCE, err));
|
||||
}, [datasource, setError, subscriptionId, workspaces.length]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(change: SelectableValue<string>) => {
|
||||
if (!change.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
onQueryChange({
|
||||
...query,
|
||||
azureLogAnalytics: {
|
||||
...query.azureLogAnalytics,
|
||||
workspace: change.value,
|
||||
},
|
||||
});
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
const options = useMemo(() => [...workspaces, variableOptionGroup], [workspaces, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Workspace">
|
||||
<Select
|
||||
inputId="azure-monitor-logs-workspaces-field"
|
||||
value={findOption(workspaces, query.azureLogAnalytics.workspace)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkspaceField;
|
@ -8,7 +8,7 @@ async function migrateWorkspaceQueryToResourceQuery(
|
||||
query: AzureMonitorQuery,
|
||||
onChange: (newQuery: AzureMonitorQuery) => void
|
||||
) {
|
||||
if (query.azureLogAnalytics.workspace !== undefined && !query.azureLogAnalytics.resource) {
|
||||
if (query.azureLogAnalytics?.workspace !== undefined && !query.azureLogAnalytics.resource) {
|
||||
const isWorkspaceGUID = isGUIDish(query.azureLogAnalytics.workspace);
|
||||
let resource: string;
|
||||
|
||||
|
@ -44,7 +44,7 @@ const AggregationField: React.FC<AggregationFieldProps> = ({
|
||||
<Field label="Aggregation">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-aggregation-field"
|
||||
value={findOption(aggregationOptions, query.azureMonitor.aggregation)}
|
||||
value={findOption(aggregationOptions, query.azureMonitor?.aggregation)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Button, Select, Input, HorizontalGroup, VerticalGroup, InlineLabel } from '@grafana/ui';
|
||||
|
||||
import { Field } from '../Field';
|
||||
@ -10,6 +10,10 @@ interface DimensionFieldsProps extends AzureQueryEditorFieldProps {
|
||||
}
|
||||
|
||||
const DimensionFields: React.FC<DimensionFieldsProps> = ({ query, dimensionOptions, onQueryChange }) => {
|
||||
const dimensionFilters = useMemo(() => query.azureMonitor?.dimensionFilters ?? [], [
|
||||
query.azureMonitor?.dimensionFilters,
|
||||
]);
|
||||
|
||||
const setDimensionFilters = useCallback(
|
||||
(newFilters: AzureMetricDimension[]) => {
|
||||
onQueryChange({
|
||||
@ -25,17 +29,17 @@ const DimensionFields: React.FC<DimensionFieldsProps> = ({ query, dimensionOptio
|
||||
|
||||
const addFilter = useCallback(() => {
|
||||
setDimensionFilters([
|
||||
...query.azureMonitor.dimensionFilters,
|
||||
...dimensionFilters,
|
||||
{
|
||||
dimension: '',
|
||||
operator: 'eq',
|
||||
filter: '',
|
||||
},
|
||||
]);
|
||||
}, [query.azureMonitor.dimensionFilters, setDimensionFilters]);
|
||||
}, [dimensionFilters, setDimensionFilters]);
|
||||
|
||||
const removeFilter = (index: number) => {
|
||||
const newFilters = [...query.azureMonitor.dimensionFilters];
|
||||
const newFilters = [...dimensionFilters];
|
||||
newFilters.splice(index, 1);
|
||||
setDimensionFilters(newFilters);
|
||||
};
|
||||
@ -45,7 +49,7 @@ const DimensionFields: React.FC<DimensionFieldsProps> = ({ query, dimensionOptio
|
||||
fieldName: Key,
|
||||
value: AzureMetricDimension[Key]
|
||||
) => {
|
||||
const newFilters = [...query.azureMonitor.dimensionFilters];
|
||||
const newFilters = [...dimensionFilters];
|
||||
const newFilter = newFilters[filterIndex];
|
||||
newFilter[fieldName] = value;
|
||||
setDimensionFilters(newFilters);
|
||||
@ -60,7 +64,7 @@ const DimensionFields: React.FC<DimensionFieldsProps> = ({ query, dimensionOptio
|
||||
return (
|
||||
<Field label="Dimension">
|
||||
<VerticalGroup spacing="xs">
|
||||
{query.azureMonitor.dimensionFilters.map((filter, index) => (
|
||||
{dimensionFilters.map((filter, index) => (
|
||||
<HorizontalGroup key={index} spacing="xs">
|
||||
<Select
|
||||
placeholder="Field"
|
||||
|
@ -5,7 +5,7 @@ import { Field } from '../Field';
|
||||
import { AzureQueryEditorFieldProps } from '../../types';
|
||||
|
||||
const LegendFormatField: React.FC<AzureQueryEditorFieldProps> = ({ onQueryChange, query }) => {
|
||||
const [value, setValue] = useState<string>(query.azureMonitor.alias ?? '');
|
||||
const [value, setValue] = useState<string>(query.azureMonitor?.alias ?? '');
|
||||
|
||||
// As calling onQueryChange initiates a the datasource refresh, we only want to call it once
|
||||
// the field loses focus
|
||||
|
@ -19,7 +19,7 @@ const MetricName: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const { resourceGroup, metricDefinition, resourceName, metricNamespace } = query.azureMonitor;
|
||||
const { resourceGroup, metricDefinition, resourceName, metricNamespace } = query.azureMonitor ?? {};
|
||||
if (!(subscriptionId && resourceGroup && metricDefinition && resourceName && metricNamespace)) {
|
||||
metricNames.length > 0 && setMetricNames([]);
|
||||
return;
|
||||
@ -61,7 +61,7 @@ const MetricName: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
<Field label="Metric">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-metric-field"
|
||||
value={findOption(metricNames, query.azureMonitor.metricName)}
|
||||
value={findOption(metricNames, query.azureMonitor?.metricName)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -19,7 +19,7 @@ const MetricNamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const { resourceGroup, metricDefinition, resourceName } = query.azureMonitor;
|
||||
const { resourceGroup, metricDefinition, resourceName } = query.azureMonitor ?? {};
|
||||
if (!(subscriptionId && resourceGroup && metricDefinition && resourceName)) {
|
||||
metricNamespaces.length > 0 && setMetricNamespaces([]);
|
||||
return;
|
||||
@ -73,7 +73,7 @@ const MetricNamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
<Field label="Metric namespace">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-metric-namespace-field"
|
||||
value={findOption(metricNamespaces, query.azureMonitor.metricNamespace)}
|
||||
value={findOption(metricNamespaces, query.azureMonitor?.metricNamespace)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -32,7 +32,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
mockQuery.azureMonitor.metricName = undefined;
|
||||
(mockQuery.azureMonitor ?? {}).metricName = undefined;
|
||||
mockDatasource.azureMonitorDatasource.getSubscriptions = jest.fn().mockResolvedValueOnce([
|
||||
{
|
||||
value: 'abc-123',
|
||||
@ -117,7 +117,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const onChange = jest.fn();
|
||||
const mockQuery = createMockQuery();
|
||||
mockQuery.azureMonitor.aggregation = undefined;
|
||||
(mockQuery.azureMonitor ?? {}).aggregation = undefined;
|
||||
mockDatasource.getMetricNames = jest.fn().mockResolvedValue([
|
||||
{
|
||||
value: 'metric-a',
|
||||
|
@ -62,7 +62,7 @@ const ResourceGroupsField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
<Field label="Resource group">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-group-field"
|
||||
value={findOption(resourceGroups, query.azureMonitor.resourceGroup)}
|
||||
value={findOption(resourceGroups, query.azureMonitor?.resourceGroup)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -18,7 +18,7 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const [resourceNames, setResourceNames] = useState<AzureMonitorOption[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const { resourceGroup, metricDefinition } = query.azureMonitor;
|
||||
const { resourceGroup, metricDefinition } = query.azureMonitor ?? {};
|
||||
|
||||
if (!(subscriptionId && resourceGroup && metricDefinition)) {
|
||||
resourceNames.length > 0 && setResourceNames([]);
|
||||
@ -56,7 +56,7 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
|
||||
const options = useMemo(() => [...resourceNames, variableOptionGroup], [resourceNames, variableOptionGroup]);
|
||||
|
||||
const selectedResourceNameValue = findOption(resourceNames, query.azureMonitor.resourceName);
|
||||
const selectedResourceNameValue = findOption(resourceNames, query.azureMonitor?.resourceName);
|
||||
return (
|
||||
<Field label="Resource name">
|
||||
<Select
|
||||
|
@ -18,7 +18,7 @@ const NamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const [namespaces, setNamespaces] = useState<AzureMonitorOption[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const { resourceGroup } = query.azureMonitor;
|
||||
const { resourceGroup } = query.azureMonitor ?? {};
|
||||
|
||||
if (!(subscriptionId && resourceGroup)) {
|
||||
namespaces.length && setNamespaces([]);
|
||||
@ -61,7 +61,7 @@ const NamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
{/* It's expected that the label reads Resource type but the property is metricDefinition */}
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-type-field"
|
||||
value={findOption(namespaces, query.azureMonitor.metricDefinition)}
|
||||
value={findOption(namespaces, query.azureMonitor?.metricDefinition)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
|
@ -58,7 +58,7 @@ const TimeGrainField: React.FC<TimeGrainFieldProps> = ({
|
||||
<Field label="Time grain">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-time-grain-field"
|
||||
value={findOption(timeGrainOptions, query.azureMonitor.timeGrain)}
|
||||
value={findOption(timeGrainOptions, query.azureMonitor?.timeGrain)}
|
||||
onChange={handleChange}
|
||||
options={timeGrains}
|
||||
width={38}
|
||||
|
@ -5,7 +5,7 @@ import { Field } from '../Field';
|
||||
import { AzureQueryEditorFieldProps } from '../../types';
|
||||
|
||||
const TopField: React.FC<AzureQueryEditorFieldProps> = ({ onQueryChange, query }) => {
|
||||
const [value, setValue] = useState<string>(query.azureMonitor.top ?? '');
|
||||
const [value, setValue] = useState<string>(query.azureMonitor?.top ?? '');
|
||||
|
||||
// As calling onQueryChange initiates a the datasource refresh, we only want to call it once
|
||||
// the field loses focus
|
||||
|
@ -18,11 +18,6 @@ jest.mock('@grafana/ui', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const variableOptionGroup = {
|
||||
label: 'Template variables',
|
||||
options: [],
|
||||
};
|
||||
|
||||
describe('Azure Monitor QueryEditor', () => {
|
||||
it('renders the Metrics query editor when the query type is Metrics', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
@ -31,14 +26,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
queryType: AzureQueryType.AzureMonitor,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
@ -49,14 +37,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
queryType: AzureQueryType.LogAnalytics,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
|
||||
await waitFor(() => expect(screen.queryByTestId('azure-monitor-logs-query-editor')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
@ -78,14 +59,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
},
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByTestId('azure-monitor-application-insights-query-editor')).toBeInTheDocument()
|
||||
);
|
||||
@ -99,14 +73,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const mockQuery = createMockQuery();
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={onChange} onRunQuery={() => {}} />);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Service');
|
||||
@ -122,12 +89,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
mockDatasource.azureMonitorDatasource.getSubscriptions = jest.fn().mockRejectedValue(invalidNamespaceError());
|
||||
render(
|
||||
<QueryEditor
|
||||
query={createMockQuery()}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<QueryEditor query={createMockQuery()} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />
|
||||
);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-query-editor')).toBeInTheDocument());
|
||||
|
||||
@ -141,14 +103,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
queryType: AzureQueryType.AzureMonitor,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Service');
|
||||
@ -164,14 +119,7 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
queryType: AzureQueryType.ApplicationInsights,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
render(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId('azure-monitor-application-insights-query-editor')).toBeInTheDocument()
|
||||
);
|
||||
|
@ -1,7 +1,14 @@
|
||||
import { Alert } from '@grafana/ui';
|
||||
import { QueryEditorProps } from '@grafana/data';
|
||||
import React from 'react';
|
||||
import Datasource from '../../datasource';
|
||||
import { AzureMonitorQuery, AzureQueryType, AzureMonitorOption, AzureMonitorErrorish } from '../../types';
|
||||
import AzureMonitorDatasource from '../../datasource';
|
||||
import {
|
||||
AzureMonitorQuery,
|
||||
AzureQueryType,
|
||||
AzureMonitorOption,
|
||||
AzureMonitorErrorish,
|
||||
AzureDataSourceJsonData,
|
||||
} from '../../types';
|
||||
import MetricsQueryEditor from '../MetricsQueryEditor';
|
||||
import QueryTypeField from './QueryTypeField';
|
||||
import useLastError from '../../utils/useLastError';
|
||||
@ -11,14 +18,13 @@ import ApplicationInsightsEditor from '../ApplicationInsightsEditor';
|
||||
import InsightsAnalyticsEditor from '../InsightsAnalyticsEditor';
|
||||
import { Space } from '../Space';
|
||||
|
||||
interface BaseQueryEditorProps {
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
onChange: (newQuery: AzureMonitorQuery) => void;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
}
|
||||
export type AzureMonitorQueryEditorProps = QueryEditorProps<
|
||||
AzureMonitorDatasource,
|
||||
AzureMonitorQuery,
|
||||
AzureDataSourceJsonData
|
||||
>;
|
||||
|
||||
const QueryEditor: React.FC<BaseQueryEditorProps> = ({ query, datasource, onChange }) => {
|
||||
const QueryEditor: React.FC<AzureMonitorQueryEditorProps> = ({ query, datasource, onChange }) => {
|
||||
const [errorMessage, setError] = useLastError();
|
||||
const subscriptionId = query.subscription || datasource.azureMonitorDatasource.defaultSubscriptionId;
|
||||
const variableOptionGroup = {
|
||||
@ -51,8 +57,9 @@ const QueryEditor: React.FC<BaseQueryEditorProps> = ({ query, datasource, onChan
|
||||
);
|
||||
};
|
||||
|
||||
interface EditorForQueryTypeProps extends BaseQueryEditorProps {
|
||||
interface EditorForQueryTypeProps extends Omit<AzureMonitorQueryEditorProps, 'onRunQuery'> {
|
||||
subscriptionId?: string;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
}
|
||||
|
||||
@ -65,6 +72,7 @@ const EditorForQueryType: React.FC<EditorForQueryTypeProps> = ({
|
||||
setError,
|
||||
}) => {
|
||||
switch (query.queryType) {
|
||||
case undefined:
|
||||
case AzureQueryType.AzureMonitor:
|
||||
return (
|
||||
<MetricsQueryEditor
|
||||
|
@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select, MultiSelect } from '@grafana/ui';
|
||||
|
||||
import { AzureMonitorQuery, AzureQueryType, AzureQueryEditorFieldProps, AzureMonitorOption } from '../types';
|
||||
import { AzureMonitorQuery, AzureQueryEditorFieldProps, AzureMonitorOption, AzureQueryType } from '../types';
|
||||
import { findOption, findOptions } from '../utils/common';
|
||||
import { Field } from './Field';
|
||||
|
||||
@ -64,8 +64,6 @@ const SubscriptionField: React.FC<SubscriptionFieldProps> = ({
|
||||
};
|
||||
|
||||
if (query.queryType === AzureQueryType.AzureMonitor) {
|
||||
// TODO: set the fields to undefined so we don't
|
||||
// get "resource group select could not be found" errors
|
||||
newQuery.azureMonitor = {
|
||||
...newQuery.azureMonitor,
|
||||
resourceGroup: undefined,
|
||||
|
@ -28,6 +28,7 @@ export function useMetricsMetadata(
|
||||
if (
|
||||
!(
|
||||
subscriptionId &&
|
||||
query.azureMonitor &&
|
||||
query.azureMonitor.resourceGroup &&
|
||||
query.azureMonitor.metricDefinition &&
|
||||
query.azureMonitor.resourceName &&
|
||||
@ -53,10 +54,10 @@ export function useMetricsMetadata(
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
aggregation:
|
||||
query.azureMonitor.aggregation && metadata.supportedAggTypes.includes(query.azureMonitor.aggregation)
|
||||
query.azureMonitor?.aggregation && metadata.supportedAggTypes.includes(query.azureMonitor.aggregation)
|
||||
? query.azureMonitor.aggregation
|
||||
: metadata.primaryAggType,
|
||||
timeGrain: query.azureMonitor.timeGrain || 'auto',
|
||||
timeGrain: query.azureMonitor?.timeGrain || 'auto', // TODO: move this default value somewhere better?
|
||||
allowedTimeGrainsMs: convertTimeGrainsToMs(metadata.supportedTimeGrains),
|
||||
},
|
||||
});
|
||||
@ -80,11 +81,11 @@ export function useMetricsMetadata(
|
||||
});
|
||||
}, [
|
||||
subscriptionId,
|
||||
query.azureMonitor.resourceGroup,
|
||||
query.azureMonitor.metricDefinition,
|
||||
query.azureMonitor.resourceName,
|
||||
query.azureMonitor.metricNamespace,
|
||||
query.azureMonitor.metricName,
|
||||
query.azureMonitor?.resourceGroup,
|
||||
query.azureMonitor?.metricDefinition,
|
||||
query.azureMonitor?.resourceName,
|
||||
query.azureMonitor?.metricNamespace,
|
||||
query.azureMonitor?.metricName,
|
||||
query,
|
||||
datasource,
|
||||
onQueryChange,
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
ScopedVars,
|
||||
} from '@grafana/data';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||
import InsightsAnalyticsDatasource from './insights_analytics/insights_analytics_datasource';
|
||||
import { migrateMetricsDimensionFilters } from './query_ctrl';
|
||||
import { map } from 'rxjs/operators';
|
||||
@ -37,7 +37,15 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
/** @deprecated */
|
||||
insightsAnalyticsDatasource?: InsightsAnalyticsDatasource;
|
||||
|
||||
pseudoDatasource: Record<AzureQueryType, DataSourceWithBackend>;
|
||||
pseudoDatasource: {
|
||||
[key in AzureQueryType]?:
|
||||
| AzureMonitorDatasource
|
||||
| AzureLogAnalyticsDatasource
|
||||
| AzureResourceGraphDatasource
|
||||
| AppInsightsDatasource
|
||||
| InsightsAnalyticsDatasource;
|
||||
} = {};
|
||||
|
||||
optionsKey: Record<AzureQueryType, string>;
|
||||
|
||||
constructor(
|
||||
@ -50,42 +58,33 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
this.azureResourceGraphDatasource = new AzureResourceGraphDatasource(instanceSettings);
|
||||
this.resourcePickerData = new ResourcePickerData(instanceSettings);
|
||||
|
||||
const pseudoDatasource: any = {};
|
||||
pseudoDatasource[AzureQueryType.AzureMonitor] = this.azureMonitorDatasource;
|
||||
pseudoDatasource[AzureQueryType.LogAnalytics] = this.azureLogAnalyticsDatasource;
|
||||
pseudoDatasource[AzureQueryType.AzureResourceGraph] = this.azureResourceGraphDatasource;
|
||||
this.pseudoDatasource = {
|
||||
[AzureQueryType.AzureMonitor]: this.azureMonitorDatasource,
|
||||
[AzureQueryType.LogAnalytics]: this.azureLogAnalyticsDatasource,
|
||||
[AzureQueryType.AzureResourceGraph]: this.azureResourceGraphDatasource,
|
||||
};
|
||||
|
||||
const cloud = getAzureCloud(instanceSettings);
|
||||
if (cloud === 'azuremonitor' || cloud === 'chinaazuremonitor') {
|
||||
// AppInsights and InsightAnalytics are only supported for Public and Azure China clouds
|
||||
this.appInsightsDatasource = new AppInsightsDatasource(instanceSettings);
|
||||
this.insightsAnalyticsDatasource = new InsightsAnalyticsDatasource(instanceSettings);
|
||||
pseudoDatasource[AzureQueryType.ApplicationInsights] = this.appInsightsDatasource;
|
||||
pseudoDatasource[AzureQueryType.InsightsAnalytics] = this.insightsAnalyticsDatasource;
|
||||
this.pseudoDatasource[AzureQueryType.ApplicationInsights] = this.appInsightsDatasource;
|
||||
this.pseudoDatasource[AzureQueryType.InsightsAnalytics] = this.insightsAnalyticsDatasource;
|
||||
}
|
||||
this.pseudoDatasource = pseudoDatasource;
|
||||
|
||||
const optionsKey: any = {};
|
||||
optionsKey[AzureQueryType.ApplicationInsights] = 'appInsights';
|
||||
optionsKey[AzureQueryType.AzureMonitor] = 'azureMonitor';
|
||||
optionsKey[AzureQueryType.InsightsAnalytics] = 'insightsAnalytics';
|
||||
optionsKey[AzureQueryType.LogAnalytics] = 'azureLogAnalytics';
|
||||
optionsKey[AzureQueryType.AzureResourceGraph] = 'azureResourceGraph';
|
||||
this.optionsKey = optionsKey;
|
||||
}
|
||||
|
||||
query(options: DataQueryRequest<AzureMonitorQuery>): Observable<DataQueryResponse> {
|
||||
console.log('query options.targets', options.targets);
|
||||
|
||||
const byType = new Map<AzureQueryType, DataQueryRequest<AzureMonitorQuery>>();
|
||||
|
||||
for (const target of options.targets) {
|
||||
// Migrate old query structure
|
||||
migrateQuery(target);
|
||||
|
||||
// Check that we have options
|
||||
const opts = (target as any)[this.optionsKey[target.queryType]];
|
||||
|
||||
// Skip hidden queries or ones without properties
|
||||
if (target.hide || !opts) {
|
||||
// Skip hidden or invalid queries or ones without properties
|
||||
if (!target.queryType || target.hide || !hasQueryForType(target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -102,7 +101,12 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
}
|
||||
|
||||
const observables: Array<Observable<DataQueryResponse>> = Array.from(byType.entries()).map(([queryType, req]) => {
|
||||
return this.pseudoDatasource[queryType].query(req);
|
||||
const ds = this.pseudoDatasource[queryType];
|
||||
if (!ds) {
|
||||
throw new Error('Data source not created for query type ' + queryType);
|
||||
}
|
||||
|
||||
return ds.query(req);
|
||||
});
|
||||
|
||||
// Single query can skip merge
|
||||
@ -270,9 +274,16 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
}
|
||||
|
||||
interpolateVariablesInQueries(queries: AzureMonitorQuery[], scopedVars: ScopedVars): AzureMonitorQuery[] {
|
||||
return queries.map(
|
||||
(query) => this.pseudoDatasource[query.queryType].applyTemplateVariables(query, scopedVars) as AzureMonitorQuery
|
||||
);
|
||||
const mapped = queries.map((query) => {
|
||||
if (!query.queryType) {
|
||||
return query;
|
||||
}
|
||||
|
||||
const ds = this.pseudoDatasource[query.queryType];
|
||||
return ds?.applyTemplateVariables(query, scopedVars) ?? query;
|
||||
});
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
replaceTemplateVariable(variable: string) {
|
||||
@ -296,7 +307,29 @@ function migrateQuery(target: AzureMonitorQuery) {
|
||||
target.queryType = AzureQueryType.AzureMonitor;
|
||||
}
|
||||
|
||||
if (target.queryType === AzureQueryType.AzureMonitor) {
|
||||
if (target.queryType === AzureQueryType.AzureMonitor && target.azureMonitor) {
|
||||
migrateMetricsDimensionFilters(target.azureMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
function hasQueryForType(query: AzureMonitorQuery): boolean {
|
||||
switch (query.queryType) {
|
||||
case AzureQueryType.AzureMonitor:
|
||||
return !!query.azureMonitor;
|
||||
|
||||
case AzureQueryType.LogAnalytics:
|
||||
return !!query.azureLogAnalytics;
|
||||
|
||||
case AzureQueryType.AzureResourceGraph:
|
||||
return !!query.azureResourceGraph;
|
||||
|
||||
case AzureQueryType.ApplicationInsights:
|
||||
return !!query.appInsights;
|
||||
|
||||
case AzureQueryType.InsightsAnalytics:
|
||||
return !!query.insightsAnalytics;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -9,20 +9,19 @@ export default class InsightsAnalyticsDatasource extends AppInsightsDatasource {
|
||||
super(instanceSettings);
|
||||
}
|
||||
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery {
|
||||
const item = target.insightsAnalytics;
|
||||
|
||||
// Old name migrations
|
||||
const old: any = item;
|
||||
if (old.rawQueryString && !item.query) {
|
||||
item.query = old.rawQueryString;
|
||||
if (!item) {
|
||||
return target;
|
||||
}
|
||||
|
||||
const query = item.rawQueryString && !item.query ? item.rawQueryString : item.query;
|
||||
|
||||
return {
|
||||
refId: target.refId,
|
||||
queryType: AzureQueryType.InsightsAnalytics,
|
||||
insightsAnalytics: {
|
||||
query: getTemplateSrv().replace(item.query, scopedVars),
|
||||
query: getTemplateSrv().replace(query, scopedVars),
|
||||
resultFormat: item.resultFormat,
|
||||
},
|
||||
};
|
||||
|
@ -206,7 +206,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
if (this.target.azureMonitor.timeGrainUnit) {
|
||||
if (this.target.azureMonitor.timeGrain !== 'auto') {
|
||||
this.target.azureMonitor.timeGrain = TimegrainConverter.createISO8601Duration(
|
||||
this.target.azureMonitor.timeGrain,
|
||||
this.target.azureMonitor.timeGrain ?? 'auto',
|
||||
this.target.azureMonitor.timeGrainUnit
|
||||
);
|
||||
}
|
||||
@ -372,7 +372,10 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
getAzureMonitorAutoInterval() {
|
||||
return this.generateAutoUnits(this.target.azureMonitor.timeGrain, (this.target.azureMonitor as any).timeGrains);
|
||||
return this.generateAutoUnits(
|
||||
this.target.azureMonitor.timeGrain ?? 'auto',
|
||||
(this.target.azureMonitor as any).timeGrains
|
||||
);
|
||||
}
|
||||
|
||||
getApplicationInsightAutoInterval() {
|
||||
@ -380,6 +383,9 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
azureMonitorAddDimensionFilter() {
|
||||
this.target.azureMonitor = this.target.azureMonitor ?? {};
|
||||
this.target.azureMonitor.dimensionFilters = this.target.azureMonitor.dimensionFilters ?? [];
|
||||
|
||||
this.target.azureMonitor.dimensionFilters.push({
|
||||
dimension: '',
|
||||
operator: 'eq',
|
||||
@ -388,6 +394,9 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
azureMonitorRemoveDimensionFilter(index: number) {
|
||||
this.target.azureMonitor = this.target.azureMonitor ?? {};
|
||||
this.target.azureMonitor.dimensionFilters = this.target.azureMonitor.dimensionFilters ?? [];
|
||||
|
||||
this.target.azureMonitor.dimensionFilters.splice(index, 1);
|
||||
this.refresh();
|
||||
}
|
||||
|
@ -1,260 +1,3 @@
|
||||
import {
|
||||
DataQuery,
|
||||
DataSourceInstanceSettings,
|
||||
DataSourceJsonData,
|
||||
DataSourceSettings,
|
||||
TableData,
|
||||
} from '@grafana/data';
|
||||
import Datasource from '../datasource';
|
||||
|
||||
export type AzureDataSourceSettings = DataSourceSettings<AzureDataSourceJsonData, AzureDataSourceSecureJsonData>;
|
||||
export type AzureDataSourceInstanceSettings = DataSourceInstanceSettings<AzureDataSourceJsonData>;
|
||||
|
||||
export interface DatasourceValidationResult {
|
||||
status: 'success' | 'error';
|
||||
message: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export type AzureResultFormat = 'time_series' | 'table';
|
||||
|
||||
export enum AzureQueryType {
|
||||
AzureMonitor = 'Azure Monitor',
|
||||
ApplicationInsights = 'Application Insights',
|
||||
InsightsAnalytics = 'Insights Analytics',
|
||||
LogAnalytics = 'Azure Log Analytics',
|
||||
AzureResourceGraph = 'Azure Resource Graph',
|
||||
}
|
||||
|
||||
export interface AzureMonitorQuery extends DataQuery {
|
||||
queryType: AzureQueryType;
|
||||
format: string;
|
||||
subscription: string;
|
||||
subscriptions: string[];
|
||||
|
||||
azureMonitor: AzureMetricQuery;
|
||||
azureLogAnalytics: AzureLogsQuery;
|
||||
appInsights?: ApplicationInsightsQuery;
|
||||
insightsAnalytics: InsightsAnalyticsQuery;
|
||||
azureResourceGraph: AzureResourceGraphQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure clouds known to Azure Monitor.
|
||||
*/
|
||||
export enum AzureCloud {
|
||||
Public = 'AzureCloud',
|
||||
China = 'AzureChinaCloud',
|
||||
USGovernment = 'AzureUSGovernment',
|
||||
Germany = 'AzureGermanCloud',
|
||||
None = '',
|
||||
}
|
||||
|
||||
export type AzureAuthType = 'msi' | 'clientsecret';
|
||||
|
||||
export type ConcealedSecret = symbol;
|
||||
|
||||
interface AzureCredentialsBase {
|
||||
authType: AzureAuthType;
|
||||
defaultSubscriptionId?: string;
|
||||
}
|
||||
|
||||
export interface AzureManagedIdentityCredentials extends AzureCredentialsBase {
|
||||
authType: 'msi';
|
||||
}
|
||||
|
||||
export interface AzureClientSecretCredentials extends AzureCredentialsBase {
|
||||
authType: 'clientsecret';
|
||||
azureCloud?: string;
|
||||
tenantId?: string;
|
||||
clientId?: string;
|
||||
clientSecret?: string | ConcealedSecret;
|
||||
}
|
||||
|
||||
export type AzureCredentials = AzureManagedIdentityCredentials | AzureClientSecretCredentials;
|
||||
|
||||
export interface AzureDataSourceJsonData extends DataSourceJsonData {
|
||||
cloudName: string;
|
||||
azureAuthType?: AzureAuthType;
|
||||
|
||||
// monitor
|
||||
tenantId?: string;
|
||||
clientId?: string;
|
||||
subscriptionId?: string;
|
||||
|
||||
// logs
|
||||
logAnalyticsDefaultWorkspace?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
azureLogAnalyticsSameAs?: boolean;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsTenantId?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsClientId?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsSubscriptionId?: string;
|
||||
|
||||
// App Insights
|
||||
appInsightsAppId?: string;
|
||||
}
|
||||
|
||||
export interface AzureDataSourceSecureJsonData {
|
||||
clientSecret?: string;
|
||||
appInsightsApiKey?: string;
|
||||
}
|
||||
|
||||
export interface AzureMetricDimension {
|
||||
dimension: string;
|
||||
operator: 'eq'; // future proof
|
||||
filter?: string; // *
|
||||
}
|
||||
|
||||
export interface AzureMetricQuery {
|
||||
resourceGroup: string | undefined;
|
||||
resourceName: string | undefined;
|
||||
metricDefinition: string | undefined;
|
||||
metricNamespace: string | undefined;
|
||||
metricName: string | undefined;
|
||||
timeGrainUnit?: string;
|
||||
timeGrain: string;
|
||||
allowedTimeGrainsMs: number[];
|
||||
aggregation: string | undefined;
|
||||
dimensionFilters: AzureMetricDimension[];
|
||||
alias: string;
|
||||
top: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsQuery {
|
||||
query: string;
|
||||
resultFormat: string;
|
||||
resource?: string;
|
||||
|
||||
/** @deprecated Queries should be migrated to use Resource instead */
|
||||
workspace?: string;
|
||||
}
|
||||
|
||||
export interface AzureResourceGraphQuery {
|
||||
query: string;
|
||||
resultFormat: string;
|
||||
}
|
||||
|
||||
export interface ApplicationInsightsQuery {
|
||||
metricName: string;
|
||||
timeGrain: string;
|
||||
timeGrainCount: string;
|
||||
timeGrainType: string;
|
||||
timeGrainUnit: string;
|
||||
aggregation: string;
|
||||
dimension: string[]; // Was string before 7.1
|
||||
// dimensions: string[]; why is this metadata stored on the object!
|
||||
dimensionFilter: string;
|
||||
alias: string;
|
||||
}
|
||||
|
||||
export interface InsightsAnalyticsQuery {
|
||||
query: string;
|
||||
resultFormat: string;
|
||||
}
|
||||
|
||||
// Represents an errors that come back from frontend requests.
|
||||
// Not totally sure how accurate this type is.
|
||||
export type AzureMonitorErrorish = Error;
|
||||
|
||||
// Azure Monitor API Types
|
||||
|
||||
export interface AzureMonitorMetricsMetadataResponse {
|
||||
value: AzureMonitorMetricMetadataItem[];
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricMetadataItem {
|
||||
id: string;
|
||||
resourceId: string;
|
||||
primaryAggregationType: string;
|
||||
supportedAggregationTypes: string[];
|
||||
name: AzureMonitorLocalizedValue;
|
||||
dimensions?: AzureMonitorLocalizedValue[];
|
||||
metricAvailabilities?: AzureMonitorMetricAvailabilityMetadata[];
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricAvailabilityMetadata {
|
||||
timeGrain: string;
|
||||
retention: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorLocalizedValue {
|
||||
value: string;
|
||||
localizedValue: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricDefinitionsResponse {
|
||||
data: {
|
||||
value: Array<{ name: string; type: string; location?: string }>;
|
||||
};
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorResourceGroupsResponse {
|
||||
data: {
|
||||
value: Array<{ name: string }>;
|
||||
};
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsVariable {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsTableData extends TableData {
|
||||
columns: AzureLogsTableColumn[];
|
||||
rows: any[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsTableColumn {
|
||||
text: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorOption<T = string> {
|
||||
label: string;
|
||||
value: T;
|
||||
}
|
||||
|
||||
export interface AzureQueryEditorFieldProps {
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
subscriptionId?: string;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
|
||||
onQueryChange: (newQuery: AzureMonitorQuery) => void;
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
}
|
||||
|
||||
export interface AzureResourceSummaryItem {
|
||||
subscriptionName: string;
|
||||
resourceGroupName: string | undefined;
|
||||
resourceName: string | undefined;
|
||||
}
|
||||
|
||||
export interface RawAzureResourceGroupItem {
|
||||
subscriptionURI: string;
|
||||
subscriptionName: string;
|
||||
|
||||
resourceGroupURI: string;
|
||||
resourceGroupName: string;
|
||||
}
|
||||
|
||||
export interface RawAzureResourceItem {
|
||||
id: string;
|
||||
name: string;
|
||||
subscriptionId: string;
|
||||
resourceGroup: string;
|
||||
type: string;
|
||||
location: string;
|
||||
}
|
||||
|
||||
export interface AzureGraphResponse<T = unknown> {
|
||||
data: T;
|
||||
}
|
||||
export * from './logAnalyticsMetadata';
|
||||
export * from './query';
|
||||
export * from './types';
|
||||
|
@ -0,0 +1,105 @@
|
||||
import { DataQuery } from '@grafana/data';
|
||||
|
||||
export enum AzureQueryType {
|
||||
AzureMonitor = 'Azure Monitor',
|
||||
ApplicationInsights = 'Application Insights',
|
||||
InsightsAnalytics = 'Insights Analytics',
|
||||
LogAnalytics = 'Azure Log Analytics',
|
||||
AzureResourceGraph = 'Azure Resource Graph',
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the query as it moves through the frontend query editor and datasource files.
|
||||
* It can represent new queries that are still being edited, so all properties are optional
|
||||
*/
|
||||
export interface AzureMonitorQuery extends DataQuery {
|
||||
queryType?: AzureQueryType;
|
||||
|
||||
subscription?: string;
|
||||
|
||||
/** ARG uses multiple subscriptions */
|
||||
subscriptions?: string[];
|
||||
|
||||
azureMonitor?: AzureMetricQuery;
|
||||
azureLogAnalytics?: AzureLogsQuery;
|
||||
azureResourceGraph?: AzureResourceGraphQuery;
|
||||
|
||||
/** @deprecated App Insights/Insights Analytics deprecated in v8 */
|
||||
appInsights?: ApplicationInsightsQuery;
|
||||
|
||||
/** @deprecated App Insights/Insights Analytics deprecated in v8 */
|
||||
insightsAnalytics?: InsightsAnalyticsQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure Monitor Metrics sub-query properties
|
||||
*/
|
||||
export interface AzureMetricQuery {
|
||||
resourceGroup?: string;
|
||||
resourceName?: string;
|
||||
metricDefinition?: string;
|
||||
metricNamespace?: string;
|
||||
metricName?: string;
|
||||
timeGrain?: string;
|
||||
allowedTimeGrainsMs?: number[];
|
||||
aggregation?: string;
|
||||
dimensionFilters?: AzureMetricDimension[];
|
||||
alias?: string;
|
||||
top?: string;
|
||||
|
||||
/** @deprecated */
|
||||
timeGrainUnit?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure Monitor Logs sub-query properties
|
||||
*/
|
||||
export interface AzureLogsQuery {
|
||||
query?: string;
|
||||
resultFormat?: string;
|
||||
resource?: string;
|
||||
|
||||
workspace?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure Monitor ARG sub-query properties
|
||||
*/
|
||||
export interface AzureResourceGraphQuery {
|
||||
query?: string;
|
||||
resultFormat?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure Monitor App Insights sub-query properties
|
||||
* @deprecated App Insights deprecated in v8 in favor of Metrics queries
|
||||
*/
|
||||
export interface ApplicationInsightsQuery {
|
||||
metricName?: string;
|
||||
timeGrain?: string;
|
||||
timeGrainCount?: string;
|
||||
timeGrainType?: string;
|
||||
timeGrainUnit?: string;
|
||||
aggregation?: string;
|
||||
dimension?: string[]; // Was string before 7.1
|
||||
dimensionFilter?: string;
|
||||
alias?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure Monitor Insights Analytics sub-query properties
|
||||
* @deprecated Insights Analytics deprecated in v8 in favor of Logs queries
|
||||
*/
|
||||
export interface InsightsAnalyticsQuery {
|
||||
query?: string;
|
||||
resultFormat?: string;
|
||||
|
||||
/** @deprecated Migrate field to query */
|
||||
rawQueryString?: string;
|
||||
}
|
||||
|
||||
export interface AzureMetricDimension {
|
||||
dimension: string;
|
||||
operator: 'eq'; // future proof
|
||||
filter?: string; // *
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourceSettings, TableData } from '@grafana/data';
|
||||
import Datasource from '../datasource';
|
||||
|
||||
import { AzureMonitorQuery } from './query';
|
||||
|
||||
export type AzureDataSourceSettings = DataSourceSettings<AzureDataSourceJsonData, AzureDataSourceSecureJsonData>;
|
||||
export type AzureDataSourceInstanceSettings = DataSourceInstanceSettings<AzureDataSourceJsonData>;
|
||||
|
||||
export interface DatasourceValidationResult {
|
||||
status: 'success' | 'error';
|
||||
message: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export type AzureResultFormat = 'time_series' | 'table';
|
||||
|
||||
/**
|
||||
* Azure clouds known to Azure Monitor.
|
||||
*/
|
||||
export enum AzureCloud {
|
||||
Public = 'AzureCloud',
|
||||
China = 'AzureChinaCloud',
|
||||
USGovernment = 'AzureUSGovernment',
|
||||
Germany = 'AzureGermanCloud',
|
||||
None = '',
|
||||
}
|
||||
|
||||
export type AzureAuthType = 'msi' | 'clientsecret';
|
||||
|
||||
export type ConcealedSecret = symbol;
|
||||
|
||||
interface AzureCredentialsBase {
|
||||
authType: AzureAuthType;
|
||||
defaultSubscriptionId?: string;
|
||||
}
|
||||
|
||||
export interface AzureManagedIdentityCredentials extends AzureCredentialsBase {
|
||||
authType: 'msi';
|
||||
}
|
||||
|
||||
export interface AzureClientSecretCredentials extends AzureCredentialsBase {
|
||||
authType: 'clientsecret';
|
||||
azureCloud?: string;
|
||||
tenantId?: string;
|
||||
clientId?: string;
|
||||
clientSecret?: string | ConcealedSecret;
|
||||
}
|
||||
|
||||
export type AzureCredentials = AzureManagedIdentityCredentials | AzureClientSecretCredentials;
|
||||
|
||||
export interface AzureDataSourceJsonData extends DataSourceJsonData {
|
||||
cloudName: string;
|
||||
azureAuthType?: AzureAuthType;
|
||||
|
||||
// monitor
|
||||
tenantId?: string;
|
||||
clientId?: string;
|
||||
subscriptionId?: string;
|
||||
|
||||
// logs
|
||||
logAnalyticsDefaultWorkspace?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
azureLogAnalyticsSameAs?: boolean;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsTenantId?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsClientId?: string;
|
||||
/** @deprecated Azure Logs credentials */
|
||||
logAnalyticsSubscriptionId?: string;
|
||||
|
||||
// App Insights
|
||||
appInsightsAppId?: string;
|
||||
}
|
||||
|
||||
export interface AzureDataSourceSecureJsonData {
|
||||
clientSecret?: string;
|
||||
appInsightsApiKey?: string;
|
||||
}
|
||||
|
||||
// Represents an errors that come back from frontend requests.
|
||||
// Not totally sure how accurate this type is.
|
||||
export type AzureMonitorErrorish = Error;
|
||||
|
||||
// Azure Monitor API Types
|
||||
export interface AzureMonitorMetricsMetadataResponse {
|
||||
value: AzureMonitorMetricMetadataItem[];
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricMetadataItem {
|
||||
id: string;
|
||||
resourceId: string;
|
||||
primaryAggregationType: string;
|
||||
supportedAggregationTypes: string[];
|
||||
name: AzureMonitorLocalizedValue;
|
||||
dimensions?: AzureMonitorLocalizedValue[];
|
||||
metricAvailabilities?: AzureMonitorMetricAvailabilityMetadata[];
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricAvailabilityMetadata {
|
||||
timeGrain: string;
|
||||
retention: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorLocalizedValue {
|
||||
value: string;
|
||||
localizedValue: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorMetricDefinitionsResponse {
|
||||
data: {
|
||||
value: Array<{ name: string; type: string; location?: string }>;
|
||||
};
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorResourceGroupsResponse {
|
||||
data: {
|
||||
value: Array<{ name: string }>;
|
||||
};
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsVariable {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsTableData extends TableData {
|
||||
columns: AzureLogsTableColumn[];
|
||||
rows: any[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface AzureLogsTableColumn {
|
||||
text: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorOption<T = string> {
|
||||
label: string;
|
||||
value: T;
|
||||
}
|
||||
|
||||
export interface AzureQueryEditorFieldProps {
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
subscriptionId?: string;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
|
||||
onQueryChange: (newQuery: AzureMonitorQuery) => void;
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
}
|
||||
|
||||
export interface AzureResourceSummaryItem {
|
||||
subscriptionName: string;
|
||||
resourceGroupName: string | undefined;
|
||||
resourceName: string | undefined;
|
||||
}
|
||||
|
||||
export interface RawAzureResourceGroupItem {
|
||||
subscriptionURI: string;
|
||||
subscriptionName: string;
|
||||
|
||||
resourceGroupURI: string;
|
||||
resourceGroupName: string;
|
||||
}
|
||||
|
||||
export interface RawAzureResourceItem {
|
||||
id: string;
|
||||
name: string;
|
||||
subscriptionId: string;
|
||||
resourceGroup: string;
|
||||
type: string;
|
||||
location: string;
|
||||
}
|
||||
|
||||
export interface AzureGraphResponse<T = unknown> {
|
||||
data: T;
|
||||
}
|
Loading…
Reference in New Issue
Block a user