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

[8.4] [Security Solution][Detections] Update rules count indicator in the Rules table to show pagination info (#138902) #139288

Merged
merged 1 commit into from
Aug 23, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
RULES_TABLE,
RULE_SWITCH,
SEVERITY,
SHOWING_RULES_TEXT,
} from '../../screens/alerts_detection_rules';
import {
ABOUT_CONTINUE_BTN,
Expand Down Expand Up @@ -218,18 +217,21 @@ describe('Custom query rules', () => {
const initialNumberOfRules = rules.length;
const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1;

cy.get(SHOWING_RULES_TEXT).should('have.text', `Showing ${initialNumberOfRules} rules`);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(initialNumberOfRules);
});

deleteFirstRule();
waitForRulesTableToBeRefreshed();

cy.get(RULES_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
cy.get(SHOWING_RULES_TEXT).should(
'have.text',
`Showing ${expectedNumberOfRulesAfterDeletion} rules`
);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
Expand All @@ -253,10 +255,10 @@ describe('Custom query rules', () => {
cy.get(RULES_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
cy.get(SHOWING_RULES_TEXT).should(
'have.text',
`Showing ${expectedNumberOfRulesAfterDeletion} rule`
);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
Expand All @@ -281,10 +283,10 @@ describe('Custom query rules', () => {
cy.get(RULES_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
cy.get(SHOWING_RULES_TEXT).should(
'have.text',
`Showing ${expectedNumberOfRulesAfterDeletion} rules`
);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
* 2.0.
*/

import { rawRules } from '../../../server/lib/detection_engine/rules/prepackaged_rules';
import {
COLLAPSED_ACTION_BTN,
ELASTIC_RULES_BTN,
pageSelector,
RELOAD_PREBUILT_RULES_BTN,
RULES_EMPTY_PROMPT,
RULE_SWITCH,
SHOWING_RULES_TEXT,
RULES_MONITORING_TABLE,
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
RULE_NAME,
} from '../../screens/alerts_detection_rules';

import {
deleteFirstRule,
deleteSelectedRules,
Expand Down Expand Up @@ -59,7 +59,16 @@ describe('Prebuilt rules', () => {

changeRowsPerPageTo(rowsPerPage);

cy.get(SHOWING_RULES_TEXT).should('have.text', `Showing ${expectedNumberOfRules} rules`);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
// Assert the total number of loaded rules equals the expected number of in-memory rules
expect(body.total).to.equal(rawRules.length);
// Assert the table was refreshed with the rules returned by the API request
const ruleNames = rawRules.map((rule) => rule.name);
cy.get(RULE_NAME).each(($item) => {
expect($item.text()).to.be.oneOf(ruleNames);
});
});

cy.get(pageSelector(expectedNumberOfPages)).should('exist');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { useFormatUrl } from '../../../../../../common/components/link_to';
import { Loader } from '../../../../../../common/components/loader';

import * as i18n from './translations';
import { AllRulesUtilityBar } from '../utility_bar';
import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar';
import type { AllExceptionListsColumns } from './columns';
import { getAllExceptionListsColumns } from './columns';
import { useAllExceptionLists } from './use_all_exception_lists';
Expand Down Expand Up @@ -378,11 +378,8 @@ export const ExceptionListsTable = React.memo(() => {
<EuiLoadingContent data-test-subj="initialLoadingPanelAllRulesTable" lines={10} />
) : (
<>
<AllRulesUtilityBar
hasBulkActions={false}
canBulkEdit={hasPermissions}
paginationTotal={exceptionListsWithRuleRefs.length ?? 0}
numberSelectedItems={0}
<ExceptionsTableUtilityBar
totalExceptionLists={exceptionListsWithRuleRefs.length}
onRefresh={handleRefresh}
/>
<EuiBasicTable<ExceptionsTableItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { TestProviders } from '../../../../../../common/mock';
import { render, screen, within } from '@testing-library/react';
import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar';

describe('ExceptionsTableUtilityBar', () => {
it('displays correct exception lists label and refresh rules action button', () => {
const EXCEPTION_LISTS_NUMBER = 25;
render(
<TestProviders>
<ExceptionsTableUtilityBar
onRefresh={jest.fn()}
totalExceptionLists={EXCEPTION_LISTS_NUMBER}
/>
</TestProviders>
);

expect(screen.getByTestId('showingExceptionLists')).toBeInTheDocument();
expect(screen.getByTestId('refreshRulesAction')).toBeInTheDocument();
expect(screen.getByText(`Showing ${EXCEPTION_LISTS_NUMBER} lists`)).toBeInTheDocument();
});

it('invokes refresh on refresh action click', () => {
const mockRefresh = jest.fn();
render(
<TestProviders>
<ExceptionsTableUtilityBar onRefresh={mockRefresh} totalExceptionLists={1} />
</TestProviders>
);

const buttonWrapper = screen.getByTestId('refreshRulesAction');
within(buttonWrapper).getByRole('button').click();

expect(mockRefresh).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import {
UtilityBar,
UtilityBarAction,
UtilityBarGroup,
UtilityBarSection,
UtilityBarText,
} from '../../../../../../common/components/utility_bar';
import * as i18n from './translations';

interface ExceptionsTableUtilityBarProps {
onRefresh?: () => void;
totalExceptionLists: number;
}

export const ExceptionsTableUtilityBar: React.FC<ExceptionsTableUtilityBarProps> = ({
onRefresh,
totalExceptionLists,
}) => {
return (
<UtilityBar border>
<UtilityBarSection>
<UtilityBarGroup>
<UtilityBarText dataTestSubj="showingExceptionLists">
{i18n.SHOWING_EXCEPTION_LISTS(totalExceptionLists)}
</UtilityBarText>
</UtilityBarGroup>
<UtilityBarGroup>
<UtilityBarAction
dataTestSubj="refreshRulesAction"
iconSide="left"
iconType="refresh"
onClick={onRefresh}
>
{i18n.REFRESH_EXCEPTIONS_TABLE}
</UtilityBarAction>
</UtilityBarGroup>
</UtilityBarSection>
</UtilityBar>
);
};

ExceptionsTableUtilityBar.displayName = 'ExceptionsTableUtilityBar';
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ export const EXCEPTION_LIST_ACTIONS = i18n.translate(
}
);

export const SHOWING_EXCEPTION_LISTS = (totalLists: number) =>
i18n.translate(
'xpack.securitySolution.detectionEngine.rules.all.exceptions.showingExceptionLists',
{
values: { totalLists },
defaultMessage: 'Showing {totalLists} {totalLists, plural, =1 {list} other {lists}}',
}
);

export const RULES_ASSIGNED_TO_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.all.exceptions.rulesAssignedTitle',
{
Expand Down Expand Up @@ -151,3 +160,10 @@ export const EXCEPTION_LIST_SEARCH_PLACEHOLDER = i18n.translate(
defaultMessage: 'e.g. Example List Name',
}
);

export const REFRESH_EXCEPTIONS_TABLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.all.exceptions.refresh',
{
defaultMessage: 'Refresh',
}
);
Loading