ui: eject disks todo

This commit is contained in:
Aaron Greenspan
2021-01-22 15:18:16 -07:00
committed by Aiden McClelland
parent 8c79984e80
commit 5a4e980d31
23 changed files with 35 additions and 115 deletions

View File

@@ -76,7 +76,9 @@ export class AppComponent {
this.init()
}
ionViewDidEnter(){
ionViewDidEnter () {
// weird bug where a browser grabbed the value 'getdots' from the app.component.html preload input field.
// this removes that field after prleloading occurs.
pauseFor(500).then(() => this.untilLoaded = false)
}

View File

@@ -1,3 +1,4 @@
<!-- TODO: EJECT-DISKS, add a check box to allow a user to eject a disk on backup completion. -->
<ion-content>
<div style="height: 85%; margin: 20px; display: flex; flex-direction: column; justify-content: space-between;">
<div>

View File

@@ -1,10 +0,0 @@
.error-message {
--background: var(--ion-color-danger);
margin: 12px;
border-radius: 3px;
font-weight: bold;
}
.legacy-error-message {
margin: 5px;
}

View File

@@ -14,7 +14,7 @@ export class AppBackupConfirmationComponent implements OnInit {
password: string
$error$: BehaviorSubject<string> = new BehaviorSubject('')
// pass this through the modalCtrl once ejecting disks is an option in the UI.
// TODO: EJECT-DISKS pass this through the modalCtrl once ejecting disks is an option in the UI.
eject = true
message: string

View File

@@ -173,4 +173,4 @@ function validate<T> (t: T, test: (t: T) => Boolean, desc: string) {
}
const defaultUninstallationWarning = serviceName => `Uninstalling ${ serviceName } will result in the deletion of its data.`
const defaultUninstallationWarning = serviceName => `Uninstalling ${ serviceName } will result in the deletion of its data.`

View File

@@ -2,4 +2,4 @@
<ion-label>
New EmbassyOS Version {{version | displayEmver}} Available!
</ion-label>
</ion-item>
</ion-item>

View File

@@ -8,4 +8,4 @@ ion-item {
text-align: center;
font-weight: bold;
}
}
}

View File

@@ -100,7 +100,7 @@ export class AppBackupPage {
m.onWillDismiss().then(res => {
const data = res.data
if (data.cancel) return
// we hard code the 'eject' last argument to be false, until ejection is an option in the UI.
// TODO: EJECT-DISKS we hard code the 'eject' last argument to be false, until ejection is an option in the UI. When it is, add it to the data object above ^
return this.create(disk, partition, data.password, false)
})

View File

@@ -39,4 +39,4 @@
</ion-button>
</div>
</div>
</ion-content>
</ion-content>

View File

@@ -5,4 +5,4 @@
align-items: center;
height: 100%;
min-height: 100px;
}
}

View File

@@ -28,7 +28,7 @@ export class OSWelcomePage {
.then(() => this.apiService.acknowledgeOSWelcome(this.config.version))
.catch(console.error)
// return false to skip subsequent alert modals
// return false to skip subsequent alert modals (e.g. check for updates modals)
// return true to show subsequent alert modals
return this.modalCtrl.dismiss(this.autoCheckUpdates)
}

View File

@@ -61,7 +61,7 @@ export class AppModel extends MapSubject<AppInstalledFull> {
)
}
// when an app is backing up
// TODO: EJECT-DISKS: we can use this to watch for an app completing its backup process.
watchForBackup (appId: string): Observable<string | undefined> {
const toWatch = super.watch(appId)
if (!toWatch) return of(undefined)

View File

@@ -14,7 +14,7 @@ export interface BaseApp {
export interface AppAvailablePreview extends BaseApp {
versionLatest: string
descriptionShort: string
latestVersionTimestamp: Date
latestVersionTimestamp: Date //used for sorting AAL
}
export type AppAvailableFull =

View File

@@ -88,4 +88,4 @@
right: 0px;
top: 0px;
margin: 0px;
}
}

View File

@@ -58,4 +58,4 @@
z-index: 1;
right: -2px;
--border-radius: 100px;
}
}

