mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
transitive dependency error and metrics scrolling
This commit is contained in:
committed by
Aiden McClelland
parent
97997bff97
commit
ffa9cac362
@@ -62,15 +62,15 @@
|
|||||||
<ng-container *ngIf="!connectionFailure">
|
<ng-container *ngIf="!connectionFailure">
|
||||||
<ion-item *ngFor="let health of healthChecks | keyvalue : asIsOrder">
|
<ion-item *ngFor="let health of healthChecks | keyvalue : asIsOrder">
|
||||||
<ng-container *ngIf="$any(health.value).result as result">
|
<ng-container *ngIf="$any(health.value).result as result">
|
||||||
<ion-spinner class="icon-spinner" color="primary" slot="start" *ngIf="['starting', 'loading'] | includes : result"></ion-spinner>
|
<ion-spinner class="icon-spinner" color="primary" slot="start" *ngIf="[HealthResult.Starting, HealthResult.Loading] | includes : result"></ion-spinner>
|
||||||
<ion-icon slot="start" *ngIf="result === 'success'" name="checkmark" color="success"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === HealthResult.Success" name="checkmark" color="success"></ion-icon>
|
||||||
<ion-icon slot="start" *ngIf="result === 'failure'" name="warning" color="warning"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === HealthResult.Failure" name="warning" color="warning"></ion-icon>
|
||||||
<ion-icon slot="start" *ngIf="result === 'disabled'" name="remove" color="dark"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === HealthResult.Disabled" name="remove" color="dark"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2 style="font-weight: bold;">{{ health.key }}</h2>
|
<h2 style="font-weight: bold;">{{ health.key }}</h2>
|
||||||
<h2>Result: {{ result | titlecase }}</h2>
|
<h2>Result: {{ result | titlecase }}</h2>
|
||||||
<p *ngIf="result === 'loading'"><ion-text color="primary">{{ $any(health.value).message }}</ion-text></p>
|
<p *ngIf="result === HealthResult.Loading"><ion-text color="primary">{{ $any(health.value).message }}</ion-text></p>
|
||||||
<p *ngIf="result === 'failure'"><ion-text color="warning">{{ $any(health.value).error }}</ion-text></p>
|
<p *ngIf="result === HealthResult.Failure"><ion-text color="warning">{{ $any(health.value).error }}</ion-text></p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { wizardModal } from 'src/app/components/install-wizard/install-wizard.co
|
|||||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||||
import { ConfigService } from 'src/app/services/config.service'
|
import { ConfigService } from 'src/app/services/config.service'
|
||||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { DependencyErrorConfigUnsatisfied, DependencyErrorType, HealthCheckResult, PackageDataEntry, PackageMainStatus, PackageState } from 'src/app/services/patch-db/data-model'
|
import { DependencyErrorConfigUnsatisfied, DependencyErrorType, HealthCheckResult, HealthResult, PackageDataEntry, PackageMainStatus, PackageState } from 'src/app/services/patch-db/data-model'
|
||||||
import { DependencyStatus, HealthStatus, PrimaryRendering, PrimaryStatus, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
import { DependencyStatus, HealthStatus, PrimaryRendering, PrimaryStatus, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||||
import { ConnectionFailure, ConnectionService } from 'src/app/services/connection.service'
|
import { ConnectionFailure, ConnectionService } from 'src/app/services/connection.service'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
@@ -24,6 +24,7 @@ export class AppShowPage {
|
|||||||
PackageState = PackageState
|
PackageState = PackageState
|
||||||
DependencyErrorType = DependencyErrorType
|
DependencyErrorType = DependencyErrorType
|
||||||
Math = Math
|
Math = Math
|
||||||
|
HealthResult = HealthResult
|
||||||
PS = PrimaryStatus
|
PS = PrimaryStatus
|
||||||
DS = DependencyStatus
|
DS = DependencyStatus
|
||||||
PR = PrimaryRendering
|
PR = PrimaryRendering
|
||||||
@@ -210,13 +211,13 @@ export class AppShowPage {
|
|||||||
if (error) {
|
if (error) {
|
||||||
// health checks failed
|
// health checks failed
|
||||||
if ([DependencyErrorType.InterfaceHealthChecksFailed, DependencyErrorType.HealthChecksFailed].includes(error.type)) {
|
if ([DependencyErrorType.InterfaceHealthChecksFailed, DependencyErrorType.HealthChecksFailed].includes(error.type)) {
|
||||||
errorText = 'Health Check Failed'
|
errorText = 'Health check failed'
|
||||||
// not fully installed (same as !localDep?.installed)
|
// not fully installed (same as !localDep?.installed)
|
||||||
} else if (error.type === DependencyErrorType.NotInstalled) {
|
} else if (error.type === DependencyErrorType.NotInstalled) {
|
||||||
if (localDep) {
|
if (localDep) {
|
||||||
errorText = localDep.state // 'Installing' | 'Removing'
|
errorText = localDep.state // 'Installing' | 'Removing'
|
||||||
} else {
|
} else {
|
||||||
errorText = 'Not Installed'
|
errorText = 'Not installed'
|
||||||
actionText = 'Install'
|
actionText = 'Install'
|
||||||
action = () => this.fixDep('install', id)
|
action = () => this.fixDep('install', id)
|
||||||
}
|
}
|
||||||
@@ -225,19 +226,21 @@ export class AppShowPage {
|
|||||||
if (localDep) {
|
if (localDep) {
|
||||||
errorText = localDep.state // 'Updating' | 'Removing'
|
errorText = localDep.state // 'Updating' | 'Removing'
|
||||||
} else {
|
} else {
|
||||||
errorText = 'Incorrect Version'
|
errorText = 'Incorrect version'
|
||||||
actionText = 'Update'
|
actionText = 'Update'
|
||||||
action = () => this.fixDep('update', id)
|
action = () => this.fixDep('update', id)
|
||||||
}
|
}
|
||||||
// not running
|
// not running
|
||||||
} else if (error.type === DependencyErrorType.NotRunning) {
|
} else if (error.type === DependencyErrorType.NotRunning) {
|
||||||
errorText = 'Not Running'
|
errorText = 'Not running'
|
||||||
actionText = 'Start'
|
actionText = 'Start'
|
||||||
// config unsatisfied
|
// config unsatisfied
|
||||||
} else if (error.type === DependencyErrorType.ConfigUnsatisfied) {
|
} else if (error.type === DependencyErrorType.ConfigUnsatisfied) {
|
||||||
errorText = 'Config Not Satisfied'
|
errorText = 'Config not satisfied'
|
||||||
actionText = 'Auto Config'
|
actionText = 'Auto Config'
|
||||||
action = () => this.fixDep('configure', id)
|
action = () => this.fixDep('configure', id)
|
||||||
|
} else if (error.type === DependencyErrorType.Transitive) {
|
||||||
|
errorText = 'Dependency has a dependency issue'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localDep && localDep.state !== PackageState.Installed) {
|
if (localDep && localDep.state !== PackageState.Installed) {
|
||||||
|
|||||||
@@ -8,18 +8,20 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<skeleton-list *ngIf="loading; else loaded" groups="2"></skeleton-list>
|
<skeleton-list *ngIf="loading" groups="2"></skeleton-list>
|
||||||
|
|
||||||
<ng-template #loaded>
|
<div id="metricSection">
|
||||||
<ion-item-group *ngFor="let metricGroup of metrics | keyvalue : asIsOrder">
|
<ng-container *ngIf="!loading">
|
||||||
<ion-item-divider>{{ metricGroup.key }}</ion-item-divider>
|
<ion-item-group *ngFor="let metricGroup of metrics | keyvalue : asIsOrder">
|
||||||
<ion-item *ngFor="let metric of metricGroup.value | keyvalue : asIsOrder">
|
<ion-item-divider>{{ metricGroup.key }}</ion-item-divider>
|
||||||
<ion-label>{{ metric.key }}</ion-label>
|
<ion-item *ngFor="let metric of metricGroup.value | keyvalue : asIsOrder">
|
||||||
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
|
<ion-label>{{ metric.key }}</ion-label>
|
||||||
<ion-text style="color: white;">{{ metric.value.value }} {{ metric.value.unit }}</ion-text>
|
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
|
||||||
</ion-note>
|
<ion-text style="color: white;">{{ metric.value.value }} {{ metric.value.unit }}</ion-text>
|
||||||
</ion-item>
|
</ion-note>
|
||||||
</ion-item-group>
|
</ion-item>
|
||||||
</ng-template>
|
</ion-item-group>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
@@ -14,26 +14,34 @@ export class ServerMetricsPage {
|
|||||||
loading = true
|
loading = true
|
||||||
going = false
|
going = false
|
||||||
metrics: Metrics = { }
|
metrics: Metrics = { }
|
||||||
@ViewChild(IonContent) content: IonContent
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly errToast: ErrorToastService,
|
private readonly errToast: ErrorToastService,
|
||||||
private readonly embassyApi: ApiService,
|
private readonly embassyApi: ApiService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit () {
|
async ngOnInit () {
|
||||||
|
await this.getMetrics()
|
||||||
|
let headersCount = 0
|
||||||
|
let rowsCount = 0
|
||||||
|
Object.values(this.metrics).forEach(groupVal => {
|
||||||
|
headersCount++
|
||||||
|
Object.keys(groupVal).forEach(_ => {
|
||||||
|
rowsCount++
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const height = headersCount * 54 + rowsCount * 50 + 24 // extra 24 for room at the bottom
|
||||||
|
const elem = document.getElementById('metricSection')
|
||||||
|
elem.style.height = `${height}px`
|
||||||
this.startDaemon()
|
this.startDaemon()
|
||||||
}
|
this.loading = false
|
||||||
|
|
||||||
ngAfterViewInit () {
|
|
||||||
this.content.scrollToPoint(undefined, 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
this.stopDaemon()
|
this.stopDaemon()
|
||||||
}
|
}
|
||||||
|
|
||||||
async startDaemon (): Promise<void> {
|
private async startDaemon (): Promise<void> {
|
||||||
this.going = true
|
this.going = true
|
||||||
while (this.going) {
|
while (this.going) {
|
||||||
await this.getMetrics()
|
await this.getMetrics()
|
||||||
@@ -41,11 +49,11 @@ export class ServerMetricsPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stopDaemon () {
|
private stopDaemon () {
|
||||||
this.going = false
|
this.going = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMetrics (): Promise<void> {
|
private async getMetrics (): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const metrics = await this.embassyApi.getServerMetrics({ })
|
const metrics = await this.embassyApi.getServerMetrics({ })
|
||||||
Object.entries(metrics).forEach(([groupKey, groupVal]) => {
|
Object.entries(metrics).forEach(([groupKey, groupVal]) => {
|
||||||
@@ -59,8 +67,6 @@ export class ServerMetricsPage {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errToast.present(e)
|
this.errToast.present(e)
|
||||||
this.stopDaemon()
|
this.stopDaemon()
|
||||||
} finally {
|
|
||||||
this.loading = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,7 +261,11 @@ export enum PackageMainStatus {
|
|||||||
Restoring = 'restoring',
|
Restoring = 'restoring',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HealthCheckResult = HealthCheckResultStarting | HealthCheckResultLoading | HealthCheckResultDisabled | HealthCheckResultSuccess | HealthCheckResultFailure
|
export type HealthCheckResult = HealthCheckResultStarting |
|
||||||
|
HealthCheckResultLoading |
|
||||||
|
HealthCheckResultDisabled |
|
||||||
|
HealthCheckResultSuccess |
|
||||||
|
HealthCheckResultFailure
|
||||||
|
|
||||||
export enum HealthResult {
|
export enum HealthResult {
|
||||||
Starting = 'starting',
|
Starting = 'starting',
|
||||||
@@ -293,7 +297,13 @@ export interface HealthCheckResultFailure {
|
|||||||
error: string
|
error: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DependencyError = DependencyErrorNotInstalled | DependencyErrorNotRunning | DependencyErrorIncorrectVersion | DependencyErrorConfigUnsatisfied | DependencyErrorHealthChecksFailed | DependencyErrorInterfaceHealthChecksFailed
|
export type DependencyError = DependencyErrorNotInstalled |
|
||||||
|
DependencyErrorNotRunning |
|
||||||
|
DependencyErrorIncorrectVersion |
|
||||||
|
DependencyErrorConfigUnsatisfied |
|
||||||
|
DependencyErrorHealthChecksFailed |
|
||||||
|
DependencyErrorInterfaceHealthChecksFailed |
|
||||||
|
DependencyErrorTransitive
|
||||||
|
|
||||||
export enum DependencyErrorType {
|
export enum DependencyErrorType {
|
||||||
NotInstalled = 'not-installed',
|
NotInstalled = 'not-installed',
|
||||||
@@ -302,6 +312,7 @@ export enum DependencyErrorType {
|
|||||||
ConfigUnsatisfied = 'config-unsatisfied',
|
ConfigUnsatisfied = 'config-unsatisfied',
|
||||||
HealthChecksFailed = 'health-checks-failed',
|
HealthChecksFailed = 'health-checks-failed',
|
||||||
InterfaceHealthChecksFailed = 'interface-health-checks-failed',
|
InterfaceHealthChecksFailed = 'interface-health-checks-failed',
|
||||||
|
Transitive = 'transitive',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DependencyErrorNotInstalled {
|
export interface DependencyErrorNotInstalled {
|
||||||
@@ -333,6 +344,10 @@ export interface DependencyErrorInterfaceHealthChecksFailed {
|
|||||||
failures: { [id: string]: HealthCheckResult }
|
failures: { [id: string]: HealthCheckResult }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DependencyErrorTransitive {
|
||||||
|
type: DependencyErrorType.Transitive
|
||||||
|
}
|
||||||
|
|
||||||
export interface DependencyInfo {
|
export interface DependencyInfo {
|
||||||
[id: string]: DependencyEntry
|
[id: string]: DependencyEntry
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user