From 238ede33b983a506a52e91fde3443978b651c4e5 Mon Sep 17 00:00:00 2001 From: Aaron Greenspan Date: Wed, 13 Jan 2021 17:11:12 -0700 Subject: [PATCH] ui: adds install/uninstall warnings --- .../dependencies/dependencies.component.ts | 5 +- .../developer-notes.component.html | 11 ++--- .../developer-notes.component.ts | 48 ++----------------- .../install-wizard.component.html | 2 +- .../install-wizard.component.ts | 11 +++-- .../install-wizard/prebaked-wizards.ts | 39 +++++++++------ ui/src/app/models/app-types.ts | 2 + .../app-available-show.page.ts | 6 ++- .../app-installed-show.page.ts | 1 + ui/src/app/services/api/mock-api.service.ts | 1 + ui/src/app/services/api/mock-app-fixures.ts | 4 +- ui/src/app/util/rxjs.util.ts | 2 +- 12 files changed, 57 insertions(+), 75 deletions(-) diff --git a/ui/src/app/components/install-wizard/dependencies/dependencies.component.ts b/ui/src/app/components/install-wizard/dependencies/dependencies.component.ts index 6341f155f..5f15dda11 100644 --- a/ui/src/app/components/install-wizard/dependencies/dependencies.component.ts +++ b/ui/src/app/components/install-wizard/dependencies/dependencies.component.ts @@ -38,9 +38,12 @@ export class DependenciesComponent implements OnInit, Loadable, Colorable { label: string $color$ = new BehaviorSubject('medium') - constructor (private readonly popoverController: PopoverController) { } + constructor (private readonly popoverController: PopoverController) { + console.log('dependencies') + } load () { + console.log('loading dependencies') this.$color$.next(this.$color$.getValue()) } diff --git a/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.html b/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.html index 226a014b3..9b5ca1b81 100644 --- a/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.html +++ b/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.html @@ -1,17 +1,12 @@ -
+
- {{successText}} + Warning
- {{summary}} + {{params.developerNotes}}
- -
- - {{label}} -
\ No newline at end of file diff --git a/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.ts b/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.ts index dca8f88b3..22a68203b 100644 --- a/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.ts +++ b/ui/src/app/components/install-wizard/developer-notes/developer-notes.component.ts @@ -1,8 +1,5 @@ import { Component, Input, OnInit } from '@angular/core' -import { BehaviorSubject, from, Subject } from 'rxjs' -import { takeUntil } from 'rxjs/operators' -import { markAsLoadingDuring$ } from 'src/app/services/loader.service' -import { capitalizeFirstLetter } from 'src/app/util/misc.util' +import { BehaviorSubject, Subject } from 'rxjs' import { Colorable, Loadable } from '../loadable' import { WizardAction } from '../wizard-types' @@ -18,50 +15,13 @@ export class DeveloperNotesComponent implements OnInit, Loadable, Colorable { } $loading$ = new BehaviorSubject(false) - $color$ = new BehaviorSubject('medium') + $color$ = new BehaviorSubject('warning') $cancel$ = new Subject() - load () {} + load () { } constructor () { } ngOnInit () { - switch (this.params.action) { - case 'install': - this.summary = `Installation of ${this.params.title} is now in progress. You will receive a notification when the installation has completed.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('primary') - this.successText = 'In Progress' - break - case 'downgrade': - this.summary = `Downgrade for ${this.params.title} is now in progress. You will receive a notification when the downgrade has completed.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('primary') - this.successText = 'In Progress' - break - case 'update': - this.summary = `Update for ${this.params.title} is now in progress. You will receive a notification when the update has completed.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('primary') - this.successText = 'In Progress' - break - case 'uninstall': - this.summary = `${capitalizeFirstLetter(this.params.title)} has been successfully uninstalled.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('success') - this.successText = 'Success' - break - case 'stop': - this.summary = `${capitalizeFirstLetter(this.params.title)} has been successfully stopped.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('success') - this.successText = 'Success' - break - case 'configure': - this.summary = `New config for ${this.params.title} has been successfully saved.` - this.label = `${capitalizeFirstLetter(this.params.verb)} ${this.params.title}...` - this.$color$.next('success') - this.successText = 'Success' - break - } + console.log('Developer Notes', this.params) } } diff --git a/ui/src/app/components/install-wizard/install-wizard.component.html b/ui/src/app/components/install-wizard/install-wizard.component.html index 35e527a34..80af87d79 100644 --- a/ui/src/app/components/install-wizard/install-wizard.component.html +++ b/ui/src/app/components/install-wizard/install-wizard.component.html @@ -10,8 +10,8 @@ - + diff --git a/ui/src/app/components/install-wizard/install-wizard.component.ts b/ui/src/app/components/install-wizard/install-wizard.component.ts index 5bfc10bb0..b6d879565 100644 --- a/ui/src/app/components/install-wizard/install-wizard.component.ts +++ b/ui/src/app/components/install-wizard/install-wizard.component.ts @@ -81,10 +81,15 @@ 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 - await this.slideContainer.lockSwipes(false) - await Promise.all([this.contentContainer.scrollToTop(), this.slideContainer.slideNext()]) - await this.slideContainer.lockSwipes(true) 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.currentSlide.load() } } diff --git a/ui/src/app/components/install-wizard/prebaked-wizards.ts b/ui/src/app/components/install-wizard/prebaked-wizards.ts index 8737eded2..f9047359e 100644 --- a/ui/src/app/components/install-wizard/prebaked-wizards.ts +++ b/ui/src/app/components/install-wizard/prebaked-wizards.ts @@ -9,9 +9,9 @@ export class WizardBaker { constructor (private readonly apiService: ApiService, private readonly appModel: AppModel) { } install (values: { - id: string, title: string, version: string, serviceRequirements: AppDependency[], developerNotes?: string + id: string, title: string, version: string, serviceRequirements: AppDependency[], installWarning?: string }): InstallWizardComponent['params'] { - const { id, title, version, serviceRequirements, developerNotes } = values + const { id, title, version, serviceRequirements, installWarning } = values validate(id, exists, 'missing id') validate(title, exists, 'missing title') @@ -22,9 +22,9 @@ export class WizardBaker { const toolbar: TopbarParams = { action, title, version } const slideDefinitions: SlideDefinition[] = [ - { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: { - action, title, version, serviceRequirements, - }}, + installWarning ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: { + action, developerNotes: installWarning, + }} : undefined, { selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Install', params: { action, title, version, serviceRequirements, }}, @@ -34,13 +34,13 @@ export class WizardBaker { }), }}, ] - return { toolbar, slideDefinitions } + return { toolbar, slideDefinitions: slideDefinitions.filter(exists) } } update (values: { - id: string, title: string, version: string, serviceRequirements: AppDependency[] + id: string, title: string, version: string, serviceRequirements: AppDependency[], installWarning?: string }): InstallWizardComponent['params'] { - const { id, title, version, serviceRequirements } = values + const { id, title, version, serviceRequirements, installWarning } = values validate(id, exists, 'missing id') validate(title, exists, 'missing title') @@ -51,6 +51,9 @@ export class WizardBaker { const toolbar: TopbarParams = { action, title, version } const slideDefinitions: SlideDefinition[] = [ + installWarning ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: { + action, developerNotes: installWarning, + }} : undefined, { selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Update', params: { action, title, version, serviceRequirements, }}, @@ -63,13 +66,13 @@ export class WizardBaker { }), }}, ] - return { toolbar, slideDefinitions } + return { toolbar, slideDefinitions: slideDefinitions.filter(exists) } } downgrade (values: { - id: string, title: string, version: string, serviceRequirements: AppDependency[] + id: string, title: string, version: string, serviceRequirements: AppDependency[], installWarning?: string }): InstallWizardComponent['params'] { - const { id, title, version, serviceRequirements } = values + const { id, title, version, serviceRequirements, installWarning } = values validate(id, exists, 'missing id') validate(title, exists, 'missing title') @@ -80,6 +83,9 @@ export class WizardBaker { const toolbar: TopbarParams = { action, title, version } const slideDefinitions: SlideDefinition[] = [ + installWarning ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: { + action, developerNotes: installWarning, + }} : undefined, { selector: 'dependencies', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Downgrade', params: { action, title, version, serviceRequirements, }}, @@ -92,13 +98,13 @@ export class WizardBaker { }), }}, ] - return { toolbar, slideDefinitions } + return { toolbar, slideDefinitions: slideDefinitions.filter(exists) } } uninstall (values: { - id: string, title: string, version: string + id: string, title: string, version: string, uninstallWarning?: string }): InstallWizardComponent['params'] { - const { id, title, version } = values + const { id, title, version, uninstallWarning } = values validate(id, exists, 'missing id') validate(title, exists, 'missing title') @@ -108,6 +114,9 @@ export class WizardBaker { const toolbar: TopbarParams = { action, title, version } const slideDefinitions: SlideDefinition[] = [ + uninstallWarning ? { selector: 'developer-notes', cancelButton: { afterLoading: { text: 'Cancel' } }, nextButton: 'Next', params: { + action, developerNotes: uninstallWarning, + }} : undefined, { selector: 'dependents', cancelButton: { whileLoading: { }, afterLoading: { text: 'Cancel' } }, nextButton: 'Uninstall', params: { action, verb: 'uninstalling', title, fetchBreakages: () => this.apiService.uninstallApp(id, true).then( ({ breakages }) => breakages ), }}, @@ -115,7 +124,7 @@ export class WizardBaker { action, verb: 'uninstalling', title, executeAction: () => this.apiService.uninstallApp(id).then(() => this.appModel.delete(id)), }}, ] - return { toolbar, slideDefinitions } + return { toolbar, slideDefinitions: slideDefinitions.filter(exists) } } stop (values: { diff --git a/ui/src/app/models/app-types.ts b/ui/src/app/models/app-types.ts index 6fd9caab2..d96b7d7d7 100644 --- a/ui/src/app/models/app-types.ts +++ b/ui/src/app/models/app-types.ts @@ -29,6 +29,7 @@ export interface AppAvailableVersionSpecificInfo { releaseNotes: string serviceRequirements: AppDependency[] versionViewing: string + installWarning?: string } // installed @@ -43,6 +44,7 @@ export interface AppInstalledFull extends AppInstalledPreview { lastBackup: string | null configuredRequirements: AppDependency[] | null // null if not yet configured hasFetchedFull: boolean + uninstallWarning?: string } // dependencies diff --git a/ui/src/app/pages/apps-routes/app-available-show/app-available-show.page.ts b/ui/src/app/pages/apps-routes/app-available-show/app-available-show.page.ts index 796421686..589e2c289 100644 --- a/ui/src/app/pages/apps-routes/app-available-show/app-available-show.page.ts +++ b/ui/src/app/pages/apps-routes/app-available-show/app-available-show.page.ts @@ -61,6 +61,8 @@ export class AppAvailableShowPage extends Cleanup { this.appId = this.route.snapshot.paramMap.get('appId') as string this.cleanup( + // new version always includes dependencies, but not vice versa + this.$newVersionLoading$.subscribe(this.$dependenciesLoading$), markAsLoadingDuring$(this.$loading$, from(this.apiService.getAvailableApp(this.appId)).pipe( tap(app => this.$app$ = initPropertySubject(app)), @@ -133,7 +135,7 @@ export class AppAvailableShowPage extends Cleanup { const previousVersion = this.$app$.versionViewing.getValue() this.$app$.versionViewing.next(version) markAsLoadingDuring$( - this.$newVersionLoading$, this.syncVersionSpecificInfo(`=${version}`) + this.$newVersionLoading$, this.syncVersionSpecificInfo(`=${version}`), ) .subscribe({ error: e => { @@ -158,6 +160,7 @@ export class AppAvailableShowPage extends Cleanup { title: app.title, version: app.versionViewing, serviceRequirements: app.serviceRequirements, + installWarning: app.installWarning, }), ) if (cancelled) return @@ -172,6 +175,7 @@ export class AppAvailableShowPage extends Cleanup { title: app.title, version: app.versionViewing, serviceRequirements: app.serviceRequirements, + installWarning: app.installWarning, } switch (action) { diff --git a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts index 8b3341ca4..0e32c75ae 100644 --- a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts +++ b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts @@ -267,6 +267,7 @@ export class AppInstalledShowPage extends Cleanup { id: app.id, title: app.title, version: app.versionInstalled, + uninstallWarning: app.uninstallWarning, }), ) diff --git a/ui/src/app/services/api/mock-api.service.ts b/ui/src/app/services/api/mock-api.service.ts index fbd070445..23052ec95 100644 --- a/ui/src/app/services/api/mock-api.service.ts +++ b/ui/src/app/services/api/mock-api.service.ts @@ -73,6 +73,7 @@ export class MockApiService extends ApiService { } async getAvailableApp (appId: string): Promise { + console.log('getAvilableApp', appId) // throw new Error('Some horrible horrible error message gosh its awful') return mockGetAvailableApp(appId) .then(res => { diff --git a/ui/src/app/services/api/mock-app-fixures.ts b/ui/src/app/services/api/mock-app-fixures.ts index 855f5a647..ded5ffd9a 100644 --- a/ui/src/app/services/api/mock-app-fixures.ts +++ b/ui/src/app/services/api/mock-app-fixures.ts @@ -92,6 +92,7 @@ export const cupsI: AppInstalledFull = { instructions: 'some instructions', lastBackup: new Date().toISOString(), ui: true, + uninstallWarning: 'This is A GREAT APP man, I just don\'t know', configuredRequirements: [ toServiceRequirement(lightningI, { @@ -201,6 +202,7 @@ export const thunderA: AppAvailableFull = { descriptionLong: 'Thunder is an innovative payment network and new kind of money. Thunder utilizes a robust p2p network to garner decentralized consensus.', versions: ['0.8.0', '0.8.1', '1.0.0', '1.0.1'], versionViewing: '1.0.1', + installWarning: 'Oooooh you really might want to think twice about installing this...', serviceRequirements: [ toServiceRequirement(bitcoinA, { optional: null, @@ -275,7 +277,7 @@ export const bitwardenA: AppAvailableFull = { export const mockApiAppAvailableFull: { [appId: string]: AppAvailableFull; } = { bitcoind: bitcoinA, - lightning: lightningA, + 'c-lightning': lightningA, btcPay: btcPayA, thunder: thunderA, cups: cupsA, diff --git a/ui/src/app/util/rxjs.util.ts b/ui/src/app/util/rxjs.util.ts index e4e2a9288..c66fb1299 100644 --- a/ui/src/app/util/rxjs.util.ts +++ b/ui/src/app/util/rxjs.util.ts @@ -1,4 +1,4 @@ -import { Observable, from, interval, race, OperatorFunction, Observer, BehaviorSubject } from 'rxjs' +import { Observable, from, interval, race, OperatorFunction, Observer, BehaviorSubject, Subject } from 'rxjs' import { take, map, switchMap, delay, tap } from 'rxjs/operators' export function fromAsync$ (async: (s: S) => Promise, s: S): Observable