diff --git a/ui/src/app/pages/apps-routes/app-show/app-show.page.ts b/ui/src/app/pages/apps-routes/app-show/app-show.page.ts index f225b5e77..1d96082dc 100644 --- a/ui/src/app/pages/apps-routes/app-show/app-show.page.ts +++ b/ui/src/app/pages/apps-routes/app-show/app-show.page.ts @@ -42,7 +42,7 @@ export class AppShowPage { } = { } as any connectionFailure: boolean loading = true - healthChecks: { [id: string]: HealthCheckResult } + healthChecks: { [id: string]: HealthCheckResult } = { } installProgress: ProgressData @ViewChild(IonContent) content: IonContent @@ -80,18 +80,17 @@ export class AppShowPage { this.installProgress = !isEmptyObject(pkg['install-progress']) ? this.packageLoadingService.transform(pkg['install-progress']) : undefined this.statuses = renderPkgStatus(pkg) - // health - if (this.pkg.installed?.status.main.status === PackageMainStatus.Running) { - this.healthChecks = { ...this.pkg.installed.status.main.health } - } else { - this.healthChecks = { } - } + const installed = pkg.installed - // dependencies - if (!pkg.installed) { - this.dependencies = { } - } else { - const currentDeps = pkg.installed['current-dependencies'] + if (!!installed) { + // health + if (installed.status.main.status === PackageMainStatus.Running) { + this.healthChecks = { ...installed.status.main.health } + } else { + this.healthChecks = { } + } + // dependencies + const currentDeps = installed['current-dependencies'] Object.keys(currentDeps).forEach(key => { const manifestDep = pkg.manifest.dependencies[key] if (!this.dependencies[key] && manifestDep) { @@ -243,7 +242,7 @@ export class AppShowPage { // config unsatisfied } else if (error.type === DependencyErrorType.ConfigUnsatisfied) { errorText = 'Config not satisfied' - actionText = 'Auto Config' + actionText = 'Auto config' action = () => this.fixDep('configure', id) } else if (error.type === DependencyErrorType.Transitive) { errorText = 'Dependency has a dependency issue' @@ -254,8 +253,6 @@ export class AppShowPage { } } - if (!this.dependencies[id]) this.dependencies[id] = { } as any - const depInfo = this.pkg.installed['dependency-info'][id] this.dependencies[id].title = depInfo.manifest.title @@ -287,16 +284,11 @@ export class AppShowPage { } private async configureDep (depId: string): Promise { - const configErrors = (this.pkg.installed.status['dependency-errors'][depId] as DependencyErrorConfigUnsatisfied).errors - - const description = `` - const dependentTitle = this.pkg.manifest.title - const configRecommendation: Recommendation = { dependentId: this.pkgId, - dependentTitle, + dependentTitle: this.pkg.manifest.title, dependentIcon: this.pkg['static-files'].icon, - description, + description: (this.pkg.installed.status['dependency-errors'][depId] as DependencyErrorConfigUnsatisfied).error, } const params = { pkgId: depId, @@ -352,7 +344,7 @@ export class AppShowPage { { action: () => this.navCtrl.navigateForward(['instructions'], { relativeTo: this.route }), title: 'Instructions', - description: '', + description: `Understand how to use ${pkgTitle}`, icon: 'list-outline', color: 'danger', }, @@ -400,7 +392,7 @@ export class AppShowPage { { action: () => this.navCtrl.navigateForward(['logs'], { relativeTo: this.route }), title: 'Logs', - description: '', + description: 'Raw, unfiltered service logs', icon: 'receipt-outline', color: 'danger', }, diff --git a/ui/src/app/pages/server-routes/preferences/preferences.page.html b/ui/src/app/pages/server-routes/preferences/preferences.page.html index dfb0dade0..0e2dfcf64 100644 --- a/ui/src/app/pages/server-routes/preferences/preferences.page.html +++ b/ui/src/app/pages/server-routes/preferences/preferences.page.html @@ -9,11 +9,33 @@ - + + General {{ fields['name'].name }} {{ patch.data.ui.name || defaultName }} + + + Auto Report Bugs + {{ server['share-stats'] ? 'Enabled' : 'Disabled' }} + + + + + Marketplace + + Auto Check for Updates + {{ patch.data.ui['auto-check-updates'] ? 'Enabled' : 'Disabled' }} + + + \ No newline at end of file diff --git a/ui/src/app/pages/server-routes/preferences/preferences.page.ts b/ui/src/app/pages/server-routes/preferences/preferences.page.ts index 270dad06f..9ea070ed4 100644 --- a/ui/src/app/pages/server-routes/preferences/preferences.page.ts +++ b/ui/src/app/pages/server-routes/preferences/preferences.page.ts @@ -4,7 +4,7 @@ import { IonContent, ModalController } from '@ionic/angular' import { GenericInputComponent } from 'src/app/modals/generic-input/generic-input.component' import { ConfigSpec } from 'src/app/pkg-config/config-types' import { ApiService } from 'src/app/services/api/embassy-api.service' -import { ErrorToastService } from 'src/app/services/error-toast.service' +import { ServerConfigService } from 'src/app/services/server-config.service' @Component({ selector: 'preferences', @@ -19,6 +19,7 @@ export class PreferencesPage { constructor ( private readonly modalCtrl: ModalController, private readonly api: ApiService, + public readonly serverConfig: ServerConfigService, public readonly patch: PatchDbService, ) { } diff --git a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.module.ts b/ui/src/app/pages/server-routes/security-routes/security-options/security-options.module.ts deleted file mode 100644 index 412442d43..000000000 --- a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from '@angular/core' -import { CommonModule } from '@angular/common' -import { IonicModule } from '@ionic/angular' -import { SecurityOptionsPage } from './security-options.page' -import { Routes, RouterModule } from '@angular/router' -import { SharingModule } from 'src/app/modules/sharing.module' - -const routes: Routes = [ - { - path: '', - component: SecurityOptionsPage, - }, -] - -@NgModule({ - imports: [ - CommonModule, - IonicModule, - RouterModule.forChild(routes), - SharingModule, - ], - declarations: [ - SecurityOptionsPage, - ], -}) -export class SecurityOptionsPageModule { } diff --git a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.html b/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.html deleted file mode 100644 index 9269969fd..000000000 --- a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - Privacy and Security - - - - - - - General - - Report Bugs - {{ server['share-stats'] ? 'Enabled' : 'Disabled' }} - - - Marketplace - - Auto Check for Updates - {{ patch.data.ui['auto-check-updates'] ? 'Enabled' : 'Disabled' }} - - - - Security - - - SSH Keys - - - Active Sessions - - - - \ No newline at end of file diff --git a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.scss b/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.ts b/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.ts deleted file mode 100644 index 9dfe91290..000000000 --- a/ui/src/app/pages/server-routes/security-routes/security-options/security-options.page.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, ViewChild } from '@angular/core' -import { ServerConfigService } from 'src/app/services/server-config.service' -import { PatchDbService } from 'src/app/services/patch-db/patch-db.service' -import { ConfigService } from 'src/app/services/config.service' -import { IonContent } from '@ionic/angular' - -@Component({ - selector: 'security-options', - templateUrl: './security-options.page.html', - styleUrls: ['./security-options.page.scss'], -}) -export class SecurityOptionsPage { - @ViewChild(IonContent) content: IonContent - - constructor ( - public readonly serverConfig: ServerConfigService, - public readonly config: ConfigService, - public readonly patch: PatchDbService, - ) { } - - ngAfterViewInit () { - this.content.scrollToPoint(undefined, 1) - } -} diff --git a/ui/src/app/pages/server-routes/security-routes/security-routing.module.ts b/ui/src/app/pages/server-routes/security-routes/security-routing.module.ts deleted file mode 100644 index 8bcccafd8..000000000 --- a/ui/src/app/pages/server-routes/security-routes/security-routing.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { NgModule } from '@angular/core' -import { Routes, RouterModule } from '@angular/router' - -const routes: Routes = [ - { - path: '', - loadChildren: () => import('./security-options/security-options.module').then(m => m.SecurityOptionsPageModule), - }, - { - path: 'sessions', - loadChildren: () => import('./sessions/sessions.module').then(m => m.SessionsPageModule), - }, - { - path: 'ssh-keys', - loadChildren: () => import('./ssh-keys/ssh-keys.module').then(m => m.SSHKeysPageModule), - }, -] - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], -}) -export class SecurityRoutingModule { } \ No newline at end of file diff --git a/ui/src/app/pages/server-routes/server-routing.module.ts b/ui/src/app/pages/server-routes/server-routing.module.ts index 56791ac53..d7fdc9856 100644 --- a/ui/src/app/pages/server-routes/server-routing.module.ts +++ b/ui/src/app/pages/server-routes/server-routing.module.ts @@ -11,33 +11,37 @@ const routes: Routes = [ loadChildren: () => import('./server-backup/server-backup.module').then(m => m.ServerBackupPageModule), }, { - path: 'specs', - loadChildren: () => import('./server-specs/server-specs.module').then(m => m.ServerSpecsPageModule), - }, - { - path: 'metrics', - loadChildren: () => import('./server-metrics/server-metrics.module').then(m => m.ServerMetricsPageModule), + path: 'lan', + loadChildren: () => import('./lan/lan.module').then(m => m.LANPageModule), }, { path: 'logs', loadChildren: () => import('./server-logs/server-logs.module').then(m => m.ServerLogsPageModule), }, { - path: 'wifi', - loadChildren: () => import('./wifi/wifi.module').then(m => m.WifiPageModule), - }, - { - path: 'lan', - loadChildren: () => import('./lan/lan.module').then(m => m.LANPageModule), - }, - { - path: 'security', - loadChildren: () => import('./security-routes/security-routing.module').then( m => m.SecurityRoutingModule), + path: 'metrics', + loadChildren: () => import('./server-metrics/server-metrics.module').then(m => m.ServerMetricsPageModule), }, { path: 'preferences', loadChildren: () => import('./preferences/preferences.module').then( m => m.PreferencesPageModule), }, + { + path: 'sessions', + loadChildren: () => import('./sessions/sessions.module').then( m => m.SessionsPageModule), + }, + { + path: 'specs', + loadChildren: () => import('./server-specs/server-specs.module').then(m => m.ServerSpecsPageModule), + }, + { + path: 'ssh', + loadChildren: () => import('./ssh-keys/ssh-keys.module').then( m => m.SSHKeysPageModule), + }, + { + path: 'wifi', + loadChildren: () => import('./wifi/wifi.module').then(m => m.WifiPageModule), + }, ] @NgModule({ diff --git a/ui/src/app/pages/server-routes/server-show/server-show.page.html b/ui/src/app/pages/server-routes/server-show/server-show.page.html index e2d010f5d..1a7ff122b 100644 --- a/ui/src/app/pages/server-routes/server-show/server-show.page.html +++ b/ui/src/app/pages/server-routes/server-show/server-show.page.html @@ -13,7 +13,10 @@ {{ cat.key }} - {{ button.title }} + +

{{ button.title }}

+

{{ button.description }}

+
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 36b1e8820..b8f50a6ab 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 @@ -108,66 +108,83 @@ export class ServerShowPage { 'Backups': [ { title: 'Create Backup', + description: 'Back up your Embassy and all its services', icon: 'save-outline', action: () => this.navCtrl.navigateForward(['backup'], { relativeTo: this.route }), detail: true, }, ], - 'Settings': [ - { - title: 'Preferences', - icon: 'options-outline', - action: () => this.navCtrl.navigateForward(['preferences'], { relativeTo: this.route }), - detail: true, - }, - { - title: 'Privacy and Security', - icon: 'shield-checkmark-outline', - action: () => this.navCtrl.navigateForward(['security'], { relativeTo: this.route }), - detail: true, - }, - { - title: 'LAN', - icon: 'home-outline', - action: () => this.navCtrl.navigateForward(['lan'], { relativeTo: this.route }), - detail: true, - }, - { - title: 'WiFi', - icon: 'wifi', - action: () => this.navCtrl.navigateForward(['wifi'], { relativeTo: this.route }), - detail: true, - }, - ], 'Insights': [ { title: 'About', + description: 'Basic information about your Embassy', icon: 'information-circle-outline', action: () => this.navCtrl.navigateForward(['specs'], { relativeTo: this.route }), detail: true, }, { title: 'Monitor', + description: 'CPU, disk, memory, and other useful metrics', icon: 'pulse', action: () => this.navCtrl.navigateForward(['metrics'], { relativeTo: this.route }), detail: true, }, { title: 'Logs', + description: 'Raw, unfiltered device logs', icon: 'newspaper-outline', action: () => this.navCtrl.navigateForward(['logs'], { relativeTo: this.route }), detail: true, }, ], + 'Settings': [ + { + title: 'Preferences', + description: 'Device name, background tasks', + icon: 'options-outline', + action: () => this.navCtrl.navigateForward(['preferences'], { relativeTo: this.route }), + detail: true, + }, + { + title: 'LAN', + description: 'Access your Embassy on the Local Area Network', + icon: 'home-outline', + action: () => this.navCtrl.navigateForward(['lan'], { relativeTo: this.route }), + detail: true, + }, + { + title: 'SSH', + description: 'Access your Embassy from the command line', + icon: 'terminal-outline', + action: () => this.navCtrl.navigateForward(['ssh'], { relativeTo: this.route }), + detail: true, + }, + { + title: 'WiFi', + description: 'Add or remove WiFi networks', + icon: 'wifi', + action: () => this.navCtrl.navigateForward(['wifi'], { relativeTo: this.route }), + detail: true, + }, + { + title: 'Active Sessions', + description: 'View and manage device access', + icon: 'desktop-outline', + action: () => this.navCtrl.navigateForward(['sessions'], { relativeTo: this.route }), + detail: true, + }, + ], 'Power': [ { title: 'Restart', + description: '', icon: 'reload', action: () => this.presentAlertRestart(), detail: false, }, { title: 'Shutdown', + description: '', icon: 'power', action: () => this.presentAlertShutdown(), detail: false, @@ -184,6 +201,7 @@ export class ServerShowPage { interface ServerSettings { [key: string]: { title: string + description: string icon: string action: Function detail: boolean diff --git a/ui/src/app/pages/server-routes/security-routes/sessions/sessions.module.ts b/ui/src/app/pages/server-routes/sessions/sessions.module.ts similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/sessions/sessions.module.ts rename to ui/src/app/pages/server-routes/sessions/sessions.module.ts diff --git a/ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.html b/ui/src/app/pages/server-routes/sessions/sessions.page.html similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.html rename to ui/src/app/pages/server-routes/sessions/sessions.page.html diff --git a/ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.scss b/ui/src/app/pages/server-routes/sessions/sessions.page.scss similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.scss rename to ui/src/app/pages/server-routes/sessions/sessions.page.scss diff --git a/ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.ts b/ui/src/app/pages/server-routes/sessions/sessions.page.ts similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/sessions/sessions.page.ts rename to ui/src/app/pages/server-routes/sessions/sessions.page.ts diff --git a/ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.module.ts b/ui/src/app/pages/server-routes/ssh-keys/ssh-keys.module.ts similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.module.ts rename to ui/src/app/pages/server-routes/ssh-keys/ssh-keys.module.ts diff --git a/ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.html b/ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.html similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.html rename to ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.html diff --git a/ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.scss b/ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.scss similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.scss rename to ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.scss diff --git a/ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.ts b/ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.ts similarity index 100% rename from ui/src/app/pages/server-routes/security-routes/ssh-keys/ssh-keys.page.ts rename to ui/src/app/pages/server-routes/ssh-keys/ssh-keys.page.ts diff --git a/ui/src/app/services/api/api.types.ts b/ui/src/app/services/api/api.types.ts index 1e861774c..b41975a85 100644 --- a/ui/src/app/services/api/api.types.ts +++ b/ui/src/app/services/api/api.types.ts @@ -34,7 +34,7 @@ export module RR { export type GetServerMetricsRes = Metrics export type UpdateServerReq = WithExpire<{ }> // server.update - export type UpdateServerRes = WithRevision + export type UpdateServerRes = WithRevision<'updating' | 'no-updates'> export type RestartServerReq = { } // server.restart export type RestartServerRes = null diff --git a/ui/src/app/services/api/embassy-api.service.ts b/ui/src/app/services/api/embassy-api.service.ts index c99c1c901..6cc9c53e6 100644 --- a/ui/src/app/services/api/embassy-api.service.ts +++ b/ui/src/app/services/api/embassy-api.service.ts @@ -54,8 +54,15 @@ export abstract class ApiService implements Source, Http { protected abstract updateServerRaw (params: RR.UpdateServerReq): Promise updateServer = (params: RR.UpdateServerReq) => this.syncResponse( - () => this.updateServerRaw(params), + () => this.updateServerWrapper(params), )() + async updateServerWrapper (params: RR.UpdateServerReq) { + const res = await this.updateServerRaw(params) + if (res.response === 'no-updates') { + throw new Error('Could ont find a newer version of EmbassyOS') + } + return res + } abstract restartServer (params: RR.UpdateServerReq): Promise diff --git a/ui/src/app/services/api/embassy-mock-api.service.ts b/ui/src/app/services/api/embassy-mock-api.service.ts index de1c6383a..3c7650e7a 100644 --- a/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/ui/src/app/services/api/embassy-mock-api.service.ts @@ -118,9 +118,11 @@ export class MockApiService extends ApiService { value: initialProgress, }, ] - const res = await this.http.rpcRequest>({ method: 'db.patch', params: { patch } }) + const res = await this.http.rpcRequest({ method: 'db.patch', params: { patch } }) + res.response = 'updating' this.updateOSProgress(initialProgress.size) + return res } diff --git a/ui/src/app/services/global-error-handler.service.ts b/ui/src/app/services/global-error-handler.service.ts index ac0bb9824..1c3475d28 100644 --- a/ui/src/app/services/global-error-handler.service.ts +++ b/ui/src/app/services/global-error-handler.service.ts @@ -3,10 +3,11 @@ import { ErrorHandler, Injectable } from '@angular/core' @Injectable() export class GlobalErrorHandler implements ErrorHandler { - handleError (error: any): void { - const chunkFailedMessage = /Loading chunk [\d]+ failed/ + handleError (e: any): void { + console.error(e) + const chunkFailedMessage = /Loading chunk [\d]+ failed/ - if (chunkFailedMessage.test(error.message)) { + if (chunkFailedMessage.test(e.message)) { window.location.reload() } } diff --git a/ui/src/app/services/patch-db/data-model.ts b/ui/src/app/services/patch-db/data-model.ts index 5413b1272..9107d5168 100644 --- a/ui/src/app/services/patch-db/data-model.ts +++ b/ui/src/app/services/patch-db/data-model.ts @@ -334,7 +334,7 @@ export interface DependencyErrorIncorrectVersion { export interface DependencyErrorConfigUnsatisfied { type: DependencyErrorType.ConfigUnsatisfied - errors: string[] + error: string } export interface DependencyErrorHealthChecksFailed {