mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Drew cleanup (#380)
* accordion works * cleanup * styling * more styling * App show change (#387) * show page change * no marketplace * app show changes * update marketplace list * icon * top left icon * toolbar * right size * out of toolbar * no service details * fix skeleton text and server metrics page * stuck * add session management * complete sessions feature * app show page * remove unnecessary icons * add cli to list of possible sessions * Modal global (#383) * modal checkpoint * global modal * black looks good now * black looks good now * not smaller Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Drew Ansbacher <drew.ansbacher@gmail.com> Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Matt Hill <matthewonthemoon@gmail.com> Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com>
This commit is contained in:
committed by
Aiden McClelland
parent
4c294566d7
commit
a43ff976a2
@@ -1,8 +1,8 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button (click)="dismiss()">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
<ion-button (click)="dismiss()" color="light">
|
||||
<ion-icon slot="icon-only" name="close-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ action.name }}</ion-title>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<ion-label>{{ valueString[i] }}</ion-label>
|
||||
|
||||
<ion-button slot="end" fill="clear" (click)="presentAlertDelete(i, $event)">
|
||||
<ion-icon slot="icon-only" name="close-outline" color="medium"></ion-icon>
|
||||
<ion-icon slot="icon-only" name="close-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</div>
|
||||
|
||||
@@ -118,7 +118,6 @@ export class AppConfigListPage extends ModalPresentable {
|
||||
},
|
||||
{
|
||||
text: 'Delete',
|
||||
cssClass: 'alert-danger',
|
||||
handler: () => {
|
||||
if (typeof key === 'number') {
|
||||
(this.value as any[]).splice(key, 1)
|
||||
|
||||
@@ -41,7 +41,6 @@ export class AppConfigObjectPage {
|
||||
},
|
||||
{
|
||||
text: 'Delete',
|
||||
cssClass: 'alert-danger',
|
||||
handler: () => {
|
||||
this.dismiss(true)
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<ion-button *ngIf="spec.masked" fill="clear" [color]="unmasked ? 'danger' : 'primary'" (click)="toggleMask()">
|
||||
<ion-icon slot="icon-only" [name]="unmasked ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-button *ngIf="value && spec.nullable" fill="clear" color="medium" (click)="clear()">
|
||||
<ion-button *ngIf="value && spec.nullable" fill="clear" (click)="clear()">
|
||||
<ion-icon slot="icon-only" name="close" size="small"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
@@ -41,8 +41,8 @@
|
||||
<!-- number -->
|
||||
<ion-item *ngIf="spec.type === 'number'">
|
||||
<ion-input type="tel" placeholder="Enter value" [(ngModel)]="value" (ngModelChange)="handleInput()"></ion-input>
|
||||
<span slot="end" *ngIf="spec.units"><ion-text color="medium">{{ spec.units }}</ion-text></span>
|
||||
<ion-button *ngIf="value && spec.nullable" slot="end" fill="clear" color="medium" (click)="clear()">
|
||||
<span slot="end" *ngIf="spec.units"><ion-text>{{ spec.units }}</ion-text></span>
|
||||
<ion-button *ngIf="value && spec.nullable" slot="end" fill="clear" (click)="clear()">
|
||||
<ion-icon slot="icon-only" name="close" size="small"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
@@ -63,20 +63,18 @@
|
||||
<!-- metadata -->
|
||||
<div class="ion-padding-start">
|
||||
<p *ngIf="spec.type === 'string' && spec.patternDescription">
|
||||
<ion-text color="medium">{{ spec.patternDescription }}</ion-text>
|
||||
{{ spec.patternDescription }}
|
||||
</p>
|
||||
<p *ngIf="spec.type === 'number' && spec.integral">
|
||||
<ion-text color="medium">{{ integralDescription }}</ion-text>
|
||||
{{ integralDescription }}
|
||||
</p>
|
||||
<p *ngIf="rangeDescription">
|
||||
<ion-text color="medium">{{ rangeDescription }}</ion-text>
|
||||
</p>
|
||||
<p *ngIf="spec.default !== undefined">
|
||||
<ion-text color="medium">
|
||||
<p>Default: {{ defaultDescription }} <ion-icon style="padding-left: 8px;" name="refresh-outline" color="dark" style="cursor: pointer;" (click)="refreshDefault()"></ion-icon></p>
|
||||
<p *ngIf="spec.type === 'number' && spec.units">Units: {{ spec.units }}</p>
|
||||
</ion-text>
|
||||
{{ rangeDescription }}
|
||||
</p>
|
||||
<ng-container *ngIf="spec.default !== undefined">
|
||||
<p>Default: {{ defaultDescription }} <ion-icon style="padding-left: 8px;" name="refresh-outline" color="dark" style="cursor: pointer;" (click)="refreshDefault()"></ion-icon></p>
|
||||
<p *ngIf="spec.type === 'number' && spec.units">Units: {{ spec.units }}</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ion-item-group>
|
||||
|
||||
|
||||
@@ -176,7 +176,6 @@ export class AppConfigValuePage {
|
||||
},
|
||||
{
|
||||
text: `Leave`,
|
||||
cssClass: 'alert-danger',
|
||||
handler: () => {
|
||||
this.modalCtrl.dismiss()
|
||||
},
|
||||
|
||||
59
ui/src/app/modals/app-restore/app-restore.component.html
Normal file
59
ui/src/app/modals/app-restore/app-restore.component.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button (click)="dismiss()">
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>
|
||||
Restore From Backup
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding-top">
|
||||
|
||||
<text-spinner *ngIf="loading" text="Loading Drives"></text-spinner>
|
||||
<text-spinner *ngIf="submitting" text="Initiating Backup"></text-spinner>
|
||||
|
||||
<ion-content *ngIf="!loading && !submitting">
|
||||
<ion-item class="ion-margin-bottom">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<p class="ion-padding-bottom"><ion-text color="warning">Warning</ion-text></p>
|
||||
<h2>
|
||||
Restoring from backup will overwrite all current data for {{ patch.data['package-data'][pkgId].manifest.title }} .
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider>Select Backup Drive</ion-item-divider>
|
||||
|
||||
<ion-item *ngIf="allPartitionsMounted">
|
||||
<ion-text class="ion-text-wrap" color="warning">No partitions available. Insert the storage device containing the backup you intend to restore.</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-card *ngFor="let disk of disks | keyvalue">
|
||||
<ion-card-header>
|
||||
<ion-card-title>
|
||||
{{ disk.value.size }}
|
||||
</ion-card-title>
|
||||
<ion-card-subtitle>
|
||||
{{ disk.key }}
|
||||
</ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-item-group>
|
||||
<ion-item button *ngFor="let partition of disk.value.partitions | keyvalue" [disabled]="partition.value['is-mounted']" (click)="presentModal(partition.key)">
|
||||
<ion-icon slot="start" name="save-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ partition.value.label || partition.key }} ({{ partition.value.size || 'unknown size' }})</h2>
|
||||
<p *ngIf="!partition.value['is-mounted']; else unavailable"><ion-text color="success">Available</ion-text></p>
|
||||
<ng-template #unavailable>
|
||||
<p><ion-text color="danger">Unavailable</ion-text></p>
|
||||
</ng-template>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</ion-content>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { AppRestoreComponent } from './app-restore.component'
|
||||
import { PwaBackComponentModule } from '../../components/pwa-back-button/pwa-back.component.module'
|
||||
import { BackupConfirmationComponentModule } from '../backup-confirmation/backup-confirmation.component.module'
|
||||
import { SharingModule } from '../../modules/sharing.module'
|
||||
import { TextSpinnerComponentModule } from '../../components/text-spinner/text-spinner.component.module'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
SharingModule,
|
||||
BackupConfirmationComponentModule,
|
||||
PwaBackComponentModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [
|
||||
AppRestoreComponent,
|
||||
],
|
||||
exports: [AppRestoreComponent],
|
||||
|
||||
})
|
||||
export class AppRestoreComponentModule { }
|
||||
99
ui/src/app/modals/app-restore/app-restore.component.ts
Normal file
99
ui/src/app/modals/app-restore/app-restore.component.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { LoadingController, ModalController } from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/embassy/embassy-api.service'
|
||||
import { BackupConfirmationComponent } from 'src/app/modals/backup-confirmation/backup-confirmation.component'
|
||||
import { DiskInfo } from 'src/app/services/api/api.types'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-restore',
|
||||
templateUrl: './app-restore.component.html',
|
||||
styleUrls: ['./app-restore.component.scss'],
|
||||
})
|
||||
export class AppRestoreComponent {
|
||||
@Input() pkgId: string
|
||||
disks: DiskInfo
|
||||
title: string
|
||||
loading = true
|
||||
submitting = false
|
||||
allPartitionsMounted: boolean
|
||||
|
||||
subs: Subscription[] = []
|
||||
|
||||
constructor (
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly embassyApi: ApiService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
public readonly patch: PatchDbService,
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
console.log('initing')
|
||||
this.getExternalDisks()
|
||||
}
|
||||
|
||||
// ngAfterViewInit () {
|
||||
// this.content.scrollToPoint(undefined, 1)
|
||||
// }
|
||||
|
||||
async refresh () {
|
||||
this.loading = true
|
||||
await this.getExternalDisks()
|
||||
}
|
||||
|
||||
async getExternalDisks (): Promise<void> {
|
||||
try {
|
||||
this.disks = await this.embassyApi.getDisks({ })
|
||||
this.allPartitionsMounted = Object.values(this.disks).every(d => Object.values(d.partitions).every(p => p['is-mounted']))
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
console.log('loading false')
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async presentModal (logicalname: string): Promise<void> {
|
||||
const m = await this.modalCtrl.create({
|
||||
componentProps: {
|
||||
type: 'restore',
|
||||
},
|
||||
cssClass: 'alertlike-modal',
|
||||
component: BackupConfirmationComponent,
|
||||
backdropDismiss: false,
|
||||
})
|
||||
|
||||
m.onWillDismiss().then(res => {
|
||||
const data = res.data
|
||||
if (data.cancel) return
|
||||
this.restore(logicalname, data.password)
|
||||
})
|
||||
|
||||
await m.present()
|
||||
}
|
||||
|
||||
dismiss () {
|
||||
this.modalCtrl.dismiss({ })
|
||||
}
|
||||
|
||||
private async restore (logicalname: string, password: string): Promise<void> {
|
||||
console.log('here here here')
|
||||
this.submitting = true
|
||||
// await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.restorePackage({
|
||||
id: this.pkgId,
|
||||
logicalname,
|
||||
password,
|
||||
})
|
||||
} catch (e) {
|
||||
this.modalCtrl.dismiss({ error: e })
|
||||
} finally {
|
||||
this.modalCtrl.dismiss({ })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
<div style="height: 85%; margin: 24px; display: flex; flex-direction: column; justify-content: space-between;">
|
||||
<div *ngIf="type === 'backup'">
|
||||
<h4><ion-text color="dark">Encrypt Backup</ion-text></h4>
|
||||
<p><ion-text color="medium">Enter your master password to create an encrypted backup.</ion-text></p>
|
||||
<p><ion-text>Enter your master password to create an encrypted backup.</ion-text></p>
|
||||
</div>
|
||||
<div *ngIf="type === 'restore'">
|
||||
<h4><ion-text color="dark">Decrypt Backup</ion-text></h4>
|
||||
<p><ion-text color="medium">Enter the password that was originally used to encrypt this backup.</ion-text></p>
|
||||
<p><ion-text>Enter the password that was originally used to encrypt this backup.</ion-text></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user