diff --git a/web/projects/setup-wizard/src/app/pages/loading.page.ts b/web/projects/setup-wizard/src/app/pages/loading.page.ts
index e65e791e7..c367968d5 100644
--- a/web/projects/setup-wizard/src/app/pages/loading.page.ts
+++ b/web/projects/setup-wizard/src/app/pages/loading.page.ts
@@ -1,20 +1,105 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
+import { toSignal } from '@angular/core/rxjs-interop'
import { Router } from '@angular/router'
-import { InitializingComponent } from '@start9labs/shared'
+import { ErrorService, InitializingComponent } from '@start9labs/shared'
+import { T } from '@start9labs/start-sdk'
+import {
+ catchError,
+ EMPTY,
+ filter,
+ from,
+ interval,
+ map,
+ startWith,
+ switchMap,
+ take,
+ tap,
+} from 'rxjs'
+import { ApiService } from 'src/app/services/api.service'
import { StateService } from 'src/app/services/state.service'
@Component({
standalone: true,
- template: `
-
- `,
+ template: '
',
+ styles: ':host { max-width: unset; align-items: stretch; }',
imports: [InitializingComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class LoadingPage {
- readonly stateService = inject(StateService)
+ private readonly api = inject(ApiService)
+ private readonly errorService = inject(ErrorService)
+
+ readonly type = inject(StateService).setupType
readonly router = inject(Router)
+ readonly progress = toSignal(
+ from(this.getStatus()).pipe(
+ filter(Boolean),
+ take(1),
+ switchMap(({ guid, progress }) =>
+ this.api.openProgressWebsocket$(guid).pipe(
+ startWith(progress),
+ catchError((_, watch$) =>
+ interval(2000).pipe(
+ switchMap(() =>
+ from(this.api.getStatus()).pipe(catchError(() => EMPTY)),
+ ),
+ take(1),
+ switchMap(() => watch$),
+ ),
+ ),
+ tap(({ overall }) => {
+ if (overall === true) {
+ this.getStatus()
+ }
+ }),
+ ),
+ ),
+ map(({ phases, overall }) => ({
+ total: getDecimal(overall),
+ message: phases
+ .filter(p => p.progress !== true && p.progress !== null)
+ .map(p => `${p.name}${getPhaseBytes(p.progress)}`)
+ .join(','),
+ })),
+ catchError(e => {
+ this.errorService.handleError(e)
+ return EMPTY
+ }),
+ ),
+ { initialValue: { total: 0, message: '' } },
+ )
+
+ private async getStatus(): Promise<{
+ status: 'running'
+ guid: string
+ progress: T.FullProgress
+ } | null> {
+ const res = await this.api.getStatus()
+
+ if (!res) {
+ this.router.navigate(['home'])
+ return null
+ } else if (res.status === 'complete') {
+ this.router.navigate(['success'])
+ return null
+ } else {
+ return res
+ }
+ }
+}
+
+function getDecimal(progress: T.Progress): number {
+ if (progress === true) {
+ return 1
+ } else if (!progress || !progress.total) {
+ return 0
+ } else {
+ return progress.total && progress.done / progress.total
+ }
+}
+
+function getPhaseBytes(progress: T.Progress): string {
+ return progress === true || !progress
+ ? ''
+ : `: (${progress.done}/${progress.total})`
}
diff --git a/web/projects/setup-wizard/src/app/pages/recover.page.ts b/web/projects/setup-wizard/src/app/pages/recover.page.ts
index 0a6647202..480e7269b 100644
--- a/web/projects/setup-wizard/src/app/pages/recover.page.ts
+++ b/web/projects/setup-wizard/src/app/pages/recover.page.ts
@@ -1,6 +1,7 @@
+import { DatePipe } from '@angular/common'
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
-import { DriveComponent, ErrorService } from '@start9labs/shared'
+import { ErrorService } from '@start9labs/shared'
import {
TuiButton,
TuiDialogService,
@@ -9,15 +10,9 @@ import {
TuiTitle,
} from '@taiga-ui/core'
import { TuiCardLarge, TuiCell } from '@taiga-ui/layout'
-import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
-import { filter } from 'rxjs'
-import { CifsComponent } from 'src/app/components/cifs.component'
-import { PASSWORD } from 'src/app/components/password.component'
-import {
- ApiService,
- CifsRecoverySource,
- DiskBackupTarget,
-} from 'src/app/services/api.service'
+import { CIFS, CifsResponse } from 'src/app/components/cifs.component'
+import { ServerComponent } from 'src/app/components/server.component'
+import { ApiService, StartOSDiskInfoFull } from 'src/app/services/api.service'
import { StateService } from 'src/app/services/state.service'
@Component({
@@ -38,8 +33,10 @@ import { StateService } from 'src/app/services/state.service'
Physical Drive
- Restore StartOS data from a physical drive that is plugged directly into
- your server.
+
+ Restore StartOS data from a physical drive that is plugged directly
+ into your server.
+
Warning. Do not use this option if you are using a Raspberry Pi with
an external SSD as your main data drive. The Raspberry Pi cannot not
@@ -47,18 +44,11 @@ import { StateService } from 'src/app/services/state.service'
cause data corruption.
- @for (d of drives; track d) {
-
+ @for (server of servers; track $index) {
+
}
}
-