From 3be050acf5b98b7864378b81c5ce22b69424906f Mon Sep 17 00:00:00 2001 From: santoshp210-akamai <159890961+santoshp210-akamai@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:22:46 +0530 Subject: [PATCH 1/3] upcoming: [DI-28227] - Firewall Alerts enhancements --- .../EntityTypeSelect.test.tsx | 25 +++++++ .../GeneralInformation/EntityTypeSelect.tsx | 4 ++ .../EditAlert/EditAlertDefinition.test.tsx | 68 ++++++++++++++++++- .../Alerts/EditAlert/EditAlertResources.tsx | 10 +++ packages/manager/src/mocks/serverHandlers.ts | 54 +++++++++++++++ 5 files changed, 159 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx index 952574122dd..d6258cc7024 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx @@ -129,4 +129,29 @@ describe('EntityTypeSelect component tests', () => { within(entityTypeDropdown).queryByRole('button', { name: 'Clear' }) ).not.toBeInTheDocument(); }); + + it('should display tooltip text on hover of the help icon', async () => { + renderWithThemeAndHookFormContext({ + component: ( + + ), + }); + + const entityTypeContainer = screen.getByTestId(ENTITY_TYPE_SELECT_TEST_ID); + const helpButton = + within(entityTypeContainer).getByTestId('tooltip-info-icon'); + + await userEvent.hover(helpButton); + + expect( + await screen.findByText( + 'Select a firewall entity type to filter the list in the Entities section. The metrics and dimensions in the Criteria section will update automatically based on your selection.' + ) + ).toBeVisible(); + + await userEvent.unhover(helpButton); + }); }); diff --git a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx index b5f00f52aed..405e42e44d0 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx @@ -55,6 +55,10 @@ export const EntityTypeSelect = (props: EntityTypeSelectProps) => { options={entityTypeOptions} placeholder="Select an Entity Type" sx={{ marginTop: '5px' }} + textFieldProps={{ + labelTooltipText: + 'Select a firewall entity type to filter the list in the Entities section. The metrics and dimensions in the Criteria section will update automatically based on your selection.', + }} value={ entityTypeOptions.find((option) => option.value === field.value) ?? undefined diff --git a/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertDefinition.test.tsx b/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertDefinition.test.tsx index 9c921f21bf2..3289a183404 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertDefinition.test.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertDefinition.test.tsx @@ -1,8 +1,13 @@ -import { waitFor } from '@testing-library/react'; +import { waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { alertFactory, notificationChannelFactory } from 'src/factories'; +import { + alertFactory, + firewallMetricRulesFactory, + firewallNodebalancerMetricCriteria, + notificationChannelFactory, +} from 'src/factories'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { UPDATE_ALERT_SUCCESS_MESSAGE } from '../constants'; @@ -47,6 +52,9 @@ const alertDetails = alertFactory.build({ service_type: 'linode', scope: 'entity', }); + +const ENTITY_TYPE_SELECT_TEST_ID = 'entity-type-select'; + describe('EditAlertDefinition component', () => { it( 'renders the components of the form', @@ -116,4 +124,60 @@ describe('EditAlertDefinition component', () => { }, { timeout: 10000 } ); + + it('should render EntityTypeSelect for firewall with Linode entity type', () => { + const linodeFirewallAlertDetails = alertFactory.build({ + id: 1, + rule_criteria: { + rules: [firewallMetricRulesFactory.build()], + }, + scope: 'entity', + service_type: 'firewall', + }); + + const { getByTestId } = renderWithTheme( + + ); + + const entityTypeSelect = getByTestId(ENTITY_TYPE_SELECT_TEST_ID); + expect(entityTypeSelect).toBeVisible(); + + const combobox = within(entityTypeSelect).getByRole('combobox'); + expect(combobox).toHaveAttribute('value', 'Linodes'); + }); + + it('should render EntityTypeSelect for firewall with NodeBalancer entity type', () => { + const nodebalancerFirewallAlertDetails = alertFactory.build({ + id: 2, + rule_criteria: { + rules: [firewallNodebalancerMetricCriteria.build()], + }, + scope: 'entity', + service_type: 'firewall', + }); + + const { getByTestId } = renderWithTheme( + + ); + + const entityTypeSelect = getByTestId(ENTITY_TYPE_SELECT_TEST_ID); + expect(entityTypeSelect).toBeVisible(); + + const combobox = within(entityTypeSelect).getByRole('combobox'); + expect(combobox).toHaveAttribute('value', 'NodeBalancers'); + }); + + it('should not render EntityTypeSelect for non-firewall service types', () => { + const { queryByTestId } = renderWithTheme( + + ); + + expect(queryByTestId(ENTITY_TYPE_SELECT_TEST_ID)).not.toBeInTheDocument(); + }); }); diff --git a/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertResources.tsx b/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertResources.tsx index fb24c4b98c3..8672f9a92f9 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertResources.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/EditAlert/EditAlertResources.tsx @@ -8,6 +8,7 @@ import { Breadcrumb } from 'src/components/Breadcrumb/Breadcrumb'; import { useEditAlertDefinition } from 'src/queries/cloudpulse/alerts'; import { AlertResources } from '../AlertsResources/AlertsResources'; +import { entityLabelMap } from '../constants'; import { isResourcesEqual } from '../Utils/AlertResourceUtils'; import { getAlertBoxStyles } from '../Utils/utils'; import { EditAlertResourcesConfirmDialog } from './EditAlertResourcesConfirmationDialog'; @@ -85,6 +86,14 @@ export const EditAlertResources = (props: EditAlertProps) => { type, } = alertDetails; + const entityType = + serviceType === 'firewall' + ? alertDetails.rule_criteria.rules[0]?.label.includes( + entityLabelMap['nodebalancer'] + ) + ? 'nodebalancer' + : 'linode' + : undefined; return ( <> @@ -100,6 +109,7 @@ export const EditAlertResources = (props: EditAlertProps) => { alertLabel={label} alertResourceIds={entity_ids} alertType={type} + entityType={entityType} handleResourcesSelection={handleResourcesSelection} isSelectionsNeeded serviceType={service_type} diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index ee7e446336b..c888dac3e55 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -3219,6 +3219,28 @@ export const handlers = [ rules: [firewallNodebalancerMetricCriteria.build()], }, }), + alertFactory.build({ + id: 340, + label: 'Firewall-nodebalancer-system', + type: 'system', + service_type: 'firewall', + entity_ids: ['25'], + rule_criteria: { + rules: [ + firewallNodebalancerMetricCriteria.build({ dimension_filters: [] }), + ], + }, + }), + alertFactory.build({ + id: 123, + label: 'Firewall-linode-system', + type: 'system', + service_type: 'firewall', + entity_ids: ['1', '4'], + rule_criteria: { + rules: [firewallMetricRulesFactory.build()], + }, + }), ]; return HttpResponse.json(makeResourcePage(alerts)); }), @@ -3286,6 +3308,38 @@ export const handlers = [ }) ); } + if (params.id === '340' && params.serviceType === 'firewall') { + return HttpResponse.json( + alertFactory.build({ + id: 340, + label: 'Firewall - nodebalancer - system', + type: 'system', + service_type: 'firewall', + entity_ids: ['25'], + rule_criteria: { + rules: [ + firewallNodebalancerMetricCriteria.build({ + dimension_filters: [], + }), + ], + }, + }) + ); + } + if (params.id === '123' && params.serviceType === 'firewall') { + return HttpResponse.json( + alertFactory.build({ + id: 123, + label: 'Firewall-linode-system', + type: 'system', + service_type: 'firewall', + entity_ids: ['1', '4'], + rule_criteria: { + rules: [firewallMetricRulesFactory.build()], + }, + }) + ); + } if (params.id !== undefined) { return HttpResponse.json( alertFactory.build({ From ef871db91442ef0800582d5b8d5700d28e3f6743 Mon Sep 17 00:00:00 2001 From: santoshp210-akamai <159890961+santoshp210-akamai@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:16:38 +0530 Subject: [PATCH 2/3] add changeset --- .../.changeset/pr-13110-upcoming-features-1763617588411.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-13110-upcoming-features-1763617588411.md diff --git a/packages/manager/.changeset/pr-13110-upcoming-features-1763617588411.md b/packages/manager/.changeset/pr-13110-upcoming-features-1763617588411.md new file mode 100644 index 00000000000..17bae8d23d4 --- /dev/null +++ b/packages/manager/.changeset/pr-13110-upcoming-features-1763617588411.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +ACLP-Alerting: Filtering entities for firewall system alerts, add tooltip text to Entity Type component ([#13110](https://github.com/linode/manager/pull/13110)) From d15e06e583ab5de4f00abd460ccafb52ad24cbeb Mon Sep 17 00:00:00 2001 From: santoshp210-akamai <159890961+santoshp210-akamai@users.noreply.github.com> Date: Tue, 25 Nov 2025 09:30:44 +0530 Subject: [PATCH 3/3] upcoming: [DI-28227] - Use constant for the tooltip string --- .../GeneralInformation/EntityTypeSelect.test.tsx | 7 ++----- .../CreateAlert/GeneralInformation/EntityTypeSelect.tsx | 7 ++++--- .../manager/src/features/CloudPulse/Alerts/constants.ts | 3 +++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx index d6258cc7024..4a4065dceff 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.test.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { renderWithThemeAndHookFormContext } from 'src/utilities/testHelpers'; +import { entityTypeTooltipText } from '../../constants'; import { EntityTypeSelect } from './EntityTypeSelect'; describe('EntityTypeSelect component tests', () => { @@ -146,11 +147,7 @@ describe('EntityTypeSelect component tests', () => { await userEvent.hover(helpButton); - expect( - await screen.findByText( - 'Select a firewall entity type to filter the list in the Entities section. The metrics and dimensions in the Criteria section will update automatically based on your selection.' - ) - ).toBeVisible(); + expect(await screen.findByText(entityTypeTooltipText)).toBeVisible(); await userEvent.unhover(helpButton); }); diff --git a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx index 405e42e44d0..1ecef33f6b9 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/CreateAlert/GeneralInformation/EntityTypeSelect.tsx @@ -3,7 +3,8 @@ import * as React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import type { ControllerRenderProps, FieldPathByValue } from 'react-hook-form'; -import type { Item } from '../../constants'; +import { entityTypeTooltipText, type Item } from '../../constants'; + import type { CreateAlertDefinitionForm } from '../types'; interface EntityTypeSelectProps { @@ -56,8 +57,8 @@ export const EntityTypeSelect = (props: EntityTypeSelectProps) => { placeholder="Select an Entity Type" sx={{ marginTop: '5px' }} textFieldProps={{ - labelTooltipText: - 'Select a firewall entity type to filter the list in the Entities section. The metrics and dimensions in the Criteria section will update automatically based on your selection.', + labelTooltipText: entityTypeTooltipText, + tooltipPosition: 'right', }} value={ entityTypeOptions.find((option) => option.value === field.value) ?? diff --git a/packages/manager/src/features/CloudPulse/Alerts/constants.ts b/packages/manager/src/features/CloudPulse/Alerts/constants.ts index d796dad6c75..45ba4ff3c1a 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/constants.ts +++ b/packages/manager/src/features/CloudPulse/Alerts/constants.ts @@ -274,3 +274,6 @@ export const entityLabelMap = { linode: 'Linode', nodebalancer: 'Node Balancer', }; + +export const entityTypeTooltipText = + 'Select a firewall entity type to filter the list in the Entities section. The metrics and dimensions in the Criteria section will update automatically based on your selection.';