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>
This commit is contained in:
Matt Hill
2026-03-28 23:13:59 -06:00
parent 104567e457
commit b01e5d9f09
12 changed files with 29 additions and 24 deletions

View File

@@ -128,6 +128,7 @@ impl Public {
update_progress: None, update_progress: None,
shutting_down: false, shutting_down: false,
restarting: false, restarting: false,
restart: None,
}, },
unread_notification_count: 0, unread_notification_count: 0,
password_hash: account.password.clone(), password_hash: account.password.clone(),
@@ -151,7 +152,6 @@ impl Public {
kiosk: Some(kiosk).filter(|_| &*PLATFORM != "raspberrypi"), kiosk: Some(kiosk).filter(|_| &*PLATFORM != "raspberrypi"),
language, language,
keyboard, keyboard,
restart: None,
}, },
package_data: AllPackageData::default(), package_data: AllPackageData::default(),
ui: serde_json::from_str(*DB_UI_SEED_CELL.get().unwrap_or(&"null")) ui: serde_json::from_str(*DB_UI_SEED_CELL.get().unwrap_or(&"null"))
@@ -218,8 +218,6 @@ pub struct ServerInfo {
pub kiosk: Option<bool>, pub kiosk: Option<bool>,
pub language: Option<InternedString>, pub language: Option<InternedString>,
pub keyboard: Option<KeyboardOptions>, pub keyboard: Option<KeyboardOptions>,
#[serde(default)]
pub restart: Option<RestartReason>,
} }
#[derive(Debug, Clone, Deserialize, Serialize, TS)] #[derive(Debug, Clone, Deserialize, Serialize, TS)]
@@ -381,6 +379,8 @@ pub struct ServerStatus {
pub shutting_down: bool, pub shutting_down: bool,
#[serde(default)] #[serde(default)]
pub restarting: bool, pub restarting: bool,
#[serde(default)]
pub restart: Option<RestartReason>,
} }
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)] #[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]

View File

@@ -272,7 +272,7 @@ pub async fn set_hostname_rpc(
} }
if let Some(hostname) = &hostname { if let Some(hostname) = &hostname {
hostname.save(server_info)?; hostname.save(server_info)?;
server_info.as_restart_mut().ser(&Some(RestartReason::Mdns))?; server_info.as_status_info_mut().as_restart_mut().ser(&Some(RestartReason::Mdns))?;
} }
ServerHostnameInfo::load(server_info) ServerHostnameInfo::load(server_info)
}) })

View File

