diff --git a/frontend/projects/ui/src/app/app.component.html b/frontend/projects/ui/src/app/app.component.html index 34c3353bb..0c2f60ec4 100644 --- a/frontend/projects/ui/src/app/app.component.html +++ b/frontend/projects/ui/src/app/app.component.html @@ -18,5 +18,10 @@ + + + diff --git a/frontend/projects/ui/src/app/app.component.ts b/frontend/projects/ui/src/app/app.component.ts index 6789c4808..5c0058149 100644 --- a/frontend/projects/ui/src/app/app.component.ts +++ b/frontend/projects/ui/src/app/app.component.ts @@ -12,6 +12,7 @@ import { PatchMonitorService } from './services/patch-monitor.service' }) export class AppComponent implements OnDestroy { readonly subscription = merge(this.patchData, this.patchMonitor).subscribe() + readonly sidebarOpen$ = this.splitPane.sidebarOpen$ constructor( private readonly patchData: PatchDataService, diff --git a/frontend/projects/ui/src/app/app.module.ts b/frontend/projects/ui/src/app/app.module.ts index 3e7fcc635..47afeec88 100644 --- a/frontend/projects/ui/src/app/app.module.ts +++ b/frontend/projects/ui/src/app/app.module.ts @@ -19,6 +19,7 @@ import { EnterModule } from './app/enter/enter.module' import { APP_PROVIDERS } from './app.providers' import { PatchDbModule } from './services/patch-db/patch-db.module' import { ToastContainerModule } from './components/toast-container/toast-container.module' +import { ConnectionBarComponentModule } from './components/connection-bar/connection-bar.component.module' @NgModule({ declarations: [AppComponent], @@ -47,6 +48,7 @@ import { ToastContainerModule } from './components/toast-container/toast-contain MarketplaceModule, PatchDbModule, ToastContainerModule, + ConnectionBarComponentModule, ], providers: APP_PROVIDERS, bootstrap: [AppComponent], diff --git a/frontend/projects/ui/src/app/app/menu/menu.component.html b/frontend/projects/ui/src/app/app/menu/menu.component.html index 0351745f4..3bfd04d58 100644 --- a/frontend/projects/ui/src/app/app/menu/menu.component.html +++ b/frontend/projects/ui/src/app/app/menu/menu.component.html @@ -49,6 +49,7 @@ + -
-
- - - -

Log Out

-   - -
-
-
-
+ + + diff --git a/frontend/projects/ui/src/app/app/menu/menu.component.scss b/frontend/projects/ui/src/app/app/menu/menu.component.scss index 7e921edcb..ebbeb134a 100644 --- a/frontend/projects/ui/src/app/app/menu/menu.component.scss +++ b/frontend/projects/ui/src/app/app/menu/menu.component.scss @@ -27,8 +27,8 @@ .snek { position: absolute; - bottom: 90px; - left: 20px; + bottom: 56px; + right: 20px; width: 20px; cursor: pointer; } @@ -36,8 +36,4 @@ .bottom { position: absolute; bottom: 0; - right: 0; - width: 100%; - height: 75px; - text-align: center; } 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 4f6bc8c30..0e0ec1f52 100644 --- a/frontend/projects/ui/src/app/app/menu/menu.component.ts +++ b/frontend/projects/ui/src/app/app/menu/menu.component.ts @@ -1,9 +1,6 @@ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core' -import { AlertController } from '@ionic/angular' import { LocalStorageService } from '../../services/local-storage.service' import { EOSService } from '../../services/eos.service' -import { ApiService } from '../../services/api/embassy-api.service' -import { AuthService } from '../../services/auth.service' import { PatchDbService } from '../../services/patch-db/patch-db.service' import { Observable } from 'rxjs' import { map } from 'rxjs/operators' @@ -61,40 +58,10 @@ export class MenuComponent { .pipe(map(pkgs => pkgs.length)) constructor( - private readonly alertCtrl: AlertController, - private readonly embassyApi: ApiService, - private readonly authService: AuthService, private readonly patch: PatchDbService, private readonly localStorageService: LocalStorageService, private readonly eosService: EOSService, @Inject(AbstractMarketplaceService) private readonly marketplaceService: MarketplaceService, ) {} - - async presentAlertLogout() { - const alert = await this.alertCtrl.create({ - header: 'Caution', - message: - 'Do you know your password? If you log out and forget your password, you may permanently lose access to your Embassy.', - buttons: [ - { - text: 'Cancel', - role: 'cancel', - }, - { - text: 'Logout', - handler: () => this.logout(), - cssClass: 'enter-click', - }, - ], - }) - - await alert.present() - } - - // should wipe cache independent of actual BE logout - private logout() { - this.embassyApi.logout({}).catch(e => console.error('Failed to log out', e)) - this.authService.setUnverified() - } } diff --git a/frontend/projects/ui/src/app/app/menu/menu.module.ts b/frontend/projects/ui/src/app/app/menu/menu.module.ts index 0dc074849..8797309fe 100644 --- a/frontend/projects/ui/src/app/app/menu/menu.module.ts +++ b/frontend/projects/ui/src/app/app/menu/menu.module.ts @@ -4,9 +4,16 @@ import { RouterModule } from '@angular/router' import { IonicModule } from '@ionic/angular' import { MenuComponent } from './menu.component' import { SnekModule } from '../snek/snek.module' +import { ConnectionBarComponentModule } from 'src/app/components/connection-bar/connection-bar.component.module' @NgModule({ - imports: [CommonModule, IonicModule, RouterModule, SnekModule], + imports: [ + CommonModule, + IonicModule, + RouterModule, + SnekModule, + ConnectionBarComponentModule, + ], declarations: [MenuComponent], exports: [MenuComponent], }) diff --git a/frontend/projects/ui/src/app/app/preloader/preloader.component.ts b/frontend/projects/ui/src/app/app/preloader/preloader.component.ts index 8af7336b6..60919b738 100644 --- a/frontend/projects/ui/src/app/app/preloader/preloader.component.ts +++ b/frontend/projects/ui/src/app/app/preloader/preloader.component.ts @@ -19,6 +19,7 @@ const ICONS = [ 'chevron-forward', 'close', 'cloud-outline', + 'cloud-done', 'cloud-done-outline', 'cloud-download-outline', 'cloud-offline-outline', diff --git a/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.html b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.html new file mode 100644 index 000000000..b7597dfa1 --- /dev/null +++ b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.html @@ -0,0 +1,21 @@ + +
+ +

{{ connection.message }}

+ +
+
diff --git a/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.module.ts b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.module.ts new file mode 100644 index 000000000..c67816642 --- /dev/null +++ b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { ConnectionBarComponent } from './connection-bar.component' + +@NgModule({ + declarations: [ConnectionBarComponent], + imports: [CommonModule, IonicModule], + exports: [ConnectionBarComponent], +}) +export class ConnectionBarComponentModule {} diff --git a/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.scss b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.scss new file mode 100644 index 000000000..1f9826193 --- /dev/null +++ b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.scss @@ -0,0 +1,9 @@ +.connection-toolbar { + padding: 0 24px; + --min-height: 36px; +} + +.icon { + font-size: 23px; + padding-right: 12px; +} \ No newline at end of file diff --git a/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.ts b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.ts new file mode 100644 index 000000000..dd1274b03 --- /dev/null +++ b/frontend/projects/ui/src/app/components/connection-bar/connection-bar.component.ts @@ -0,0 +1,53 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { combineLatest, map, Observable, startWith, tap } from 'rxjs' +import { ConnectionService } from 'src/app/services/connection.service' +import { PatchDbService } from 'src/app/services/patch-db/patch-db.service' + +@Component({ + selector: 'connection-bar', + templateUrl: './connection-bar.component.html', + styleUrls: ['./connection-bar.component.scss'], + // changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ConnectionBarComponent { + private readonly websocket$ = this.connectionService.websocketConnected$ + + readonly connection$: Observable<{ + message: string + icon: string + color: string + dots: boolean + }> = combineLatest([ + this.connectionService.networkConnected$, + this.websocket$, + ]).pipe( + map(([network, websocket]) => { + if (!network) + return { + message: 'No Internet', + icon: 'cloud-offline-outline', + color: 'dark', + dots: false, + } + if (!websocket) + return { + message: 'Connecting', + icon: 'cloud-offline-outline', + color: 'warning', + dots: true, + } + + return { + message: 'Connected', + icon: 'cloud-done', + color: 'success', + dots: false, + } + }), + ) + + constructor( + private readonly connectionService: ConnectionService, + private readonly patch: PatchDbService, + ) {} +} diff --git a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.html b/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.html deleted file mode 100644 index 2da6d6039..000000000 --- a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - {{ content.message }} - - - View solutions - - diff --git a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.ts b/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.ts deleted file mode 100644 index 497e763bd..000000000 --- a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ChangeDetectionStrategy, Component, Inject } from '@angular/core' -import { Observable, Subject, merge, tap, map } from 'rxjs' - -import { OfflineMessage, OfflineToastService } from './offline-toast.service' - -@Component({ - selector: 'offline-toast', - templateUrl: './offline-toast.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class OfflineToastComponent { - private readonly dismiss$ = new Subject() - - readonly content$ = merge(this.dismiss$, this.failure$) - - constructor( - @Inject(OfflineToastService) - private readonly failure$: Observable, - ) {} - - onDismiss() { - this.dismiss$.next(null) - } -} diff --git a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.service.ts b/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.service.ts deleted file mode 100644 index 97178c339..000000000 --- a/frontend/projects/ui/src/app/components/toast-container/offline-toast/offline-toast.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from '@angular/core' -import { combineLatest, Observable, of } from 'rxjs' -import { map, switchMap } from 'rxjs/operators' -import { AuthService } from 'src/app/services/auth.service' -import { ConnectionService } from 'src/app/services/connection.service' - -export interface OfflineMessage { - readonly message: string - readonly link?: string -} - -// Watch for connection status -@Injectable({ providedIn: 'root' }) -export class OfflineToastService extends Observable { - private readonly stream$ = this.authService.isVerified$.pipe( - switchMap(verified => (verified ? this.failure$ : of(null))), - ) - - private readonly failure$ = combineLatest([ - this.connectionService.networkConnected$, - this.connectionService.websocketConnected$, - ]).pipe( - map(([network, websocket]) => { - if (!network) return { message: 'No Internet' } - if (!websocket) - return { - message: 'Connecting to Embassy...', - link: 'https://start9.com/latest/support/common-issues', - } - return null - }), - ) - - constructor( - private readonly authService: AuthService, - private readonly connectionService: ConnectionService, - ) { - super(subscriber => this.stream$.subscribe(subscriber)) - } -} diff --git a/frontend/projects/ui/src/app/components/toast-container/toast-container.component.html b/frontend/projects/ui/src/app/components/toast-container/toast-container.component.html index d475b1947..3b7ca2cf1 100644 --- a/frontend/projects/ui/src/app/components/toast-container/toast-container.component.html +++ b/frontend/projects/ui/src/app/components/toast-container/toast-container.component.html @@ -1,4 +1,3 @@ - diff --git a/frontend/projects/ui/src/app/components/toast-container/toast-container.module.ts b/frontend/projects/ui/src/app/components/toast-container/toast-container.module.ts index 0003cc51f..e23fcc454 100644 --- a/frontend/projects/ui/src/app/components/toast-container/toast-container.module.ts +++ b/frontend/projects/ui/src/app/components/toast-container/toast-container.module.ts @@ -5,7 +5,6 @@ import { AlertModule, ToastModule } from '@start9labs/shared' import { ToastContainerComponent } from './toast-container.component' import { NotificationsToastComponent } from './notifications-toast/notifications-toast.component' -import { OfflineToastComponent } from './offline-toast/offline-toast.component' import { RefreshAlertComponent } from './refresh-alert/refresh-alert.component' import { UpdateToastComponent } from './update-toast/update-toast.component' @@ -14,7 +13,6 @@ import { UpdateToastComponent } from './update-toast/update-toast.component' declarations: [ ToastContainerComponent, NotificationsToastComponent, - OfflineToastComponent, RefreshAlertComponent, UpdateToastComponent, ], 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 b731186c9..4ea359297 100644 --- a/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts +++ b/frontend/projects/ui/src/app/pages/notifications/notifications.page.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' +import { Component } from '@angular/core' import { ApiService } from 'src/app/services/api/embassy-api.service' import { ServerNotifications, diff --git a/frontend/projects/ui/src/app/pages/server-routes/marketplaces/marketplaces.page.ts b/frontend/projects/ui/src/app/pages/server-routes/marketplaces/marketplaces.page.ts index a1aa59c20..d8edda5fe 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/marketplaces/marketplaces.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/marketplaces/marketplaces.page.ts @@ -1,6 +1,7 @@ import { Component, Inject } from '@angular/core' import { ActionSheetController, + AlertController, LoadingController, ModalController, } from '@ionic/angular' @@ -51,6 +52,7 @@ export class MarketplacesPage { private readonly config: ConfigService, private readonly patch: PatchDbService, private readonly destroy$: DestroyService, + private readonly alertCtrl: AlertController, ) {} ngOnInit() { @@ -129,7 +131,7 @@ export class MarketplacesPage { text: 'Delete', role: 'destructive', handler: () => { - this.delete(id) + this.presentAlertDelete(id) }, }) } @@ -189,6 +191,28 @@ export class MarketplacesPage { .subscribe() } + private async presentAlertDelete(id: string) { + const name = this.marketplaces.find(m => m.id === id)?.name + + const alert = await this.alertCtrl.create({ + header: 'Confirm', + message: `Are you sure you want to delete ${name}?`, + buttons: [ + { + text: 'Cancel', + role: 'cancel', + }, + { + text: 'Delete', + handler: () => this.delete(id), + cssClass: 'enter-click', + }, + ], + }) + + await alert.present() + } + private async delete(id: string): Promise { const data = await getMarketplace(this.patch) const marketplace: UIMarketplaceData = JSON.parse(JSON.stringify(data)) diff --git a/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.html b/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.html index f972fc398..44d1bd1cd 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.html +++ b/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.html @@ -8,24 +8,21 @@ - - - General - - Device Name - {{ ui.name || 'My Embassy' }} - + + General + + Device Name + {{ name.current }} + - Marketplace - - Auto Check for Updates - - {{ ui['auto-check-updates'] !== false ? 'Enabled' : 'Disabled' }} - - - - + Marketplace + + Auto Check for Updates + {{ auto ? 'Enabled' : 'Disabled' }} + + diff --git a/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.ts b/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.ts index a0b58c6c5..4bfe716cb 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/preferences/preferences.page.ts @@ -12,6 +12,10 @@ import { import { ApiService } from 'src/app/services/api/embassy-api.service' import { ServerConfigService } from 'src/app/services/server-config.service' import { LocalStorageService } from '../../../services/local-storage.service' +import { + ServerNameInfo, + ServerNameService, +} from 'src/app/services/server-name.service' @Component({ selector: 'preferences', @@ -22,8 +26,9 @@ import { LocalStorageService } from '../../../services/local-storage.service' export class PreferencesPage { clicks = 0 - readonly ui$ = this.patch.watch$('ui') + readonly autoCheck$ = this.patch.watch$('ui', 'auto-check-updates') readonly server$ = this.patch.watch$('server-info') + readonly name$ = this.serverNameService.name$ constructor( private readonly loadingCtrl: LoadingController, @@ -32,24 +37,22 @@ export class PreferencesPage { private readonly toastCtrl: ToastController, private readonly localStorageService: LocalStorageService, private readonly patch: PatchDbService, + private readonly serverNameService: ServerNameService, readonly serverConfig: ServerConfigService, ) {} - async presentModalName( - placeholder: string, - initialValue: string, - ): Promise { + async presentModalName(name: ServerNameInfo): Promise { const options: GenericInputOptions = { title: 'Edit Device Name', message: 'This is for your reference only.', label: 'Device Name', useMask: false, - placeholder, + placeholder: name.default, nullable: true, - initialValue, + initialValue: name.current, buttonText: 'Save', submitFn: (value: string) => - this.setDbValue('name', value || placeholder), + this.setDbValue('name', value || name.default), } const modal = await this.modalCtrl.create({ diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html index 21bf0a180..8fac1c849 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html +++ b/frontend/projects/ui/src/app/pages/server-routes/server-show/server-show.page.html @@ -1,7 +1,7 @@ - - {{ ui.name || "My Embassy" }} + + {{ name.current }} 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 e08ef3836..26fe75efe 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 @@ -8,6 +8,7 @@ import { import { ApiService } from 'src/app/services/api/embassy-api.service' import { ActivatedRoute } from '@angular/router' import { PatchDbService } from 'src/app/services/patch-db/patch-db.service' +import { ServerNameService } from 'src/app/services/server-name.service' import { Observable, of } from 'rxjs' import { filter, take, tap } from 'rxjs/operators' import { isEmptyObject, ErrorToastService } from '@start9labs/shared' @@ -15,6 +16,7 @@ import { EOSService } from 'src/app/services/eos.service' import { LocalStorageService } from 'src/app/services/local-storage.service' import { OSUpdatePage } from 'src/app/modals/os-update/os-update.page' import { getAllPackages } from '../../../util/get-package-data' +import { AuthService } from 'src/app/services/auth.service' @Component({ selector: 'server-show', @@ -26,7 +28,7 @@ export class ServerShowPage { clicks = 0 readonly server$ = this.patch.watch$('server-info') - readonly ui$ = this.patch.watch$('ui') + readonly name$ = this.serverNameService.name$ readonly showUpdate$ = this.eosService.showUpdate$ readonly showDiskRepair$ = this.localStorageService.showDiskRepair$ @@ -41,6 +43,8 @@ export class ServerShowPage { private readonly patch: PatchDbService, private readonly eosService: EOSService, private readonly localStorageService: LocalStorageService, + private readonly serverNameService: ServerNameService, + private readonly authService: AuthService, ) {} ngOnInit() { @@ -74,6 +78,26 @@ export class ServerShowPage { } } + async presentAlertLogout() { + const alert = await this.alertCtrl.create({ + header: 'Confirm', + message: 'Are you sure you want to log out?', + buttons: [ + { + text: 'Cancel', + role: 'cancel', + }, + { + text: 'Logout', + handler: () => this.logout(), + cssClass: 'enter-click', + }, + ], + }) + + await alert.present() + } + async presentAlertRestart() { const alert = await this.alertCtrl.create({ header: 'Restart', @@ -171,6 +195,12 @@ export class ServerShowPage { await alert.present() } + // should wipe cache independent of actual BE logout + private logout() { + this.embassyApi.logout({}).catch(e => console.error('Failed to log out', e)) + this.authService.setUnverified() + } + private async restart() { const action = 'Restart' @@ -456,6 +486,14 @@ export class ServerShowPage { }, ], Power: [ + { + title: 'Log Out', + description: '', + icon: 'log-out-outline', + action: () => this.presentAlertLogout(), + detail: false, + disabled$: of(false), + }, { title: 'Restart', description: '', diff --git a/frontend/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts b/frontend/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts index 0783ea856..10b3ea827 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts @@ -95,18 +95,14 @@ export class SideloadPage { manifest: this.toUpload.manifest!, icon: this.toUpload.icon!, }) - this.api - .uploadPackage(guid, await blobToBuffer(this.toUpload.file!)) - .catch(e => { - this.errToast.present(e) - }) + const buffer = await blobToBuffer(this.toUpload.file!) + this.api.uploadPackage(guid, buffer).catch(e => console.error(e)) + + this.navCtrl.navigateRoot('/services') } catch (e: any) { this.errToast.present(e) } finally { loader.dismiss() - await this.navCtrl.navigateForward( - `/services/${this.toUpload.manifest!.id}`, - ) this.clearToUpload() } } diff --git a/frontend/projects/ui/src/app/services/api/mock-patch.ts b/frontend/projects/ui/src/app/services/api/mock-patch.ts index d97e9d591..c0fa3ef0c 100644 --- a/frontend/projects/ui/src/app/services/api/mock-patch.ts +++ b/frontend/projects/ui/src/app/services/api/mock-patch.ts @@ -41,6 +41,7 @@ export const mockPatchData: DataModel = { updated: false, 'update-progress': null, }, + hostname: 'random-words', }, 'recovered-packages': { 'btc-rpc-proxy': { diff --git a/frontend/projects/ui/src/app/services/patch-db/data-model.ts b/frontend/projects/ui/src/app/services/patch-db/data-model.ts index 3b759c89b..037087aeb 100644 --- a/frontend/projects/ui/src/app/services/patch-db/data-model.ts +++ b/frontend/projects/ui/src/app/services/patch-db/data-model.ts @@ -56,6 +56,7 @@ export interface ServerInfo { 'status-info': ServerStatusInfo 'eos-version-compat': string 'password-hash': string + hostname: string } export interface ServerStatusInfo { diff --git a/frontend/projects/ui/src/app/services/server-name.service.ts b/frontend/projects/ui/src/app/services/server-name.service.ts new file mode 100644 index 000000000..81857b8e1 --- /dev/null +++ b/frontend/projects/ui/src/app/services/server-name.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core' +import { PatchDbService } from './patch-db/patch-db.service' +import { combineLatest, filter, map, Observable } from 'rxjs' + +export interface ServerNameInfo { + current: string + default: string +} + +@Injectable({ providedIn: 'root' }) +export class ServerNameService { + private readonly chosenName$ = this.patch.watch$('ui', 'name') + private readonly hostname$ = this.patch + .watch$('server-info', 'hostname') + .pipe(filter(Boolean)) + + readonly name$: Observable = combineLatest([ + this.chosenName$, + this.hostname$, + ]).pipe( + map(([chosen, hostname]) => { + return { + current: chosen || hostname, + default: hostname, + } + }), + ) + + constructor(private readonly patch: PatchDbService) {} +}