mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
fixing things up
This commit is contained in:
committed by
Aiden McClelland
parent
1dbef9d689
commit
c1db00aebb
@@ -1,17 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core'
|
||||
import { BrowserModule } from '@angular/platform-browser'
|
||||
import { RouteReuseStrategy } from '@angular/router'
|
||||
import { HttpClientModule } from '@angular/common/http'
|
||||
import { ApiService } from './services/api/api.service'
|
||||
import { MockApiService } from './services/api/mock-api.service'
|
||||
import { LiveApiService } from './services/api/live-api.service'
|
||||
import { HttpService } from './services/api/http.service'
|
||||
|
||||
import { IonicModule, IonicRouteStrategy, iosTransitionAnimation } from '@ionic/angular';
|
||||
import * as config from './config/config'
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
import { IonicModule, IonicRouteStrategy, iosTransitionAnimation } from '@ionic/angular'
|
||||
import { AppComponent } from './app.component'
|
||||
import { AppRoutingModule } from './app-routing.module'
|
||||
const useMocks = require('../../config.json').useMocks as boolean
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
@@ -30,7 +28,7 @@ import { AppRoutingModule } from './app-routing.module';
|
||||
{
|
||||
provide: ApiService ,
|
||||
useFactory: (http: HttpService) => {
|
||||
if(config.config.useMocks) {
|
||||
if (useMocks) {
|
||||
return new MockApiService()
|
||||
} else {
|
||||
return new LiveApiService(http)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export const config: Config = {
|
||||
"useMocks": true
|
||||
}
|
||||
|
||||
interface Config {
|
||||
useMocks: boolean
|
||||
}
|
||||
@@ -4,9 +4,8 @@ import { IonicModule } from '@ionic/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { EmbassyPage } from './embassy.page';
|
||||
import { PasswordPageModule } from '../password/password.module';
|
||||
|
||||
import { EmbassyPageRoutingModule } from './embassy-routing.module';
|
||||
|
||||
import { PipesModule } from 'src/app/pipes/pipe.module'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -15,6 +14,7 @@ import { EmbassyPageRoutingModule } from './embassy-routing.module';
|
||||
IonicModule,
|
||||
EmbassyPageRoutingModule,
|
||||
PasswordPageModule,
|
||||
PipesModule,
|
||||
],
|
||||
declarations: [EmbassyPage]
|
||||
})
|
||||
|
||||
@@ -9,19 +9,15 @@
|
||||
|
||||
<ion-card color="dark">
|
||||
<ion-card-header class="ion-text-center" style="padding-bottom: 8px;">
|
||||
<ion-card-title>{{ loading ? 'Loading Embassy Drives' : 'Select Embassy Drive'}}</ion-card-title>
|
||||
<ion-card-title>{{ loading ? 'Loading Drives' : 'Select Storage Drive'}}</ion-card-title>
|
||||
<ion-card-subtitle>Select the drive where all your Embassy data will be stored.</ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
|
||||
<ion-card-content class="ion-margin">
|
||||
<ng-container *ngIf="!loading && !embassyDrives.length">
|
||||
<h2 color="light">No Embassy drives found</h2>
|
||||
<p color="light">Please connect an Embassy drive to your embassy and refresh the page.</p>
|
||||
<ion-button
|
||||
(click)="window.location.reload()"
|
||||
style="text-align:center"
|
||||
class="claim-button"
|
||||
>
|
||||
<ng-container *ngIf="!loading && !storageDrives.length">
|
||||
<h2 color="light">No drives found</h2>
|
||||
<p color="light">Please connect an storage drive to your Embassy and refresh the page.</p>
|
||||
<ion-button style="margin-top: 25px;" (click)="window.location.reload()" color="light">
|
||||
Refresh
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
@@ -39,13 +35,16 @@
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="embassyDrives.length">
|
||||
<ion-item (click)="chooseDrive(drive)" class="ion-margin-bottom" button color="light" lines="none" *ngFor="let drive of embassyDrives">
|
||||
<ng-container *ngIf="storageDrives.length">
|
||||
<ion-item (click)="chooseDrive(drive)" class="ion-margin-bottom" button color="light" lines="none" *ngFor="let drive of storageDrives">
|
||||
<ion-icon slot="start" name="save-outline"></ion-icon>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h1>{{ drive.logicalname }}</h1>
|
||||
<h2 style="min-height: 19px;">{{ getLabel(drive) }}</h2>
|
||||
<p> Using {{ getUsage(drive) }} of {{drive.capacity.toFixed(2)}} GiB</p>
|
||||
<h1>{{ drive.logicalname }} - {{ drive.capacity | convertBytes }}</h1>
|
||||
<h2 *ngIf="drive.vendor || drive.model">
|
||||
{{ drive.vendor }}
|
||||
<span *ngIf="drive.vendor && drive.model"> - </span>
|
||||
{{ drive.model }}
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
@@ -7,38 +7,4 @@ ion-card-title {
|
||||
font-family: 'Montserrat';
|
||||
font-size: x-large;
|
||||
--color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
// ion-item {
|
||||
// --border-radius: 4px;
|
||||
// --border-style: solid;
|
||||
// --border-width: 1px;
|
||||
// --border-color: var(--ion-color-light);
|
||||
// }
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { iosTransitionAnimation, LoadingController, ModalController, NavController } from '@ionic/angular'
|
||||
import { AlertController, iosTransitionAnimation, LoadingController, ModalController, NavController } from '@ionic/angular'
|
||||
import { ApiService, DiskInfo } from 'src/app/services/api/api.service'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
import { PasswordPage } from '../password/password.page'
|
||||
@@ -10,7 +10,7 @@ import { PasswordPage } from '../password/password.page'
|
||||
styleUrls: ['embassy.page.scss'],
|
||||
})
|
||||
export class EmbassyPage {
|
||||
embassyDrives = []
|
||||
storageDrives = []
|
||||
selectedDrive: DiskInfo = null
|
||||
loading = true
|
||||
window = window
|
||||
@@ -18,23 +18,48 @@ export class EmbassyPage {
|
||||
constructor(
|
||||
private readonly apiService: ApiService,
|
||||
private readonly navCtrl: NavController,
|
||||
private modalController: ModalController,
|
||||
private stateService: StateService,
|
||||
private loadingCtrl: LoadingController
|
||||
) {}
|
||||
private readonly modalController: ModalController,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly stateService: StateService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
) { }
|
||||
|
||||
async ngOnInit() {
|
||||
const drives = (await this.apiService.getDrives()).filter(d => !d['embassy_os'])
|
||||
this.embassyDrives = (await this.apiService.getDrives()).filter(d => !d['embassy_os'])
|
||||
async ngOnInit () {
|
||||
this.storageDrives = await this.apiService.getDrives()
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
async chooseDrive(drive: DiskInfo) {
|
||||
async chooseDrive (drive: DiskInfo) {
|
||||
if (!!drive.partitions.find(p => p.used)) {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Warning',
|
||||
subHeader: 'Drive contains data!',
|
||||
message: 'All data stored on this drive will be permanently deleted.',
|
||||
buttons: [
|
||||
{
|
||||
role: 'cancel',
|
||||
text: 'Cancel',
|
||||
},
|
||||
{
|
||||
text: 'Continue',
|
||||
handler: () => {
|
||||
this.presentModalPassword(drive)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
await alert.present()
|
||||
} else {
|
||||
this.presentModalPassword(drive)
|
||||
}
|
||||
}
|
||||
|
||||
private async presentModalPassword (drive: DiskInfo): Promise<void> {
|
||||
const modal = await this.modalController.create({
|
||||
component: PasswordPage,
|
||||
componentProps: {
|
||||
embassyDrive: drive
|
||||
}
|
||||
storageDrive: drive
|
||||
},
|
||||
})
|
||||
modal.onDidDismiss().then(async ret => {
|
||||
if (!ret.data || !ret.data.password) return
|
||||
@@ -45,13 +70,13 @@ export class EmbassyPage {
|
||||
|
||||
await loader.present()
|
||||
|
||||
this.stateService.embassyDrive = drive
|
||||
this.stateService.storageDrive = drive
|
||||
this.stateService.embassyPassword = ret.data.password
|
||||
|
||||
try {
|
||||
this.stateService.torAddress = (await this.stateService.setupEmbassy()).torAddress
|
||||
} catch (e) {
|
||||
console.log(e.message)
|
||||
console.error(e.message)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
if(!!this.stateService.recoveryDrive) {
|
||||
@@ -61,21 +86,6 @@ export class EmbassyPage {
|
||||
}
|
||||
}
|
||||
})
|
||||
await modal.present();
|
||||
}
|
||||
|
||||
getLabel(drive: DiskInfo) {
|
||||
const labels = drive.partitions.map(p => p.label).filter(l => !!l)
|
||||
return labels.length ? labels.join(' / ') : 'unnamed'
|
||||
}
|
||||
|
||||
getUsage(drive: DiskInfo) {
|
||||
let usage = 0
|
||||
drive.partitions.forEach(par => {
|
||||
if(par.used) {
|
||||
usage += par.used
|
||||
}
|
||||
})
|
||||
return usage.toFixed(2)
|
||||
await modal.present()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,31 +13,4 @@ ion-item {
|
||||
--border-style: solid;
|
||||
--border-width: 1px;
|
||||
--border-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
@@ -13,31 +13,4 @@ ion-item {
|
||||
--border-style: solid;
|
||||
--border-width: 1px;
|
||||
--border-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,29 @@
|
||||
<ion-header>
|
||||
<ion-toolbar color="light">
|
||||
<ion-title>
|
||||
<span *ngIf="!!recoveryDrive">Unlock Drive</span>
|
||||
<span *ngIf="!recoveryDrive">Set Password</span>
|
||||
{{ !!storageDrive ? 'Set Password' : 'Unlock Drive' }}
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content color="light">
|
||||
<form (ngSubmit)="!!recoveryDrive ? verifyPw() : submitPw()">
|
||||
<form (ngSubmit)="!!storageDrive ? submitPw() : verifyPw()">
|
||||
<div style="padding: 8px 24px;">
|
||||
<p *ngIf="!!embassyDrive">Choose a password for your embassy. You will need it every time you log in. If you lose it you will be permanently locked out of your embassy.</p>
|
||||
<p *ngIf="embassyDrive && getUsage(embassyDrive) > 0" style="padding-bottom: 15px;color: var(--ion-color-warning);"><b>Warning:</b> After submit, any data currently stored on <b>{{ getLabel(embassyDrive) }}</b> will be wiped.</p>
|
||||
<div style="padding-bottom: 16px;">
|
||||
<ng-container *ngIf="!!storageDrive">
|
||||
<h3>Choose a password for your Embassy. Make it good. Write it down. If you lose this password, you may be permanently locked out of your Embassy.</h3>
|
||||
<p *ngIf="hasData" style="color: var(--ion-color-warning);"><b>Warning:</b> data on this drive will be permanently deleted.</p>
|
||||
</ng-container>
|
||||
<p *ngIf="!storageDrive">Enter the password that was used to encrypt this drive.</p>
|
||||
</div>
|
||||
|
||||
<h4 class="input-label">
|
||||
<h4 class="password-input" *ngIf="!!storageDrive">
|
||||
Password:
|
||||
</h4>
|
||||
|
||||
<ion-item
|
||||
color="dark"
|
||||
[class]="pwError ? 'error-border' : password && !recoveryDrive ? 'success-border' : ''"
|
||||
[class]="pwError ? 'error-border' : password && !!storageDrive ? 'success-border' : ''"
|
||||
>
|
||||
<ion-input
|
||||
[(ngModel)]="password"
|
||||
@@ -34,9 +38,9 @@
|
||||
<ion-icon slot="icon-only" [name]="unmasked1 ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
<p style="color: var(--ion-color-danger);">{{pwError}}</p>
|
||||
<ng-container *ngIf="!recoveryDrive">
|
||||
<h4 class="input-label">
|
||||
<p style="color: var(--ion-color-danger);">{{ pwError }}</p>
|
||||
<ng-container *ngIf="!!storageDrive">
|
||||
<h4 class="password-input">
|
||||
Verify Password:
|
||||
</h4>
|
||||
|
||||
@@ -63,14 +67,14 @@
|
||||
|
||||
<ion-footer>
|
||||
<ion-toolbar color="light">
|
||||
<ion-buttons slot="end" class="ion-padding-end">
|
||||
<ion-button color="dark" class="claim-button" (click)="cancel()">
|
||||
<!-- <ion-buttons slot="end" class="ion-padding-end"> -->
|
||||
<ion-button class="ion-padding-end" slot="end" color="dark" fill="clear" (click)="cancel()">
|
||||
Cancel
|
||||
</ion-button>
|
||||
<ion-button color="dark" class="claim-button" (click)="!!recoveryDrive ? verifyPw() : submitPw()">
|
||||
{{ !!recoveryDrive ? 'Unlock' : 'Submit' }}
|
||||
<ion-button class="ion-padding-end" slot="end" color="dark" fill="clear" strong="true" (click)="!!storageDrive ? submitPw() : verifyPw()">
|
||||
{{ !!storageDrive ? 'Finish' : 'Unlock' }}
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<!-- </ion-buttons> -->
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin: 6px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
.password-input {
|
||||
color: var(--ion-color-dark);
|
||||
// padding-top: 10px;
|
||||
margin-bottom: 6px;
|
||||
font-size: medium;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { LoadingController, ModalController } from '@ionic/angular'
|
||||
import { ApiService, DiskInfo } from 'src/app/services/api/api.service'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-password',
|
||||
@@ -10,7 +9,7 @@ import { StateService } from 'src/app/services/state.service'
|
||||
})
|
||||
export class PasswordPage {
|
||||
@Input() recoveryDrive: DiskInfo
|
||||
@Input() embassyDrive: DiskInfo
|
||||
@Input() storageDrive: DiskInfo
|
||||
|
||||
pwError = ''
|
||||
password = ''
|
||||
@@ -20,18 +19,22 @@ export class PasswordPage {
|
||||
passwordVer = ''
|
||||
unmasked2 = false
|
||||
|
||||
hasData: boolean
|
||||
|
||||
constructor(
|
||||
private modalController: ModalController,
|
||||
private apiService: ApiService,
|
||||
private loadingCtrl: LoadingController,
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
ngOnInit() { }
|
||||
ngOnInit() {
|
||||
if (this.storageDrive && this.storageDrive.partitions.find(p => p.used)) {
|
||||
this.hasData = true
|
||||
}
|
||||
}
|
||||
|
||||
async verifyPw () {
|
||||
|
||||
if(!this.recoveryDrive) this.pwError = 'No recovery drive' // unreachable
|
||||
if (!this.recoveryDrive) this.pwError = 'No recovery drive' // unreachable
|
||||
const loader = await this.loadingCtrl.create({
|
||||
message: 'Verifying Password'
|
||||
})
|
||||
@@ -79,23 +82,7 @@ export class PasswordPage {
|
||||
this.verError = this.password !== this.passwordVer ? "*passwords do not match" : ''
|
||||
}
|
||||
|
||||
|
||||
cancel () {
|
||||
this.modalController.dismiss()
|
||||
}
|
||||
|
||||
getLabel(drive: DiskInfo) {
|
||||
const labels = drive.partitions.map(p => p.label).filter(l => !!l)
|
||||
return labels.length ? labels.join(' / ') : 'unnamed'
|
||||
}
|
||||
|
||||
getUsage(drive: DiskInfo) {
|
||||
let usage = 0
|
||||
drive.partitions.forEach(par => {
|
||||
if(par.used) {
|
||||
usage += par.used
|
||||
}
|
||||
})
|
||||
return usage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<p *ngIf="error" style="padding-top: 4px"><ion-text color="danger">*{{ error }}</ion-text></p>
|
||||
</div>
|
||||
</ion-item-group>
|
||||
<ion-button style="margin-top: 25px;" type="submit" color="light">
|
||||
<ion-button type="submit" color="light" class="claim-button">
|
||||
Submit
|
||||
</ion-button>
|
||||
</form>
|
||||
|
||||
@@ -13,31 +13,4 @@ ion-item {
|
||||
--border-style: solid;
|
||||
--border-width: 1px;
|
||||
--border-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import { IonicModule } from '@ionic/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RecoverPage } from './recover.page';
|
||||
import { PasswordPageModule } from '../password/password.module';
|
||||
|
||||
import { RecoverPageRoutingModule } from './recover-routing.module';
|
||||
import { PipesModule } from 'src/app/pipes/pipe.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -15,6 +15,7 @@ import { RecoverPageRoutingModule } from './recover-routing.module';
|
||||
IonicModule,
|
||||
RecoverPageRoutingModule,
|
||||
PasswordPageModule,
|
||||
PipesModule,
|
||||
],
|
||||
declarations: [RecoverPage]
|
||||
})
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
<ion-card color="dark">
|
||||
<ion-card-header class="ion-text-center" style="padding-bottom: 8px;">
|
||||
<ion-card-title>{{ loading ? 'Loading Recovery Drives' : 'Select Recovery Drive'}}</ion-card-title>
|
||||
<ion-card-subtitle>Select the drive containing the Embassy you want to recover.</ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
|
||||
|
||||
<ion-card-content class="ion-margin">
|
||||
<ng-container *ngIf="!loading && !recoveryDrives.length">
|
||||
<h2 color="light">No recovery drives found</h2>
|
||||
<p color="light">Please connect a recovery drive to your embassy and refresh the page.</p>
|
||||
<p color="light">Please connect a recovery drive to your Embassy and refresh the page.</p>
|
||||
<ion-button
|
||||
(click)="window.location.reload()"
|
||||
style="text-align:center"
|
||||
@@ -43,22 +44,27 @@
|
||||
<ion-item (click)="chooseDrive(drive)" class="ion-margin-bottom" button color="light" lines="none" *ngFor="let drive of recoveryDrives" [ngClass]="drive.logicalname === selectedDrive?.logicalname ? 'selected' : null">
|
||||
<ion-icon slot="start" name="save-outline"></ion-icon>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h1>{{ drive.logicalname }}</h1>
|
||||
<h2>{{ drive.model }}</h2>
|
||||
<p> Embassy version: {{drive['embassy_os'].version}}</p>
|
||||
<h1>{{ drive.logicalname }} - {{ drive.capacity | convertBytes }}</h1>
|
||||
<h2 *ngIf="drive.vendor || drive.model">
|
||||
{{ drive.vendor }}
|
||||
<span *ngIf="drive.vendor && drive.model"> - </span>
|
||||
{{ drive.model }}
|
||||
</h2>
|
||||
<h2> Embassy version: {{drive['embassy_os'].version}}</h2>
|
||||
</ion-label>
|
||||
<ion-icon *ngIf="drive['embassy_os'].version.startsWith('0.2') || passwords[drive.logicalname]" color="success" slot="end" name="lock-open-outline"></ion-icon>
|
||||
<ion-icon *ngIf="!drive['embassy_os'].version.startsWith('0.2') && !passwords[drive.logicalname]" color="danger" slot="end" name="lock-closed-outline"></ion-icon>
|
||||
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
<ion-button
|
||||
(click)="selectRecoveryDrive()"
|
||||
[disabled]="!selectedDrive || (!passwords[selectedDrive.logicalname] && !selectedDrive['embassy_os'].version.startsWith('0.2'))"
|
||||
class="claim-button"
|
||||
>
|
||||
Next
|
||||
</ion-button>
|
||||
<ion-button
|
||||
(click)="selectRecoveryDrive()"
|
||||
color="light"
|
||||
[disabled]="!selectedDrive || (!passwords[selectedDrive.logicalname] && !selectedDrive['embassy_os'].version.startsWith('0.2'))"
|
||||
class="claim-button"
|
||||
>
|
||||
Next
|
||||
</ion-button>
|
||||
</ion-item-group>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
@@ -16,31 +16,4 @@ ion-item {
|
||||
--border-style: solid;
|
||||
--border-width: 1px;
|
||||
--border-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ export class RecoverPage {
|
||||
constructor(
|
||||
private readonly apiService: ApiService,
|
||||
private readonly navCtrl: NavController,
|
||||
private modalController: ModalController,
|
||||
private stateService: StateService
|
||||
private readonly modalController: ModalController,
|
||||
private readonly stateService: StateService
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -43,7 +43,8 @@ export class RecoverPage {
|
||||
component: PasswordPage,
|
||||
componentProps: {
|
||||
recoveryDrive: this.selectedDrive
|
||||
}
|
||||
},
|
||||
cssClass: 'alertlike-modal',
|
||||
})
|
||||
modal.onDidDismiss().then(async ret => {
|
||||
if (!ret.data) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</ion-card-header>
|
||||
<div class="divider"></div>
|
||||
<ion-card-content class="ion-margin">
|
||||
<p class="input-label">Tor Address:</p>
|
||||
<p class="addr-label">Tor Address:</p>
|
||||
<ion-item style="--border-radius: 8px 8px 0 0 !important;" color="light">
|
||||
<ion-label>
|
||||
<p>{{ stateService.torAddress }}</p>
|
||||
|
||||
@@ -15,35 +15,16 @@ ion-item {
|
||||
--border-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: medium;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
height: 48px;
|
||||
--background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: left;
|
||||
--background: rgb(222, 222, 222);
|
||||
border-top: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--ion-color-medium);
|
||||
ion-item {
|
||||
--border-color: var(--ion-color-medium);
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 0;
|
||||
background: linear-gradient(90deg,var(--ion-color-dark) 0,var(--ion-color-medium) 50%,var(--ion-color-dark) 100%);
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.addr-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
18
setup-wizard/src/app/pipes/convert-bytes.pipe.ts
Normal file
18
setup-wizard/src/app/pipes/convert-bytes.pipe.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
|
||||
// converts bytes to gigabytes
|
||||
@Pipe({
|
||||
name: 'convertBytes',
|
||||
})
|
||||
export class ConvertBytesPipe implements PipeTransform {
|
||||
transform (bytes: number): string {
|
||||
if (bytes === 0) return '0 Bytes'
|
||||
|
||||
const k = 1024
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
|
||||
}
|
||||
}
|
||||
10
setup-wizard/src/app/pipes/pipe.module.ts
Normal file
10
setup-wizard/src/app/pipes/pipe.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ConvertBytesPipe } from './convert-bytes.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ConvertBytesPipe],
|
||||
imports: [],
|
||||
exports: [ConvertBytesPipe],
|
||||
})
|
||||
|
||||
export class PipesModule {}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { pauseFor } from '../state.service'
|
||||
import { ApiService, DiskInfo } from './api.service'
|
||||
import { ApiService } from './api.service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -30,69 +30,75 @@ export class MockApiService extends ApiService {
|
||||
async getDrives() {
|
||||
return [
|
||||
{
|
||||
vendor: 'vendor',
|
||||
model: 'model',
|
||||
logicalname: 'Name1',
|
||||
partitions: [{
|
||||
logicalname: 'Name1',
|
||||
vendor: 'Vendor',
|
||||
model: 'Model',
|
||||
logicalname: '/dev/sda',
|
||||
partitions: [
|
||||
{
|
||||
logicalname: 'sda1',
|
||||
label: 'label 1',
|
||||
capacity: 100000,
|
||||
used: 200.1255312
|
||||
}, {
|
||||
logicalname: 'Name1',
|
||||
label: 'label 2',
|
||||
capacity: 50000,
|
||||
used: 200.1255312
|
||||
}],
|
||||
},
|
||||
{
|
||||
logicalname: 'sda2',
|
||||
label: 'label 2',
|
||||
capacity: 50000,
|
||||
used: 200.1255312
|
||||
}
|
||||
],
|
||||
capacity: 150000,
|
||||
'embassy_os': null
|
||||
},
|
||||
{
|
||||
vendor: 'vendor',
|
||||
model: 'model',
|
||||
logicalname: 'Name2',
|
||||
partitions: [{
|
||||
logicalname: 'Name2',
|
||||
label: null,
|
||||
capacity: 1600.01234,
|
||||
used: 0.00,
|
||||
}],
|
||||
vendor: 'Vendor',
|
||||
model: 'Model',
|
||||
logicalname: 'dev/sdb',
|
||||
partitions: [
|
||||
// {
|
||||
// logicalname: 'sdb1',
|
||||
// label: null,
|
||||
// capacity: 1600.01234,
|
||||
// used: 0.00,
|
||||
// }
|
||||
],
|
||||
capacity: 1600.01234,
|
||||
'embassy_os': null
|
||||
},
|
||||
{
|
||||
vendor: 'vendor',
|
||||
model: 'model',
|
||||
logicalname: 'Name3',
|
||||
partitions: [{
|
||||
logicalname: 'Name3',
|
||||
vendor: 'Vendor',
|
||||
model: 'Model',
|
||||
logicalname: 'dev/sdc',
|
||||
partitions: [
|
||||
{
|
||||
logicalname: 'sdc1',
|
||||
label: 'label 1',
|
||||
capacity: null,
|
||||
used: null
|
||||
}],
|
||||
}
|
||||
],
|
||||
capacity: 100000,
|
||||
'embassy_os': {
|
||||
version: '0.3.3',
|
||||
}
|
||||
},
|
||||
{
|
||||
vendor: 'vendor',
|
||||
model: 'model',
|
||||
logicalname: 'Name4',
|
||||
partitions: [{
|
||||
logicalname: 'Name4',
|
||||
vendor: 'Vendor',
|
||||
model: 'Model',
|
||||
logicalname: '/dev/sdd',
|
||||
partitions: [
|
||||
{
|
||||
logicalname: 'sdd1',
|
||||
label: null,
|
||||
capacity: 10000,
|
||||
used: null
|
||||
}],
|
||||
}
|
||||
],
|
||||
capacity: 10000,
|
||||
'embassy_os': {
|
||||
version: '0.2.7',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ApiService, DiskInfo } from './api/api.service'
|
||||
export class StateService {
|
||||
polling = false
|
||||
|
||||
embassyDrive: DiskInfo;
|
||||
storageDrive: DiskInfo;
|
||||
embassyPassword: string
|
||||
recoveryDrive: DiskInfo;
|
||||
recoveryPassword: string
|
||||
@@ -45,7 +45,7 @@ export class StateService {
|
||||
|
||||
async setupEmbassy () : Promise<{ torAddress: string }> {
|
||||
const ret = await this.apiService.setupEmbassy({
|
||||
'embassy-logicalname': this.embassyDrive.logicalname,
|
||||
'embassy-logicalname': this.storageDrive.logicalname,
|
||||
'embassy-password': this.embassyPassword,
|
||||
'recovery-logicalname': this.recoveryDrive?.logicalname,
|
||||
'recovery-password': this.recoveryPassword
|
||||
|
||||
@@ -25,65 +25,39 @@
|
||||
@import "~@ionic/angular/css/text-transformation.css";
|
||||
@import "~@ionic/angular/css/flex-utils.css";
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
color: var(--ion-color-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.alert-error .alert-title {
|
||||
color: var(--ion-color-danger) !important;
|
||||
}
|
||||
|
||||
.loader {
|
||||
--spinner-color: var(--ion-color-light) !important;
|
||||
}
|
||||
|
||||
ion-avatar {
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
ion-action-sheet {
|
||||
--backdrop-opacity: 0.75 !important;
|
||||
}
|
||||
|
||||
ion-alert {
|
||||
--backdrop-opacity: 0.75 !important;
|
||||
}
|
||||
|
||||
ion-loading {
|
||||
--backdrop-opacity: 0.75 !important;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
--highlight-color-valid: transparent;
|
||||
--highlight-color-invalid: transparent;
|
||||
--highlight-color-focused: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 50px 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg,rgba(255,255,255,0) 0,rgba(255, 255, 255, 0.31) 50%,rgba(255,255,255,0) 100%);
|
||||
.claim-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 24px;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-bottom: 24px;
|
||||
ion-icon {
|
||||
font-size: 28px;
|
||||
margin-right: 10px;
|
||||
.alertlike-modal {
|
||||
.modal-wrapper {
|
||||
max-height: 380px !important;
|
||||
top: 25% !important;
|
||||
width: 90% !important;
|
||||
left: 5% !important;
|
||||
--box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.success-alert .alert-wrapper {
|
||||
box-shadow: 4px 4px 30px var(--ion-color-light);
|
||||
border: 1px solid rgba(255,255,255,.3);
|
||||
background: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.success-alert .alert-title {
|
||||
color: var(--ion-color-success);
|
||||
@media (min-width:1000px) {
|
||||
.alertlike-modal {
|
||||
.modal-wrapper {
|
||||
width: 40% !important;
|
||||
left: 30% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
/** Ionic CSS Variables **/
|
||||
:root {
|
||||
--ion-text-color: var(--ion-color-dark);
|
||||
--ion-text-color-rgb: var(--ion-color-dark-rgb);
|
||||
|
||||
--ion-font-family: 'Benton Sans';
|
||||
/** primary **/
|
||||
--ion-color-primary: #428cff;
|
||||
|
||||
Reference in New Issue
Block a user