Commit Graph
100 Commits
Author SHA1 Message Date
gorkem-bwl 906d306827 chore(deps): bump postcss (transitive)
Patches CVE-2026-41305 (medium — XSS via unescaped </style> in CSS stringify output).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:46:46 -04:00
gorkem-bwl 6f988cc688 fix(settings): drop from field from transport JSON preview
The transport JSON preview is strictly for verifying what is handed to
nodemailer.createTransport. The From header is built per-message in
sendMail, so showing it inside the transport JSON was misleading. The
separate From: ... pre block below the JSON is the right place for
that preview.
2026-04-29 15:48:12 -04:00
gorkem-bwl 8fbbb1dd4b Revert "refactor(email): set From at transport level instead of per-message"
This reverts commit baa4d693ae.
2026-04-29 15:42:02 -04:00
gorkem-bwl baa4d693ae refactor(email): set From at transport level instead of per-message
The /settings transport preview shows `from` inside the createTransport
JSON, but the implementation was passing it per-message via sendMail.
Switch to passing it as part of the transport config so what the
preview shows matches what is actually built — no behavioural change
for outgoing emails since nodemailer treats transport-level `from` as
the default for every sendMail call.
2026-04-29 15:38:22 -04:00
gorkem-bwl e11553c218 feat(settings): restore From-header preview block under SMTP transport JSON
Brings back the second pre-block I dropped when consolidating the
preview. The transport JSON shows what's handed to nodemailer
createTransport; the From-header block shows the rendered envelope
recipients will see — they answer different questions and both belong.

Conditioned on systemEmailAddress so empty configs don't render an
empty pre.
2026-04-29 15:33:15 -04:00
gorkem-bwl e71892d0bc feat(smtp): add optional sender display name to SMTP configuration
Closes #3600. Previously the From header on test emails and notifications
showed only the raw email address. Adds an optional "Sender name" field
so emails appear from a friendly name like "Checkmate notifications"
<user@example.org>.

## Behaviour
- Field is optional. When empty/null/whitespace, the From header falls
  back to the raw email address — identical to current behaviour, no
  regression for existing installs.
- When set, the email service hands nodemailer { name, address } as the
  message from field. Nodemailer handles RFC-5322 encoding (quotes,
  commas, non-ASCII) so the display name is safe for any input.
- Unsetting works: clearing the input transforms the value to null in
  the Zod parse step, and the settings repository already turns null
  values into a $unset operation.
- Both client and server Zod schemas trim and empty-string-to-null,
  preventing whitespace-only display names from being stored.

## Surfaces
- AppSettings schema, Settings type, EmailTransportConfig pick, server
  Zod validation, client Zod validation, client form defaults, and the
  Settings page form all carry the new systemEmailDisplayName field.
- The transport preview pre-block on /settings now includes a `from`
  key showing exactly what the email service hands nodemailer — the
  string when no display name is set, or { name, address } when it is.
- en.json carries the new label and placeholder. Other locales fall
  back until translated (16 locales pending — separate follow-up).

## Conventions conformance (per docs/frontend-conventions.md)
- The pre-block I touched had three rule #1 violations (sx p,
  borderRadius, backgroundColor); hoisted those to native props using
  theme.shape.borderRadius. Other rule #1 violations elsewhere on this
  page are pre-existing and intentionally left alone.
- No new sx-with-native-equivalents introduced.
- No color="text.X" shorthand introduced.
- No theme module import introduced.
2026-04-29 15:30:16 -04:00
gorkem-bwl aa7051095a docs(client): document frontend conventions and enforce via ESLint
Capture the five recurring code-review patterns from the recent PR series
(#3591–#3596) as enforceable rules so they don't have to be raised again
in review.

## Conventions
- Prefer MUI native props over `sx` (e.g. color={...}, mt={...}, width={...}).
- Use the full theme path for colors: theme.palette.text.secondary, never
  the "text.secondary" shorthand string. The shorthand is invisible to
  grep, which makes future audits and refactors miss callsites.
- No hardcoded numeric or string literals — use LAYOUT, typographyLevels,
  theme.shape.borderRadius, theme.palette tokens.
- Use useTheme() inside components; don't import { theme } from
  @/Utils/Theme/Theme (factory output, not a live mode-aware instance).
- Pair runtime tuples with derived types so they can't drift.

## Files
- docs/frontend-conventions.md — long-form doc with before/after examples
  drawn from the actual review fixes, plus a pre-PR checklist.
- CLAUDE.md — short summary in the Code Conventions section pointing to
  the doc, so it's loaded into agent context at session start.

## ESLint enforcement
- client/.eslintrc.cjs — four no-restricted-syntax selectors for each rule:
  - color="…" / bgcolor="…" / borderColor="…" with a dotted shorthand value
  - sx={{ key: ... }} where key has a native equivalent, only on hoistable
    components (Box, Stack, Typography, Grid, Container, Paper, Card*,
    Divider, Link, Chip) — Dialog/Drawer/Menu etc. only accept sx.
  - import { theme } from "@/Utils/Theme/Theme"
  - Typography fontSize={13} (the body default — drop the prop).
- TypeScript files are now actually parsed: added @typescript-eslint/parser
  and @typescript-eslint/eslint-plugin and a TS override that extends the
  React plugin configs. Several @typescript-eslint/recommended rules
  disabled to avoid noise on the existing codebase.
- client/package.json — lint script now covers .ts/.tsx; new lint-strict
  script for CI use once the codebase is conformant; --max-warnings 0
  removed from `lint` so existing-code warnings don't block the workflow.

## Surface
Running `npm run lint` after this change reports ~280 warnings against
the existing codebase, almost all from rule #1 (sx-vs-native). These are
intentionally warnings, not errors — they surface the work without
blocking. Each warning links to the rule number in the conventions doc
so the reasoning is one click away.
2026-04-29 13:49:58 -04:00
gorkem-bwl 5716b5eea4 feat(settings): explanatory body in Remove monitors confirmation modal
The remove-all-monitors confirmation dialog only had a one-line title
and an empty body, which looked awkward and didn't communicate what was
actually about to be deleted alongside the monitors themselves.

- Adds a paragraph explaining that check history, incidents, scheduled
  maintenance windows, and dependent status pages will also be removed,
  with an inline tip to export monitors first to keep a backup.
- The Confirm button now uses confirmColor='error' to make the
  destructive action visually distinct, with a localized
  'Remove monitors' label.
- Translated to all 16 locales, with terminology aligned to each
  locale's existing usage (e.g. zh-CN/zh-TW use 监控/監控 to match the
  existing button label, vi uses 'trình giám sát', etc.).
2026-04-28 23:58:13 -04:00
gorkem-bwl c89dbebe98 feat(infrastructure): show notice when network charts have zero traffic
When Capture runs inside a container (typical for Docker Desktop), the
only visible interfaces are loopback, so every bytes_sent/bytes_recv
counter is zero and the charts render as flat lines without any
explanation. Users couldn't tell whether Capture was unreachable, the
monitor was broken, or there was just genuinely no traffic.

