Commit Graph
1674 Commits
Author SHA1 Message Date
Alex Holliday 22230b8a08 UI fixes for job queue table 2026-05-04 11:53:12 -07:00
Alexander Holliday 39807c2de1 Merge pull request #3629 from bluewave-labs/feat/infrastructure-form-helper-text
feat(infrastructure): clarify capture endpoint and authorization secret on monitor form
2026-05-02 10:48:33 -07: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
Alex 4c04294f71 extract duplicate code, add slot components 2026-04-30 14:42:19 -07:00
Alex Holliday 05798914a8 Merge branch 'develop' into feat/raise-max-recent-checks 2026-04-30 11:01:27 -07:00
Alex Holliday e906b237a0 mutate status page on save 2026-04-30 10:57:01 -07:00
Alex Holliday d47cc65fed Increase max recent checks limit from 25 -> 50, extract constants 2026-04-30 10:30:54 -07:00
Alexander Holliday bdf1e13ce8 Merge pull request #3607 from bluewave-labs/feat/smtp-from-name
feat(smtp): add optional sender display name to SMTP configuration
2026-04-29 13:01:08 -07: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 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
Alexander Holliday 100e569aa8 Merge pull request #3583 from ayshaL/fix/blank-screen-on-timezone
Fix: prevent blank screen crash when clearing timezone search field
2026-04-29 12:13:40 -07:00
Alex Holliday b2c3e08db3 fix reveresed checks 2026-04-29 12:03:23 -07:00
Alexander Holliday a7d5a84206 Merge pull request #3569 from bluewave-labs/feat/status-page-themes-frontend
feat(status-page): four selectable themes for the public status page
2026-04-29 11:35:23 -07:00
Alex Holliday e86734cee9 resolve conflcits 2026-04-29 11:28:57 -07:00
Alex Holliday cc84c37a2d remove planning docs 2026-04-29 11:22:20 -07:00
Alex Holliday e85e9dc2d4 remove duplicated time util 2026-04-29 11:15:33 -07:00
Alex Holliday 1398ab6721 remove dead code 2026-04-29 11:12:35 -07:00
Alex Holliday d32ea7f8c3 remove dead code 2026-04-29 11:07:34 -07:00
Alex Holliday edeed00be6 fix unnecessary cast, remove dead keys 2026-04-29 10:56:57 -07:00
Alex Holliday 45c02e0f7f unsafe lookup fix 2026-04-29 10:51:40 -07:00
Alex Holliday fcb4fbf277 fix optional types 2026-04-29 10:35:35 -07:00
Alex Holliday cf5691e250 fix build error 2026-04-29 10:01:43 -07:00
Alex Holliday f3b4b908fd Merge branch 'develop' into feat/settings-remove-monitors-modal 2026-04-29 10:00:01 -07:00
Alex Holliday 91bdc662ca Merge branch 'develop' into feat/infrastructure-network-empty-state 2026-04-29 09:56:55 -07:00
Alex Holliday 301942d0eb normalize 2026-04-29 09:56:01 -07:00
Alex Holliday 29bb1615f5 Merge branch 'develop' into feat/incidents-page-polish 2026-04-29 09:51:06 -07:00
Alex Holliday e0ac040063 Merge branch 'develop' into feat/account-team-modals 2026-04-29 09:49:23 -07:00
Alex Holliday 63031e938e normalize 2026-04-29 09:47:11 -07:00
Alex Holliday 4b82129199 Merge branch 'develop' into refactor/button-input-styling 2026-04-29 09:46:54 -07:00
Alex Holliday 2dd9218910 normailze dialog and basepage 2026-04-29 09:42:49 -07:00
Alex Holliday 5792ca624e normalize NoticeBanner 2026-04-29 09:37:37 -07: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 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