From acca383993d4dba34c5635ab798f08b41d0aa603 Mon Sep 17 00:00:00 2001 From: Juan Pablo Djeredjian Date: Tue, 23 Aug 2022 13:35:53 +0200 Subject: [PATCH] [Security Solution][Detections] Update rules count indicator in the Rules table to show pagination info (#138902) **Fixes:** https://github.com/elastic/kibana/issues/121754 ## Summary Changes rules count pagination count to format: **"Showing 1-10 of 596 rules"** -> when page 1, rules per page is 10 and total rules is 596 **"Showing 6-6 of 6 rules"** -> when page 2, rules per page is 5 and total rules is 6 See other cases in tests. **Before changes** ![image](https://user-images.githubusercontent.com/5354282/184883106-118f0041-5567-4cf8-bfd5-8383e8146018.png) ![image](https://user-images.githubusercontent.com/5354282/184884145-22d30482-cc2d-4796-8f84-d809a8ca6d8a.png) **After changes** ![image](https://user-images.githubusercontent.com/5354282/184882149-d6c55dff-39a0-4a72-94a9-217b2e5ca7ac.png) ![image](https://user-images.githubusercontent.com/5354282/184886334-a107a2c5-31dc-4a7b-9e70-54c87c1630e0.png) ## Codebase changes - Refactors `AllRulesUtilityBar` component to separate usage of the utility bar between the all-rules table use-case and the Exceptions table use-case, by creating a new `ExceptionsTableUtilityBar` component. ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) (cherry picked from commit 147e4142c80b8b30d70f30d44230ec09ad0018f2) --- .../detection_rules/custom_query_rule.spec.ts | 30 ++-- .../detection_rules/prebuilt_rules.spec.ts | 15 +- .../rules/all/exceptions/exceptions_table.tsx | 9 +- .../exceptions_table_utility_bar.test.tsx | 43 +++++ .../exceptions_table_utility_bar.tsx | 51 ++++++ .../rules/all/exceptions/translations.ts | 16 ++ ...t.tsx => rules_table_utility_bar.test.tsx} | 159 ++++++++++++++---- ...ty_bar.tsx => rules_table_utility_bar.tsx} | 134 +++++++-------- .../rules/all/rules_tables.tsx | 11 +- .../detection_engine/rules/translations.ts | 13 +- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 13 files changed, 334 insertions(+), 153 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx rename x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/{utility_bar.test.tsx => rules_table_utility_bar.test.tsx} (52%) rename x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/{utility_bar.tsx => rules_table_utility_bar.tsx} (58%) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts index ba886993c7433..5725e511f2dec 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts @@ -23,7 +23,6 @@ import { RULES_TABLE, RULE_SWITCH, SEVERITY, - SHOWING_RULES_TEXT, } from '../../screens/alerts_detection_rules'; import { ABOUT_CONTINUE_BTN, @@ -218,7 +217,10 @@ 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(); @@ -226,10 +228,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})` @@ -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})` @@ -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})` diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts index 397162f69d490..ed5f5629985ae 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { rawRules } from '../../../server/lib/detection_engine/rules/prepackaged_rules'; import { COLLAPSED_ACTION_BTN, ELASTIC_RULES_BTN, @@ -12,11 +13,10 @@ import { 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, @@ -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'); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx index 415bbfd1498c7..d7908d0bbce66 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx @@ -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'; @@ -378,11 +378,8 @@ export const ExceptionListsTable = React.memo(() => { ) : ( <> - diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx new file mode 100644 index 0000000000000..d2bf2b8547f68 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx @@ -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( + + + + ); + + 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( + + + + ); + + const buttonWrapper = screen.getByTestId('refreshRulesAction'); + within(buttonWrapper).getByRole('button').click(); + + expect(mockRefresh).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx new file mode 100644 index 0000000000000..062b4b0fef8f9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx @@ -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 = ({ + onRefresh, + totalExceptionLists, +}) => { + return ( + + + + + {i18n.SHOWING_EXCEPTION_LISTS(totalExceptionLists)} + + + + + {i18n.REFRESH_EXCEPTIONS_TABLE} + + + + + ); +}; + +ExceptionsTableUtilityBar.displayName = 'ExceptionsTableUtilityBar'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts index 004b6c5d97bec..b22d4030384a3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts @@ -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', { @@ -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', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx similarity index 52% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx rename to x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx index 91f4a0b06e71d..4fecfc4afa6a2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx @@ -9,67 +9,80 @@ import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; -import { AllRulesUtilityBar } from './utility_bar'; +import { getShowingRulesParams, RulesTableUtilityBar } from './rules_table_utility_bar'; import { TestProviders } from '../../../../../common/mock'; -describe('AllRules', () => { - it('renders AllRulesUtilityBar total rules and selected rules', () => { +jest.mock('./rules_table/rules_table_context'); + +describe('RulesTableUtilityBar', () => { + it('renders RulesTableUtilityBar total rules and selected rules', () => { const wrapper = mount( - ); - expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual('Showing 4 rules'); + expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual( + 'Showing 1-10 of 21 rules' + ); expect(wrapper.find('[data-test-subj="selectedRules"]').at(0).text()).toEqual( 'Selected 1 rule' ); }); - it('does not render total selected and bulk actions when "hasBulkActions" is false', () => { + it('renders correct pagination label according to pagination data', () => { const wrapper = mount( - ); - - expect(wrapper.find('[data-test-subj="showingRules"]').exists()).toBeFalsy(); - expect(wrapper.find('[data-test-subj="tableBulkActions"]').exists()).toBeFalsy(); - expect(wrapper.find('[data-test-subj="showingExceptionLists"]').at(0).text()).toEqual( - 'Showing 4 lists' + expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual( + 'Showing 1-10 of 21 rules' ); }); it('renders utility actions if user has permissions', () => { const wrapper = mount( - ); @@ -80,15 +93,19 @@ describe('AllRules', () => { it('renders no utility actions if user has no permissions', () => { const wrapper = mount( - ); @@ -100,15 +117,19 @@ describe('AllRules', () => { const mockRefresh = jest.fn(); const wrapper = mount( - ); @@ -122,15 +143,19 @@ describe('AllRules', () => { const mockSwitch = jest.fn(); const wrapper = mount( - ); @@ -146,15 +171,19 @@ describe('AllRules', () => { const mockSwitch = jest.fn(); const wrapper = mount( - ); @@ -165,4 +194,72 @@ describe('AllRules', () => { expect(mockSwitch).not.toHaveBeenCalled(); }); }); + + describe('getShowingRulesParams creates correct label when', () => { + it('there are 0 rules to display', () => { + const pagination = { + page: 1, + perPage: 10, + total: 0, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(0); + expect(lastInPage).toEqual(0); + }); + + it('there is 1 rule to display', () => { + const pagination = { + page: 1, + perPage: 10, + total: 1, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(1); + }); + + it('the table displays the first page, and rules per page is less than total rules', () => { + const pagination = { + page: 1, + perPage: 10, + total: 21, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(10); + }); + + it('the table displays the first page, and rules per page is greater than total rules', () => { + const pagination = { + page: 1, + perPage: 10, + total: 8, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(8); + }); + + it('the table displays the second page, and rules per page is less than total rules', () => { + const pagination = { + page: 2, + perPage: 10, + total: 31, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(11); + expect(lastInPage).toEqual(20); + }); + + it('the table displays the last page, displaying the remaining rules', () => { + const pagination = { + page: 2, + perPage: 100, + total: 101, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(101); + expect(lastInPage).toEqual(101); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx similarity index 58% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx rename to x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx index 4809a44528e2a..7f9b0dba04881 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx @@ -25,25 +25,31 @@ import { } from '../../../../../common/components/utility_bar'; import * as i18n from '../translations'; import { useKibana } from '../../../../../common/lib/kibana'; -import { useRulesTableContextOptional } from './rules_table/rules_table_context'; +import { useRulesTableContext } from './rules_table/rules_table_context'; +import type { PaginationOptions } from '../../../../containers/detection_engine/rules/types'; -interface AllRulesUtilityBarProps { +export const getShowingRulesParams = ({ page, perPage, total: totalRules }: PaginationOptions) => { + const firstInPage = totalRules === 0 ? 0 : (page - 1) * perPage + 1; + const lastInPage = page * perPage > totalRules ? totalRules : page * perPage; + + return [firstInPage, lastInPage, totalRules] as const; +}; + +interface RulesTableUtilityBarProps { canBulkEdit: boolean; isAllSelected?: boolean; isAutoRefreshOn?: boolean; numberSelectedItems: number; onGetBulkItemsPopoverContent?: (closePopover: () => void) => EuiContextMenuPanelDescriptor[]; - onRefresh?: () => void; - onRefreshSwitch?: (checked: boolean) => void; - onToggleSelectAll?: () => void; - paginationTotal: number; - hasBulkActions: boolean; - hasPagination?: boolean; + onRefresh: () => void; + onRefreshSwitch: (checked: boolean) => void; + onToggleSelectAll: () => void; + pagination: PaginationOptions; isBulkActionInProgress?: boolean; hasDisabledActions?: boolean; } -export const AllRulesUtilityBar = React.memo( +export const RulesTableUtilityBar = React.memo( ({ canBulkEdit, isAllSelected, @@ -53,14 +59,12 @@ export const AllRulesUtilityBar = React.memo( onRefresh, onRefreshSwitch, onToggleSelectAll, - paginationTotal, - hasBulkActions = true, - hasPagination, + pagination, isBulkActionInProgress, hasDisabledActions, }) => { const { timelines } = useKibana().services; - const rulesTableContext = useRulesTableContextOptional(); + const rulesTableContext = useRulesTableContext(); const isAnyRuleSelected = numberSelectedItems > 0; const handleGetBulkItemsPopoverContent = useCallback( @@ -125,73 +129,44 @@ export const AllRulesUtilityBar = React.memo( - {hasBulkActions ? ( - - {i18n.SHOWING_RULES(paginationTotal)} - - ) : ( - - {i18n.SHOWING_EXCEPTION_LISTS(paginationTotal)} - - )} + + {i18n.SHOWING_RULES(...getShowingRulesParams(pagination))} + + <> + + + {i18n.SELECTED_RULES(numberSelectedItems)} + - {hasBulkActions ? ( - <> - - - {i18n.SELECTED_RULES(numberSelectedItems)} - - - {canBulkEdit && onToggleSelectAll && hasPagination && ( - - {isAllSelected ? i18n.CLEAR_SELECTION : i18n.SELECT_ALL_RULES(paginationTotal)} - - )} - - {canBulkEdit && ( - - {i18n.BATCH_ACTIONS} - - )} - + {canBulkEdit && ( - {i18n.REFRESH} + {isAllSelected ? i18n.CLEAR_SELECTION : i18n.SELECT_ALL_RULES(pagination.total)} + )} + + {canBulkEdit && ( - {i18n.REFRESH_RULE_POPOVER_LABEL} + {i18n.BATCH_ACTIONS} - - - ) : ( - + )} + ( > {i18n.REFRESH} + + {i18n.REFRESH_RULE_POPOVER_LABEL} + - )} + + + + {timelines.getLastUpdated({ + showUpdating: rulesTableContext.state.isFetching, + updatedAt: rulesTableContext.state.lastUpdated, + })} - {rulesTableContext && ( - - {timelines.getLastUpdated({ - showUpdating: rulesTableContext.state.isFetching, - updatedAt: rulesTableContext.state.lastUpdated, - })} - - )} ); } ); -AllRulesUtilityBar.displayName = 'AllRulesUtilityBar'; +RulesTableUtilityBar.displayName = 'RulesTableUtilityBar'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index 328b9a51b30a3..d04832d2e738c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -5,8 +5,6 @@ * 2.0. */ -/* eslint-disable complexity */ - import { EuiBasicTable, EuiConfirmModal, @@ -33,7 +31,7 @@ import { showRulesTable } from './helpers'; import { useRulesTableContext } from './rules_table/rules_table_context'; import { useAsyncConfirmation } from './rules_table/use_async_confirmation'; import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; -import { AllRulesUtilityBar } from './utility_bar'; +import { RulesTableUtilityBar } from './rules_table_utility_bar'; import { useBulkActionsDryRun } from './bulk_actions/use_bulk_actions_dry_run'; import { useBulkActionsConfirmation } from './bulk_actions/use_bulk_actions_confirmation'; import { useBulkEditFormFlyout } from './bulk_actions/use_bulk_edit_form_flyout'; @@ -147,7 +145,6 @@ export const RulesTables = React.memo( } = useBulkEditFormFlyout(); const selectedItemsCount = isAllSelected ? pagination.total : selectedRuleIds.length; - const hasPagination = pagination.total > pagination.perPage; const { isBulkActionsDryRunLoading, executeBulkActionsDryRun } = useBulkActionsDryRun(); @@ -334,10 +331,9 @@ export const RulesTables = React.memo( )} {shouldShowRulesTable && ( <> - ( onToggleSelectAll={toggleSelectAll} isBulkActionInProgress={isBulkActionsDryRunLoading || loadingRulesAction != null} hasDisabledActions={loadingRulesAction != null} - hasBulkActions /> +export const SHOWING_RULES = (firstInPage: number, lastOfPage: number, totalRules: number) => i18n.translate('xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle', { - values: { totalRules }, - defaultMessage: 'Showing {totalRules} {totalRules, plural, =1 {rule} other {rules}}', + values: { firstInPage, lastOfPage, totalRules }, + defaultMessage: + 'Showing {firstInPage}-{lastOfPage} of {totalRules} {totalRules, plural, =1 {rule} other {rules}}', }); export const SELECT_ALL_RULES = (totalRules: number) => @@ -839,12 +840,6 @@ export const REFRESH_RULE_POPOVER_LABEL = i18n.translate( } ); -export const SHOWING_EXCEPTION_LISTS = (totalLists: number) => - i18n.translate('xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists', { - values: { totalLists }, - defaultMessage: 'Showing {totalLists} {totalLists, plural, =1 {list} other {lists}}', - }); - /** * Bulk Export */ diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 32c569f3e1a44..7569530cd05f2 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -25489,8 +25489,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "Durée de l'écart le plus récent dans l'exécution de la règle. Ajustez l'historique des règles ou {seeDocs} pour réduire les écarts.", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "Sélection totale de {totalRules} {totalRules, plural, =1 {règle} other {règles}} effectuée", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "Sélection de {selectedRules} {selectedRules, plural, =1 {règle} other {règles}} effectuée", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "Affichage de {totalLists} {totalLists, plural, =1 {liste} other {listes}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "Affichage de {totalRules} {totalRules, plural, =1 {règle} other {règles}}", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName} a été créé", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "Infobulle pour la colonne : {columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "Installez {missingRules} {missingRules, plural, =1 {règle prédéfinie} other {règles prédéfinies}} d'Elastic et {missingTimelines} {missingTimelines, plural, =1 {chronologie prédéfinie} other {chronologies prédéfinies}} d'Elastic ", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8d1e9d4d7e9aa..eb13233182a1c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -25467,8 +25467,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "ルール実行の最新のギャップの期間。ルールルックバックを調整するか、ギャップの軽減については{seeDocs}してください。", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "すべての{totalRules} {totalRules, plural, other {個のルール}}を選択", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "{selectedRules} {selectedRules, plural, other {ルール}}を選択しました", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "{totalLists} {totalLists, plural, other {件のリスト}}を表示しています。", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "{totalRules} {totalRules, plural, other {ルール}}を表示中", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName}が作成されました", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "列のツールチップ:{columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "{missingRules} Elastic事前構築済み{missingRules, plural, other {ルール}}と{missingTimelines} Elastic事前構築済み{missingTimelines, plural, other {タイムライン}}をインストール ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index bff67ba6129e6..08ac9da04c44f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25497,8 +25497,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "规则执行中最近缺口的持续时间。调整规则回查或{seeDocs}以缩小缺口。", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "选择所有 {totalRules} 个{totalRules, plural, other {规则}}", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "已选择 {selectedRules} 个{selectedRules, plural, other {规则}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "正在显示 {totalLists} 个{totalLists, plural, other {列表}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "正在显示 {totalRules} 个{totalRules, plural, other {规则}}", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName} 已创建", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "列的工具提示:{columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "安装 {missingRules} 个 Elastic 预构建{missingRules, plural, other {规则}}以及 {missingTimelines} 个 Elastic 预构建{missingTimelines, plural, other {时间线}} ",