bug fixes and cosmetic improvements

This commit is contained in:
Matt Hill
2021-09-01 14:45:16 -06:00
parent ec6f464bc0
commit 09a9cfe88c
21 changed files with 147 additions and 118 deletions

View File

@@ -97,26 +97,29 @@ export class AppComponent {
if (auth === AuthState.VERIFIED) { if (auth === AuthState.VERIFIED) {
this.patch.start() this.patch.start()
this.showMenu = true
// if on the login screen, route to dashboard
if (this.router.url.startsWith('/login')) {
this.router.navigate([''], { replaceUrl: true })
}
this.subscriptions = this.subscriptions.concat([
// start the connection monitor
...this.connectionService.start(),
// watch connection to display connectivity issues
this.watchConnection(),
// // watch router to highlight selected menu item
this.watchRouter(),
// // watch status to display/hide maintenance page
])
this.patch.watch$() this.patch.watch$()
.pipe( .pipe(
filter(data => !isEmptyObject(data as object)), filter(data => !isEmptyObject(data as object)),
take(1), take(1),
) )
.subscribe(_ => { .subscribe(_ => {
this.showMenu = true this.subscriptions = this.subscriptions.concat([
// if on the login screen, route to dashboard
if (this.router.url.startsWith('/login')) {
this.router.navigate([''], { replaceUrl: true })
}
this.subscriptions = [
// start the connection monitor
...this.connectionService.start(),
// watch connection to display connectivity issues
this.watchConnection(),
// // watch router to highlight selected menu item
this.watchRouter(),
// // watch status to display/hide maintenance page
this.watchStatus(), this.watchStatus(),
// // watch version to refresh browser window // // watch version to refresh browser window
this.watchVersion(), this.watchVersion(),
@@ -124,7 +127,7 @@ export class AppComponent {
this.watchNotifications(), this.watchNotifications(),
// // run startup alerts // // run startup alerts
this.startupAlertsService.runChecks(), this.startupAlertsService.runChecks(),
] ])
}) })
// UNVERIFIED // UNVERIFIED
} else if (auth === AuthState.UNVERIFIED) { } else if (auth === AuthState.UNVERIFIED) {
@@ -230,6 +233,10 @@ export class AppComponent {
message = 'Embassy not found on Local Area Network.' message = 'Embassy not found on Local Area Network.'
link = 'https://docs.start9.com/support/FAQ/setup-faq.html#lan-failure' link = 'https://docs.start9.com/support/FAQ/setup-faq.html#lan-failure'
break break
case ConnectionFailure.Unknown:
message = 'Unknown connection error. Please refresh the page.'
link = 'https://docs.start9.com/support/FAQ/setup-faq.html#unknown-failure'
break
} }
await this.presentToastOffline(message, link) await this.presentToastOffline(message, link)
} }

View File

@@ -25,14 +25,14 @@
</h4> </h4>
<!-- string --> <!-- string -->
<ion-item color="dark" *ngIf="spec.type === 'string'"> <ion-item color="dark" *ngIf="spec.type === 'string'">
<ion-input [type]="spec.masked && !unmasked[entry.key] ? 'password' : 'text'" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(key, spec)" (ionChange)="handleInputChange(spec)"></ion-input> <ion-input [type]="spec.masked && !unmasked[entry.key] ? 'password' : 'text'" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(entry.key, spec)" (ionChange)="handleInputChange(spec)"></ion-input>
<ion-button *ngIf="spec.masked" fill="clear" color="light" (click)="unmasked[entry.key] = !unmasked[entry.key]"> <ion-button *ngIf="spec.masked" fill="clear" color="light" (click)="unmasked[entry.key] = !unmasked[entry.key]">
<ion-icon slot="icon-only" [name]="unmasked[entry.key] ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon> <ion-icon slot="icon-only" [name]="unmasked[entry.key] ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
<!-- number --> <!-- number -->
<ion-item color="dark" *ngIf="spec.type === 'number'"> <ion-item color="dark" *ngIf="spec.type === 'number'">
<ion-input type="tel" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(key, spec)" (ionChange)="handleInputChange(spec)"></ion-input> <ion-input type="tel" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(entry.key, spec)" (ionChange)="handleInputChange(spec)"></ion-input>
<ion-note *ngIf="spec.units" slot="end" color="light" style="font-size: medium;">{{ spec.units }}</ion-note> <ion-note *ngIf="spec.units" slot="end" color="light" style="font-size: medium;">{{ spec.units }}</ion-note>
</ion-item> </ion-item>
<!-- boolean --> <!-- boolean -->
@@ -43,7 +43,7 @@
<!-- enum --> <!-- enum -->
<ion-item *ngIf="spec.type === 'enum'"> <ion-item *ngIf="spec.type === 'enum'">
<ion-label>{{ spec.name }}</ion-label> <ion-label>{{ spec.name }}</ion-label>
<ion-select [interfaceOptions]="{ message: getWarningText(spec.warning) }" slot="end" placeholder="Select" [formControlName]="entry.key" [selectedText]="spec['value-names'][formGroup.get(entry.key).value]" (ionChange)="handleInputChange(entry.key, spec)"> <ion-select [interfaceOptions]="{ message: getWarningText(spec.warning) }" slot="end" placeholder="Select" [formControlName]="entry.key" [selectedText]="spec['value-names'][formGroup.get(entry.key).value]" (ionChange)="handleInputChange(spec)">
<ion-select-option *ngFor="let option of spec.values" [value]="option"> <ion-select-option *ngFor="let option of spec.values" [value]="option">
{{ spec['value-names'][option] }} {{ spec['value-names'][option] }}
</ion-select-option> </ion-select-option>
@@ -68,7 +68,7 @@
spec.variants[entry.value.controls[spec.tag.id].value] : spec.variants[entry.value.controls[spec.tag.id].value] :
spec.spec" spec.spec"
[formGroup]="entry.value" [formGroup]="entry.value"
[current]="current ? current[key] : undefined" [current]="current ? current[entry.key] : undefined"
[unionSpec]="spec.type === 'union' ? spec : undefined" [unionSpec]="spec.type === 'union' ? spec : undefined"
></form-object> ></form-object>
</div> </div>

View File

@@ -20,10 +20,10 @@ export class CompleteComponent implements OnInit, Loadable {
} }
@Input() transitions: { @Input() transitions: {
cancel: () => void cancel: () => any
next: () => void next: () => any
final: () => void final: () => any
error: (e: Error) => void error: (e: Error) => any
} }
loading$ = new BehaviorSubject(false) loading$ = new BehaviorSubject(false)

