From 89ff5de01bfaf918c0b5abf2d5eb12e36e4bb269 Mon Sep 17 00:00:00 2001 From: Aaron Greenspan Date: Fri, 8 Jan 2021 14:52:43 -0700 Subject: [PATCH] ui: adds a banner to the marketplace page when an OS update is detected --- .../update-os-banner.component.html | 5 ++ .../update-os-banner.component.module.ts | 16 +++++++ .../update-os-banner.component.scss | 11 +++++ .../update-os-banner.component.ts | 47 ++++++++++++++++++ .../app-available-list.module.ts | 2 + .../app-available-list.page.html | 2 +- .../app-available-list.page.ts | 3 ++ .../server-show/server-show.page.ts | 2 +- ui/src/app/services/api/mock-api.service.ts | 2 +- ui/src/app/services/os-update.service.ts | 48 +++++++++++++++++++ ui/use-mocks.json | 2 +- 11 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 ui/src/app/components/update-os-banner/update-os-banner.component.html create mode 100644 ui/src/app/components/update-os-banner/update-os-banner.component.module.ts create mode 100644 ui/src/app/components/update-os-banner/update-os-banner.component.scss create mode 100644 ui/src/app/components/update-os-banner/update-os-banner.component.ts create mode 100644 ui/src/app/services/os-update.service.ts diff --git a/ui/src/app/components/update-os-banner/update-os-banner.component.html b/ui/src/app/components/update-os-banner/update-os-banner.component.html new file mode 100644 index 000000000..0f8cbc42f --- /dev/null +++ b/ui/src/app/components/update-os-banner/update-os-banner.component.html @@ -0,0 +1,5 @@ + + + New Embassy OS Version {{version}} Available! + + \ No newline at end of file diff --git a/ui/src/app/components/update-os-banner/update-os-banner.component.module.ts b/ui/src/app/components/update-os-banner/update-os-banner.component.module.ts new file mode 100644 index 000000000..e06ba5fa8 --- /dev/null +++ b/ui/src/app/components/update-os-banner/update-os-banner.component.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { UpdateOsBannerComponent } from './update-os-banner.component' +import { IonicModule } from '@ionic/angular' + +@NgModule({ + declarations: [ + UpdateOsBannerComponent, + ], + imports: [ + CommonModule, + IonicModule, + ], + exports: [UpdateOsBannerComponent], +}) +export class UpdateOsBannerComponentModule { } diff --git a/ui/src/app/components/update-os-banner/update-os-banner.component.scss b/ui/src/app/components/update-os-banner/update-os-banner.component.scss new file mode 100644 index 000000000..43db077a7 --- /dev/null +++ b/ui/src/app/components/update-os-banner/update-os-banner.component.scss @@ -0,0 +1,11 @@ +ion-item { + + --background: linear-gradient(90deg, var(--ion-color-light), var(--ion-color-primary)); + --min-height: 0px; + ion-label { + font-family: 'Open Sans'; + font-size: small; + text-align: center; + font-weight: bold; + } +} \ No newline at end of file diff --git a/ui/src/app/components/update-os-banner/update-os-banner.component.ts b/ui/src/app/components/update-os-banner/update-os-banner.component.ts new file mode 100644 index 000000000..4b407d951 --- /dev/null +++ b/ui/src/app/components/update-os-banner/update-os-banner.component.ts @@ -0,0 +1,47 @@ +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' + +@Component({ + selector: 'update-os-banner', + templateUrl: './update-os-banner.component.html', + styleUrls: ['./update-os-banner.component.scss'], +}) +export class UpdateOsBannerComponent { + updateAvailable$: Observable + constructor ( + private readonly osUpdateService: OsUpdateService, + private readonly alertCtrl: AlertController, + private readonly loader: LoaderService, + ) { + this.updateAvailable$ = this.osUpdateService.watchForUpdateAvailable() + } + + ngOnInit () { } + + async confirmUpdate (versionLatest: string) { + const alert = await this.alertCtrl.create({ + header: `Update Embassy OS`, + message: `Are you sure you want to update your Embassy OS to version ${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), + ) + } +} diff --git a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.module.ts b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.module.ts index abe1fa401..434130c4c 100644 --- a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.module.ts +++ b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.module.ts @@ -7,6 +7,7 @@ import { SharingModule } from '../../../modules/sharing.module' import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module' import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module' import { StatusComponentModule } from 'src/app/components/status/status.component.module' +import { UpdateOsBannerComponentModule } from 'src/app/components/update-os-banner/update-os-banner.component.module' const routes: Routes = [ @@ -25,6 +26,7 @@ const routes: Routes = [ SharingModule, PwaBackComponentModule, BadgeMenuComponentModule, + UpdateOsBannerComponentModule, ], declarations: [AppAvailableListPage], }) diff --git a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.html b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.html index ddc829024..7765a6793 100644 --- a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.html +++ b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.html @@ -5,10 +5,10 @@ + - diff --git a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.ts b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.ts index 03f74a3ce..912931566 100644 --- a/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.ts +++ b/ui/src/app/pages/apps-routes/app-available-list/app-available-list.page.ts @@ -7,6 +7,7 @@ import { PropertySubjectId, initPropertySubject } from 'src/app/util/property-su import { Subscription, BehaviorSubject, combineLatest } from 'rxjs' import { take } from 'rxjs/operators' import { markAsLoadingDuringP } from 'src/app/services/loader.service' +import { OsUpdateService } from 'src/app/services/os-update.service' @Component({ selector: 'app-available-list', @@ -24,6 +25,7 @@ export class AppAvailableListPage { private readonly apiService: ApiService, private readonly appModel: AppModel, private readonly zone: NgZone, + private readonly osUpdateService: OsUpdateService, ) { } async ngOnInit () { @@ -33,6 +35,7 @@ export class AppAvailableListPage { markAsLoadingDuringP(this.$loading$, Promise.all([ this.getApps(), + this.osUpdateService.checkForUpdates(), // checks for an os update, banner component renders conditionally pauseFor(600), ])) } diff --git a/ui/src/app/pages/server-routes/server-show/server-show.page.ts b/ui/src/app/pages/server-routes/server-show/server-show.page.ts index 978f6002f..1ec311e8b 100644 --- a/ui/src/app/pages/server-routes/server-show/server-show.page.ts +++ b/ui/src/app/pages/server-routes/server-show/server-show.page.ts @@ -153,7 +153,7 @@ export class ServerShowPage { const alert = await this.alertCtrl.create({ backdropDismiss: false, header: 'Confirm', - message: `Are you sure you shut down your Embassy? To turn it back on, you will need to physically unplug the device and plug it back in.`, + message: `Are you sure you want to shut down your Embassy? To turn it back on, you will need to physically unplug the device and plug it back in.`, buttons: [ { text: 'Cancel', diff --git a/ui/src/app/services/api/mock-api.service.ts b/ui/src/app/services/api/mock-api.service.ts index acadf6e1a..ff109010c 100644 --- a/ui/src/app/services/api/mock-api.service.ts +++ b/ui/src/app/services/api/mock-api.service.ts @@ -420,7 +420,7 @@ const mockApiServer: () => ReqRes.GetServerRes = () => ({ }) const mockVersionLatest: ReqRes.GetVersionLatestRes = { - versionLatest: '0.2.8', + versionLatest: '15.2.8', canUpdate: true, } diff --git a/ui/src/app/services/os-update.service.ts b/ui/src/app/services/os-update.service.ts new file mode 100644 index 000000000..1dbe3d26b --- /dev/null +++ b/ui/src/app/services/os-update.service.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@angular/core' +import { NavController } from '@ionic/angular' +import { BehaviorSubject, forkJoin, Observable, of } from 'rxjs' +import { catchError, map, take, tap } from 'rxjs/operators' +import { ServerModel, ServerStatus } from '../models/server-model' +import { ApiService } from './api/api.service' +import { Emver } from './emver.service' + + +// call checkForUpdates in marketplace pages, can subscribe globally however +@Injectable({ providedIn: 'root' }) +export class OsUpdateService { + private readonly $updateAvailable$ = new BehaviorSubject(undefined) + + constructor ( + private readonly emver: Emver, + private readonly serverModel: ServerModel, + private readonly apiService: ApiService, + private readonly navCtrl: NavController, + ) { } + + watchForUpdateAvailable (): Observable { + return this.$updateAvailable$.asObservable() + } + + // undefined when no update available, string for the versionLatest if there is + checkForUpdates (): Promise { + return forkJoin([ + this.apiService.getVersionLatest(), + this.serverModel.watch().versionInstalled.pipe(take(1)), + ]).pipe( + map(([vl, vi]) => this.emver.compare(vi, vl.versionLatest) === -1 ? vl.versionLatest : undefined), + catchError(e => { + console.error(`OsUpdateService Error: ${e}`) + return of(undefined) + }), + // cache the result for components to learn update available without having to have called this method + tap(updateAvailable => this.$updateAvailable$.next(updateAvailable)), + ).toPromise() + } + + async updateEmbassyOS (versionLatest: string): Promise { + await this.apiService.updateAgent(versionLatest) + this.serverModel.update({ status: ServerStatus.UPDATING }) + this.$updateAvailable$.next(undefined) + await this.navCtrl.navigateRoot('/embassy') + } +} \ No newline at end of file diff --git a/ui/use-mocks.json b/ui/use-mocks.json index 2caee7215..3425efc8a 100644 --- a/ui/use-mocks.json +++ b/ui/use-mocks.json @@ -1,3 +1,3 @@ { - "useMocks": true + "useMocks": false }