View File

@@ -1,26 +0,0 @@
<ion-header *ngIf="{appLoading: $appLoading$ | async} as vars">
<ion-toolbar>
<ion-buttons style="margin: 0px 15px" slot="start">
<img class="bulb" *ngIf="status$ | async | displayBulb: 'green'" src="assets/img/green-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'red'" src="assets/img/red-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'yellow'" src="assets/img/yellow-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'off'" src="assets/img/black-bulb.png"/>
</ion-buttons>
<ion-title>{{$app$.title | async}}</ion-title>
<ion-buttons slot="end" *ngIf="">
<ion-spinner *ngIf="vars.appLoading" name="dots" color="medium"></ion-spinner>
<ion-button *ngIf="!vars.appLoading" (click)=presentPopoverMenu($event)>
<ion-icon name="ellipsis-vertical"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content style="--overflow: hidden;" *ngIf="{isRunning: isRunning$ | async, status: status$ | async, appLoading: $appLoading$ | async, iframeLoading: $iframeLoading$ | async } as vars">
<ion-spinner *ngIf="vars.appLoading || vars.iframeLoading" style="position: absolute; width: 4vh; left: calc(50% - 2vh); height: 100%;" name="lines" color="warning"></ion-spinner>
<iframe (load)="iframeLoaded()" *ngIf="!vars.appLoading && vars.isRunning" [id]="appId + '-ui'" src="http://localhost:8100" width="100%" height="100%" style="border:1px solid black;"></iframe>
<div *ngIf="!vars.appLoading && !vars.isRunning" class="flex-center" style="border:1px solid black; color: white">
<ion-label style="margin:10px">{{$app$.title | async}} is not running.</ion-label>
<ion-button fill="outline" (click)="toServiceShow()">View</ion-button>
</div>
</ion-content>

View File

