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:
Drew Ansbacher
2021-07-29 16:59:03 -04:00
committed by Aiden McClelland
parent 4c294566d7
commit a43ff976a2
71 changed files with 808 additions and 694 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)

View File

@@ -41,7 +41,6 @@ export class AppConfigObjectPage {
},
{
text: 'Delete',
cssClass: 'alert-danger',
handler: () => {
this.dismiss(true)
},

View File

@@ -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>

View File

@@ -176,7 +176,6 @@ export class AppConfigValuePage {
},
{
text: `Leave`,
cssClass: 'alert-danger',
handler: () => {
this.modalCtrl.dismiss()
},

View 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>

View File

@@ -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 { }

View 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({ })
}
}
}

View File

@@ -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>