Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure Monitor: Fix subscription selector when changing data sources #56284

Merged
merged 4 commits into from Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,84 @@
import { render, screen } from '@testing-library/react';
import React from 'react';

import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';

import ArgQueryEditor from './ArgQueryEditor';

jest.mock('@grafana/runtime', () => ({
...(jest.requireActual('@grafana/runtime') as unknown as object),
getTemplateSrv: () => ({
replace: (val: string) => {
return val;
},
}),
}));

const variableOptionGroup = {
label: 'Template variables',
options: [],
};

const defaultProps = {
query: createMockQuery(),
datasource: createMockDatasource(),
variableOptionGroup: variableOptionGroup,
onChange: jest.fn(),
setError: jest.fn(),
};

describe('ArgQueryEditor', () => {
it('should render', async () => {
render(<ArgQueryEditor {...defaultProps} />);
expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument();
});

it('should select a subscription from the fetched array', async () => {
const datasource = createMockDatasource({
getSubscriptions: jest.fn().mockResolvedValue([{ value: 'foo' }]),
});
const onChange = jest.fn();
render(<ArgQueryEditor {...defaultProps} datasource={datasource} onChange={onChange} />);
expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument();
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo'] }));
});

it('should select a subscription from existing query', async () => {
const onChange = jest.fn();
const query = createMockQuery({
subscriptions: ['bar'],
});
render(<ArgQueryEditor {...defaultProps} onChange={onChange} query={query} />);
expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument();
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['bar'] }));
});

it('should change the subscription if the selected one is not part of the fetched array', async () => {
const onChange = jest.fn();
const datasource = createMockDatasource({
getSubscriptions: jest.fn().mockResolvedValue([{ value: 'foo' }]),
});
const query = createMockQuery({
subscriptions: ['bar'],
});
render(<ArgQueryEditor {...defaultProps} datasource={datasource} onChange={onChange} query={query} />);
expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument();
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo'] }));
expect(onChange).not.toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['bar'] }));
});

it('should keep a subset of subscriptions if the new list does not contain all the query subscriptions', async () => {
const onChange = jest.fn();
const datasource = createMockDatasource({
getSubscriptions: jest.fn().mockResolvedValue([{ value: 'foo' }, { value: 'bar' }]),
});
const query = createMockQuery({
subscriptions: ['foo', 'bar', 'foobar'],
});
render(<ArgQueryEditor {...defaultProps} datasource={datasource} onChange={onChange} query={query} />);
expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument();
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo', 'bar'] }));
expect(onChange).not.toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo', 'bar', 'foobar'] }));
});
});
@@ -1,4 +1,5 @@
import React, { useEffect, useState, useRef } from 'react';
import { intersection } from 'lodash';
import React, { useState, useMemo } from 'react';

import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/ui';

Expand All @@ -18,6 +19,28 @@ interface ArgQueryEditorProps {
}

const ERROR_SOURCE = 'arg-subscriptions';

function selectSubscriptions(
fetchedSubscriptions: string[],
currentSubscriptions?: string[],
currentSubscription?: string
) {
let querySubscriptions = currentSubscriptions || [];
if (querySubscriptions.length === 0 && currentSubscription) {
querySubscriptions = [currentSubscription];
}
if (querySubscriptions.length === 0 && fetchedSubscriptions.length) {
querySubscriptions = [fetchedSubscriptions[0]];
}
const commonSubscriptions = intersection(querySubscriptions, fetchedSubscriptions);
if (fetchedSubscriptions.length && querySubscriptions.length > commonSubscriptions.length) {
// If not all of the query subscriptions are in the list of fetched subscriptions, then
// select only the ones present (or the first one if none is present)
querySubscriptions = commonSubscriptions.length > 0 ? commonSubscriptions : [fetchedSubscriptions[0]];
}
return querySubscriptions;
}

const ArgQueryEditor: React.FC<ArgQueryEditorProps> = ({
query,
datasource,
Expand All @@ -26,31 +49,28 @@ const ArgQueryEditor: React.FC<ArgQueryEditorProps> = ({
onChange,
setError,
}) => {
const fetchedRef = useRef(false);
const [subscriptions, setSubscriptions] = useState<AzureMonitorOption[]>([]);

useEffect(() => {
if (fetchedRef.current) {
return;
}

fetchedRef.current = true;
useMemo(() => {
datasource
.getSubscriptions()
.then((results) => {
const fetchedSubscriptions = results.map((v) => ({ label: v.text, value: v.value, description: v.value }));
setSubscriptions(fetchedSubscriptions);
setError(ERROR_SOURCE, undefined);

if (!query.subscriptions?.length && fetchedSubscriptions?.length) {
onChange({
...query,
subscriptions: [query.subscription ?? fetchedSubscriptions[0].value],
});
}
onChange({
...query,
subscriptions: selectSubscriptions(
fetchedSubscriptions.map((v) => v.value),
query.subscriptions,
query.subscription
),
});
})
.catch((err) => setError(ERROR_SOURCE, err));
}, [datasource, onChange, query, setError]);
// We are only interested in re-fetching subscriptions if the data source changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [datasource]);

return (
<span data-testid="azure-monitor-arg-query-editor-with-experimental-ui">
Expand Down