Commit Graph
100 Commits
Author SHA1 Message Date
gorkem-bwl 0b09895098 docs: align dev setup docs with current server config
## Changes
- Replace stale QUEUE_TYPE env var (superSimpleQueue/lessSimpleQueue) with QUEUE_MODE (primary/worker) to match server/src/config/envValidation.ts
- Mark ORIGIN, TOKEN_TTL and LOG_LEVEL as optional with their defaults; note that only CLIENT_HOST, JWT_SECRET and DB_CONNECTION_STRING are strictly required
- Note that CLIENT_HOST must be a full URL (enforced by env validation)
- Remove Redis port 6379 from the port-conflict troubleshooting list; the server has no Redis dependency
- Point CLAUDE.md at CONTRIBUTING.md as the setup source of truth

## Why
A contributor followed the setup docs and hit references to files and env vars that no longer exist after the repo reorg. This brings the contributor docs in line with the actual dev workflow.
2026-07-21 19:44:22 +03:00
gorkem-bwl 242e853bf0 i18n(it): review pass — fix grammar, awkward phrasing, inconsistencies
91 leaves refined after a native-Italian style pass.

## Categories of fixes

- Grammar / gender agreement — e.g. `logs.table.headers.lastSeenAt`
  "Ultima visto il" → "Visto l'ultima volta"; heap gauge subject
  agreement in `logs.diagnostics.gauges.allocatedPercentage`.
- Awkward phrasing / calques — `notFound.subtitle` drops stilted
  "ad esso"; `incidents.fallback.title` "in salute" → "funzionano
  correttamente" (was reading as if for a person, not systems);
  `settings.form.removeMonitors.title` "Reset del sistema" →
  "Reimposta il sistema"; "con successo" → "correttamente" on
  status-page delete confirmations.
- Consistency — paused monitor status unified on "In pausa" across
  `common.labels.paused`, monitor status labels, status-bar keys, and
  the `bulkPause.*_one/other` copies. Button verbs
  "Sospendi"/"Riprendi" kept for brevity; status noun stays "In pausa".
- Mistranslations — `buttons.testNotifications` "Testa" → "Prova";
  `buttons.toggleTheme` "Cambia" → "Alterna"; Twilio "Auth token" now
  translated; Mongoose `readyState` clarified to "Stato di connessione".
- Register — trimmed "Ancora" from several empty-state titles so they
  read like natural Italian empty states.

## Verification

874 leaves in EN and IT, 0 missing / 0 extra, all placeholders and
inline tags preserved, no empty values.
2026-07-13 16:18:24 +03:00
gorkem-bwl 523bf2253c feat(i18n): add Italian translation, document translation workflow
## Changes

- Add `client/src/locales/it.json` — Italian translation of all 874 UI
  keys, structure mirrors `en.json` exactly. Placeholders (`{{value}}`,
  etc.) and inline tag tokens (`<settingsLink>`, `<highlight>`, ...)
  are preserved. Product/brand names, technical abbreviations, and
  placeholder-style examples (e.g. `you@example.com`) are kept in
  English. 116 leaves are intentionally kept verbatim in English
  (brand names, protocol names, sample values, port numbers, regex).
- Register `it: "Italiano"` in `LanguageSelector`'s `languageNames`
  map so the dropdown shows the localised name; the selector already
  picks up any locale present in the i18n resources.
- Fill in the two "How do I..." sections that CONTRIBUTING.md's table
  of contents already links to but did not have bodies:
  - "Improve the documentation?" — short guidance on doc PRs and
    keeping README translations in sync.
  - "Help with translations?" — describes the current per-language
    JSON workflow (source of truth: `en.json`; improve an existing
    language by editing its JSON; add a new one by adding a JSON file
    and registering the display name in `LanguageSelector`). Notes
    that the older PoEditor sync workflow is no longer authoritative.

## Benefits

- Italian speakers can now use Checkmate in Italian.
- Contributors who follow the "Help with translations?" link from
  the CONTRIBUTING TOC land on real, current guidance instead of a
  broken anchor.
- Translation quality can be improved incrementally by anyone
  editing `it.json` directly; no external tooling required.
2026-07-13 16:10:04 +03:00
gorkem-bwl f92dc835b7 fix(status page): apply brand color via a dedicated brand token
The status page appearance form saves a customer-picked brand color
(`statusPage.color`), but `StatusPageThemeProvider` never consumed it —
every rendered surface styled from `tokens.up`, so the picker had no
visible effect on the public page.

