This commit is contained in:
Aaron Greenspan
2020-12-18 11:47:11 -07:00
committed by Aiden McClelland
parent 7acfd2da5b
commit 6da3c7e326
4 changed files with 70 additions and 65 deletions

View File

@@ -11,22 +11,22 @@
</ion-header>
<ion-content class="ion-padding-bottom" *ngIf="{
id: app$.id | async,
status: app$.status | async,
title: app$.title | async,
versionInstalled: app$.versionInstalled | async,
versionViewing: app$.versionViewing | async,
descriptionLong: app$.descriptionLong | async,
serviceRequirements: app$.serviceRequirements | async,
iconURL: app$.iconURL | async,
releaseNotes: app$.releaseNotes | async
id: $app$.id | async,
status: $app$.status | async,
title: $app$.title | async,
versionInstalled: $app$.versionInstalled | async,
versionViewing: $app$.versionViewing | async,
descriptionLong: $app$.descriptionLong | async,
serviceRequirements: $app$.serviceRequirements | async,
iconURL: $app$.iconURL | async,
releaseNotes: $app$.releaseNotes | async
} as vars"
>
<ion-spinner *ngIf="($loading$ | async)" class="center" name="lines" color="warning"></ion-spinner>
<error-message [$error$]="$error$" [dismissable]="vars.id"></error-message>
<ng-container *ngIf="!($loading$ | async) && vars.id && (app$ | compareInstalledAndViewing | async) as installedStatus">
<ng-container *ngIf="!($loading$ | async) && vars.id && ($app$ | compareInstalledAndViewing | async) as installedStatus">
<ion-item-group>
<ion-item lines="none">
<ion-avatar slot="start">
@@ -91,10 +91,10 @@
</ion-item>
<ion-item-divider>Release Notes</ion-item-divider>
<ion-item lines="none" button details="true" [disabled]="" (click)="presentModalReleaseNotes()" [disabled]="$versionSpecificLoading$ | async">
<ion-item lines="none" button details="true" [disabled]="" (click)="presentModalReleaseNotes()" [disabled]="$newVersionLoading$ | async">
<ion-icon slot="start" name="newspaper-outline" color="medium"></ion-icon>
<ion-label *ngIf="!($versionSpecificLoading$ | async)"><ion-text color="medium">New in {{ vars.versionViewing | displayEmver }}</ion-text></ion-label>
<ion-spinner style="display: block; margin: auto;" name="lines" color="dark" *ngIf="$versionSpecificLoading$ | async"></ion-spinner>
<ion-label *ngIf="!($newVersionLoading$ | async)"><ion-text color="medium">New in {{ vars.versionViewing | displayEmver }}</ion-text></ion-label>
<ion-spinner style="display: block; margin: auto;" name="lines" color="dark" *ngIf="$newVersionLoading$ | async"></ion-spinner>
</ion-item>
<ng-container *ngIf="(vars.serviceRequirements)?.length">
@@ -103,7 +103,7 @@
<ion-icon name="help-circle-outline"></ion-icon>
</ion-button>
</ion-item-divider>
<dependency-list [$loading$]="$versionSpecificLoading$" [hostApp]="app$ | peekProperties" [dependencies]="vars.serviceRequirements"></dependency-list>
<dependency-list [$loading$]="$dependenciesLoading$" [hostApp]="$app$ | peekProperties" [dependencies]="vars.serviceRequirements"></dependency-list>
</ng-container>
<ion-item-divider></ion-item-divider>
<ion-item lines="none" button (click)="presentAlertVersions()">

View File

