-
-
Notifications
You must be signed in to change notification settings - Fork 565
Description
Is your feature request related to a problem? Please describe.
- Teams need to brand and re-layout status pages without forking source; current approach makes upgrades hard.
Describe the solution you'd like
Add a Customisation section to Status Page settings (persisted in DB, survives restarts):
- Custom CSS textarea (fonts, colours, spacing, animations).
- Optional Custom HTML slots for header and footer; render these instead of defaults when present.
- Optional Custom JavaScript executed after page load (behind an explicit enable toggle/feature flag).
- Live preview before publish; export/import JSON for backup.
- Security: server-side HTML sanitisation, strict CSP, content size limits, audit log, and role-based access.
- Fix toggles: ensure charts and uptime % render when enabled; add unit/e2e tests.
Describe alternatives you’ve considered
-
Forking and patching source per deployment (works but painful to maintain).
-
Separate status-site fed by Checkmate webhooks + small DB + custom frontend.
-
Other open-source status pages for ideas or interim use:
- Kener — minimal UI with a simple CSS override model.
- OneUptime — supports custom HTML/CSS/JS; see technical notes below.
Additional context
Implementation from OneUptime in TypeScript
Schema: extend StatusPage
with four text fields (PostgreSQL TEXT
):
// StatusPage.ts
public headerHTML?: string;
public footerHTML?: string;
public customCSS?: string;
public customJavaScript?: string;
Guard with plan/role checks.
Admin UI: dedicated editors with syntax highlighting/validation:
- HTML editors for header/footer
- CSS editor
- JavaScript editor
Editors integrate with a form schema for validation, syntax highlighting, and error reporting.
Rendering
- CSS injection at runtime:
const css = statusPage.customCSS;
if (css) {
const style = document.createElement('style');
style.innerText = css;
document.head.appendChild(style);
}
- Conditional HTML replacement for components (example: header):
{!headerHtml ? (
<Header logo={logo} links={links} onLogoClicked={...} />
) : (
<div dangerouslySetInnerHTML={{ __html: headerHtml }} />
)}
- Post-mount JS execution after the page finishes loading:
const onPageLoadComplete = () => {
if (javascript) { new Function(javascript)(); }
};
Flow: server renders base template → client fetches status-page config → inject CSS → mount components with optional HTML overrides → run custom JS last.
State: custom content held in React state and updated from fetched config:
const [javascript, setJavaScript] = useState<string | null>(null);
// later
setJavaScript(get(masterpage, 'statusPage.customJavaScript') ?? null);
Ops/UX: preview without going live; works on both default and custom domains; premium-feature gating is possible.