diff --git a/src/components/IOC/IOCIcons/IOCIcons.js b/src/components/IOC/IOCIcons/IOCIcons.js index bd39c3573504a5e9929ac18f7d42cc6d5fbfe619..ae64619c38f67b761da73f835c5616f203e12cd1 100644 --- a/src/components/IOC/IOCIcons/IOCIcons.js +++ b/src/components/IOC/IOCIcons/IOCIcons.js @@ -1,11 +1,9 @@ import React from "react"; -import { Typography, useTheme, Stack } from "@mui/material"; +import { Typography, useTheme, Stack, Badge } from "@mui/material"; import { Brightness1, StopCircle, - Error, RadioButtonUnchecked, - ErrorOutline, HelpOutline, PlayCircleFilled, PauseCircleFilled @@ -14,13 +12,25 @@ import Popover from "../../common/Popover"; import { AlertBanner } from "@ess-ics/ce-ui-common"; import LabeledIcon from "../../common/LabeledIcon/LabeledIcon"; +const STATUS = { + active: "active", + disabled: "disabled", + alert: "alert", + inactive: "inactive", + inactiveAlert: "inactive alert" +}; + +const SEVERITY = { + info: "info" +}; + function AlertMessagesPopoverContents({ title, alerts }) { // Filter out INFO level alerts // And for now filter out links on alerts due to issues with // focus behavior of popovers // Also normalize the type to lowercase since AlertBanner expects lowercase const sanitizedAlerts = ( - alerts?.filter((alert) => alert?.type.toLowerCase() !== "info") || [] + alerts?.filter((alert) => alert?.type.toLowerCase() !== SEVERITY.info) || [] ).map((alert) => ({ ...alert, type: alert?.type?.toLowerCase(), @@ -57,25 +67,25 @@ export function IOCStatusIcon({ ioc }) { const alertSeverity = ioc?.alertSeverity?.toLowerCase(); const iconConfig = { - active: { + [STATUS.active]: { title: "Active", icon: Brightness1 }, - disabled: { + [STATUS.disabled]: { title: "Disabled", icon: StopCircle }, - alert: { + [STATUS.alert]: { title: "Alert", - icon: Error + icon: Brightness1 }, - inactive: { + [STATUS.inactive]: { title: "Inactive", icon: RadioButtonUnchecked }, - "inactive alert": { + [STATUS.inactiveAlert]: { title: "Alert", - icon: ErrorOutline + icon: RadioButtonUnchecked }, null: { title: "Unknown", @@ -89,44 +99,61 @@ export function IOCStatusIcon({ ioc }) { active = undefined; } - if (active && (alertSeverity === undefined || alertSeverity === "info")) { + if ( + active && + (alertSeverity === undefined || alertSeverity === SEVERITY.info) + ) { // Active status / running - status = "active"; + status = STATUS.active; } else if ( active === false && - (alertSeverity === undefined || alertSeverity === "info") + (alertSeverity === undefined || alertSeverity === SEVERITY.info) ) { // stopped/paused - status = "disabled"; + status = STATUS.disabled; } else if ( active !== undefined && alertSeverity !== undefined && - alertSeverity !== "info" + alertSeverity !== SEVERITY.info ) { // warning/error - status = "alert"; + status = STATUS.alert; } else if ( (active === undefined || activeDeployment === null) && - (alertSeverity === undefined || alertSeverity === "info") + (alertSeverity === undefined || alertSeverity === SEVERITY.info) ) { // Inactive status - status = "inactive"; + status = STATUS.inactive; } else if ( (active === undefined || activeDeployment === null) && alertSeverity !== undefined && - alertSeverity !== "info" + alertSeverity !== SEVERITY.info ) { // inactive with warning/error - status = "inactive alert"; + status = STATUS.inactiveAlert; } else { // unknown fallback state status = null; } const iconTitle = iconConfig[status].title; + + const getLabel = () => { + if (status === STATUS.alert || status === STATUS.inactiveAlert) { + const warnings = alerts.filter((alert) => alert.type === "WARNING"); + const errors = alerts.filter((alert) => alert.type === "ERROR"); + const hasWarnings = Boolean(warnings.length); + const hasErrors = Boolean(errors.length); + return `${iconTitle} ${hasWarnings ? warnings.length + " warnings" : ""}${ + hasErrors ? errors.length + " errors" : "" + }`; + } + return iconTitle; + }; + const statusIcon = ( <LabeledIcon - label={iconTitle} + label={getLabel()} Icon={iconConfig[status].icon} labelPosition="none" /> @@ -149,7 +176,16 @@ export function IOCStatusIcon({ ioc }) { onMouseLeave={handlePopoverClose} style={{ color: theme.palette.status.icons }} > - {statusIcon} + {status === STATUS.alert || status === STATUS.inactiveAlert ? ( + <Badge + badgeContent={"!"} + color="error" + > + {statusIcon} + </Badge> + ) : ( + statusIcon + )} </div> )} popoverContents={ diff --git a/src/components/IOC/IOCTable/IOCTable.spec.js b/src/components/IOC/IOCTable/IOCTable.spec.js index 024236759fc015fb55b73a381bf791a2dbc9214a..6508c8def6a54d8ec119881afe327f2591758430 100644 --- a/src/components/IOC/IOCTable/IOCTable.spec.js +++ b/src/components/IOC/IOCTable/IOCTable.spec.js @@ -6,7 +6,7 @@ const { AfterAsync } = composeStories(stories); const textColumns = ["IOC name", "Description", "Host", "Network"]; const columns = ["Status"].concat(textColumns); const firstRowData = [ - "Alert", + "Alert 1 warnings1 errors !", "VacS-RFQ:SC-IOC-130", "Some description", "vacs-accv-vm-ioc", @@ -39,7 +39,7 @@ describe("IOCTable", () => { .each(($el, index) => { if (index === 0) { const iconTitle = firstRowData[index]; - cy.wrap($el).findByRole("img", { name: iconTitle }); + cy.wrap($el).findByRole("cell", { name: iconTitle }); } else { cy.wrap($el) .find("p")