From e96ef695a36e74e4bc351672fd8109a53d918298 Mon Sep 17 00:00:00 2001 From: Aaron Greenspan Date: Wed, 20 Jan 2021 13:04:32 -0700 Subject: [PATCH] ui: revert to sync style --- ui/src/app/app.component.ts | 5 +- .../app/modals/os-welcome/os-welcome.page.ts | 10 +- ui/src/app/models/server-model.ts | 16 +-- ui/src/app/services/api/mock-api.service.ts | 1 - ui/src/app/services/os-update.service.ts | 11 ++ .../app/services/startup-alerts.notifier.ts | 113 ++++++++---------- ui/src/app/services/sync.service.ts | 5 +- ui/use-mocks.json | 2 +- 8 files changed, 72 insertions(+), 91 deletions(-) diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 4c4e67837..8154c739a 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -3,7 +3,7 @@ import { ServerModel, ServerStatus } from './models/server-model' import { Storage } from '@ionic/storage' import { SyncDaemon } from './services/sync.service' import { AuthService, AuthState } from './services/auth.service' -import { GlobalAlertsNotifier } from './services/startup-alerts.notifier' +import { StartupAlertsNotifier } from './services/startup-alerts.notifier' import { ApiService } from './services/api/api.service' import { Router } from '@angular/router' import { BehaviorSubject, Observable } from 'rxjs' @@ -66,7 +66,7 @@ export class AppComponent { private readonly alertCtrl: AlertController, private readonly loader: LoaderService, private readonly emver: Emver, - private readonly globalAlertsNotifier: GlobalAlertsNotifier, + private readonly globalAlertsNotifier: StartupAlertsNotifier, readonly splitPane: SplitPaneTracker, ) { // set dark theme @@ -81,7 +81,6 @@ export class AppComponent { await this.storage.ready() await this.authService.restoreCache() await this.emver.init() - this.globalAlertsNotifier.init() this.authService.listen({ [AuthState.VERIFIED]: async () => { diff --git a/ui/src/app/modals/os-welcome/os-welcome.page.ts b/ui/src/app/modals/os-welcome/os-welcome.page.ts index 17e8f4a34..8418d04b8 100644 --- a/ui/src/app/modals/os-welcome/os-welcome.page.ts +++ b/ui/src/app/modals/os-welcome/os-welcome.page.ts @@ -19,18 +19,14 @@ export class OSWelcomePage { private readonly modalCtrl: ModalController, private readonly apiService: ApiService, private readonly serverModel: ServerModel, - private readonly loader: LoaderService, ) { } async dismiss () { - await this.loader.displayDuringP( - this.apiService + this.apiService .patchServerConfig('autoCheckUpdates', this.autoCheckUpdates) .then(() => this.serverModel.update({ autoCheckUpdates: this.autoCheckUpdates })) - .then(() => pauseFor(600000)) .catch(console.error), - ).then( - () => this.modalCtrl.dismiss({ autoCheckUpdates: this.autoCheckUpdates }) - ) + + this.modalCtrl.dismiss({ autoCheckUpdates: this.autoCheckUpdates }) } } diff --git a/ui/src/app/models/server-model.ts b/ui/src/app/models/server-model.ts index ee72ee064..cd73d6871 100644 --- a/ui/src/app/models/server-model.ts +++ b/ui/src/app/models/server-model.ts @@ -1,12 +1,11 @@ import { Injectable } from '@angular/core' -import { Subject, BehaviorSubject, Observable } from 'rxjs' +import { Subject, BehaviorSubject } from 'rxjs' import { PropertySubject, peekProperties, initPropertySubject } from '../util/property-subject.util' import { AppModel } from './app-model' import { ConfigService } from 'src/app/services/config.service' import { Storage } from '@ionic/storage' -import { throttleTime, delay, filter, map } from 'rxjs/operators' +import { throttleTime, delay } from 'rxjs/operators' import { StorageKeys } from './storage-keys' -import { exists } from '../util/misc.util' export enum ServerModelState { BOOT, @@ -51,13 +50,7 @@ export class ServerModel { }) } - sync (update: Partial, timestamp: Date = new Date()): void { - return this.update(update, timestamp, ServerModelState.LIVE) - } - - update (update: Partial, timestamp: Date = new Date(), src?: ServerModelState): void { - console.log('updating:', update) - console.log('present:', this.peek()) + update (update: Partial, timestamp: Date = new Date()): void { if (this.lastUpdateTimestamp > timestamp) return if (update.versionInstalled && (update.versionInstalled !== this.config.version) && this.embassy.status.getValue() === ServerStatus.RUNNING) { @@ -79,7 +72,6 @@ export class ServerModel { }, ) this.$delta$.next() - if (src) this.$modelState$.next(src) this.lastUpdateTimestamp = timestamp } @@ -98,7 +90,7 @@ export class ServerModel { async restoreCache (): Promise { const emb = await this.storage.get(StorageKeys.SERVER_CACHE_KEY) - if (emb && emb.versionInstalled === this.config.version) this.update(emb, new Date(), ServerModelState.LOCALSTORAGE) + if (emb && emb.versionInstalled === this.config.version) this.update(emb, new Date()) } // server state change diff --git a/ui/src/app/services/api/mock-api.service.ts b/ui/src/app/services/api/mock-api.service.ts index 6b837c1b9..f07c6b2b8 100644 --- a/ui/src/app/services/api/mock-api.service.ts +++ b/ui/src/app/services/api/mock-api.service.ts @@ -167,7 +167,6 @@ export class MockApiService extends ApiService { } async patchServerConfig (attr: string, value: any): Promise { - console.log('huh', attr, value) await mockPatchServerConfig() this.serverModel.update({ [attr]: value }) return { } diff --git a/ui/src/app/services/os-update.service.ts b/ui/src/app/services/os-update.service.ts index 704608085..b581811e7 100644 --- a/ui/src/app/services/os-update.service.ts +++ b/ui/src/app/services/os-update.service.ts @@ -48,6 +48,17 @@ export class OsUpdateService { ) } + updateIsAvailable (vi: string, vl: string): boolean { + if (!vi || !vl) return false + if (this.emver.compare(vi, vl) === -1) { + this.$updateAvailable$.next(vl) + return true + } else { + this.$updateAvailable$.next(undefined) + return false + } + } + async checkForAppsUpdate (): Promise { const availableApps = await this.apiService.getAvailableApps() return !!availableApps.find(app => this.emver.compare(app.versionInstalled, app.versionLatest) === -1) diff --git a/ui/src/app/services/startup-alerts.notifier.ts b/ui/src/app/services/startup-alerts.notifier.ts index c53de9420..cbe808879 100644 --- a/ui/src/app/services/startup-alerts.notifier.ts +++ b/ui/src/app/services/startup-alerts.notifier.ts @@ -1,76 +1,74 @@ import { Injectable } from '@angular/core' import { AlertController, ModalController, NavController } from '@ionic/angular' -import { combineLatest, Observable, of } from 'rxjs' -import { concatMap, debounceTime, distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators' import { OSWelcomePage } from '../modals/os-welcome/os-welcome.page' -import { ServerModel, ServerModelState } from '../models/server-model' -import { exists, traceWheel } from '../util/misc.util' +import { S9Server } from '../models/server-model' import { ApiService } from './api/api.service' import { ConfigService } from './config.service' +import { Emver } from './emver.service' import { LoaderService } from './loader.service' import { OsUpdateService } from './os-update.service' @Injectable({ providedIn: 'root' }) -export class GlobalAlertsNotifier { +export class StartupAlertsNotifier { constructor ( - private readonly osUpdateService: OsUpdateService, private readonly alertCtrl: AlertController, private readonly navCtrl: NavController, private readonly loader: LoaderService, private readonly config: ConfigService, private readonly modalCtrl: ModalController, - private readonly server: ServerModel, private readonly apiService: ApiService, - ) { + private readonly emver: Emver, + private readonly osUpdateService: OsUpdateService, + ) { } + + displayedWelcomeMessage = false + checkedForUpdates = false + welcomeSetAutoUpdateCheck = false + + async handleSpecial (server: Readonly): Promise { + this.handleOSWelcome(server) + if (!this.displayedWelcomeMessage) this.handleUpdateCheck(server) } - init () { - console.log('init') - of({ }).pipe( - concatMap( - () => this.welcomeNeeded$().pipe( - take(1), // we only show welcome at most once per app instance - concatMap(vi => vi ? this.presentOsWelcome(vi) : of({ })), - ), - ), - concatMap( - () => this.osUpdateAlertNeeded$().pipe( - concatMap(vl => vl ? this.presentUpdateDailogues(vl) : of({ })), - ), - ), - ).subscribe() + private async handleOSWelcome (server: Readonly) { + if (server.welcomeAck || server.versionInstalled !== this.config.version || this.displayedWelcomeMessage) return + + this.displayedWelcomeMessage = true + + const modal = await this.modalCtrl.create({ + backdropDismiss: false, + component: OSWelcomePage, + presentingElement: await this.modalCtrl.getTop(), + componentProps: { + version: server.versionInstalled, + }, + }) + + modal.onDidDismiss().then(res => { + this.welcomeSetAutoUpdateCheck = res.data.autoCheckUpdates + this.apiService.acknowledgeOSWelcome(this.config.version) + this.handleUpdateCheck(server) + }) + await modal.present() } - // emits versionInstalled when welcomeAck is false and f.e and b.e have same version - private welcomeNeeded$ (): Observable { - const { welcomeAck, versionInstalled } = this.server.watch() + private async handleUpdateCheck (server: Readonly) { + if (this.displayedWelcomeMessage && !this.welcomeSetAutoUpdateCheck) return + if (!this.displayedWelcomeMessage && (!server.autoCheckUpdates || this.checkedForUpdates)) return - return combineLatest([ this.server.$modelState$, welcomeAck, versionInstalled ]).pipe( - filter(([ms, _, vi]) => ms === ServerModelState.LIVE && !!vi), - map(([_, wa, vi]) => !wa && vi === this.config.version ? vi : undefined), - ) - } - - // emits versionLatest whenever autoCheckUpdates becomes true and checkForUpdates yields a new version - private osUpdateAlertNeeded$ (): Observable { - return this.server.watch().autoCheckUpdates.pipe( - distinctUntilChanged(), - filter(exists), // - concatMap(() => this.osUpdateService.checkForUpdates$()), - ) - } - - private async presentUpdateDailogues (vl : string): Promise { - const { update } = await this.presentAlertNewOS(vl) - if (update) { - return this.loader.displayDuringP( - this.osUpdateService.updateEmbassyOS(vl), - ).catch(e => alert(e)) + this.checkedForUpdates = true + if (this.osUpdateService.updateIsAvailable(server.versionInstalled, server.versionLatest)) { + const { update } = await this.presentAlertNewOS(server.versionLatest) + if (update) { + return this.loader + .displayDuringP(this.osUpdateService.updateEmbassyOS(server.versionLatest)) + .catch(e => alert(e)) + } } try { - const newApps = await this.osUpdateService.checkForAppsUpdate() - if (newApps) { + const availableApps = await this.apiService.getAvailableApps() + if (!!availableApps.find(app => this.emver.compare(app.versionInstalled, app.versionLatest) === -1)) { return this.presentAlertNewApps() } } catch (e) { @@ -78,23 +76,6 @@ export class GlobalAlertsNotifier { } } - private async presentOsWelcome (vi: string): Promise { - return new Promise(async resolve => { - const modal = await this.modalCtrl.create({ - backdropDismiss: false, - component: OSWelcomePage, - presentingElement: await this.modalCtrl.getTop(), - componentProps: { version: vi }, - }) - //kick this off async - this.apiService.acknowledgeOSWelcome(this.config.version).catch(e => { - console.error(`Unable to acknowledge OS welcome`, e) - }) - await modal.present() - modal.onDidDismiss().then(() => resolve()) - }) - } - private async presentAlertNewApps () { const alert = await this.alertCtrl.create({ backdropDismiss: true, diff --git a/ui/src/app/services/sync.service.ts b/ui/src/app/services/sync.service.ts index 6888b04ee..8fb8fc0e7 100644 --- a/ui/src/app/services/sync.service.ts +++ b/ui/src/app/services/sync.service.ts @@ -6,6 +6,7 @@ import { AppModel } from '../models/app-model' import { SyncNotifier } from './sync.notifier' import { BehaviorSubject, Observable, of, from, Subject, EMPTY } from 'rxjs' import { switchMap, concatMap, catchError, delay, tap } from 'rxjs/operators' +import { StartupAlertsNotifier } from './startup-alerts.notifier' @Injectable({ providedIn: 'root', @@ -22,6 +23,7 @@ export class SyncDaemon { private readonly serverModel: ServerModel, private readonly appModel: AppModel, private readonly syncNotifier: SyncNotifier, + private readonly startupAlertsNotifier: StartupAlertsNotifier, ) { this.$sync$.pipe( switchMap(go => go @@ -36,6 +38,7 @@ export class SyncDaemon { sync (): Observable { return from(this.getServerAndApps()).pipe( concatMap(() => this.syncNotifier.handleSpecial(this.serverModel.peek())), + concatMap(() => this.startupAlertsNotifier.handleSpecial(this.serverModel.peek())), tap(() => this.$synced$.next()), catchError(e => of(console.error(`Exception in sync service`, e))), ) @@ -54,7 +57,7 @@ export class SyncDaemon { switch (serverRes.result) { case 'resolve': { - this.serverModel.sync(serverRes.value, now) + this.serverModel.update(serverRes.value, now) break } case 'reject': { diff --git a/ui/use-mocks.json b/ui/use-mocks.json index 3425efc8a..2caee7215 100644 --- a/ui/use-mocks.json +++ b/ui/use-mocks.json @@ -1,3 +1,3 @@ { - "useMocks": false + "useMocks": true }