mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
start
This commit is contained in:
committed by
Aiden McClelland
parent
01c6b91c52
commit
c4fa205c3d
@@ -84,8 +84,6 @@ export class AppComponent {
|
||||
this.http.authReqEnabled = true
|
||||
this.showMenu = true
|
||||
this.patch.start()
|
||||
// watch patch DB to display name and unread count
|
||||
this.watchPatch()
|
||||
this.connectionService.start()
|
||||
// watch connection to display connectivity issues
|
||||
this.watchConnection(auth)
|
||||
@@ -111,13 +109,6 @@ export class AppComponent {
|
||||
})
|
||||
}
|
||||
|
||||
watchPatch (): void {
|
||||
this.patch.watch$('server-info', 'unread-notification-count')
|
||||
.subscribe(unread => {
|
||||
this.unreadCount = unread
|
||||
})
|
||||
}
|
||||
|
||||
private watchConnection (auth: AuthState): void {
|
||||
this.connectionService.watchFailure$()
|
||||
.pipe(
|
||||
@@ -194,6 +185,7 @@ export class AppComponent {
|
||||
finalize(() => console.log('FINALIZING!!!')),
|
||||
)
|
||||
.subscribe(count => {
|
||||
this.unreadCount = count
|
||||
if (previous !== undefined && count > previous) this.presentToastNotifications()
|
||||
previous = count
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import { PackageDataEntry, PackageMainStatus, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||
|
||||
@Component({
|
||||
@@ -8,17 +10,35 @@ import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||
styleUrls: ['./status.component.scss'],
|
||||
})
|
||||
export class StatusComponent {
|
||||
@Input() pkg: PackageDataEntry
|
||||
@Input() connected: boolean
|
||||
@Input() pkgId: string
|
||||
@Input() size?: 'small' | 'medium' | 'large' = 'large'
|
||||
@Input() style?: string = 'regular'
|
||||
@Input() weight?: string = 'normal'
|
||||
display = ''
|
||||
color = ''
|
||||
showDots = false
|
||||
subs = []
|
||||
pkg: PackageDataEntry
|
||||
|
||||
ngOnChanges () {
|
||||
const { display, color, showDots } = renderPkgStatus(this.pkg)
|
||||
constructor (
|
||||
private readonly patch: PatchDbModel,
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
this.subs = [
|
||||
this.patch.watch$('package-data', this.pkgId, 'installed', 'status', 'main', 'status').subscribe(_ => {
|
||||
this.pkg = this.patch.data['package-data'][this.pkgId]
|
||||
this.render(this.pkg)
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
}
|
||||
|
||||
private render (pkg: PackageDataEntry) {
|
||||
const { display, color, showDots } = renderPkgStatus(pkg.state, pkg.installed.status)
|
||||
this.display = display
|
||||
this.color = color
|
||||
this.showDots = showDots
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
|
||||
<img style="position: absolute" class="main-img" [src]="pkg.value['static-files'].icon" alt="icon" />
|
||||
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
||||
<img class="bulb-on" *ngIf="pkg.value | displayBulb: 'green' : connected" src="assets/img/running-bulb.png"/>
|
||||
<img class="bulb-on" *ngIf="pkg.value | displayBulb: 'red' : connected" src="assets/img/issue-bulb.png"/>
|
||||
<img class="bulb-on" *ngIf="pkg.value | displayBulb: 'yellow' : connected" src="assets/img/warning-bulb.png"/>
|
||||
<img class="bulb-off" *ngIf="pkg.value | displayBulb: 'off' : connected" src="assets/img/off-bulb.png"/>
|
||||
<img class="bulb-on" *ngIf="pkg.key | displayBulb : 'green' : connected" src="assets/img/running-bulb.png"/>
|
||||
<img class="bulb-on" *ngIf="pkg.key | displayBulb : 'red' : connected" src="assets/img/issue-bulb.png"/>
|
||||
<img class="bulb-on" *ngIf="pkg.key | displayBulb : 'yellow' : connected" src="assets/img/warning-bulb.png"/>
|
||||
<img class="bulb-off" *ngIf="pkg.key | displayBulb : 'off' : connected" src="assets/img/off-bulb.png"/>
|
||||
|
||||
<ion-card-header>
|
||||
<status *ngIf="connected" [pkg]="pkg.value" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
<status *ngIf="connected" [pkgId]="pkg.key" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
<ion-card-title>{{ (pkg.value | manifest).title }}</ion-card-title>
|
||||
</ion-card-header>
|
||||
</ion-card>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { IonContent } from '@ionic/angular'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||
|
||||
@@ -14,7 +13,6 @@ export class AppMetricsPage {
|
||||
pkg: PackageDataEntry
|
||||
|
||||
@ViewChild(IonContent) content: IonContent
|
||||
subs: Subscription[] = []
|
||||
|
||||
constructor (
|
||||
private readonly route: ActivatedRoute,
|
||||
@@ -23,23 +21,13 @@ export class AppMetricsPage {
|
||||
|
||||
ngOnInit () {
|
||||
const pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||
|
||||
this.subs = [
|
||||
this.patch.watch$('package-data', pkgId)
|
||||
.subscribe(pkg => {
|
||||
this.pkg = pkg
|
||||
}),
|
||||
]
|
||||
this.pkg = this.patch.data['package-data'][pkgId]
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
}
|
||||
|
||||
asIsOrder (a: any, b: any) {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
|
||||
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||
</ion-item>
|
||||
@@ -30,19 +29,19 @@
|
||||
<h5>{{ manifest.version | displayEmver }}</h5>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
|
||||
<div class="status-readout">
|
||||
<status *ngIf="connected" size="large" weight="500" [pkg]="pkg"></status>
|
||||
<ion-button *ngIf="(pkg | status) === FeStatus.NeedsConfig" expand="block" [routerLink]="['config']">
|
||||
<status *ngIf="connected" size="large" weight="500" [pkgId]="pkgId"></status>
|
||||
<ion-button *ngIf="(pkgId | status) === FeStatus.NeedsConfig" expand="block" [routerLink]="['config']">
|
||||
Configure
|
||||
</ion-button>
|
||||
<ion-button *ngIf="[FeStatus.Running, FeStatus.StartingUp, FeStatus.NeedsAttention] | includes : (pkg | status)" expand="block" color="danger" (click)="stop()">
|
||||
<ion-button *ngIf="[FeStatus.Running, FeStatus.StartingUp, FeStatus.NeedsAttention] | includes : (pkgId | status)" expand="block" color="danger" (click)="stop()">
|
||||
Stop
|
||||
</ion-button>
|
||||
<ion-button *ngIf="(pkg | status) === FeStatus.DependencyIssue" expand="block" (click)="scrollToRequirements()">
|
||||
<ion-button *ngIf="(pkgId | status) === FeStatus.DependencyIssue" expand="block" (click)="scrollToRequirements()">
|
||||
Fix
|
||||
</ion-button>
|
||||
<ion-button *ngIf="(pkg | status) === FeStatus.Stopped" expand="block" color="success" (click)="tryStart()">
|
||||
<ion-button *ngIf="(pkgId | status) === FeStatus.Stopped" expand="block" color="success" (click)="tryStart()">
|
||||
Start
|
||||
</ion-button>
|
||||
</div>
|
||||
@@ -68,20 +67,20 @@
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<ion-item-group class="ion-padding-bottom">
|
||||
<ion-item-group class="ion-padding-bottom">
|
||||
<!-- dependencies -->
|
||||
<ng-container *ngIf="!(pkg.installed['current-dependencies'] | empty)">
|
||||
<ion-item-divider id="dependencies">Dependencies</ion-item-divider>
|
||||
<!-- A current-dependency is a subset of the manifest.dependencies that is currently required as determined by the service config. -->
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let dep of pkg.installed['current-dependencies'] | keyvalue" sizeSm="12" sizeMd="6">
|
||||
<ion-item *ngrxLet="patch.watch$('package-data', dep.key) as localDep">
|
||||
<ion-col *ngFor="let dep of pkg.installed['current-dependencies'] | keyvalue" sizeXs="12" sizeMd="6">
|
||||
<ion-item>
|
||||
<ion-thumbnail slot="start">
|
||||
<img [src]="localDep ? localDep['static-files'].icon : pkg.installed.status['dependency-errors'][dep.key]?.icon" />
|
||||
<img [src]="patch.data['package-data'][dep.key] ? patch.data['package-data'][dep.key]['static-files'].icon : pkg.installed.status['dependency-errors'][dep.key]?.icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 style="font-family: 'Montserrat'">{{ localDep ? (localDep | manifest).title : pkg.installed.status['dependency-errors'][dep.key]?.title }}</h2>
|
||||
<h2 style="font-family: 'Montserrat'">{{ patch.data['package-data'][dep.key] ? (patch.data['package-data'][dep.key] | manifest).title : pkg.installed.status['dependency-errors'][dep.key]?.title }}</h2>
|
||||
<p>{{ manifest.dependencies[dep.key].version | displayEmver }}</p>
|
||||
<p><ion-text [color]="pkg.installed.status['dependency-errors'][dep.key] ? 'warning' : 'success'">{{ pkg.installed.status['dependency-errors'][dep.key] ? pkg.installed.status['dependency-errors'][dep.key].type : 'satisfied' }}</ion-text></p>
|
||||
</ion-label>
|
||||
@@ -91,11 +90,11 @@
|
||||
</ion-button>
|
||||
|
||||
<ng-container *ngIf="pkg.installed.status['dependency-errors'][dep.key]">
|
||||
<ion-button *ngIf="!localDep" slot="end" size="small" (click)="fixDep('install', dep.key)">
|
||||
<ion-button *ngIf="!patch.data['package-data'][dep.key]" slot="end" size="small" (click)="fixDep('install', dep.key)">
|
||||
Install
|
||||
</ion-button>
|
||||
|
||||
<ng-container *ngIf="localDep && localDep.state === PackageState.Installed">
|
||||
<ng-container *ngIf="patch.data['package-data'][dep.key] && patch.data['package-data'][dep.key].state === PackageState.Installed">
|
||||
<ion-button *ngIf="pkg.installed.status['dependency-errors'][dep.key].type === DependencyErrorType.NotRunning" slot="end" size="small" [routerLink]="['/services', dep.key]">
|
||||
Start
|
||||
</ion-button>
|
||||
@@ -107,8 +106,8 @@
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="localDep && localDep.state !== PackageState.Installed" slot="end" class="spinner">
|
||||
<ion-spinner [color]="localDep.state === PackageState.Removing ? 'danger' : 'primary'" style="height: 3vh; width: 3vh" name="dots"></ion-spinner>
|
||||
<div *ngIf="patch.data['package-data'][dep.key] && patch.data['package-data'][dep.key].state !== PackageState.Installed" slot="end" class="spinner">
|
||||
<ion-spinner [color]="patch.data['package-data'][dep.key].state === PackageState.Removing ? 'danger' : 'primary'" style="height: 3vh; width: 3vh" name="dots"></ion-spinner>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ion-item>
|
||||
|
||||
@@ -48,11 +48,10 @@ export class AppShowPage {
|
||||
|
||||
async ngOnInit () {
|
||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||
this.pkg = this.patch.data['package-data'][this.pkgId]
|
||||
// @TODO re-fetch manifest if package state changes.
|
||||
this.manifest = getManifest(this.pkg)
|
||||
this.subs = [
|
||||
this.patch.watch$('package-data', this.pkgId).subscribe(pkg => {
|
||||
this.pkg = pkg
|
||||
this.manifest = getManifest(this.pkg)
|
||||
}),
|
||||
this.patch.connected$().subscribe(c => this.connected = c),
|
||||
]
|
||||
this.setButtons()
|
||||
@@ -62,7 +61,7 @@ export class AppShowPage {
|
||||
this.content.scrollToPoint(undefined, 1)
|
||||
}
|
||||
|
||||
async ngOnDestroy () {
|
||||
ngOnDestroy () {
|
||||
this.subs.forEach(sub => sub.unsubscribe())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { PackageDataEntry } from '../services/patch-db/data-model'
|
||||
import { PackageState, Status } from '../services/patch-db/data-model'
|
||||
import { PatchDbModel } from '../services/patch-db/patch-db.service'
|
||||
import { renderPkgStatus } from '../services/pkg-status-rendering.service'
|
||||
|
||||
@Pipe({
|
||||
@@ -7,9 +8,14 @@ import { renderPkgStatus } from '../services/pkg-status-rendering.service'
|
||||
})
|
||||
export class DisplayBulbPipe implements PipeTransform {
|
||||
|
||||
transform (pkg: PackageDataEntry, bulb: DisplayBulb, connected: boolean): boolean {
|
||||
constructor (
|
||||
private readonly patch: PatchDbModel,
|
||||
) { }
|
||||
|
||||
transform (pkgId: string, bulb: DisplayBulb, connected: boolean): boolean {
|
||||
const pkg = this.patch.data['package-data'][pkgId]
|
||||
if (!connected) return bulb === 'off'
|
||||
const { color } = renderPkgStatus(pkg)
|
||||
const { color } = renderPkgStatus(pkg.state, pkg.installed.status)
|
||||
switch (color) {
|
||||
case 'danger': return bulb === 'red'
|
||||
case 'success': return bulb === 'green'
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { PackageDataEntry } from '../services/patch-db/data-model'
|
||||
import { PatchDbModel } from '../services/patch-db/patch-db.service'
|
||||
import { FEStatus, renderPkgStatus } from '../services/pkg-status-rendering.service'
|
||||
|
||||
@Pipe({
|
||||
name: 'status',
|
||||
})
|
||||
export class StatusPipe implements PipeTransform {
|
||||
transform (pkg: PackageDataEntry): FEStatus {
|
||||
return renderPkgStatus(pkg).feStatus
|
||||
|
||||
constructor (
|
||||
private readonly patch: PatchDbModel,
|
||||
) { }
|
||||
|
||||
transform (pkgId: string): FEStatus {
|
||||
console.log(pkgId)
|
||||
const pkg = this.patch.data['package-data'][pkgId]
|
||||
return renderPkgStatus(pkg.state, pkg.installed.status).feStatus
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import { parsePropertiesPermissive } from 'src/app/util/properties.util'
|
||||
import { Mock } from './mock-app-fixures'
|
||||
import { HttpService } from '../http.service'
|
||||
import markdown from 'raw-loader!src/assets/markdown/md-sample.md'
|
||||
import { map } from 'rxjs/operators'
|
||||
|
||||
@Injectable()
|
||||
export class MockApiService extends ApiService {
|
||||
@@ -22,10 +21,9 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// every time a patch is returned from the mock, we override its sequence to be 1 more than the last sequence in the patch-db as provided by `o`.
|
||||
watch$ (store: Store<DataModel>): Observable<Update<DataModel>> {
|
||||
store.watchCache$().pipe(map(cache => cache.sequence)).subscribe(seq => {
|
||||
store.sequence$.subscribe(seq => {
|
||||
console.log('INCOMING: ', seq)
|
||||
if (this.sequence < seq) {
|
||||
console.log('hererereree')
|
||||
this.sequence = seq
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@ export class LocalStorageBootstrap implements Bootstrapper<DataModel> {
|
||||
|
||||
async init (): Promise<DBCache<DataModel>> {
|
||||
const cache: DBCache<DataModel> = await this.storage.get(LocalStorageBootstrap.CONTENT_KEY)
|
||||
return cache || { sequence: 0, data: { } }
|
||||
return cache || { sequence: 0, data: { } as DataModel }
|
||||
}
|
||||
|
||||
async update (cache: DBCache<DataModel>): Promise<void> {
|
||||
|
||||
@@ -18,6 +18,7 @@ export enum ConnectionStatus {
|
||||
})
|
||||
export class PatchDbModel {
|
||||
connectionStatus$ = new BehaviorSubject(ConnectionStatus.Initializing)
|
||||
data: DataModel
|
||||
private patchDb: PatchDB<DataModel>
|
||||
private patchSub: Subscription
|
||||
|
||||
@@ -29,6 +30,7 @@ export class PatchDbModel {
|
||||
async init (): Promise<void> {
|
||||
const cache = await this.bootstrapper.init()
|
||||
this.patchDb = new PatchDB(this.sources, cache)
|
||||
this.data = this.patchDb.store.cache.data
|
||||
}
|
||||
|
||||
start (): void {
|
||||
@@ -75,7 +77,7 @@ export class PatchDbModel {
|
||||
return this.connectionStatus$.asObservable()
|
||||
}
|
||||
|
||||
watch$: Store<DataModel> ['watch$'] = (...args: (string | number)[]): Observable<DataModel> => {
|
||||
watch$: Store<DataModel>['watch$'] = (...args: (string | number)[]): Observable<DataModel> => {
|
||||
// console.log('WATCHING')
|
||||
return this.patchDb.store.watch$(...(args as [])).pipe(
|
||||
tap(cache => console.log('CHANGE IN STORE', cache)),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { HealthCheckResultLoading, MainStatusRunning, PackageDataEntry, PackageMainStatus, PackageState, Status } from './patch-db/data-model'
|
||||
import { HealthCheckResultLoading, MainStatusRunning, PackageMainStatus, PackageState, Status } from './patch-db/data-model'
|
||||
|
||||
export function renderPkgStatus (pkg: PackageDataEntry): PkgStatusRendering {
|
||||
switch (pkg.state) {
|
||||
export function renderPkgStatus (state: PackageState, status: Status): PkgStatusRendering {
|
||||
switch (state) {
|
||||
case PackageState.Installing: return { display: 'Installing', color: 'primary', showDots: true, feStatus: FEStatus.Installing }
|
||||
case PackageState.Updating: return { display: 'Updating', color: 'primary', showDots: true, feStatus: FEStatus.Updating }
|
||||
case PackageState.Removing: return { display: 'Removing', color: 'warning', showDots: true, feStatus: FEStatus.Removing }
|
||||
case PackageState.Installed: return handleInstalledState(pkg.installed.status)
|
||||
case PackageState.Installed: return handleInstalledState(status)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user