mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
ui: eject disks todo
This commit is contained in:
committed by
Aiden McClelland
parent
8c79984e80
commit
5a4e980d31
@@ -76,7 +76,9 @@ export class AppComponent {
|
|||||||
this.init()
|
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)
|
pauseFor(500).then(() => this.untilLoaded = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- TODO: EJECT-DISKS, add a check box to allow a user to eject a disk on backup completion. -->
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<div style="height: 85%; margin: 20px; display: flex; flex-direction: column; justify-content: space-between;">
|
<div style="height: 85%; margin: 20px; display: flex; flex-direction: column; justify-content: space-between;">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
.error-message {
|
|
||||||
--background: var(--ion-color-danger);
|
|
||||||
margin: 12px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legacy-error-message {
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ export class AppBackupConfirmationComponent implements OnInit {
|
|||||||
password: string
|
password: string
|
||||||
$error$: BehaviorSubject<string> = new BehaviorSubject('')
|
$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
|
eject = true
|
||||||
message: string
|
message: string
|
||||||
|
|
||||||
|
|||||||
@@ -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.`
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
<ion-label>
|
<ion-label>
|
||||||
New EmbassyOS Version {{version | displayEmver}} Available!
|
New EmbassyOS Version {{version | displayEmver}} Available!
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ ion-item {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export class AppBackupPage {
|
|||||||
m.onWillDismiss().then(res => {
|
m.onWillDismiss().then(res => {
|
||||||
const data = res.data
|
const data = res.data
|
||||||
if (data.cancel) return
|
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)
|
return this.create(disk, partition, data.password, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -39,4 +39,4 @@
|
|||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class OSWelcomePage {
|
|||||||
.then(() => this.apiService.acknowledgeOSWelcome(this.config.version))
|
.then(() => this.apiService.acknowledgeOSWelcome(this.config.version))
|
||||||
.catch(console.error)
|
.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 true to show subsequent alert modals
|
||||||
return this.modalCtrl.dismiss(this.autoCheckUpdates)
|
return this.modalCtrl.dismiss(this.autoCheckUpdates)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
watchForBackup (appId: string): Observable<string | undefined> {
|
||||||
const toWatch = super.watch(appId)
|
const toWatch = super.watch(appId)
|
||||||
if (!toWatch) return of(undefined)
|
if (!toWatch) return of(undefined)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export interface BaseApp {
|
|||||||
export interface AppAvailablePreview extends BaseApp {
|
export interface AppAvailablePreview extends BaseApp {
|
||||||
versionLatest: string
|
versionLatest: string
|
||||||
descriptionShort: string
|
descriptionShort: string
|
||||||
latestVersionTimestamp: Date
|
latestVersionTimestamp: Date //used for sorting AAL
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AppAvailableFull =
|
export type AppAvailableFull =
|
||||||
|
|||||||
@@ -88,4 +88,4 @@
|
|||||||
right: 0px;
|
right: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,4 +58,4 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
right: -2px;
|
right: -2px;
|
||||||
--border-radius: 100px;
|
--border-radius: 100px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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 { 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 { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||||
import { ObjectConfigComponentModule } from 'src/app/components/object-config/object-config.component.module'
|
import { ObjectConfigComponentModule } from 'src/app/components/object-config/object-config.component.module'
|
||||||
|
// TODO: EJECT-DISKS
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- TODO: EJECT-DISKS -->
|
||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-buttons slot="start">
|
<ion-buttons slot="start">
|
||||||
@@ -16,16 +17,14 @@
|
|||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<!-- <ion-list> -->
|
<ion-item *ngFor="let d of disks; let i = index">
|
||||||
<ion-item *ngFor="let d of disks; let i = index">
|
<ion-icon slot="start" name="save-outline"></ion-icon>
|
||||||
<ion-icon slot="start" name="save-outline"></ion-icon>
|
<ion-label>{{d.logicalname}} ({{ d.size }})</ion-label>
|
||||||
<ion-label>{{d.logicalname}} ({{ d.size }})</ion-label>
|
<ion-button *ngIf="!(d.$ejecting$ | async)" slot="end" fill="clear" color="medium" (click)="ejectDisk(i)">
|
||||||
<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-icon color="primary" class="icon" src="/assets/icon/eject.svg"></ion-icon>
|
</ion-button>
|
||||||
</ion-button>
|
<ion-spinner *ngIf="d.$ejecting$ | async" name="lines" color="medium"></ion-spinner>
|
||||||
<ion-spinner *ngIf="d.$ejecting$ | async" name="lines" color="medium"></ion-spinner>
|
</ion-item>
|
||||||
</ion-item>
|
|
||||||
<!-- </ion-list> -->
|
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { DiskInfo } from 'src/app/models/server-model'
|
|||||||
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
|
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
|
||||||
import { BehaviorSubject } from 'rxjs'
|
import { BehaviorSubject } from 'rxjs'
|
||||||
import { AlertController } from '@ionic/angular'
|
import { AlertController } from '@ionic/angular'
|
||||||
|
// TODO: EJECT-DISKS
|
||||||
|
|
||||||
type Ejectable<T> = T & { $ejecting$: BehaviorSubject<boolean> }
|
type Ejectable<T> = T & { $ejecting$: BehaviorSubject<boolean> }
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export class LiveApiService extends ApiService {
|
|||||||
return this.authRequest<ReqRes.GetExternalDisksRes>({ method: Method.GET, url: `/disks` })
|
return this.authRequest<ReqRes.GetExternalDisksRes>({ method: Method.GET, url: `/disks` })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: EJECT-DISKS
|
||||||
async ejectExternalDisk (logicalName: string): Promise<Unit> {
|
async ejectExternalDisk (logicalName: string): Promise<Unit> {
|
||||||
return this.authRequest({ method: Method.POST, url: `/disks/eject`, data: { logicalName } })
|
return this.authRequest({ method: Method.POST, url: `/disks/eject`, data: { logicalName } })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,13 +22,15 @@ export class StartupAlertsNotifier {
|
|||||||
private readonly osUpdateService: OsUpdateService,
|
private readonly osUpdateService: OsUpdateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
// So. This takes our three checks and filters down to those that should run.
|
// 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
|
// 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
|
// 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> {
|
async runChecks (server: Readonly<S9Server>): Promise<void> {
|
||||||
await this.checks
|
await this.checks
|
||||||
.filter(c => !c.hasRun && c.shouldRun(server))
|
.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) => {
|
.reduce(async (previousDisplay, c) => {
|
||||||
let checkRes: any
|
let checkRes: any
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { ConfigService } from 'src/app/services/config.service'
|
import { ToastController, NavController } from '@ionic/angular'
|
||||||
import { ToastController, NavController, ModalController, AlertController } from '@ionic/angular'
|
|
||||||
import { ServerModel, S9Server } from '../models/server-model'
|
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({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
@@ -15,16 +9,9 @@ export class SyncNotifier {
|
|||||||
checkedForUpdates = false
|
checkedForUpdates = false
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly config: ConfigService,
|
|
||||||
private readonly toastCtrl: ToastController,
|
private readonly toastCtrl: ToastController,
|
||||||
private readonly modalCtrl: ModalController,
|
|
||||||
private readonly alertCtrl: AlertController,
|
|
||||||
private readonly navCtrl: NavController,
|
private readonly navCtrl: NavController,
|
||||||
private readonly serverModel: ServerModel,
|
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> {
|
async handleSpecial (server: Readonly<S9Server>): Promise<void> {
|
||||||
@@ -67,41 +54,3 @@ export class SyncNotifier {
|
|||||||
this.serverModel.update(updates)
|
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()),
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
@@ -160,4 +160,4 @@ export function capitalizeFirstLetter (string: string): string {
|
|||||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const exists = t => !!t
|
export const exists = t => !!t
|
||||||
|
|||||||
Reference in New Issue
Block a user