@@ -149,6 +162,10 @@ export const CrossAccountLogsQueryField = (props: CrossAccountLogsQueryProps) =>
+
+
-
- {props.selectedLogGroups.map((lg) => (
-
- {lg.label}
- props.onChange(props.selectedLogGroups.filter((slg) => slg.value !== lg.value))}
- />
-
- ))}
-
+
>
);
};
diff --git a/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.test.tsx b/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.test.tsx
new file mode 100644
index 00000000000..b514d386903
--- /dev/null
+++ b/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.test.tsx
@@ -0,0 +1,93 @@
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+
+import { SelectedLogsGroups } from './SelectedLogsGroups';
+
+const defaultProps = {
+ selectedLogGroups: [
+ {
+ value: 'aws/lambda/lambda-name1',
+ label: 'aws/lambda/lambda-name1',
+ text: 'aws/lambda/lambda-name1',
+ },
+ {
+ value: 'aws/lambda/lambda-name2',
+ label: 'aws/lambda/lambda-name2',
+ text: 'aws/lambda/lambda-name2',
+ },
+ ],
+ onChange: jest.fn(),
+};
+
+describe('SelectedLogsGroups', () => {
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
+ describe("'Show more' button", () => {
+ it('should not be displayed in case 0 logs have been selected', async () => {
+ render();
+ await waitFor(() => expect(screen.queryByText('Show all')).not.toBeInTheDocument());
+ });
+ it('should not be displayed in case logs group have been selected but theyre less than 10', async () => {
+ render();
+ await waitFor(() => expect(screen.queryByText('Show all')).not.toBeInTheDocument());
+ });
+ it('should be displayed in case more than 10 log groups have been selected', async () => {
+ const selectedLogGroups = Array(12).map((i) => ({
+ value: `logGroup${i}`,
+ text: `logGroup${i}`,
+ label: `logGroup${i}`,
+ }));
+ render();
+ await waitFor(() => expect(screen.getByText('Show all')).toBeInTheDocument());
+ });
+ });
+
+ describe("'Clear selection' button", () => {
+ it('should not be displayed in case 0 logs have been selected', async () => {
+ render();
+ await waitFor(() => expect(screen.queryByText('Clear selection')).not.toBeInTheDocument());
+ });
+ it('should be displayed in case at least one log group have been selected', async () => {
+ const selectedLogGroups = Array(11).map((i) => ({
+ value: `logGroup${i}`,
+ text: `logGroup${i}`,
+ label: `logGroup${i}`,
+ }));
+ render();
+ await waitFor(() => expect(screen.getByText('Clear selection')).toBeInTheDocument());
+ });
+
+ it('should display confirm dialog before clearing all selections', async () => {
+ const selectedLogGroups = Array(11).map((i) => ({
+ value: `logGroup${i}`,
+ text: `logGroup${i}`,
+ label: `logGroup${i}`,
+ }));
+ render();
+ await waitFor(() => userEvent.click(screen.getByText('Clear selection')));
+ await waitFor(() =>
+ expect(screen.getByText('Are you sure you want to clear all log groups?')).toBeInTheDocument()
+ );
+ await waitFor(() => userEvent.click(screen.getByLabelText('Confirm Modal Danger Button')));
+ expect(defaultProps.onChange).toHaveBeenCalledWith([]);
+ });
+ });
+
+ describe("'Clear selection' button", () => {
+ it('should not be displayed in case 0 logs have been selected', async () => {
+ render();
+ await waitFor(() => expect(screen.queryByText('Clear selection')).not.toBeInTheDocument());
+ });
+ it('should be displayed in case at least one log group have been selected', async () => {
+ const selectedLogGroups = Array(11).map((i) => ({
+ value: `logGroup${i}`,
+ text: `logGroup${i}`,
+ label: `logGroup${i}`,
+ }));
+ render();
+ await waitFor(() => expect(screen.getByText('Clear selection')).toBeInTheDocument());
+ });
+ });
+});
diff --git a/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.tsx b/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.tsx
new file mode 100644
index 00000000000..0733da6aabd
--- /dev/null
+++ b/public/app/plugins/datasource/cloudwatch/components/SelectedLogsGroups.tsx
@@ -0,0 +1,84 @@
+import React, { useEffect, useState } from 'react';
+
+import { Button, ConfirmModal, useStyles2 } from '@grafana/ui';
+
+import { SelectableResourceValue } from '../api';
+
+import getStyles from './styles';
+
+type CrossAccountLogsQueryProps = {
+ selectedLogGroups: SelectableResourceValue[];
+ onChange: (selectedLogGroups: SelectableResourceValue[]) => void;
+};
+
+const MAX_VISIBLE_LOG_GROUPS = 6;
+
+export const SelectedLogsGroups = ({ selectedLogGroups, onChange }: CrossAccountLogsQueryProps) => {
+ const styles = useStyles2(getStyles);
+ const [showConfirm, setShowConfirm] = useState(false);
+ const [visibleSelectecLogGroups, setVisibleSelectecLogGroups] = useState(
+ selectedLogGroups.slice(0, MAX_VISIBLE_LOG_GROUPS)
+ );
+
+ useEffect(() => {
+ setVisibleSelectecLogGroups(selectedLogGroups.slice(0, MAX_VISIBLE_LOG_GROUPS));
+ }, [selectedLogGroups]);
+
+ return (
+ <>
+
+ {visibleSelectecLogGroups.map((lg) => (
+
+ ))}
+ {visibleSelectecLogGroups.length !== selectedLogGroups.length && (
+
+ )}
+ {selectedLogGroups.length > 0 && (
+
+ )}
+
+ {
+ setShowConfirm(false);
+ onChange([]);
+ }}
+ onDismiss={() => setShowConfirm(false)}
+ />
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/cloudwatch/components/styles.ts b/public/app/plugins/datasource/cloudwatch/components/styles.ts
index 5371a277ece..1903d570845 100644
--- a/public/app/plugins/datasource/cloudwatch/components/styles.ts
+++ b/public/app/plugins/datasource/cloudwatch/components/styles.ts
@@ -10,8 +10,27 @@ const getStyles = (theme: GrafanaTheme2) => ({
selectedLogGroupsContainer: css({
marginLeft: theme.spacing(0.5),
+ marginBottom: theme.spacing(0.5),
display: 'flex',
flexFlow: 'wrap',
+ gap: theme.spacing(1),
+ button: {
+ margin: 'unset',
+ },
+ }),
+
+ limitLabel: css({
+ color: theme.colors.text.secondary,
+ textAlign: 'center',
+ maxWidth: 'none',
+ svg: {
+ marginRight: theme.spacing(0.5),
+ },
+ }),
+
+ logGroupCountLabel: css({
+ color: theme.colors.text.secondary,
+ maxWidth: 'none',
}),
tableScroller: css({
@@ -61,24 +80,16 @@ const getStyles = (theme: GrafanaTheme2) => ({
display: 'flex',
}),
+ searchField: css({
+ width: '100%',
+ marginRight: theme.spacing(1),
+ }),
+
resultLimit: css({
margin: '4px 0',
fontStyle: 'italic',
}),
- selectedLogGroup: css({
- background: theme.colors.background.secondary,
- borderRadius: theme.shape.borderRadius(),
- margin: theme.spacing(0, 1, 1, 0),
- padding: theme.spacing(0.5, 0, 0.5, 1),
- color: theme.colors.text.primary,
- fontSize: theme.typography.size.sm,
- }),
-
- search: css({
- marginRight: '10px',
- }),
-
removeButton: css({
verticalAlign: 'middle',
marginLeft: theme.spacing(0.5),