mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
better transfer progress (#2350)
* better transfer progress * frontend for calculating transfer size * fixes from testing * improve internal api --------- Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
@@ -2,15 +2,12 @@
|
||||
<ion-grid>
|
||||
<ion-row class="ion-align-items-center">
|
||||
<ion-col class="ion-text-center">
|
||||
<ion-card
|
||||
*ngIf="{ decimal: progress$ | async } as progress"
|
||||
color="dark"
|
||||
>
|
||||
<ion-card *ngIf="progress$ | async as progress" color="dark">
|
||||
<ion-card-header>
|
||||
<ion-card-title>Initializing StartOS</ion-card-title>
|
||||
<div class="center-wrapper">
|
||||
<ion-card-subtitle *ngIf="progress.decimal as decimal">
|
||||
Progress: {{ (decimal * 100).toFixed(0)}}%
|
||||
<ion-card-subtitle>
|
||||
{{ progress.transferred | toMessage }}
|
||||
</ion-card-subtitle>
|
||||
</div>
|
||||
</ion-card-header>
|
||||
@@ -18,16 +15,22 @@
|
||||
<ion-card-content class="ion-margin">
|
||||
<ion-progress-bar
|
||||
color="tertiary"
|
||||
style="
|
||||
max-width: 700px;
|
||||
margin: auto;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 40px;
|
||||
"
|
||||
[type]="progress.decimal && progress.decimal < 1 ? 'determinate' : 'indeterminate'"
|
||||
[value]="progress.decimal || 0"
|
||||
style="max-width: 700px; margin: auto; margin-bottom: 36px"
|
||||
[type]="progress.transferred && progress.transferred < 1 ? 'determinate' : 'indeterminate'"
|
||||
[value]="progress.transferred || 0"
|
||||
></ion-progress-bar>
|
||||
<p>{{ progress.decimal | toMessage }}</p>
|
||||
<p>
|
||||
<ng-container *ngIf="progress.totalBytes as total">
|
||||
<ng-container
|
||||
*ngIf="progress.transferred as transferred; else calculating"
|
||||
>
|
||||
Progress: {{ (transferred * 100).toFixed() }}%
|
||||
</ng-container>
|
||||
<ng-template #calculating>
|
||||
{{ (progress.totalBytes / 1073741824).toFixed(2) }} GB
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</p>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
|
||||
@@ -2,6 +2,14 @@ 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 { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService, pauseFor } from '@start9labs/shared'
|
||||
|
||||
type Progress = {
|
||||
totalBytes: number | null
|
||||
transferred: number
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-loading',
|
||||
@@ -9,23 +17,49 @@ import { Pipe, PipeTransform } from '@angular/core'
|
||||
styleUrls: ['loading.page.scss'],
|
||||
})
|
||||
export class LoadingPage {
|
||||
readonly progress$ = this.stateService.dataProgress$
|
||||
readonly progress$ = new BehaviorSubject<Progress>({
|
||||
totalBytes: null,
|
||||
transferred: 0,
|
||||
})
|
||||
|
||||
constructor(
|
||||
private readonly stateService: StateService,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly api: ApiService,
|
||||
private readonly errorToastService: ErrorToastService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.stateService.pollDataTransferProgress()
|
||||
const progSub = this.stateService.dataCompletionSubject$.subscribe(
|
||||
async complete => {
|
||||
if (complete) {
|
||||
progSub.unsubscribe()
|
||||
await this.navCtrl.navigateForward(`/success`)
|
||||
}
|
||||
},
|
||||
)
|
||||
this.poll()
|
||||
}
|
||||
|
||||
async poll() {
|
||||
try {
|
||||
const progress = await this.api.getStatus()
|
||||
|
||||
if (!progress) return
|
||||
|
||||
const {
|
||||
'total-bytes': totalBytes,
|
||||
'bytes-transferred': 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +75,7 @@ export class ToMessagePipe implements PipeTransform {
|
||||
}
|
||||
|
||||
if (!progress) {
|
||||
return 'Preparing data. This can take a while'
|
||||
return 'Calculating size'
|
||||
} else if (progress < 1) {
|
||||
return 'Copying data'
|
||||
} else {
|
||||
|
||||
@@ -17,8 +17,6 @@ let tries: number
|
||||
export class MockApiService extends ApiService {
|
||||
async getStatus() {
|
||||
const restoreOrMigrate = true
|
||||
const total = 4
|
||||
|
||||
await pauseFor(1000)
|
||||
|
||||
if (tries === undefined) {
|
||||
@@ -27,7 +25,9 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
tries++
|
||||
const progress = tries - 1
|
||||
|
||||
const total = tries <= 4 ? tries * 268435456 : 1073741824
|
||||
const progress = tries > 4 ? (tries - 4) * 268435456 : 0
|
||||
|
||||
return {
|
||||
'bytes-transferred': restoreOrMigrate ? progress : 0,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import { ApiService, RecoverySource } from './api/api.service'
|
||||
import { pauseFor, ErrorToastService } from '@start9labs/shared'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -12,47 +10,7 @@ export class StateService {
|
||||
recoverySource?: RecoverySource
|
||||
recoveryPassword?: string
|
||||
|
||||
dataTransferProgress?: {
|
||||
bytesTransferred: number
|
||||
totalBytes: number | null
|
||||
complete: boolean
|
||||
}
|
||||
dataProgress$ = new BehaviorSubject<number>(0)
|
||||
dataCompletionSubject$ = new BehaviorSubject(false)
|
||||
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly errorToastService: ErrorToastService,
|
||||
) {}
|
||||
|
||||
async pollDataTransferProgress() {
|
||||
await pauseFor(500)
|
||||
|
||||
if (this.dataTransferProgress?.complete) {
|
||||
this.dataCompletionSubject$.next(true)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const progress = await this.api.getStatus()
|
||||
if (!progress) return
|
||||
|
||||
this.dataTransferProgress = {
|
||||
bytesTransferred: progress['bytes-transferred'],
|
||||
totalBytes: progress['total-bytes'],
|
||||
complete: progress.complete,
|
||||
}
|
||||
if (this.dataTransferProgress.totalBytes) {
|
||||
this.dataProgress$.next(
|
||||
this.dataTransferProgress.bytesTransferred /
|
||||
this.dataTransferProgress.totalBytes,
|
||||
)
|
||||
}
|
||||
} catch (e: any) {
|
||||
this.errorToastService.present(e)
|
||||
}
|
||||
setTimeout(() => this.pollDataTransferProgress(), 0) // prevent call stack from growing
|
||||
}
|
||||
constructor(private readonly api: ApiService) {}
|
||||
|
||||
async importDrive(guid: string, password: string): Promise<void> {
|
||||
await this.api.attach({
|
||||
|
||||
Reference in New Issue
Block a user