View File

@@ -30,10 +30,10 @@
*ngFor="let dep of dependentBreakages | keyvalue" *ngFor="let dep of dependentBreakages | keyvalue"
> >
<ion-thumbnail style="position: relative; height: 4vh; width: 4vh" slot="start"> <ion-thumbnail style="position: relative; height: 4vh; width: 4vh" slot="start">
<img [src]="dep.value.iconURL" /> <img [src]="patch.data['package-data'][dep.key]['static-files'].icon" />
</ion-thumbnail> </ion-thumbnail>
<ion-label> <ion-label>
<h5>{{ dep.value.title }}</h5> <h5>{{ patch.data['package-data'][dep.key].manifest.title }}</h5>
</ion-label> </ion-label>
</ion-item> </ion-item>
</div> </div>

View File

@@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'
import { BehaviorSubject, from, Subject } from 'rxjs' import { BehaviorSubject, from, Subject } from 'rxjs'
import { takeUntil, tap } from 'rxjs/operators' import { takeUntil, tap } from 'rxjs/operators'
import { Breakages } from 'src/app/services/api/api.types' import { Breakages } from 'src/app/services/api/api.types'
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
import { capitalizeFirstLetter, isEmptyObject } from 'src/app/util/misc.util' import { capitalizeFirstLetter, isEmptyObject } from 'src/app/util/misc.util'
import { Loadable, markAsLoadingDuring$ } from '../loadable' import { Loadable, markAsLoadingDuring$ } from '../loadable'
import { WizardAction } from '../wizard-types' import { WizardAction } from '../wizard-types'
@@ -20,10 +21,10 @@ export class DependentsComponent implements OnInit, Loadable {
skipConfirmationDialogue?: boolean skipConfirmationDialogue?: boolean
} }
@Input() transitions: { @Input() transitions: {
cancel: () => void cancel: () => any
next: () => void next: () => any
final: () => void final: () => any
error: (e: Error) => void error: (e: Error) => any
} }
dependentBreakages: Breakages dependentBreakages: Breakages
@@ -33,7 +34,9 @@ export class DependentsComponent implements OnInit, Loadable {
loading$ = new BehaviorSubject(false) loading$ = new BehaviorSubject(false)
cancel$ = new Subject<void>() cancel$ = new Subject<void>()
constructor () { } constructor (
public readonly patch: PatchDbService,
) { }
ngOnInit () { } ngOnInit () { }
load () { load () {

View File

@@ -38,11 +38,11 @@
<!-- cancel button if loading/not loading --> <!-- cancel button if loading/not loading -->
<ion-button slot="start" *ngIf="(currentSlide.loading$ | async) && currentBottomBar.cancel.whileLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline"> <ion-button slot="start" *ngIf="(currentSlide.loading$ | async) && currentBottomBar.cancel.whileLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline">
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{ cancel.text }}</ion-text> <ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text.length > 16">{{ cancel.text }}</ion-text>
<ion-icon *ngIf="!cancel.text" name="close"></ion-icon> <ion-icon *ngIf="!cancel.text" name="close"></ion-icon>
</ion-button> </ion-button>
<ion-button slot="start" *ngIf="!(currentSlide.loading$ | async) && currentBottomBar.cancel.afterLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline"> <ion-button slot="start" *ngIf="!(currentSlide.loading$ | async) && currentBottomBar.cancel.afterLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline">
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{ cancel.text }}</ion-text> <ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text.length > 16">{{ cancel.text }}</ion-text>
<ion-icon *ngIf="!cancel.text" name="close"></ion-icon> <ion-icon *ngIf="!cancel.text" name="close"></ion-icon>
</ion-button> </ion-button>

View File

@@ -1,6 +1,6 @@
<ion-content <ion-content
[scrollEvents]="true" [scrollEvents]="true"
(ionScroll)="scrollEvent($event)" (ionScroll)="scrollEvent()"
style="height: 100%;" style="height: 100%;"
id="ion-content" id="ion-content"
class="ion-padding" class="ion-padding"

View File

@@ -5,5 +5,5 @@
[style.font-weight]="weight" [style.font-weight]="weight"
> >
{{ disconnected ? 'Unknown' : rendering.display }} {{ disconnected ? 'Unknown' : rendering.display }}
<ion-spinner *ngIf="rendering.showDots" class="dots dots-small" name="dots" [color]="color"></ion-spinner> <ion-spinner *ngIf="rendering.showDots" class="dots dots-small" name="dots"></ion-spinner>
</p> </p>

View File

@@ -64,17 +64,17 @@
<p>No config options for {{ pkg.manifest.title }} {{ pkg.manifest.version }}.</p> <p>No config options for {{ pkg.manifest.title }} {{ pkg.manifest.version }}.</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
</ng-container>
<!-- has config --> <!-- has config -->
<form [formGroup]="configForm" (ngSubmit)="save()" novalidate> <form [formGroup]="configForm" (ngSubmit)="save(pkg)" novalidate>
<form-object <form-object
[objectSpec]="configSpec" [objectSpec]="configSpec"
[formGroup]="configForm" [formGroup]="configForm"
[current]="current" [current]="current"
showEdited [showEdited]="true"
></form-object> ></form-object>
</form> </form>
</ng-container>
</ng-template> </ng-template>
</ion-content> </ion-content>

View File

@@ -15,6 +15,7 @@ export class AppRestoreComponent {
@Input() pkgId: string @Input() pkgId: string
disks: DiskInfo disks: DiskInfo
loading = true loading = true
submitting = false
allPartitionsMounted: boolean allPartitionsMounted: boolean
modal: HTMLIonModalElement modal: HTMLIonModalElement
@@ -73,10 +74,17 @@ export class AppRestoreComponent {
} }
private async restore (logicalname: string, password: string): Promise<void> { private async restore (logicalname: string, password: string): Promise<void> {
await this.embassyApi.restorePackage({ this.submitting = true
id: this.pkgId, try {
logicalname, await this.embassyApi.restorePackage({
password, id: this.pkgId,
}) logicalname,
password,
})
} catch (e) {
this.errToast.present(e)
} finally {
this.submitting = false
}
} }
} }

