Pad the settings cards, and make status and timeline readable at a glance

The Team settings cards (Escalation, Sources, Members, Switches, Single
sign-on) printed their text flush against the border with the button in the
corner: .card has never had padding and these never added any. A card with
a header row now pads itself, with the title left, the button right and a
divider before the content.

The incident page no longer carries the primary action twice. The copy up
by the status is gone and the sticky bar keeps it; Note is the timeline's
link, with Copy in the bar for a resolved incident, and the phone's More
sheet drops what the bar already shows. In the queue, a row's title wraps
to two lines so the namespace that tells rows apart is no longer cut off,
zero counts on the filter chips are dimmed, and a row omits the status the
filter already states and the team once the queue is narrowed to one.

Status colours failed 4.5:1 against their own fill in the light theme
(warning 3.6, info 4.1, critical 4.4, ok 4.45, snooze 4.49), so the light
tokens are darker; the dark theme already passed and is unchanged. Severity
badges now carry a shape as well as a colour, and each timeline event has an
icon. An escalation that ran out of levels, a failed notification and a
silent heartbeat stand out in amber or red.

Web UI only: no endpoint or JSON shape changed, so nothing to mirror in
terdut-tui.
This commit is contained in:
Niklas Ye
2026-10-08 14:07:24 +02:00
parent 065b557860
commit 7412456c5a
5 changed files with 104 additions and 54 deletions
+17
View File
@@ -1,5 +1,7 @@
// DOM helpers, the bottom sheet, confirmation and toasts.
import { severityClass } from './format.js';
// h builds an element. attrs: class, text, on<event>, dataset, aria/other
// attributes; boolean true sets an empty attribute, false/null skips it.
export function h(tag, attrs = {}, ...children) {
@@ -32,6 +34,11 @@ export function clear(el, ...children) {
// Stroke icons, 24×24. Built as SVG nodes so the CSP needs no inline anything.
const ICONS = {
alertTriangle: ['M12 4l9.5 16.5h-19z', 'M12 10v4.5', 'M12 17.5h.01'],
alertCircle: ['circle:12,12,9', 'M12 7.5v5', 'M12 16h.01'],
infoCircle: ['circle:12,12,9', 'M12 11v5.5', 'M12 7.5h.01'],
arrowUp: ['M12 19V5', 'M6 11l6-6 6 6'],
plus: ['M12 5v14M5 12h14'],
back: ['M15 18l-6-6 6-6'],
more: ['M5 12h.01M12 12h.01M19 12h.01'],
queueList: ['M4 6h16M4 12h16M4 18h10'],
@@ -171,6 +178,16 @@ export function badge(text, cls = '') {
return h('span', { class: `badge ${cls}`, text });
}
// The severity as a badge with a shape as well as a colour: a triangle for
// critical, a circle with ! for warning, a circle with i for anything else, so
// the coloured bar and badge are not the only thing that says it.
const SEVERITY_ICON = { 'sev-critical': 'alertTriangle', 'sev-warning': 'alertCircle' };
export function severityBadge(severity) {
const cls = severityClass(severity);
return h('span', { class: `badge plain ${cls}` },
icon(SEVERITY_ICON[cls] || 'infoCircle', 'icon badge-icon'), severity);
}
// Access granted by the identity provider's groups. The server refuses to edit
// it by hand (it would be undone at the next sign-in), so the controls that
// would try are disabled with this as their reason.