fix wizard and server metrics

This commit is contained in:
Matt Hill
2021-10-05 14:24:00 -06:00
committed by Aiden McClelland
parent f46d935bb0
commit b978d5062f
14 changed files with 620 additions and 584 deletions

View File

@@ -1,24 +1,16 @@
import { Component, Input, OnInit } from '@angular/core'
import { BehaviorSubject, Subject } from 'rxjs'
import { Loadable } from '../loadable'
import { Component, Input } from '@angular/core'
@Component({
selector: 'alert',
templateUrl: './alert.component.html',
styleUrls: ['../install-wizard.component.scss'],
})
export class AlertComponent implements OnInit, Loadable {
export class AlertComponent {
@Input() params: {
title: string
message: string
titleColor: string
}
loading$ = new BehaviorSubject(false)
cancel$ = new Subject<void>()
load () { }
constructor () { }
ngOnInit () { }
}

View File

@@ -1,17 +1,4 @@
<div *ngIf="!(loading$ | async) && !params.skipCompletionDialogue" class="slide-content">
<div style="margin-top: 25px;">
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
<ion-label [color]="color$ | async" style="font-size: xx-large; font-weight: bold;">
{{ successText }}
</ion-label>
</div>
<div class="long-message">
{{ summary }}
</div>
</div>
</div>
<div *ngIf="loading$ | async" class="center-spinner">
<ion-spinner color="warning" name="lines"></ion-spinner>
<ion-label class="long-message">{{ label }}</ion-label>
<ion-label class="long-message">{{ message }}</ion-label>
</div>

View File

@@ -3,7 +3,6 @@ import { CommonModule } from '@angular/common'
import { CompleteComponent } from './complete.component'
import { IonicModule } from '@ionic/angular'
import { RouterModule } from '@angular/router'
import { SharingModule } from 'src/app/modules/sharing.module'
@NgModule({
declarations: [
@@ -13,7 +12,6 @@ import { SharingModule } from 'src/app/modules/sharing.module'
CommonModule,
IonicModule,
RouterModule.forChild([]),
SharingModule,
],
exports: [CompleteComponent],
})

View File

@@ -1,8 +1,8 @@
import { Component, Input, OnInit } from '@angular/core'
import { Component, Input } from '@angular/core'
import { BehaviorSubject, from, Subject } from 'rxjs'
import { takeUntil } from 'rxjs/operators'
import { capitalizeFirstLetter } from 'src/app/util/misc.util'
import { Loadable, markAsLoadingDuring$ } from '../loadable'
import { markAsLoadingDuring$ } from '../loadable'
import { WizardAction } from '../wizard-types'
@Component({
@@ -10,13 +10,12 @@ import { WizardAction } from '../wizard-types'
templateUrl: './complete.component.html',
styleUrls: ['../install-wizard.component.scss'],
})
export class CompleteComponent implements OnInit, Loadable {
export class CompleteComponent {
@Input() params: {
action: WizardAction
verb: string // loader verb: '*stopping* ...'
title: string
executeAction: () => Promise<any>
skipCompletionDialogue?: boolean
}
@Input() transitions: {
@@ -27,61 +26,20 @@ export class CompleteComponent implements OnInit, Loadable {
}
loading$ = new BehaviorSubject(false)
color$ = new BehaviorSubject('medium')
cancel$ = new Subject<void>()
label: string
summary: string
successText: string
message: string
load () {
markAsLoadingDuring$(this.loading$, from(this.params.executeAction())).pipe(takeUntil(this.cancel$)).subscribe(
{
error: e => this.transitions.error(new Error(`${this.params.action} failed: ${e.message || e}`)),
complete: () => this.params.skipCompletionDialogue && this.transitions.final(),
complete: () => this.transitions.final(),
},
)
}
constructor () { }
ngOnInit () {
switch (this.params.action) {
case 'install':
this.summary = `Installation of ${this.params.title} is now in progress. You will receive a notification when the installation has completed.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('primary')
this.successText = 'In Progress'
break
case 'downgrade':
this.summary = `Downgrade for ${this.params.title} is now in progress. You will receive a notification when the downgrade has completed.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('primary')
this.successText = 'In Progress'
break
case 'update':
this.summary = `Update for ${this.params.title} is now in progress. You will receive a notification when the update has completed.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('primary')
this.successText = 'In Progress'
break
case 'uninstall':
this.summary = `${capitalizeFirstLetter(this.params.title)} has been successfully uninstalled.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('success')
this.successText = 'Success'
break
case 'stop':
this.summary = `${capitalizeFirstLetter(this.params.title)} has been successfully stopped.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('success')
this.successText = 'Success'
break
case 'configure':
this.summary = `New config for ${this.params.title} has been successfully saved.`
this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
this.color$.next('success')
this.successText = 'Success'
break
}
this.message = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...`
}
}

View File

@@ -16,11 +16,11 @@
</ion-label>
</div>
<div *ngIf="longMessage" class="long-message" >
{{ longMessage }}
<div *ngIf="message" class="long-message" >
{{ message }}
</div>
<div style="margin: 25px 0px;">
<div *ngIf="hasDependentViolation" style="border-width: 0px 0px 1px 0px; font-size: unset; text-align: left; font-weight: bold; margin-left: 13px; border-style: solid; border-color: var(--ion-color-light-tint);">
<div *ngIf="hasDependentViolation" style="margin: 25px 0px;">
<div style="border-width: 0px 0px 1px 0px; font-size: unset; text-align: left; font-weight: bold; margin-left: 13px; border-style: solid; border-color: var(--ion-color-light-tint);">
<ion-text color="warning">Affected Services</ion-text>
</div>
<ion-item

View File

@@ -1,10 +1,10 @@
import { Component, Input, OnInit } from '@angular/core'
import { Component, Input } from '@angular/core'
import { BehaviorSubject, from, Subject } from 'rxjs'
import { takeUntil, tap } from 'rxjs/operators'
import { Breakages } from 'src/app/services/api/api.types'
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
import { capitalizeFirstLetter, isEmptyObject } from 'src/app/util/misc.util'
import { Loadable, markAsLoadingDuring$ } from '../loadable'
import { markAsLoadingDuring$ } from '../loadable'
import { WizardAction } from '../wizard-types'
@Component({
@@ -12,13 +12,12 @@ import { WizardAction } from '../wizard-types'
templateUrl: './dependents.component.html',
styleUrls: ['../install-wizard.component.scss'],
})
export class DependentsComponent implements OnInit, Loadable {
export class DependentsComponent {
@Input() params: {
title: string,
action: WizardAction, //Are you sure you want to *uninstall*...,
verb: string, // *Uninstalling* will cause problems...
fetchBreakages: () => Promise<Breakages>,
skipConfirmationDialogue?: boolean
fetchBreakages: () => Promise<Breakages>
}
@Input() transitions: {
cancel: () => any
@@ -29,33 +28,28 @@ export class DependentsComponent implements OnInit, Loadable {
dependentBreakages: Breakages
hasDependentViolation: boolean
longMessage: string | null = null
color$ = new BehaviorSubject('medium') // this will display disabled while loading
message: string | null = null
loading$ = new BehaviorSubject(false)
cancel$ = new Subject<void>()
constructor (
public readonly patch: PatchDbService,
) { }
ngOnInit () { }
load () {
this.color$.next('medium')
markAsLoadingDuring$(this.loading$, from(this.params.fetchBreakages())).pipe(
markAsLoadingDuring$(this.loading$, from(this.params.fetchBreakages()))
.pipe(
takeUntil(this.cancel$),
tap(breakages => this.dependentBreakages = breakages),
).subscribe(
)
.subscribe(
{
complete: () => {
this.hasDependentViolation = this.dependentBreakages && !isEmptyObject(this.dependentBreakages)
if (this.hasDependentViolation) {
this.longMessage = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title} will prohibit the following services from functioning properly and will cause them to stop if they are currently running.`
this.color$.next('warning')
} else if (this.params.skipConfirmationDialogue) {
this.transitions.next()
this.message = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title} will prohibit the following services from functioning properly and will cause them to stop if they are currently running.`
} else {
this.longMessage = `No other services installed on your Embassy will be affected by this action.`
this.color$.next('success')
this.message = `No other services installed on your Embassy will be affected by this action.`
}
},
error: (e: Error) => this.transitions.error(new Error(`Fetching dependent service information failed: ${e.message || e}`)),

View File

@@ -9,15 +9,15 @@ export interface Loadable {
cancel$: Subject<void> // will cancel load function
}
export function markAsLoadingDuring$<T> ($trigger$: Subject<boolean>, o: Observable<T>): Observable<T> {
export function markAsLoadingDuring$<T> (trigger$: Subject<boolean>, o: Observable<T>): Observable<T> {
let shouldBeOn = true
const displayIfItsBeenAtLeast = 5 // ms
return fromSync$(() => {
emitAfter$(displayIfItsBeenAtLeast).subscribe(() => { if (shouldBeOn) $trigger$.next(true) })
emitAfter$(displayIfItsBeenAtLeast).subscribe(() => { if (shouldBeOn) trigger$.next(true) })
}).pipe(
concatMap(() => o),
finalize(() => {
$trigger$.next(false)
trigger$.next(false)
shouldBeOn = false
}),
)

View File

@@ -1,13 +1,11 @@
import { Component, Input, OnInit } from '@angular/core'
import { BehaviorSubject, Subject } from 'rxjs'
import { Loadable } from '../loadable'
import { Component, Input } from '@angular/core'
@Component({
selector: 'notes',
templateUrl: './notes.component.html',
styleUrls: ['../install-wizard.component.scss'],
})
export class NotesComponent implements OnInit, Loadable {
export class NotesComponent {
@Input() params: {
notes: { [version: string]: string }
title: string
@@ -15,14 +13,8 @@ export class NotesComponent implements OnInit, Loadable {
headline: string
}
loading$ = new BehaviorSubject(false)
cancel$ = new Subject<void>()
load () { }
constructor () { }
ngOnInit () { }
asIsOrder () {
return 0
}

View File

@@ -41,7 +41,6 @@ export class WizardBaker {
slide: {
selector: 'dependents',
params: {
skipConfirmationDialogue: true,
action,
verb: 'updating',
title,
@@ -143,7 +142,6 @@ export class WizardBaker {
{ slide: {
selector: 'dependents',
params: {
skipConfirmationDialogue: true,
action,
verb: 'downgrading',
title,

View File

@@ -104,9 +104,9 @@
<!-- ** menu ** -->
<ion-item-divider>Menu</ion-item-divider>
<ion-item button detail *ngFor="let button of buttons" (click)="button.action()">
<ion-icon slot="start" [name]="button.icon" color="dark"></ion-icon>
<ion-icon slot="start" [name]="button.icon"></ion-icon>
<ion-label>
<h2><b>{{ button.title }}</b></h2>
<h2>{{ button.title }}</h2>
<p *ngIf="button.description">{{ button.description }}</p>
</ion-label>
</ion-item>

View File

@@ -64,7 +64,6 @@ export class AppShowPage {
async ngOnInit () {
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
// this.setServiceValues(this.patch.data['package-data'])
this.subs = [
// 1

View File

@@ -48,8 +48,10 @@ export class ServerMetricsPage {
async getMetrics (): Promise<void> {
try {
const metrics = await this.embassyApi.getServerMetrics({ })
Object.entries(metrics).forEach(([key, val]) => {
this.metrics[key] = val
Object.entries(metrics).forEach(([groupKey, groupVal]) => {
Object.entries(groupVal).forEach(([key, val]) => {
this.metrics[groupKey][key] = val
})
})
} catch (e) {
this.errToast.present(e)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'
import { pauseFor } from '../../util/misc.util'
import { ApiService } from './embassy-api.service'
import { PatchOp } from 'patch-db-client'
import { InstallProgress, PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model'
import { DependencyErrorType, InstallProgress, PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model'
import { RR, WithRevision } from './api.types'
import { parsePropertiesPermissive } from 'src/app/util/properties.util'
import { Mock } from './api.fixures'
@@ -333,12 +333,14 @@ export class MockApiService extends ApiService {
unpacked: 0,
'unpack-complete': false,
}
const pkg: PackageDataEntry = {
...Mock.Pkgs[params.id],
...Mock.LocalPkgs[params.id],
state: PackageState.Installing,
'install-progress': initialProgress,
installed: undefined,
}
const patch = [
{
op: PatchOp.ADD,
@@ -346,6 +348,7 @@ export class MockApiService extends ApiService {
value: pkg,
},
]
const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
setTimeout(async () => {
this.updateProgress(params.id, initialProgress)
@@ -411,12 +414,16 @@ export class MockApiService extends ApiService {
async startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
await pauseFor(2000)
const path = `/package-data/${params.id}/installed/status/main/status`
const path = `/package-data/${params.id}/installed/status/main`
const patch = [
{
op: PatchOp.REPLACE,
path,
value: PackageMainStatus.Running,
value: {
status: PackageMainStatus.Running,
started: new Date().toISOString(), // UTC date string
health: { },
},
},
]
return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
@@ -424,17 +431,26 @@ export class MockApiService extends ApiService {
async dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes> {
await pauseFor(2000)
return { }
return {
'lnd': {
dependency: 'bitcoind',
error: {
type: DependencyErrorType.NotRunning,
},
},
}
}
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
await pauseFor(2000)
const path = `/package-data/${params.id}/installed/status/main/status`
const path = `/package-data/${params.id}/installed/status/main`
const patch = [
{
op: PatchOp.REPLACE,
path,
value: PackageMainStatus.Stopping,
value: {
status: PackageMainStatus.Stopping,
},
},
]
const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
@@ -442,7 +458,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path,
path: path + '/status',
value: PackageMainStatus.Stopped,
},
]
@@ -540,7 +556,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: `/package-data/${id}`,
value: Mock.Pkgs[id],
value: Mock.LocalPkgs[id],
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })