mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
update disks type, bring back server name, and better gifs for loading and updating
This commit is contained in:
@@ -95,6 +95,7 @@
|
|||||||
<ion-icon name="medkit-outline"></ion-icon>
|
<ion-icon name="medkit-outline"></ion-icon>
|
||||||
<ion-icon name="newspaper-outline"></ion-icon>
|
<ion-icon name="newspaper-outline"></ion-icon>
|
||||||
<ion-icon name="notifications-outline"></ion-icon>
|
<ion-icon name="notifications-outline"></ion-icon>
|
||||||
|
<ion-icon name="options-outline"></ion-icon>
|
||||||
<ion-icon name="phone-portrait-outline"></ion-icon>
|
<ion-icon name="phone-portrait-outline"></ion-icon>
|
||||||
<ion-icon name="play-circle-outline"></ion-icon>
|
<ion-icon name="play-circle-outline"></ion-icon>
|
||||||
<ion-icon name="power"></ion-icon>
|
<ion-icon name="power"></ion-icon>
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ export class AppComponent {
|
|||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
backdropDismiss: false,
|
backdropDismiss: false,
|
||||||
header: 'Refresh Needed',
|
header: 'Refresh Needed',
|
||||||
message: 'Your EmbassyOS UI is out of date. Hard refresh the page to get the latest UI.',
|
message: 'Your user interface is cached and out of date. Hard refresh the page to get the latest UI.',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: 'Refresh Page',
|
text: 'Refresh Page',
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { PatchDbService } from './services/patch-db/patch-db.service'
|
|||||||
import { LocalStorageBootstrap } from './services/patch-db/local-storage-bootstrap'
|
import { LocalStorageBootstrap } from './services/patch-db/local-storage-bootstrap'
|
||||||
import { SharingModule } from './modules/sharing.module'
|
import { SharingModule } from './modules/sharing.module'
|
||||||
import { FormBuilder } from '@angular/forms'
|
import { FormBuilder } from '@angular/forms'
|
||||||
|
import { GenericInputComponentModule } from './modals/generic-input/generic-input.component.module'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
@@ -37,6 +38,7 @@ import { FormBuilder } from '@angular/forms'
|
|||||||
QrCodeModule,
|
QrCodeModule,
|
||||||
OSWelcomePageModule,
|
OSWelcomePageModule,
|
||||||
MarkdownPageModule,
|
MarkdownPageModule,
|
||||||
|
GenericInputComponentModule,
|
||||||
SharingModule,
|
SharingModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@@ -13,39 +13,50 @@
|
|||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top">
|
||||||
|
|
||||||
<text-spinner *ngIf="loading" text="Loading Drives"></text-spinner>
|
<!-- submitting -->
|
||||||
<text-spinner *ngIf="submitting" text="Initiating Backup"></text-spinner>
|
<text-spinner *ngIf="submitting" text="Initiating Backup"></text-spinner>
|
||||||
|
|
||||||
<ion-content *ngIf="!loading && !submitting">
|
<!-- not submitting -->
|
||||||
<ion-item class="ion-margin-bottom">
|
<ion-item *ngIf="!submitting" class="ion-margin-bottom">
|
||||||
|
<ion-label>
|
||||||
|
<h2>
|
||||||
|
Select the drive containing the backup you would like to restore.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<ion-text color="warning">
|
||||||
|
Warning! All current data for {{ patch.data['package-data'][pkgId].manifest.title }} will be overwritten by the backup.
|
||||||
|
</ion-text>
|
||||||
|
</h2>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<!-- loading -->
|
||||||
|
<ng-container *ngIf="loading">
|
||||||
|
<ion-item-divider>
|
||||||
|
<ion-skeleton-text animated style="width: 120px; height: 16px;"></ion-skeleton-text>
|
||||||
|
</ion-item-divider>
|
||||||
|
<ion-item>
|
||||||
|
<ion-avatar slot="start" style="margin-right: 24px;">
|
||||||
|
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
|
||||||
|
</ion-avatar>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>
|
<ion-skeleton-text animated style="width: 100px; height: 20px; margin-bottom: 12px;"></ion-skeleton-text>
|
||||||
Select the drive containing the backup you would like to restore.
|
<ion-skeleton-text animated style="width: 50px; height: 16px; margin-bottom: 16px;"></ion-skeleton-text>
|
||||||
<br />
|
<ion-skeleton-text animated style="width: 100px;"></ion-skeleton-text>
|
||||||
<br />
|
|
||||||
<ion-text color="warning">
|
|
||||||
Warning! All current data for {{ patch.data['package-data'][pkgId].manifest.title }} will be overwritten by the backup.
|
|
||||||
</ion-text>
|
|
||||||
</h2>
|
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<ion-item *ngIf="allPartitionsMounted">
|
<!-- not loading and not submitting -->
|
||||||
<ion-text class="ion-text-wrap" color="warning">No drives found containing a valid backup for {{ patch.data['package-data'][pkgId].manifest.title }}. Insert the storage device containing the backup you intend to restore.</ion-text>
|
<ion-content *ngIf="!loading && !submitting">
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<div *ngFor="let disk of disks | keyvalue">
|
<div *ngFor="let disk of disks">
|
||||||
<ion-item-divider>{{ disk.key }} - {{ disk.value.size }}</ion-item-divider>
|
<ion-item-divider>{{ disk.logicalname }} - {{ disk.capacity | convertBytes }}</ion-item-divider>
|
||||||
<ion-item button *ngFor="let partition of disk.value.partitions | keyvalue" [disabled]="partition.value['is-mounted']" (click)="presentModal(partition.key)">
|
<ion-item button *ngFor="let partition of disk.partitions" (click)="presentModal(partition.logicalname)">
|
||||||
<ion-icon slot="start" name="save-outline" size="large"></ion-icon>
|
<ion-icon slot="start" name="save-outline" size="large"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h1>{{ partition.value.label || partition.key }}</h1>
|
<h1>{{ partition.label || partition.logicalname }}</h1>
|
||||||
<h2>{{ partition.value.size || 'unknown size' }}</h2>
|
<h2>{{ partition.capacity | convertBytes }}</h2>
|
||||||
<p *ngIf="!partition.value['is-mounted']; else unavailable"><ion-text color="success">Available</ion-text></p>
|
|
||||||
<ng-template #unavailable>
|
|
||||||
<p><ion-text color="danger">Unavailable</ion-text></p>
|
|
||||||
</ng-template>
|
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { AppRestoreComponent } from './app-restore.component'
|
import { AppRestoreComponent } from './app-restore.component'
|
||||||
import { BackupConfirmationComponentModule } from '../backup-confirmation/backup-confirmation.component.module'
|
|
||||||
import { SharingModule } from '../../modules/sharing.module'
|
import { SharingModule } from '../../modules/sharing.module'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -10,7 +9,6 @@ import { SharingModule } from '../../modules/sharing.module'
|
|||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
BackupConfirmationComponentModule,
|
|
||||||
SharingModule,
|
SharingModule,
|
||||||
],
|
],
|
||||||
exports: [AppRestoreComponent],
|
exports: [AppRestoreComponent],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { ModalController } from '@ionic/angular'
|
import { ModalController } from '@ionic/angular'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { BackupConfirmationComponent } from 'src/app/modals/backup-confirmation/backup-confirmation.component'
|
import { GenericInputComponent } from 'src/app/modals/generic-input/generic-input.component'
|
||||||
import { DiskInfo } from 'src/app/services/api/api.types'
|
import { DiskInfo } from 'src/app/services/api/api.types'
|
||||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
@@ -13,7 +13,7 @@ import { ErrorToastService } from 'src/app/services/error-toast.service'
|
|||||||
})
|
})
|
||||||
export class AppRestoreComponent {
|
export class AppRestoreComponent {
|
||||||
@Input() pkgId: string
|
@Input() pkgId: string
|
||||||
disks: DiskInfo
|
disks: DiskInfo[]
|
||||||
loading = true
|
loading = true
|
||||||
submitting = false
|
submitting = false
|
||||||
allPartitionsMounted: boolean
|
allPartitionsMounted: boolean
|
||||||
@@ -39,7 +39,6 @@ export class AppRestoreComponent {
|
|||||||
async getExternalDisks (): Promise<void> {
|
async getExternalDisks (): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.disks = await this.embassyApi.getDisks({ })
|
this.disks = await this.embassyApi.getDisks({ })
|
||||||
this.allPartitionsMounted = Object.values(this.disks).every(d => Object.values(d.partitions).every(p => p['is-mounted']))
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errToast.present(e)
|
this.errToast.present(e)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -59,7 +58,7 @@ export class AppRestoreComponent {
|
|||||||
},
|
},
|
||||||
cssClass: 'alertlike-modal',
|
cssClass: 'alertlike-modal',
|
||||||
presentingElement: await this.modalCtrl.getTop(),
|
presentingElement: await this.modalCtrl.getTop(),
|
||||||
component: BackupConfirmationComponent,
|
component: GenericInputComponent,
|
||||||
})
|
})
|
||||||
|
|
||||||
modal.onWillDismiss().then(res => {
|
modal.onWillDismiss().then(res => {
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { BackupConfirmationComponent } from './backup-confirmation.component'
|
import { GenericInputComponent } from './generic-input.component'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { SharingModule } from 'src/app/modules/sharing.module'
|
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [BackupConfirmationComponent],
|
declarations: [GenericInputComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
|
FormsModule,
|
||||||
RouterModule.forChild([]),
|
RouterModule.forChild([]),
|
||||||
SharingModule,
|
SharingModule,
|
||||||
FormsModule,
|
|
||||||
],
|
],
|
||||||
exports: [BackupConfirmationComponent],
|
exports: [GenericInputComponent],
|
||||||
})
|
})
|
||||||
export class BackupConfirmationComponentModule { }
|
export class GenericInputComponentModule { }
|
||||||
@@ -3,11 +3,11 @@ import { IonicSafeString, LoadingController, ModalController } from '@ionic/angu
|
|||||||
import { getErrorMessage } from 'src/app/services/error-toast.service'
|
import { getErrorMessage } from 'src/app/services/error-toast.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'backup-confirmation',
|
selector: 'generic-input',
|
||||||
templateUrl: './backup-confirmation.component.html',
|
templateUrl: './generic-input.component.html',
|
||||||
styleUrls: ['./backup-confirmation.component.scss'],
|
styleUrls: ['./generic-input.component.scss'],
|
||||||
})
|
})
|
||||||
export class BackupConfirmationComponent {
|
export class GenericInputComponent {
|
||||||
@Input() title: string
|
@Input() title: string
|
||||||
@Input() message: string
|
@Input() message: string
|
||||||
@Input() label = 'Enter value'
|
@Input() label = 'Enter value'
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
<div style="display: flex; flex-direction: column; justify-content: space-between; height: 100%">
|
<div style="display: flex; flex-direction: column; justify-content: space-between; height: 100%">
|
||||||
<h2>A Whole New Embassy</h2>
|
<h2>A Whole New Embassy</h2>
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<p>Version {{ version }} is something new.</p>
|
<p>New features and more new features!</p>
|
||||||
<p>This release also enables displaying Service license information and contains utilities to facilitate the next major release of EmbassyOS.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="close-button">
|
<div class="close-button">
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { NotificationColorPipe } from '../pipes/notification-color.pipe'
|
|||||||
import { InstallState } from '../pipes/install-state.pipe'
|
import { InstallState } from '../pipes/install-state.pipe'
|
||||||
import { TextSpinnerComponentModule } from '../components/text-spinner/text-spinner.component.module'
|
import { TextSpinnerComponentModule } from '../components/text-spinner/text-spinner.component.module'
|
||||||
import { PwaBackComponentModule } from '../components/pwa-back-button/pwa-back.component.module'
|
import { PwaBackComponentModule } from '../components/pwa-back-button/pwa-back.component.module'
|
||||||
|
import { ConvertBytesPipe } from '../pipes/convert-bytes.pipe'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -28,6 +29,7 @@ import { PwaBackComponentModule } from '../components/pwa-back-button/pwa-back.c
|
|||||||
LaunchablePipe,
|
LaunchablePipe,
|
||||||
EmptyPipe,
|
EmptyPipe,
|
||||||
NotificationColorPipe,
|
NotificationColorPipe,
|
||||||
|
ConvertBytesPipe,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
TextSpinnerComponentModule,
|
TextSpinnerComponentModule,
|
||||||
@@ -48,6 +50,7 @@ import { PwaBackComponentModule } from '../components/pwa-back-button/pwa-back.c
|
|||||||
LaunchablePipe,
|
LaunchablePipe,
|
||||||
EmptyPipe,
|
EmptyPipe,
|
||||||
NotificationColorPipe,
|
NotificationColorPipe,
|
||||||
|
ConvertBytesPipe,
|
||||||
// components
|
// components
|
||||||
TextSpinnerComponentModule,
|
TextSpinnerComponentModule,
|
||||||
PwaBackComponentModule,
|
PwaBackComponentModule,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<ion-content *ngIf="patch.data['server-info'].status as status">
|
<ion-content *ngIf="patch.data['server-info'].status as status" style="--background: black;">
|
||||||
|
|
||||||
<ion-grid style="height: 100%;">
|
<ion-grid style="height: 100%;">
|
||||||
<ion-row class="ion-align-items-center ion-text-center" style="height: 100%;">
|
<ion-row class="ion-align-items-center ion-text-center" style="height: 100%;">
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<ng-container *ngIf="status === ServerStatus.Updating">
|
<ng-container *ngIf="status === ServerStatus.Updating">
|
||||||
<h1>Embassy Updating</h1>
|
<h1>Embassy updating</h1>
|
||||||
<img src="assets/img/gifs/cube.gif" />
|
<img src="assets/img/gifs/updating.gif" />
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="status === ServerStatus.BackingUp">
|
<ng-container *ngIf="status === ServerStatus.BackingUp">
|
||||||
<h1>Backing Up</h1>
|
<h1>Embassy backing up</h1>
|
||||||
<img src="assets/img/gifs/backing-up.gif" />
|
<img src="assets/img/gifs/backing-up.gif" />
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
img {
|
img {
|
||||||
width: 20%;
|
width: 50%;
|
||||||
border-radius: 0;
|
max-width: 500px;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { CommonModule } from '@angular/common'
|
||||||
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
import { PreferencesPage } from './preferences.page'
|
||||||
|
import { Routes, RouterModule } from '@angular/router'
|
||||||
|
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: PreferencesPage,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
SharingModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
PreferencesPage,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class PreferencesPageModule { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<pwa-back-button></pwa-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>Preferences</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding-top">
|
||||||
|
|
||||||
|
<ion-item-group>
|
||||||
|
<ion-item button (click)="presentModalName()">
|
||||||
|
<ion-label>{{ fields['name'].name }}</ion-label>
|
||||||
|
<ion-note slot="end">{{ patch.data.ui.name }}</ion-note>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-group>
|
||||||
|
|
||||||
|
</ion-content>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { Component, ViewChild } from '@angular/core'
|
||||||
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
|
import { IonContent, LoadingController, ModalController } from '@ionic/angular'
|
||||||
|
import { GenericInputComponent } from 'src/app/modals/generic-input/generic-input.component'
|
||||||
|
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||||
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'preferences',
|
||||||
|
templateUrl: './preferences.page.html',
|
||||||
|
styleUrls: ['./preferences.page.scss'],
|
||||||
|
})
|
||||||
|
export class PreferencesPage {
|
||||||
|
@ViewChild(IonContent) content: IonContent
|
||||||
|
fields = fields
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private readonly modalCtrl: ModalController,
|
||||||
|
private readonly loadingCtrl: LoadingController,
|
||||||
|
private readonly errToast: ErrorToastService,
|
||||||
|
private readonly api: ApiService,
|
||||||
|
public readonly patch: PatchDbService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngAfterViewInit () {
|
||||||
|
this.content.scrollToPoint(undefined, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
async presentModalName (): Promise<void> {
|
||||||
|
const modal = await this.modalCtrl.create({
|
||||||
|
componentProps: {
|
||||||
|
title: 'Edit Device Name',
|
||||||
|
message: 'This is for your reference only.',
|
||||||
|
label: 'Device Name',
|
||||||
|
useMask: false,
|
||||||
|
value: this.patch.data.ui.name,
|
||||||
|
buttonText: 'Save',
|
||||||
|
submitFn: async (value: string) => await this.setDbValue('name', value),
|
||||||
|
},
|
||||||
|
cssClass: 'alertlike-modal',
|
||||||
|
presentingElement: await this.modalCtrl.getTop(),
|
||||||
|
component: GenericInputComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
await modal.present()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setDbValue (key: string, value: string): Promise<void> {
|
||||||
|
const loader = await this.loadingCtrl.create({
|
||||||
|
spinner: 'lines',
|
||||||
|
message: 'Saving...',
|
||||||
|
cssClass: 'loader',
|
||||||
|
})
|
||||||
|
await loader.present()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.api.setDbValue({ pointer: `/${key}`, value })
|
||||||
|
} catch (e) {
|
||||||
|
this.errToast.present(e)
|
||||||
|
} finally {
|
||||||
|
loader.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields: ConfigSpec = {
|
||||||
|
'name': {
|
||||||
|
name: 'Device Name',
|
||||||
|
type: 'string',
|
||||||
|
nullable: false,
|
||||||
|
masked: false,
|
||||||
|
copyable: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item-divider>General</ion-item-divider>
|
<ion-item-divider>General</ion-item-divider>
|
||||||
<ion-item button (click)="serverConfig.presentAlert('share-stats', server['share-stats'])">
|
<ion-item button (click)="serverConfig.presentAlert('share-stats', server['share-stats'])">
|
||||||
<ion-label>Share Anonymous Statistics</ion-label>
|
<ion-label>Report Bugs</ion-label>
|
||||||
<ion-note slot="end">{{ server['share-stats'] ? 'Enabled' : 'Disabled' }}</ion-note>
|
<ion-note slot="end">{{ server['share-stats'] ? 'Enabled' : 'Disabled' }}</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { AlertController, LoadingController, ModalController } from '@ionic/angu
|
|||||||
import { SSHKeys } from 'src/app/services/api/api.types'
|
import { SSHKeys } from 'src/app/services/api/api.types'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { BackupConfirmationComponent } from 'src/app/modals/backup-confirmation/backup-confirmation.component'
|
import { GenericInputComponent } from 'src/app/modals/generic-input/generic-input.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ssh-keys',
|
selector: 'ssh-keys',
|
||||||
@@ -41,7 +41,7 @@ export class SSHKeysPage {
|
|||||||
const { name, description } = sshSpec
|
const { name, description } = sshSpec
|
||||||
|
|
||||||
const modal = await this.modalCtrl.create({
|
const modal = await this.modalCtrl.create({
|
||||||
component: BackupConfirmationComponent,
|
component: GenericInputComponent,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
title: name,
|
title: name,
|
||||||
message: description,
|
message: description,
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core'
|
|
||||||
import { BehaviorSubject } from 'rxjs'
|
|
||||||
import { SSHKeys } from 'src/app/services/api/api.types'
|
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class SSHService {
|
|
||||||
private readonly keys$ = new BehaviorSubject<SSHKeys>({ })
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private readonly embassyApi: ApiService,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
watch$ () {
|
|
||||||
return this.keys$.asObservable()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ import { CommonModule } from '@angular/common'
|
|||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { ServerBackupPage } from './server-backup.page'
|
import { ServerBackupPage } from './server-backup.page'
|
||||||
import { RouterModule, Routes } from '@angular/router'
|
import { RouterModule, Routes } from '@angular/router'
|
||||||
import { BackupConfirmationComponentModule } from 'src/app/modals/backup-confirmation/backup-confirmation.component.module'
|
|
||||||
import { SharingModule } from 'src/app/modules/sharing.module'
|
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
@@ -18,7 +17,6 @@ const routes: Routes = [
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
BackupConfirmationComponentModule,
|
|
||||||
SharingModule,
|
SharingModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<ion-item class="ion-margin-bottom">
|
<ion-item class="ion-margin-bottom">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>
|
<h2>
|
||||||
Select the drive where you want to create a backup of your Embassy, including all your installed services.
|
Select the drive where you want to create a backup of your Embassy.
|
||||||
</h2>
|
</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@@ -38,22 +38,14 @@
|
|||||||
<!-- loaded -->
|
<!-- loaded -->
|
||||||
<ng-container *ngIf="!loading">
|
<ng-container *ngIf="!loading">
|
||||||
|
|
||||||
<ion-item *ngIf="allPartitionsMounted">
|
|
||||||
<ion-text class="ion-text-wrap" color="warning">No partitions available. To begin a backup, insert a storage device into your Embassy.</ion-text>
|
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<div *ngFor="let disk of disks | keyvalue">
|
<div *ngFor="let disk of disks">
|
||||||
<ion-item-divider>{{ disk.key }} - {{ disk.value.size }}</ion-item-divider>
|
<ion-item-divider>{{ disk.logicalname }} - {{ disk.capacity | convertBytes }}</ion-item-divider>
|
||||||
<ion-item button *ngFor="let partition of disk.value.partitions | keyvalue" [disabled]="partition.value['is-mounted']" (click)="presentModal(partition.key)">
|
<ion-item button *ngFor="let partition of disk.partitions" (click)="presentModal(partition.logicalname)">
|
||||||
<ion-icon slot="start" name="save-outline" size="large"></ion-icon>
|
<ion-icon slot="start" name="save-outline" size="large"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h1>{{ partition.value.label || partition.key }}</h1>
|
<h1>{{ partition.label || partition.logicalname }}</h1>
|
||||||
<h2>{{ partition.value.size || 'unknown size' }}</h2>
|
<h2>{{ partition.capacity | convertBytes }}</h2>
|
||||||
<p *ngIf="!partition.value['is-mounted']; else unavailable"><ion-text color="success">Available</ion-text></p>
|
|
||||||
<ng-template #unavailable>
|
|
||||||
<p><ion-text color="danger">Unavailable</ion-text></p>
|
|
||||||
</ng-template>
|
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { ModalController } from '@ionic/angular'
|
import { ModalController } from '@ionic/angular'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { BackupConfirmationComponent } from 'src/app/modals/backup-confirmation/backup-confirmation.component'
|
import { GenericInputComponent } from 'src/app/modals/generic-input/generic-input.component'
|
||||||
import { DiskInfo } from 'src/app/services/api/api.types'
|
import { DiskInfo } from 'src/app/services/api/api.types'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import { ErrorToastService } from 'src/app/services/error-toast.service'
|
|||||||
styleUrls: ['./server-backup.page.scss'],
|
styleUrls: ['./server-backup.page.scss'],
|
||||||
})
|
})
|
||||||
export class ServerBackupPage {
|
export class ServerBackupPage {
|
||||||
disks: DiskInfo
|
disks: DiskInfo[]
|
||||||
loading = true
|
loading = true
|
||||||
allPartitionsMounted: boolean
|
allPartitionsMounted: boolean
|
||||||
|
|
||||||
@@ -33,7 +33,6 @@ export class ServerBackupPage {
|
|||||||
async getExternalDisks (): Promise<void> {
|
async getExternalDisks (): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.disks = await this.embassyApi.getDisks({ })
|
this.disks = await this.embassyApi.getDisks({ })
|
||||||
this.allPartitionsMounted = Object.values(this.disks).every(d => Object.values(d.partitions).every(p => p['is-mounted']))
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errToast.present(e)
|
this.errToast.present(e)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -52,7 +51,7 @@ export class ServerBackupPage {
|
|||||||
submitFn: async (value: string) => await this.create(logicalname, value),
|
submitFn: async (value: string) => await this.create(logicalname, value),
|
||||||
},
|
},
|
||||||
cssClass: 'alertlike-modal',
|
cssClass: 'alertlike-modal',
|
||||||
component: BackupConfirmationComponent,
|
component: GenericInputComponent,
|
||||||
})
|
})
|
||||||
|
|
||||||
return await m.present()
|
return await m.present()
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ const routes: Routes = [
|
|||||||
path: 'security',
|
path: 'security',
|
||||||
loadChildren: () => import('./security-routes/security-routing.module').then( m => m.SecurityRoutingModule),
|
loadChildren: () => import('./security-routes/security-routing.module').then( m => m.SecurityRoutingModule),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'preferences',
|
||||||
|
loadChildren: () => import('./preferences/preferences.module').then( m => m.PreferencesPageModule),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>Embassy</ion-title>
|
<ion-title>{{ patch.data.ui.name || patch.data['server-info'].id }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<badge-menu-button></badge-menu-button>
|
<badge-menu-button></badge-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { AlertController, LoadingController, NavController } from '@ionic/angula
|
|||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { ActivatedRoute } from '@angular/router'
|
import { ActivatedRoute } from '@angular/router'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'server-show',
|
selector: 'server-show',
|
||||||
@@ -19,6 +20,7 @@ export class ServerShowPage {
|
|||||||
private readonly embassyApi: ApiService,
|
private readonly embassyApi: ApiService,
|
||||||
private readonly navCtrl: NavController,
|
private readonly navCtrl: NavController,
|
||||||
private readonly route: ActivatedRoute,
|
private readonly route: ActivatedRoute,
|
||||||
|
public readonly patch: PatchDbService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
@@ -48,8 +50,8 @@ export class ServerShowPage {
|
|||||||
|
|
||||||
async presentAlertShutdown () {
|
async presentAlertShutdown () {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
header: 'Confirm',
|
header: 'Warning',
|
||||||
message: `Are you sure you want to shut down your Embassy? To turn it back on, you will need to physically unplug the device and plug it back in.`,
|
message: `Embassy will remain off. To power back on, you will need to unplug the device and plug it back in.`,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: 'Cancel',
|
text: 'Cancel',
|
||||||
@@ -103,7 +105,21 @@ export class ServerShowPage {
|
|||||||
|
|
||||||
private setButtons (): void {
|
private setButtons (): void {
|
||||||
this.settings = {
|
this.settings = {
|
||||||
|
'Backups': [
|
||||||
|
{
|
||||||
|
title: 'Create Backup',
|
||||||
|
icon: 'save-outline',
|
||||||
|
action: () => this.navCtrl.navigateForward(['backup'], { relativeTo: this.route }),
|
||||||
|
detail: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
'Settings': [
|
'Settings': [
|
||||||
|
{
|
||||||
|
title: 'Preferences',
|
||||||
|
icon: 'options-outline',
|
||||||
|
action: () => this.navCtrl.navigateForward(['preferences'], { relativeTo: this.route }),
|
||||||
|
detail: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Privacy and Security',
|
title: 'Privacy and Security',
|
||||||
icon: 'shield-checkmark-outline',
|
icon: 'shield-checkmark-outline',
|
||||||
@@ -143,14 +159,6 @@ export class ServerShowPage {
|
|||||||
detail: true,
|
detail: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'Backups': [
|
|
||||||
{
|
|
||||||
title: 'Create Backup',
|
|
||||||
icon: 'save-outline',
|
|
||||||
action: () => this.navCtrl.navigateForward(['backup'], { relativeTo: this.route }),
|
|
||||||
detail: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'Power': [
|
'Power': [
|
||||||
{
|
{
|
||||||
title: 'Restart',
|
title: 'Restart',
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<ion-item-divider>Country</ion-item-divider>
|
<ion-item-divider>Country</ion-item-divider>
|
||||||
|
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<ng-container *ngIf="loading">
|
<!-- <ng-container *ngIf="loading">
|
||||||
<ion-item class="skeleton-parts">
|
<ion-item class="skeleton-parts">
|
||||||
<ion-button slot="start" fill="clear">
|
<ion-button slot="start" fill="clear">
|
||||||
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
|
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
|
||||||
@@ -32,16 +32,14 @@
|
|||||||
<ion-skeleton-text animated style="width: 150px;"></ion-skeleton-text>
|
<ion-skeleton-text animated style="width: 150px;"></ion-skeleton-text>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ng-container>
|
</ng-container> -->
|
||||||
|
|
||||||
<!-- not loading -->
|
<!-- not loading -->
|
||||||
<ng-container *ngIf="!loading">
|
<ion-item button detail="false" (click)="presentAlertCountry()" [disabled]="loading">
|
||||||
<ion-item button detail="false" (click)="presentAlertCountry()">
|
<ion-icon slot="start" name="earth-outline" size="large"></ion-icon>
|
||||||
<ion-icon slot="start" name="earth-outline" size="large"></ion-icon>
|
<ion-label *ngIf="wifi.country">{{ wifi.country }} - {{ this.countries[wifi.country] }}</ion-label>
|
||||||
<ion-label *ngIf="wifi.country">{{ wifi.country }} - {{ this.countries[wifi.country] }}</ion-label>
|
<ion-label *ngIf="!wifi.country">Select Country</ion-label>
|
||||||
<ion-label *ngIf="!wifi.country">Select Country</ion-label>
|
</ion-item>
|
||||||
</ion-item>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<ng-container *ngIf="loading">
|
<ng-container *ngIf="loading">
|
||||||
|
|||||||
18
ui/src/app/pipes/convert-bytes.pipe.ts
Normal file
18
ui/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]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -864,46 +864,46 @@ export module Mock {
|
|||||||
'signal-strength': 50,
|
'signal-strength': 50,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Disks: RR.GetDisksRes = {
|
export const Disks: RR.GetDisksRes = [
|
||||||
'/dev/sda': {
|
{
|
||||||
size: '32GB',
|
logicalname: '/dev/sda',
|
||||||
description: 'Samsung',
|
partitions: [
|
||||||
partitions: {
|
{
|
||||||
'sdba2': {
|
logicalname: 'sdba1',
|
||||||
size: null,
|
|
||||||
'is-mounted': false,
|
|
||||||
label: 'Matt Stuff',
|
label: 'Matt Stuff',
|
||||||
|
capacity: 1000000000000,
|
||||||
|
used: 0,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
capacity: 1000000000000,
|
||||||
|
'embassy-os': {
|
||||||
|
version: '0.3.0',
|
||||||
|
name: '', // @TODO what is this?
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/dev/sba': {
|
{
|
||||||
size: '64GB',
|
logicalname: '/dev/sdb',
|
||||||
description: 'small USB stick',
|
partitions: [
|
||||||
partitions: {
|
{
|
||||||
'sdba2': {
|
logicalname: 'sdba1',
|
||||||
size: '16GB',
|
|
||||||
'is-mounted': true,
|
|
||||||
label: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/dev/sbd': {
|
|
||||||
size: '128GB',
|
|
||||||
description: 'large USB stick',
|
|
||||||
partitions: {
|
|
||||||
'sdba1': {
|
|
||||||
size: '32GB',
|
|
||||||
'is-mounted': false,
|
|
||||||
label: 'Partition 1',
|
label: 'Partition 1',
|
||||||
|
capacity: 1000000000,
|
||||||
|
used: 1000000000,
|
||||||
},
|
},
|
||||||
'sdba2': {
|
{
|
||||||
size: null,
|
logicalname: 'sdba2',
|
||||||
'is-mounted': true,
|
|
||||||
label: 'Partition 2',
|
label: 'Partition 2',
|
||||||
|
capacity: 900000000,
|
||||||
|
used: 300000000,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
capacity: 10000000000,
|
||||||
|
'embassy-os': {
|
||||||
|
version: '0.3.0',
|
||||||
|
name: '', // @TODO what is this?
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
|
|
||||||
export const PackageProperties: RR.GetPackagePropertiesRes<2> = {
|
export const PackageProperties: RR.GetPackagePropertiesRes<2> = {
|
||||||
version: 2,
|
version: 2,
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export module RR {
|
|||||||
// disk
|
// disk
|
||||||
|
|
||||||
export type GetDisksReq = { } // disk.list
|
export type GetDisksReq = { } // disk.list
|
||||||
export type GetDisksRes = DiskInfo
|
export type GetDisksRes = DiskInfo[]
|
||||||
|
|
||||||
export type EjectDisksReq = { logicalname: string } // disk.eject
|
export type EjectDisksReq = { logicalname: string } // disk.eject
|
||||||
export type EjectDisksRes = null
|
export type EjectDisksRes = null
|
||||||
@@ -289,23 +289,18 @@ export interface SessionMetadata {
|
|||||||
export type PlatformType = 'cli' | 'ios' | 'ipad' | 'iphone' | 'android' | 'phablet' | 'tablet' | 'cordova' | 'capacitor' | 'electron' | 'pwa' | 'mobile' | 'mobileweb' | 'desktop' | 'hybrid'
|
export type PlatformType = 'cli' | 'ios' | 'ipad' | 'iphone' | 'android' | 'phablet' | 'tablet' | 'cordova' | 'capacitor' | 'electron' | 'pwa' | 'mobile' | 'mobileweb' | 'desktop' | 'hybrid'
|
||||||
|
|
||||||
export interface DiskInfo {
|
export interface DiskInfo {
|
||||||
[id: string]: DiskInfoEntry
|
logicalname: string
|
||||||
}
|
partitions: {
|
||||||
|
logicalname: string
|
||||||
export interface DiskInfoEntry {
|
label: string | null
|
||||||
size: string
|
capacity: number
|
||||||
description: string | null
|
used: number | null
|
||||||
partitions: PartitionInfo
|
}[],
|
||||||
}
|
capacity: number
|
||||||
|
'embassy-os': {
|
||||||
export interface PartitionInfo {
|
version: string
|
||||||
[logicalname: string]: PartitionInfoEntry
|
name: string
|
||||||
}
|
} | null
|
||||||
|
|
||||||
export interface PartitionInfoEntry {
|
|
||||||
'is-mounted': boolean // We do not allow backups to mounted partitions
|
|
||||||
size: string | null
|
|
||||||
label: string | null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerSpecs {
|
export interface ServerSpecs {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface DataModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UIData {
|
export interface UIData {
|
||||||
|
name: string
|
||||||
'welcome-ack': string
|
'welcome-ack': string
|
||||||
'auto-check-updates': boolean
|
'auto-check-updates': boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { AlertInput, AlertButton } from '@ionic/core'
|
import { AlertInput, AlertButton, IonicSafeString } from '@ionic/core'
|
||||||
import { ApiService } from './api/embassy-api.service'
|
import { ApiService } from './api/embassy-api.service'
|
||||||
import { ConfigSpec } from '../pkg-config/config-types'
|
import { ConfigSpec } from '../pkg-config/config-types'
|
||||||
import { AlertController, LoadingController } from '@ionic/angular'
|
import { AlertController, LoadingController } from '@ionic/angular'
|
||||||
@@ -120,7 +120,7 @@ export const serverConfig: ConfigSpec = {
|
|||||||
'auto-check-updates': {
|
'auto-check-updates': {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
name: 'Auto Check for Updates',
|
name: 'Auto Check for Updates',
|
||||||
description: 'On launch, EmbassyOS will automatically check for updates of itself and your installed services. Updating still requires user approval and action. No updates will ever be performed automatically.',
|
description: 'On launch, EmbassyOS will automatically check for updates of itself and your installed services. Updating still requires your approval and action. Updates will never be performed automatically.',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
// 'eos-marketplace': {
|
// 'eos-marketplace': {
|
||||||
@@ -143,8 +143,8 @@ export const serverConfig: ConfigSpec = {
|
|||||||
// },
|
// },
|
||||||
'share-stats': {
|
'share-stats': {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
name: 'Share Anonymous Statistics',
|
name: 'Report Bugs',
|
||||||
description: 'Start9 uses this information to identify bugs quickly and improve EmbassyOS. The information is 100% anonymous and transmitted over Tor.',
|
description: new IonicSafeString(`Bug reports are anonymized and transmitted over Tor. This helps us identify and fix bugs quickly. <a href="https://docs.start9.com" target="_blank" rel="noreferrer">Read more</a> `) as any, // @TODO get actual link
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
// password: {
|
// password: {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.6 MiB After Width: | Height: | Size: 486 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 473 KiB |
BIN
ui/src/assets/img/gifs/updating.gif
Normal file
BIN
ui/src/assets/img/gifs/updating.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 MiB |
Reference in New Issue
Block a user