mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
ui: adds a banner to the marketplace page when an OS update is detected
This commit is contained in:
committed by
Aiden McClelland
parent
6da3c7e326
commit
89ff5de01b
@@ -0,0 +1,5 @@
|
|||||||
|
<ion-item button lines="none" *ngIf="updateAvailable$ | async as version" (click)="confirmUpdate(version)">
|
||||||
|
<ion-label>
|
||||||
|
New Embassy OS Version {{version}} Available!
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
@@ -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 { }
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<undefined | string>
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { SharingModule } from '../../../modules/sharing.module'
|
|||||||
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.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 { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||||
import { StatusComponentModule } from 'src/app/components/status/status.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 = [
|
const routes: Routes = [
|
||||||
@@ -25,6 +26,7 @@ const routes: Routes = [
|
|||||||
SharingModule,
|
SharingModule,
|
||||||
PwaBackComponentModule,
|
PwaBackComponentModule,
|
||||||
BadgeMenuComponentModule,
|
BadgeMenuComponentModule,
|
||||||
|
UpdateOsBannerComponentModule,
|
||||||
],
|
],
|
||||||
declarations: [AppAvailableListPage],
|
declarations: [AppAvailableListPage],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
<badge-menu-button></badge-menu-button>
|
<badge-menu-button></badge-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
<update-os-banner></update-os-banner>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-bottom">
|
<ion-content class="ion-padding-bottom">
|
||||||
|
|
||||||
<ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
|
<ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
|
||||||
<ion-refresher-content pullingIcon="lines" refreshingSpinner="lines"></ion-refresher-content>
|
<ion-refresher-content pullingIcon="lines" refreshingSpinner="lines"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { PropertySubjectId, initPropertySubject } from 'src/app/util/property-su
|
|||||||
import { Subscription, BehaviorSubject, combineLatest } from 'rxjs'
|
import { Subscription, BehaviorSubject, combineLatest } from 'rxjs'
|
||||||
import { take } from 'rxjs/operators'
|
import { take } from 'rxjs/operators'
|
||||||
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
|
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
|
||||||
|
import { OsUpdateService } from 'src/app/services/os-update.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-available-list',
|
selector: 'app-available-list',
|
||||||
@@ -24,6 +25,7 @@ export class AppAvailableListPage {
|
|||||||
private readonly apiService: ApiService,
|
private readonly apiService: ApiService,
|
||||||
private readonly appModel: AppModel,
|
private readonly appModel: AppModel,
|
||||||
private readonly zone: NgZone,
|
private readonly zone: NgZone,
|
||||||
|
private readonly osUpdateService: OsUpdateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
@@ -33,6 +35,7 @@ export class AppAvailableListPage {
|
|||||||
|
|
||||||
markAsLoadingDuringP(this.$loading$, Promise.all([
|
markAsLoadingDuringP(this.$loading$, Promise.all([
|
||||||
this.getApps(),
|
this.getApps(),
|
||||||
|
this.osUpdateService.checkForUpdates(), // checks for an os update, banner component renders conditionally
|
||||||
pauseFor(600),
|
pauseFor(600),
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class ServerShowPage {
|
|||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
backdropDismiss: false,
|
backdropDismiss: false,
|
||||||
header: 'Confirm',
|
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: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: 'Cancel',
|
text: 'Cancel',
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ const mockApiServer: () => ReqRes.GetServerRes = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const mockVersionLatest: ReqRes.GetVersionLatestRes = {
|
const mockVersionLatest: ReqRes.GetVersionLatestRes = {
|
||||||
versionLatest: '0.2.8',
|
versionLatest: '15.2.8',
|
||||||
canUpdate: true,
|
canUpdate: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
ui/src/app/services/os-update.service.ts
Normal file
48
ui/src/app/services/os-update.service.ts
Normal file
@@ -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<undefined | string> {
|
||||||
|
return this.$updateAvailable$.asObservable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// undefined when no update available, string for the versionLatest if there is
|
||||||
|
checkForUpdates (): Promise<undefined | string> {
|
||||||
|
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<void> {
|
||||||
|
await this.apiService.updateAgent(versionLatest)
|
||||||
|
this.serverModel.update({ status: ServerStatus.UPDATING })
|
||||||
|
this.$updateAvailable$.next(undefined)
|
||||||
|
await this.navCtrl.navigateRoot('/embassy')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"useMocks": true
|
"useMocks": false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user