mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
finsih status refactor
This commit is contained in:
committed by
Aiden McClelland
parent
9a9403e51b
commit
5b3e445b53
@@ -42,7 +42,17 @@
|
||||
<img *ngIf="!connectionFailure" [class]="pkg.value.bulb.class" [src]="pkg.value.bulb.img" />
|
||||
|
||||
<ion-card-header>
|
||||
<status *ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state" [disconnected]="connectionFailure" [rendering]="pkg.value.statusRendering" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
<ion-grid class="status-grid">
|
||||
<ion-row class="ion-align-items-center">
|
||||
<ion-col></ion-col>
|
||||
<ion-col>
|
||||
<status *ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state" [disconnected]="connectionFailure" [rendering]="pkg.value.primaryRendering" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-icon *ngIf="pkg.value.error" name="warning-outline" color="warning"></ion-icon>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<p *ngIf="!!pkg.value.installProgress" class="main-status"><ion-text color="primary">{{ pkg.value.entry.state | titlecase }}...{{ pkg.value.installProgress.totalProgress }}%</ion-text></p>
|
||||
<ion-card-title>{{ pkg.value.entry.manifest.title }}</ion-card-title>
|
||||
</ion-card-header>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.installed-card {
|
||||
margin: 2px;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
background: linear-gradient(37deg, #333333, #131313);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
@@ -83,3 +84,17 @@
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.status-grid {
|
||||
--ion-grid-padding: 0;
|
||||
ion-row {
|
||||
min-height: 22px;
|
||||
}
|
||||
ion-col {
|
||||
--ion-grid-column-padding: 0
|
||||
}
|
||||
ion-icon {
|
||||
font-size: calc(12px + .4vw);
|
||||
padding-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ConnectionFailure, ConnectionService } from 'src/app/services/connectio
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { PrimaryRendering, renderPkgStatus, StatusRendering } from 'src/app/services/pkg-status-rendering.service'
|
||||
import { DependencyStatus, HealthStatus, PrimaryRendering, renderPkgStatus, StatusRendering } from 'src/app/services/pkg-status-rendering.service'
|
||||
import { filter } from 'rxjs/operators'
|
||||
import { isEmptyObject } from 'src/app/util/misc.util'
|
||||
import { PackageLoadingService, ProgressData } from 'src/app/services/package-loading.service'
|
||||
@@ -15,19 +15,11 @@ import { PackageLoadingService, ProgressData } from 'src/app/services/package-lo
|
||||
styleUrls: ['./app-list.page.scss'],
|
||||
})
|
||||
export class AppListPage {
|
||||
PackageState = PackageState
|
||||
|
||||
subs: Subscription[] = []
|
||||
connectionFailure: boolean
|
||||
pkgs: { [id: string]: {
|
||||
entry: PackageDataEntry
|
||||
bulb: {
|
||||
class: string
|
||||
img: string
|
||||
}
|
||||
statusRendering: StatusRendering | null
|
||||
sub: Subscription | null
|
||||
installProgress: ProgressData
|
||||
}} = { }
|
||||
PackageState = PackageState
|
||||
pkgs: { [id: string]: PkgInfo } = { }
|
||||
loading = true
|
||||
|
||||
constructor (
|
||||
@@ -70,17 +62,19 @@ export class AppListPage {
|
||||
class: 'bulb-off',
|
||||
img: 'assets/img/off-bulb.png',
|
||||
},
|
||||
statusRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
||||
sub: null,
|
||||
primaryRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
||||
installProgress: !isEmptyObject(pkgs[id]['install-progress']) ? this.installPackageService.transform(pkgs[id]['install-progress']) : undefined,
|
||||
error: false,
|
||||
sub: null,
|
||||
}
|
||||
// subscribe to pkg
|
||||
this.pkgs[id].sub = this.patch.watch$('package-data', id).subscribe(pkg => {
|
||||
if (!pkg) return
|
||||
let bulbClass = 'bulb-on'
|
||||
let img = ''
|
||||
const statusRendering = PrimaryRendering[renderPkgStatus(pkg).primary]
|
||||
switch (statusRendering.color) {
|
||||
const statuses = renderPkgStatus(pkg)
|
||||
const primaryRendering = PrimaryRendering[statuses.primary]
|
||||
switch (primaryRendering.color) {
|
||||
case 'danger':
|
||||
img = 'assets/img/danger-bulb.png'
|
||||
break
|
||||
@@ -101,7 +95,8 @@ export class AppListPage {
|
||||
class: bulbClass,
|
||||
img,
|
||||
}
|
||||
this.pkgs[id].statusRendering = statusRendering
|
||||
this.pkgs[id].primaryRendering = primaryRendering
|
||||
this.pkgs[id].error = [HealthStatus.NeedsConfig, HealthStatus.Failure].includes(statuses.health) || [DependencyStatus.Issue, DependencyStatus.Critical].includes(statuses.dependency)
|
||||
})
|
||||
})
|
||||
}),
|
||||
@@ -128,3 +123,15 @@ export class AppListPage {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
interface PkgInfo {
|
||||
entry: PackageDataEntry
|
||||
bulb: {
|
||||
class: string
|
||||
img: string
|
||||
}
|
||||
primaryRendering: StatusRendering
|
||||
installProgress: ProgressData
|
||||
error: boolean
|
||||
sub: Subscription | null
|
||||
}
|
||||
|
||||
@@ -65,13 +65,47 @@ export class AppShowPage {
|
||||
|
||||
async ngOnInit () {
|
||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||
this.setValues(this.patch.data['package-data'])
|
||||
// this.setServiceValues(this.patch.data['package-data'])
|
||||
|
||||
this.subs = [
|
||||
// 1
|
||||
this.patch.watch$('package-data')
|
||||
.subscribe(pkgs => {
|
||||
this.setValues(pkgs)
|
||||
this.patch.watch$('package-data', this.pkgId)
|
||||
.subscribe(pkg => {
|
||||
this.pkg = pkg
|
||||
this.installProgress = !isEmptyObject(pkg['install-progress']) ? this.packageLoadingService.transform(pkg['install-progress']) : undefined
|
||||
this.statuses = renderPkgStatus(pkg)
|
||||
|
||||
// health
|
||||
if (this.pkg.installed?.status.main.status === PackageMainStatus.Running) {
|
||||
this.healthChecks = { ...this.pkg.installed.status.main.health }
|
||||
} else {
|
||||
this.healthChecks = { }
|
||||
}
|
||||
|
||||
// dependencies
|
||||
if (!pkg.installed) {
|
||||
this.dependencies = { }
|
||||
} else {
|
||||
const currentDeps = pkg.installed['current-dependencies']
|
||||
Object.keys(currentDeps).forEach(key => {
|
||||
const manifestDep = pkg.manifest.dependencies[key]
|
||||
if (!this.dependencies[key] && manifestDep) {
|
||||
this.dependencies[key] = { } as any
|
||||
this.dependencies[key].sub = this.patch.watch$('package-data', key)
|
||||
.subscribe(localDep => {
|
||||
this.setDepValues(key, manifestDep.version, localDep)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// unsub to deleted
|
||||
Object.keys(this.dependencies).forEach(key => {
|
||||
if (!currentDeps[key]) {
|
||||
this.dependencies[key].sub.unsubscribe()
|
||||
delete this.dependencies[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
}),
|
||||
// 2
|
||||
this.connectionService.watchFailure$()
|
||||
@@ -88,6 +122,9 @@ export class AppShowPage {
|
||||
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
Object.values(this.dependencies).forEach(dep => {
|
||||
dep.sub.unsubscribe()
|
||||
})
|
||||
}
|
||||
|
||||
launchUi (): void {
|
||||
@@ -166,87 +203,63 @@ export class AppShowPage {
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
private setValues (pkgs: { [id: string]: PackageDataEntry }): void {
|
||||
this.pkg = pkgs[this.pkgId]
|
||||
this.installProgress = !isEmptyObject(this.pkg['install-progress']) ? this.packageLoadingService.transform(this.pkg['install-progress']) : undefined
|
||||
this.statuses = renderPkgStatus(this.pkg)
|
||||
private setDepValues (id: string, version: string, localDep: PackageDataEntry | undefined): void {
|
||||
let errorText = ''
|
||||
let spinnerColor = ''
|
||||
let actionText = 'View'
|
||||
let action: () => any = () => this.navCtrl.navigateForward(`/services/${id}`)
|
||||
|
||||
if (!this.pkg.installed) {
|
||||
this.dependencies = { }
|
||||
this.healthChecks = { }
|
||||
} else {
|
||||
// ** dependencies
|
||||
Object.keys(this.pkg.installed['current-dependencies'] || { })
|
||||
.forEach(id => {
|
||||
// we can safely ignore any current dependencies that are not defined in the service manifest
|
||||
const manifestDep = this.pkg.manifest.dependencies[id]
|
||||
if (manifestDep) {
|
||||
let errorText = ''
|
||||
let spinnerColor = ''
|
||||
let actionText = 'View'
|
||||
let action: () => any = () => this.navCtrl.navigateForward(`/services/${id}`)
|
||||
const error = this.pkg.installed.status['dependency-errors'][id] || null
|
||||
|
||||
const error = this.pkg.installed.status['dependency-errors'][id] || null
|
||||
if (error) {
|
||||
// health checks failed
|
||||
if ([DependencyErrorType.InterfaceHealthChecksFailed, DependencyErrorType.HealthChecksFailed].includes(error.type)) {
|
||||
errorText = 'Health Check Failed'
|
||||
// not fully installed (same as !localDep?.installed)
|
||||
} else if (error.type === DependencyErrorType.NotInstalled) {
|
||||
if (localDep) {
|
||||
errorText = localDep.state // 'Installing' | 'Removing'
|
||||
} else {
|
||||
errorText = 'Not Installed'
|
||||
actionText = 'Install'
|
||||
action = () => this.fixDep('install', id)
|
||||
}
|
||||
// incorrect version
|
||||
} else if (error.type === DependencyErrorType.IncorrectVersion) {
|
||||
if (localDep) {
|
||||
errorText = localDep.state // 'Updating' | 'Removing'
|
||||
} else {
|
||||
errorText = 'Incorrect Version'
|
||||
actionText = 'Update'
|
||||
action = () => this.fixDep('update', id)
|
||||
}
|
||||
// not running
|
||||
} else if (error.type === DependencyErrorType.NotRunning) {
|
||||
errorText = 'Not Running'
|
||||
actionText = 'Start'
|
||||
// config unsatisfied
|
||||
} else if (error.type === DependencyErrorType.ConfigUnsatisfied) {
|
||||
errorText = 'Config Not Satisfied'
|
||||
actionText = 'Auto Config'
|
||||
action = () => this.fixDep('configure', id)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
const localDep = pkgs[id]
|
||||
// health checks failed
|
||||
if ([DependencyErrorType.InterfaceHealthChecksFailed, DependencyErrorType.HealthChecksFailed].includes(error.type)) {
|
||||
errorText = 'Health Check Failed'
|
||||
// not fully installed (same as !localDep?.installed)
|
||||
} else if (error.type === DependencyErrorType.NotInstalled) {
|
||||
if (localDep) {
|
||||
errorText = localDep.state // 'Installing' | 'Removing'
|
||||
} else {
|
||||
errorText = 'Not Installed'
|
||||
actionText = 'Install'
|
||||
action = () => this.fixDep('install', id)
|
||||
}
|
||||
// incorrect version
|
||||
} else if (error.type === DependencyErrorType.IncorrectVersion) {
|
||||
if (localDep) {
|
||||
errorText = localDep.state // 'Updating' | 'Removing'
|
||||
} else {
|
||||
errorText = 'Incorrect Version'
|
||||
actionText = 'Update'
|
||||
action = () => this.fixDep('update', id)
|
||||
}
|
||||
// not running
|
||||
} else if (error.type === DependencyErrorType.NotRunning) {
|
||||
errorText = 'Not Running'
|
||||
actionText = 'Start'
|
||||
// config unsatisfied
|
||||
} else if (error.type === DependencyErrorType.ConfigUnsatisfied) {
|
||||
errorText = 'Config Not Satisfied'
|
||||
actionText = 'Auto Config'
|
||||
action = () => this.fixDep('configure', id)
|
||||
}
|
||||
|
||||
if (localDep && localDep.state !== PackageState.Installed) {
|
||||
spinnerColor = localDep.state === PackageState.Removing ? 'danger' : 'primary'
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.dependencies[id]) this.dependencies[id] = { } as any
|
||||
|
||||
const depInfo = this.pkg.installed['dependency-info'][id]
|
||||
|
||||
this.dependencies[id].title = depInfo.manifest.title
|
||||
this.dependencies[id].icon = depInfo.icon
|
||||
this.dependencies[id].version = manifestDep.version
|
||||
this.dependencies[id].errorText = errorText
|
||||
this.dependencies[id].actionText = actionText
|
||||
this.dependencies[id].spinnerColor = spinnerColor
|
||||
this.dependencies[id].action = action
|
||||
}
|
||||
})
|
||||
// ** health
|
||||
if (this.pkg.installed.status.main.status === PackageMainStatus.Running) {
|
||||
this.healthChecks = { ...this.pkg.installed.status.main.health }
|
||||
} else {
|
||||
this.healthChecks = { }
|
||||
if (localDep && localDep.state !== PackageState.Installed) {
|
||||
spinnerColor = localDep.state === PackageState.Removing ? 'danger' : 'primary'
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.dependencies[id]) this.dependencies[id] = { } as any
|
||||
|
||||
const depInfo = this.pkg.installed['dependency-info'][id]
|
||||
|
||||
this.dependencies[id].title = depInfo.manifest.title
|
||||
this.dependencies[id].icon = depInfo.icon
|
||||
this.dependencies[id].version = version
|
||||
this.dependencies[id].errorText = errorText
|
||||
this.dependencies[id].actionText = actionText
|
||||
this.dependencies[id].spinnerColor = spinnerColor
|
||||
this.dependencies[id].action = action
|
||||
}
|
||||
|
||||
private async installDep (depId: string): Promise<void> {
|
||||
@@ -398,6 +411,7 @@ interface DependencyInfo {
|
||||
spinnerColor: string
|
||||
actionText: string
|
||||
action: () => any
|
||||
sub: Subscription
|
||||
}
|
||||
|
||||
interface Button {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { isEmptyObject } from '../util/misc.util'
|
||||
import { PackageDataEntry, InstalledPackageDataEntry, PackageMainStatus, PackageState, Status } from './patch-db/data-model'
|
||||
import { PackageDataEntry, PackageMainStatus, PackageState, Status } from './patch-db/data-model'
|
||||
|
||||
export function renderPkgStatus (pkg: PackageDataEntry): {
|
||||
primary: PrimaryStatus,
|
||||
dependency: DependencyStatus | null,
|
||||
health: HealthStatus | null
|
||||
} {
|
||||
console.log('PKGPKG', pkg)
|
||||
let primary: PrimaryStatus
|
||||
let dependency: DependencyStatus | null = null
|
||||
let health: HealthStatus | null = null
|
||||
@@ -92,10 +91,10 @@ export enum HealthStatus {
|
||||
export const PrimaryRendering: { [key: string]: StatusRendering } = {
|
||||
[PrimaryStatus.Installing]: { display: 'Installing', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Updating]: { display: 'Updating', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Removing]: { display: 'Removing', color: 'warning', showDots: true },
|
||||
[PrimaryStatus.Removing]: { display: 'Removing', color: 'danger', showDots: true },
|
||||
[PrimaryStatus.Stopping]: { display: 'Stopping', color: 'dark-shade', showDots: true },
|
||||
[PrimaryStatus.Stopped]: { display: 'Stopped', color: 'dark-shade', showDots: false },
|
||||
[PrimaryStatus.BackingUp]: { display: 'Backing Up', color: 'warning', showDots: true },
|
||||
[PrimaryStatus.BackingUp]: { display: 'Backing Up', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Restoring]: { display: 'Restoring', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Running]: { display: 'Running', color: 'success', showDots: false },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user