diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.tsx
index 062d7967bf3018..e06aea2fb2785e 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.tsx
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { bucketRulesResponse, showRulesTable } from './helpers';
+import { bucketRulesResponse, caseInsensitiveSort, showRulesTable } from './helpers';
import { mockRule, mockRuleError } from './__mocks__/mock';
import uuid from 'uuid';
import { Rule, RuleError } from '../../../../containers/detection_engine/rules';
@@ -86,4 +86,15 @@ describe('AllRulesTable Helpers', () => {
expect(result).toBeTruthy();
});
});
+
+ describe('caseInsensitiveSort', () => {
+ describe('when an array of differently cased tags is passed', () => {
+ const unsortedTags = ['atest', 'Ctest', 'Btest', 'ctest', 'btest', 'Atest'];
+ const result = caseInsensitiveSort(unsortedTags);
+ it('returns an alphabetically sorted array with no regard for casing', () => {
+ const expected = ['atest', 'Atest', 'Btest', 'btest', 'Ctest', 'ctest'];
+ expect(result).toEqual(expected);
+ });
+ });
+ });
});
diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts
index 0ebeb84d57468c..c54c9ed9b8ef9d 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts
@@ -33,3 +33,7 @@ export const showRulesTable = ({
}) =>
(rulesCustomInstalled != null && rulesCustomInstalled > 0) ||
(rulesInstalled != null && rulesInstalled > 0);
+
+export const caseInsensitiveSort = (tags: string[]): string[] => {
+ return tags.sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase())); // Case insensitive
+};
diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
index 2bf62317dbcac7..9748dde91d18be 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
@@ -27,6 +27,7 @@ import {
import styled from 'styled-components';
import * as i18n from '../../translations';
import { toggleSelectedGroup } from '../../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group';
+import { caseInsensitiveSort } from '../helpers';
interface TagsFilterPopoverProps {
selectedTags: string[];
@@ -62,9 +63,7 @@ const TagsFilterPopoverComponent = ({
selectedTags,
onSelectedTagsChanged,
}: TagsFilterPopoverProps) => {
- const sortedTags = useMemo(() => {
- return tags.sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase())); // Case insensitive
- }, [tags]);
+ const sortedTags = useMemo(() => caseInsensitiveSort(tags), [tags]);
const [isTagPopoverOpen, setIsTagPopoverOpen] = useState(false);
const [searchInput, setSearchInput] = useState('');
const [filterTags, setFilterTags] = useState(sortedTags);
diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/tag_display.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/tag_display.tsx
index dd1b10b7c429ca..9503f5b8841330 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/tag_display.tsx
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/tag_display.tsx
@@ -4,10 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useState } from 'react';
+import React, { useMemo, useState } from 'react';
import { EuiPopover, EuiBadgeGroup, EuiBadge, EuiButtonEmpty } from '@elastic/eui';
import styled from 'styled-components';
import * as i18n from '../translations';
+import { caseInsensitiveSort } from './helpers';
interface TagsDisplayProps {
tags: string[];
@@ -34,12 +35,13 @@ const TagPopoverButton = styled(EuiButtonEmpty)`
*/
const TagsDisplayComponent = ({ tags }: TagsDisplayProps) => {
const [isTagPopoverOpen, setIsTagPopoverOpen] = useState(false);
+ const sortedTags = useMemo(() => caseInsensitiveSort(tags), [tags]);
return (
<>
- {tags.length <= 3 ? (
+ {sortedTags.length <= 3 ? (
- {tags.map((tag: string, i: number) => (
+ {sortedTags.map((tag: string, i: number) => (
{
) : (
- {tags.slice(0, 3).map((tag: string, i: number) => (
+ {sortedTags.slice(0, 3).map((tag: string, i: number) => (
{
repositionOnScroll
>
- {tags.map((tag: string, i: number) => (
+ {sortedTags.map((tag: string, i: number) => (
{tag}