Rather than overriding `tokens.up` (the semantic OK/up status color,
which would let a red or orange brand color render the "all
operational" indicator in a red that reads as downtime), this
introduces a separate `brand` / `brandStrong` / `brandSoft` token
triple that is distinct from the up/OK color.

## Changes

- `themes/tokens.ts`: add optional `brand` / `brandStrong` / `brandSoft`
  fields on `StatusPageThemeTokens`. Themes leave them undefined; the
  provider falls back to the theme's `up*` values so nothing regresses
  before individual themes opt in.
- `themes/StatusPageThemeProvider.tsx`: add `brandColor` prop and a
  `resolveBrandTokens` helper. When a valid hex is provided it feeds
  `brand`, `brandStrong = darken(x, 0.2)`, `brandSoft = alpha(x, 0.15)`
  using MUI's shared `alpha`/`darken` (replaces the ad-hoc hex helpers).
  Invalid or empty values fall through cleanly.
- `Status/index.tsx`: pass `brandColor={statusPage.color}` only at the
  public route. The admin preview provider wraps an iframe whose
  document renders itself, so passing the prop there had no effect and
  is dropped.
- `themes/refined/styles.ts`: switch accent surfaces (hero logo, active
  chart-switch button, hardware pill, footer link) from `tokens.up` to
  `tokens.brand`. Uptime bars, status pills, and OK indicators stay on
  `tokens.up`. Other themes keep their current styling until a designer
  decides which surfaces should switch.

## Benefits

- Brand Color picker actually changes the rendered accent surfaces.
- The semantic "OK/up" status color is never repainted by the brand
  color, so operational-state indicators stay green regardless of the
  customer's brand.
- Reuses MUI's `alpha` / `darken` helpers already used across the
  client; no divergent color utilities.
- Small, incremental adoption: themes opt in at their own pace by
  reading `tokens.brand*` where they want the brand accent.
2026-07-13 15:52:12 +03:00
gorkem-bwl 77b817778b address review feedback: rename notice to match new trigger
The notice now triggers on interface names (loopback / container-bridge
only), not on zero traffic. Update the variable, i18n key, and English
copy to match:

- showNoTrafficNotice -> showLoopbackOnlyNotice
- pages.infrastructure.charts.labels.netNoTraffic ->
  pages.infrastructure.charts.labels.loopbackOnlyNotice
- English string rewritten to describe the loopback-only condition
  rather than "zero traffic on every interface"

Other locales still hold the old string under the old key and will fall
back to English until the translation pipeline picks up the new key.
Tracked separately.
2026-07-11 04:29:22 +03:00
gorkem-bwl 9459edce00 scope 10mb body limit to /monitors/import/json only
Address review feedback: keep the global express.json() at the default
100kb and mount a route-scoped 10mb parser in front of it for
/api/v1/monitors/import/json. Express matches middleware in registration
order, so the import route uses the larger parser and every other
endpoint keeps the tight default. No change in DoS surface for normal
traffic.
2026-07-11 04:22:42 +03:00
gorkem-bwl 2810cd3562 fix(infrastructure): trigger network "no traffic" notice on interface name only
The notice at the top of the network charts was firing whenever the aggregated
per-second delta was zero across all interfaces. That is a false positive when
Capture is running on a real host but the polling interval is >= 1 minute and
the aggregation bucket is also 1 minute — first == last in the bucket, delta
is zero, but the interface has plenty of real traffic in its cumulative
counters.

Base the notice on interface names instead: only show it when the ONLY
interfaces Capture reports are loopback / container-bridge names (lo, lo0,
docker0). Real NICs (enp0s6, eth0, wlan0, tunN, vethN, brN, etc.) keep the
notice hidden even when the aggregation currently reports zero throughput.

The underlying zero-throughput bug (single-sample buckets producing zero
deltas) is tracked separately.
2026-07-10 03:16:42 +03:00
gorkem-bwl f4177baed5 fix(server): raise express.json body limit to 10mb
Express defaults to a 100kb JSON body, which is too small for realistic
imports through POST /api/v1/monitors/import/json (backups with many
monitors and their config easily exceed 100kb, returning
"request entity too large").

Raise the parser cap to 10mb. That covers real-world import payloads
while keeping the DoS surface bounded — a larger, streaming file-upload
route for imports remains desirable as a follow-up.
2026-07-10 00:06:31 +03:00
gorkem-bwl 5feb666bdb fix(status-page): inject sanitized customCSS on the public page
The customCSS field on status pages was persisted and validated
end-to-end but never rendered on the public page, so operator-supplied
styles had no effect.

Inject the string as a <style> tag on the public route (which the
admin preview iframe also renders), reusing the existing
cssReferencesExternalResource check so external-resource CSS
(@import, url(http…), //…) is dropped defensively on the client.

The admin preview iframe already points at the public URL, so this
one insertion covers both the live page and the in-app preview.
2026-07-09 21:55:25 +03:00
gorkem-bwl cbd1153189 docs(readme): polish German translation — informal 'du', tighter phrasing, fewer AI tells 2026-05-29 12:11:56 -04:00
gorkem-bwl 88042e7c50 docs(readme): add machine-translation disclaimer to 7 less-confident translations
For ar, ca, cs, fi, th, uk, vi the AI-generated translation quality
is hardest for me to vouch for. Added a clear "machine-translated
draft — native-speaker PRs welcome" notice at the top of each so
the community can fix them. The note appears below the language
selector for visibility.
2026-05-29 12:09:40 -04:00
gorkem-bwl ba44985763 docs(readme): fix TOC anchors and refresh Spanish translation
## Anchor fix
GitHub auto-generates anchor IDs from the rendered heading text, so
the English TOC links (#users-guide, #installation, etc.) in the
translated READMEs were broken — the matching anchor IDs only existed
in the English README. Added hidden <a id="..."></a> markers before
each section heading in all 17 READMEs (root + 16 translations) so
the TOC works in every language.

## Spanish refresh
The existing Spanish README was a human translation of an older
revision of the project README — it carried its own Traducciones and
Patrocinadores sections, an outdated demo URL, and a different
feature list. Rewrote it from the current English README structure
while keeping a fluent Spanish tone.
2026-05-29 11:49:24 -04:00
gorkem-bwl b164fa63bf docs(readme): add README translations for all supported locales
Mirrors the Graphify pattern: a centered flag + native-language link
bar at the top of every README points to the rest. All translated
files live in docs/translations/ so the repo root stays clean.

## Coverage
- Added 15 new translations: ar, ca, cs, de, fi, fr, ja, pt-BR, ru,
  th, tr, uk, vi, zh-CN, zh-TW
- Moved README.es.md from the repo root to docs/translations/
- Updated the root README to include the language selector

The 17 languages here match the locales the Checkmate UI already
ships translations for, so README parity is consistent with what a
user sees inside the app.

## Quality note
Translations were drafted as a starting point and may need
native-speaker review for tone and idiom — especially Arabic, Thai,
the two Chinese variants, Japanese, and Vietnamese. Technical terms
(Docker, MongoDB, Redis, Webhook, etc.), URLs, contributor names,
and badge URLs are intentionally left as-is.
2026-05-29 11:09:05 -04:00
gorkem-bwl bc7b3a5ffb fix(i18n): close translation gaps across 16 locales
## Changes
- Add 59 missing keys to every non-en locale (DNS monitor strings,
  status-page themes, monitor status labels, network error messages,
  email sender display name)
- Catalan: add 12 bulk-monitor selection keys that were introduced after
  ca.json was first added
- Fill 188 empty string values across ar, cs, fi, fr, ja, pt-BR, tr,
  uk and vi
- Remove 10 orphan keys from es.json that were not referenced anywhere
  in the client code

## Benefits
- All 16 locales now report 100% structural coverage against en.json
- Status page theme picker, DNS monitor type, and bulk monitor actions
  are fully translated
- No more empty strings rendered as blank labels in production UI
- es.json no longer carries dead keys diverging from the reference

## Notes
- Placeholders ({{count}}, {{value}}, {{name}}) verified intact in
  every locale
- Brand terms (DNS, A, AAAA, CNAME, MX, NS, TXT, 8.8.8.8) intentionally
  kept untranslated
- Build, prettier format-check and JSON validity all pass
2026-05-14 07:36:37 -04:00
gorkem-bwl c45bcfaa2f revert(maintenance): keep one-time TTL cleanup, narrow PR to validator-only
Per review feedback: auto-deleting completed one-time maintenance windows is
intentional cleanup, not a bug. The actual bug is past-dated end values being
accepted at creation time, which the validator refines now reject up front.

Reverts:
- Restore expiry field + TTL index on MaintenanceWindow schema
- Restore repository's auto-set of expiry = end for repeat=0
- Drop migration 0007 (no longer needed)
- Restore expiry properties in openapi.json
- Restore expiry in create/edit validators (still optional)

Kept from this PR:
- .strict() on create/edit body schemas
- end > start refine on create/edit
- end > now refine on create when repeat=0 (the real fix)
- DurationUnits const tuple + reuse (rules 5/8/10)
- Client no longer sends redundant expiry (server still derives it)
2026-05-07 13:38:10 -04:00
gorkem-bwl b462ba7562 refactor(maintenance): centralize DurationUnit + sync OpenAPI spec
Convention pass per docs/coding-conventions.md (rules 5/8/10/11):
- Promote DurationUnit from a raw union type to a const tuple + derived type.
- Mongoose schema enum imports DurationUnits instead of inlining the values.
- Both validators import DurationUnits instead of inlining z.enum twice.
- Drop stale 'expiry' entries from openapi.json (spec is now strict-mode-correct).
2026-05-07 12:38:54 -04:00
gorkem-bwl bd059da94a refactor(maintenance): tighten validator + migration per /simplify
- Collapse two refines into a single superRefine in createMaintenanceWindowBodyValidation; same on edit.
- Match peer migration convention: use mongoose.connection.db directly, not Model.collection.
- Tighten TTL index detection: require expireAfterSeconds + single-field key.
- Add Starting log at migration top to match peers 0003-0006.
2026-05-07 12:33:03 -04:00
gorkem-bwl 4db95cfa44 fix(maintenance): stop silent deletion of one-time maintenance windows
Maintenance windows could disappear seconds after creation when the API received
a payload with end dates already in the past. The repository auto-set
expiry = end for one-time windows (repeat = 0), and Mongo's TTL index on the
expiry field then deleted the row on its next sweep. This was particularly
visible with automation tools sending payloads in non-UTC timezones.

## Changes

### Validator hardening
- Add .strict() to create + edit body schemas so unknown keys return 400
  instead of being silently dropped.
- Refine end > start on create.
- Refine end > now for one-time create payloads (repeat = 0).
- Refine end > start on edit when both are provided.
- Remove the accepted expiry field from both schemas.

### Stop the auto-delete behaviour
- Repository.create no longer copies end into expiry.
- Schema's expiry field + TTL index removed.
- Migration 0007 drops the live TTL index and unsets stale expiry values on
  existing rows so legacy data is no longer at risk.

### Client
- Form submission no longer includes expiry.
2026-05-07 12:29:26 -04:00
gorkem-bwl 602769b3e7 feat(checks): render status code 5000 as "Down" with subtype tooltip
Status code 5000 is Checkmate's internal sentinel for "no HTTP response
received" (DNS failure, connection refused, timeout, TLS error, etc.).
Showing the raw number to admins is confusing — the value isn't a real
HTTP code and means nothing without context.

This change replaces "5000" with "Down" across all check/incident
surfaces, and adds a hover tooltip that explains the underlying cause
based on the stored error message. Real HTTP codes (2xx/3xx/4xx/5xx)
are unchanged.

## Changes
- Add client/src/Utils/statusCode.ts with formatStatusCode,
  getStatusCodeTooltip, getStatusCodeValueType, extractErrorCode, and a
  message-to-subtype parser (timeout / dns / refused / tls / reset).
- Wire into 6 render sites: Checks table, Uptime details Checks table,
  GeoChecks table + map popup, Incidents table, Incident details dialog.
- Add common.statusCode.* i18n keys in en.json with subtype-specific
  descriptions. Tooltip appends the raw error code (ECONNREFUSED,
  ETIMEDOUT, CERT_HAS_EXPIRED, etc.) when present in the message.

## Tooltip examples
- "queryA ECONNREFUSED www.example.com" →
  "The server refused the connection (port closed or service not listening). (ECONNREFUSED)"
- "connect ETIMEDOUT 1.2.3.4:443" →
  "The server didn't respond in time (request timed out). (ETIMEDOUT)"

## Notes
- No DB or server changes; statusCode field stays 5000 in storage.
- Other locales fall back to English keys until translated.
2026-05-07 01:13:09 -04:00
gorkem-bwl 940fc38056 docs: rename frontend-conventions to coding-conventions, add backend rules
The conventions doc grew up as an FE-only thing. After the DNS provider
PR series highlighted real backend patterns that get repeatedly missed
in code review (DI, AppError envelope, schema enum, test setup style,
centralized Zod enums, OpenAPI response schemas), it makes sense to
have a single doc that covers both halves of the codebase.

Changes:

- Rename docs/frontend-conventions.md → docs/coding-conventions.md.
- Add a new top-level rule 0: look at peer implementations and follow
  the established pattern. Applies to both FE and BE. Includes a
  4-step "how to apply" and a self-check for PR authors.
- Keep the 5 frontend rules unchanged (rules 1-5).
- Add 6 backend rules (rules 6-11):
  - Controller → Service → Repository → Mongoose layering.
  - Provider skeleton (DI, SERVICE_NAME / TIMEOUT_MS, timeRequest,
    inline setTimeout race, outer AppError catch).
  - Mongoose enum reusing types/* const tuples.
  - Provider test conventions (file location, @jest/globals, contract
    test, inline setup() per test).
  - Centralize Zod enums in types/* — don't duplicate.
  - New entity fields must land in *ResponseSchema for OpenAPI.
- Pre-PR checklist split into Universal / Frontend / Backend.
- CLAUDE.md updated to reference the new file and summarize all 11
  rules + rule 0.
2026-05-06 13:55:58 -04:00
gorkem-bwl 1458cf4e4a fix(status-page): use operator-configured timezone on public pages
Anonymous visitors to a public status page have no persisted Redux
state, so ThemedHeatmap and ThemedHistogram tooltips always rendered
timestamps in the hardcoded "America/Toronto" default — regardless of
the timezone the operator configured. Even on the same domain,
ThemedHeatmap and ThemedHistogram had no code path to consume the
operator-configured statusPage.timezone returned by the API.

- Add SYSTEM_TIMEZONE module constant and a small resolveTimezone()
  helper to TimeUtils.ts. formatDateWithTz's timezone parameter is now
  optional and defaults to the system tz, so callers don't need to
  rebuild the prop -> browser -> UTC chain inline.
- Add a `timezone` field to StatusPageThemeContextValue so any themed
  component on the public page can read the page-wide tz without prop
  drilling (parallels how `theme` and `mode` are already exposed).
- Wire statusPage.timezone into StatusPageThemeProvider from
  Pages/StatusPage/Status/index.tsx (both the public route and the
  admin preview).
- ThemedHeatmap and ThemedHistogram now read tz from the context
  instead of useSelector(state.ui.timezone) — that selector was
  unreliable for anonymous visitors and removing it cuts a Redux
  subscription on the public page.
- Replace the inline `data?.timezone || Intl.DateTimeFormat()...`
  expression in useStatusPageForm.ts with resolveTimezone().

Closes #3628.
2026-05-01 22:28:12 -04:00
gorkem-bwl cb285bbb66 i18n: machine-translate new captureUrl key and hardware description
Translates captureUrl.label ("Capture endpoint") and the new long
description.hardware copy into all 15 non-English locales (ar, cs, de,
es, fi, fr, ja, pt-BR, ru, th, tr, uk, vi, zh-CN, zh-TW). The literal
URL example and the token name "Bearer" are kept untranslated.
2026-05-01 22:06:03 -04:00
gorkem-bwl 13b13b6818 i18n: stop clobbering translated hardware description
The previous commit overwrote description.hardware with English in 15
non-English locales. Restore each locale's existing translation; only
the en.json copy carries the new path/Bearer guidance. Translators will
pick up the English text on the next PoEditor sync.
2026-05-01 21:51:31 -04:00
gorkem-bwl 63c1a60b06 refactor(infrastructure): move capture-form guidance to ConfigBox subtitle
The previous commit added inline helperText under the URL and Secret
fields, but no other form in the codebase uses helperText for static
guidance — only for validation errors. The project's pattern for setup
guidance is the ConfigBox subtitle text on the left side of the form,
populated from pages.createMonitor.form.general.description.<type>.

Move the guidance there so this form follows the same convention as
every other monitor type.

- Remove urlHelperText / secretHelperText from GeneralSettingsConfig
- Remove the new helperText props on the URL and Secret TextFields
- Drop captureUrl.helperText and secret.helperText keys from all
  16 locales
- Beef up description.hardware to mention the /api/v1/metrics path
  requirement and the no-Bearer-prefix rule

The realistic captureUrl placeholder (added in the previous commit)
stays — it does most of the URL-disambiguation work on its own.
2026-05-01 18:01:44 -04:00
gorkem-bwl d5cd957bbd feat(infrastructure): add helper text to capture endpoint and secret fields
Two real users hit the same confusion: the Capture endpoint URL needs
the full path /api/v1/metrics, and the authorization secret should not
include a "Bearer" prefix. The form previously gave no guidance on
either — same generic placeholder as HTTP monitors and no helper text.

- Replace the URL field's generic label/placeholder with hardware-
  specific copy ("Capture endpoint", realistic 192.168.1.10:5001/...
  example) and add helper text under the field.
- Add helper text under the authorization secret field clarifying that
  only the raw token belongs there — Bearer is added automatically.
- Wire optional urlHelperText / secretHelperText through
  GeneralSettingsConfig so other monitor types are unaffected.
- Add three new i18n keys (captureUrl.label/placeholder/helperText)
  and one (secret.helperText) to all 16 locales. Non-English locales
  carry the English copy as a placeholder until translators pick the
  keys up via the existing PoEditor pipeline.
2026-05-01 16:46:46 -04:00
gorkem-bwl 79d2eb68fa chore(deps): bump vite to ^6.4.2
Patches CVE-2026-39365 (medium — path traversal in optimized deps .map handling).
Relaxes pinned version 6.4.1 to ^6.4.2 patch range; semver-compatible.
2026-04-30 01:48:16 -04:00
gorkem-bwl bc9441bcd0 chore(deps): bump fast-xml-parser (transitive)
Patches CVE-2026-41650 (medium — XML comment and CDATA injection via unescaped delimiters in XMLBuilder).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:47:42 -04:00
gorkem-bwl d868f6931d chore(deps): bump protocol-buffers-schema (transitive)
Patches CVE-2026-5758 (medium — prototype pollution in protocol-buffers-schema).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:47:34 -04:00
gorkem-bwl 29dbebd228 chore(deps): bump yaml (transitive)
Patches CVE-2026-33532 (medium — stack overflow via deeply nested YAML collections).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:47:08 -04:00
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 aaf7d7e47d 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:28 -04:00
gorkem-bwl c40f4e9f1c chore(deps): bump follow-redirects (transitive)
Patches GHSA-r4q5-vmmm-2653 (medium — leaks Custom-Authorization headers to cross-domain redirect targets).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:46:07 -04:00
gorkem-bwl 35daed605f chore(deps): bump flatted (transitive)
Patches CVE-2026-33228 (high — prototype pollution via parse() in flatted).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:45:33 -04:00
gorkem-bwl 6434afe2c9 chore(deps): bump picomatch (transitive)
Patches CVE-2026-33671 (high — ReDoS via extglob quantifiers) and CVE-2026-33672 (medium — method injection via POSIX character classes).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:44:39 -04:00
gorkem-bwl 788ca78234 chore(deps): bump lodash to 4.18.1 (transitive)
Patches CVE-2026-4800 (high — code injection via _.template) and
CVE-2026-2950 (medium — prototype pollution via array path bypass).

Transitive bump within existing semver range; no package.json change.
2026-04-30 01:44:00 -04:00
gorkem-bwl 3adadf0d07 chore(deps): bump multer to 1.4.5-lts.2 in server
## Changes
- Pin multer from ^1.4.5-lts.1 to ^1.4.5-lts.2

## Benefits
- Picks up the latest 1.x LTS patch (released 2025-03-20)
- Patch-level bump within existing semver range; no API changes
- Two routes use multer (authRoute, statusPageRoute) and both rely only on the stable basic API
2026-04-30 01:27:14 -04:00
gorkem-bwl 55b9702fc3 chore(deps): bump axios to 1.15.2 in client and server
## Changes
- Bump axios from ^1.7.x to ^1.15.2 in both client/ and server/

## Benefits
- Patches CVE-2025-62718 (NO_PROXY hostname normalization SSRF)
- Patches CVE-2026-40175 (cloud metadata exfiltration via header injection)
- Minor bump within existing ^1.x semver range; no API changes
2026-04-30 01:26:14 -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