mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
Feat/combine uis (#2633)
* wip * restructure backend for new ui structure * new patchdb bootstrap, single websocket api, local storage migration, more * update db websocket * init apis * update patch-db * setup progress * feat: implement state service, alert and routing Signed-off-by: waterplea <alexander@inkin.ru> * update setup wizard for new types * feat: add init page Signed-off-by: waterplea <alexander@inkin.ru> * chore: refactor message, patch-db source stream and connection service Signed-off-by: waterplea <alexander@inkin.ru> * fix method not found on state * fix backend bugs * fix compat assets * address comments * remove unneeded styling * cleaner progress * bugfixes * fix init logs * fix progress reporting * fix navigation by getting state after init * remove patch dependency from live api * fix caching * re-add patchDB to live api * fix metrics values * send close frame * add bootId and fix polling --------- Signed-off-by: waterplea <alexander@inkin.ru> Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: waterplea <alexander@inkin.ru>
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { NavController } from '@ionic/angular'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import {
|
||||
EMPTY,
|
||||
Observable,
|
||||
catchError,
|
||||
filter,
|
||||
from,
|
||||
interval,
|
||||
map,
|
||||
of,
|
||||
startWith,
|
||||
switchMap,
|
||||
take,
|
||||
tap,
|
||||
} from 'rxjs'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService, pauseFor } from '@start9labs/shared'
|
||||
|
||||
type Progress = {
|
||||
totalBytes: number | null
|
||||
transferred: number
|
||||
}
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
@Component({
|
||||
selector: 'app-loading',
|
||||
@@ -17,10 +25,46 @@ type Progress = {
|
||||
styleUrls: ['loading.page.scss'],
|
||||
})
|
||||
export class LoadingPage {
|
||||
readonly progress$ = new BehaviorSubject<Progress>({
|
||||
totalBytes: null,
|
||||
transferred: 0,
|
||||
})
|
||||
readonly progress$ = this.getRunningStatus$().pipe(
|
||||
switchMap(res =>
|
||||
this.api.openProgressWebsocket$(res.guid).pipe(
|
||||
startWith(res.progress),
|
||||
catchError((_, watch$) => {
|
||||
return interval(2000).pipe(
|
||||
switchMap(() =>
|
||||
from(this.api.getStatus()).pipe(catchError(() => EMPTY)),
|
||||
),
|
||||
take(1),
|
||||
switchMap(() => watch$),
|
||||
)
|
||||
}),
|
||||
tap(progress => {
|
||||
if (progress.overall === true) {
|
||||
this.getStatus()
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
map(({ phases, overall }) => {
|
||||
return {
|
||||
total: getDecimal(overall),
|
||||
message: phases
|
||||
.filter(
|
||||
(
|
||||
p,
|
||||
): p is {
|
||||
name: string
|
||||
progress: {
|
||||
done: number
|
||||
total: number | null
|
||||
}
|
||||
} => p.progress !== true && p.progress !== null,
|
||||
)
|
||||
.map(p => `${p.name}${getPhaseBytes(p.progress)}`)
|
||||
.join(','),
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
constructor(
|
||||
private readonly navCtrl: NavController,
|
||||
@@ -28,55 +72,55 @@ export class LoadingPage {
|
||||
private readonly errorToastService: ErrorToastService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.poll()
|
||||
}
|
||||
private async getStatus(): Promise<{
|
||||
status: 'running'
|
||||
guid: string
|
||||
progress: T.FullProgress
|
||||
} | void> {
|
||||
const res = await this.api.getStatus()
|
||||
|
||||
async poll() {
|
||||
try {
|
||||
const progress = await this.api.getStatus()
|
||||
|
||||
if (!progress) return
|
||||
|
||||
const { totalBytes, bytesTransferred } = progress
|
||||
|
||||
this.progress$.next({
|
||||
totalBytes,
|
||||
transferred: totalBytes ? bytesTransferred / totalBytes : 0,
|
||||
})
|
||||
|
||||
if (progress.complete) {
|
||||
this.navCtrl.navigateForward(`/success`)
|
||||
this.progress$.complete()
|
||||
return
|
||||
}
|
||||
|
||||
await pauseFor(250)
|
||||
|
||||
setTimeout(() => this.poll(), 0) // prevent call stack from growing
|
||||
} catch (e: any) {
|
||||
this.errorToastService.present(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'toMessage',
|
||||
})
|
||||
export class ToMessagePipe implements PipeTransform {
|
||||
constructor(private readonly stateService: StateService) {}
|
||||
|
||||
transform(progress: number | null): string {
|
||||
if (['fresh', 'attach'].includes(this.stateService.setupType || '')) {
|
||||
return 'Setting up your server'
|
||||
}
|
||||
|
||||
if (!progress) {
|
||||
return 'Calculating size'
|
||||
} else if (progress < 1) {
|
||||
return 'Copying data'
|
||||
if (!res) {
|
||||
this.navCtrl.navigateRoot('/home')
|
||||
} else if (res.status === 'complete') {
|
||||
this.navCtrl.navigateForward(`/success`)
|
||||
} else {
|
||||
return 'Finalizing'
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
private getRunningStatus$(): Observable<{
|
||||
status: 'running'
|
||||
guid: string
|
||||
progress: T.FullProgress
|
||||
}> {
|
||||
return from(this.getStatus()).pipe(
|
||||
filter(Boolean),
|
||||
catchError(e => {
|
||||
this.errorToastService.present(e)
|
||||
return of(e)
|
||||
}),
|
||||
take(1),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
| false
|
||||
| {
|
||||
done: number
|
||||
total: number | null
|
||||
},
|
||||
): string {
|
||||
return progress === false ? '' : `: (${progress.done}/${progress.total})`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user