View File

@@ -1,7 +1,6 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { IonicSafeString, LoadingController, ModalController } from '@ionic/angular' import { IonicSafeString, LoadingController, ModalController } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { getErrorMessage } from 'src/app/services/error-toast.service'
import { ErrorToastService, getErrorMessage } from 'src/app/services/error-toast.service'
@Component({ @Component({
selector: 'backup-confirmation', selector: 'backup-confirmation',

View File

@@ -10,18 +10,19 @@
</ion-header> </ion-header>
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<form [formGroup]="formGroup" (ngSubmit)="save()" novalidate> <form [formGroup]="formGroup" (ngSubmit)="handleClick(submitBtn.handler)" novalidate>
<form-object <form-object
[objectSpec]="spec" [objectSpec]="spec"
[formGroup]="formGroup" [formGroup]="formGroup"
></form-object> ></form-object>
<button hidden type="submit"></button>
</form> </form>
</ion-content> </ion-content>
<ion-footer> <ion-footer>
<ion-toolbar> <ion-toolbar class="footer">
<ion-buttons slot="end" class="ion-padding-end"> <ion-buttons slot="end">
<ion-button *ngFor="let button of buttons" fill="outline" (click)="handleClick(button)"> <ion-button class="ion-padding-end" *ngFor="let button of buttons" (click)="handleClick(button.handler)">
{{ button.text }} {{ button.text }}
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>

View File

@@ -7,6 +7,7 @@ import { ConfigSpec } from 'src/app/pkg-config/config-types'
export interface ActionButton { export interface ActionButton {
text: string text: string
handler: (value: any) => Promise<boolean> handler: (value: any) => Promise<boolean>
isSubmit?: boolean
} }
@Component({ @Component({
@@ -18,6 +19,7 @@ export class GenericFormPage {
@Input() title: string @Input() title: string
@Input() spec: ConfigSpec @Input() spec: ConfigSpec
@Input() buttons: ActionButton[] @Input() buttons: ActionButton[]
submitBtn: ActionButton
formGroup: FormGroup formGroup: FormGroup
constructor ( constructor (
@@ -27,20 +29,25 @@ export class GenericFormPage {
ngOnInit () { ngOnInit () {
this.formGroup = this.formService.createForm(this.spec) this.formGroup = this.formService.createForm(this.spec)
this.submitBtn = this.buttons.find(btn => btn.isSubmit) || {
text: '',
handler: () => Promise.resolve(true),
}
console.log(this.submitBtn)
} }
async dismiss (): Promise<void> { async dismiss (): Promise<void> {
this.modalCtrl.dismiss() this.modalCtrl.dismiss()
} }
async handleClick (button: ActionButton): Promise<void> { async handleClick (handler: ActionButton['handler']): Promise<void> {
if (this.formGroup.invalid) { if (this.formGroup.invalid) {
this.formGroup.markAllAsTouched() this.formGroup.markAllAsTouched()
document.getElementsByClassName('validation-error')[0].parentElement.parentElement.scrollIntoView({ behavior: 'smooth' }) document.getElementsByClassName('validation-error')[0].parentElement.parentElement.scrollIntoView({ behavior: 'smooth' })
return return
} }
const success = await button.handler(this.formGroup.value) const success = await handler(this.formGroup.value)
if (success !== false) this.modalCtrl.dismiss() if (success !== false) this.modalCtrl.dismiss()
} }
} }

View File

@@ -61,6 +61,7 @@ export class AppActionsPage {
handler: (value: any) => { handler: (value: any) => {
return this.executeAction(pkg.manifest.id, action.key, value) return this.executeAction(pkg.manifest.id, action.key, value)
}, },
isSubmit: true,
}, },
], ],
}, },

View File

@@ -6,6 +6,7 @@ import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-m
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service' import { PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
import { filter } from 'rxjs/operators' import { filter } from 'rxjs/operators'
import { isEmptyObject } from 'src/app/util/misc.util'
@Component({ @Component({
selector: 'app-list', selector: 'app-list',
@@ -38,7 +39,11 @@ export class AppListPage {
this.patch.watch$('package-data') this.patch.watch$('package-data')
.pipe( .pipe(
filter(obj => { filter(obj => {
return Object.keys(obj).length !== Object.keys(this.pkgs).length return obj &&
(
isEmptyObject(obj) ||
Object.keys(obj).length !== Object.keys(this.pkgs).length
)
}), }),
) )
.subscribe(pkgs => { .subscribe(pkgs => {

View File

@@ -1,6 +1,6 @@
<ion-content> <ion-content>
<ion-grid style="height: 100%; max-width: 540px;"> <ion-grid style="height: 100%; max-width: 540px;">
<ion-row class="ion-align-items-center" style="height: 100%;"> <ion-row class="ion-align-items-center" style="height: 90%;">
<ion-col class="ion-text-center"> <ion-col class="ion-text-center">
<div style="padding-bottom: 16px;"> <div style="padding-bottom: 16px;">

View File

@@ -7,16 +7,20 @@
</ion-header> </ion-header>
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<h1 style="font-family: 'Montserrat'; font-weight: 100px; margin: 32px 0;" class="ion-text-center">Embassy Marketplace</h1> <h1 style="font-family: 'Montserrat'; font-size: 42px; margin: 32px 0;" class="ion-text-center">Embassy Marketplace</h1>
<ion-toolbar style="padding-bottom: 32px; max-width: 600px;" color="transparent"> <ion-grid style="padding-bottom: 32px;">
<ion-searchbar color="dark" (keyup.enter)="search()" debounce="300" [(ngModel)]="query"></ion-searchbar> <ion-row>
<ion-buttons slot="end"> <ion-col sizeMd="6" offset-md="3">
<ion-button color="primary" fill="solid" (click)="search()"> <ion-toolbar color="transparent">
<ion-icon slot="icon-only" name="search-outline"></ion-icon> <ion-searchbar enterkeyhint="search" color="dark" (keyup.enter)="search()" debounce="300" [(ngModel)]="query"></ion-searchbar>
</ion-button> <ion-button style="height: 42px;" slot="end" color="primary" fill="solid" (click)="search()">
</ion-buttons> <ion-icon slot="icon-only" name="search-outline"></ion-icon>
</ion-toolbar> </ion-button>
</ion-toolbar>
</ion-col>
</ion-row>
</ion-grid>
<!-- page loading --> <!-- page loading -->
<ng-container *ngIf="pageLoading; else pageLoaded"> <ng-container *ngIf="pageLoading; else pageLoaded">

View File

@@ -21,6 +21,7 @@
.selected { .selected {
font-weight: bold; font-weight: bold;
font-size: 17px;
} }
.dim { .dim {

View File

@@ -85,7 +85,7 @@ export class WifiPage {
spec: wifiSpec.spec, spec: wifiSpec.spec,
buttons: [ buttons: [
{ {
text: 'Save', text: 'Save for Later',
handler: async (value: { ssid: string, password: string }) => { handler: async (value: { ssid: string, password: string }) => {
await this.save(value.ssid, value.password) await this.save(value.ssid, value.password)
}, },

View File

@@ -55,18 +55,23 @@ export class ConnectionService {
} else { } else {
// diagnosing // diagnosing
this.connectionFailure$.next(ConnectionFailure.Diagnosing) this.connectionFailure$.next(ConnectionFailure.Diagnosing)
const torSuccess = await this.testAddrs(addrs.tor)
if (torSuccess) { if (!addrs) {
// TOR SUCCESS, EMBASSY IS PROBLEM this.connectionFailure$.next(ConnectionFailure.Unknown)
this.connectionFailure$.next(ConnectionFailure.Embassy)
} else { } else {
const clearnetSuccess = await this.testAddrs(addrs.clearnet) const torSuccess = await this.testAddrs(addrs.tor)
if (clearnetSuccess) { if (torSuccess) {
// CLEARNET SUCCESS, TOR IS PROBLEM // TOR SUCCESS, EMBASSY IS PROBLEM
this.connectionFailure$.next(ConnectionFailure.Tor) this.connectionFailure$.next(ConnectionFailure.Embassy)
} else { } else {
// INTERNET IS PROBLEM const clearnetSuccess = await this.testAddrs(addrs.clearnet)
this.connectionFailure$.next(ConnectionFailure.Internet) if (clearnetSuccess) {
// CLEARNET SUCCESS, TOR IS PROBLEM
this.connectionFailure$.next(ConnectionFailure.Tor)
} else {
// INTERNET IS PROBLEM
this.connectionFailure$.next(ConnectionFailure.Internet)
}
} }
} }
} }
@@ -101,4 +106,5 @@ export enum ConnectionFailure {
Tor = 'tor', Tor = 'tor',
Lan = 'lan', Lan = 'lan',
Internet = 'internet', Internet = 'internet',
Unknown = 'unknown',
} }

View File

@@ -1,7 +1,7 @@
import { Inject, Injectable, InjectionToken } from '@angular/core' import { Inject, Injectable, InjectionToken } from '@angular/core'
import { Bootstrapper, PatchDB, Source, Store } from 'patch-db-client' import { Bootstrapper, PatchDB, Source, Store } from 'patch-db-client'
import { BehaviorSubject, combineLatest, Observable, of, Subscription } from 'rxjs' import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'
import { catchError, debounceTime, delay, filter, finalize, map, take, tap, timeout } from 'rxjs/operators' import { catchError, debounceTime, finalize, map, tap } from 'rxjs/operators'
import { pauseFor } from 'src/app/util/misc.util' import { pauseFor } from 'src/app/util/misc.util'
import { ApiService } from '../api/embassy-api.service' import { ApiService } from '../api/embassy-api.service'
import { DataModel } from './data-model' import { DataModel } from './data-model'
@@ -20,7 +20,7 @@ export enum PatchConnection {
providedIn: 'root', providedIn: 'root',
}) })
export class PatchDbService { export class PatchDbService {
patchConnection$ = new BehaviorSubject(PatchConnection.Initializing) private patchConnection$ = new BehaviorSubject(PatchConnection.Initializing)
private patchDb: PatchDB<DataModel> private patchDb: PatchDB<DataModel>
private patchSub: Subscription private patchSub: Subscription
data: DataModel data: DataModel
@@ -40,50 +40,37 @@ export class PatchDbService {
} }
start (): void { start (): void {
console.log(this.patchSub ? 'restarting patch-db' : 'starting patch-db')
// make sure everything is stopped before initializing // make sure everything is stopped before initializing
if (this.patchSub) { if (this.patchSub) {
console.log('Retrying')
this.patchSub.unsubscribe() this.patchSub.unsubscribe()
this.patchSub = undefined this.patchSub = undefined
} }
try {
const connectedSub$ = this.patchDb.connectionMade$()
.pipe(
tap(() => {
this.patchConnection$.next(PatchConnection.Connected)
}),
timeout(30000),
take(1),
)
const updateSub$ = this.patchDb.sync$() this.patchSub = this.patchDb.sync$()
.pipe( .pipe(
debounceTime(500), debounceTime(400),
tap(cache => { tap(cache => {
this.bootstrapper.update(cache) this.patchConnection$.next(PatchConnection.Connected)
}), this.bootstrapper.update(cache)
) }),
)
this.patchSub = combineLatest([connectedSub$, updateSub$]) .subscribe({
.subscribe({ error: async e => {
error: async e => { console.error('patch-db SYNC ERROR', e)
console.error('patch-db-sync sub ERROR', e) this.patchConnection$.next(PatchConnection.Disconnected)
this.patchConnection$.next(PatchConnection.Disconnected) await pauseFor(4000)
console.log('Erroring out') this.start()
await pauseFor(4000) },
this.start() complete: () => {
}, console.warn('patch-db SYNC COMPLETE')
complete: () => { },
console.warn('patch-db-sync sub COMPLETE') })
},
})
} catch (e) {
console.error('Failed to initialize PatchDB', e)
}
} }
stop (): void { stop (): void {
console.log('STOPPING PATCH DB') console.log('stopping patch-db')
this.patchConnection$.next(PatchConnection.Initializing) this.patchConnection$.next(PatchConnection.Initializing)
this.patchDb.store.reset() this.patchDb.store.reset()
if (this.patchSub) { if (this.patchSub) {
@@ -109,7 +96,7 @@ export class PatchDbService {
.pipe( .pipe(
tap(data => console.log('NEW VALUE', data, ...args)), tap(data => console.log('NEW VALUE', data, ...args)),
catchError(e => { catchError(e => {
console.error('Error watching Patch DB', e) console.error('Error watching patch-db', e)
return of(e.message) return of(e.message)
}), }),
finalize(() => console.log('UNSUBSCRIBING', ...args)), finalize(() => console.log('UNSUBSCRIBING', ...args)),