mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Convert Logs to React (#32315)
* Convert Logs to React * copy changes * fix effect deps * tests for logs * remove any from test * Update QueryEditor.tsx
This commit is contained in:
parent
7ea58f9cf5
commit
d2bdb4ed41
@ -17,6 +17,8 @@ export default function createMockDatasource() {
|
||||
getSubscriptions: jest.fn().mockResolvedValueOnce([]),
|
||||
},
|
||||
|
||||
getAzureLogAnalyticsWorkspaces: jest.fn().mockResolvedValueOnce([]),
|
||||
|
||||
getResourceGroups: jest.fn().mockResolvedValueOnce([]),
|
||||
getMetricDefinitions: jest.fn().mockResolvedValueOnce([]),
|
||||
getResourceNames: jest.fn().mockResolvedValueOnce([]),
|
||||
|
@ -0,0 +1,47 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { AzureMonitorOption, AzureQueryEditorFieldProps, AzureResultFormat } from '../../types';
|
||||
import { findOption } from '../../utils/common';
|
||||
import { Field } from '../Field';
|
||||
|
||||
const FORMAT_OPTIONS: Array<AzureMonitorOption<AzureResultFormat>> = [
|
||||
{ label: 'Time series', value: 'time_series' },
|
||||
{ label: 'Table', value: 'table' },
|
||||
];
|
||||
|
||||
const FormatAsField: React.FC<AzureQueryEditorFieldProps> = ({ query, variableOptionGroup, onQueryChange }) => {
|
||||
const options = useMemo(() => [...FORMAT_OPTIONS, variableOptionGroup], [variableOptionGroup]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(change: SelectableValue<AzureResultFormat>) => {
|
||||
const { value } = change;
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
onQueryChange({
|
||||
...query,
|
||||
azureLogAnalytics: {
|
||||
...query.azureLogAnalytics,
|
||||
resultFormat: value,
|
||||
},
|
||||
});
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
return (
|
||||
<Field label="Format as">
|
||||
<Select
|
||||
inputId="azure-monitor-logs-workspaces-field"
|
||||
value={findOption(FORMAT_OPTIONS, query.azureLogAnalytics.resultFormat)}
|
||||
onChange={handleChange}
|
||||
options={options}
|
||||
width={38}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormatAsField;
|
@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types';
|
||||
import Datasource from '../../datasource';
|
||||
import { InlineFieldRow } from '@grafana/ui';
|
||||
import SubscriptionField from '../SubscriptionField';
|
||||
import WorkspaceField from './WorkspaceField';
|
||||
import QueryField from './QueryField';
|
||||
import FormatAsField from './FormatAsField';
|
||||
|
||||
interface LogsQueryEditorProps {
|
||||
query: AzureMonitorQuery;
|
||||
datasource: Datasource;
|
||||
subscriptionId: string;
|
||||
onChange: (newQuery: AzureMonitorQuery) => void;
|
||||
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
|
||||
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
|
||||
}
|
||||
|
||||
const LogsQueryEditor: React.FC<LogsQueryEditorProps> = ({
|
||||
query,
|
||||
datasource,
|
||||
subscriptionId,
|
||||
variableOptionGroup,
|
||||
onChange,
|
||||
setError,
|
||||
}) => {
|
||||
return (
|
||||
<div data-testid="azure-monitor-logs-query-editor">
|
||||
<InlineFieldRow>
|
||||
<SubscriptionField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
<WorkspaceField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</InlineFieldRow>
|
||||
|
||||
<QueryField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
|
||||
<FormatAsField
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
subscriptionId={subscriptionId}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onQueryChange={onChange}
|
||||
setError={setError}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogsQueryEditor;
|
@ -0,0 +1,32 @@
|
||||
import { CodeEditor } from '@grafana/ui';
|
||||
import React, { useCallback } from 'react';
|
||||
import { AzureQueryEditorFieldProps } from '../../types';
|
||||
|
||||
const QueryField: React.FC<AzureQueryEditorFieldProps> = ({ query, onQueryChange }) => {
|
||||
const onChange = useCallback(
|
||||
(newQuery: string) => {
|
||||
onQueryChange({
|
||||
...query,
|
||||
azureLogAnalytics: {
|
||||
...query.azureLogAnalytics,
|
||||
query: newQuery,
|
||||
},
|
||||
});
|
||||
},
|
||||
[onQueryChange, query]
|
||||
);
|
||||
|
||||
return (
|
||||
<CodeEditor
|
||||
value={query.azureLogAnalytics.query}
|
||||
language="kql"
|
||||
height={200}
|
||||
width="100%"
|
||||
showMiniMap={false}
|
||||
onBlur={onChange}
|
||||
onSave={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default QueryField;
|
@ -0,0 +1,64 @@
|
||||
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([]);
|
||||
}
|
||||
|
||||
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;
|
@ -0,0 +1 @@
|
||||
export { default } from './LogsQueryEditor';
|
@ -26,7 +26,7 @@ const LegendFormatField: React.FC<AzureQueryEditorFieldProps> = ({ onQueryChange
|
||||
}, [onQueryChange, query, value]);
|
||||
|
||||
return (
|
||||
<Field label="Legend Format">
|
||||
<Field label="Legend format">
|
||||
<Input
|
||||
id="azure-monitor-metrics-legend-field"
|
||||
placeholder="Alias patterns"
|
||||
|
@ -65,7 +65,7 @@ const MetricNamespaceField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const options = useMemo(() => [...metricNamespaces, variableOptionGroup], [metricNamespaces, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Metric Namespace">
|
||||
<Field label="Metric namespace">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-metric-namespace-field"
|
||||
value={findOption(metricNamespaces, query.azureMonitor.metricNamespace)}
|
||||
|
@ -59,7 +59,7 @@ const ResourceGroupsField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
const options = useMemo(() => [...resourceGroups, variableOptionGroup], [resourceGroups, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Resource Group">
|
||||
<Field label="Resource group">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-group-field"
|
||||
value={findOption(resourceGroups, query.azureMonitor.resourceGroup)}
|
||||
|
@ -58,7 +58,7 @@ const ResourceNameField: React.FC<AzureQueryEditorFieldProps> = ({
|
||||
|
||||
const selectedResourceNameValue = findOption(resourceNames, query.azureMonitor.resourceName);
|
||||
return (
|
||||
<Field label="Resource Name">
|
||||
<Field label="Resource name">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-resource-name-field"
|
||||
value={selectedResourceNameValue}
|
||||
|
@ -55,7 +55,7 @@ const TimeGrainField: React.FC<TimeGrainFieldProps> = ({
|
||||
}, [timeGrainOptions, variableOptionGroup]);
|
||||
|
||||
return (
|
||||
<Field label="Time Grain">
|
||||
<Field label="Time grain">
|
||||
<Select
|
||||
inputId="azure-monitor-metrics-time-grain-field"
|
||||
value={findOption(timeGrainOptions, query.azureMonitor.timeGrain)}
|
||||
|
@ -8,6 +8,15 @@ import createMockQuery from '../../__mocks__/query';
|
||||
import createMockDatasource from '../../__mocks__/datasource';
|
||||
import { AzureQueryType } from '../../types';
|
||||
import { invalidNamespaceError } from '../../__mocks__/errors';
|
||||
import * as ui from '@grafana/ui';
|
||||
|
||||
// Have to mock CodeEditor because it doesnt seem to work in tests???
|
||||
jest.mock('@grafana/ui', () => ({
|
||||
...jest.requireActual<typeof ui>('@grafana/ui'),
|
||||
CodeEditor: function CodeEditor({ value }: { value: string }) {
|
||||
return <pre>{value}</pre>;
|
||||
},
|
||||
}));
|
||||
|
||||
const variableOptionGroup = {
|
||||
label: 'Template variables',
|
||||
@ -17,9 +26,14 @@ const variableOptionGroup = {
|
||||
describe('Azure Monitor QueryEditor', () => {
|
||||
it('renders the Metrics query editor when the query type is Metrics', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const mockQuery = {
|
||||
...createMockQuery(),
|
||||
queryType: AzureQueryType.AzureMonitor,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={createMockQuery()}
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
@ -28,22 +42,22 @@ describe('Azure Monitor QueryEditor', () => {
|
||||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it("does not render the Metrics query editor when the query type isn't Metrics", async () => {
|
||||
it('renders the Metrics query editor when the query type is Metrics', async () => {
|
||||
const mockDatasource = createMockDatasource();
|
||||
const mockQuery = createMockQuery();
|
||||
const logsMockQuery = {
|
||||
...mockQuery,
|
||||
const mockQuery = {
|
||||
...createMockQuery(),
|
||||
queryType: AzureQueryType.LogAnalytics,
|
||||
};
|
||||
|
||||
render(
|
||||
<QueryEditor
|
||||
query={logsMockQuery}
|
||||
query={mockQuery}
|
||||
datasource={mockDatasource}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => expect(screen.queryByTestId('azure-monitor-metrics-query-editor')).not.toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByTestId('azure-monitor-logs-query-editor')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('changes the query type when selected', async () => {
|
||||
|
@ -5,6 +5,7 @@ import { AzureMonitorQuery, AzureQueryType, AzureMonitorOption, AzureMonitorErro
|
||||
import MetricsQueryEditor from '../MetricsQueryEditor';
|
||||
import QueryTypeField from './QueryTypeField';
|
||||
import useLastError from '../../utils/useLastError';
|
||||
import LogsQueryEditor from '../LogsQueryEditor';
|
||||
|
||||
interface BaseQueryEditorProps {
|
||||
query: AzureMonitorQuery;
|
||||
@ -70,6 +71,18 @@ const EditorForQueryType: React.FC<EditorForQueryTypeProps> = ({
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
|
||||
case AzureQueryType.LogAnalytics:
|
||||
return (
|
||||
<LogsQueryEditor
|
||||
subscriptionId={subscriptionId}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
onChange={onChange}
|
||||
variableOptionGroup={variableOptionGroup}
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -30,7 +30,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
];
|
||||
|
||||
// Query types that have been migrated to React
|
||||
reactQueryEditors = [AzureQueryType.AzureMonitor];
|
||||
reactQueryEditors = [AzureQueryType.AzureMonitor, AzureQueryType.LogAnalytics];
|
||||
|
||||
// target: AzureMonitorQuery;
|
||||
|
||||
|
@ -3,6 +3,8 @@ import Datasource from './datasource';
|
||||
|
||||
export type AzureDataSourceSettings = DataSourceSettings<AzureDataSourceJsonData, AzureDataSourceSecureJsonData>;
|
||||
|
||||
export type AzureResultFormat = 'time_series' | 'table';
|
||||
|
||||
export enum AzureQueryType {
|
||||
AzureMonitor = 'Azure Monitor',
|
||||
ApplicationInsights = 'Application Insights',
|
||||
|
Loading…
Reference in New Issue
Block a user