Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b2609e98f | |||
| fa6d82d6e5 | |||
| 7efd1bbba7 | |||
| 3bf94a5d7f |
@@ -15,5 +15,5 @@ type: application
|
|||||||
# appVersion and image.tag in values.yaml no longer agree, and that is not an oversight:
|
# appVersion and image.tag in values.yaml no longer agree, and that is not an oversight:
|
||||||
# image.tag stays "latest", which is what a local install actually pulls. appVersion is
|
# image.tag stays "latest", which is what a local install actually pulls. appVersion is
|
||||||
# metadata and drives nothing.
|
# metadata and drives nothing.
|
||||||
version: 0.36.0
|
version: 0.37.1
|
||||||
appVersion: "v0.36.0"
|
appVersion: "v0.37.1"
|
||||||
|
|||||||
@@ -6,20 +6,19 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
{{- include "terdut-server.labels" . | nindent 4 }}
|
{{- include "terdut-server.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: {{ .Values.replicaCount }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
{{- include "terdut-server.selectorLabels" . | nindent 6 }}
|
{{- include "terdut-server.selectorLabels" . | nindent 6 }}
|
||||||
# Recreate, not RollingUpdate, even though the PVC that forced it is gone:
|
# RollingUpdate, not Recreate: the sweeper, notifier and migration runner
|
||||||
# the sweeper, notifier and migration runner take a Postgres advisory lock
|
# each take a Postgres advisory lock around their own pass, and new-incident
|
||||||
# each, and new-incident creation on the first webhook for a brand-new
|
# creation on the first webhook for a brand-new groupKey resolves its own
|
||||||
# groupKey resolves its own insert conflict — so two replicas overlapping
|
# insert conflict -- so two replicas overlapping during a rollout no longer
|
||||||
# during a rollout no longer double-page, race a migration, or drop a
|
# double-page, race a migration, or drop a webhook payload (v0.36.0). No
|
||||||
# webhook payload. Nothing left here actually requires Recreate anymore;
|
# explicit maxUnavailable/maxSurge: the 25%/25% default rounds to 0/1 at
|
||||||
# it stays the default pending a deliberate decision to raise replicas
|
# replicaCount: 2, which is zero-downtime already.
|
||||||
# above 1 and move to RollingUpdate.
|
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
# Safe above 1 since v0.36.0: the sweeper, notifier and migration runner each
|
||||||
|
# take a Postgres advisory lock around their own pass, and a webhook that
|
||||||
|
# loses the race to open a brand-new incident attaches to the winner's row
|
||||||
|
# instead of dropping its payload. An image older than v0.36.0 does not have
|
||||||
|
# these guards -- do not raise this against one.
|
||||||
|
replicaCount: 2
|
||||||
|
|
||||||
networking:
|
networking:
|
||||||
hostname: "terdut.example.com"
|
hostname: "terdut.example.com"
|
||||||
servicePort: 8080
|
servicePort: 8080
|
||||||
|
|||||||
@@ -583,6 +583,10 @@ details[open] > summary { margin-bottom: 8px; }
|
|||||||
}
|
}
|
||||||
.actionbar .btn { min-height: 48px; }
|
.actionbar .btn { min-height: 48px; }
|
||||||
.actionbar .btn-primary { flex: 1; font-size: 16px; }
|
.actionbar .btn-primary { flex: 1; font-size: 16px; }
|
||||||
|
/* The extra actions that only phones hide behind "More" — see actionBar() and
|
||||||
|
extraActions() in incident.js. Hidden by default; the desktop block below
|
||||||
|
shows them and hides the now-redundant More button instead. */
|
||||||
|
.action-extra { display: none; }
|
||||||
|
|
||||||
.detail-placeholder {
|
.detail-placeholder {
|
||||||
display: grid; place-items: center; height: 100%;
|
display: grid; place-items: center; height: 100%;
|
||||||
@@ -669,7 +673,7 @@ details[open] > summary { margin-bottom: 8px; }
|
|||||||
caught by the unrelated .label > span styling meant for label chips. */
|
caught by the unrelated .label > span styling meant for label chips. */
|
||||||
.week-nav .week-label { font-size: 14px; font-weight: 650; min-width: 11.5em; text-align: center; white-space: nowrap; }
|
.week-nav .week-label { font-size: 14px; font-weight: 650; min-width: 11.5em; text-align: center; white-space: nowrap; }
|
||||||
.week-label small { color: var(--faint); font-weight: 600; font-size: 11px; margin-left: 2px; }
|
.week-label small { color: var(--faint); font-weight: 600; font-size: 11px; margin-left: 2px; }
|
||||||
.days { list-style: none; margin: 0; padding: 0; }
|
.days { list-style: none; margin: 0 auto; padding: 0; }
|
||||||
.day { display: grid; grid-template-columns: 3.2em 4.2em 1fr; align-items: center; gap: 8px; min-height: 50px; padding: 0 14px; }
|
.day { display: grid; grid-template-columns: 3.2em 4.2em 1fr; align-items: center; gap: 8px; min-height: 50px; padding: 0 14px; }
|
||||||
.day + .day { border-top: 1px solid var(--border); }
|
.day + .day { border-top: 1px solid var(--border); }
|
||||||
.day-name { font-weight: 650; }
|
.day-name { font-weight: 650; }
|
||||||
@@ -773,7 +777,15 @@ kbd {
|
|||||||
.pane-list .chips { flex-wrap: wrap; overflow-x: visible; }
|
.pane-list .chips { flex-wrap: wrap; overflow-x: visible; }
|
||||||
.pane-list .chip-sep { display: none; }
|
.pane-list .chip-sep { display: none; }
|
||||||
.chips-fade { display: none; }
|
.chips-fade { display: none; }
|
||||||
.view-queue:not(.has-detail) .pane-detail { display: block; }
|
/* With nothing selected there is no detail to show next to, so the list
|
||||||
|
takes the whole row instead of leaving the second column as dead space
|
||||||
|
around the placeholder text. Selecting an incident (.has-detail) drops
|
||||||
|
back to the base minmax(340,420) 1fr rule above. */
|
||||||
|
.view-queue:not(.has-detail) { grid-template-columns: 1fr; }
|
||||||
|
.view-queue:not(.has-detail) .pane-list { border-right: 0; }
|
||||||
|
/* Full width reads better capped than edge-to-edge on a very wide monitor,
|
||||||
|
matching .detail's own cap below. */
|
||||||
|
.view-queue:not(.has-detail) .list { max-width: 900px; margin: 0 auto; }
|
||||||
|
|
||||||
/* On desktop the list stays visible next to the detail. */
|
/* On desktop the list stays visible next to the detail. */
|
||||||
.app.detail-open .nav { display: flex; }
|
.app.detail-open .nav { display: flex; }
|
||||||
@@ -787,8 +799,12 @@ kbd {
|
|||||||
.actionbar {
|
.actionbar {
|
||||||
position: sticky; bottom: 0;
|
position: sticky; bottom: 0;
|
||||||
padding: 12px 32px;
|
padding: 12px 32px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.actionbar .btn-primary { flex: 0 1 240px; }
|
.actionbar .btn-primary { flex: 0 1 240px; }
|
||||||
|
/* Room enough to show every action, so More is fully redundant here. */
|
||||||
|
.action-extra { display: inline-flex; }
|
||||||
|
.more-btn { display: none; }
|
||||||
|
|
||||||
.sheet {
|
.sheet {
|
||||||
width: min(440px, calc(100% - 32px));
|
width: min(440px, calc(100% - 32px));
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ function render() {
|
|||||||
h('div', { class: 'card' }, shortcuts())),
|
h('div', { class: 'card' }, shortcuts())),
|
||||||
|
|
||||||
h('div', { class: 'page-head' }),
|
h('div', { class: 'page-head' }),
|
||||||
h('button', { class: 'btn btn-block', type: 'button', onclick: signOut }, icon('logout'), 'Sign out'),
|
// Wrapped in a div: .btn is inline-flex, and only a block-level element
|
||||||
|
// picks up .view-page > *'s margin:auto centering (see app.css:316).
|
||||||
|
h('div', {}, h('button', { class: 'btn btn-block', type: 'button', onclick: signOut }, icon('logout'), 'Sign out')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,9 @@ function render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function backLink() {
|
function backLink() {
|
||||||
return h('a', { class: 'back-link', href: '/admin/teams' }, icon('chevronLeft'), h('span', { text: 'Teams' }));
|
// Wrapped in a div: .back-link is inline-flex, and only a block-level
|
||||||
|
// element picks up .view-page > *'s margin:auto centering (app.css:316).
|
||||||
|
return h('div', {}, h('a', { class: 'back-link', href: '/admin/teams' }, icon('chevronLeft'), h('span', { text: 'Teams' })));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- identity --------------------------------------------------------------
|
// --- identity --------------------------------------------------------------
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ function render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function backLink() {
|
function backLink() {
|
||||||
return h('a', { class: 'back-link', href: '/admin/users' }, icon('chevronLeft'), h('span', { text: 'Users' }));
|
// Wrapped in a div: .back-link is inline-flex, and only a block-level
|
||||||
|
// element picks up .view-page > *'s margin:auto centering (app.css:316).
|
||||||
|
return h('div', {}, h('a', { class: 'back-link', href: '/admin/users' }, icon('chevronLeft'), h('span', { text: 'Users' })));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- identity --------------------------------------------------------------
|
// --- identity --------------------------------------------------------------
|
||||||
|
|||||||
@@ -453,9 +453,25 @@ function quickActions() {
|
|||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Desktop has room to show what a phone folds into the More sheet below — see
|
||||||
|
// the .action-extra/.more-btn rules in app.css. Resolved/archived incidents
|
||||||
|
// already say everything via primaryAction()/secondaryAction(), so there is
|
||||||
|
// nothing extra to surface for them.
|
||||||
|
function extraActions() {
|
||||||
|
if (!isOpen()) return [];
|
||||||
|
const out = [
|
||||||
|
h('button', { class: 'btn btn-sm action-extra', type: 'button', onclick: assign }, icon('user'), 'Assign…'),
|
||||||
|
h('button', { class: 'btn btn-sm action-extra', type: 'button', onclick: addNote }, icon('note'), 'Add note…'),
|
||||||
|
];
|
||||||
|
out.push(inc.status === 'acknowledged'
|
||||||
|
? h('button', { class: 'btn btn-sm action-extra', type: 'button', onclick: unacknowledge }, icon('undo'), 'Clear ack')
|
||||||
|
: h('button', { class: 'btn btn-sm action-extra', type: 'button', onclick: resolve }, icon('checkCircle'), 'Resolve…'));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
function actionBar() {
|
function actionBar() {
|
||||||
const more = h('button', { class: 'btn', type: 'button', 'aria-label': 'More actions', onclick: moreMenu }, icon('more'), 'More');
|
const more = h('button', { class: 'btn more-btn', type: 'button', 'aria-label': 'More actions', onclick: moreMenu }, icon('more'), 'More');
|
||||||
const bar = h('div', { class: 'actionbar' }, primaryAction(), secondaryAction(), more);
|
const bar = h('div', { class: 'actionbar' }, primaryAction(), secondaryAction(), ...extraActions(), more);
|
||||||
if (busy) for (const b of bar.querySelectorAll('button')) b.disabled = true;
|
if (busy) for (const b of bar.querySelectorAll('button')) b.disabled = true;
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user