mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/diagnostic repair disk (#1358)
* add disk repair actions to diagnostic ui and server menu * only display repair disk button when activated * fix typo * add repairDrive fn with restart to diagnostic ui * fix copy * add alert before repairing disk in diagnostic ui * fix repair disk message spacing and hidden display * fix version comparisons and enable dismissable refresh modal * eager load medkit and fix storefront to outline icon
This commit is contained in:
@@ -162,6 +162,7 @@
|
||||
<ion-icon name="logo-bitcoin"></ion-icon>
|
||||
<ion-icon name="mail-outline"></ion-icon>
|
||||
<ion-icon name="map-outline"></ion-icon>
|
||||
<ion-icon name="medkit-outline"></ion-icon>
|
||||
<ion-icon name="newspaper-outline"></ion-icon>
|
||||
<ion-icon name="notifications-outline"></ion-icon>
|
||||
<ion-icon name="options-outline"></ion-icon>
|
||||
|
||||
@@ -396,7 +396,7 @@ export class AppComponent {
|
||||
|
||||
private async presentAlertRefreshNeeded() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
backdropDismiss: false,
|
||||
backdropDismiss: true,
|
||||
header: 'Refresh Needed',
|
||||
message:
|
||||
'Your user interface is cached and out of date. Hard refresh the page to get the latest UI.',
|
||||
|
||||
@@ -56,8 +56,6 @@ export class BackupService {
|
||||
}
|
||||
|
||||
hasValidBackup(target: BackupTarget): boolean {
|
||||
return [0, 1].includes(
|
||||
this.emver.compare(target['embassy-os']?.version, '0.3.0'),
|
||||
)
|
||||
return this.emver.compare(target['embassy-os']?.version, '0.3.0') !== -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,73 +24,83 @@
|
||||
<ng-template #data>
|
||||
<ion-item-group>
|
||||
<div *ngFor="let cat of settings | keyvalue : asIsOrder">
|
||||
<ion-item-divider
|
||||
><ion-text color="dark">{{ cat.key }}</ion-text></ion-item-divider
|
||||
>
|
||||
<ion-item
|
||||
button
|
||||
*ngFor="let button of cat.value"
|
||||
[detail]="button.detail"
|
||||
[disabled]="button.disabled | async"
|
||||
(click)="button.action()"
|
||||
>
|
||||
<ion-icon slot="start" [name]="button.icon"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ button.title }}</h2>
|
||||
<p *ngIf="button.description">{{ button.description }}</p>
|
||||
<ion-item-divider>
|
||||
<ion-text color="dark" *ngIf="cat.key !== 'Power'"
|
||||
>{{ cat.key }}</ion-text
|
||||
>
|
||||
<ion-text
|
||||
color="dark"
|
||||
*ngIf="cat.key === 'Power'"
|
||||
(click)="addClick()"
|
||||
>{{ cat.key }}</ion-text
|
||||
>
|
||||
</ion-item-divider>
|
||||
<ng-container *ngFor="let button of cat.value">
|
||||
<ion-item
|
||||
button
|
||||
[style.display]="(button.title === 'Repair Disk' && !(localStorageService.showDiskRepair$ | async)) ? 'none' : 'block'"
|
||||
[detail]="button.detail"
|
||||
[disabled]="button.disabled | async"
|
||||
(click)="button.action()"
|
||||
>
|
||||
<ion-icon slot="start" [name]="button.icon"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ button.title }}</h2>
|
||||
<p *ngIf="button.description">{{ button.description }}</p>
|
||||
|
||||
<!-- "Create Backup" button only -->
|
||||
<p *ngIf="button.title === 'Create Backup'">
|
||||
<ng-container
|
||||
*ngIf="patch.data['server-info']['status-info'] as statusInfo"
|
||||
>
|
||||
<ion-text
|
||||
color="warning"
|
||||
*ngIf="!statusInfo['backing-up'] && !statusInfo['update-progress']"
|
||||
>
|
||||
Last Backup: {{ patch.data['server-info']['last-backup'] ?
|
||||
(patch.data['server-info']['last-backup'] | date: 'short') :
|
||||
'never' }}
|
||||
</ion-text>
|
||||
<span *ngIf="!!statusInfo['backing-up']" class="inline">
|
||||
<ion-spinner
|
||||
color="success"
|
||||
style="height: 12px; width: 12px; margin-right: 6px"
|
||||
></ion-spinner>
|
||||
<ion-text color="success"> Backing up </ion-text>
|
||||
</span>
|
||||
</ng-container>
|
||||
</p>
|
||||
<!-- "Software Update" button only -->
|
||||
<p *ngIf="button.title === 'Software Update'">
|
||||
<ng-container *ngIf="button.disabled | async; else enabled">
|
||||
<ion-text
|
||||
*ngIf="patch.data['server-info']['status-info'].updated"
|
||||
class="inline"
|
||||
color="warning"
|
||||
>
|
||||
Update Complete, Restart to apply changes
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #enabled>
|
||||
<!-- "Create Backup" button only -->
|
||||
<p *ngIf="button.title === 'Create Backup'">
|
||||
<ng-container
|
||||
*ngIf="eosService.updateAvailable$ | async; else check"
|
||||
*ngIf="patch.data['server-info']['status-info'] as statusInfo"
|
||||
>
|
||||
<ion-text class="inline" color="success">
|
||||
<ion-icon name="rocket-outline"></ion-icon>
|
||||
Update Available
|
||||
<ion-text
|
||||
color="warning"
|
||||
*ngIf="!statusInfo['backing-up'] && !statusInfo['update-progress']"
|
||||
>
|
||||
Last Backup: {{ patch.data['server-info']['last-backup'] ?
|
||||
(patch.data['server-info']['last-backup'] | date: 'short') :
|
||||
'never' }}
|
||||
</ion-text>
|
||||
<span *ngIf="!!statusInfo['backing-up']" class="inline">
|
||||
<ion-spinner
|
||||
color="success"
|
||||
style="height: 12px; width: 12px; margin-right: 6px"
|
||||
></ion-spinner>
|
||||
<ion-text color="success"> Backing up </ion-text>
|
||||
</span>
|
||||
</ng-container>
|
||||
</p>
|
||||
<!-- "Software Update" button only -->
|
||||
<p *ngIf="button.title === 'Software Update'">
|
||||
<ng-container *ngIf="button.disabled | async; else enabled">
|
||||
<ion-text
|
||||
*ngIf="patch.data['server-info']['status-info'].updated"
|
||||
class="inline"
|
||||
color="warning"
|
||||
>
|
||||
Update Complete, Restart to apply changes
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #check>
|
||||
<ion-text class="inline" color="dark">
|
||||
<ion-icon name="refresh"></ion-icon>
|
||||
Check for updates
|
||||
</ion-text>
|
||||
<ng-template #enabled>
|
||||
<ng-container
|
||||
*ngIf="eosService.updateAvailable$ | async; else check"
|
||||
>
|
||||
<ion-text class="inline" color="success">
|
||||
<ion-icon name="rocket-outline"></ion-icon>
|
||||
Update Available
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #check>
|
||||
<ion-text class="inline" color="dark">
|
||||
<ion-icon name="refresh"></ion-icon>
|
||||
Check for updates
|
||||
</ion-text>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ion-item-group>
|
||||
</ng-template>
|
||||
|
||||
@@ -16,6 +16,7 @@ import { wizardModal } from 'src/app/components/install-wizard/install-wizard.co
|
||||
import { exists, isEmptyObject, ErrorToastService } from '@start9labs/shared'
|
||||
import { EOSService } from 'src/app/services/eos.service'
|
||||
import { ServerStatus } from 'src/app/services/patch-db/data-model'
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service'
|
||||
|
||||
@Component({
|
||||
selector: 'server-show',
|
||||
@@ -25,6 +26,7 @@ import { ServerStatus } from 'src/app/services/patch-db/data-model'
|
||||
export class ServerShowPage {
|
||||
ServerStatus = ServerStatus
|
||||
hasRecoveredPackage: boolean
|
||||
clicks = 0
|
||||
|
||||
constructor(
|
||||
private readonly alertCtrl: AlertController,
|
||||
@@ -37,6 +39,7 @@ export class ServerShowPage {
|
||||
private readonly route: ActivatedRoute,
|
||||
public readonly eosService: EOSService,
|
||||
public readonly patch: PatchDbService,
|
||||
public readonly localStorageService: LocalStorageService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -143,6 +146,35 @@ export class ServerShowPage {
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
async presentAlertRepairDisk() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Repair Disk',
|
||||
message: new IonicSafeString(
|
||||
`<ion-text color="warning">Warning:</ion-text> <p>This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action.</p><p>If anything happens to the device during the reboot (between the bep and chime), such as loosing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem *will* be in an unrecoverable state. Please proceed with caution.</p>`,
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Repair',
|
||||
handler: () => {
|
||||
try {
|
||||
this.embassyApi.repairDisk({}).then(_ => {
|
||||
this.restart()
|
||||
})
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
}
|
||||
},
|
||||
cssClass: 'enter-click',
|
||||
},
|
||||
],
|
||||
})
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
private async restart() {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
@@ -305,7 +337,7 @@ export class ServerShowPage {
|
||||
{
|
||||
title: 'Marketplace Settings',
|
||||
description: 'Add or remove marketplaces',
|
||||
icon: 'storefront',
|
||||
icon: 'storefront-outline',
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['marketplaces'], {
|
||||
relativeTo: this.route,
|
||||
@@ -418,12 +450,31 @@ export class ServerShowPage {
|
||||
detail: false,
|
||||
disabled: of(false),
|
||||
},
|
||||
{
|
||||
title: 'Repair Disk',
|
||||
description: '',
|
||||
icon: 'medkit-outline',
|
||||
action: () => this.presentAlertRepairDisk(),
|
||||
detail: false,
|
||||
disabled: of(false),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
asIsOrder() {
|
||||
return 0
|
||||
}
|
||||
|
||||
async addClick() {
|
||||
this.clicks++
|
||||
if (this.clicks >= 5) {
|
||||
this.clicks = 0
|
||||
const newVal = await this.localStorageService.toggleShowDiskRepair()
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.clicks = Math.max(this.clicks - 1, 0)
|
||||
}, 10000)
|
||||
}
|
||||
}
|
||||
|
||||
interface ServerSettings {
|
||||
|
||||
@@ -93,6 +93,8 @@ export abstract class ApiService
|
||||
params: RR.SystemRebuildReq,
|
||||
): Promise<RR.SystemRebuildRes>
|
||||
|
||||
abstract repairDisk(params: RR.SystemRebuildReq): Promise<RR.SystemRebuildRes>
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
abstract marketplaceProxy<T>(
|
||||
|
||||
@@ -99,6 +99,10 @@ export class LiveApiService extends ApiService {
|
||||
return this.http.rpcRequest({ method: 'server.rebuild', params })
|
||||
}
|
||||
|
||||
async repairDisk(params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
return this.http.rpcRequest({ method: 'disk.repair', params })
|
||||
}
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async marketplaceProxy<T>(path: string, params: {}, url: string): Promise<T> {
|
||||
|
||||
@@ -193,6 +193,11 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async repairDisk(params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async marketplaceProxy(path: string, params: {}, url: string): Promise<any> {
|
||||
|
||||
@@ -27,7 +27,7 @@ export const mockPatchData: DataModel = {
|
||||
'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',
|
||||
'eos-version-compat': '>=0.3.0 <=0.3.0.1',
|
||||
'status-info': null,
|
||||
},
|
||||
'recovered-packages': {
|
||||
|
||||
@@ -2,17 +2,21 @@ import { Injectable } from '@angular/core'
|
||||
import { Storage } from '@ionic/storage-angular'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
const SHOW_DEV_TOOLS = 'SHOW_DEV_TOOLS'
|
||||
const SHOW_DISK_REPAIR = 'SHOW_DISK_REPAIR'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LocalStorageService {
|
||||
showDevTools$: BehaviorSubject<boolean> = new BehaviorSubject(false)
|
||||
showDiskRepair$: BehaviorSubject<boolean> = new BehaviorSubject(false)
|
||||
constructor(private readonly storage: Storage) {}
|
||||
|
||||
async init() {
|
||||
const val = await this.storage.get(SHOW_DEV_TOOLS)
|
||||
this.showDevTools$.next(!!val)
|
||||
const devTools = await this.storage.get(SHOW_DEV_TOOLS)
|
||||
this.showDevTools$.next(!!devTools)
|
||||
const diskRepair = await this.storage.get(SHOW_DISK_REPAIR)
|
||||
this.showDiskRepair$.next(!!diskRepair)
|
||||
}
|
||||
|
||||
async toggleShowDevTools(): Promise<boolean> {
|
||||
@@ -21,4 +25,11 @@ export class LocalStorageService {
|
||||
this.showDevTools$.next(newVal)
|
||||
return newVal
|
||||
}
|
||||
|
||||
async toggleShowDiskRepair(): Promise<boolean> {
|
||||
const newVal = !(await this.storage.get(SHOW_DISK_REPAIR))
|
||||
await this.storage.set(SHOW_DISK_REPAIR, newVal)
|
||||
this.showDiskRepair$.next(newVal)
|
||||
return newVal
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user