@@ -25,9 +25,14 @@ import { displayEmver } from 'src/app/pipes/emver.pipe'
})
export class AppAvailableShowPage extends Cleanup {
$loading$ = new BehaviorSubject(true)
$versionSpecificLoading$ = new BehaviorSubject(false)
// When a new version is selected
$newVersionLoading$ = new BehaviorSubject(false)
// When dependencies are refreshing
$dependenciesLoading$ = new BehaviorSubject(false)
$error$ = new BehaviorSubject(undefined)
app$: PropertySubject<AppAvailableFull> = { } as any
$app$: PropertySubject<AppAvailableFull> = { } as any
appId: string
openRecommendation = false
@@ -58,26 +63,18 @@ export class AppAvailableShowPage extends Cleanup {
this.cleanup(
markAsLoadingDuring$(this.$loading$,
from(this.apiService.getAvailableApp(this.appId)).pipe(
tap(app => this.app$ = initPropertySubject(app)),
tap(app => this.$app$ = initPropertySubject(app)),
concatMap(() => this.fetchRecommendation()),
),
).pipe(
concatMap(() => this.syncWhenDependencyInstalls()), //must be final in stack
catchError(e => of(this.setError(e))),
).subscribe(),
merge(this.$loading$, this.$versionSpecificLoading$).pipe(concatMap(l => {
if (l) {
this.showMoreReleaseNotes = false
}
return pauseFor(125)
})).subscribe(
() => this.setMoreReleaseNotes(),
),
)
}
ionViewDidEnter () {
markAsLoadingDuring$(this.$versionSpecificLoading$, this.fetchAppVersionInfo()).subscribe({
markAsLoadingDuring$(this.$dependenciesLoading$, this.syncVersionSpecificInfo()).subscribe({
error: e => this.setError(e),
})
}
@@ -96,25 +93,25 @@ export class AppAvailableShowPage extends Cleanup {
return await popover.present()
}
fetchAppVersionInfo (versionSpec?: string): Observable<any> {
if (!this.app$.versionViewing) return of({ })
const specToFetch = versionSpec || `=${this.app$.versionViewing.getValue()}`
syncVersionSpecificInfo (versionSpec?: string): Observable<any> {
if (!this.$app$.versionViewing) return of({ })
const specToFetch = versionSpec || `=${this.$app$.versionViewing.getValue()}`
return from(this.apiService.getAvailableAppVersionSpecificInfo(this.appId, specToFetch)).pipe(
tap(versionInfo => this.syncVersionSpecificInfo(versionInfo)),
tap(versionInfo => this.mergeInfo(versionInfo)),
)
}
private syncVersionSpecificInfo (versionSpecificInfo: AppAvailableVersionSpecificInfo) {
private mergeInfo (versionSpecificInfo: AppAvailableVersionSpecificInfo) {
this.zone.run(() => {
Object.entries(versionSpecificInfo).forEach( ([k, v]) => {
if (!this.app$[k]) this.app$[k] = new BehaviorSubject(undefined)
if (v !== this.app$[k].getValue()) this.app$[k].next(v)
if (!this.$app$[k]) this.$app$[k] = new BehaviorSubject(undefined)
if (v !== this.$app$[k].getValue()) this.$app$[k].next(v)
})
})
}
async presentAlertVersions () {
const app = peekProperties(this.app$)
const app = peekProperties(this.$app$)
const alert = await this.alertCtrl.create({
header: 'Versions',
backdropDismiss: false,
@@ -133,13 +130,15 @@ export class AppAvailableShowPage extends Cleanup {
}, {
text: 'Ok',
handler: (version: string) => {
const previousVersion = this.app$.versionViewing.getValue()
this.app$.versionViewing.next(version)
markAsLoadingDuring$(this.$versionSpecificLoading$, this.fetchAppVersionInfo(`=${version}`))
const previousVersion = this.$app$.versionViewing.getValue()
this.$app$.versionViewing.next(version)
markAsLoadingDuring$(
this.$newVersionLoading$, this.syncVersionSpecificInfo(`=${version}`)
)
.subscribe({
error: e => {
this.setError(e)
this.app$.versionViewing.next(previousVersion)
this.$app$.versionViewing.next(previousVersion)
},
})
},
@@ -151,7 +150,7 @@ export class AppAvailableShowPage extends Cleanup {
}
async install () {
const app = peekProperties(this.app$)
const app = peekProperties(this.$app$)
const { cancelled } = await wizardModal(
this.modalCtrl,
this.wizardBaker.install({
@@ -166,7 +165,7 @@ export class AppAvailableShowPage extends Cleanup {
}
async update (action: 'update' | 'downgrade') {
const app = peekProperties(this.app$)
const app = peekProperties(this.$app$)
const value = {
id: app.id,
@@ -190,7 +189,7 @@ export class AppAvailableShowPage extends Cleanup {
}
async presentModalReleaseNotes () {
const { releaseNotes, versionViewing } = peekProperties(this.app$)
const { releaseNotes, versionViewing } = peekProperties(this.$app$)
const modal = await this.modalCtrl.create({
component: AppReleaseNotesPage,
@@ -207,17 +206,17 @@ export class AppAvailableShowPage extends Cleanup {
this.recommendation = history.state && history.state.installationRecommendation
if (this.recommendation) {
return from(this.fetchAppVersionInfo(this.recommendation.versionSpec))
return from(this.syncVersionSpecificInfo(this.recommendation.versionSpec))
} else {
return of({ })
}
}
private syncWhenDependencyInstalls (): Observable<void> {
return this.app$.serviceRequirements.pipe(
return this.$app$.serviceRequirements.pipe(
filter(deps => !!deps),
switchMap(deps => this.appModel.watchForInstallations(deps)),
concatMap(() => markAsLoadingDuring$(this.$versionSpecificLoading$, this.fetchAppVersionInfo())),
concatMap(() => markAsLoadingDuring$(this.$dependenciesLoading$, this.syncVersionSpecificInfo())),
catchError(e => of(console.error(e))),
)
}
@@ -226,24 +225,4 @@ export class AppAvailableShowPage extends Cleanup {
console.error(e)
this.$error$.next(e.message)
}
private setMoreReleaseNotes () {
const releaseNotes = document.getElementById(`release-notes-${this.appId}`)
if (releaseNotes) {
this.showMoreReleaseNotes = isTextOverflow(releaseNotes)
}
}
@HostListener('window:resize', ['$event'])
onResize () {
this.setMoreReleaseNotes()
}
}
function isTextOverflow (elem: any): boolean {
if (elem) {
return (elem.offsetWidth < elem.scrollWidth)
}
return false
}

View File

@@ -0,0 +1,26 @@
<ion-header *ngIf="{appLoading: $appLoading$ | async} as vars">
<ion-toolbar>
<ion-buttons style="margin: 0px 15px" slot="start">
<img class="bulb" *ngIf="status$ | async | displayBulb: 'green'" src="assets/img/green-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'red'" src="assets/img/red-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'yellow'" src="assets/img/yellow-bulb.png"/>
<img class="bulb" *ngIf="status$ | async | displayBulb: 'off'" src="assets/img/black-bulb.png"/>
</ion-buttons>
<ion-title>{{$app$.title | async}}</ion-title>
<ion-buttons slot="end" *ngIf="">
<ion-spinner *ngIf="vars.appLoading" name="dots" color="medium"></ion-spinner>
<ion-button *ngIf="!vars.appLoading" (click)=presentPopoverMenu($event)>
<ion-icon name="ellipsis-vertical"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content style="--overflow: hidden;" *ngIf="{isRunning: isRunning$ | async, status: status$ | async, appLoading: $appLoading$ | async, iframeLoading: $iframeLoading$ | async } as vars">
<ion-spinner *ngIf="vars.appLoading || vars.iframeLoading" style="position: absolute; width: 4vh; left: calc(50% - 2vh); height: 100%;" name="lines" color="warning"></ion-spinner>
<iframe (load)="iframeLoaded()" *ngIf="!vars.appLoading && vars.isRunning" [id]="appId + '-ui'" src="http://localhost:8100" width="100%" height="100%" style="border:1px solid black;"></iframe>
<div *ngIf="!vars.appLoading && !vars.isRunning" class="flex-center" style="border:1px solid black; color: white">
<ion-label style="margin:10px">{{$app$.title | async}} is not running.</ion-label>
<ion-button fill="outline" (click)="toServiceShow()">View</ion-button>
</div>
</ion-content>

View File

@@ -1,3 +1,3 @@
{
"useMocks": false
"useMocks": true
}