@@ -7,6 +7,7 @@ import { SharingModule } from 'src/app/modules/sharing.module'
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
import { ObjectConfigComponentModule } from 'src/app/components/object-config/object-config.component.module'
// TODO: EJECT-DISKS
const routes: Routes = [
{

View File

@@ -1,3 +1,4 @@
<!-- TODO: EJECT-DISKS -->
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
@@ -16,16 +17,14 @@
</ion-refresher>
<ion-item-group>
<!-- <ion-list> -->
<ion-item *ngFor="let d of disks; let i = index">
<ion-icon slot="start" name="save-outline"></ion-icon>
<ion-label>{{d.logicalname}} ({{ d.size }})</ion-label>
<ion-button *ngIf="!(d.$ejecting$ | async)" slot="end" fill="clear" color="medium" (click)="ejectDisk(i)">
<ion-icon color="primary" class="icon" src="/assets/icon/eject.svg"></ion-icon>
</ion-button>
<ion-spinner *ngIf="d.$ejecting$ | async" name="lines" color="medium"></ion-spinner>
</ion-item>
<!-- </ion-list> -->
<ion-item *ngFor="let d of disks; let i = index">
<ion-icon slot="start" name="save-outline"></ion-icon>
<ion-label>{{d.logicalname}} ({{ d.size }})</ion-label>
<ion-button *ngIf="!(d.$ejecting$ | async)" slot="end" fill="clear" color="medium" (click)="ejectDisk(i)">
<ion-icon color="primary" class="icon" src="/assets/icon/eject.svg"></ion-icon>
</ion-button>
<ion-spinner *ngIf="d.$ejecting$ | async" name="lines" color="medium"></ion-spinner>
</ion-item>
</ion-item-group>
</ion-content>

View File

@@ -5,6 +5,7 @@ import { DiskInfo } from 'src/app/models/server-model'
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
import { BehaviorSubject } from 'rxjs'
import { AlertController } from '@ionic/angular'
// TODO: EJECT-DISKS
type Ejectable<T> = T & { $ejecting$: BehaviorSubject<boolean> }

View File

@@ -65,6 +65,7 @@ export class LiveApiService extends ApiService {
return this.authRequest<ReqRes.GetExternalDisksRes>({ method: Method.GET, url: `/disks` })
}
// TODO: EJECT-DISKS
async ejectExternalDisk (logicalName: string): Promise<Unit> {
return this.authRequest({ method: Method.POST, url: `/disks/eject`, data: { logicalName } })
}

View File

@@ -22,13 +22,15 @@ export class StartupAlertsNotifier {
private readonly osUpdateService: OsUpdateService,
) { }
// So. This takes our three checks and filters down to those that should run.
// Then, the reduce fires, quickly iterating through yielding a promise (acc) to the next element
// This takes our three checks and filters down to those that should run.
// Then, the reduce fires, quickly iterating through yielding a promise (previousDisplay) to the next element
// Each promise fires more or less concurrently, so each c.check(server) is run concurrently
// Then, since we await acc before c.display(res), each promise executing gets hung awaiting the display of the previous run
// Then, since we await previoudDisplay before c.display(res), each promise executing gets hung awaiting the display of the previous run
async runChecks (server: Readonly<S9Server>): Promise<void> {
await this.checks
.filter(c => !c.hasRun && c.shouldRun(server))
// returning true in the below block means to continue to next modal
// returning false means to skip all subsequent modals
.reduce(async (previousDisplay, c) => {
let checkRes: any
try {

View File

@@ -1,12 +1,6 @@
import { Injectable } from '@angular/core'
import { ConfigService } from 'src/app/services/config.service'
import { ToastController, NavController, ModalController, AlertController } from '@ionic/angular'
import { ToastController, NavController } from '@ionic/angular'
import { ServerModel, S9Server } from '../models/server-model'
import { OSWelcomePage } from '../modals/os-welcome/os-welcome.page'
import { ApiService } from './api/api.service'
import { Emver } from './emver.service'
import { LoaderService } from './loader.service'
import { OsUpdateService } from './os-update.service'
@Injectable({
providedIn: 'root',
})
@@ -15,16 +9,9 @@ export class SyncNotifier {
checkedForUpdates = false
constructor (
private readonly config: ConfigService,
private readonly toastCtrl: ToastController,
private readonly modalCtrl: ModalController,
private readonly alertCtrl: AlertController,
private readonly navCtrl: NavController,
private readonly serverModel: ServerModel,
private readonly apiService: ApiService,
private readonly loader: LoaderService,
private readonly emver: Emver,
private readonly osUpdateService: OsUpdateService,
) { }
async handleSpecial (server: Readonly<S9Server>): Promise<void> {
@@ -67,41 +54,3 @@ export class SyncNotifier {
this.serverModel.update(updates)
}
}
// return new Promise(async resolve => {
// const confirm = await this.alertController.create({
// cssClass: 'alert-demo',
// header: 'Warning',
// message: `<h6>This is a <i>hosted</i> instance of Burn After Reading.</h6>
// <p>Since you are not the server operator, you can never be 100% certain that your data are private or secure.</p>
// <p>You can run your own, private instance with the click of a button using the Start9 Embassy.</p>`,
// buttons: [
// {
// text: 'Run my Own',
// handler: () => {
// const a = document.createElement('a')
// const site = (this.config.isConsulate || !this.config.isTor) ? 'https://start9labs.com' : 'http://privacy34kn4ez3y3nijweec6w4g54i3g54sdv7r5mr6soma3w4begyd.onion/'
// a.href = site
// a.target = '_blank'
// pauseFor(500).then(() => a.click())
// return resolve()
// },
// },
// {
// text: 'Use Demo',
// role: 'cancel',
// handler: () => resolve(),
// },
// ],
// })
// await confirm.present()
// const alert = document.getElementsByClassName('alert-demo').item(0)
// this.cleanup(
// fromEvent(alert, 'keyup')
// .pipe(filter((k: KeyboardEvent) => isEnter(k)))
// .subscribe(() => confirm.dismiss()),
// )
// })
// }

View File

@@ -160,4 +160,4 @@ export function capitalizeFirstLetter (string: string): string {
return string.charAt(0).toUpperCase() + string.slice(1)
}
export const exists = t => !!t
export const exists = t => !!t