mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
fix wizard and server metrics
This commit is contained in:
committed by
Aiden McClelland
parent
f46d935bb0
commit
b978d5062f
@@ -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 () { }
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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],
|
||||
})
|
||||
|
||||
@@ -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}...`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`)),
|
||||
|
||||
@@ -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
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 } })
|
||||
|
||||
Reference in New Issue
Block a user