@@ -16,7 +16,7 @@ use crate::account::AccountInfo;
use crate::context::config::ServerConfig; use crate::context::config::ServerConfig;
use crate::context::{CliContext, InitContext, RpcContext}; use crate::context::{CliContext, InitContext, RpcContext};
use crate::db::model::Database; use crate::db::model::Database;
use crate::db::model::public::{RestartReason, ServerStatus}; use crate::db::model::public::ServerStatus;
use crate::developer::OS_DEVELOPER_KEY_PATH; use crate::developer::OS_DEVELOPER_KEY_PATH;
use crate::hostname::ServerHostname; use crate::hostname::ServerHostname;
use crate::middleware::auth::local::LocalAuthContext; use crate::middleware::auth::local::LocalAuthContext;
@@ -375,10 +375,10 @@ pub async fn init(
backup_progress: None, backup_progress: None,
shutting_down: false, shutting_down: false,
restarting: false, restarting: false,
restart: None,
}; };
db.mutate(|v| { db.mutate(|v| {
let server_info = v.as_public_mut().as_server_info_mut(); let server_info = v.as_public_mut().as_server_info_mut();
server_info.as_restart_mut().ser(&None::<RestartReason>)?;
server_info.as_ntp_synced_mut().ser(&ntp_synced)?; server_info.as_ntp_synced_mut().ser(&ntp_synced)?;
server_info.as_ram_mut().ser(&ram)?; server_info.as_ram_mut().ser(&ram)?;
server_info.as_devices_mut().ser(&devices)?; server_info.as_devices_mut().ser(&devices)?;

View File

@@ -354,7 +354,7 @@ pub fn kiosk<C: Context>() -> ParentHandler<C> {
.mutate(|db| { .mutate(|db| {
let server_info = db.as_public_mut().as_server_info_mut(); let server_info = db.as_public_mut().as_server_info_mut();
server_info.as_kiosk_mut().ser(&Some(true))?; server_info.as_kiosk_mut().ser(&Some(true))?;
server_info.as_restart_mut().ser(&Some(RestartReason::Kiosk)) server_info.as_status_info_mut().as_restart_mut().ser(&Some(RestartReason::Kiosk))
}) })
.await .await
.result?; .result?;
@@ -371,7 +371,7 @@ pub fn kiosk<C: Context>() -> ParentHandler<C> {
.mutate(|db| { .mutate(|db| {
let server_info = db.as_public_mut().as_server_info_mut(); let server_info = db.as_public_mut().as_server_info_mut();
server_info.as_kiosk_mut().ser(&Some(false))?; server_info.as_kiosk_mut().ser(&Some(false))?;
server_info.as_restart_mut().ser(&Some(RestartReason::Kiosk)) server_info.as_status_info_mut().as_restart_mut().ser(&Some(RestartReason::Kiosk))
}) })
.await .await
.result?; .result?;
@@ -1370,7 +1370,7 @@ pub async fn set_language(
server_info server_info
.as_language_mut() .as_language_mut()
.ser(&Some(language.clone()))?; .ser(&Some(language.clone()))?;
server_info.as_restart_mut().ser(&Some(RestartReason::Language)) server_info.as_status_info_mut().as_restart_mut().ser(&Some(RestartReason::Language))
}) })
.await .await
.result?; .result?;

View File

@@ -81,6 +81,7 @@ pub async fn update_system(
.await .await
.into_public() .into_public()
.into_server_info() .into_server_info()
.into_status_info()
.into_restart() .into_restart()
.de()? .de()?
.is_some() .is_some()
@@ -286,7 +287,7 @@ async fn maybe_do_update(
.mutate(|db| { .mutate(|db| {
let server_info = db.as_public_mut().as_server_info_mut(); let server_info = db.as_public_mut().as_server_info_mut();
if server_info.as_restart().de()?.is_some() { if server_info.as_status_info().as_restart().de()?.is_some() {
return Err(Error::new( return Err(Error::new(
eyre!("{}", t!("update.already-updated-restart-required")), eyre!("{}", t!("update.already-updated-restart-required")),
crate::ErrorKind::InvalidRequest, crate::ErrorKind::InvalidRequest,
@@ -342,7 +343,7 @@ async fn maybe_do_update(
.as_status_info_mut() .as_status_info_mut()
.as_update_progress_mut() .as_update_progress_mut()
.ser(&None)?; .ser(&None)?;
server_info.as_restart_mut().ser(&Some(RestartReason::Update)) server_info.as_status_info_mut().as_restart_mut().ser(&Some(RestartReason::Update))
}) })
.await .await
.result?; .result?;

View File

@@ -29,11 +29,12 @@ impl VersionT for Version {
} }
#[instrument(skip_all)] #[instrument(skip_all)]
fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<Value, Error> { fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<Value, Error> {
db["public"]["serverInfo"]["statusInfo"] let status_info = db["public"]["serverInfo"]["statusInfo"]
.as_object_mut() .as_object_mut();
.map(|m| m.remove("updated")); if let Some(m) = status_info {
m.remove("updated");
db["public"]["serverInfo"]["restart"] = Value::Null; m.insert("restart".into(), Value::Null);
}
Ok(Value::Null) Ok(Value::Null)
} }

View File

@@ -3,7 +3,6 @@ import type { Governor } from './Governor'
import type { KeyboardOptions } from './KeyboardOptions' import type { KeyboardOptions } from './KeyboardOptions'
import type { LshwDevice } from './LshwDevice' import type { LshwDevice } from './LshwDevice'
import type { NetworkInfo } from './NetworkInfo' import type { NetworkInfo } from './NetworkInfo'
import type { RestartReason } from './RestartReason'
import type { ServerStatus } from './ServerStatus' import type { ServerStatus } from './ServerStatus'
import type { SmtpValue } from './SmtpValue' import type { SmtpValue } from './SmtpValue'
@@ -33,5 +32,4 @@ export type ServerInfo = {
kiosk: boolean | null kiosk: boolean | null
language: string | null language: string | null
keyboard: KeyboardOptions | null keyboard: KeyboardOptions | null
restart: RestartReason | null
} }

View File

@@ -2,10 +2,12 @@
import type { BackupProgress } from './BackupProgress' import type { BackupProgress } from './BackupProgress'
import type { FullProgress } from './FullProgress' import type { FullProgress } from './FullProgress'
import type { PackageId } from './PackageId' import type { PackageId } from './PackageId'
import type { RestartReason } from './RestartReason'
export type ServerStatus = { export type ServerStatus = {
backupProgress: { [key: PackageId]: BackupProgress } | null backupProgress: { [key: PackageId]: BackupProgress } | null
updateProgress: FullProgress | null updateProgress: FullProgress | null
shuttingDown: boolean shuttingDown: boolean
restarting: boolean restarting: boolean
restart: RestartReason | null
} }

View File

@@ -149,7 +149,9 @@ export class PortalComponent {
readonly name = toSignal(this.patch.watch$('serverInfo', 'name')) readonly name = toSignal(this.patch.watch$('serverInfo', 'name'))
readonly update = toSignal(inject(OSService).updating$) readonly update = toSignal(inject(OSService).updating$)
readonly restartReason = toSignal(this.patch.watch$('serverInfo', 'restart')) readonly restartReason = toSignal(
this.patch.watch$('serverInfo', 'statusInfo', 'restart'),
)
readonly bar = signal(true) readonly bar = signal(true)
getProgress(size: number, downloaded: number): number { getProgress(size: number, downloaded: number): number {

View File

@@ -26,6 +26,7 @@ export namespace Mock {
updateProgress: null, updateProgress: null,
restarting: false, restarting: false,
shuttingDown: false, shuttingDown: false,
restart: null,
} }
export const RegistryOSUpdate: T.OsVersionInfoMap = { export const RegistryOSUpdate: T.OsVersionInfoMap = {

View File

@@ -445,7 +445,7 @@ export class MockApiService extends ApiService {
this.mockRevision([ this.mockRevision([
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/serverInfo/restart', path: '/serverInfo/statusInfo/restart',
value: 'kiosk', value: 'kiosk',
}, },
]) ])
@@ -471,7 +471,7 @@ export class MockApiService extends ApiService {
this.mockRevision([ this.mockRevision([
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/serverInfo/restart', path: '/serverInfo/statusInfo/restart',
value: 'mdns', value: 'mdns',
}, },
]) ])
@@ -507,7 +507,7 @@ export class MockApiService extends ApiService {
this.mockRevision([ this.mockRevision([
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/serverInfo/restart', path: '/serverInfo/statusInfo/restart',
value: 'language', value: 'language',
}, },
]) ])
@@ -1852,7 +1852,7 @@ export class MockApiService extends ApiService {
const patch3: Operation<string>[] = [ const patch3: Operation<string>[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/serverInfo/restart', path: '/serverInfo/statusInfo/restart',
value: 'update', value: 'update',
}, },
{ {

View File

@@ -231,8 +231,8 @@ export const mockPatchData: DataModel = {
restarting: false, restarting: false,
shuttingDown: false, shuttingDown: false,
backupProgress: null, backupProgress: null,
restart: null,
}, },
restart: null,
name: 'Random Words', name: 'Random Words',
hostname: 'random-words', hostname: 'random-words',
pubkey: 'npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m', pubkey: 'npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m',