mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
working
This commit is contained in:
committed by
Aiden McClelland
parent
8f0e0a392e
commit
834de9ab54
@@ -5,37 +5,11 @@
|
|||||||
{
|
{
|
||||||
"files": ["*.ts"],
|
"files": ["*.ts"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"project": ["tsconfig.json", "e2e/tsconfig.json"],
|
"project": ["tsconfig.json"],
|
||||||
"createDefaultProgram": true
|
"createDefaultProgram": true
|
||||||
},
|
},
|
||||||
"extends": [
|
|
||||||
"plugin:@angular-eslint/ng-cli-compat",
|
|
||||||
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
|
|
||||||
"plugin:@angular-eslint/template/process-inline-templates"
|
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"@angular-eslint/component-class-suffix": [
|
"semi": [1, "never"]
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"suffixes": ["Page", "Component"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@angular-eslint/component-selector": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"type": "element",
|
|
||||||
"prefix": "app",
|
|
||||||
"style": "kebab-case"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@angular-eslint/directive-selector": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"type": "attribute",
|
|
||||||
"prefix": "app",
|
|
||||||
"style": "camelCase"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
1
setup-wizard/.gitignore
vendored
1
setup-wizard/.gitignore
vendored
@@ -12,6 +12,7 @@
|
|||||||
Thumbs.db
|
Thumbs.db
|
||||||
UserInterfaceState.xcuserstate
|
UserInterfaceState.xcuserstate
|
||||||
$RECYCLE.BIN/
|
$RECYCLE.BIN/
|
||||||
|
/out-tsc
|
||||||
|
|
||||||
*.log
|
*.log
|
||||||
log.txt
|
log.txt
|
||||||
|
|||||||
@@ -10,15 +10,6 @@ const routes: Routes = [
|
|||||||
path: 'recover',
|
path: 'recover',
|
||||||
loadChildren: () => import('./pages/recover/recover.module').then( m => m.RecoverPageModule)
|
loadChildren: () => import('./pages/recover/recover.module').then( m => m.RecoverPageModule)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'password',
|
|
||||||
loadChildren: () => import('./pages/password/password.module').then( m => m.PasswordPageModule)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
redirectTo: 'wizard',
|
|
||||||
pathMatch: 'full'
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
<h2 color="light">Connecting to Embassy</h2>
|
<h2 color="light">Connecting to Embassy</h2>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
<ng-template #loaded>
|
<ng-template #loaded>
|
||||||
<ion-content *ngIf="error">
|
<ion-router-outlet></ion-router-outlet>
|
||||||
<h2 color="light">{{ error }}</h2>
|
|
||||||
</ion-content>
|
|
||||||
<ion-router-outlet *ngIf="!error"></ion-router-outlet>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { NavController, ToastController } from '@ionic/angular';
|
import { NavController, ToastController } from '@ionic/angular'
|
||||||
import { ApiService } from './services/api/api.service';
|
import { ApiService } from './services/api/api.service'
|
||||||
import { StateService } from './services/state.service';
|
import { StateService } from './services/state.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html',
|
templateUrl: 'app.component.html',
|
||||||
styleUrls: ['app.component.scss'],
|
styleUrls: ['app.component.scss'],
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly apiService: ApiService,
|
private readonly apiService: ApiService,
|
||||||
private readonly stateService: StateService,
|
private readonly stateService: StateService,
|
||||||
private readonly navCtrl: NavController,
|
private readonly navCtrl: NavController,
|
||||||
public toastController: ToastController
|
private readonly toastController: ToastController
|
||||||
) {
|
) {
|
||||||
this.apiService.watchError$.subscribe(error => {
|
this.apiService.watchError$.subscribe(error => {
|
||||||
if(error) {
|
if(error) {
|
||||||
@@ -25,12 +25,10 @@ export class AppComponent {
|
|||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.stateService.getState()
|
await this.stateService.getState()
|
||||||
if (!this.stateService.selectedDataDrive) {
|
if (this.stateService.recoveryDrive) {
|
||||||
await this.navCtrl.navigateForward(`/wizard`)
|
|
||||||
} else if(this.stateService.hasPassword) {
|
|
||||||
//redirect to embassyOS
|
|
||||||
} else if (this.stateService.recoveryDrive) {
|
|
||||||
await this.navCtrl.navigateForward(`/recover`)
|
await this.navCtrl.navigateForward(`/recover`)
|
||||||
|
} else {
|
||||||
|
await this.navCtrl.navigateForward(`/wizard`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +43,9 @@ export class AppComponent {
|
|||||||
role: 'cancel',
|
role: 'cancel',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
})
|
||||||
await toast.present();
|
await toast.present()
|
||||||
|
|
||||||
await toast.onDidDismiss();
|
await toast.onDidDismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { IonicModule } from '@ionic/angular';
|
import { IonicModule } from '@ionic/angular';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { HomePage } from './home.page';
|
import { HomePage } from './home.page';
|
||||||
|
import { PasswordPageModule } from '../password/password.module';
|
||||||
|
|
||||||
import { HomePageRoutingModule } from './home-routing.module';
|
import { HomePageRoutingModule } from './home-routing.module';
|
||||||
|
|
||||||
@@ -12,7 +13,8 @@ import { HomePageRoutingModule } from './home-routing.module';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
HomePageRoutingModule
|
HomePageRoutingModule,
|
||||||
|
PasswordPageModule,
|
||||||
],
|
],
|
||||||
declarations: [HomePage]
|
declarations: [HomePage]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,17 +6,17 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<div *ngIf="!stateService.selectedDataDrive">
|
<div *ngIf="!stateService.dataDrive">
|
||||||
<h2 color="light">Select Data Drive</h2>
|
<h2 color="light">Select Data Drive</h2>
|
||||||
<ion-card
|
<ion-card
|
||||||
*ngFor="let drive of dataDrives"
|
*ngFor="let drive of dataDrives"
|
||||||
(click)="selectDrive(drive)"
|
(click)="selectDrive(drive)"
|
||||||
button="true"
|
button="true"
|
||||||
[class.selected]="selectedDrive === drive['logical-name']"
|
[class.selected]="selectedDrive?.logicalname === drive.logicalname"
|
||||||
color="light"
|
color="light"
|
||||||
>
|
>
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<ion-card-title>{{drive["logical-name"]}}</ion-card-title>
|
<ion-card-title>{{drive.logicalname}}</ion-card-title>
|
||||||
<ion-card-subtitle>{{drive.labels}}</ion-card-subtitle>
|
<ion-card-subtitle>{{drive.labels}}</ion-card-subtitle>
|
||||||
</ion-card-header>
|
</ion-card-header>
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</ion-card>
|
</ion-card>
|
||||||
<ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
|
<ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="stateService.selectedDataDrive">
|
<div *ngIf="stateService.dataDrive">
|
||||||
<ion-card
|
<ion-card
|
||||||
(click)="presentPasswordModal()"
|
(click)="presentPasswordModal()"
|
||||||
button="true"
|
button="true"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { AlertController, ModalController } from '@ionic/angular'
|
import { AlertController, ModalController, LoadingController } from '@ionic/angular'
|
||||||
import { ApiService } from 'src/app/services/api/api.service'
|
import { ApiService, DataDrive } from 'src/app/services/api/api.service'
|
||||||
import { StateService } from 'src/app/services/state.service'
|
import { StateService } from 'src/app/services/state.service'
|
||||||
import { PasswordPage } from '../password/password.page'
|
import { PasswordPage } from '../password/password.page'
|
||||||
|
|
||||||
@@ -11,26 +11,27 @@ import { PasswordPage } from '../password/password.page'
|
|||||||
})
|
})
|
||||||
export class HomePage {
|
export class HomePage {
|
||||||
dataDrives = []
|
dataDrives = []
|
||||||
selectedDrive = null
|
selectedDrive: DataDrive = null
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly apiService: ApiService,
|
private readonly apiService: ApiService,
|
||||||
private readonly stateService: StateService,
|
private readonly stateService: StateService,
|
||||||
private readonly alertController: AlertController,
|
private readonly alertController: AlertController,
|
||||||
private modalController: ModalController,
|
private readonly modalController: ModalController,
|
||||||
|
private readonly loadingCtrl: LoadingController,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
if(!this.stateService.selectedDataDrive) {
|
if(!this.stateService.dataDrive) {
|
||||||
this.dataDrives = await this.apiService.getStorageDisks()
|
this.dataDrives = await this.apiService.getDataDrives()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectDrive(name: string) {
|
selectDrive(drive: DataDrive) {
|
||||||
if (name === this.selectedDrive) {
|
if (drive.logicalname === this.selectedDrive?.logicalname) {
|
||||||
this.selectedDrive = null
|
this.selectedDrive = null
|
||||||
} else {
|
} else {
|
||||||
this.selectedDrive = name
|
this.selectedDrive = drive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ export class HomePage {
|
|||||||
const alert = await this.alertController.create({
|
const alert = await this.alertController.create({
|
||||||
cssClass: 'my-custom-class',
|
cssClass: 'my-custom-class',
|
||||||
header: 'Warning!',
|
header: 'Warning!',
|
||||||
message: 'This disk will be entirely wiped of all memory.',
|
message: 'This drive will be entirely wiped of all memory.',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: 'Cancel',
|
text: 'Cancel',
|
||||||
@@ -50,7 +51,7 @@ export class HomePage {
|
|||||||
}, {
|
}, {
|
||||||
text: 'Okay',
|
text: 'Okay',
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
await this.chooseDisk()
|
await this.chooseDrive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -59,30 +60,38 @@ export class HomePage {
|
|||||||
await alert.present();
|
await alert.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
async chooseDisk() {
|
async chooseDrive() {
|
||||||
await this.apiService.selectStorageDisk({logicalName: this.selectedDrive})
|
await this.apiService.selectDataDrive(this.selectedDrive.logicalname)
|
||||||
this.stateService.selectedDataDrive = this.selectedDrive
|
this.stateService.dataDrive = this.selectedDrive
|
||||||
}
|
}
|
||||||
|
|
||||||
async presentPasswordModal() {
|
async presentPasswordModal() {
|
||||||
const modal = await this.modalController.create({
|
const modal = await this.modalController.create({
|
||||||
component: PasswordPage,
|
component: PasswordPage,
|
||||||
backdropDismiss: false,
|
backdropDismiss: false
|
||||||
componentProps: {
|
|
||||||
'version': null,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
modal.onDidDismiss().then(ret => {
|
modal.onDidDismiss().then(ret => {
|
||||||
if(ret.data.pwValid) {
|
const pass = ret.data.password
|
||||||
this.submitPassword(ret.data.password)
|
if (pass) {
|
||||||
|
this.submitPassword(pass)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await modal.present();
|
await modal.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitPassword (pw: string) {
|
async submitPassword (pw: string) {
|
||||||
await this.apiService.submitPassword(pw)
|
const loader = await this.loadingCtrl.create({
|
||||||
// @TODO navigate to embassyOS
|
message: 'Setting up your Embassy'
|
||||||
|
})
|
||||||
|
await loader.present()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.apiService.submitPassword(pw)
|
||||||
|
location.reload()
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
loader.dismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<div *ngIf="!needsVer">
|
<div *ngIf="needsVer">
|
||||||
<h2>Enter Password</h2>
|
<h2>Enter Password</h2>
|
||||||
<ion-input type="password" [(ngModel)]="password">Password:</ion-input>
|
<ion-input type="password" [(ngModel)]="password">Password:</ion-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="needsVer">
|
<div *ngIf="!needsVer">
|
||||||
<h2>Create Password</h2>
|
<h2>Create Password</h2>
|
||||||
<ion-input type="password" [(ngModel)]="password">Password:</ion-input>
|
<ion-input type="password" [(ngModel)]="password">Password:</ion-input>
|
||||||
<ion-input type="password" [(ngModel)]="passwordVer">Verify Password:</ion-input>
|
<ion-input type="password" [(ngModel)]="passwordVer">Verify Password:</ion-input>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { ModalController } from '@ionic/angular'
|
import { ModalController } from '@ionic/angular'
|
||||||
|
import { RecoveryDrive } from 'src/app/services/api/api.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'password',
|
selector: 'password',
|
||||||
@@ -7,9 +8,9 @@ import { ModalController } from '@ionic/angular'
|
|||||||
styleUrls: ['password.page.scss'],
|
styleUrls: ['password.page.scss'],
|
||||||
})
|
})
|
||||||
export class PasswordPage {
|
export class PasswordPage {
|
||||||
@Input() version: string | null
|
@Input() recoveryDrive: RecoveryDrive
|
||||||
|
|
||||||
needsVer = true
|
needsVer: boolean
|
||||||
|
|
||||||
error = ''
|
error = ''
|
||||||
password = ''
|
password = ''
|
||||||
@@ -20,27 +21,20 @@ export class PasswordPage {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.needsVer = !this.version?.startsWith('0.3')
|
this.needsVer = !!this.recoveryDrive && !this.recoveryDrive.version.startsWith('0.2')
|
||||||
console.log('needs', this.needsVer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitPassword () {
|
async submitPassword () {
|
||||||
if (this.needsVer && this.password !== this.passwordVer) {
|
if (!this.needsVer && this.password !== this.passwordVer) {
|
||||||
this.error="*passwords dont match"
|
this.error="*passwords dont match"
|
||||||
} else {
|
} else {
|
||||||
this.dismiss(true)
|
this.modalController.dismiss({
|
||||||
|
password: this.password,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel () {
|
cancel () {
|
||||||
this.dismiss(false)
|
this.modalController.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
dismiss(submitted: boolean) {
|
|
||||||
this.modalController.dismiss({
|
|
||||||
pwValid: submitted,
|
|
||||||
pw: this.password
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { IonicModule } from '@ionic/angular';
|
import { IonicModule } from '@ionic/angular';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { RecoverPage } from './recover.page';
|
import { RecoverPage } from './recover.page';
|
||||||
|
import { PasswordPageModule } from '../password/password.module';
|
||||||
|
|
||||||
import { RecoverPageRoutingModule } from './recover-routing.module';
|
import { RecoverPageRoutingModule } from './recover-routing.module';
|
||||||
|
|
||||||
@@ -12,7 +13,8 @@ import { RecoverPageRoutingModule } from './recover-routing.module';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
RecoverPageRoutingModule
|
RecoverPageRoutingModule,
|
||||||
|
PasswordPageModule,
|
||||||
],
|
],
|
||||||
declarations: [RecoverPage]
|
declarations: [RecoverPage]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<div *ngIf="!stateService.recoveryDrive">
|
<div *ngIf="!stateService.recoveryDrive">
|
||||||
<h2 color="light">Select Data Drive</h2>
|
<h2 color="light">Select Recovery Drive</h2>
|
||||||
<ion-card
|
<ion-card
|
||||||
*ngFor="let drive of dataDrives"
|
*ngFor="let drive of dataDrives"
|
||||||
(click)="selectDrive(drive)"
|
(click)="selectDrive(drive)"
|
||||||
button="true"
|
button="true"
|
||||||
[class.selected]="selectedDrive === drive['logical-name']"
|
[class.selected]="selectedDrive?.logicalname === drive.logicalname"
|
||||||
color="light"
|
color="light"
|
||||||
>
|
>
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<ion-card-title>{{drive["logical-name"]}}</ion-card-title>
|
<ion-card-title>{{drive.logicalname}}</ion-card-title>
|
||||||
<ion-card-subtitle>{{drive.name}}</ion-card-subtitle>
|
<ion-card-subtitle>{{drive.name}}</ion-card-subtitle>
|
||||||
</ion-card-header>
|
</ion-card-header>
|
||||||
|
|
||||||
@@ -24,15 +24,15 @@
|
|||||||
Currently running {{drive.version}}
|
Currently running {{drive.version}}
|
||||||
</ion-card-content>
|
</ion-card-content>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
<ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
|
<ion-button (click)="chooseDrive()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="stateService.recoveryDrive">
|
<div *ngIf="stateService.recoveryDrive">
|
||||||
<h2>Progress: {{ 100 * stateService.dataProgress }}% <ion-spinner *ngIf="stateService.dataProgress != 1"></ion-spinner> </h2>
|
<h2>Progress: {{ 100 * stateService.dataProgress }}% <ion-spinner *ngIf="stateService.dataProgress !== 1"></ion-spinner> </h2>
|
||||||
<ion-progress-bar value="{{stateService.dataProgress}}"></ion-progress-bar>
|
<ion-progress-bar value="{{stateService.dataProgress}}"></ion-progress-bar>
|
||||||
<ion-button
|
<ion-button
|
||||||
(click)="navToEmbassy()"
|
(click)="navToEmbassy()"
|
||||||
color="primary"
|
color="primary"
|
||||||
[disabled]="stateService.dataProgress != 1"
|
[disabled]="stateService.dataProgress !== 1"
|
||||||
>
|
>
|
||||||
Go To Embassy
|
Go To Embassy
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { AlertController, ModalController } from '@ionic/angular'
|
import { AlertController, ModalController, LoadingController } from '@ionic/angular'
|
||||||
import { ApiService, EmbassyDrive } from 'src/app/services/api/api.service'
|
import { ApiService, RecoveryDrive } from 'src/app/services/api/api.service'
|
||||||
import { StateService } from 'src/app/services/state.service'
|
import { StateService } from 'src/app/services/state.service'
|
||||||
import { PasswordPage } from '../password/password.page'
|
import { PasswordPage } from '../password/password.page'
|
||||||
|
|
||||||
@@ -11,62 +11,33 @@ import { PasswordPage } from '../password/password.page'
|
|||||||
})
|
})
|
||||||
export class RecoverPage {
|
export class RecoverPage {
|
||||||
dataDrives = []
|
dataDrives = []
|
||||||
selectedDrive = null
|
selectedDrive: RecoveryDrive = null
|
||||||
selectedVersion = null
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly apiService: ApiService,
|
private readonly apiService: ApiService,
|
||||||
private readonly stateService: StateService,
|
private readonly stateService: StateService,
|
||||||
public alertController: AlertController,
|
public alertController: AlertController,
|
||||||
private modalController: ModalController,
|
private modalController: ModalController,
|
||||||
|
private readonly loadingCtrl: LoadingController,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
if(!this.stateService.recoveryDrive) {
|
if(!this.stateService.recoveryDrive) {
|
||||||
this.dataDrives = await this.apiService.getEmbassyDrives()
|
this.dataDrives = await this.apiService.getRecoveryDrives()
|
||||||
} else {
|
} else {
|
||||||
this.stateService.pollDataTransferProgress()
|
this.stateService.pollDataTransferProgress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectDrive(disk: EmbassyDrive) {
|
selectDrive(drive: RecoveryDrive) {
|
||||||
const name = disk['logical-name']
|
if (drive.logicalname === this.selectedDrive?.logicalname) {
|
||||||
const version = disk.version
|
|
||||||
if (name === this.selectedDrive) {
|
|
||||||
this.selectedDrive = null
|
this.selectedDrive = null
|
||||||
this.selectedVersion = null
|
|
||||||
} else {
|
} else {
|
||||||
this.selectedDrive = name
|
this.selectedDrive = drive
|
||||||
this.selectedVersion = version
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async warn() {
|
async chooseDrive() {
|
||||||
const alert = await this.alertController.create({
|
|
||||||
cssClass: 'my-custom-class',
|
|
||||||
header: 'Warning!',
|
|
||||||
message: 'Once you select this the recovery process will begin.',
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
text: 'Cancel',
|
|
||||||
role: 'cancel',
|
|
||||||
cssClass: 'secondary',
|
|
||||||
handler: () => {
|
|
||||||
this.selectedDrive = null
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: 'Okay',
|
|
||||||
handler: async () => {
|
|
||||||
await this.chooseDisk()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
await alert.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
async chooseDisk() {
|
|
||||||
this.presentPasswordModal()
|
this.presentPasswordModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,25 +46,38 @@ export class RecoverPage {
|
|||||||
component: PasswordPage,
|
component: PasswordPage,
|
||||||
backdropDismiss: false,
|
backdropDismiss: false,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
'version': this.selectedVersion,
|
recoveryDrive: this.selectedDrive,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
modal.onDidDismiss().then(ret => {
|
modal.onDidDismiss().then(ret => {
|
||||||
if(ret.data.pwValid) {
|
const pass = ret.data.password
|
||||||
this.submitPWAndDisk(ret.data.password)
|
if(pass) {
|
||||||
|
this.submitPWAndDrive(pass)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await modal.present();
|
await modal.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitPWAndDisk(pw: string) {
|
async submitPWAndDrive(pw: string) {
|
||||||
await this.apiService.selectEmbassyDrive({logicalName: this.selectedDrive}, pw)
|
const loader = await this.loadingCtrl.create({
|
||||||
this.stateService.recoveryDrive = this.selectedDrive
|
message: 'Validating password'
|
||||||
this.stateService.pollDataTransferProgress()
|
})
|
||||||
|
await loader.present()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.apiService.selectRecoveryDrive(this.selectedDrive.logicalname, pw)
|
||||||
|
this.stateService.recoveryDrive = this.selectedDrive
|
||||||
|
this.stateService.pollDataTransferProgress()
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
loader.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async navToEmbassy() {
|
async navToEmbassy() {
|
||||||
// @TODO nav to embassy
|
location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
import { Subject } from "rxjs";
|
import { Subject } from 'rxjs'
|
||||||
|
|
||||||
export abstract class ApiService {
|
export abstract class ApiService {
|
||||||
protected error$: Subject<string> = new Subject()
|
protected error$: Subject<string> = new Subject();
|
||||||
watchError$ = this.error$.asObservable()
|
watchError$ = this.error$.asObservable();
|
||||||
abstract getState (): Promise<State>
|
abstract getState (): Promise<State>;
|
||||||
abstract getStorageDisks (): Promise<StorageDisk[]>
|
abstract getDataDrives (): Promise<DataDrive[]>;
|
||||||
abstract selectStorageDisk (disk: { logicalName: string }): Promise<void>
|
abstract selectDataDrive (logicalName: string): Promise<void>;
|
||||||
abstract getEmbassyDrives (): Promise<EmbassyDrive[]>
|
abstract getRecoveryDrives (): Promise<RecoveryDrive[]>;
|
||||||
abstract selectEmbassyDrive (disk: { logicalName: string }, password: string): Promise<void>
|
abstract selectRecoveryDrive (logicalName: string, password: string): Promise<void>;
|
||||||
abstract getDataTransferProgress () : Promise<TransferProgress>
|
abstract getDataTransferProgress (): Promise<TransferProgress>;
|
||||||
abstract submitPassword (password: string) : Promise<void>
|
abstract submitPassword (password: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
'selected-data-drive': string | null,
|
'data-drive': DataDrive | null;
|
||||||
'recovery-drive': string | null,
|
'recovery-drive': RecoveryDrive | null;
|
||||||
'has-password': boolean,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransferProgress {
|
export interface TransferProgress {
|
||||||
'bytes-transfered': number
|
'bytes-transfered': number;
|
||||||
'total-bytes': number
|
'total-bytes': number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StorageDisk {
|
export interface DataDrive {
|
||||||
"logical-name": string
|
logicalname: string;
|
||||||
labels: string[]
|
labels: string[];
|
||||||
capacity: number
|
capacity: number;
|
||||||
used: number
|
used: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbassyDrive {
|
export interface RecoveryDrive {
|
||||||
"logical-name": string
|
logicalname: string;
|
||||||
version: string
|
version: string;
|
||||||
name: string
|
name: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,36 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from '@angular/core'
|
||||||
import { pauseFor } from "../state.service";
|
import { pauseFor } from '../state.service'
|
||||||
import { ApiService } from "./api.service"
|
import { ApiService } from './api.service'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class MockApiService extends ApiService {
|
export class MockApiService extends ApiService {
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getState () {
|
async getState() {
|
||||||
|
await pauseFor(2000)
|
||||||
return {
|
return {
|
||||||
'selected-data-drive': 'page1',
|
'data-drive': null,
|
||||||
|
// {
|
||||||
|
// logicalname: 'name1',
|
||||||
|
// labels: ['label 1', 'label 2'],
|
||||||
|
// capacity: 1600,
|
||||||
|
// used: 200,
|
||||||
|
// },
|
||||||
'recovery-drive': null,
|
'recovery-drive': null,
|
||||||
'has-password': false,
|
// {
|
||||||
'data-transfer-progress': null
|
// logicalname: 'name1',
|
||||||
|
// version: '0.3.3',
|
||||||
|
// name: 'My Embassy'
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDataTransferProgress () {
|
async getDataTransferProgress() {
|
||||||
tries = Math.min(tries + 1, 4)
|
tries = Math.min(tries + 1, 4)
|
||||||
return {
|
return {
|
||||||
'bytes-transfered': tries,
|
'bytes-transfered': tries,
|
||||||
@@ -28,17 +38,17 @@ export class MockApiService extends ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStorageDisks () {
|
async getDataDrives() {
|
||||||
await pauseFor(2000)
|
await pauseFor(2000)
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"logical-name": 'name1',
|
logicalname: 'name1',
|
||||||
labels: ['label 1', 'label 2'],
|
labels: ['label 1', 'label 2'],
|
||||||
capacity: 1600,
|
capacity: 1600,
|
||||||
used: 200,
|
used: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"logical-name": 'name2',
|
logicalname: 'name2',
|
||||||
labels: [],
|
labels: [],
|
||||||
capacity: 1600,
|
capacity: 1600,
|
||||||
used: 0,
|
used: 0,
|
||||||
@@ -46,31 +56,31 @@ export class MockApiService extends ApiService {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectStorageDisk(disk) {
|
async selectDataDrive(drive) {
|
||||||
await pauseFor(200)
|
await pauseFor(2000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEmbassyDrives () {
|
async getRecoveryDrives() {
|
||||||
await pauseFor(2000)
|
await pauseFor(2000)
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"logical-name": 'name1',
|
logicalname: 'name1',
|
||||||
version: '0.2.3',
|
version: '0.3.3',
|
||||||
name: 'Embassy 0.2.3'
|
name: 'My Embassy'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectEmbassyDrive(disk) {
|
async selectRecoveryDrive(logicalName, password) {
|
||||||
await pauseFor(200)
|
await pauseFor(2000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitPassword(password) {
|
async submitPassword(password) {
|
||||||
await pauseFor(200)
|
await pauseFor(2000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tries = 2
|
let tries = 0
|
||||||
|
|||||||
@@ -1,38 +1,37 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from '@angular/core'
|
||||||
import { ApiService } from "./api/api.service"
|
import { ApiService, DataDrive, RecoveryDrive } from './api/api.service'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class StateService {
|
export class StateService {
|
||||||
loading = true
|
loading = true;
|
||||||
|
|
||||||
selectedDataDrive: string
|
dataDrive: DataDrive;
|
||||||
recoveryDrive: string
|
recoveryDrive: RecoveryDrive;
|
||||||
hasPassword: Boolean
|
dataTransferProgress: { bytesTransfered: number; totalBytes: number } | null;
|
||||||
dataTransferProgress: { bytesTransfered: number, totalBytes: number } | null
|
dataProgress = 0;
|
||||||
dataProgress = 0
|
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
private readonly apiService: ApiService
|
private readonly apiService: ApiService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getState () {
|
async getState() {
|
||||||
const state = await this.apiService.getState()
|
const state = await this.apiService.getState()
|
||||||
if(state) {
|
if(state) {
|
||||||
this.selectedDataDrive = state['selected-data-drive']
|
this.dataDrive = state['data-drive']
|
||||||
this.recoveryDrive = state['recovery-drive']
|
this.recoveryDrive = state['recovery-drive']
|
||||||
this.hasPassword = state['has-password']
|
|
||||||
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async pollDataTransferProgress () {
|
async pollDataTransferProgress() {
|
||||||
if (
|
if (
|
||||||
this.dataTransferProgress?.totalBytes &&
|
this.dataTransferProgress?.totalBytes &&
|
||||||
this.dataTransferProgress.bytesTransfered === this.dataTransferProgress.totalBytes
|
this.dataTransferProgress.bytesTransfered === this.dataTransferProgress.totalBytes
|
||||||
) {return }
|
) {return }
|
||||||
|
|
||||||
const progress = await this.apiService.getDataTransferProgress()
|
const progress = await this.apiService.getDataTransferProgress()
|
||||||
this.dataTransferProgress = {
|
this.dataTransferProgress = {
|
||||||
bytesTransfered: progress['bytes-transfered'],
|
bytesTransfered: progress['bytes-transfered'],
|
||||||
@@ -46,6 +45,7 @@ export class StateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pauseFor (ms: number): Promise<void> {
|
export const pauseFor = (ms: number) => {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
const promise = new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
return promise
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user