feat: unified restart notification with reason-specific messaging (#3147)

* feat: unified restart notification with reason-specific messaging

Replace statusInfo.updated (bool) with serverInfo.restart (nullable enum)
to unify all restart-needed scenarios under a single PatchDB field.

Backend sets the restart reason in RPC handlers for hostname change (mdns),
language change, kiosk toggle, and OS update download. Init clears it on
boot. The update flow checks this field to prevent updates when a restart
is already pending.

Frontend shows a persistent action bar with reason-specific i18n messages
instead of per-feature restart dialogs. For .local hostname changes, the
existing "open new address" dialog is preserved — the restart toast
appears after the user logs in on the new address.

Also includes migration in v0_4_0_alpha_23 to remove statusInfo.updated
and initialize serverInfo.restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix broken styling and improve settings layout

* refactor: move restart field from ServerInfo to ServerStatus

The restart reason belongs with other server state (shutting_down,
restarting, update_progress) rather than on the top-level ServerInfo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix PR comment

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Matt Hill
2026-03-29 02:23:59 -06:00
committed by GitHub
parent bbbc8f7440
commit b0b4b41c42
22 changed files with 192 additions and 203 deletions

View File

@@ -50,45 +50,32 @@ import { CHANGE_PASSWORD } from './change-password'
</button>
}
</div>
<div tuiCell>
<span tuiTitle>
<strong>Change password</strong>
</span>
<button tuiButton size="s" (click)="onChangePassword()">Change</button>
</div>
<div tuiCell>
<span tuiTitle>
<strong>Restart</strong>
<span tuiSubtitle>Restart the VPS</span>
</span>
<button
tuiButton
size="s"
appearance="secondary"
iconStart="@tui.rotate-cw"
[loading]="restarting()"
(click)="onRestart()"
>
Restart
</button>
</div>
<div tuiCell>
<span tuiTitle>
<strong>Logout</strong>
</span>
<button
tuiButton
size="s"
appearance="secondary-destructive"
iconStart="@tui.log-out"
(click)="onLogout()"
>
Logout
</button>
</div>
</div>
<div tuiCardLarge [style.align-items]="'start'">
<button tuiButton size="s" (click)="onChangePassword()">
Change password
</button>
<button
tuiButton
size="s"
iconStart="@tui.rotate-cw"
[loading]="restarting()"
(click)="onRestart()"
>
Reboot VPS
</button>
<button tuiButton size="s" iconStart="@tui.log-out" (click)="onLogout()">
Logout
</button>
</div>
`,
styles: `
:host {
display: flex;
flex-direction: column;
gap: 1rem;
}
[tuiCardLarge] {
background: var(--tui-background-neutral-1);
@@ -148,9 +135,9 @@ export default class Settings {
await this.api.restart()
this.dialogs
.open(
'The VPS is restarting. Please wait 1\u20132 minutes, then refresh the page.',
'The VPS is rebooting. Please wait 1\u20132 minutes, then refresh the page.',
{
label: 'Restarting',
label: 'Rebooting',
},
)
.subscribe()

View File

@@ -14,7 +14,7 @@ body {
isolation: isolate;
overflow-x: hidden;
background:
conic-gradient(var(--tui-background-base)),
linear-gradient(var(--tui-background-base, #171717), var(--tui-background-base, #171717)),
radial-gradient(circle at top right, #5240a8, transparent 40%),
radial-gradient(circle at bottom right, #9236c9, transparent),
radial-gradient(circle at 25% 100%, #5b65d5, transparent 30%),