diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx index 9b6220147b1..32c4b44c92e 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.test.tsx @@ -118,4 +118,37 @@ describe('LogsQueryEdiutor', () => { expect(await screen.findByLabelText('web-server_DataDisk')).toBeDisabled(); }); + + it('should show info about multiple selection', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.subscription; + delete query?.azureLogAnalytics?.resources; + const onChange = jest.fn(); + + render( + {}} + /> + ); + + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + resourcePickerButton.click(); + + const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); + subscriptionButton.click(); + + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); + resourceGroupButton.click(); + + const checkbox = await screen.findByLabelText('web-server'); + await userEvent.click(checkbox); + expect(checkbox).toBeChecked(); + + expect(await screen.findByText('You may only choose items of the same resource type.')).toBeInTheDocument(); + }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx index b1c7d95d64c..f29bb2c41e8 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/LogsQueryEditor.tsx @@ -82,6 +82,11 @@ const LogsQueryEditor: React.FC = ({ // eslint-disable-next-line )} + selectionNotice={() => + config.featureToggles.azureMultipleResourcePicker + ? 'You may only choose items of the same resource type.' + : '' + } /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx index c1e326dc2b8..01cb3db99cf 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx @@ -270,6 +270,45 @@ describe('MetricsQueryEditor', () => { expect(await screen.findByLabelText('web-server_DataDisk')).toBeDisabled(); }); + it('should show info about multiple selection', async () => { + const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); + const query = createMockQuery(); + delete query?.subscription; + delete query?.azureMonitor?.resources; + delete query?.azureMonitor?.metricNamespace; + const onChange = jest.fn(); + + render( + {}} + /> + ); + + const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); + resourcePickerButton.click(); + + const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); + subscriptionButton.click(); + + const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); + resourceGroupButton.click(); + + const checkbox = await screen.findByLabelText('web-server'); + await userEvent.click(checkbox); + expect(checkbox).toBeChecked(); + + expect( + await screen.findByText( + 'You can select items of the same resource type and location. To select resources of a different resource type or location, please first uncheck your current selection.' + ) + ).toBeInTheDocument(); + }); + it('should change the metric name when selected', async () => { const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() }); const onChange = jest.fn(); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx index ec2e079fbb5..4358ab8422d 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/MetricsQueryEditor.tsx @@ -49,6 +49,11 @@ const MetricsQueryEditor: React.FC = ({ resourceName: r.resourceName, region: query.azureMonitor?.region, })) ?? []; + + const supportMultipleResource = (namespace?: string) => { + return multiResourceCompatibleTypes[namespace?.toLocaleLowerCase() ?? ''] ?? false; + }; + const disableRow = (row: ResourceRow, selectedRows: ResourceRowGroup) => { if (selectedRows.length === 0) { // Only if there is some resource(s) selected we should disable rows @@ -70,10 +75,20 @@ const MetricsQueryEditor: React.FC = ({ rowResource.subscription !== selectedRowSample.subscription || rowResource.region !== selectedRowSample.region || rowResource.metricNamespace?.toLocaleLowerCase() !== selectedRowSample.metricNamespace?.toLocaleLowerCase() || - !multiResourceCompatibleTypes[rowResource.metricNamespace?.toLocaleLowerCase() ?? ''] + !supportMultipleResource(rowResource.metricNamespace) ); }; + const selectionNotice = (selectedRows: ResourceRowGroup) => { + if (selectedRows.length === 0 || !config.featureToggles.azureMultipleResourcePicker) { + return ''; + } + const selectedRowSample = parseResourceDetails(selectedRows[0].uri, selectedRows[0].location); + return supportMultipleResource(selectedRowSample.metricNamespace) + ? 'You can select items of the same resource type and location. To select resources of a different resource type or location, please first uncheck your current selection.' + : ''; + }; + return ( @@ -95,6 +110,7 @@ const MetricsQueryEditor: React.FC = ({ // eslint-disable-next-line )} + selectionNotice={selectionNotice} /> extends AzureQueryEditorFieldProps { labelWidth?: number; disableRow: (row: ResourceRow, selectedRows: ResourceRowGroup) => boolean; renderAdvanced: (resources: T[], onChange: (resources: T[]) => void) => React.ReactNode; + selectionNotice?: (selectedRows: ResourceRowGroup) => string; } const ResourceField: React.FC> = ({ @@ -34,6 +35,7 @@ const ResourceField: React.FC> labelWidth, disableRow, renderAdvanced, + selectionNotice, }) => { const styles = useStyles2(getStyles); const [pickerIsOpen, setPickerIsOpen] = useState(false); @@ -74,6 +76,7 @@ const ResourceField: React.FC> queryType={queryType} disableRow={disableRow} renderAdvanced={renderAdvanced} + selectionNotice={selectionNotice} /> diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx index c99550162c3..93d04ba6ff6 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/ResourcePicker.tsx @@ -29,6 +29,7 @@ interface ResourcePickerProps { onCancel: () => void; disableRow: (row: ResourceRow, selectedRows: ResourceRowGroup) => boolean; renderAdvanced: (resources: T[], onChange: (resources: T[]) => void) => React.ReactNode; + selectionNotice?: (selectedRows: ResourceRowGroup) => string; } const ResourcePicker = ({ @@ -40,6 +41,7 @@ const ResourcePicker = ({ queryType, disableRow, renderAdvanced, + selectionNotice, }: ResourcePickerProps) => { const styles = useStyles2(getStyles); @@ -49,6 +51,7 @@ const ResourcePicker = ({ const [internalSelected, setInternalSelected] = useState(resources); const [errorMessage, setErrorMessage] = useState(undefined); const [shouldShowLimitFlag, setShouldShowLimitFlag] = useState(false); + const selectionNoticeText = selectionNotice?.(selectedRows); // Sync the resourceURI prop to internal state useEffect(() => { @@ -241,6 +244,11 @@ const ResourcePicker = ({ + {selectionNoticeText?.length ? ( + + {selectionNoticeText} + + ) : null} )}