mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
use hostname from patchDB as default server name (#1758)
* replace offline toast with global indicator * use hostname from patchDB as default server name * add alert to marketplace delete and reword logout alert
This commit is contained in:
@@ -18,5 +18,10 @@
|
||||
<ion-footer>
|
||||
<footer appFooter></footer>
|
||||
</ion-footer>
|
||||
<ion-footer
|
||||
*ngIf="(authService.isVerified$ | async) && !(sidebarOpen$ | async)"
|
||||
>
|
||||
<connection-bar></connection-bar>
|
||||
</ion-footer>
|
||||
<toast-container></toast-container>
|
||||
</ion-app>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
</ion-item-group>
|
||||
|
||||
<img
|
||||
appSnek
|
||||
class="snek"
|
||||
@@ -56,21 +57,6 @@
|
||||
src="assets/img/icons/snek.png"
|
||||
[appSnekHighScore]="snekScore$ | async"
|
||||
/>
|
||||
<div class="bottom">
|
||||
<div class="divider" style="margin-bottom: 10px"></div>
|
||||
<ion-menu-toggle auto-hide="false">
|
||||
<ion-item
|
||||
button
|
||||
lines="none"
|
||||
style="--background: transparent; margin-bottom: 86px; text-align: center"
|
||||
fill="clear"
|
||||
(click)="presentAlertLogout()"
|
||||
>
|
||||
<ion-label class="inline">
|
||||
<h2>Log Out</h2>
|
||||
|
||||
<ion-icon name="log-out-outline"></ion-icon>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
</div>
|
||||
<ion-footer class="bottom">
|
||||
<connection-bar></connection-bar>
|
||||
</ion-footer>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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],
|
||||
})
|
||||
|
||||
@@ -19,6 +19,7 @@ const ICONS = [
|
||||
'chevron-forward',
|
||||
'close',
|
||||
'cloud-outline',
|
||||
'cloud-done',
|
||||
'cloud-done-outline',
|
||||
'cloud-download-outline',
|
||||
'cloud-offline-outline',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<ion-toolbar
|
||||
*ngIf="connection$ | async as connection"
|
||||
class="connection-toolbar"
|
||||
[color]="connection.color"
|
||||
>
|
||||
<div class="inline" slot="start">
|
||||
<ion-icon
|
||||
slot="end"
|
||||
[name]="connection.icon"
|
||||
class="icon"
|
||||
color="light"
|
||||
></ion-icon>
|
||||
<p style="margin: 8px 0; font-weight: 600">{{ connection.message }}</p>
|
||||
<ion-spinner
|
||||
*ngIf="connection.dots"
|
||||
name="dots"
|
||||
color="light"
|
||||
class="ion-margin-start"
|
||||
></ion-spinner>
|
||||
</div>
|
||||
</ion-toolbar>
|
||||
@@ -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 {}
|
||||
@@ -0,0 +1,9 @@
|
||||
.connection-toolbar {
|
||||
padding: 0 24px;
|
||||
--min-height: 36px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 23px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
@@ -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,
|
||||
) {}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<toast
|
||||
*ngIf="content$ | async as content"
|
||||
class="warning-toast"
|
||||
header="Unable to Connect"
|
||||
(dismiss)="onDismiss()"
|
||||
>
|
||||
{{ content.message }}
|
||||
<button toastButton icon="close" side="start" (click)="onDismiss()"></button>
|
||||
<a
|
||||
*ngIf="content.link"
|
||||
toastButton
|
||||
side="end"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
[href]="content.link"
|
||||
>
|
||||
View solutions
|
||||
</a>
|
||||
</toast>
|
||||
@@ -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<null>()
|
||||
|
||||
readonly content$ = merge(this.dismiss$, this.failure$)
|
||||
|
||||
constructor(
|
||||
@Inject(OfflineToastService)
|
||||
private readonly failure$: Observable<OfflineMessage | null>,
|
||||
) {}
|
||||
|
||||
onDismiss() {
|
||||
this.dismiss$.next(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<OfflineMessage | null> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
<notifications-toast></notifications-toast>
|
||||
<offline-toast></offline-toast>
|
||||
<refresh-alert></refresh-alert>
|
||||
<update-toast></update-toast>
|
||||
|
||||
@@ -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,
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<void> {
|
||||
const data = await getMarketplace(this.patch)
|
||||
const marketplace: UIMarketplaceData = JSON.parse(JSON.stringify(data))
|
||||
|
||||
@@ -8,24 +8,21 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ng-container *ngIf="ui$ | async as ui">
|
||||
<ion-item-group *ngIf="server$ | async as server">
|
||||
<ion-item-divider>General</ion-item-divider>
|
||||
<ion-item button (click)="presentModalName('My Embassy', ui.name)">
|
||||
<ion-label>Device Name</ion-label>
|
||||
<ion-note slot="end">{{ ui.name || 'My Embassy' }}</ion-note>
|
||||
</ion-item>
|
||||
<ion-item-group *ngIf="name$ | async as name">
|
||||
<ion-item-divider>General</ion-item-divider>
|
||||
<ion-item button (click)="presentModalName(name)">
|
||||
<ion-label>Device Name</ion-label>
|
||||
<ion-note slot="end">{{ name.current }}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider>Marketplace</ion-item-divider>
|
||||
<ion-item
|
||||
button
|
||||
(click)="serverConfig.presentAlert('auto-check-updates', ui['auto-check-updates'] !== false)"
|
||||
>
|
||||
<ion-label>Auto Check for Updates</ion-label>
|
||||
<ion-note slot="end">
|
||||
{{ ui['auto-check-updates'] !== false ? 'Enabled' : 'Disabled' }}
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ng-container>
|
||||
<ion-item-divider>Marketplace</ion-item-divider>
|
||||
<ion-item
|
||||
*ngIf="autoCheck$ | async as auto"
|
||||
button
|
||||
(click)="serverConfig.presentAlert('auto-check-updates', auto)"
|
||||
>
|
||||
<ion-label>Auto Check for Updates</ion-label>
|
||||
<ion-note slot="end"> {{ auto ? 'Enabled' : 'Disabled' }} </ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
||||
|
||||
@@ -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<void> {
|
||||
async presentModalName(name: ServerNameInfo): Promise<void> {
|
||||
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({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title *ngIf="ui$ | async as ui; else loadingTitle">
|
||||
{{ ui.name || "My Embassy" }}
|
||||
<ion-title *ngIf="name$ | async as name; else loadingTitle">
|
||||
{{ name.current }}
|
||||
</ion-title>
|
||||
<ng-template #loadingTitle>
|
||||
<ion-title>
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ export const mockPatchData: DataModel = {
|
||||
updated: false,
|
||||
'update-progress': null,
|
||||
},
|
||||
hostname: 'random-words',
|
||||
},
|
||||
'recovered-packages': {
|
||||
'btc-rpc-proxy': {
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface ServerInfo {
|
||||
'status-info': ServerStatusInfo
|
||||
'eos-version-compat': string
|
||||
'password-hash': string
|
||||
hostname: string
|
||||
}
|
||||
|
||||
export interface ServerStatusInfo {
|
||||
|
||||
30
frontend/projects/ui/src/app/services/server-name.service.ts
Normal file
30
frontend/projects/ui/src/app/services/server-name.service.ts
Normal file
@@ -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<ServerNameInfo> = combineLatest([
|
||||
this.chosenName$,
|
||||
this.hostname$,
|
||||
]).pipe(
|
||||
map(([chosen, hostname]) => {
|
||||
return {
|
||||
current: chosen || hostname,
|
||||
default: hostname,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
constructor(private readonly patch: PatchDbService) {}
|
||||
}
|
||||
Reference in New Issue
Block a user