From 9c21d71c4491474f5e14b388104612249eeed3c9 Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Tue, 28 Apr 2026 23:54:39 -0400 Subject: [PATCH 1/7] refactor(inputs): softer button hover, sx-forwarding TextInput, themed FieldLabel - Button.tsx: contained variant's hover now uses HOVER.DARKEN=0.06 instead of MUI's default 16%, which was visibly heavy on the green primary buttons across the app. Also fixes a subtle bug where the earlier hover sx merge order silently dropped the boxShadow:'none' reset. Added a HOVER token group to constants.ts so the darken value has a single source of truth. - TextInput.tsx: forward the caller's sx to the wrapper Stack when a fieldLabel is present (previously it was applied to the inner TextField, so flex:1 etc. didn't propagate to the visible width). Inner sx now also explicitly width:100% so wrapped inputs don't collapse to content width when their parent is a flex row. - FieldLabel.tsx: drop the hardcoded fontSize:'14px' and use variant=body1 (=13px from theme) to match the rest of the app's body typography. --- client/src/Components/inputs/Button.tsx | 40 ++++++++++--- client/src/Components/inputs/FieldLabel.tsx | 2 +- client/src/Components/inputs/TextInput.tsx | 62 +++++++++++---------- client/src/Utils/Theme/constants.ts | 4 ++ 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/client/src/Components/inputs/Button.tsx b/client/src/Components/inputs/Button.tsx index 54f776075..4eae654b2 100644 --- a/client/src/Components/inputs/Button.tsx +++ b/client/src/Components/inputs/Button.tsx @@ -1,19 +1,43 @@ import Button from "@mui/material/Button"; import type { ButtonProps } from "@mui/material/Button"; -import { useTheme } from "@mui/material/styles"; +import { useTheme, darken } from "@mui/material/styles"; +import { HOVER } from "@/Utils/Theme/constants"; + +const PALETTE_COLORS = [ + "primary", + "secondary", + "error", + "warning", + "info", + "success", +] as const; +type PaletteColor = (typeof PALETTE_COLORS)[number]; export const ButtonInput = ({ sx, ...props }: ButtonProps) => { const theme = useTheme(); - const outlinedSx = + + const hoverOverrides: Record = { boxShadow: "none" }; + + if (props.variant === "outlined") { + hoverOverrides.borderColor = theme.palette.text.secondary; + } + + if (props.variant === "contained") { + const colorKey = (props.color ?? "primary") as PaletteColor; + const palette = theme.palette[colorKey]; + if (palette && typeof palette === "object" && "main" in palette) { + hoverOverrides.backgroundColor = darken(palette.main, HOVER.DARKEN); + } + } + + const variantSx = props.variant === "outlined" ? { color: theme.palette.text.primary, borderColor: theme.palette.divider, - "&:hover": { - borderColor: theme.palette.text.secondary, - }, } : {}; + return ( } > - + Date: Tue, 28 Apr 2026 23:56:10 -0400 Subject: [PATCH 3/7] feat(incidents): consistent typography, icons, and layout across the page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - All uppercase headers (Active Incidents, Latest Incidents, Incident Statistics, Resolved Incidents, summary card titles, details card sections) now use the existing 'eyebrow' typography variant. That's the same style used on the Logs page and lives in Theme.ts so future tweaks land in one place. - Latest Incidents and Incident Statistics rows now share a minHeight so both cards line up vertically; Latest Incidents items dropped their extra dividers and Box wrappers. - Body text in the summary cards (and the details dialog) uses variant=body1 (13px) consistently — previously a mix of body1/body2 and unspecified Typography. - All lucide icons in CardSummary go through the design-system wrapper so they share the project's strokeWidth=1.5 default rather than lucide's default 2. - ControlsIncidentFilter: replaced the missing pages.incidents.filters.clearFilters key (which was rendering as raw text) with the existing common.buttons.clearFilters. - CardDetails: extracted local SectionHeading and Cell helpers; switched the cards' bare cells to variant=body1 + variant=eyebrow for headings; dropped redundant title-dividers (eyebrow style already separates visually). --- .../Incidents/Components/CardDetails.tsx | 100 +++++++++--------- .../Incidents/Components/CardSummary.tsx | 63 +++++------ .../Components/ControlsIncidentFilter.tsx | 2 +- client/src/Pages/Incidents/index.tsx | 11 +- 4 files changed, 85 insertions(+), 91 deletions(-) diff --git a/client/src/Pages/Incidents/Components/CardDetails.tsx b/client/src/Pages/Incidents/Components/CardDetails.tsx index 448ba2e69..c4ae3a83d 100644 --- a/client/src/Pages/Incidents/Components/CardDetails.tsx +++ b/client/src/Pages/Incidents/Components/CardDetails.tsx @@ -20,6 +20,20 @@ interface CardDetailsProps { sx?: object; } +const SectionHeading = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + +const Cell = ({ children }: { children: React.ReactNode }) => ( + {children} +); + export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { const { t } = useTranslation(); const theme = useTheme(); @@ -33,22 +47,18 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { gap={theme.spacing(LAYOUT.MD)} sx={sx} > - - {t("pages.incidents.dialog.details.title")} - + {t("pages.incidents.dialog.details.title")} - - {t("pages.incidents.dialog.details.overview")} - - - + {t("pages.incidents.dialog.details.overview")} - {t("pages.incidents.dialog.details.status")} + + {t("pages.incidents.dialog.details.status")} + { {monitor && ( <> - {t("pages.incidents.dialog.details.monitor")} + + {t("pages.incidents.dialog.details.monitor")} + - {monitor.name ?? "N/A"} + {monitor.name ?? "N/A"} - {t("pages.incidents.dialog.details.url")} + {t("pages.incidents.dialog.details.url")} - {monitor.url ?? "N/A"} + {monitor.url ?? "N/A"} )} @@ -78,51 +90,48 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { - - {t("pages.incidents.dialog.details.analysis")} - - + {t("pages.incidents.dialog.details.analysis")} - {t("pages.incidents.dialog.details.timeline")} + {t("pages.incidents.dialog.details.timeline")} - {t("pages.incidents.dialog.details.detailsLabel")} + {t("pages.incidents.dialog.details.detailsLabel")} - + - + - {t("pages.incidents.dialog.details.startedAt")} + {t("pages.incidents.dialog.details.startedAt")} - + {formatDateWithTz(incident.startTime, "D MMM YYYY, h:mm A", uiTimezone)} - + - {t("pages.incidents.dialog.details.statusCode")} + {t("pages.incidents.dialog.details.statusCode")} - {incident.statusCode ?? "N/A"} + {incident.statusCode ?? "N/A"} - {t("pages.incidents.dialog.details.downtime")} + {t("pages.incidents.dialog.details.downtime")} - {getIncidentsDuration(incident)} + {getIncidentsDuration(incident)} - {t("pages.incidents.dialog.details.message")} + {t("pages.incidents.dialog.details.message")} - {incident.message ?? "N/A"} + {incident.message ?? "N/A"} @@ -130,60 +139,53 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { {!incident.status && ( - + {t("pages.incidents.dialog.details.resolutionDetails")} - - + - {t("pages.incidents.dialog.details.resolvedAt")} + {t("pages.incidents.dialog.details.resolvedAt")} - + {incident.endTime ? formatDateWithTz(incident.endTime, "D MMM YYYY, h:mm A", uiTimezone) : "N/A"} - + - - {t("pages.incidents.dialog.details.resolutionType")} - + {t("pages.incidents.dialog.details.resolutionType")} - + {incident.resolutionType ? t( `pages.incidents.dialog.details.resolutionTypes.${incident.resolutionType}` ) : "N/A"} - + {incident.resolvedBy && ( <> - - {t("pages.incidents.dialog.details.resolvedBy")} - + {t("pages.incidents.dialog.details.resolvedBy")} - - {incident.resolvedByEmail ?? incident.resolvedBy} - + {incident.resolvedByEmail ?? incident.resolvedBy} )} {incident.comment && ( <> - {t("pages.incidents.dialog.details.comment")} + {t("pages.incidents.dialog.details.comment")} - {incident.comment} + {incident.comment} )} diff --git a/client/src/Pages/Incidents/Components/CardSummary.tsx b/client/src/Pages/Incidents/Components/CardSummary.tsx index 938455808..ae75f5f37 100644 --- a/client/src/Pages/Incidents/Components/CardSummary.tsx +++ b/client/src/Pages/Incidents/Components/CardSummary.tsx @@ -1,8 +1,7 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; -import Divider from "@mui/material/Divider"; import Grid from "@mui/material/Grid"; -import { BaseBox, ValueLabel } from "@/Components/design-elements"; +import { BaseBox, Icon, ValueLabel } from "@/Components/design-elements"; import { CircleCheck, TriangleAlert, Bell, Wrench, Globe } from "lucide-react"; import Box from "@mui/material/Box"; @@ -25,6 +24,7 @@ const SummaryItem = ({ icon, label, value }: SummaryItemProps) => { alignItems="center" justifyContent="space-between" gap={theme.spacing(2)} + minHeight={32} > { gap={theme.spacing(2)} > {icon} - {label} + {label} {value} @@ -67,15 +67,11 @@ export const SummaryCard = ({ > {title} - {children} @@ -97,10 +93,13 @@ export const SummaryCardActiveIncidents = ({ const activeCount = summary.totalActive; const hasActive = activeCount > 0; const color = hasActive ? theme.palette.error.main : theme.palette.success.main; - const icon = hasActive ? ( - - ) : ( - + const icon = ( + + + ); const msg = t("pages.incidents.summaryCard.activeIncidents.active", { count: activeCount, @@ -133,10 +132,7 @@ const SummaryIncidentItem = ({ incident }: { incident: IncidentSummaryItem }) => container alignItems="center" spacing={2} - sx={{ - width: "100%", - py: theme.spacing(0.5), - }} + sx={{ width: "100%", minHeight: 32 }} > gap: theme.spacing(2), }} > - + size={{ xs: 12, md: 6, lg: 4 }} sx={{ textAlign: { xs: "left", md: "right" }, - fontWeight: 500, + fontWeight: 600, }} > {duration} @@ -190,22 +184,17 @@ export const SummaryCardLatestIncidents = ({ summary, }: SummaryCardLatestIncidentsProps) => { const { t } = useTranslation(); - const theme = useTheme(); const latestIncidents = summary?.latestIncidents ?? []; return ( - - {latestIncidents.slice(0, 3).map((incident, index) => ( - - - {index < latestIncidents.length - 1 && ( - - )} - - ))} - + {latestIncidents.slice(0, 3).map((incident) => ( + + ))} ); }; @@ -224,17 +213,17 @@ export const SummaryCardStats = ({ summary }: SummaryCardStatsProps) => { return ( } + icon={} label={t("pages.incidents.summaryCard.incidentStats.totalIncidents")} value={summary?.total || 0} /> } + icon={} label={t("pages.incidents.summaryCard.incidentStats.mostAffectedMonitor")} value={mostAffected} /> } + icon={} label={t("pages.incidents.summaryCard.incidentStats.avgResolutionTime")} value={ summary.total > 0 diff --git a/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx b/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx index a0f4eb15a..af7cba105 100644 --- a/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx +++ b/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx @@ -75,7 +75,7 @@ export const ControlsIncidentFilter = ({ variant="contained" onClick={onClearFilters} > - {t("pages.incidents.filters.clearFilters")} + {t("common.buttons.clearFilters")} )} diff --git a/client/src/Pages/Incidents/index.tsx b/client/src/Pages/Incidents/index.tsx index 84c414b26..a0a7e04d8 100644 --- a/client/src/Pages/Incidents/index.tsx +++ b/client/src/Pages/Incidents/index.tsx @@ -15,6 +15,7 @@ import { HeaderTimeRange } from "@/Components/common"; import { ControlsIncidentFilter } from "@/Pages/Incidents/Components/ControlsIncidentFilter"; import { useGet } from "@/Hooks/UseApi"; +import { LAYOUT } from "@/Utils/Theme/constants"; import { useState, useEffect, useMemo } from "react"; import { useParams } from "react-router-dom"; import type { Incident, IncidentsResponse, IncidentSummary } from "@/Types/Incident"; @@ -186,8 +187,9 @@ const IncidentsPage = () => { {activeIncidentsCount > 0 && ( <> {t("pages.incidents.table.activeIncidents")} @@ -208,8 +210,9 @@ const IncidentsPage = () => { )} {t("pages.incidents.table.resolvedIncidents")} From 5792ca624e3e0eea67b4bb5fdd13ca43dac9dad4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 29 Apr 2026 09:37:37 -0700 Subject: [PATCH 4/7] normalize NoticeBanner --- .../design-elements/MonitorStatus.tsx | 2 +- .../design-elements/NoticeBanner.tsx | 31 +++++++++---------- client/src/Utils/Theme/Palette.ts | 13 ++++---- client/src/Utils/Theme/Theme.ts | 2 +- client/src/Utils/Theme/constants.ts | 1 + 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/client/src/Components/design-elements/MonitorStatus.tsx b/client/src/Components/design-elements/MonitorStatus.tsx index dbeb5fa84..14f33d934 100644 --- a/client/src/Components/design-elements/MonitorStatus.tsx +++ b/client/src/Components/design-elements/MonitorStatus.tsx @@ -17,7 +17,7 @@ export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => { return ( = { info: "ⓘ", @@ -25,29 +27,26 @@ export const NoticeBanner = ({ severity = "info", children }: NoticeBannerProps) direction="row" alignItems="flex-start" gap={theme.spacing(LAYOUT.SM)} - sx={{ - width: "100%", - p: theme.spacing(LAYOUT.MD), - borderRadius: 1, - border: `1px solid ${alpha(tone, 0.45)}`, - backgroundColor: alpha(tone, 0.08), - textAlign: "left", - }} + width={"100%"} + p={theme.spacing(LAYOUT.MD)} + borderRadius={theme.shape.borderRadius} + border={`1px solid ${alpha(tone, 0.45)}`} + bgcolor={alpha(tone, 0.08)} + textAlign={"left"} > {SEVERITY_GLYPH[severity]} {children} diff --git a/client/src/Utils/Theme/Palette.ts b/client/src/Utils/Theme/Palette.ts index 0fe08583a..92c08cd2f 100644 --- a/client/src/Utils/Theme/Palette.ts +++ b/client/src/Utils/Theme/Palette.ts @@ -1,12 +1,13 @@ const typographyBase = 13; export const typographyLevels = { - base: typographyBase, - xs: `${(typographyBase - 4) / 16}rem`, - s: `${(typographyBase - 2) / 16}rem`, - m: `${typographyBase / 16}rem`, - l: `${(typographyBase + 2) / 16}rem`, - xl: `${(typographyBase + 10) / 16}rem`, + base: typographyBase, // 13px + xs: `${(typographyBase - 4) / 16}rem`, // 9px + s: `${(typographyBase - 2) / 16}rem`, // 11px + m: `${typographyBase / 16}rem`, // 13px + l: `${(typographyBase + 2) / 16}rem`, // 15px + xl: `${(typographyBase + 5) / 16}rem`, // 18px + xxl: `${(typographyBase + 10) / 16}rem`, // 23px }; export const colors = { diff --git a/client/src/Utils/Theme/Theme.ts b/client/src/Utils/Theme/Theme.ts index 19f864c6f..7c712d66d 100644 --- a/client/src/Utils/Theme/Theme.ts +++ b/client/src/Utils/Theme/Theme.ts @@ -58,7 +58,7 @@ export const theme = (mode: string, palette: any) => fontFamilyMonospace, fontSize: typographyLevels.base, h1: { - fontSize: typographyLevels.xl, + fontSize: typographyLevels.xxl, fontWeight: 500, }, h2: { diff --git a/client/src/Utils/Theme/constants.ts b/client/src/Utils/Theme/constants.ts index 8b045f9f6..e0d74815e 100644 --- a/client/src/Utils/Theme/constants.ts +++ b/client/src/Utils/Theme/constants.ts @@ -8,6 +8,7 @@ export const SPACING = { } as const; export const LAYOUT = { + XXS: 2, XS: 4, SM: 6, MD: 8, From 2dd921891045af89f13db243074d2a2a2b166982 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 29 Apr 2026 09:42:49 -0700 Subject: [PATCH 5/7] normailze dialog and basepage --- .../Components/design-elements/BasePage.tsx | 4 ++-- client/src/Components/inputs/Dialog.tsx | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/src/Components/design-elements/BasePage.tsx b/client/src/Components/design-elements/BasePage.tsx index 845d20a4c..c955fb6b7 100644 --- a/client/src/Components/design-elements/BasePage.tsx +++ b/client/src/Components/design-elements/BasePage.tsx @@ -38,9 +38,9 @@ export const PageSpeedKeyPriorityFallback = () => { diff --git a/client/src/Components/inputs/Dialog.tsx b/client/src/Components/inputs/Dialog.tsx index 38b858bd6..02d164abd 100644 --- a/client/src/Components/inputs/Dialog.tsx +++ b/client/src/Components/inputs/Dialog.tsx @@ -53,24 +53,24 @@ export const DialogInput = ({ > {title && ( {title} {content && ( {content} @@ -79,7 +79,7 @@ export const DialogInput = ({ )} {children && ( - {children} + {children} )} Date: Wed, 29 Apr 2026 09:47:11 -0700 Subject: [PATCH 6/7] normalize --- client/src/Components/inputs/TextInput.tsx | 3 ++- client/src/Utils/Theme/constants.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/Components/inputs/TextInput.tsx b/client/src/Components/inputs/TextInput.tsx index 8b7092d0b..13277be72 100644 --- a/client/src/Components/inputs/TextInput.tsx +++ b/client/src/Components/inputs/TextInput.tsx @@ -5,6 +5,7 @@ import { typographyLevels } from "@/Utils/Theme/Palette"; import { useTheme } from "@mui/material/styles"; import Stack from "@mui/material/Stack"; import { FieldLabel } from "./FieldLabel"; +import { LAYOUT } from "@/Utils/Theme/constants"; interface TextInputProps extends Omit { fieldLabel?: string; @@ -56,7 +57,7 @@ export const TextInput = forwardRef(function T if (fieldLabel) { return ( {fieldLabel} diff --git a/client/src/Utils/Theme/constants.ts b/client/src/Utils/Theme/constants.ts index 4b2e04be6..d718d61dc 100644 --- a/client/src/Utils/Theme/constants.ts +++ b/client/src/Utils/Theme/constants.ts @@ -18,5 +18,5 @@ export const LAYOUT = { } as const; export const HOVER = { - DARKEN: 0.06, + DARKEN: 0.06, // This is a coefficient for darkening function } as const; From 301942d0eb5f863b334de0136c326a0cbc4c710d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 29 Apr 2026 09:56:01 -0700 Subject: [PATCH 7/7] normalize --- .../Incidents/Components/CardDetails.tsx | 23 +++++++++++-------- .../Incidents/Components/CardSummary.tsx | 2 +- client/src/Pages/Incidents/index.tsx | 8 +++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/client/src/Pages/Incidents/Components/CardDetails.tsx b/client/src/Pages/Incidents/Components/CardDetails.tsx index c4ae3a83d..82ececaa8 100644 --- a/client/src/Pages/Incidents/Components/CardDetails.tsx +++ b/client/src/Pages/Incidents/Components/CardDetails.tsx @@ -13,6 +13,7 @@ import { useSelector } from "react-redux"; import type { RootState } from "@/Types/state"; import { formatDateWithTz } from "@/Utils/TimeUtils"; import { getIncidentsDuration } from "@/Pages/Incidents/utils"; +import { theme } from "@/Utils/Theme/Theme"; interface CardDetailsProps { incident: Incident | null; @@ -20,15 +21,19 @@ interface CardDetailsProps { sx?: object; } -const SectionHeading = ({ children }: { children: React.ReactNode }) => ( - - {children} - -); +const SectionHeading = ({ children }: { children: React.ReactNode }) => { + const theme = useTheme(); + + return ( + + {children} + + ); +}; const Cell = ({ children }: { children: React.ReactNode }) => ( {children} diff --git a/client/src/Pages/Incidents/Components/CardSummary.tsx b/client/src/Pages/Incidents/Components/CardSummary.tsx index ae75f5f37..60dadaa74 100644 --- a/client/src/Pages/Incidents/Components/CardSummary.tsx +++ b/client/src/Pages/Incidents/Components/CardSummary.tsx @@ -68,7 +68,7 @@ export const SummaryCard = ({ {title} diff --git a/client/src/Pages/Incidents/index.tsx b/client/src/Pages/Incidents/index.tsx index a0a7e04d8..63cd18889 100644 --- a/client/src/Pages/Incidents/index.tsx +++ b/client/src/Pages/Incidents/index.tsx @@ -188,8 +188,8 @@ const IncidentsPage = () => { <> {t("pages.incidents.table.activeIncidents")} @@ -211,8 +211,8 @@ const IncidentsPage = () => { {t("pages.incidents.table.resolvedIncidents")}