- 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
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.
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.
- 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
- 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
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.
- 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).
- 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.
- 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.
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
## 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.
- Added `accountSid` and `twilioPhoneNumber` fields to Notification
type, MongoDB model, and frontend type instead of reusing
`address` and `homeserverUrl`
- Updated provider, validation, form hook, and form UI to use new fields
- Added Pushover and Twilio to notificationsService routing tests
(both handleNotifications and sendTestNotification)
- All 59 tests passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds Twilio SMS as a new notification channel, allowing users to
receive SMS alerts via the Twilio API.
Backend: provider using HTTP Basic Auth, type registration, validation,
service wiring. Uses existing fields: address (Account SID),
accessToken (Auth Token), homeserverUrl (From number), phone (To number).
Frontend: form UI with 4 fields, validation, i18n keys.
Tests: 18 provider tests + updated service test constructor.
Closes#3095
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds Pushover as a new notification channel, allowing users to receive
push notifications on their devices via the Pushover API.
Backend: provider, type registration, validation, service wiring
Frontend: form UI with app token and user key fields, validation, i18n
Tests: full unit test suite (15 tests, 100% coverage on provider)
Closes#3445
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove redundant 'defaultValue' prop on Telegram chat ID Controller in create/index.tsx;
the form already initialises via 'defaultValues: defaults' at the useForm level, making
the per-Controller prop unnecessary and inconsistent with the reviewer's expectation.
- Fix 'View Incident' URL in telegram.ts: was pointing to the infrastructure details page
(/infrastructure/:id) instead of the incidents page (/incidents/:id).
- Merge duplicate react-router-dom imports into one
- Replace useIsAdmin + useIsSuperAdmin + useSelector with single useSelector
- Remove redundant !includes("superadmin") check from canDeleteUser