Detect the case where checks exist (chart configs were built) but every
interface across every check reports zero bytesSentPerSecond and
deltaBytesRecv, and render a NoticeBanner above the chart grid
explaining it and suggesting Capture be run on the host.

Adds pages.infrastructure.charts.labels.netNoTraffic to all 16 locales.
2026-04-28 23:57:14 -04:00
gorkem-bwl 5d5d1dbb23 feat(incidents): consistent typography, icons, and layout across the page
- 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 <Icon>
  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 <Typography> cells to variant=body1 + variant=eyebrow
  for headings; dropped redundant title-dividers (eyebrow style already
  separates visually).
2026-04-28 23:56:10 -04:00
gorkem-bwl 93505f006c feat(account): side-by-side name and password fields in Add Member modal
- AddTeamMemberDialog: First name / Last name now share a row, and
  Password / Confirm password share a row. Each field uses sx={flex:1}
  so the row totals match the width of the email/role rows below.
- InviteTeamMemberDialog: drop the redundant mt={theme.spacing(...)}
  workaround on the form Stack (the new Dialog component provides this
  spacing).
- Constants conformance: spacing literals replaced with LAYOUT.XS.
2026-04-28 23:55:27 -04:00
gorkem-bwl a6204b7bf5 Merge branch 'refactor/button-input-styling' into feat/account-team-modals 2026-04-28 23:54:48 -04:00
gorkem-bwl 9c21d71c44 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.
2026-04-28 23:54:39 -04:00
gorkem-bwl fef3f2c294 refactor(dialog): standard modal layout, NoticeBanner design-element, softer Cancel
Dialog component:
- Title bar gets a subtle background tint + bottom border. Title is
  variant=h2 weight=600. Description tucks under the title with
  variant=body1 secondary color (replaces MUI's DialogContentText).
- Action bar gets a matching subtle tint + top border. Cancel is now
  outlined (was contained-error, which made every modal's Cancel button
  look destructive). Confirm keeps its color (primary by default,
  caller can pass error for destructive flows).
- Content area sits between with its own breathing room baked in, so
  callers no longer need mt={theme.spacing(...)} workarounds.
- The cancelColor prop is removed; sites that genuinely need a
  destructive Cancel can use confirmColor='error' on the Confirm button
  instead.

NoticeBanner design-element:
- Extracted from the inline alert pattern in PageSpeedKeyPriorityFallback
  into a reusable component with severity=info|warning|error.
- Refactored PageSpeedKeyPriorityFallback to use it.

DialogResolution.tsx: drop the now-removed cancelColor prop and the
mt-Box wrapper that's no longer needed (Dialog provides the spacing).
2026-04-28 23:53:59 -04:00
gorkem-bwl 23061e31d1 i18n(create-monitor): translate game description for the remaining 9 locales
Fills in machine translations for ar, cs, fi, fr, ja, pt-BR, tr, uk, vi
so every locale now ships a native translation of the game-monitor
description (including the new server-query setup sentence and the
<gamedigLink> placeholder).
2026-04-28 18:02:57 -04:00
gorkem-bwl 34b1a9cdc2 feat(create-monitor): explain server-side query setup for game monitors
The game monitor type relies on each game's native query protocol — many
require a config file change on the game server (e.g. Minecraft Java
needs `enable-query=true` in `server.properties`). Without that, the
monitor silently fails to reach the server.

Append a sentence to the game-type general settings description that:

- tells the user some games need server-side queries enabled
- points them to the GameDig supported-games list for protocol details

Implementation:

- Use <Trans> with a `gamedigLink` slot so the link renders inline
- Loosen ConfigBox `subtitle` from `string` to `React.ReactNode` so the
  subtitle can host the <Trans> output
- Update all 16 locale files. Six (de, es, ru, th, zh-CN, zh-TW) get a
  full translation of the new sentence; nine empty ones (ar, cs, fi, fr,
  ja, pt-BR, tr, uk, vi) fall back to the English string per the locale
  gap policy
2026-04-28 17:55:24 -04:00
gorkem-bwl bab65770ce refactor(status-page): simplify renderer lookup, extract route prefix, memoize wrapper style
Four small follow-ups from a code review pass:

1. Drop the redundant `?? THEMED_RENDERERS[DEFAULT_STATUS_PAGE_THEME]`
   fallback in Status/index.tsx — the map is now a total Record, so the
   first lookup cannot return undefined.
2. Extract the literal "/status/public" into PUBLIC_STATUS_PAGE_PREFIX in
   Types/StatusPage.ts and reuse from the three runtime call sites
   (Status/index.tsx, HeaderStatusPageControls.tsx, StatusPagesTable.tsx).
   The Routes/index.tsx route definition keeps its string literal — the
   route table is otherwise all literals and the prefix only matters when
   it's interpolated.
3. Delete two narrating comments above the public/admin branches in
   Status/index.tsx — the JSX is self-describing.
4. Move the inline `style` object construction in StatusPageThemeProvider
   into the existing useMemo so the wrapper div receives a stable style
   reference. The previous spread defeated the surrounding memoization on
   every render.
2026-04-28 16:52:16 -04:00
gorkem-bwl ed3645c3d0 refactor(status-page): drop legacy single-design renderer and CSS overrides
The 4 themed renderers (refined, modern, bold, editorial) cover every
StatusPageTheme value and the model defaults to "refined", so the legacy
fallback path in Status/index.tsx was unreachable in practice.

Removing it lets us delete:

- theme-overrides.css (the only remaining CSS file in StatusPage)
- StatusBar / MonitorsList / InfrastructureMetrics (only the legacy
  fallback consumed them)
- The .sp-* className hooks that wired CSS rules into the components

Pure sx via the per-theme styles.ts recipes is now the single source of
truth for every status page surface. Net diff is -801 / +42.

Status/index.tsx now resolves a renderer from the theme map (falling back
to the default theme) and keeps the public-route and admin-preview
branches it already had.
2026-04-28 16:38:35 -04:00
gorkem-bwl 40bcf7f6ac docs: align CONTRIBUTING.md and CLAUDE.md with current toolchain
CONTRIBUTING.md: surface format-check + build in code guidelines
and the PR checklist so contributors run the same verifications
the project enforces locally.

CLAUDE.md: correct stale test framework reference (Mocha+Chai+Sinon
-> Jest) and update the test file glob to server/test/**/*.test.ts.
2026-04-27 23:50:01 -04:00
gorkem-bwl a2786a77ec refactor(status-page): tighten the theme-fields backend after second review
Apply review feedback:
- Extract makeStatusPage from the two test files that duplicated it (test/unit/services/statusPageService.test.ts and test/unit/controllers/statusPageThemeFlag.test.ts) into test/helpers/makeStatusPage.ts. Both files now import the shared helper, matching the existing test/helpers/ convention used for repository fakes and provider contracts
- Add a blank line in statusPageController.getStatusPageByUrl between the normalizedMonitors map and the themesEnabled lookup so the response-shaping section breathes a bit
- Drop the obsolete localStorage references from the plan doc that survived from an earlier draft of the design — the public page never persisted a per-visitor mode choice in localStorage, so the test bullet under 2.11 and the risk row both pointed at functionality that does not exist
2026-04-27 19:33:03 -04:00
gorkem-bwl a5af4e48df Merge remote-tracking branch 'origin/develop' into feat/status-page-themes-backend 2026-04-27 19:29:44 -04:00
gorkem-bwl d80d939bd8 test(status-page): cover theme-flag helpers and document remaining caveats
Address review follow-ups on PR #3568:

- Extract the controller's withoutThemeFields and applyDefaultTheme helpers from a private class field into a standalone module (controllers/statusPageThemeFlag.ts) so they can be tested without a controller harness; the controller is now a one-line consumer
- Add 9 unit tests covering both helpers (test/unit/controllers/statusPageThemeFlag.test.ts): no-mutation guarantees, partial inputs, all-fields-preserved verbatim, override-with-defaults semantics, and "page has no theme set yet" — the flag-off path is now exercised in both directions
- Expand the comment over withoutThemeFields to spell out why the strip is silent rather than a 400: this is an ops kill switch, not API semantics; clients shouldn't need to know whether themes are disabled today

Two caveats called out in review that this commit does NOT change:
- Mongoose `default:` directives only inject during hydration, not on partial updates. Legacy documents updated with `findOneAndUpdate` still won't have `theme` / `themeMode` written to Mongo. They render as defaults on read because the schema injects them — functionally equivalent, but the DB will hold a mix of present and absent fields indefinitely. Acceptable per the original commit intent.
- docs/plans/status-page-themes.md (304 lines) covers both backend and frontend work for the themes feature. It lives in this PR as the design artefact that drove both branches; moving it for purity would break the "where did this come from?" trail. Leaving it in.
2026-04-27 19:26:16 -04:00
gorkem-bwl 5874efff3c refactor(status-page): apply review feedback on theme-fields backend
- StatusPage Mongoose model: import DEFAULT_STATUS_PAGE_THEME / DEFAULT_STATUS_PAGE_THEME_MODE from types/statusPage so the four sources of the default literal stay locked together
- openapi.json: add explicit "default" alongside the enum on StatusPageTheme and StatusPageThemeMode component schemas; documentation already mentioned the defaults but the JSON didn't carry them
- statusPageController: add JSDoc-style comments above withoutThemeFields and applyDefaultTheme spelling out the asymmetric strip-on-write / force-on-read semantics so the next reviewer doesn't have to re-derive the design
2026-04-27 19:02:44 -04:00
gorkem-bwl ab9e722caa refactor(status-page): consolidate font stacks and pill recipes
Second /simplify pass picked up:
- pillHardware in refined and modern hardcoded blue hex codes (#60a5fa, #1d4ed8, #2563eb) while bold and editorial already used the green token system. Switch refined and modern to tokens.up / tokens.upSoft so all four themes are consistent and the public status page no longer leaks blue
- pill and pillHardware in refined and modern duplicated the shared 6 typography fields (fontSize, textTransform, letterSpacing, padding, borderRadius, fontWeight). Extract a pillBase constant per theme and spread, leaving only the colour deltas on each
- The 4 themes each defined their own font-stack constants. Consolidate them in themes/shared/fontStacks.ts (SANS_STACK, BOLD_SANS_STACK, SERIF_STACK, EDITORIAL_SECONDARY_SANS_STACK, MONO_STACK) and import. Drops 6 duplicated literal stacks
- modern dark-mode card hover used the light-mode shadow as a fallback. Add darkShadowHover and pick it up via cardHoverShadow when isDark
- refined and editorial styles factories silence their unused isDark parameter with `void isDark` instead of an underscore prefix; bold and modern still use it actively
2026-04-27 18:52:53 -04:00
gorkem-bwl 4f8f2f1422 refactor(status-page): tighten the bold/modern/editorial conversion
Apply review feedback:
- Editorial chartSwitch: drop the per-button isFirst flag and put the divider on the parent via "& > button + button { borderLeft }"; chartSwitchButton(active) now matches bold/modern's signature
- Drop the empty company: {} entries in bold/modern and the wrapper span around the company name; the parent brand row already styles it
- Editorial styles factory: keep the (tokens, isDark) signature for cross-theme uniformity but acknowledge the unused isDark with a void-statement instead of an underscore prefix
2026-04-27 18:45:45 -04:00
gorkem-bwl c6c50063d8 refactor(status-page): convert bold, modern and editorial themes to MUI sx
Finishes the migration started for refined. Each theme now consumes the same pattern:

- A typed *Styles interface that names every entry the page consumes (no `as Function` casts at the call site)
- A *Styles factory that takes (tokens, isDark) and returns sx recipes derived from existing tokens.ts plus the shared toneColor/toneSoft helpers in shared/overallStatus
- A useMemo around the factory call so MUI's sx processor sees referential equality across renders that don't change tokens
- modern.css's keyframes (pulse + staggered fade-in + reduced-motion guard) ported via @mui/system keyframes inside the modern styles factory
- bold.css's hero glow + conic logo + pseudo-elements ported as inline sx via "&::before" / "& > *" selectors
- editorial.css's serif typography + hairline dividers + flat rectangular badges ported as plain sx with the serif/sans family stacks named at module scope

Drop the four .css files (~1789 lines) along with the className= attributes and the import "./*.css" lines in each StatusPage component.

The shared themed components (ThemedHeatmap, ThemedHistogram, ThemedInfrastructure) lose their legacy classPrefix branch entirely now that no theme uses it. The dual-API gate is gone; there is one path.

Verified: tsc --noEmit clean, prettier clean.

Note: theme-overrides.css remains for the legacy non-themed status page components (StatusBar, MonitorsList, HeaderStatusPageControls). That's separate scope from the four-theme work the reviewer flagged; can be migrated in a follow-up.
2026-04-27 18:39:42 -04:00
gorkem-bwl b95d8886b9 refactor(status-page): tighten the refined-theme conversion
Apply review feedback:
- Type the styles factory's return as a named RefinedStyles interface so the consumer no longer needs `as Function` / `as any` casts on factory entries
- Lift toneColor / toneSoft to shared/overallStatus alongside the existing OverallTone type — the next three themes will need the same mapping
- Reuse heatLevel() in the legacy classPrefix branch of ThemedInfrastructure so both API paths share one threshold table
- Memoize the styles map in RefinedStatusPage so MUI's sx processor sees referential equality across renders that don't actually change tokens
- Make the dual-API gate in ThemedHeatmap / ThemedHistogram require ALL relevant sx props together so a partial migration can't silently fall back to the legacy class path
2026-04-27 18:30:04 -04:00
gorkem-bwl 163f5ec1ec refactor(status-page): convert refined theme to MUI sx + theme tokens
The reviewer's feedback on this PR is that the themes ship hardcoded class names against per-theme CSS files instead of following the project's MUI sx + theme.spacing()/palette pattern. This commit handles the refined theme as a proof of concept; the other three follow.

What changed
- New src/Pages/StatusPage/Status/themes/refined/styles.ts: a single function (tokens, isDark) -> sx recipes that mirror every rule in the deleted refined.css. All values are derived from the tokens already declared in tokens.ts so the colour/spacing source of truth doesn't change.
- RefinedStatusPage.tsx: drops the className= attributes and the import "./refined.css" in favour of sx={styles.x} drawn from the recipe map. Hardcoded class strings gone.
- refined.css: deleted (was 420 lines).
- Shared themed components (ThemedHeatmap, ThemedHistogram, ThemedInfrastructure): grew an opt-in sx-based API alongside the existing classPrefix one. The new API is what refined uses; bold / modern / editorial keep working unchanged on the legacy classPrefix path until they are migrated, after which the legacy code path is removed.

Verified
- tsc --noEmit clean
- prettier clean
- Pre-existing vite build error on this branch (flag-icons resolve, unrelated) is untouched

Next
- Convert the bold, modern and editorial themes the same way and remove the legacy classPrefix branch from the shared components.
2026-04-27 18:21:31 -04:00
gorkem-bwl 2f8765cf3e chore(i18n): close translation gaps across all 16 locales
- Seed the 29 keys that were missing in every non-English locale (Pushover/Twilio config, register setup notice, public status-page status-bar messages, "service is down")
- Fill core UI strings (sidebar menu, buttons, table headers, password rules, image upload, auth footer) where they were left as empty values in the original translations
- Bring Spanish to 100% net coverage with a hand pass over remaining empties and same-as-English entries

Coverage net of empty/missing keys:
- 6 locales now at 100% (de, es, ru, th, zh-CN, zh-TW)
- All locales above 94% (worst: ar/fi at 94.8%, was 85.1% / 87.9%)
- Zero missing keys in any locale (was 29 each)

Some keys are intentionally same-as-English (HTTP, gRPC, Pagespeed, Docker etc.). Long-form copy in createMonitor descriptions and a few infrastructure stat labels remain empty in the lower-coverage locales for native review.
2026-04-27 11:21:48 -04:00
gorkem-bwl 7342385729 fix(client): unblock the auth page build
Drop unused HeaderAuthControls/SPACING imports and switch the form-side wrapper from Stack to Box so the polymorphic component prop type-checks.
2026-04-26 02:29:23 -04:00
gorkem-bwl 671911dc1d feat(client): elevate auth pages with a two-column brand layout
- BaseAuthPage now renders a left form column and a right brand panel with eyebrow / tagline / description copy and a chess-board pattern over the brand green gradient
- Move the language selector and theme toggle to the page's top-right inside the form column so they read clearly in light and dark
- Every auth page (login, register, recovery, set new password) inherits the new layout
- Add brandPanel translations across all 16 locales; phrase the tagline as "your servers" instead of "stack" so it translates cleanly
2026-04-26 02:26:29 -04:00
gorkem-bwl 2ec55c6469 fix(client): replace lingering hardcoded colours with theme tokens
- Default status-page colour now uses the brand green instead of a royal-blue hex
- PageSpeed API-key alert pulls from theme.palette.warning + alpha for both modes instead of hand-rolled amber values
- Settings JSON preview block uses action.hover instead of the hand-rolled #1e1e1e/#f5f5f5 pair
- Drop the redundant #E0E0E0 thumb override on SwitchComponent so the theme MuiSwitch override actually wins
2026-04-26 01:59:09 -04:00
gorkem-bwl d678b3a304 fix(client): lighten the upload icon in ImageUpload
Match the rest of the icon system: 20px, 1.5 stroke, currentColor with 0.7 opacity instead of the lucide default heavy 24/2 stroke.
2026-04-26 01:56:28 -04:00
gorkem-bwl bf3bd50624 feat(client): unify card titles to the eyebrow style across uptime details
- StatBox titles now use the eyebrow variant (matches /uptime summary cards)
- BaseChart drops its leading icon block and renders the title via eyebrow so all chart cards share one header style
- Inside the average-response gauge, the qualitative label uses eyebrow with the status colour and the metric uses h1; the gauge track is a neutral disabled-action background so the active arc reads in light and dark
2026-04-26 01:56:22 -04:00
gorkem-bwl a4f69daae7 fix: surface notification test failures cleanly instead of as 500s
Server-side, return 200 with success: false and a friendly message when sendTestNotification reports failure (the underlying call already swallows the error); reserve real 500s for unexpected exceptions.

Client-side, teach usePost to honour the response body's success flag so success:false flips the toast to error without throwing through axios. Also tidy the toast container: drop icons, no wrapping, single-line ellipsis with a sensible max-width that hugs short messages.
2026-04-26 01:56:13 -04:00
gorkem-bwl 127ee5508a fix(client): truncate long notification destinations with a middle ellipsis
The destination column wrapped onto two lines for long webhook URLs. Cap the cell at 320px and use rtl + plaintext bidi so the start and end of the URL stay visible with an ellipsis in between; full address is in the title attribute.
2026-04-26 01:56:05 -04:00
gorkem-bwl d71fbf8c06 fix(client): bump dark-mode selected toggle background so it stands out
The 6% primary tint that read fine in light mode disappeared against dark backgrounds. Use a 22% tint in dark mode (30% on hover) and keep the lighter 6/10% in light mode.
2026-04-26 01:55:58 -04:00
gorkem-bwl aa3e72ec6d fix(client): make confirmation modals dismiss on ESC
Wire the dialog's onClose to onCancel for keyboard escape but ignore backdrop clicks so users can't lose work by clicking outside the modal.
2026-04-26 01:55:49 -04:00
gorkem-bwl 9d7f4929ad fix(client): use native language names in the settings dropdown too
Export the languageNames map and reuse it in the Settings page so EN/DE/TR turn into English/Deutsch/Türkçe alongside the auth-page selector.
2026-04-26 01:55:42 -04:00
gorkem-bwl 319f667028 feat(client): unify section headers on /logs and group titles with their tables
- Apply the eyebrow variant to "Runtime stats" and "Memory & CPU" so /logs sections share the same uppercase header style as Job queue
- Pair each section's heading + explainer with its table in a tighter sub-stack so the big gap only sits between sections, not under the explainer
- Restore the missing useTheme() call inside TableFailedJobs and TableLogs so the monospace token resolves
2026-04-26 01:55:33 -04:00
gorkem-bwl bcab1a0a4d fix(client): swap the sidebar logs icon from Database to ScrollText
ScrollText reads as logs/journal; Database read more like a storage admin tool.
2026-04-26 01:55:25 -04:00
gorkem-bwl 11ea7dcb3b feat(client): add a sidebar-specific accent colour for dark mode
The sidebar selected-icon colour was sharing primary.main, which read too dark in dark mode. Introduce palette.sidebar.accent (brand green in light mode, a lighter green in dark mode) and route NavItem through it so primary stays brand-green for buttons and the rest of the UI.
2026-04-26 01:55:17 -04:00
gorkem-bwl 1bff81c6bb fix(client): tighten the toast appearance
- Drop the per-type icon
- Lower min-height to 40px and tighten padding
- Thin both the active progress bar and its track to 2px and pin them to the same baseline so they sit on top of each other
2026-04-26 01:32:05 -04:00
gorkem-bwl 2016a208f2 fix(client): keep Chrome autofill background within the rounded input
The autofill inset shadow was bleeding past the rounded corners. Clip it via overflow: hidden on the outlined input root and bump the override rules to !important so they beat Chrome's user-agent styles.
2026-04-26 01:32:00 -04:00
gorkem-bwl dfc1b65e4b fix(client): restyle the register page setup notice
Drop the default MUI info-blue alert in favour of a neutral panel: theme-driven action.hover background, divider border, secondary text colour and no icon. Reads as a quiet aside instead of a status message.
2026-04-26 01:31:54 -04:00
gorkem-bwl f7629eb1be refactor(client): show native language names instead of country flags
Replace the flag + 2-letter code in the language selector with each language's native name (English, Deutsch, 日本語, ...) and drop the unused flag-icons dependency.
2026-04-26 01:31:47 -04:00
gorkem-bwl 72fc28c1fa fix(client): give auth pages a stable form width
The login/register form used percentage widths that collapsed to ~15% on wide screens, wrapping the "Forgot password" / "Reset password" links onto two lines. Switch to a fixed 400px max-width that just shrinks below it on small screens.
2026-04-26 01:31:41 -04:00
gorkem-bwl da70d07051 chore(client): document MUI default fallbacks in getResponseColor
Annotate the hex literals used when callers omit theme colours so the intent (defensive MUI default match) is obvious instead of looking like arbitrary values.
2026-04-26 01:22:06 -04:00
gorkem-bwl c6db7e6479 refactor(client): centralise monospace font through the theme
Add a fontFamilyMonospace token to theme.typography (ui-monospace stack with sensible fallbacks) and route the four ad-hoc fontFamily="monospace" call sites through it so the project has one source of truth.
2026-04-26 01:22:01 -04:00
gorkem-bwl 82ad40ac82 fix(client): replace hardcoded blue accents in tooltip and toast
- Tooltip backgrounds now pull from the theme's grey palette instead of a hand-rolled blue gradient (visible bug in dark mode)
- Toast progress bars use theme.palette.primary.main so they match the rest of the brand
2026-04-26 01:21:54 -04:00
gorkem-bwl 4fd9b2ecf5 feat(client): add eyebrow typography variant and lighter page titles
- Introduce a reusable eyebrow Typography variant in the theme (13px, 500 weight, uppercase, 0.08em tracking) for section headings
- Apply it to ConfigBox titles in /settings and to "Job queue" / "Failed jobs" in /logs
- Drop the page header weight from 600 to 400 with tighter tracking so titles read lighter and more refined
2026-04-26 01:21:47 -04:00
gorkem-bwl 2dccf73050 fix(client): green-tone the empty state illustration
The foreground card was painted in blue (#EEF4FE/#7DA8E8 etc.); recoloured to the brand green family so the illustration matches the rest of the UI.
2026-04-26 01:21:11 -04:00
gorkem-bwl d6532c60a6 fix(client): brand primary colour is the brand green, not blue
Renames the primary palette token from blueBlueWave to brandGreen and points it at #13715B in both light and dark themes, so primary buttons, sidebar selection, slider rings, switch tracks etc. follow the brand instead of the old blue.
2026-04-26 01:21:04 -04:00
gorkem-bwl 99be8651aa feat(client): unify brand mark — green king across sidebar, page header and favicon
- Replace the blue chess-piece SVG with a green king silhouette adapted from Cburnett's chess set (Wikimedia Commons, CC BY-SA 3.0); applies to the page-header logo and the browser favicon
- Drop the placeholder green "C" square in the sidebar in favour of the same king SVG
- Add a NOTICE file documenting the asset attribution and license
2026-04-26 01:07:16 -04:00
gorkem-bwl 8ca53bd765 fix(client): smaller, lighter labels on uptime status cards
Up/down/paused/initializing labels now use the same uppercase 11px treatment as the table headers, with looser tracking, instead of the heavier h2 variant.
2026-04-26 01:07:10 -04:00
gorkem-bwl 26e49f6161 fix(client): drop card chrome around the settings save button
The sticky save bar no longer renders a paper background, top border or full-width margin extension — it just sticks to the bottom on its own.
2026-04-26 00:42:16 -04:00
gorkem-bwl cca027b5eb fix(client): subtle tinted selection on toggle button group
Selected segment uses a 6% primary alpha rather than the previous green tint, and the per-button border override is gone so adjacent segments share one clean divider line.
2026-04-26 00:42:11 -04:00
gorkem-bwl 51f9c09132 feat(client): unify switch, radio and slider styling via theme overrides
- Switch: 36x20 contained pill with 6px right padding so labels keep their distance even inside Stacks
- Radio: theme-level override, 20px ring with a fixed-size inner dot — checked state no longer animates a scale change that pushed labels around
- Slider: white thumb with primary-colour ring, 4px track, soft hover/active glow
- Drop the custom RadioInput icon overrides that bypassed the theme and caused the size jiggle
2026-04-26 00:32:18 -04:00
gorkem-bwl 897204ead3 refactor(client): extract useClientPagination hook and clean up Select prop
- Replace duplicated page/rowsPerPage state in Team, Notifications and Status Pages tables with a shared useClientPagination hook
- Drop unused placeholderColor prop from Select; placeholder always uses secondary text
- Restore LAYOUT.MD constant for the account menu item gap
2026-04-26 00:22:14 -04:00
gorkem-bwl 25735df0c6 fix(client): use theme divider for table header line so it shows in dark mode 2026-04-26 00:18:45 -04:00
gorkem-bwl e3b6183e00 fix(client): soften empty state typography and copy
Drop the heavy 600-weight title in favour of regular-weight secondary text, and reword "Nothing here" to "Nothing to show yet".
2026-04-26 00:18:41 -04:00
gorkem-bwl b2741ad567 fix(client): increase internal padding on status summary cards 2026-04-26 00:18:37 -04:00
gorkem-bwl 7905e97a84 fix(client): match account menu icon style with sidebar nav icons 2026-04-26 00:13:35 -04:00
gorkem-bwl b7d719132d fix(client): use secondary text color for empty select placeholders
Disabled-text was too pale for filter dropdowns like Type/Status/State, where the placeholder doubles as the field label.
2026-04-26 00:13:32 -04:00
gorkem-bwl 210e03cea0 fix(client): refine table header divider and typography
- replace heavier per-cell header borders with one lighter row divider
- shrink header text to 11px with looser tracking for a more refined feel
- tighten failed-jobs labels: "Fail count" -> "Count", "Last failed at" -> "Last failed"
2026-04-26 00:13:27 -04:00
gorkem-bwl 995fc59299 feat(client): add pagination to team, notifications and status page tables 2026-04-26 00:13:23 -04:00
gorkem-bwl cbd8236cb4 chore(i18n): seed jobQueueExplainer and failedJobsExplainer for non-English locales 2026-04-26 00:13:19 -04:00
gorkem-bwl 095086cdfd chore(i18n): seed translations for new UI surfaces
Across en + 15 locales:
- pages.<X>.fallback.title / .description for every page that has an
  EmptyState (uptime, infrastructure, pageSpeed, notifications,
  maintenance, statusPages, incidents, logs, logs.queueFallback,
  checks, account.team).
- pages.<X>.header.title / .description for every page that uses the
  new PageHeader (same list, plus settings).
- pages.logs.diagnostics.sections.runtimeStats / .memoryCpu titles
  and descriptions for the diagnostics section explainers.
- components.pageHeader.links.support / docs / changelog tooltip
  labels.

en.json also gains pages.logs.jobQueueExplainer and
.failedJobsExplainer (English only — non-English locales fall back
to English until a translator sweep).
2026-04-25 23:28:51 -04:00
gorkem-bwl 59846a041f fix(client): dark-mode text-field polish
- MuiOutlinedInput hover override: was inheriting MUI's default
  white outline in dark mode (too bright). Now uses an alpha-23%
  white in dark and text.primary in light.
- TextInput: -webkit-autofill now repaints the input bg with
  background.paper (instead of Chrome's harsh blue/yellow autofill
  highlight), text in text.primary, with the standard 5000s-transition
  trick to suppress the brief flash. Works in both modes.
2026-04-25 23:28:32 -04:00
gorkem-bwl 7d91d9e28b fix(client): job queue table layout + theme-aware running-row tint
TableJobs:
- Cut from 11 to 7 columns, dropping active / runCount / failCount /
  lastFinishedAt (covered by Failed jobs table or by lastRun + lastRunTook).
- All cells get whiteSpace:nowrap + textOverflow:ellipsis + maxWidth so
  long timestamps and IDs no longer wrap and inflate row height; full
  value visible via title tooltip.
- Running-row tint: was theme.palette.success.light (too saturated in
  light, drowns white text in dark). Now #ECF7F2 in light, an 18%-alpha
  green in dark — readable in both modes.

TabQueue:
- One-line explainer above the Job queue heading, with the words
  "Highlighted rows" wrapped in the same green tint so the meaning
  is immediately associated.
- One-line explainer above Failed jobs heading too.
2026-04-25 23:27:50 -04:00
gorkem-bwl 752f59b09b feat(client): diagnostics page polish
- Stats and StatGauges use CSS grid (5 + 4 columns) so cards in each
  row are equal width; widths overridden against the legacy 25%-flex
  GradientBox so they fill their grid cell.
- DetailGauge gains a maxWidth prop (default 225) so consumers in
  wide grids can opt out of the cap.
- Section explainers above each row: "Runtime stats" + description,
  "Memory & CPU" + description (i18n driven, propagated to all 16
  locales via pages.logs.diagnostics.sections).
- Both grids render immediately with placeholder "—" values, so the
  initial paint shows the layout and values fill in as data loads
  (eliminates the layout shake when switching to the tab).
2026-04-25 23:27:35 -04:00
gorkem-bwl 262c4eee93 feat(client): PageHeader on every page; remove sidebar bottom menu
- New PageHeader component (variant D — grouped icon-pill toolbar):
  big title + muted description on the left, Support / Docs /
  Changelog as a 3-icon segmented pill on the right with tooltips.
  External links open in a new tab.
- BasePage / BasePageWithStates / MonitorBasePageWithStates accept
  a headerKey prop; when set, render PageHeader pulling
  pages.<headerKey>.header.title and .description from i18n.
  When unset, falls back to the existing breadcrumb (no behavior
  change for not-yet-migrated pages).
- All top-level pages (uptime, infrastructure, pageSpeed,
  notifications, maintenance, statusPages, incidents, logs, checks,
  account, settings) now pass their headerKey.
- Sidebar: removed the bottom menu (Support / Discussions / Docs /
  Changelog) since those links now live in the page header.
2026-04-25 23:27:22 -04:00
gorkem-bwl 031a6fdf3c feat(client): unified EmptyState across all pages and table empties
- New EmptyState + EmptyStateIllustration components: stacked-cards SVG
  with grid background, theme-aware light/dark palette.
- Variants: default (centered with title + description), compact
  (horizontal, in-section), fullscreen (vertically centers in viewport).
- Wired into Checks, Incidents, Logs (Logs+Queue tabs), Notifications,
  Maintenance, Status pages, and Team tab — each with i18n title +
  description and a fullscreen layout when truly empty.
- Table.EmptyView now wraps the EmptyState in a divider-bordered card
  so short messages no longer look orphaned.
- Incidents Option-A short-circuit: when summary.total === 0, replace
  the whole page chrome with EmptyState; otherwise keep filters + cards.
- Fallback.tsx (BaseFallback / EmptyFallback / EmptyMonitorFallback /
  ErrorFallback) refactored to delegate to EmptyState.
2026-04-25 23:26:34 -04:00
gorkem-bwl ff208710d7 feat(client): unified EmptyState component for empty/error placeholders
Replaces the cards-with-halo SkeletonCard fallback (which produced a
washed-out, hard-to-read placeholder) with a single canonical empty
state used everywhere in the app.

What's new:

- EmptyStateIllustration.tsx — custom inline SVG: two stacked monitor
  cards (front blue, back gray, both with hairline strokes and a soft
  fade toward the bottom), set against a faint grid of solid + dashed
  background lines. Uses only lightened palette tokens (#7DA8E8 blue,
  #B6C2CF gray, #CBD5E1 grid).
- EmptyState.tsx — the layout: illustration + title + description +
  optional CTA + optional secondary link + optional inline alert slot.
  Supports a compact horizontal variant for in-panel use.

Migrations:

- Fallback.tsx: BaseFallback / EmptyFallback / EmptyMonitorFallback /
  ErrorFallback now delegate to EmptyState. Public APIs unchanged so
  every existing consumer (BasePageWithStates, MonitorBasePageWithStates,
  Pages/Uptime, Pages/Notifications, Pages/Infrastructure, etc.) keeps
  working without edits.
- BasePage.tsx: PageSpeedKeyPriorityFallback rebuilt on top of EmptyState
  with the warning slot. Fixes the previous reports of "white cloudy
  area" + half-faded text — message and link now render in consistent
  dark text with green Settings link.

No prop changes for any page-level consumer. The illustration is a
single SVG with no external assets.
2026-04-25 21:19:52 -04:00
gorkem-bwl 50fb4f47fd fix(client): hide Open site action when URL is not browser-openable
The Open site action in monitor row menus called `window.open(monitor.url)`
unconditionally, which produced unresolvable navigation for monitors
targeting internal services:
- Hardware monitors always point at a Capture agent (e.g.
  http://capture:59232/api/v1/metrics) that the user's browser can't
  reach.
- Port, ping, docker, game, grpc, and websocket monitors store hostnames
  or non-HTTP endpoints, which browsers can't load anyway.

This change hides the action where it can't possibly work:
- Removed entirely from the Infrastructure (hardware) monitors table.
- In the Uptime monitors table, only shown for http and pagespeed
  monitor types whose URL starts with http:// or https://.

A more comprehensive fix that adds a separate user-facing siteUrl
field on the Monitor schema is left for a follow-up.

Closes #3434
2026-04-23 23:38:07 -04:00
gorkem-bwl 22f1d035b7 docs(openapi): document all query params on /monitors/team/with-checks
The OpenAPI spec only listed `limit` for GET /monitors/team/with-checks,
but the route's Zod schema (getMonitorsWithChecksQueryValidation) also
accepts page, rowsPerPage, filter, field, order, type, and explain.
Users hitting the endpoint via Swagger UI would either get rejected
with "page is not allowed" (when guessing param names) or miss
pagination entirely.

Adds the missing parameters with constraints mirrored from the
validation schema. Also bumps `limit` max from 50 to 100 to match
the schema (was 100 in code, 50 in spec).

Closes #3354
2026-04-23 23:35:52 -04:00
gorkem-bwl f654310c4d fix(client): source app version from package.json
The client version shown on the Settings page was hardcoded as a
literal in vite.config.ts, while client/package.json sat at the
placeholder "0.0.0". Bumping the displayed version required editing
two unrelated places, and stale Docker client images would keep
showing the old number after upgrades.

This change makes client/package.json the single source of truth
and reads it at build time. Bumps client/package.json from 0.0.0
to 3.6.1 to preserve current behaviour.

Closes #3271
2026-04-23 23:33:41 -04:00
gorkem-bwl d44f7497a5 fix(server): suppress mongoose reserved-key warning on Check.errors
Mongoose 8 logs a reserved-key warning at boot because the Check schema
defines an `errors` field, which collides with Mongoose's internal
document `errors` accessor. The field is intentional and safe to keep,
so opt out of the warning via `suppressReservedKeysWarning: true`.

Closes #1539
2026-04-23 23:32:33 -04:00
gorkem-bwl dbccce445b fix(client): allow configurable Vite allowed hosts
Vite >=4.3 rejects requests with a Host header not in the allowlist,
which broke status-page submissions and dev-server access for users
serving Checkmate behind a reverse proxy after upgrading.

Adds VITE_ALLOWED_HOSTS env var (comma-separated list). When unset,
falls back to allowing all hosts so existing self-hosted deployments
keep working without changes.

Closes #3397
Closes #2951
2026-04-23 23:31:05 -04:00
gorkem-bwl 944ee74a1d feat(status-page): four selectable themes for the public status page
Adds four fully-designed visual themes for the public status page
(refined | modern | bold | editorial) with a light/dark mode selector,
admin preview in a mock browser frame, and a shared theme provider
that keeps the component tree unified while letting each theme own
its visual identity.

## Selectable themes
- Refined — clean, flat cards, soft shadows, colored status dot.
- Modern — flat surfaces with a pulsing status dot and staggered
  fade-in cards.
- Bold — conic-gradient logo, 34px hero title with a check disc,
  subtle dual-radial glow on dark mode, accent-green hover border.
- Editorial — serif headings, narrow newspaper column, 'Service
  Report' eyebrow + title, flat rectangular badges and dateline.

## Architecture
- Single `StatusPageThemeProvider` hosts CSS custom-property tokens
  per theme and resolves light/dark based on admin-forced mode,
  falling back to `prefers-color-scheme` with a matchMedia listener.
- Each theme owns only its `*StatusPage.tsx` + scoped CSS file.
  The heatmap, histogram, and infrastructure renderers are shared
  across all four themes (parameterized by a `classPrefix`) to avoid
  the 12-file duplication the initial draft had.
- Renderer lookup table in `Status/index.tsx` replaces a 4-way
  ternary chain; unknown themes fall through to the legacy renderer.
- `resolveOverallStatus`, `statusBadgeKey`, `monoFirstChar`, and
  `monitorBadgeTone` are extracted to `themes/shared/overallStatus.tsx`.

## Admin UX
- `ThemePicker` uses the project's `RadioWithDescription` and
  `Select` components — one radio card per theme plus an Auto/
  Light-only/Dark-only mode dropdown.
- `BrowserFrame` wraps the preview in the admin panel with a mock
  chrome (traffic lights + URL bar) that adopts the status page's
  theme tokens. Edge-to-edge fill with no gray bleed.
- Public route renders the theme directly on the viewport with the
  document body painted to the theme background, reverted on unmount.

## Performance & polish
- Histogram's derived stats (padded array, max, avg, peak) are
  memoized on `checks`; `max` is reused for `peak` instead of
  computing twice.
- Editorial's dateline is wrapped in `useMemo` so the 10s poll
  doesn't rerender "April 23, 2026" as a changing string.
- Provider's `setSystemMode` reconciliation uses the updater form
  to avoid an extra render when the value is unchanged.
- `monoFirstChar` no longer uses a non-null assertion.

## Form plumbing
- `useStatusPageForm` defaults include `theme` + `themeMode`.
- `Validation/statusPage.ts` accepts both as optional zod enums.
- `Pages/StatusPage/Create/index.tsx` appends both to FormData on
  create and update.

## CLAUDE.md
- Dev port note: local client runs on 10001 (5173 is used by a
  different local project); server `CLIENT_HOST` is set to match.
2026-04-23 22:51:40 -04:00
gorkem-bwl ad964446de feat(status-page): add theme and themeMode fields (backend)
## Changes
- Add `theme` (refined | modern | bold | editorial, default "refined") and
  `themeMode` (auto | light | dark, default "auto") fields to the StatusPage
  Mongoose model and the shared `StatusPage` type.
- Extend the create/update Zod validator to accept both fields optionally.
- Map both fields in the repository's `toEntity` so GET responses include them.
- Document both fields in the create and update endpoints in `openapi.json`.
- Add `STATUS_PAGE_THEMES_ENABLED` env var (default `true`) wired through
  `SettingsService` for ops-level rollback. When disabled, the controller
  strips theme fields on write and forces defaults on read.

## Notes
- No migration needed; Mongoose applies defaults for legacy documents.
- Controller short-circuits to zero-cost when the feature flag is on.
- `DEFAULT_STATUS_PAGE_THEME` / `DEFAULT_STATUS_PAGE_THEME_MODE` constants
  exported so the frontend PR can consume the same values.
2026-04-23 22:45:50 -04:00
gorkem-bwl 39011e2e33 style: apply prettier formatting 2026-04-20 13:53:50 -04:00
gorkem-bwl 4998fe4c94 fix: hide register tip on login and redirect to setup when no super admin (#3556)
## Changes
- Removed the "Register here" link from the login page — it misled users into thinking public registration was open.
- Added redirect from /login to /register when no super admin exists (initial setup).
- Added an info alert on the register page clarifying the page is only for initial setup; additional users are invited from team settings. Hidden for the invite-token flow.
- Extracted shared useSuperAdminRedirect hook to dedupe identical fetch/redirect logic across Login and Register.

## Benefits
- Clearer UX: login page no longer suggests self-registration is available post-setup.
- Correct routing on fresh installs: users land on the registration page instead of a login page they can't use.
2026-04-20 13:50:36 -04:00
gorkem-bwl 96f9360280 style: format migration script with prettier 2026-04-03 23:43:34 -04:00
gorkem-bwl eb4a92c84f fix: restructure and translate all i18n locale files
All 15 non-English locale files had a structural mismatch with en.json:
- en.json used nested keys (common.buttons.cancel)
- Other locales used flat keys (cancel, DeleteAccountButton)
- Result: 0.3% effective translation coverage at runtime

## Changes

Migration script (client/scripts/migrate-locales.ts):
- Restructures all locale files to match en.json's nested key structure
- Recovers existing translations via safe key-matching strategies
- Backs up originals to locales/backup/

Translation of all 15 languages:
- ar (94.6%), cs (91.6%), de (89.4%), es (92.6%), fi (94.2%)
- fr (86.7%), ja (93.3%), pt-BR (91.0%), ru (93.0%), th (93.4%)
- tr (91.9%), uk (94.3%), vi (92.5%), zh-CN (94.0%), zh-TW (94.2%)

Keys intentionally left in English are technical terms (HTTP, CPU,
Docker, gRPC, etc.), placeholder examples, and brand names.

en.json was NOT modified.
2026-04-03 23:35:14 -04:00
gorkem-bwl c80720c8c9 fix: align server test suite with current source implementations
## Changes
- teamsProvider.test.ts: fix got mock wiring (use top-level mockPost
  with dynamic import so mock intercepts correctly), fix getTestMessage
  assertion, fix incident URL path
- superSimpleQueueHelper.test.ts: change default import to named import,
  update constructor from object to 16 positional params, rename
  getMonitorJob -> getHeartbeatJob, add all missing dependencies
- monitorService.test.ts: remove stale constructor params (db,
  stringService, papaparse, errorService), add missing params
  (geoChecksRepository, incidentsRepository), fix method names
  (findLatestChecksByMonitorIds -> findLatestByMonitorIds,
  findDateRangeChecksByMonitor -> findByDateRangeAndMonitorId),
  update assertions from checks -> recentChecks
- jest.config.ts: consolidate @/utils path mapping to resolve .ts files
- Extract shared createMockLogger to test/helpers/

Closes #3457
2026-04-03 21:56:14 -04:00
gorkem-bwl 9466090332 fix: rename "breached" to "threshold exceeded" in user-facing strings
Only changes user-facing text — no enum, type, or backend status changes.

## Changes
- locales/en.json: "breached" → "threshold exceeded"
- notificationMessageBuilder.ts: notification title/summary/details
- email.ts: email subject line
2026-03-11 16:30:30 -04:00
gorkem-bwl 943ef92053 fix: rename "breached" status to "exceeded" for clarity
The word "breached" in infrastructure monitoring was confusing users
as it implied a security breach. Renamed to "exceeded" which better
describes threshold violations (e.g. "threshold exceeded").

## Changes
- Renamed monitor status value from "breached" to "exceeded" across
  server types, status service, queue helper, notification builder,
  email subject lines, and MongoDB aggregation queries
- Renamed client types, status box/label components, translation key,
  and infrastructure page props to match
- Added DB migration (0005) to update existing monitors with the old
  status value
2026-03-11 01:31:05 -04:00
gorkem-bwl 84cac870d5 fix: set DNS cache TTL to prevent stale lookups
CacheableLookup defaults to maxTtl=Infinity, meaning successful DNS
lookups are cached forever until process restart. This causes monitors
to fail permanently if DNS changes or if a resolver outage causes
ENOTFOUND errors to persist after recovery.

Set maxTtl=300s (5 min) for successful lookups and errorTtl=30s for
failed lookups so the cache recovers automatically.
2026-03-10 19:04:04 -04:00
gorkem-bwl 172467c0a6 fix: address PR review feedback
- Use useIsAdmin and useIsSuperAdmin hooks instead of manual role checks
- Close delete dialog on failure, not just on success
2026-03-06 15:19:01 -05:00
gorkem-bwl 7c953978ed refactor: simplify EditUser imports and canDeleteUser logic
- Merge duplicate react-router-dom imports into one
- Replace useIsAdmin + useIsSuperAdmin + useSelector with single useSelector
- Remove redundant !includes("superadmin") check from canDeleteUser
2026-03-06 14:31:59 -05:00
gorkem-bwl 82998a7795 feat: add ability to remove team members
## Changes
- Add DELETE /api/v1/auth/users/:userId endpoint (admin + superadmin)
- Add deleteUserById service method with role hierarchy enforcement
- Superadmins can remove admins and regular users
- Admins can only remove regular users
- No one can remove superadmins, demo users, or themselves via this endpoint
- Add "Remove user" button with confirmation dialog on edit user page
- Allow admins to view user details and access the edit user page
- Add i18n strings for remove user button and confirmation dialog

## Access control
- superadmin -> can remove admin, user
- admin -> can remove user only
- admin cannot remove superadmin or other admins (enforced on both backend and frontend)
2026-03-06 14:18:27 -05:00
gorkem-bwl a1068f1d7e refactor: move dark background colors to colors object
Addresses review feedback — define gray900 and gray850 in the colors
object and reference them in the dark palette.
2026-03-04 19:56:54 -05:00
gorkem-bwl 8df263fd93 fix: also migrate threshold value of 0 to 100, fix formatting
Addresses review feedback — thresholds set to 0 also caused issues
and should be migrated to 100 (disabled) alongside the value of 5.
2026-03-04 16:44:20 -05:00
gorkem-bwl d2f3335b1a fix: add type annotations to Swagger middleware parameters
Fixes TypeScript build error TS7006 for implicit 'any' types on req, res, next.
2026-03-04 16:32:01 -05:00
gorkem-bwl 75eca743b4 fix: use neutral gray background for dark mode
## Changes
- Replace MUI default blue-tinted dark background with neutral grays
  (#151518 for default, #1c1c21 for paper/cards)
- Remove decorative blue/purple SVG blob overlay from dark mode background

## Benefits
- Dark mode now has a clean, neutral gray appearance instead of a blue tint
2026-03-04 16:30:19 -05:00
gorkem-bwl b2e2b11ef2 fix: support IPv6 addresses in ping monitor
## Changes
- Fixed ping host sanitization regex that stripped everything after
  the first colon, which destroyed IPv6 addresses like 2001:db8::1
- New regex properly handles bracketed IPv6 ([::1]:port), bare IPv6,
  and IPv4/hostname:port formats separately

## Closes
Fixes #3053
2026-03-04 15:41:01 -05:00
gorkem-bwl 93b9abd508 fix: add migration to reset infrastructure thresholds from 5 to 100
## Changes
- Added migration 0004_fixInfrastructureThresholds that finds hardware
  monitors with threshold values of 5 (the old incorrect default) and
  updates them to 100 (effectively disabled)
- Runs automatically on server startup like other migrations

## Closes
Fixes #3327
2026-03-04 15:38:34 -05:00
gorkem-bwl 888b399a4f fix: dynamically set Swagger UI server URL from request
## Changes
- Swagger UI now prepends the current server URL (protocol + host) to
  the servers list, so it works correctly in remote/Docker environments
  instead of always pointing to localhost.

## Closes
Fixes #3339
2026-03-04 15:29:44 -05:00
gorkem-bwl 369d16c7c3 fix: resolve password tooltip theme contrast and translation issues
- Fix tooltip background using non-existent tertiary.background
  property by switching to tertiary.main
- Fix Check component text color inheritance for noHighlightText
  by adding color: inherit to inner Typography
- Add translation wrapper for validation error messages in PasswordPanel
- Add translation wrapper for validation error messages in ProfilePanel
2026-01-24 19:52:06 -05:00