diff --git a/frontend/projects/ui/src/app/app.component.ts b/frontend/projects/ui/src/app/app.component.ts index b26e27879..23e6edde7 100644 --- a/frontend/projects/ui/src/app/app.component.ts +++ b/frontend/projects/ui/src/app/app.component.ts @@ -290,16 +290,18 @@ export class AppComponent { } private watchStatus (): Subscription { - return this.patch.watch$('server-info', 'status').subscribe(status => { - if (status === ServerStatus.Updated && !this.updateToast) { - this.presentToastUpdated() - } - }) + return this.patch + .watch$('server-info', 'status-info', 'updated') + .subscribe(isUpdated => { + if (isUpdated && !this.updateToast) { + this.presentToastUpdated() + } + }) } private watchUpdateProgress (): Subscription { return this.patch - .watch$('server-info', 'update-progress') + .watch$('server-info', 'status-info', 'update-progress') .subscribe(progress => { this.osUpdateProgress = progress }) @@ -454,9 +456,7 @@ export class AppComponent { await loader.present() try { - await this.embassyApi.restartServer({ - 'marketplace-url': this.config.marketplace.url, - }) + await this.embassyApi.restartServer({}) } catch (e) { this.errToast.present(e) } finally { diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-backup/server-backup.page.ts b/frontend/projects/ui/src/app/pages/server-routes/server-backup/server-backup.page.ts index 3d0ddd149..51aaf628d 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-backup/server-backup.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/server-backup/server-backup.page.ts @@ -1,14 +1,28 @@ import { Component } from '@angular/core' -import { LoadingController, ModalController, NavController } from '@ionic/angular' +import { + LoadingController, + ModalController, + NavController, +} from '@ionic/angular' import { ApiService } from 'src/app/services/api/embassy-api.service' -import { GenericInputComponent, GenericInputOptions } from 'src/app/modals/generic-input/generic-input.component' +import { + GenericInputComponent, + GenericInputOptions, +} from 'src/app/modals/generic-input/generic-input.component' import { PatchDbService } from 'src/app/services/patch-db/patch-db.service' -import { PackageDataEntry, PackageMainStatus, ServerStatus } from 'src/app/services/patch-db/data-model' +import { + PackageDataEntry, + PackageMainStatus, + ServerStatus, +} from 'src/app/services/patch-db/data-model' import { Subscription } from 'rxjs' import { take } from 'rxjs/operators' import { MappedBackupTarget } from 'src/app/util/misc.util' import * as argon2 from '@start9labs/argon2' -import { CifsBackupTarget, DiskBackupTarget } from 'src/app/services/api/api.types' +import { + CifsBackupTarget, + DiskBackupTarget, +} from 'src/app/services/api/api.types' @Component({ selector: 'server-backup', @@ -20,20 +34,21 @@ export class ServerBackupPage { pkgs: PkgInfo[] = [] subs: Subscription[] - constructor ( + constructor( private readonly loadingCtrl: LoadingController, private readonly modalCtrl: ModalController, private readonly embassyApi: ApiService, private readonly patch: PatchDbService, private readonly navCtrl: NavController, - ) { } + ) {} - ngOnInit () { + ngOnInit() { this.subs = [ - this.patch.watch$('server-info', 'status') + this.patch + .watch$('server-info', 'status-info', 'backing-up') .pipe() - .subscribe(status => { - if (status === ServerStatus.BackingUp) { + .subscribe(isBackingUp => { + if (isBackingUp) { if (!this.backingUp) { this.backingUp = true this.subscribeToBackup() @@ -49,15 +64,20 @@ export class ServerBackupPage { ] } - ngOnDestroy () { + ngOnDestroy() { this.subs.forEach(sub => sub.unsubscribe()) this.pkgs.forEach(pkg => pkg.sub.unsubscribe()) } - async presentModalPassword (target: MappedBackupTarget): Promise { - let message = 'Enter your master password to create an encrypted backup of your Embassy and all its services.' + async presentModalPassword( + target: MappedBackupTarget, + ): Promise { + let message = + 'Enter your master password to create an encrypted backup of your Embassy and all its services.' if (!target.hasValidBackup) { - message = message + ' Since this is a fresh backup, it could take a while. Future backups will likely be much faster.' + message = + message + + ' Since this is a fresh backup, it could take a while. Future backups will likely be much faster.' } const options: GenericInputOptions = { @@ -79,7 +99,11 @@ export class ServerBackupPage { await m.present() } - private async test (target: MappedBackupTarget, password: string, oldPassword?: string): Promise { + private async test( + target: MappedBackupTarget, + password: string, + oldPassword?: string, + ): Promise { const passwordHash = this.patch.getData()['server-info']['password-hash'] argon2.verify(passwordHash, password) @@ -87,7 +111,10 @@ export class ServerBackupPage { await this.createBackup(target.id, password) } else { try { - argon2.verify(target.entry['embassy-os']['password-hash'], oldPassword || password) + argon2.verify( + target.entry['embassy-os']['password-hash'], + oldPassword || password, + ) await this.createBackup(target.id, password) } catch (e) { if (oldPassword) { @@ -99,15 +126,20 @@ export class ServerBackupPage { } } - private async presentModalOldPassword (target: MappedBackupTarget, password: string): Promise { + private async presentModalOldPassword( + target: MappedBackupTarget, + password: string, + ): Promise { const options: GenericInputOptions = { title: 'Original Password Needed', - message: 'This backup was created with a different password. Enter the ORIGINAL password that was used to encrypt this backup.', + message: + 'This backup was created with a different password. Enter the ORIGINAL password that was used to encrypt this backup.', label: 'Original Password', placeholder: 'Enter original password', useMask: true, buttonText: 'Create Backup', - submitFn: (oldPassword: string) => this.test(target, password, oldPassword), + submitFn: (oldPassword: string) => + this.test(target, password, oldPassword), } const m = await this.modalCtrl.create({ @@ -119,7 +151,11 @@ export class ServerBackupPage { await m.present() } - private async createBackup (id: string, password: string, oldPassword?: string): Promise { + private async createBackup( + id: string, + password: string, + oldPassword?: string, + ): Promise { const loader = await this.loadingCtrl.create({ spinner: 'lines', message: 'Beginning backup...', @@ -138,43 +174,56 @@ export class ServerBackupPage { } } - private subscribeToBackup () { - this.patch.watch$('package-data') - .pipe( - take(1), - ) - .subscribe(pkgs => { - const pkgArr = Object.keys(pkgs).sort().map(key => pkgs[key]) - const activeIndex = pkgArr.findIndex(pkg => pkg.installed.status.main.status === PackageMainStatus.BackingUp) + private subscribeToBackup() { + this.patch + .watch$('package-data') + .pipe(take(1)) + .subscribe(pkgs => { + const pkgArr = Object.keys(pkgs) + .sort() + .map(key => pkgs[key]) + const activeIndex = pkgArr.findIndex( + pkg => + pkg.installed.status.main.status === PackageMainStatus.BackingUp, + ) - this.pkgs = pkgArr.map((pkg, i) => { - const pkgInfo = { - entry: pkg, - active: i === activeIndex, - complete: i < activeIndex, - sub: null, - } - return pkgInfo - }) - - // subscribe to pkg - this.pkgs.forEach(pkg => { - pkg.sub = this.patch.watch$('package-data', pkg.entry.manifest.id, 'installed', 'status', 'main', 'status').subscribe(status => { - if (status === PackageMainStatus.BackingUp) { - pkg.active = true - } else if (pkg.active) { - pkg.active = false - pkg.complete = true + this.pkgs = pkgArr.map((pkg, i) => { + const pkgInfo = { + entry: pkg, + active: i === activeIndex, + complete: i < activeIndex, + sub: null, } + return pkgInfo + }) + + // subscribe to pkg + this.pkgs.forEach(pkg => { + pkg.sub = this.patch + .watch$( + 'package-data', + pkg.entry.manifest.id, + 'installed', + 'status', + 'main', + 'status', + ) + .subscribe(status => { + if (status === PackageMainStatus.BackingUp) { + pkg.active = true + } else if (pkg.active) { + pkg.active = false + pkg.complete = true + } + }) }) }) - }) } } interface PkgInfo { - entry: PackageDataEntry, + entry: PackageDataEntry active: boolean - complete: boolean, - sub: Subscription, + complete: boolean + sub: Subscription } diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html index 2c9b68f85..9f877504b 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html +++ b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html @@ -41,16 +41,18 @@

- + Last Backup: {{ patch.data['server-info']['last-backup'] ? (patch.data['server-info']['last-backup'] | date: 'short') : 'never' }} - + - [ServerStatus.Updated, ServerStatus.BackingUp].includes(status), - ), + map(status => status['backing-up'] || !!status['update-progress']), ), }, ], diff --git a/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts index 16ed61a59..916d08dff 100644 --- a/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts @@ -25,22 +25,22 @@ export class MockApiService extends ApiService { private readonly revertTime = 4000 sequence: number - constructor(private readonly bootstrapper: LocalStorageBootstrap) { + constructor (private readonly bootstrapper: LocalStorageBootstrap) { super() } - async getStatic(url: string): Promise { + async getStatic (url: string): Promise { await pauseFor(2000) return markdown } // db - async getRevisions(since: number): Promise { + async getRevisions (since: number): Promise { return this.getDump() } - async getDump(): Promise { + async getDump (): Promise { const cache = await this.bootstrapper.init() return { id: cache.sequence, @@ -49,7 +49,7 @@ export class MockApiService extends ApiService { } } - async setDbValueRaw(params: RR.SetDBValueReq): Promise { + async setDbValueRaw (params: RR.SetDBValueReq): Promise { await pauseFor(2000) const patch = [ { @@ -63,7 +63,7 @@ export class MockApiService extends ApiService { // auth - async login(params: RR.LoginReq): Promise { + async login (params: RR.LoginReq): Promise { await pauseFor(2000) setTimeout(() => { @@ -73,24 +73,24 @@ export class MockApiService extends ApiService { return null } - async logout(params: RR.LogoutReq): Promise { + async logout (params: RR.LogoutReq): Promise { await pauseFor(2000) return null } - async getSessions(params: RR.GetSessionsReq): Promise { + async getSessions (params: RR.GetSessionsReq): Promise { await pauseFor(2000) return Mock.Sessions } - async killSessions(params: RR.KillSessionsReq): Promise { + async killSessions (params: RR.KillSessionsReq): Promise { await pauseFor(2000) return null } // server - async getServerLogs( + async getServerLogs ( params: RR.GetServerLogsReq, ): Promise { await pauseFor(2000) @@ -112,21 +112,21 @@ export class MockApiService extends ApiService { } } - async getServerMetrics( + async getServerMetrics ( params: RR.GetServerMetricsReq, ): Promise { await pauseFor(2000) return Mock.getServerMetrics() } - async getPkgMetrics( + async getPkgMetrics ( params: RR.GetServerMetricsReq, ): Promise { await pauseFor(2000) return Mock.getAppMetrics() } - async updateServerRaw( + async updateServerRaw ( params: RR.UpdateServerReq, ): Promise { await pauseFor(2000) @@ -142,7 +142,7 @@ export class MockApiService extends ApiService { const patch = [ { op: PatchOp.REPLACE, - path: '/server-info/update-progress', + path: '/server-info/status-info/update-progress', value: initialProgress, }, ] @@ -150,21 +150,21 @@ export class MockApiService extends ApiService { return this.withRevision(patch, 'updating') } - async restartServer( + async restartServer ( params: RR.RestartServerReq, ): Promise { await pauseFor(2000) return null } - async shutdownServer( + async shutdownServer ( params: RR.ShutdownServerReq, ): Promise { await pauseFor(2000) return null } - async systemRebuild( + async systemRebuild ( params: RR.RestartServerReq, ): Promise { await pauseFor(2000) @@ -173,7 +173,7 @@ export class MockApiService extends ApiService { // marketplace URLs - async marketplaceProxy(path: string, params: {}, url: string): Promise { + async marketplaceProxy (path: string, params: {}, url: string): Promise { await pauseFor(2000) if (path === '/package/v0/info') { @@ -196,7 +196,7 @@ export class MockApiService extends ApiService { } } - async getEos( + async getEos ( params: RR.GetMarketplaceEOSReq, ): Promise { await pauseFor(2000) @@ -211,7 +211,7 @@ export class MockApiService extends ApiService { // notification - async getNotificationsRaw( + async getNotificationsRaw ( params: RR.GetNotificationsReq, ): Promise { await pauseFor(2000) @@ -226,14 +226,14 @@ export class MockApiService extends ApiService { return this.withRevision(patch, Mock.Notifications) } - async deleteNotification( + async deleteNotification ( params: RR.DeleteNotificationReq, ): Promise { await pauseFor(2000) return null } - async deleteAllNotifications( + async deleteAllNotifications ( params: RR.DeleteAllNotificationsReq, ): Promise { await pauseFor(2000) @@ -242,60 +242,60 @@ export class MockApiService extends ApiService { // wifi - async getWifi(params: RR.GetWifiReq): Promise { + async getWifi (params: RR.GetWifiReq): Promise { await pauseFor(2000) return Mock.Wifi } - async setWifiCountry( + async setWifiCountry ( params: RR.SetWifiCountryReq, ): Promise { await pauseFor(2000) return null } - async addWifi(params: RR.AddWifiReq): Promise { + async addWifi (params: RR.AddWifiReq): Promise { await pauseFor(2000) return null } - async connectWifi(params: RR.ConnectWifiReq): Promise { + async connectWifi (params: RR.ConnectWifiReq): Promise { await pauseFor(2000) return null } - async deleteWifi(params: RR.DeleteWifiReq): Promise { + async deleteWifi (params: RR.DeleteWifiReq): Promise { await pauseFor(2000) return null } // ssh - async getSshKeys(params: RR.GetSSHKeysReq): Promise { + async getSshKeys (params: RR.GetSSHKeysReq): Promise { await pauseFor(2000) return Mock.SshKeys } - async addSshKey(params: RR.AddSSHKeyReq): Promise { + async addSshKey (params: RR.AddSSHKeyReq): Promise { await pauseFor(2000) return Mock.SshKey } - async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise { + async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise { await pauseFor(2000) return null } // backup - async getBackupTargets( + async getBackupTargets ( params: RR.GetBackupTargetsReq, ): Promise { await pauseFor(2000) return Mock.BackupTargets } - async addBackupTarget( + async addBackupTarget ( params: RR.AddBackupTargetReq, ): Promise { await pauseFor(2000) @@ -312,7 +312,7 @@ export class MockApiService extends ApiService { } } - async updateBackupTarget( + async updateBackupTarget ( params: RR.UpdateBackupTargetReq, ): Promise { await pauseFor(2000) @@ -327,21 +327,21 @@ export class MockApiService extends ApiService { } } - async removeBackupTarget( + async removeBackupTarget ( params: RR.RemoveBackupTargetReq, ): Promise { await pauseFor(2000) return null } - async getBackupInfo( + async getBackupInfo ( params: RR.GetBackupInfoReq, ): Promise { await pauseFor(2000) return Mock.BackupInfo } - async createBackupRaw( + async createBackupRaw ( params: RR.CreateBackupReq, ): Promise { await pauseFor(2000) @@ -392,14 +392,14 @@ export class MockApiService extends ApiService { // package - async getPackageProperties( + async getPackageProperties ( params: RR.GetPackagePropertiesReq, ): Promise['data']> { await pauseFor(2000) return parsePropertiesPermissive(Mock.PackageProperties) } - async getPackageLogs( + async getPackageLogs ( params: RR.GetPackageLogsReq, ): Promise { await pauseFor(2000) @@ -421,7 +421,7 @@ export class MockApiService extends ApiService { } } - async installPackageRaw( + async installPackageRaw ( params: RR.InstallPackageReq, ): Promise { await pauseFor(2000) @@ -456,14 +456,14 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async dryUpdatePackage( + async dryUpdatePackage ( params: RR.DryUpdatePackageReq, ): Promise { await pauseFor(2000) return {} } - async getPackageConfig( + async getPackageConfig ( params: RR.GetPackageConfigReq, ): Promise { await pauseFor(2000) @@ -473,14 +473,14 @@ export class MockApiService extends ApiService { } } - async drySetPackageConfig( + async drySetPackageConfig ( params: RR.DrySetPackageConfigReq, ): Promise { await pauseFor(2000) return {} } - async setPackageConfigRaw( + async setPackageConfigRaw ( params: RR.SetPackageConfigReq, ): Promise { await pauseFor(2000) @@ -494,7 +494,7 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async restorePackagesRaw( + async restorePackagesRaw ( params: RR.RestorePackagesReq, ): Promise { await pauseFor(2000) @@ -530,14 +530,14 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async executePackageAction( + async executePackageAction ( params: RR.ExecutePackageActionReq, ): Promise { await pauseFor(2000) return Mock.ActionResponse } - async startPackageRaw( + async startPackageRaw ( params: RR.StartPackageReq, ): Promise { const path = `/package-data/${params.id}/installed/status/main` @@ -616,7 +616,7 @@ export class MockApiService extends ApiService { return this.withRevision(originalPatch) } - async dryStopPackage( + async dryStopPackage ( params: RR.DryStopPackageReq, ): Promise { await pauseFor(2000) @@ -630,7 +630,7 @@ export class MockApiService extends ApiService { } } - async stopPackageRaw(params: RR.StopPackageReq): Promise { + async stopPackageRaw (params: RR.StopPackageReq): Promise { await pauseFor(2000) const path = `/package-data/${params.id}/installed/status/main` @@ -661,14 +661,14 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async dryUninstallPackage( + async dryUninstallPackage ( params: RR.DryUninstallPackageReq, ): Promise { await pauseFor(2000) return {} } - async uninstallPackageRaw( + async uninstallPackageRaw ( params: RR.UninstallPackageReq, ): Promise { await pauseFor(2000) @@ -694,7 +694,7 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async deleteRecoveredPackageRaw( + async deleteRecoveredPackageRaw ( params: RR.DeleteRecoveredPackageReq, ): Promise { await pauseFor(2000) @@ -707,7 +707,7 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } - async dryConfigureDependency( + async dryConfigureDependency ( params: RR.DryConfigureDependencyReq, ): Promise { await pauseFor(2000) @@ -718,7 +718,7 @@ export class MockApiService extends ApiService { } } - private async updateProgress( + private async updateProgress ( id: string, initialProgress: InstallProgress, ): Promise { @@ -764,7 +764,7 @@ export class MockApiService extends ApiService { }, 1000) } - private async updateOSProgress(size: number) { + private async updateOSProgress (size: number) { let downloaded = 0 while (downloaded < size) { await pauseFor(250) @@ -772,7 +772,7 @@ export class MockApiService extends ApiService { const patch = [ { op: PatchOp.REPLACE, - path: `/server-info/update-progress/downloaded`, + path: `/server-info/status-info/update-progress/downloaded`, value: downloaded, }, ] @@ -782,7 +782,7 @@ export class MockApiService extends ApiService { const patch2 = [ { op: PatchOp.REPLACE, - path: `/server-info/update-progress/downloaded`, + path: `/server-info/status-info/update-progress/downloaded`, value: size, }, ] @@ -797,7 +797,7 @@ export class MockApiService extends ApiService { }, { op: PatchOp.REMOVE, - path: '/server-info/update-progress', + path: '/server-info/status-info/update-progress', }, ] this.updateMock(patch3) @@ -814,7 +814,7 @@ export class MockApiService extends ApiService { }, 1000) } - private async updateMock(patch: Operation[]): Promise { + private async updateMock (patch: Operation[]): Promise { if (!this.sequence) { const { sequence } = await this.bootstrapper.init() this.sequence = sequence @@ -827,7 +827,7 @@ export class MockApiService extends ApiService { this.mockPatch$.next(revision) } - private async withRevision( + private async withRevision ( patch: Operation[], response: T = null, ): Promise> { diff --git a/frontend/projects/ui/src/app/services/api/mock-patch.ts b/frontend/projects/ui/src/app/services/api/mock-patch.ts index ff975440a..014614577 100644 --- a/frontend/projects/ui/src/app/services/api/mock-patch.ts +++ b/frontend/projects/ui/src/app/services/api/mock-patch.ts @@ -21,13 +21,13 @@ export const mockPatchData: DataModel = { id: 'embassy-abcdefgh', version: '0.3.0', 'last-backup': null, - status: ServerStatus.Running, 'lan-address': 'https://embassy-abcdefgh.local', 'tor-address': 'http://myveryownspecialtoraddress.onion', 'unread-notification-count': 4, 'password-hash': '$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ', 'eos-version-compat': '>=0.3.0', + 'status-info': null, }, 'recovered-packages': { 'btc-rpc-proxy': { diff --git a/frontend/projects/ui/src/app/services/connection.service.ts b/frontend/projects/ui/src/app/services/connection.service.ts index 08c088173..821de96d4 100644 --- a/frontend/projects/ui/src/app/services/connection.service.ts +++ b/frontend/projects/ui/src/app/services/connection.service.ts @@ -1,5 +1,11 @@ import { Injectable } from '@angular/core' -import { BehaviorSubject, combineLatest, fromEvent, merge, Subscription } from 'rxjs' +import { + BehaviorSubject, + combineLatest, + fromEvent, + merge, + Subscription, +} from 'rxjs' import { PatchConnection, PatchDbService } from './patch-db/patch-db.service' import { distinctUntilChanged } from 'rxjs/operators' import { ConfigService } from './config.service' @@ -9,41 +15,37 @@ import { ConfigService } from './config.service' }) export class ConnectionService { private readonly networkState$ = new BehaviorSubject(true) - private readonly connectionFailure$ = new BehaviorSubject(ConnectionFailure.None) + private readonly connectionFailure$ = new BehaviorSubject( + ConnectionFailure.None, + ) - constructor ( + constructor( private readonly configService: ConfigService, private readonly patch: PatchDbService, - ) { } + ) {} - watchFailure$ () { + watchFailure$() { return this.connectionFailure$.asObservable() } - start (): Subscription[] { - const sub1 = merge(fromEvent(window, 'online'), fromEvent(window, 'offline')) - .subscribe(event => { + start(): Subscription[] { + const sub1 = merge( + fromEvent(window, 'online'), + fromEvent(window, 'offline'), + ).subscribe(event => { this.networkState$.next(event.type === 'online') }) const sub2 = combineLatest([ // 1 - this.networkState$ - .pipe( - distinctUntilChanged(), - ), + this.networkState$.pipe(distinctUntilChanged()), // 2 - this.patch.watchPatchConnection$() - .pipe( - distinctUntilChanged(), - ), + this.patch.watchPatchConnection$().pipe(distinctUntilChanged()), // 3 - this.patch.watch$('server-info', 'update-progress') - .pipe( - distinctUntilChanged(), - ), - ]) - .subscribe(async ([network, patchConnection, progress]) => { + this.patch + .watch$('server-info', 'status-info', 'update-progress') + .pipe(distinctUntilChanged()), + ]).subscribe(async ([network, patchConnection, progress]) => { if (!network) { this.connectionFailure$.next(ConnectionFailure.Network) } else if (patchConnection !== PatchConnection.Disconnected) { diff --git a/frontend/projects/ui/src/app/services/patch-db/data-model.ts b/frontend/projects/ui/src/app/services/patch-db/data-model.ts index 92207b471..e08d307a9 100644 --- a/frontend/projects/ui/src/app/services/patch-db/data-model.ts +++ b/frontend/projects/ui/src/app/services/patch-db/data-model.ts @@ -31,11 +31,11 @@ export interface ServerInfo { 'last-backup': string | null 'lan-address': URL 'tor-address': URL - status: ServerStatus 'unread-notification-count': number - 'update-progress'?: { - size: number - downloaded: number + 'status-info': { + 'backing-up': boolean + updated: boolean + 'update-progress': { size: number | null; downloaded: number } | null } 'eos-version-compat': string 'password-hash': string @@ -377,17 +377,17 @@ export interface DependencyInfo { export interface DependencyEntry { version: string requirement: - | { - type: 'opt-in' - how: string - } - | { - type: 'opt-out' - how: string - } - | { - type: 'required' - } + | { + type: 'opt-in' + how: string + } + | { + type: 'opt-out' + how: string + } + | { + type: 'required' + } description: string | null config: { check: ActionImpl