mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
toast errors and some styling
This commit is contained in:
committed by
Aiden McClelland
parent
c2313b4eb3
commit
6bbe19aed7
@@ -49,6 +49,7 @@ const routes: Routes = [
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {
|
||||
scrollPositionRestoration: 'enabled',
|
||||
preloadingStrategy: PreloadAllModules,
|
||||
initialNavigation: 'disabled',
|
||||
useHash: true,
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
.menu-style {
|
||||
border-style: solid;
|
||||
border-width: 0px 1px 0px 0px;
|
||||
border-color: #ff4960;
|
||||
border-color: var(--ion-color-danger);
|
||||
ion-item::part(native) {
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-badge {
|
||||
|
||||
@@ -11,11 +11,8 @@
|
||||
|
||||
<ion-content>
|
||||
<text-spinner *ngIf="loading; else loaded" [text]="'Loading ' + title | titlecase"></text-spinner>
|
||||
<ng-template #loaded>
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div *ngIf="content" class="content-padding" [innerHTML]="content | markdown"></div>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'markdown',
|
||||
@@ -12,10 +13,10 @@ export class MarkdownPage {
|
||||
@Input() title: string
|
||||
content: string
|
||||
loading = true
|
||||
error = ''
|
||||
|
||||
constructor (
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
) { }
|
||||
|
||||
@@ -23,7 +24,8 @@ export class MarkdownPage {
|
||||
try {
|
||||
this.content = await this.apiService.getStatic(this.contentUrl)
|
||||
} catch (e) {
|
||||
this.error = e.message
|
||||
console.error(e.message)
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ export class OSWelcomePage {
|
||||
) { }
|
||||
|
||||
async dismiss () {
|
||||
this.apiService.setDbValue({ pointer: '/welcome-ack', value: this.config.version }).catch(console.error)
|
||||
this.apiService.setDbValue({ pointer: '/welcome-ack', value: this.config.version })
|
||||
.catch(console.error)
|
||||
|
||||
// return false to skip subsequent alert modals (e.g. check for updates modals)
|
||||
// return true to show subsequent alert modals
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Instructions"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<div *ngIf="instructions" class="instuctions-padding" [innerHTML]="instructions | markdown"></div>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Component, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { IonContent } from '@ionic/angular'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { concatMap, take, tap } from 'rxjs/operators'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-instructions',
|
||||
@@ -14,42 +13,30 @@ import { ApiService } from 'src/app/services/api/api.service'
|
||||
export class AppInstructionsPage {
|
||||
instructions: string
|
||||
loading = true
|
||||
error = ''
|
||||
|
||||
@ViewChild(IonContent) content: IonContent
|
||||
subs: Subscription[] = []
|
||||
|
||||
constructor (
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
private readonly patch: PatchDbModel,
|
||||
) { }
|
||||
|
||||
async ngOnInit () {
|
||||
const pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||
this.patch.watch$('package-data', pkgId)
|
||||
.pipe(
|
||||
concatMap(pkg => this.apiService.getStatic(pkg['static-files'].instructions)),
|
||||
tap(instructions => {
|
||||
this.instructions = instructions
|
||||
}),
|
||||
take(1),
|
||||
)
|
||||
.subscribe(
|
||||
() => { this.loading = false },
|
||||
e => {
|
||||
this.error = e.message
|
||||
this.loading = false
|
||||
},
|
||||
() => console.log('COMPLETE'),
|
||||
)
|
||||
const url = this.patch.data['package-data'][pkgId]['static-files'].instructions
|
||||
try {
|
||||
this.instructions = await this.apiService.getStatic(url)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
|
||||
<ion-content class="ion-padding" color="light">
|
||||
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<text-spinner *ngIf="!logs" text="Loading Logs"></text-spinner>
|
||||
|
||||
<div style="white-space: pre-line;">{{ logs }}</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { IonContent } from '@ionic/angular'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-logs',
|
||||
@@ -12,10 +13,10 @@ export class AppLogsPage {
|
||||
@ViewChild(IonContent, { static: false }) private content: IonContent
|
||||
pkgId: string
|
||||
logs = ''
|
||||
error = ''
|
||||
|
||||
constructor (
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
) { }
|
||||
|
||||
@@ -32,7 +33,8 @@ export class AppLogsPage {
|
||||
this.logs = logs.map(l => `${l.timestamp} ${l.log}`).join('\n\n')
|
||||
setTimeout(async () => await this.content.scrollToBottom(100), 200)
|
||||
} catch (e) {
|
||||
this.error = e.message
|
||||
console.error(e)
|
||||
this.errToast.present(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content *ngIf="pkg">
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
<ion-content>
|
||||
|
||||
<ion-card>
|
||||
<ion-card-header>
|
||||
<ion-card-title>
|
||||
@@ -19,41 +17,61 @@
|
||||
</ion-card-title>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-item *ngIf="!(pkg.installed?.status.main.health | empty); else noHealth" color="light" style="margin: 10px;">
|
||||
<ion-item *ngIf="pkg.installed?.status.main.health | empty; else health">
|
||||
<ion-label>
|
||||
<div *ngFor="let health of pkg.installed.status.main.health | keyvalue : asIsOrder" class="align" style="margin-left: 12px;">
|
||||
<ion-icon *ngIf="health.value.result === 'success'" name="checkmark-outline" color="success"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'starting'" name="timer-outline" color="warning"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'loading'" name="sync-circle-outline" color="warning"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'failure'" name="close-outline" color="danger"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'disabled'" name="remove-outline" color="medium"></ion-icon>
|
||||
<h2>{{ health.key }}</h2>
|
||||
<p style="margin-left: 24px;" *ngIf="health.value.result === 'failure'"><ion-text color="danger">{{ health.value.error }}</ion-text></p>
|
||||
</div>
|
||||
No health checks
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ng-template #noHealth>
|
||||
No health checks
|
||||
<ng-template #health>
|
||||
<ion-item *ngIf="!(pkg.installed?.status.main.health | empty); else noHealth" color="light" style="margin: 10px;">
|
||||
<ion-label>
|
||||
<div *ngFor="let health of pkg.installed.status.main.health | keyvalue : asIsOrder" class="align" style="margin-left: 12px;">
|
||||
<ion-icon *ngIf="health.value.result === 'success'" name="checkmark-outline" color="success"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'starting'" name="timer-outline" color="warning"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'loading'" name="sync-circle-outline" color="warning"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'failure'" name="close-outline" color="danger"></ion-icon>
|
||||
<ion-icon *ngIf="health.value.result === 'disabled'" name="remove-outline" color="medium"></ion-icon>
|
||||
<h2>{{ health.key }}</h2>
|
||||
<p style="margin-left: 24px;" *ngIf="health.value.result === 'failure'"><ion-text color="danger">{{ health.value.error }}</ion-text></p>
|
||||
</div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<ion-card>
|
||||
<ion-card-header>
|
||||
<ion-card-title>
|
||||
<ion-icon style="vertical-align: middle; padding-right: 12px;" name="analytics-outline"></ion-icon>
|
||||
<span style="vertical-align: middle;">Service Metrics</span>
|
||||
<ion-icon style="vertical-align: middle; padding-right: 12px;" name="pulse-outline"></ion-icon>
|
||||
<span style="vertical-align: middle;">Metrics</span>
|
||||
</ion-card-title>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-item *ngFor="let metric of metrics | keyvalue : asIsOrder">
|
||||
<ion-label>
|
||||
<ion-text color="medium">{{ metric.key }}</ion-text>
|
||||
</ion-label>
|
||||
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
|
||||
<ion-text style="color: white;">{{ metric.value.value }} {{ metric.value.unit }}</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ng-container *ngIf="loading">
|
||||
<div class="post">
|
||||
<div class="label"></div>
|
||||
<div class="note"></div>
|
||||
</div>
|
||||
<div class="post">
|
||||
<div class="label"></div>
|
||||
<div class="note"></div>
|
||||
</div>
|
||||
<div class="post">
|
||||
<div class="label"></div>
|
||||
<div class="note"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ion-item-group *ngIf="!loading">
|
||||
<ion-item *ngFor="let metric of metrics | keyvalue : asIsOrder">
|
||||
<ion-label>
|
||||
<ion-text color="medium">{{ metric.key }}</ion-text>
|
||||
</ion-label>
|
||||
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
|
||||
<ion-text style="color: white;">{{ metric.value.value }} {{ metric.value.unit }}</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
</ion-content>
|
||||
|
||||
@@ -1,3 +1,44 @@
|
||||
.metric-note {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
$base-color: #7b7b7b;
|
||||
$shine-color: #8a8a8a;
|
||||
$animation-duration: 1.2s;
|
||||
|
||||
@mixin background-gradient {
|
||||
background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px);
|
||||
background-size: 100px;
|
||||
}
|
||||
|
||||
.post {
|
||||
height: 52px;
|
||||
position: relative;
|
||||
left: 12px;
|
||||
.label {
|
||||
float: left;
|
||||
left: 30px;
|
||||
width: 55%;
|
||||
height: 24px;
|
||||
margin: 14px 0;
|
||||
border-radius: 7px;
|
||||
@include background-gradient;
|
||||
animation: shine-lines $animation-duration infinite linear
|
||||
}
|
||||
.note {
|
||||
float: right;
|
||||
position: relative;
|
||||
right: 12px;
|
||||
width: 30%;
|
||||
height: 24px;
|
||||
margin: 14px 0;
|
||||
border-radius: 7px;
|
||||
@include background-gradient;
|
||||
animation: shine-lines $animation-duration infinite linear
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shine-lines {
|
||||
0% { background-position: -100px; }
|
||||
40%, 100% { background-position: 140px; }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ActivatedRoute } from '@angular/router'
|
||||
import { IonContent } from '@ionic/angular'
|
||||
import { Metric } from 'src/app/services/api/api-types'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { pauseFor } from 'src/app/util/misc.util'
|
||||
@@ -13,6 +14,7 @@ import { pauseFor } from 'src/app/util/misc.util'
|
||||
styleUrls: ['./app-metrics.page.scss'],
|
||||
})
|
||||
export class AppMetricsPage {
|
||||
loading = true
|
||||
pkgId: string
|
||||
pkg: PackageDataEntry
|
||||
going = false
|
||||
@@ -22,6 +24,7 @@ export class AppMetricsPage {
|
||||
|
||||
constructor (
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly patch: PatchDbModel,
|
||||
private readonly apiService: ApiService,
|
||||
) { }
|
||||
@@ -33,6 +36,10 @@ export class AppMetricsPage {
|
||||
this.startDaemon()
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.stopDaemon()
|
||||
}
|
||||
@@ -53,16 +60,14 @@ export class AppMetricsPage {
|
||||
try {
|
||||
this.metrics = await this.apiService.getPkgMetrics({ id: this.pkgId})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.errToast.present(e.message)
|
||||
this.stopDaemon()
|
||||
await pauseFor(1000)
|
||||
this.startDaemon()
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
|
||||
asIsOrder (a: any, b: any) {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -16,12 +16,8 @@
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Properties"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<!-- not running -->
|
||||
<ion-item *ngIf="notRunning" class="ion-margin-bottom">
|
||||
<ion-item *ngIf="!running" class="ion-margin-bottom">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<p><ion-text color="warning">Service not running. Information on this page could be inaccurate.</ion-text></p>
|
||||
</ion-label>
|
||||
|
||||
@@ -7,9 +7,9 @@ import { AlertController, IonContent, NavController, PopoverController, ToastCon
|
||||
import { PackageProperties } from 'src/app/util/properties.util'
|
||||
import { QRComponent } from 'src/app/components/qr/qr.component'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import * as JsonPointer from 'json-pointer'
|
||||
import { FEStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||
import { PackageMainStatus } from 'src/app/services/patch-db/data-model'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import * as JsonPointer from 'json-pointer'
|
||||
|
||||
@Component({
|
||||
selector: 'app-properties',
|
||||
@@ -17,11 +17,9 @@ import { PackageMainStatus } from 'src/app/services/patch-db/data-model'
|
||||
styleUrls: ['./app-properties.page.scss'],
|
||||
})
|
||||
export class AppPropertiesPage {
|
||||
error = ''
|
||||
loading = true
|
||||
pkgId: string
|
||||
pointer: string
|
||||
qrCode: string
|
||||
properties: PackageProperties
|
||||
node: PackageProperties
|
||||
unmasked: { [key: string]: boolean } = { }
|
||||
@@ -33,15 +31,17 @@ export class AppPropertiesPage {
|
||||
constructor (
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly apiService: ApiService,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly toastCtrl: ToastController,
|
||||
private readonly popoverCtrl: PopoverController,
|
||||
private readonly navCtrl: NavController,
|
||||
public readonly patch: PatchDbModel,
|
||||
private readonly patch: PatchDbModel,
|
||||
) { }
|
||||
|
||||
async ngOnInit () {
|
||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||
this.running = this.patch.data['package-data'][this.pkgId].installed?.status.main.status === PackageMainStatus.Running
|
||||
|
||||
await this.getProperties()
|
||||
|
||||
@@ -51,10 +51,6 @@ export class AppPropertiesPage {
|
||||
this.pointer = queryParams['pointer']
|
||||
this.node = JsonPointer.get(this.properties, this.pointer || '')
|
||||
}),
|
||||
this.patch.watch$('package-data', this.pkgId, 'installed', 'status', 'main', 'status')
|
||||
.subscribe(status => {
|
||||
this.running = status === PackageMainStatus.Running
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -116,10 +112,6 @@ export class AppPropertiesPage {
|
||||
this.unmasked[key] = !this.unmasked[key]
|
||||
}
|
||||
|
||||
asIsOrder (a: any, b: any) {
|
||||
return 0
|
||||
}
|
||||
|
||||
private async getProperties (): Promise<void> {
|
||||
this.loading = true
|
||||
try {
|
||||
@@ -127,9 +119,13 @@ export class AppPropertiesPage {
|
||||
this.node = JsonPointer.get(this.properties, this.pointer || '')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
asIsOrder (a: any, b: any) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { RouterModule, Routes } from '@angular/router'
|
||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||
import { BackupConfirmationComponentModule } from 'src/app/modals/backup-confirmation/backup-confirmation.component.module'
|
||||
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||
import { TextSpinnerComponentModule } from 'src/app/components/text-spinner/text-spinner.component.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -22,6 +23,7 @@ const routes: Routes = [
|
||||
RouterModule.forChild(routes),
|
||||
BackupConfirmationComponentModule,
|
||||
PwaBackComponentModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [
|
||||
AppRestorePage,
|
||||
|
||||
@@ -14,20 +14,9 @@
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
|
||||
<ion-grid *ngIf="loading; else loaded" style="height: 100%;">
|
||||
<ion-row class="ion-align-items-center ion-text-center" style="height: 100%;">
|
||||
<ion-col>
|
||||
<ion-spinner name="lines" color="warning"></ion-spinner>
|
||||
<p>Loading Drives</p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Drives"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-margin-bottom">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<p class="ion-padding-bottom"><ion-text color="warning">Warning</ion-text></p>
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ng-container *ngIf="pkg">
|
||||
<!-- top plate -->
|
||||
<div class="top-plate">
|
||||
|
||||
@@ -12,6 +12,7 @@ import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { DependencyErrorConfigUnsatisfied, DependencyErrorNotInstalled, DependencyErrorType, PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { FEStatus, PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show',
|
||||
@@ -19,7 +20,6 @@ import { ConnectionService } from 'src/app/services/connection.service'
|
||||
styleUrls: ['./app-show.page.scss'],
|
||||
})
|
||||
export class AppShowPage {
|
||||
error: string
|
||||
pkgId: string
|
||||
pkg: PackageDataEntry
|
||||
hideLAN: boolean
|
||||
@@ -37,6 +37,7 @@ export class AppShowPage {
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly loader: LoaderService,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly apiService: ApiService,
|
||||
@@ -62,9 +63,9 @@ export class AppShowPage {
|
||||
this.setButtons()
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
// ngAfterViewInit () {
|
||||
// this.content.scrollToPoint(undefined, 1)
|
||||
// }
|
||||
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
@@ -215,23 +216,24 @@ export class AppShowPage {
|
||||
}
|
||||
|
||||
private setError (e: Error): Observable<void> {
|
||||
this.error = e.message
|
||||
console.error(e)
|
||||
this.errToast.present(e.message)
|
||||
return of()
|
||||
}
|
||||
|
||||
setButtons (): void {
|
||||
this.buttons = [
|
||||
{
|
||||
action: () => this.navCtrl.navigateForward(['metrics'], { relativeTo: this.route }),
|
||||
title: 'Health',
|
||||
icon: 'medkit-outline',
|
||||
action: () => this.navCtrl.navigateForward(['instructions'], { relativeTo: this.route }),
|
||||
title: 'Instructions',
|
||||
icon: 'list-outline',
|
||||
color: 'danger',
|
||||
disabled: [],
|
||||
},
|
||||
{
|
||||
action: () => this.navCtrl.navigateForward(['instructions'], { relativeTo: this.route }),
|
||||
title: 'Instructions',
|
||||
icon: 'list-outline',
|
||||
action: () => this.navCtrl.navigateForward(['metrics'], { relativeTo: this.route }),
|
||||
title: 'Monitor',
|
||||
icon: 'medkit-outline',
|
||||
color: 'danger',
|
||||
disabled: [],
|
||||
},
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
<text-spinner *ngIf="pageLoading; else pageLoaded" [text]="'loading marketplace'"></text-spinner>
|
||||
|
||||
<ng-template #pageLoaded>
|
||||
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-card *ngIf="eos" class="eos-card" (click)="updateEos()">
|
||||
<ion-card-header>
|
||||
<ion-card-subtitle>Now Available...</ion-card-subtitle>
|
||||
@@ -50,7 +45,7 @@
|
||||
<ng-template #loaded>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs" sizeSm="12" sizeMd="6">
|
||||
<ion-col *ngFor="let pkg of pkgs" sizeXs="12" sizeSm="12" sizeMd="6">
|
||||
<ion-item [routerLink]="['/marketplace', pkg.id]">
|
||||
<ion-thumbnail slot="start">
|
||||
<img [src]="pkg.icon" />
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
.cat-selected {
|
||||
border-width: 0 0 1px 0;
|
||||
border-style: solid;
|
||||
border-color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@ import { wizardModal } from 'src/app/components/install-wizard/install-wizard.co
|
||||
import { IonContent, ModalController } from '@ionic/angular'
|
||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-list',
|
||||
@@ -17,7 +18,6 @@ export class MarketplaceListPage {
|
||||
@ViewChild(IonContent) content: IonContent
|
||||
pageLoading = true
|
||||
pkgsLoading = true
|
||||
error = ''
|
||||
|
||||
category = 'all'
|
||||
query: string
|
||||
@@ -37,6 +37,7 @@ export class MarketplaceListPage {
|
||||
constructor (
|
||||
private readonly apiService: ApiService,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly wizardBaker: WizardBaker,
|
||||
public readonly patch: PatchDbModel,
|
||||
) { }
|
||||
@@ -55,7 +56,7 @@ export class MarketplaceListPage {
|
||||
this.pkgs = pkgs
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.pageLoading = false
|
||||
this.pkgsLoading = false
|
||||
@@ -106,7 +107,7 @@ export class MarketplaceListPage {
|
||||
return pkgs
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.pkgsLoading = false
|
||||
}
|
||||
|
||||
@@ -12,213 +12,211 @@
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
|
||||
<text-spinner *ngIf="!marketplaceService.pkgs[pkgId]" text="Loading Package"></text-spinner>
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Package"></text-spinner>
|
||||
|
||||
<ng-container *ngIf="marketplaceService.pkgs[pkgId] as pkg">
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeXl="9" sizeLg="9" sizeMd="9" sizeSm="12" sizeXs="12">
|
||||
<div class="header">
|
||||
<img [src]="pkg.icon" />
|
||||
<div class="header-text">
|
||||
<h1 class="header-title">{{ pkg.manifest.title }}</h1>
|
||||
<p class="header-version">{{ pkg.manifest.version | displayEmver }}</p>
|
||||
<div class="header-status">
|
||||
<!-- no installedPkg -->
|
||||
<p *ngIf="!installedPkg; else local">
|
||||
<ion-text color="medium">Not Installed</ion-text>
|
||||
</p>
|
||||
<!-- installedPkg -->
|
||||
<ng-template #local>
|
||||
<p *ngIf="installedPkg.state !== PackageState.Installed; else installed">
|
||||
<!-- installing, updating, removing -->
|
||||
<ion-text [color]="installedPkg.state === PackageState.Removing ? 'danger' : 'primary'">{{ installedPkg.state }}</ion-text>
|
||||
<ion-spinner class="dots dots-medium" name="dots" [color]="installedPkg.state === PackageState.Removing ? 'danger' : 'primary'"></ion-spinner>
|
||||
</p>
|
||||
<!-- installed -->
|
||||
<ng-template #installed>
|
||||
<p>
|
||||
<ion-text color="medium">Installed at {{ installedPkg.manifest.version | displayEmver }}</ion-text>
|
||||
</p>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
||||
<!-- no installedPkg -->
|
||||
<ion-button *ngIf="!installedPkg; else installedPkg2" class="main-action-button" expand="block" (click)="install()">
|
||||
Install
|
||||
</ion-button>
|
||||
<!-- installedPkg -->
|
||||
<ng-template #installedPkg2>
|
||||
<!-- not installing, updating, or removing -->
|
||||
<ng-container *ngIf="installedPkg.state === PackageState.Installed">
|
||||
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === -1" class="main-action-button" expand="block" (click)="update('update')">
|
||||
Update
|
||||
</ion-button>
|
||||
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === 1" class="main-action-button" expand="block" color="warning" (click)="update('downgrade')">
|
||||
Downgrade
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<!-- recommendation -->
|
||||
<ion-item *ngIf="rec && showRec" class="rec-item">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 style="display: flex; align-items: center;">
|
||||
<ion-avatar style="height: 3vh; width: 3vh; margin: 5px" slot="start">
|
||||
<img [src]="rec.dependentIcon" [alt]="rec.dependentTitle"/>
|
||||
</ion-avatar>
|
||||
<ion-text style="margin: 5px; font-family: 'Montserrat'; font-size: smaller;">{{ rec.dependentTitle }}</ion-text>
|
||||
</h2>
|
||||
<div style="margin: 7px 5px;">
|
||||
<p style="color: var(--ion-color-dark); font-size: small">{{ rec.description }}</p>
|
||||
<p *ngIf="pkg.manifest.version | satisfiesEmver: rec.version" class="recommendation-text">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is compatible.</p>
|
||||
<p *ngIf="!(pkg.manifest.version | satisfiesEmver: rec.version)" class="recommendation-text recommendation-error">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is NOT compatible.</p>
|
||||
<ion-button style="position: absolute; right: 0; top: 0" color="primary" fill="clear" (click)="dismissRec()">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-group>
|
||||
<!-- release notes -->
|
||||
<ion-item-divider>
|
||||
New in {{ pkg.manifest.version | displayEmver }}
|
||||
<ion-button [routerLink]="['notes']" style="position: absolute; right: 10px;" fill="clear" color="dark">
|
||||
All Release Notes
|
||||
<ion-icon slot="end" name="arrow-forward-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item-divider>
|
||||
<ion-item lines="none" color="transparent">
|
||||
<ion-label class="ion-text-wrap" >
|
||||
<div id='release-notes' [innerHTML]="pkg.manifest['release-notes'] | markdown"></div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<!-- description -->
|
||||
<ion-item-divider>Description</ion-item-divider>
|
||||
<ion-item lines="none" color="transparent">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<div id="release-notes" class="release-notes">{{ pkg.manifest.description.long }}</div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<!-- dependencies -->
|
||||
<ng-container *ngIf="!(pkg.manifest.dependencies | empty)">
|
||||
<ion-item-divider>Dependencies</ion-item-divider>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let dep of pkg.manifest.dependencies | keyvalue" sizeSm="12" sizeMd="6">
|
||||
<ion-item *ngIf="!dep.value.optional" [routerLink]="['/marketplace', dep.key]">
|
||||
<ion-thumbnail slot="start">
|
||||
<img [src]="pkg['dependency-metadata'][dep.key].icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2>
|
||||
{{ pkg['dependency-metadata'][dep.key].title }}
|
||||
<span *ngIf="dep.value.recommended"> (recommended)</span>
|
||||
</h2>
|
||||
<p style="font-size: small">{{ dep.value.version | displayEmver }}</p>
|
||||
<p>{{ dep.value.description }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-container>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-divider>Additional Info</ion-item-divider>
|
||||
<ion-card>
|
||||
<ng-template #loaded>
|
||||
<ng-container *ngIf="marketplaceService.pkgs[pkgId] as pkg">
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item detail="false">
|
||||
<ion-label>
|
||||
<h2>Service ID</h2>
|
||||
<p>{{ pkg.manifest.id }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item detail="false">
|
||||
<ion-label>
|
||||
<h2>Categories</h2>
|
||||
<p>{{ pkg.categories.join(', ') }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentAlertVersions()">
|
||||
<ion-label>
|
||||
<h2>Other Versions</h2>
|
||||
<p>Click to view other versions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ pkg.manifest.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('instructions')">
|
||||
<ion-label>
|
||||
<h2>Instructions</h2>
|
||||
<p>Click to view instructions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
<ion-col sizeXs="12" sizeSm="12" sizeMd="9" sizeLg="9" sizeXl="9">
|
||||
<div class="header">
|
||||
<img [src]="pkg.icon" />
|
||||
<div class="header-text">
|
||||
<h1 class="header-title">{{ pkg.manifest.title }}</h1>
|
||||
<p class="header-version">{{ pkg.manifest.version | displayEmver }}</p>
|
||||
<div class="header-status">
|
||||
<!-- no installedPkg -->
|
||||
<p *ngIf="!installedPkg; else local">
|
||||
<ion-text color="medium">Not Installed</ion-text>
|
||||
</p>
|
||||
<!-- installedPkg -->
|
||||
<ng-template #local>
|
||||
<p *ngIf="installedPkg.state !== PackageState.Installed; else installed">
|
||||
<!-- installing, updating, removing -->
|
||||
<ion-text [color]="installedPkg.state === PackageState.Removing ? 'danger' : 'primary'">{{ installedPkg.state }}</ion-text>
|
||||
<ion-spinner class="dots dots-medium" name="dots" [color]="installedPkg.state === PackageState.Removing ? 'danger' : 'primary'"></ion-spinner>
|
||||
</p>
|
||||
<!-- installed -->
|
||||
<ng-template #installed>
|
||||
<p>
|
||||
<ion-text color="medium">Installed at {{ installedPkg.manifest.version | displayEmver }}</ion-text>
|
||||
</p>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item [href]="pkg.manifest['upstream-repo']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Source Repository</h2>
|
||||
<p>{{ pkg.manifest['upstream-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['wrapper-repo']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Wrapper Repository</h2>
|
||||
<p>{{ pkg.manifest['wrapper-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['support-site']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Support Site</h2>
|
||||
<p>{{ pkg.manifest['support-site'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['marketing-site']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Marketing Site</h2>
|
||||
<p>{{ pkg.manifest['marketing-site'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="pkg.manifest['donation-url'] as donationUrl" [href]="donationUrl" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Donation Site</h2>
|
||||
<p>{{ donationUrl }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
||||
<!-- no installedPkg -->
|
||||
<ion-button *ngIf="!installedPkg; else installedPkg2" class="main-action-button" expand="block" (click)="install()">
|
||||
Install
|
||||
</ion-button>
|
||||
<!-- installedPkg -->
|
||||
<ng-template #installedPkg2>
|
||||
<!-- not installing, updating, or removing -->
|
||||
<ng-container *ngIf="installedPkg.state === PackageState.Installed">
|
||||
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === -1" class="main-action-button" expand="block" (click)="update('update')">
|
||||
Update
|
||||
</ion-button>
|
||||
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === 1" class="main-action-button" expand="block" color="warning" (click)="update('downgrade')">
|
||||
Downgrade
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
|
||||
<!-- recommendation -->
|
||||
<ion-item *ngIf="rec && showRec" class="rec-item">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 style="display: flex; align-items: center;">
|
||||
<ion-avatar style="height: 3vh; width: 3vh; margin: 5px" slot="start">
|
||||
<img [src]="rec.dependentIcon" [alt]="rec.dependentTitle"/>
|
||||
</ion-avatar>
|
||||
<ion-text style="margin: 5px; font-family: 'Montserrat'; font-size: smaller;">{{ rec.dependentTitle }}</ion-text>
|
||||
</h2>
|
||||
<div style="margin: 7px 5px;">
|
||||
<p style="color: var(--ion-color-dark); font-size: small">{{ rec.description }}</p>
|
||||
<p *ngIf="pkg.manifest.version | satisfiesEmver: rec.version" class="recommendation-text">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is compatible.</p>
|
||||
<p *ngIf="!(pkg.manifest.version | satisfiesEmver: rec.version)" class="recommendation-text recommendation-error">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is NOT compatible.</p>
|
||||
<ion-button style="position: absolute; right: 0; top: 0" color="primary" fill="clear" (click)="dismissRec()">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-group>
|
||||
<!-- release notes -->
|
||||
<ion-item-divider>
|
||||
New in {{ pkg.manifest.version | displayEmver }}
|
||||
<ion-button [routerLink]="['notes']" style="position: absolute; right: 10px;" fill="clear" color="dark">
|
||||
All Release Notes
|
||||
<ion-icon slot="end" name="arrow-forward-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item-divider>
|
||||
<ion-item lines="none" color="transparent">
|
||||
<ion-label class="ion-text-wrap" >
|
||||
<div id='release-notes' [innerHTML]="pkg.manifest['release-notes'] | markdown"></div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<!-- description -->
|
||||
<ion-item-divider>Description</ion-item-divider>
|
||||
<ion-item lines="none" color="transparent">
|
||||
<ion-label class="ion-text-wrap">
|
||||
<div id="release-notes" class="release-notes">{{ pkg.manifest.description.long }}</div>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<!-- dependencies -->
|
||||
<ng-container *ngIf="!(pkg.manifest.dependencies | empty)">
|
||||
<ion-item-divider>Dependencies</ion-item-divider>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let dep of pkg.manifest.dependencies | keyvalue" sizeSm="12" sizeMd="6">
|
||||
<ion-item *ngIf="!dep.value.optional" [routerLink]="['/marketplace', dep.key]">
|
||||
<ion-thumbnail slot="start">
|
||||
<img [src]="pkg['dependency-metadata'][dep.key].icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2>
|
||||
{{ pkg['dependency-metadata'][dep.key].title }}
|
||||
<span *ngIf="dep.value.recommended"> (recommended)</span>
|
||||
</h2>
|
||||
<p style="font-size: small">{{ dep.value.version | displayEmver }}</p>
|
||||
<p>{{ dep.value.description }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-container>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-divider>Additional Info</ion-item-divider>
|
||||
<ion-card>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item detail="false">
|
||||
<ion-label>
|
||||
<h2>Service ID</h2>
|
||||
<p>{{ pkg.manifest.id }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item detail="false">
|
||||
<ion-label>
|
||||
<h2>Categories</h2>
|
||||
<p>{{ pkg.categories.join(', ') }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentAlertVersions()">
|
||||
<ion-label>
|
||||
<h2>Other Versions</h2>
|
||||
<p>Click to view other versions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ pkg.manifest.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('instructions')">
|
||||
<ion-label>
|
||||
<h2>Instructions</h2>
|
||||
<p>Click to view instructions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item [href]="pkg.manifest['upstream-repo']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Source Repository</h2>
|
||||
<p>{{ pkg.manifest['upstream-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['wrapper-repo']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Wrapper Repository</h2>
|
||||
<p>{{ pkg.manifest['wrapper-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['support-site']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Support Site</h2>
|
||||
<p>{{ pkg.manifest['support-site'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item [href]="pkg.manifest['marketing-site']" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Marketing Site</h2>
|
||||
<p>{{ pkg.manifest['marketing-site'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="pkg.manifest['donation-url'] as donationUrl" [href]="donationUrl" target="_blank" detail="false">
|
||||
<ion-label>
|
||||
<h2>Donation Site</h2>
|
||||
<p>{{ donationUrl }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Component, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { AlertController, IonContent, ModalController, NavController } from '@ionic/angular'
|
||||
import { AlertController, IonContent, ModalController, NavController, ToastController } from '@ionic/angular'
|
||||
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||
import { Emver } from 'src/app/services/emver.service'
|
||||
import { displayEmver } from 'src/app/pipes/emver.pipe'
|
||||
import { pauseFor, Recommendation } from 'src/app/util/misc.util'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { MarketplaceService } from '../marketplace.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
@@ -19,7 +20,7 @@ import { MarkdownPage } from 'src/app/modals/markdown/markdown.page'
|
||||
})
|
||||
export class MarketplaceShowPage {
|
||||
@ViewChild(IonContent) content: IonContent
|
||||
error = ''
|
||||
loading = true
|
||||
pkgId: string
|
||||
installedPkg: PackageDataEntry
|
||||
PackageState = PackageState
|
||||
@@ -32,11 +33,12 @@ export class MarketplaceShowPage {
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly wizardBaker: WizardBaker,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly emver: Emver,
|
||||
private readonly patch: PatchDbModel,
|
||||
public readonly marketplaceService: MarketplaceService,
|
||||
private readonly marketplaceService: MarketplaceService,
|
||||
) { }
|
||||
|
||||
async ngOnInit () {
|
||||
@@ -66,7 +68,10 @@ export class MarketplaceShowPage {
|
||||
await this.marketplaceService.setPkg(this.pkgId, version)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
await pauseFor(100)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,10 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
|
||||
<ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
|
||||
<ion-refresher-content pullingIcon="lines" refreshingSpinner="lines"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-spinner *ngIf="loading" class="center" name="lines" color="warning"></ion-spinner>
|
||||
|
||||
<ion-item-group *ngIf="!notifications.length && !loading">
|
||||
|
||||
@@ -4,6 +4,7 @@ import { LoaderService } from 'src/app/services/loader.service'
|
||||
import { ServerNotification, ServerNotifications } from 'src/app/services/api/api-types'
|
||||
import { AlertController } from '@ionic/angular'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'notifications',
|
||||
@@ -11,7 +12,6 @@ import { ActivatedRoute } from '@angular/router'
|
||||
styleUrls: ['notifications.page.scss'],
|
||||
})
|
||||
export class NotificationsPage {
|
||||
error = ''
|
||||
loading = true
|
||||
notifications: ServerNotifications = []
|
||||
page = 1
|
||||
@@ -22,6 +22,7 @@ export class NotificationsPage {
|
||||
constructor (
|
||||
private readonly apiService: ApiService,
|
||||
private readonly loader: LoaderService,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly route: ActivatedRoute,
|
||||
) { }
|
||||
@@ -50,10 +51,9 @@ export class NotificationsPage {
|
||||
notifications = await this.apiService.getNotifications({ page: this.page, 'per-page': this.perPage })
|
||||
this.needInfinite = notifications.length >= this.perPage
|
||||
this.page++
|
||||
this.error = ''
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
return notifications
|
||||
}
|
||||
@@ -67,11 +67,10 @@ export class NotificationsPage {
|
||||
}).displayDuringP(
|
||||
this.apiService.deleteNotification({ id }).then(() => {
|
||||
this.notifications.splice(index, 1)
|
||||
this.error = ''
|
||||
}),
|
||||
).catch(e => {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { RouterModule, Routes } from '@angular/router'
|
||||
import { DevSSHKeysPage } from './dev-ssh-keys.page'
|
||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||
import { TextSpinnerComponentModule } from 'src/app/components/text-spinner/text-spinner.component.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -20,6 +21,7 @@ const routes: Routes = [
|
||||
RouterModule.forChild(routes),
|
||||
PwaBackComponentModule,
|
||||
SharingModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [DevSSHKeysPage],
|
||||
})
|
||||
|
||||
@@ -13,11 +13,7 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item *ngIf="error" class="ion-margin-bottom">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-spinner *ngIf="loading" class="center" name="lines" color="warning"></ion-spinner>
|
||||
<text-spinner *ngIf="loading" text="Loading Keys"></text-spinner>
|
||||
|
||||
<ion-item-group>
|
||||
<ion-item-divider>Saved Keys</ion-item-divider>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { LoaderService } from 'src/app/services/loader.service'
|
||||
import { SSHService } from './ssh.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { SSHKeys } from 'src/app/services/api/api-types'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'dev-ssh-keys',
|
||||
@@ -12,21 +13,19 @@ import { SSHKeys } from 'src/app/services/api/api-types'
|
||||
styleUrls: ['dev-ssh-keys.page.scss'],
|
||||
})
|
||||
export class DevSSHKeysPage {
|
||||
error = ''
|
||||
loading = true
|
||||
sshKeys: SSHKeys
|
||||
subs: Subscription[] = []
|
||||
|
||||
constructor (
|
||||
private readonly loader: LoaderService,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly serverConfigService: ServerConfigService,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly sshService: SSHService,
|
||||
) { }
|
||||
|
||||
async ngOnInit () {
|
||||
await this.sshService.getKeys()
|
||||
|
||||
this.subs = [
|
||||
this.sshService.watch$()
|
||||
.subscribe(keys => {
|
||||
@@ -34,6 +33,8 @@ export class DevSSHKeysPage {
|
||||
}),
|
||||
]
|
||||
|
||||
await this.sshService.getKeys()
|
||||
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
@@ -68,7 +69,6 @@ export class DevSSHKeysPage {
|
||||
}
|
||||
|
||||
async delete (hash: string): Promise<void> {
|
||||
this.error = ''
|
||||
this.loader.of({
|
||||
message: 'Deleting...',
|
||||
spinner: 'lines',
|
||||
@@ -77,7 +77,7 @@ export class DevSSHKeysPage {
|
||||
await this.sshService.delete(hash)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.error = ''
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ServerBackupPage } from './server-backup.page'
|
||||
import { RouterModule, Routes } from '@angular/router'
|
||||
import { BackupConfirmationComponentModule } from 'src/app/modals/backup-confirmation/backup-confirmation.component.module'
|
||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||
import { TextSpinnerComponentModule } from 'src/app/components/text-spinner/text-spinner.component.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -20,6 +21,7 @@ const routes: Routes = [
|
||||
RouterModule.forChild(routes),
|
||||
BackupConfirmationComponentModule,
|
||||
PwaBackComponentModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [
|
||||
ServerBackupPage,
|
||||
|
||||
@@ -13,12 +13,7 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-spinner *ngIf="loading; else loaded" name="lines" color="warning" class="center"></ion-spinner>
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Drives"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Routes, RouterModule } from '@angular/router'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { ServerLogsPage } from './server-logs.page'
|
||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||
import { TextSpinnerComponentModule } from 'src/app/components/text-spinner/text-spinner.component.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -18,6 +19,7 @@ const routes: Routes = [
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
PwaBackComponentModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [ServerLogsPage],
|
||||
})
|
||||
|
||||
@@ -13,11 +13,7 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding" color="light">
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-spinner *ngIf="loading; else loaded" class="center" name="lines" color="warning"></ion-spinner>
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Logs"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
<p style="white-space: pre-line;">{{ logs }}</p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, ViewChild } from '@angular/core'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { IonContent } from '@ionic/angular'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'server-logs',
|
||||
@@ -10,10 +11,10 @@ import { IonContent } from '@ionic/angular'
|
||||
export class ServerLogsPage {
|
||||
@ViewChild(IonContent, { static: false }) private content: IonContent
|
||||
loading = true
|
||||
error = ''
|
||||
logs: string
|
||||
|
||||
constructor (
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
) { }
|
||||
|
||||
@@ -27,11 +28,10 @@ export class ServerLogsPage {
|
||||
try {
|
||||
const logs = await this.apiService.getServerLogs({ })
|
||||
this.logs = logs.map(l => `${l.timestamp} ${l.log}`).join('\n\n')
|
||||
this.error = ''
|
||||
setTimeout(async () => await this.content.scrollToBottom(100), 200)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Routes, RouterModule } from '@angular/router'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { ServerMetricsPage } from './server-metrics.page'
|
||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||
import { TextSpinnerComponentModule } from 'src/app/components/text-spinner/text-spinner.component.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -18,6 +19,7 @@ const routes: Routes = [
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
PwaBackComponentModule,
|
||||
TextSpinnerComponentModule,
|
||||
],
|
||||
declarations: [ServerMetricsPage],
|
||||
})
|
||||
|
||||
@@ -8,11 +8,7 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-spinner *ngIf="loading; else loaded" class="center" name="lines" color="warning"></ion-spinner>
|
||||
<text-spinner *ngIf="loading; else loaded" text="Loading Metrics"></text-spinner>
|
||||
|
||||
<ng-template #loaded>
|
||||
<ion-item-group *ngFor="let metricGroup of metrics | keyvalue : asIsOrder">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { Metrics } from 'src/app/services/api/api-types'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { pauseFor } from 'src/app/util/misc.util'
|
||||
|
||||
@Component({
|
||||
@@ -9,17 +10,16 @@ import { pauseFor } from 'src/app/util/misc.util'
|
||||
styleUrls: ['./server-metrics.page.scss'],
|
||||
})
|
||||
export class ServerMetricsPage {
|
||||
error = ''
|
||||
loading = true
|
||||
going = false
|
||||
metrics: Metrics = { }
|
||||
|
||||
constructor (
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
this.loading = false
|
||||
this.startDaemon()
|
||||
}
|
||||
|
||||
@@ -44,8 +44,10 @@ export class ServerMetricsPage {
|
||||
this.metrics = await this.apiService.getServerMetrics({ })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
this.stopDaemon()
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
|
||||
<ion-item *ngIf="error">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-group>
|
||||
<ion-item>
|
||||
<ion-label>Select Country</ion-label>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NavController } from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
import { WifiService } from '../wifi.service'
|
||||
import { LoaderService } from 'src/app/services/loader.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'wifi-add',
|
||||
@@ -14,17 +15,16 @@ export class WifiAddPage {
|
||||
countryCode = 'US'
|
||||
ssid = ''
|
||||
password = ''
|
||||
error = ''
|
||||
|
||||
constructor (
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly apiService: ApiService,
|
||||
private readonly loader: LoaderService,
|
||||
private readonly wifiService: WifiService,
|
||||
) { }
|
||||
|
||||
async save (): Promise<void> {
|
||||
this.error = ''
|
||||
this.loader.of({
|
||||
message: 'Saving...',
|
||||
spinner: 'lines',
|
||||
@@ -40,12 +40,11 @@ export class WifiAddPage {
|
||||
this.navCtrl.back()
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
async saveAndConnect (): Promise<void> {
|
||||
this.error = ''
|
||||
this.loader.of({
|
||||
message: 'Connecting. This could take while...',
|
||||
spinner: 'lines',
|
||||
@@ -64,7 +63,7 @@ export class WifiAddPage {
|
||||
}
|
||||
}).catch (e => {
|
||||
console.error(e)
|
||||
this.error = e.message
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item *ngIf="error">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-group>
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { LoaderService } from 'src/app/services/loader.service'
|
||||
import { WiFiInfo } from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'wifi',
|
||||
@@ -14,12 +15,12 @@ import { Subscription } from 'rxjs'
|
||||
styleUrls: ['wifi.page.scss'],
|
||||
})
|
||||
export class WifiListPage {
|
||||
error = ''
|
||||
subs: Subscription[] = []
|
||||
|
||||
constructor (
|
||||
private readonly apiService: ApiService,
|
||||
private readonly loader: LoaderService,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly actionCtrl: ActionSheetController,
|
||||
private readonly wifiService: WifiService,
|
||||
public readonly patch: PatchDbModel,
|
||||
@@ -56,7 +57,6 @@ export class WifiListPage {
|
||||
|
||||
// Let's add country code here
|
||||
async connect (ssid: string): Promise<void> {
|
||||
this.error = ''
|
||||
this.loader.of({
|
||||
message: 'Connecting. This could take while...',
|
||||
spinner: 'lines',
|
||||
@@ -66,22 +66,20 @@ export class WifiListPage {
|
||||
this.wifiService.confirmWifi(ssid)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.error = ''
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
async delete (ssid: string): Promise<void> {
|
||||
this.error = ''
|
||||
this.loader.of({
|
||||
message: 'Deleting...',
|
||||
spinner: 'lines',
|
||||
cssClass: 'loader',
|
||||
}).displayDuringAsync(async () => {
|
||||
await this.apiService.deleteWifi({ ssid })
|
||||
this.error = ''
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.error = ''
|
||||
this.errToast.present(e.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,8 +494,6 @@ export class MockApiService extends ApiService {
|
||||
const url = `${registryURL}/sys/version/eos`
|
||||
let eos = await this.http.simpleGet(url)
|
||||
return (eos as any)
|
||||
await pauseFor(2000)
|
||||
return Mock.MarketplaceEos
|
||||
}
|
||||
|
||||
async getAvailableList (params: RR.GetAvailableListReq): Promise<RR.GetAvailableListRes> {
|
||||
@@ -515,7 +513,7 @@ export class MockApiService extends ApiService {
|
||||
await pauseFor(2000)
|
||||
return Mock.AvailableShow[params.id][params.version || 'latest']
|
||||
}
|
||||
const url = `${registryURL}/marketplace/available?id=${params.id}&version=${params.version || '1.3.0'}`
|
||||
const url = `${registryURL}/marketplace/available?id=${params.id}`
|
||||
let res = await this.http.simpleGet(url)
|
||||
console.log('res RES RES', res)
|
||||
return (res as any)
|
||||
|
||||
47
ui/src/app/services/error-toast.service.ts
Normal file
47
ui/src/app/services/error-toast.service.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { IonicSafeString, ToastController } from '@ionic/angular'
|
||||
import { ToastButton } from '@ionic/core'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ErrorToastService {
|
||||
private toast: HTMLIonToastElement
|
||||
|
||||
constructor (
|
||||
private readonly toastCtrl: ToastController,
|
||||
) { }
|
||||
|
||||
async present (message: string | IonicSafeString, link?: string): Promise<void> {
|
||||
if (this.toast) return
|
||||
|
||||
if (link) {
|
||||
message = new IonicSafeString(message + `<br /><br /><a href=${link} target="_blank" style="color: white;">Get Help</a>`)
|
||||
}
|
||||
|
||||
this.toast = await this.toastCtrl.create({
|
||||
header: 'Error',
|
||||
message,
|
||||
duration: 0,
|
||||
position: 'top',
|
||||
cssClass: 'error-toast',
|
||||
buttons: [
|
||||
{
|
||||
side: 'end',
|
||||
icon: 'close',
|
||||
handler: () => {
|
||||
this.dismiss()
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
await this.toast.present()
|
||||
}
|
||||
|
||||
async dismiss (): Promise<void> {
|
||||
if (this.toast) {
|
||||
await this.toast.dismiss()
|
||||
this.toast = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,16 @@ ion-toast {
|
||||
--border-color: var(--ion-color-warning);
|
||||
}
|
||||
|
||||
.error-toast {
|
||||
--border-color: var(--ion-color-danger);
|
||||
width: 40%;
|
||||
min-width: 400px;
|
||||
--end: 8px;
|
||||
right: 8px;
|
||||
left: unset;
|
||||
top: 64px;
|
||||
}
|
||||
|
||||
.sublist-spinner {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
|
||||
Reference in New Issue
Block a user