From e2d424f3f724252326941ce7fb887599c8d32923 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Wed, 25 Jan 2023 13:50:49 +0100 Subject: [PATCH 1/9] migrate tags filter to EuiSelectable --- .../tags_filter_popover.tsx | 138 +++++++----------- 1 file changed, 51 insertions(+), 87 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index b74cf38cc9266..3991d414396e7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -5,20 +5,9 @@ * 2.0. */ -import type { ChangeEvent } from 'react'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { - EuiFilterButton, - EuiFilterSelectItem, - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiPopover, - EuiText, - EuiFieldSearch, - EuiPopoverTitle, -} from '@elastic/eui'; -import styled from 'styled-components'; +import React, { useMemo, useState } from 'react'; +import type { EuiSelectableOption } from '@elastic/eui'; +import { EuiFilterButton, EuiPopover, EuiPopoverTitle, EuiSelectable } from '@elastic/eui'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { toggleSelectedGroup } from '../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group'; import { caseInsensitiveSort } from '../helpers'; @@ -29,21 +18,6 @@ interface TagsFilterPopoverProps { onSelectedTagsChanged: (newTags: string[]) => void; } -const PopoverContentWrapper = styled.div` - width: 275px; -`; - -const ScrollableDiv = styled.div` - max-height: 250px; - overflow-y: auto; -`; - -const TagOverflowContainer = styled.span` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - /** * Popover for selecting tags to filter on * @@ -60,75 +34,65 @@ const TagsFilterPopoverComponent = ({ [selectedTags, tags] ); const [isTagPopoverOpen, setIsTagPopoverOpen] = useState(false); - const [searchInput, setSearchInput] = useState(''); - const [filterTags, setFilterTags] = useState(sortedTags); - - const tagsComponent = useMemo(() => { - return filterTags.map((tag, index) => ( - toggleSelectedGroup(tag, selectedTags, onSelectedTagsChanged)} - title={tag} - > - {tag} - - )); - }, [onSelectedTagsChanged, selectedTags, filterTags]); + const [selectableOptions, setSelectableOptions] = useState(() => { + const selectedTagsSet = new Set(selectedTags); - const onSearchInputChange = useCallback((event: ChangeEvent) => { - setSearchInput(event.target.value); - }, []); - - useEffect(() => { - setFilterTags( - sortedTags.filter((tag) => tag.toLowerCase().includes(searchInput.toLowerCase())) - ); - }, [sortedTags, searchInput]); + return sortedTags.map((label) => ({ + label, + checked: selectedTagsSet.has(label) ? 'on' : undefined, + })); + }); + const handleSelectableOptionsChange = ( + newOptions: EuiSelectableOption[], + _: unknown, + changedOption: EuiSelectableOption + ) => { + setSelectableOptions(newOptions); + toggleSelectedGroup(changedOption.label, selectedTags, onSelectedTagsChanged); + }; + const triggerButton = ( + setIsTagPopoverOpen(!isTagPopoverOpen)} + numFilters={tags.length} + isSelected={isTagPopoverOpen} + hasActiveFilters={selectedTags.length > 0} + numActiveFilters={selectedTags.length} + data-test-subj="tags-filter-popover-button" + > + {i18n.TAGS} + + ); return ( setIsTagPopoverOpen(!isTagPopoverOpen)} - numFilters={tags.length} - isSelected={isTagPopoverOpen} - hasActiveFilters={selectedTags.length > 0} - numActiveFilters={selectedTags.length} - > - {i18n.TAGS} - - } + button={triggerButton} isOpen={isTagPopoverOpen} closePopover={() => setIsTagPopoverOpen(!isTagPopoverOpen)} panelPaddingSize="none" repositionOnScroll > - - - - - {tagsComponent} - {filterTags.length === 0 && ( - - - - {i18n.NO_TAGS_AVAILABLE} - - - + + {(list, search) => ( +
+ {search} + {list} +
)} -
+
); }; From 18addcf76ac5a98d9c8a1e961f3b314367d2e269 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Wed, 25 Jan 2023 14:30:45 +0100 Subject: [PATCH 2/9] add data test attribute --- .../rules_table/rules_table_filters/tags_filter_popover.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index 3991d414396e7..ec4e8916fcba1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -73,6 +73,9 @@ const TagsFilterPopoverComponent = ({ closePopover={() => setIsTagPopoverOpen(!isTagPopoverOpen)} panelPaddingSize="none" repositionOnScroll + panelProps={{ + 'data-test-subj': 'tags-filter-popover', + }} > Date: Wed, 25 Jan 2023 16:03:52 +0100 Subject: [PATCH 3/9] allow to update the tags list --- .../rules_table_filters/tags_filter_popover.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index ec4e8916fcba1..a915298d3db24 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import type { EuiSelectableOption } from '@elastic/eui'; import { EuiFilterButton, EuiPopover, EuiPopoverTitle, EuiSelectable } from '@elastic/eui'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; @@ -50,6 +50,17 @@ const TagsFilterPopoverComponent = ({ setSelectableOptions(newOptions); toggleSelectedGroup(changedOption.label, selectedTags, onSelectedTagsChanged); }; + + useEffect(() => { + const selectedTagsSet = new Set(selectedTags); + const newSelectableOptions: EuiSelectableOption[] = sortedTags.map((label) => ({ + label, + checked: selectedTagsSet.has(label) ? 'on' : undefined, + })); + + setSelectableOptions(newSelectableOptions); + }, [sortedTags, selectedTags]); + const triggerButton = ( Date: Wed, 25 Jan 2023 20:08:51 +0100 Subject: [PATCH 4/9] fix e2e tests --- .../cypress/e2e/detection_rules/bulk_edit_rules.cy.ts | 6 ------ .../security_solution/cypress/screens/common/controls.ts | 2 ++ .../security_solution/cypress/tasks/rules_bulk_edit.ts | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts index 7aa90997a8101..42282ef1e64d4 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts @@ -267,12 +267,6 @@ describe('Detection rules, bulk edit', () => { // check if only pre-populated tags exist in the tags filter checkTagsInTagsFilter(prePopulatedTags); - cy.get(EUI_FILTER_SELECT_ITEM) - .should('have.length', prePopulatedTags.length) - .each(($el, index) => { - cy.wrap($el).should('have.text', prePopulatedTags[index]); - }); - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); // open add tags form and add 2 new tags diff --git a/x-pack/plugins/security_solution/cypress/screens/common/controls.ts b/x-pack/plugins/security_solution/cypress/screens/common/controls.ts index 2b36103996168..8a2335f81049b 100644 --- a/x-pack/plugins/security_solution/cypress/screens/common/controls.ts +++ b/x-pack/plugins/security_solution/cypress/screens/common/controls.ts @@ -9,6 +9,8 @@ export const TIMELINE_SEARCHBOX = '[data-test-subj="timeline-super-select-search export const EUI_FILTER_SELECT_ITEM = '.euiFilterSelectItem'; +export const EUI_SELECTABLE_LIST_ITEM = '[data-test-subj="euiSelectableList"] li'; + export const EUI_CHECKBOX = '.euiCheckbox__input'; export const COMBO_BOX_INPUT = '[data-test-subj="comboBoxInput"]'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts b/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts index e01e72fe140db..b2203d1b1202a 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TIMELINE_SEARCHBOX, EUI_FILTER_SELECT_ITEM } from '../screens/common/controls'; +import { TIMELINE_SEARCHBOX, EUI_SELECTABLE_LIST_ITEM } from '../screens/common/controls'; import { BULK_ACTIONS_BTN, @@ -226,7 +226,7 @@ export const selectTimelineTemplate = (timelineTitle: string) => { export const checkTagsInTagsFilter = (tags: string[]) => { cy.get(RULES_TAGS_FILTER_BTN).contains(`Tags${tags.length}`).click(); - cy.get(EUI_FILTER_SELECT_ITEM) + cy.get(EUI_SELECTABLE_LIST_ITEM) .should('have.length', tags.length) .each(($el, index) => { cy.wrap($el).should('have.text', tags[index]); From 458774935e6d2bbd0ca30c0f0064617e8774c910 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Wed, 25 Jan 2023 21:58:44 +0100 Subject: [PATCH 5/9] remove duplicated code --- .../cypress/e2e/detection_rules/bulk_edit_rules.cy.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts index 42282ef1e64d4..b3f9a48b3e3ef 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/bulk_edit_rules.cy.ts @@ -290,12 +290,6 @@ describe('Detection rules, bulk edit', () => { // check if only pre-populated tags exist in the tags filter checkTagsInTagsFilter(prePopulatedTags); - cy.get(EUI_FILTER_SELECT_ITEM) - .should('have.length', prePopulatedTags.length) - .each(($el, index) => { - cy.wrap($el).should('have.text', prePopulatedTags[index]); - }); - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); // open add tags form and add 2 new tags From 0a17b845d5b844449d29a086fc20d779e6b46823 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 26 Jan 2023 12:43:08 +0100 Subject: [PATCH 6/9] display padded search field --- .../rules_table/rules_table_filters/tags_filter_popover.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index a915298d3db24..990067b30deb3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -92,7 +92,6 @@ const TagsFilterPopoverComponent = ({ searchable searchProps={{ placeholder: 'Search tags', - compressed: true, }} aria-label="Rules tag search" options={selectableOptions} From 7600ae2cdd3ae5624e19e02856cf33abbb4889db Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 26 Jan 2023 13:05:44 +0100 Subject: [PATCH 7/9] get rid of search field margin --- .../rules_table/rules_table_filters/tags_filter_popover.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index 990067b30deb3..349f5197f1735 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -101,7 +101,7 @@ const TagsFilterPopoverComponent = ({ > {(list, search) => (
- {search} + {search} {list}
)} From f210f48b2112929857ca25fed81f86d9854a1afe Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 27 Jan 2023 13:30:57 +0100 Subject: [PATCH 8/9] get rid of magic constant --- .../rules_table/rules_table_filters/tags_filter_popover.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index 349f5197f1735..f5cae740e2da0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -12,6 +12,8 @@ import * as i18n from '../../../../../detections/pages/detection_engine/rules/tr import { toggleSelectedGroup } from '../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group'; import { caseInsensitiveSort } from '../helpers'; +const TAGS_POPOVER_WIDTH = 274; + interface TagsFilterPopoverProps { selectedTags: string[]; tags: string[]; @@ -100,7 +102,7 @@ const TagsFilterPopoverComponent = ({ noMatchesMessage={i18n.NO_TAGS_AVAILABLE} > {(list, search) => ( -
+
{search} {list}
From 5d6c42a53d1394fdd02440e39f09dd7c267a617e Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 27 Jan 2023 13:34:28 +0100 Subject: [PATCH 9/9] convert hard coded text to i18n strings --- .../rules_table_filters/tags_filter_popover.tsx | 4 ++-- .../pages/detection_engine/rules/translations.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index f5cae740e2da0..8784c42920931 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -93,9 +93,9 @@ const TagsFilterPopoverComponent = ({