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

View File

@@ -272,7 +272,7 @@ pub async fn set_hostname_rpc(
}
if let Some(hostname) = &hostname {
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)
})

View File

@@ -16,7 +16,7 @@ use crate::account::AccountInfo;
use crate::context::config::ServerConfig;
use crate::context::{CliContext, InitContext, RpcContext};
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::hostname::ServerHostname;
use crate::middleware::auth::local::LocalAuthContext;
@@ -375,10 +375,10 @@ pub async fn init(
backup_progress: None,
shutting_down: false,
restarting: false,
restart: None,
};
db.mutate(|v| {
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_ram_mut().ser(&ram)?;
server_info.as_devices_mut().ser(&devices)?;

View File

@@ -354,7 +354,7 @@ pub fn kiosk<C: Context>() -> ParentHandler<C> {
.mutate(|db| {
let server_info = db.as_public_mut().as_server_info_mut();
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
.result?;
@@ -371,7 +371,7 @@ pub fn kiosk<C: Context>() -> ParentHandler<C> {
.mutate(|db| {
let server_info = db.as_public_mut().as_server_info_mut();
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
.result?;
@@ -1370,7 +1370,7 @@ pub async fn set_language(
server_info
.as_language_mut()
.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
.result?;

View File

@@ -81,6 +81,7 @@ pub async fn update_system(
.await
.into_public()
.into_server_info()
.into_status_info()
.into_restart()
.de()?
.is_some()
@@ -286,7 +287,7 @@ async fn maybe_do_update(
.mutate(|db| {
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(
eyre!("{}", t!("update.already-updated-restart-required")),
crate::ErrorKind::InvalidRequest,
@@ -342,7 +343,7 @@ async fn maybe_do_update(
.as_status_info_mut()
.as_update_progress_mut()
.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
.result?;

View File

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

View File

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

View File

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

View File

@@ -149,7 +149,9 @@ export class PortalComponent {
readonly name = toSignal(this.patch.watch$('serverInfo', 'name'))
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)
getProgress(size: number, downloaded: number): number {

View File

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

View File

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

View File

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