ui: add embassy os release notes

This commit is contained in:
Aaron Greenspan
2021-01-28 17:22:05 -07:00
committed by Aiden McClelland
parent 68faa17ab6
commit 79604182c8
18 changed files with 148 additions and 115 deletions

View File

@@ -11,7 +11,7 @@
<ion-slides *ngIf="!($error$ | async)" id="slide-show" style="--bullet-background: white" pager="false">
<ion-slide *ngFor="let slide of params.slideDefinitions">
<dependencies #components *ngIf="slide.selector === 'dependencies'" [params]="slide.params"></dependencies>
<developer-notes #components *ngIf="slide.selector === 'developer-notes'" [params]="slide.params"></developer-notes>
<notes #components *ngIf="slide.selector === 'notes'" [params]="slide.params"></notes>
<dependents #components *ngIf="slide.selector === 'dependents'" [params]="slide.params" [finished]="finished"></dependents>
<complete #components *ngIf="slide.selector === 'complete'" [params]="slide.params" [finished]="finished"></complete>
</ion-slide>

View File

@@ -7,7 +7,7 @@ import { SharingModule } from 'src/app/modules/sharing.module'
import { DependenciesComponentModule } from './dependencies/dependencies.component.module'
import { DependentsComponentModule } from './dependents/dependents.component.module'
import { CompleteComponentModule } from './complete/complete.component.module'
import { DeveloperNotesComponentModule } from './developer-notes/developer-notes.component.module'
import { DeveloperNotesComponentModule } from './notes/notes.component.module'
@NgModule({
declarations: [

View File

@@ -47,6 +47,7 @@
font-size: small;
border-width: 0px 0px 1px 0px;
border-color: #393b40;
text-align: left;
}
@media (min-width:500px) {
@@ -57,6 +58,7 @@
font-size: medium;
border-width: 0px 0px 1px 0px;
border-color: #393b40;
text-align: left;
}
}

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'
import { Component, Input, NgZone, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'
import { IonContent, IonSlides, ModalController } from '@ionic/angular'
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs'
import { map } from 'rxjs/operators'
@@ -7,7 +7,7 @@ import { capitalizeFirstLetter } from 'src/app/util/misc.util'
import { CompleteComponent } from './complete/complete.component'
import { DependenciesComponent } from './dependencies/dependencies.component'
import { DependentsComponent } from './dependents/dependents.component'
import { DeveloperNotesComponent } from './developer-notes/developer-notes.component'
import { DeveloperNotesComponent } from './notes/notes.component'
import { Colorable, Loadable } from './loadable'
import { WizardAction } from './wizard-types'
@@ -50,7 +50,7 @@ export class InstallWizardComponent extends Cleanup implements OnInit {
$currentColor$: BehaviorSubject<string> = new BehaviorSubject('medium')
$error$ = new BehaviorSubject(undefined)
constructor (private readonly modalController: ModalController) { super() }
constructor (private readonly modalController: ModalController, private readonly zone: NgZone) { super() }
ngOnInit () { }
ngAfterViewInit () {
@@ -80,15 +80,17 @@ export class InstallWizardComponent extends Cleanup implements OnInit {
private async slide () {
if (this.slideComponents[this.slideIndex + 1] === undefined) { return this.finished({ final: true }) }
this.slideIndex += 1
this.currentSlide.load()
await this.slideContainer.lockSwipes(false)
await Promise.all([
this.contentContainer.scrollToTop(),
this.slideContainer.slideNext(500),
])
await this.slideContainer.lockSwipes(true)
this.slideContainer.update()
this.zone.run(async () => {
this.slideIndex += 1
this.currentSlide.load()
await this.slideContainer.lockSwipes(false)
await Promise.all([
this.contentContainer.scrollToTop(),
this.slideContainer.slideNext(500),
])
await this.slideContainer.lockSwipes(true)
// this.slideContainer.update()
})
}
}
@@ -114,7 +116,7 @@ export type SlideDefinition = SlideCommon & (
selector: 'complete',
params: CompleteComponent['params']
} | {
selector: 'developer-notes',
selector: 'notes',
params: DeveloperNotesComponent['params']
}
)

View File

@@ -2,11 +2,11 @@
<div style="margin-top: 25px;">
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
<ion-label [color]="$color$ | async" style="font-size: xx-large; font-weight: bold;">
Warning
{{params.title}}
</ion-label>
</div>
<div class="long-message">
{{params.developerNotes}}
{{params.notes}}
</div>
</div>
</div>

View File

@@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { DeveloperNotesComponent } from './developer-notes.component'
import { DeveloperNotesComponent } from './notes.component'
import { IonicModule } from '@ionic/angular'
import { RouterModule } from '@angular/router'
import { SharingModule } from 'src/app/modules/sharing.module'

View File

@@ -4,24 +4,24 @@ import { Colorable, Loadable } from '../loadable'
import { WizardAction } from '../wizard-types'
@Component({
selector: 'developer-notes',
templateUrl: './developer-notes.component.html',
selector: 'notes',
templateUrl: './notes.component.html',
styleUrls: ['../install-wizard.component.scss'],
})
export class DeveloperNotesComponent implements OnInit, Loadable, Colorable {
@Input() params: {
action: WizardAction
developerNotes: string
notes: string
title: string
titleColor: string
}
$loading$ = new BehaviorSubject(false)
$color$ = new BehaviorSubject('warning')
$color$ = new BehaviorSubject('light')
$cancel$ = new Subject<void>()
load () { }
constructor () { }
ngOnInit () {
console.log('Developer Notes', this.params)
}
ngOnInit () { this.$color$.next(this.params.titleColor) }
}

View File

@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core'
import { AppModel, AppStatus } from 'src/app/models/app-model'
import { OsUpdateService } from 'src/app/services/os-update.service'
import { exists } from 'src/app/util/misc.util'
import { AppDependency, DependentBreakage, AppInstalledPreview } from '../../models/app-types'
import { ApiService } from '../../services/api/api.service'
@@ -7,7 +8,11 @@ import { InstallWizardComponent, SlideDefinition, TopbarParams } from './install
@Injectable({ providedIn: 'root' })
export class WizardBaker {
constructor (private readonly apiService: ApiService, private readonly appModel: AppModel) { }
constructor (
private readonly apiService: ApiService,
private readonly updateService: OsUpdateService,
private readonly appModel: AppModel
) { }
install (values: {
id: string, title: string, version: string, serviceRequirements: AppDependency[], installAlert?: string
@@ -23,8 +28,8 @@ export class WizardBaker {
const toolbar: TopbarParams = { action, title, version }
const slideDefinitions: SlideDefinition[] = [
installAlert ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, developerNotes: installAlert,
installAlert ? { selector: 'notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, notes: installAlert, title: 'Warning', titleColor: 'warning',
}} : undefined,
{ selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Install', params: {
action, title, version, serviceRequirements,
@@ -52,8 +57,8 @@ export class WizardBaker {
const toolbar: TopbarParams = { action, title, version }
const slideDefinitions: SlideDefinition[] = [
installAlert ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, developerNotes: installAlert,
installAlert ? { selector: 'notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, notes: installAlert, title: 'Warning', titleColor: 'warning',
}} : undefined,
{ selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Update', params: {
action, title, version, serviceRequirements,
@@ -70,6 +75,29 @@ export class WizardBaker {
return { toolbar, slideDefinitions: slideDefinitions.filter(exists) }
}
updateOS (values: {
version: string, releaseNotes: string
}): InstallWizardComponent['params'] {
const { version, releaseNotes } = values
validate(version, exists, 'missing version')
validate(releaseNotes, exists, 'missing updateMessage')
const action = 'update'
const title = 'EmbassyOS'
const toolbar: TopbarParams = { action, title, version }
const slideDefinitions: SlideDefinition[] = [
{ selector: 'notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Update OS', params: {
action, notes: releaseNotes, title: 'Release Notes', titleColor: 'dark',
}},
{ selector: 'complete', finishButton: 'Dismiss', cancelButton: { whileLoading: { } }, params: {
action, verb: 'beginning update for', title, executeAction: () => this.updateService.updateEmbassyOS(version),
}},
]
return { toolbar, slideDefinitions: slideDefinitions.filter(exists) }
}
downgrade (values: {
id: string, title: string, version: string, serviceRequirements: AppDependency[], installAlert?: string
}): InstallWizardComponent['params'] {
@@ -84,8 +112,8 @@ export class WizardBaker {
const toolbar: TopbarParams = { action, title, version }
const slideDefinitions: SlideDefinition[] = [
installAlert ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, developerNotes: installAlert,
installAlert ? { selector: 'notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: {
action, notes: installAlert, title: 'Warning', titleColor: 'warning',
}} : undefined,
{ selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Downgrade', params: {
action, title, version, serviceRequirements,
@@ -115,8 +143,8 @@ export class WizardBaker {
const toolbar: TopbarParams = { action, title, version }
const slideDefinitions: SlideDefinition[] = [
{ selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Continue', params: {
action, developerNotes: uninstallAlert || defaultUninstallationWarning(title) },
{ selector: 'notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Continue', params: {
action, notes: uninstallAlert || defaultUninstallationWarning(title), title: 'Warning', titleColor: 'warning' },
},
{ selector: 'dependents', cancelButton: { whileLoading: { }, afterLoading: { text: 'Cancel' } }, nextButton: 'Uninstall', params: {
action, verb: 'uninstalling', title, fetchBreakages: () => this.apiService.uninstallApp(id, true).then( ({ breakages }) => breakages ),

View File

@@ -1,5 +1,5 @@
<ion-item button lines="none" *ngIf="updateAvailable$ | async as version" (click)="confirmUpdate(version)">
<ion-item button lines="none" *ngIf="updateAvailable$ | async as res" (click)="confirmUpdate(res)">
<ion-label>
New EmbassyOS Version {{version | displayEmver}} Available!
New EmbassyOS Version {{res.versionLatest | displayEmver}} Available!
</ion-label>
</ion-item>

View File

@@ -1,9 +1,10 @@
import { Component } from '@angular/core'
import { OsUpdateService } from 'src/app/services/os-update.service'
import { Observable } from 'rxjs'
import { AlertController } from '@ionic/angular'
import { LoaderService } from 'src/app/services/loader.service'
import { displayEmver } from 'src/app/pipes/emver.pipe'
import { ModalController } from '@ionic/angular'
import { WizardBaker } from '../install-wizard/prebaked-wizards'
import { wizardModal } from '../install-wizard/install-wizard.component'
import { ReqRes } from 'src/app/services/api/api.service'
@Component({
selector: 'update-os-banner',
@@ -11,38 +12,24 @@ import { displayEmver } from 'src/app/pipes/emver.pipe'
styleUrls: ['./update-os-banner.component.scss'],
})
export class UpdateOsBannerComponent {
updateAvailable$: Observable<undefined | string>
updateAvailable$: Observable<undefined | ReqRes.GetVersionLatestRes>
constructor (
private readonly osUpdateService: OsUpdateService,
private readonly alertCtrl: AlertController,
private readonly loader: LoaderService,
private readonly modalCtrl: ModalController,
private readonly wizardBaker: WizardBaker,
) {
this.updateAvailable$ = this.osUpdateService.watchForUpdateAvailable$()
}
ngOnInit () { }
async confirmUpdate (versionLatest: string) {
const alert = await this.alertCtrl.create({
header: `Update EmbassyOS`,
message: `Update EmbassyOS to version ${displayEmver(versionLatest)}?`,
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Update',
handler: () => this.update(versionLatest),
},
],
})
await alert.present()
}
private async update (versionLatest: string) {
return this.loader.displayDuringP(
this.osUpdateService.updateEmbassyOS(versionLatest),
async confirmUpdate (res: ReqRes.GetVersionLatestRes) {
await wizardModal(
this.modalCtrl,
this.wizardBaker.updateOS({
version: res.versionLatest,
releaseNotes: res.releaseNotes,
}),
)
}
}