diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts b/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts index a32adb879..1537acfd0 100644 --- a/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts +++ b/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts @@ -141,10 +141,9 @@ export class HomePage { async presentAlertRepairDisk() { const alert = await this.alertCtrl.create({ - header: 'RepairDisk', - message: new IonicSafeString( - `Warning: This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action. If anything happens to the device during the reboot (between the bep and chime), such as loosing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem *will* be in an unrecoverable state. Please proceed with caution.`, - ), + header: 'Warning', + message: + 'This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action. If anything happens to the device during the reboot (between the bep and chime), such as loosing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem *will* be in an unrecoverable state. Please proceed with caution.', buttons: [ { text: 'Cancel', @@ -164,6 +163,7 @@ export class HomePage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() } diff --git a/frontend/projects/marketplace/src/services/marketplace.service.ts b/frontend/projects/marketplace/src/services/marketplace.service.ts index 3db2baabc..7521e5832 100644 --- a/frontend/projects/marketplace/src/services/marketplace.service.ts +++ b/frontend/projects/marketplace/src/services/marketplace.service.ts @@ -3,8 +3,6 @@ import { MarketplacePkg } from '../types/marketplace-pkg' import { Marketplace } from '../types/marketplace' export abstract class AbstractMarketplaceService { - abstract install(id: string, version?: string): Observable - abstract getMarketplace(): Observable abstract getReleaseNotes(id: string): Observable> diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts index f7a13496c..cf6b451f2 100644 --- a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts +++ b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts @@ -100,6 +100,7 @@ export class EmbassyPage { this.presentModalPassword(drive) } }, + cssClass: 'enter-click', }, ], }) diff --git a/frontend/projects/ui/src/app/app/menu/menu.component.ts b/frontend/projects/ui/src/app/app/menu/menu.component.ts index 9d0ad3bde..28229fa45 100644 --- a/frontend/projects/ui/src/app/app/menu/menu.component.ts +++ b/frontend/projects/ui/src/app/app/menu/menu.component.ts @@ -75,8 +75,8 @@ export class MenuComponent { }, { text: 'Logout', - cssClass: 'enter-click', handler: () => this.logout(), + cssClass: 'enter-click', }, ], }) diff --git a/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts b/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts index 4be31b7d9..6aa0de6c7 100644 --- a/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts +++ b/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts @@ -201,17 +201,17 @@ export class AppConfigPage { private async presentAlertBreakages(breakages: Breakages): Promise { let message: string | IonicSafeString = - 'Warning:

As a result of this change, the following services will no longer work properly and may crash:

    ' + 'As a result of this change, the following services will no longer work properly and may crash:
      ' const localPkgs = this.patch.getData()['package-data'] const bullets = Object.keys(breakages).map(id => { const title = localPkgs[id].manifest.title - return `
    • ${title}
    • ` + return `
    • ${title}
    • ` }) message = new IonicSafeString(`${message}${bullets}
    `) return new Promise(async resolve => { const alert = await this.alertCtrl.create({ - header: 'Configure Service', + header: 'Warning', message, buttons: [ { @@ -229,6 +229,7 @@ export class AppConfigPage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts b/frontend/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts index cb1e54da5..ee8da6856 100644 --- a/frontend/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts @@ -147,10 +147,8 @@ export class AppActionsPage { } const alert = await this.alertCtrl.create({ - header: 'Uninstall', - message: new IonicSafeString( - `Warning:

    ${message}

    `, - ), + header: 'Warning', + message, buttons: [ { text: 'Cancel', @@ -164,6 +162,7 @@ export class AppActionsPage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts index 290ca13cc..5cf797676 100644 --- a/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts @@ -113,10 +113,8 @@ export class AppShowStatusComponent { if (message) { const alert = await this.alertCtrl.create({ - header: 'Stop Service', - message: new IonicSafeString( - `Warning:

    ${message}

    `, - ), + header: 'Warning', + message, buttons: [ { text: 'Cancel', @@ -130,6 +128,7 @@ export class AppShowStatusComponent { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() @@ -212,7 +211,7 @@ export class AppShowStatusComponent { private async presentAlertStart(message: string): Promise { return new Promise(async resolve => { const alert = await this.alertCtrl.create({ - header: 'Warning', + header: 'Alert', message, buttons: [ { diff --git a/frontend/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.html b/frontend/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.html index d3b07119e..20ae4efae 100644 --- a/frontend/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.html +++ b/frontend/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.html @@ -10,7 +10,7 @@ { + this.install() + }, + cssClass: 'enter-click', + }, + ], + }) + await alert.present() + } + + private async install() { + const message = 'Beginning Install...' + if (this.loader) { + this.loader.message = message } else { + this.loader = await this.loadingCtrl.create({ message }) + await this.loader.present() + } + + const { id, version } = this.pkg.manifest + + try { + await this.marketplaceService + .installPackage({ + id, + 'version-spec': `=${version}`, + }) + .pipe(first()) + .toPromise() + } catch (e: any) { + this.errToast.present(e) + } finally { + this.loader.dismiss() + } + } + + private async presentAlertBreakages(breakages: Breakages): Promise { + await this.dismissLoader() + + let message: string | IonicSafeString = + 'As a result of this update, the following services will no longer work properly and may crash:
      ' + const localPkgs = this.patch.getData()['package-data'] + const bullets = Object.keys(breakages).map(id => { + const title = localPkgs[id].manifest.title + return `
    • ${title}
    • ` + }) + message = new IonicSafeString(`${message}${bullets}
    `) + + return new Promise(async resolve => { const alert = await this.alertCtrl.create({ - header: title, - subHeader: version, - message: alerts.install, + header: 'Warning', + message, buttons: [ { text: 'Cancel', role: 'cancel', + handler: () => { + resolve(false) + }, }, { - text: 'Install', - handler: () => - this.marketplaceService.install(id, version).subscribe(), + text: 'Continue', + handler: () => { + resolve(true) + }, + cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) + await alert.present() + }) + } + + async dismissLoader() { + if (this.loader) { + await this.loader.dismiss() + this.loader = undefined } } } diff --git a/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts b/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts index 3596f4234..bf098ec71 100644 --- a/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts +++ b/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts @@ -99,10 +99,10 @@ export class NotificationsPage { }, { text: 'Delete', - cssClass: 'enter-click', handler: () => { this.deleteAll() }, + cssClass: 'enter-click', }, ], }) diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.ts b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.ts index ef440895e..89384de6c 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.ts @@ -95,10 +95,9 @@ export class ServerShowPage { async presentAlertShutdown() { const alert = await this.alertCtrl.create({ - header: 'Shutdown', - message: new IonicSafeString( - `Warning:

    Are you sure you want to power down your Embassy? This can take several minutes, and your Embassy will not come back online automatically. To power on again, You will need to physically unplug your Embassy and plug it back in..

    `, - ), + header: 'Warning', + message: + 'Are you sure you want to power down your Embassy? This can take several minutes, and your Embassy will not come back online automatically. To power on again, You will need to physically unplug your Embassy and plug it back in', buttons: [ { text: 'Cancel', @@ -112,6 +111,7 @@ export class ServerShowPage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() } @@ -119,9 +119,9 @@ export class ServerShowPage { async presentAlertSystemRebuild() { const minutes = Object.keys(this.patch.getData()['package-data']).length * 2 const alert = await this.alertCtrl.create({ - header: 'System Rebuild', + header: 'Warning', message: new IonicSafeString( - `Warning: This action will tear down all service containers and rebuild them from scratch. No data will be deleted. This action is useful if your system gets into a bad state, and it should only be performed if you are experiencing general performance or reliability issues. It may take up to ${minutes} minutes to complete. During this time, you will lose all connectivity to your Embassy.`, + `This action will tear down all service containers and rebuild them from scratch. No data will be deleted. This action is useful if your system gets into a bad state, and it should only be performed if you are experiencing general performance or reliability issues. It may take up to ${minutes} minutes to complete. During this time, you will lose all connectivity to your Embassy.`, ), buttons: [ { @@ -136,15 +136,16 @@ export class ServerShowPage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() } async presentAlertRepairDisk() { const alert = await this.alertCtrl.create({ - header: 'Repair Disk', + header: 'Warning', message: new IonicSafeString( - `Warning:

    This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action.

    If anything happens to the device during the reboot (between the bep and chime), such as loosing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem *will* be in an unrecoverable state. Please proceed with caution.

    `, + `

    This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action.

    If anything happens to the device during the reboot (between the bep and chime), such as loosing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem will be in an unrecoverable state. Please proceed with caution.

    `, ), buttons: [ { @@ -165,6 +166,7 @@ export class ServerShowPage { cssClass: 'enter-click', }, ], + cssClass: 'alert-warning-message', }) await alert.present() } diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/frontend/projects/ui/src/app/services/api/api.fixures.ts index 316e2092d..b5d927c64 100644 --- a/frontend/projects/ui/src/app/services/api/api.fixures.ts +++ b/frontend/projects/ui/src/app/services/api/api.fixures.ts @@ -501,7 +501,7 @@ export module Mock { 'marketing-site': '', 'donation-url': 'https://start9.com', alerts: { - install: null, + install: 'Testing install alert', uninstall: null, restore: null, start: null, diff --git a/frontend/projects/ui/src/app/services/api/api.types.ts b/frontend/projects/ui/src/app/services/api/api.types.ts index 0199405a0..4f23af82d 100644 --- a/frontend/projects/ui/src/app/services/api/api.types.ts +++ b/frontend/projects/ui/src/app/services/api/api.types.ts @@ -184,6 +184,9 @@ export module RR { }> // package.install export type InstallPackageRes = WithRevision + export type DryUpdatePackageReq = { id: string; version: string } // package.update.dry + export type DryUpdatePackageRes = Breakages + export type GetPackageConfigReq = { id: string } // package.config.get export type GetPackageConfigRes = { spec: ConfigSpec; config: object } diff --git a/frontend/projects/ui/src/app/services/api/embassy-api.service.ts b/frontend/projects/ui/src/app/services/api/embassy-api.service.ts index 4932eb832..05a5ca1c6 100644 --- a/frontend/projects/ui/src/app/services/api/embassy-api.service.ts +++ b/frontend/projects/ui/src/app/services/api/embassy-api.service.ts @@ -199,6 +199,10 @@ export abstract class ApiService implements Source, Http { installPackage = (params: RR.InstallPackageReq) => this.syncResponse(() => this.installPackageRaw(params))() + abstract dryUpdatePackage( + params: RR.DryUpdatePackageReq, + ): Promise + abstract getPackageConfig( params: RR.GetPackageConfigReq, ): Promise diff --git a/frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts b/frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts index 84be24839..69f61ef37 100644 --- a/frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts +++ b/frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts @@ -264,6 +264,12 @@ export class LiveApiService extends ApiService { return this.http.rpcRequest({ method: 'package.install', params }) } + async dryUpdatePackage( + params: RR.DryUpdatePackageReq, + ): Promise { + return this.http.rpcRequest({ method: 'package.update.dry', params }) + } + async getPackageConfig( params: RR.GetPackageConfigReq, ): Promise { diff --git a/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts index 88965a04a..0c859a621 100644 --- a/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts @@ -4,6 +4,7 @@ import { ApiService } from './embassy-api.service' import { PatchOp, Update, Operation, RemoveOperation } from 'patch-db-client' import { DataModel, + DependencyErrorType, InstallProgress, PackageDataEntry, PackageMainStatus, @@ -496,6 +497,22 @@ export class MockApiService extends ApiService { return this.withRevision(patch) } + async dryUpdatePackage( + params: RR.DryUpdatePackageReq, + ): Promise { + await pauseFor(2000) + return { + lnd: { + dependency: 'bitcoind', + error: { + type: DependencyErrorType.IncorrectVersion, + expected: '>0.23.0', + received: params.version, + }, + }, + } + } + async getPackageConfig( params: RR.GetPackageConfigReq, ): Promise { diff --git a/frontend/projects/ui/src/app/services/marketplace.service.ts b/frontend/projects/ui/src/app/services/marketplace.service.ts index bea67321c..8088a26e2 100644 --- a/frontend/projects/ui/src/app/services/marketplace.service.ts +++ b/frontend/projects/ui/src/app/services/marketplace.service.ts @@ -145,27 +145,6 @@ export class MarketplaceService extends AbstractMarketplaceService { ) } - install(id: string, version?: string): Observable { - return defer(() => - from( - this.loadingCtrl.create({ - message: 'Beginning Installation...', - }), - ), - ).pipe( - tap(loader => loader.present()), - switchMap(loader => - this.installPackage({ - id, - 'version-spec': version ? `=${version}` : undefined, - }).pipe( - catchError(e => from(this.errToast.present(e))), - tap(() => loader.dismiss()), - ), - ), - ) - } - installPackage( req: Omit, ): Observable { diff --git a/frontend/projects/ui/src/app/util/has-deps.ts b/frontend/projects/ui/src/app/util/has-deps.ts index 9741b457a..115a09292 100644 --- a/frontend/projects/ui/src/app/util/has-deps.ts +++ b/frontend/projects/ui/src/app/util/has-deps.ts @@ -1,6 +1,6 @@ import { PackageDataEntry } from '../services/patch-db/data-model' -export function hasCurrentDeps(pkg: PackageDataEntry) { +export function hasCurrentDeps(pkg: PackageDataEntry): boolean { return !!Object.keys(pkg.installed?.['current-dependents'] || {}) // @TODO fix Manifest type .filter(depId => depId !== (pkg.manifest as any).id).length diff --git a/frontend/projects/ui/src/styles.scss b/frontend/projects/ui/src/styles.scss index 70250ed65..2a2f262d0 100644 --- a/frontend/projects/ui/src/styles.scss +++ b/frontend/projects/ui/src/styles.scss @@ -205,6 +205,12 @@ ion-button { } } +.alert-warning-message { + .alert-title { + color: var(--ion-color-warning); + } +} + .alert-success-message { .alert-title { color: var(--ion-color-success);