CloudWatch: add account dropdown to metric insights (#89926)

This commit is contained in:
Sarah Zinger
2024-07-03 12:09:40 -04:00
committed by GitHub
parent acf5c7c6ba
commit db68d58d52
3 changed files with 70 additions and 4 deletions
@@ -2,13 +2,15 @@ import { useEffect, useMemo } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorSwitch } from '@grafana/experimental';
import { config } from '@grafana/runtime';
import { Select } from '@grafana/ui';
import { CloudWatchDatasource } from '../../../../datasource';
import { useDimensionKeys, useMetrics, useNamespaces } from '../../../../hooks';
import { useAccountOptions, useDimensionKeys, useMetrics, useNamespaces } from '../../../../hooks';
import { STATISTICS } from '../../../../language/cloudwatch-sql/language';
import { CloudWatchMetricsQuery } from '../../../../types';
import { appendTemplateVariables } from '../../../../utils/utils';
import { Account } from '../../../shared/Account';
import {
getMetricNameFromExpression,
@@ -48,13 +50,24 @@ const SQLBuilderSelectRow = ({ datasource, query, onQueryChange }: SQLBuilderSel
const withSchemaEnabled = isUsingWithSchema(sql.from);
const namespaceOptions = useNamespaces(datasource);
const metricOptions = useMetrics(datasource, { region: query.region, namespace });
const metricOptions = useMetrics(datasource, {
region: query.region,
namespace,
...(config.featureToggles.cloudWatchCrossAccountQuerying &&
config.featureToggles.cloudwatchMetricInsightsCrossAccount
? { accountId: query.accountId }
: {}),
});
const existingFilters = useMemo(() => stringArrayToDimensions(schemaLabels ?? []), [schemaLabels]);
const unusedDimensionKeys = useDimensionKeys(datasource, {
region: query.region,
namespace,
metricName,
dimensionFilters: existingFilters,
...(config.featureToggles.cloudWatchCrossAccountQuerying &&
config.featureToggles.cloudwatchMetricInsightsCrossAccount
? { accountId: query.accountId }
: {}),
});
const dimensionKeys = useMemo(
() => (schemaLabels?.length ? [...unusedDimensionKeys, ...schemaLabels.map(toOption)] : unusedDimensionKeys),
@@ -76,9 +89,23 @@ const SQLBuilderSelectRow = ({ datasource, query, onQueryChange }: SQLBuilderSel
return { ...query, sql };
};
const accountState = useAccountOptions(datasource.resources, query.region);
return (
<>
<EditorFieldGroup>
{config.featureToggles.cloudWatchCrossAccountQuerying &&
config.featureToggles.cloudwatchMetricInsightsCrossAccount && (
<Account
accountId={query.accountId}
accountOptions={accountState.value || []}
onChange={(accountId) => {
onQueryChange({
...query,
accountId,
});
}}
/>
)}
<EditorField label="Namespace" width={16}>
<Select
aria-label="Namespace"
@@ -4,6 +4,7 @@ import { useAsyncFn } from 'react-use';
import { SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton, EditorList, InputGroup } from '@grafana/experimental';
import { config } from '@grafana/runtime';
import { Alert, Select, useStyles2 } from '@grafana/ui';
import { CloudWatchDatasource } from '../../../../datasource';
@@ -108,7 +109,15 @@ const FilterItem = (props: FilterItemProps) => {
const namespace = getNamespaceFromExpression(sql.from);
const metricName = getMetricNameFromExpression(sql.select);
const dimensionKeys = useDimensionKeys(datasource, { region: query.region, namespace, metricName });
const dimensionKeys = useDimensionKeys(datasource, {
region: query.region,
namespace,
metricName,
...(config.featureToggles.cloudWatchCrossAccountQuerying &&
config.featureToggles.cloudwatchMetricInsightsCrossAccount
? { accountId: query.accountId }
: {}),
});
const loadDimensionValues = async () => {
if (!filter.property?.name || !namespace) {
@@ -116,7 +125,16 @@ const FilterItem = (props: FilterItemProps) => {
}
return datasource.resources
.getDimensionValues({ region: query.region, namespace, metricName, dimensionKey: filter.property.name })
.getDimensionValues({
region: query.region,
namespace,
metricName,
dimensionKey: filter.property.name,
...(config.featureToggles.cloudWatchCrossAccountQuerying &&
config.featureToggles.cloudwatchMetricInsightsCrossAccount
? { accountId: query.accountId }
: {}),
})
.then((result: Array<SelectableValue<string>>) => {
return appendTemplateVariables(datasource, result);
});
@@ -330,4 +330,25 @@ describe('QueryEditor should render right editor', () => {
expect(screen.queryByText('Are you sure?')).toBeNull();
});
});
describe('metric insights in builder mode', () => {
let originalValueCloudWatchCrossAccountQuerying: boolean | undefined;
let originalValueCloudwatchMetricInsightsCrossAccount: boolean | undefined;
beforeEach(() => {
originalValueCloudWatchCrossAccountQuerying = config.featureToggles.cloudWatchCrossAccountQuerying;
originalValueCloudwatchMetricInsightsCrossAccount = config.featureToggles.cloudwatchMetricInsightsCrossAccount;
});
afterEach(() => {
config.featureToggles.cloudWatchCrossAccountQuerying = originalValueCloudWatchCrossAccountQuerying;
config.featureToggles.cloudwatchMetricInsightsCrossAccount = originalValueCloudwatchMetricInsightsCrossAccount;
});
it('should have an account selector when the feature is enabled', async () => {
config.featureToggles.cloudWatchCrossAccountQuerying = true;
config.featureToggles.cloudwatchMetricInsightsCrossAccount = true;
props.datasource.resources.getAccounts = jest.fn().mockResolvedValue(['account123']);
render(<QueryEditor {...props} query={validMetricQueryBuilderQuery} />);
await screen.findByText('Metric Query');
expect(await screen.findByText('Account')).toBeInTheDocument();
});
});
});