mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
chore: refactor install and setup wizards (#2561)
* chore: refactor install and setup wizards * chore: return tui-root
This commit is contained in:
182
web/projects/setup-wizard/src/app/pages/storage.page.ts
Normal file
182
web/projects/setup-wizard/src/app/pages/storage.page.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { Component, inject } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import {
|
||||
DiskInfo,
|
||||
DriveComponent,
|
||||
ErrorService,
|
||||
LoadingService,
|
||||
toGuid,
|
||||
} from '@start9labs/shared'
|
||||
import { TuiDialogService, TuiLoaderModule } from '@taiga-ui/core'
|
||||
import {
|
||||
TuiButtonModule,
|
||||
TuiCardModule,
|
||||
TuiCellModule,
|
||||
} from '@taiga-ui/experimental'
|
||||
import { TUI_PROMPT } from '@taiga-ui/kit'
|
||||
import { filter, of, switchMap } from 'rxjs'
|
||||
import { PASSWORD } from 'src/app/components/password.component'
|
||||
import {
|
||||
ApiService,
|
||||
BackupRecoverySource,
|
||||
DiskMigrateSource,
|
||||
DiskRecoverySource,
|
||||
} from 'src/app/services/api.service'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
template: `
|
||||
<section tuiCardLarge>
|
||||
@if (loading || drives.length) {
|
||||
<header>Select storage drive</header>
|
||||
This is the drive where your StartOS data will be stored.
|
||||
} @else {
|
||||
<header>No drives found</header>
|
||||
Please connect a storage drive to your server. Then click "Refresh".
|
||||
}
|
||||
|
||||
@if (loading) {
|
||||
<tui-loader />
|
||||
}
|
||||
|
||||
@for (d of drives; track d) {
|
||||
<button tuiCell [drive]="d" [disabled]="isSmall(d)" (click)="select(d)">
|
||||
@if (isSmall(d)) {
|
||||
<span tuiSubtitle class="g-error">Drive capacity too small</span>
|
||||
}
|
||||
</button>
|
||||
}
|
||||
|
||||
<button tuiButton iconLeft="tuiIconRotateCwLarge" (click)="getDrives()">
|
||||
Refresh
|
||||
</button>
|
||||
</section>
|
||||
`,
|
||||
imports: [
|
||||
TuiCardModule,
|
||||
TuiLoaderModule,
|
||||
TuiCellModule,
|
||||
TuiButtonModule,
|
||||
DriveComponent,
|
||||
],
|
||||
})
|
||||
export default class StoragePage {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly router = inject(Router)
|
||||
private readonly dialogs = inject(TuiDialogService)
|
||||
private readonly stateService = inject(StateService)
|
||||
private readonly loader = inject(LoadingService)
|
||||
private readonly errorService = inject(ErrorService)
|
||||
|
||||
drives: DiskInfo[] = []
|
||||
loading = true
|
||||
|
||||
async ngOnInit() {
|
||||
await this.getDrives()
|
||||
}
|
||||
|
||||
isSmall({ capacity }: DiskInfo) {
|
||||
return capacity < 34359738368
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
this.loading = true
|
||||
await this.getDrives()
|
||||
}
|
||||
|
||||
async getDrives() {
|
||||
this.loading = true
|
||||
try {
|
||||
const disks = await this.api.getDrives()
|
||||
if (this.stateService.setupType === 'fresh') {
|
||||
this.drives = disks
|
||||
} else if (this.stateService.setupType === 'restore') {
|
||||
this.drives = disks.filter(
|
||||
d =>
|
||||
!d.partitions
|
||||
.map(p => p.logicalname)
|
||||
.includes(
|
||||
(
|
||||
(this.stateService.recoverySource as BackupRecoverySource)
|
||||
?.target as DiskRecoverySource
|
||||
)?.logicalname,
|
||||
),
|
||||
)
|
||||
} else if (this.stateService.setupType === 'transfer') {
|
||||
const guid = (this.stateService.recoverySource as DiskMigrateSource)
|
||||
.guid
|
||||
this.drives = disks.filter(d => {
|
||||
return (
|
||||
d.guid !== guid && !d.partitions.map(p => p.guid).includes(guid)
|
||||
)
|
||||
})
|
||||
}
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
select(drive: DiskInfo) {
|
||||
of(!toGuid(drive) && !drive.partitions.some(p => p.used))
|
||||
.pipe(
|
||||
switchMap(unused =>
|
||||
unused
|
||||
? of(true)
|
||||
: this.dialogs.open(TUI_PROMPT, {
|
||||
label: 'Warning',
|
||||
size: 's',
|
||||
data: {
|
||||
content:
|
||||
'<strong>Drive contains data!</strong><p>All data stored on this drive will be permanently deleted.</p>',
|
||||
yes: 'Continue',
|
||||
no: 'Cancel',
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => {
|
||||
// for backup recoveries
|
||||
if (this.stateService.recoveryPassword) {
|
||||
this.setupEmbassy(
|
||||
drive.logicalname,
|
||||
this.stateService.recoveryPassword,
|
||||
)
|
||||
} else {
|
||||
// for migrations and fresh setups
|
||||
this.presentModalPassword(drive.logicalname)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private presentModalPassword(logicalname: string) {
|
||||
this.dialogs
|
||||
.open<string>(PASSWORD, {
|
||||
label: 'Set Password',
|
||||
size: 's',
|
||||
data: { storageDrive: true },
|
||||
})
|
||||
.subscribe(password => {
|
||||
this.setupEmbassy(logicalname, password)
|
||||
})
|
||||
}
|
||||
|
||||
private async setupEmbassy(
|
||||
logicalname: string,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
const loader = this.loader.open('Connecting to drive...').subscribe()
|
||||
|
||||
try {
|
||||
await this.stateService.setupEmbassy(logicalname, password)
|
||||
await this.router.navigate([`loading`])
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
loader.unsubscribe()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user