mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +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" />
|
<img *ngIf="!connectionFailure" [class]="pkg.value.bulb.class" [src]="pkg.value.bulb.img" />
|
||||||
|
|
||||||
<ion-card-header>
|
<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>
|
<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-title>{{ pkg.value.entry.manifest.title }}</ion-card-title>
|
||||||
</ion-card-header>
|
</ion-card-header>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.installed-card {
|
.installed-card {
|
||||||
margin: 2px;
|
margin: 4px;
|
||||||
|
padding: 4px;
|
||||||
background: linear-gradient(37deg, #333333, #131313);
|
background: linear-gradient(37deg, #333333, #131313);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -83,3 +84,17 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 0;
|
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 { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||||
import { Subscription } from 'rxjs'
|
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 { filter } from 'rxjs/operators'
|
||||||
import { isEmptyObject } from 'src/app/util/misc.util'
|
import { isEmptyObject } from 'src/app/util/misc.util'
|
||||||
import { PackageLoadingService, ProgressData } from 'src/app/services/package-loading.service'
|
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'],
|
styleUrls: ['./app-list.page.scss'],
|
||||||
})
|
})
|
||||||
export class AppListPage {
|
export class AppListPage {
|
||||||
|
PackageState = PackageState
|
||||||
|
|
||||||
subs: Subscription[] = []
|
subs: Subscription[] = []
|
||||||
connectionFailure: boolean
|
connectionFailure: boolean
|
||||||
pkgs: { [id: string]: {
|
pkgs: { [id: string]: PkgInfo } = { }
|
||||||
entry: PackageDataEntry
|
|
||||||
bulb: {
|
|
||||||
class: string
|
|
||||||
img: string
|
|
||||||
}
|
|
||||||
statusRendering: StatusRendering | null
|
|
||||||
sub: Subscription | null
|
|
||||||
installProgress: ProgressData
|
|
||||||
}} = { }
|
|
||||||
PackageState = PackageState
|
|
||||||
loading = true
|
loading = true
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
@@ -70,17 +62,19 @@ export class AppListPage {
|
|||||||
class: 'bulb-off',
|
class: 'bulb-off',
|
||||||
img: 'assets/img/off-bulb.png',
|
img: 'assets/img/off-bulb.png',
|
||||||
},
|
},
|
||||||
statusRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
primaryRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
||||||
sub: null,
|
|
||||||
installProgress: !isEmptyObject(pkgs[id]['install-progress']) ? this.installPackageService.transform(pkgs[id]['install-progress']) : undefined,
|
installProgress: !isEmptyObject(pkgs[id]['install-progress']) ? this.installPackageService.transform(pkgs[id]['install-progress']) : undefined,
|
||||||
|
error: false,
|
||||||
|
sub: null,
|
||||||
}
|
}
|
||||||
// subscribe to pkg
|
// subscribe to pkg
|
||||||
this.pkgs[id].sub = this.patch.watch$('package-data', id).subscribe(pkg => {
|
this.pkgs[id].sub = this.patch.watch$('package-data', id).subscribe(pkg => {
|
||||||
if (!pkg) return
|
if (!pkg) return
|
||||||
let bulbClass = 'bulb-on'
|
let bulbClass = 'bulb-on'
|
||||||
let img = ''
|
let img = ''
|
||||||
const statusRendering = PrimaryRendering[renderPkgStatus(pkg).primary]
|
const statuses = renderPkgStatus(pkg)
|
||||||
switch (statusRendering.color) {
|
const primaryRendering = PrimaryRendering[statuses.primary]
|
||||||
|
switch (primaryRendering.color) {
|
||||||
case 'danger':
|
case 'danger':
|
||||||
img = 'assets/img/danger-bulb.png'
|
img = 'assets/img/danger-bulb.png'
|
||||||
break
|
break
|
||||||
@@ -101,7 +95,8 @@ export class AppListPage {
|
|||||||
class: bulbClass,
|
class: bulbClass,
|
||||||
img,
|
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
|
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 () {
|
async ngOnInit () {
|
||||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||||
this.setValues(this.patch.data['package-data'])
|
// this.setServiceValues(this.patch.data['package-data'])
|
||||||
|
|
||||||
this.subs = [
|
this.subs = [
|
||||||
// 1
|
// 1
|
||||||
this.patch.watch$('package-data')
|
this.patch.watch$('package-data', this.pkgId)
|
||||||
.subscribe(pkgs => {
|
.subscribe(pkg => {
|
||||||
this.setValues(pkgs)
|
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
|
// 2
|
||||||
this.connectionService.watchFailure$()
|
this.connectionService.watchFailure$()
|
||||||
@@ -88,6 +122,9 @@ export class AppShowPage {
|
|||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
this.subs.forEach(sub => sub.unsubscribe())
|
this.subs.forEach(sub => sub.unsubscribe())
|
||||||
|
Object.values(this.dependencies).forEach(dep => {
|
||||||
|
dep.sub.unsubscribe()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
launchUi (): void {
|
launchUi (): void {
|
||||||
@@ -166,87 +203,63 @@ export class AppShowPage {
|
|||||||
await modal.present()
|
await modal.present()
|
||||||
}
|
}
|
||||||
|
|
||||||
private setValues (pkgs: { [id: string]: PackageDataEntry }): void {
|
private setDepValues (id: string, version: string, localDep: PackageDataEntry | undefined): void {
|
||||||
this.pkg = pkgs[this.pkgId]
|
let errorText = ''
|
||||||
this.installProgress = !isEmptyObject(this.pkg['install-progress']) ? this.packageLoadingService.transform(this.pkg['install-progress']) : undefined
|
let spinnerColor = ''
|
||||||
this.statuses = renderPkgStatus(this.pkg)
|
let actionText = 'View'
|
||||||
|
let action: () => any = () => this.navCtrl.navigateForward(`/services/${id}`)
|
||||||
|
|
||||||
if (!this.pkg.installed) {
|
const error = this.pkg.installed.status['dependency-errors'][id] || null
|
||||||
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
|
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) {
|
if (localDep && localDep.state !== PackageState.Installed) {
|
||||||
const localDep = pkgs[id]
|
spinnerColor = localDep.state === PackageState.Removing ? 'danger' : 'primary'
|
||||||
// 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 (!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> {
|
private async installDep (depId: string): Promise<void> {
|
||||||
@@ -398,6 +411,7 @@ interface DependencyInfo {
|
|||||||
spinnerColor: string
|
spinnerColor: string
|
||||||
actionText: string
|
actionText: string
|
||||||
action: () => any
|
action: () => any
|
||||||
|
sub: Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Button {
|
interface Button {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { isEmptyObject } from '../util/misc.util'
|
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): {
|
export function renderPkgStatus (pkg: PackageDataEntry): {
|
||||||
primary: PrimaryStatus,
|
primary: PrimaryStatus,
|
||||||
dependency: DependencyStatus | null,
|
dependency: DependencyStatus | null,
|
||||||
health: HealthStatus | null
|
health: HealthStatus | null
|
||||||
} {
|
} {
|
||||||
console.log('PKGPKG', pkg)
|
|
||||||
let primary: PrimaryStatus
|
let primary: PrimaryStatus
|
||||||
let dependency: DependencyStatus | null = null
|
let dependency: DependencyStatus | null = null
|
||||||
let health: HealthStatus | null = null
|
let health: HealthStatus | null = null
|
||||||
@@ -92,10 +91,10 @@ export enum HealthStatus {
|
|||||||
export const PrimaryRendering: { [key: string]: StatusRendering } = {
|
export const PrimaryRendering: { [key: string]: StatusRendering } = {
|
||||||
[PrimaryStatus.Installing]: { display: 'Installing', color: 'primary', showDots: true },
|
[PrimaryStatus.Installing]: { display: 'Installing', color: 'primary', showDots: true },
|
||||||
[PrimaryStatus.Updating]: { display: 'Updating', 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.Stopping]: { display: 'Stopping', color: 'dark-shade', showDots: true },
|
||||||
[PrimaryStatus.Stopped]: { display: 'Stopped', color: 'dark-shade', showDots: false },
|
[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.Restoring]: { display: 'Restoring', color: 'primary', showDots: true },
|
||||||
[PrimaryStatus.Running]: { display: 'Running', color: 'success', showDots: false },
|
[PrimaryStatus.Running]: { display: 'Running', color: 'success', showDots: false },
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user