mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
bug fixes and cosmetic improvements
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 => {
|
||||||
|
|||||||
@@ -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;">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
.selected {
|
.selected {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dim {
|
.dim {
|
||||||
|
|||||||
@@ -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)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
Reference in New Issue
Block a user