mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
update display obj on union change (#2224)
* update display obj on union change * deelete unnecessary changes * more efficient * fix: properly change height of form object * more config examples --------- Co-authored-by: waterplea <alexander@inkin.ru>
This commit is contained in:
@@ -22,8 +22,7 @@
|
|||||||
[formControlName]="entry.key"
|
[formControlName]="entry.key"
|
||||||
(ionFocus)="presentAlertChangeWarning(entry.key, spec)"
|
(ionFocus)="presentAlertChangeWarning(entry.key, spec)"
|
||||||
(ionChange)="handleInputChange()"
|
(ionChange)="handleInputChange()"
|
||||||
>
|
></ion-textarea>
|
||||||
</ion-textarea>
|
|
||||||
<ng-template #notTextArea>
|
<ng-template #notTextArea>
|
||||||
<ion-input
|
<ion-input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -38,8 +37,7 @@
|
|||||||
[formControlName]="entry.key"
|
[formControlName]="entry.key"
|
||||||
(ionFocus)="presentAlertChangeWarning(entry.key, spec)"
|
(ionFocus)="presentAlertChangeWarning(entry.key, spec)"
|
||||||
(ionChange)="handleInputChange()"
|
(ionChange)="handleInputChange()"
|
||||||
>
|
></ion-input>
|
||||||
</ion-input>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ion-button
|
<ion-button
|
||||||
*ngIf="spec.type === 'string' && spec.masked"
|
*ngIf="spec.type === 'string' && spec.masked"
|
||||||
@@ -59,8 +57,9 @@
|
|||||||
slot="end"
|
slot="end"
|
||||||
color="light"
|
color="light"
|
||||||
style="font-size: medium"
|
style="font-size: medium"
|
||||||
>{{ spec.units }}</ion-note
|
|
||||||
>
|
>
|
||||||
|
{{ spec.units }}
|
||||||
|
</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<p class="error-message">
|
<p class="error-message">
|
||||||
<span *ngIf="(formGroup | getControl: entry.key).errors as errors">
|
<span *ngIf="(formGroup | getControl: entry.key).errors as errors">
|
||||||
@@ -92,11 +91,11 @@
|
|||||||
*ngIf="original?.[entry.key] === undefined"
|
*ngIf="original?.[entry.key] === undefined"
|
||||||
color="success"
|
color="success"
|
||||||
>
|
>
|
||||||
(New)</ion-text
|
(New)
|
||||||
>
|
</ion-text>
|
||||||
<ion-text *ngIf="entry.value.dirty" color="warning">
|
<ion-text *ngIf="entry.value.dirty" color="warning">
|
||||||
(Edited)</ion-text
|
(Edited)
|
||||||
>
|
</ion-text>
|
||||||
</b>
|
</b>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<!-- boolean -->
|
<!-- boolean -->
|
||||||
@@ -157,14 +156,9 @@
|
|||||||
></ion-icon>
|
></ion-icon>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<!-- body -->
|
<!-- body -->
|
||||||
<div
|
<tui-expand
|
||||||
|
[expanded]="objectDisplay[entry.key].expanded"
|
||||||
[id]="objectId | toElementId: entry.key"
|
[id]="objectId | toElementId: entry.key"
|
||||||
[ngStyle]="{
|
|
||||||
'max-height': objectDisplay[entry.key].height,
|
|
||||||
overflow: 'hidden',
|
|
||||||
'transition-property': 'max-height',
|
|
||||||
'transition-duration': '.42s'
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<div class="nested-wrapper">
|
<div class="nested-wrapper">
|
||||||
<form-object
|
<form-object
|
||||||
@@ -172,11 +166,10 @@
|
|||||||
[formGroup]="$any(entry.value)"
|
[formGroup]="$any(entry.value)"
|
||||||
[current]="current?.[entry.key]"
|
[current]="current?.[entry.key]"
|
||||||
[original]="original?.[entry.key]"
|
[original]="original?.[entry.key]"
|
||||||
(onResize)="resize(entry.key)"
|
|
||||||
(hasNewOptions)="setHasNew(entry.key)"
|
(hasNewOptions)="setHasNew(entry.key)"
|
||||||
></form-object>
|
></form-object>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</tui-expand>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- union -->
|
<!-- union -->
|
||||||
<form-union
|
<form-union
|
||||||
@@ -259,15 +252,10 @@
|
|||||||
></ion-icon>
|
></ion-icon>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<!-- object/union body -->
|
<!-- object/union body -->
|
||||||
<div
|
<tui-expand
|
||||||
style="padding-left: 24px"
|
style="padding-left: 24px"
|
||||||
|
[expanded]="objectListDisplay[entry.key][i].expanded"
|
||||||
[id]="objectId | toElementId: entry.key:i"
|
[id]="objectId | toElementId: entry.key:i"
|
||||||
[ngStyle]="{
|
|
||||||
'max-height': objectListDisplay[entry.key][i].height,
|
|
||||||
overflow: 'hidden',
|
|
||||||
'transition-property': 'max-height',
|
|
||||||
'transition-duration': '.42s'
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<form-object
|
<form-object
|
||||||
*ngIf="spec.subtype === 'object'"
|
*ngIf="spec.subtype === 'object'"
|
||||||
@@ -278,7 +266,6 @@
|
|||||||
(onInputChange)="
|
(onInputChange)="
|
||||||
updateLabel(entry.key, i, $any(spec.spec)['display-as'])
|
updateLabel(entry.key, i, $any(spec.spec)['display-as'])
|
||||||
"
|
"
|
||||||
(onResize)="resize(entry.key, i)"
|
|
||||||
></form-object>
|
></form-object>
|
||||||
<form-union
|
<form-union
|
||||||
*ngIf="spec.subtype === 'union'"
|
*ngIf="spec.subtype === 'union'"
|
||||||
@@ -289,7 +276,6 @@
|
|||||||
(onInputChange)="
|
(onInputChange)="
|
||||||
updateLabel(entry.key, i, $any(spec.spec)['display-as'])
|
updateLabel(entry.key, i, $any(spec.spec)['display-as'])
|
||||||
"
|
"
|
||||||
(onResize)="resize(entry.key, i)"
|
|
||||||
></form-union>
|
></form-union>
|
||||||
<div style="text-align: right; padding-top: 12px">
|
<div style="text-align: right; padding-top: 12px">
|
||||||
<ion-button
|
<ion-button
|
||||||
@@ -301,7 +287,7 @@
|
|||||||
Delete
|
Delete
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</tui-expand>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- string or number -->
|
<!-- string or number -->
|
||||||
<div
|
<div
|
||||||
@@ -318,8 +304,7 @@
|
|||||||
$any(spec.spec).placeholder || 'Enter ' + spec.name
|
$any(spec.spec).placeholder || 'Enter ' + spec.name
|
||||||
"
|
"
|
||||||
[formControlName]="i"
|
[formControlName]="i"
|
||||||
>
|
></ion-input>
|
||||||
</ion-input>
|
|
||||||
<ion-button
|
<ion-button
|
||||||
strong
|
strong
|
||||||
fill="clear"
|
fill="clear"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
|||||||
import { SharedPipesModule } from '@start9labs/shared'
|
import { SharedPipesModule } from '@start9labs/shared'
|
||||||
import { TuiElasticContainerModule } from '@taiga-ui/kit'
|
import { TuiElasticContainerModule } from '@taiga-ui/kit'
|
||||||
import { EnumListPageModule } from 'src/app/modals/enum-list/enum-list.module'
|
import { EnumListPageModule } from 'src/app/modals/enum-list/enum-list.module'
|
||||||
|
import { TuiExpandModule } from '@taiga-ui/core'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -39,6 +40,7 @@ import { EnumListPageModule } from 'src/app/modals/enum-list/enum-list.module'
|
|||||||
SharedPipesModule,
|
SharedPipesModule,
|
||||||
EnumListPageModule,
|
EnumListPageModule,
|
||||||
TuiElasticContainerModule,
|
TuiElasticContainerModule,
|
||||||
|
TuiExpandModule,
|
||||||
],
|
],
|
||||||
exports: [FormObjectComponent, FormLabelComponent],
|
exports: [FormObjectComponent, FormLabelComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Inject,
|
Inject,
|
||||||
inject,
|
inject,
|
||||||
|
SimpleChanges,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms'
|
import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms'
|
||||||
import { AlertButton, AlertController, ModalController } from '@ionic/angular'
|
import { AlertButton, AlertController, ModalController } from '@ionic/angular'
|
||||||
@@ -41,15 +42,14 @@ export class FormObjectComponent {
|
|||||||
@Input() current?: Config
|
@Input() current?: Config
|
||||||
@Input() original?: Config
|
@Input() original?: Config
|
||||||
@Output() onInputChange = new EventEmitter<void>()
|
@Output() onInputChange = new EventEmitter<void>()
|
||||||
@Output() onResize = new EventEmitter<void>()
|
|
||||||
@Output() hasNewOptions = new EventEmitter<void>()
|
@Output() hasNewOptions = new EventEmitter<void>()
|
||||||
warningAck: { [key: string]: boolean } = {}
|
warningAck: { [key: string]: boolean } = {}
|
||||||
unmasked: { [key: string]: boolean } = {}
|
unmasked: { [key: string]: boolean } = {}
|
||||||
objectDisplay: {
|
objectDisplay: {
|
||||||
[key: string]: { expanded: boolean; height: string; hasNewOptions: boolean }
|
[key: string]: { expanded: boolean; hasNewOptions: boolean }
|
||||||
} = {}
|
} = {}
|
||||||
objectListDisplay: {
|
objectListDisplay: {
|
||||||
[key: string]: { expanded: boolean; height: string; displayAs: string }[]
|
[key: string]: { expanded: boolean; displayAs: string }[]
|
||||||
} = {}
|
} = {}
|
||||||
objectId = v4()
|
objectId = v4()
|
||||||
|
|
||||||
@@ -63,6 +63,37 @@ export class FormObjectComponent {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.setDisplays()
|
||||||
|
|
||||||
|
// setTimeout hack to avoid ExpressionChangedAfterItHasBeenCheckedError
|
||||||
|
setTimeout(() => {
|
||||||
|
if (
|
||||||
|
this.original &&
|
||||||
|
Object.keys(this.current || {}).some(
|
||||||
|
key => this.original![key] === undefined,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
this.hasNewOptions.emit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
const specChanges = changes['objectSpec']
|
||||||
|
|
||||||
|
if (!specChanges) return
|
||||||
|
|
||||||
|
if (
|
||||||
|
!specChanges.firstChange &&
|
||||||
|
Object.keys({
|
||||||
|
...specChanges.previousValue,
|
||||||
|
...specChanges.currentValue,
|
||||||
|
}).length !== Object.keys(specChanges.previousValue).length
|
||||||
|
) {
|
||||||
|
this.setDisplays()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setDisplays() {
|
||||||
Object.keys(this.objectSpec).forEach(key => {
|
Object.keys(this.objectSpec).forEach(key => {
|
||||||
const spec = this.objectSpec[key]
|
const spec = this.objectSpec[key]
|
||||||
|
|
||||||
@@ -74,7 +105,6 @@ export class FormObjectComponent {
|
|||||||
]
|
]
|
||||||
this.objectListDisplay[key][index] = {
|
this.objectListDisplay[key][index] = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
height: '0px',
|
|
||||||
displayAs: displayAs
|
displayAs: displayAs
|
||||||
? (Mustache as any).render(displayAs, obj)
|
? (Mustache as any).render(displayAs, obj)
|
||||||
: '',
|
: '',
|
||||||
@@ -83,33 +113,10 @@ export class FormObjectComponent {
|
|||||||
} else if (spec.type === 'object') {
|
} else if (spec.type === 'object') {
|
||||||
this.objectDisplay[key] = {
|
this.objectDisplay[key] = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
height: '0px',
|
|
||||||
hasNewOptions: false,
|
hasNewOptions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// setTimeout hack to avoid ExpressionChangedAfterItHasBeenCheckedError
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.original) {
|
|
||||||
Object.keys(this.current || {}).forEach(key => {
|
|
||||||
if ((this.original as Config)[key] === undefined) {
|
|
||||||
this.hasNewOptions.emit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
resize(key: string, i?: number): void {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (i !== undefined) {
|
|
||||||
this.objectListDisplay[key][i].height = this.getScrollHeight(key, i)
|
|
||||||
} else {
|
|
||||||
this.objectDisplay[key].height = this.getScrollHeight(key)
|
|
||||||
}
|
|
||||||
this.onResize.emit()
|
|
||||||
}, 250) // 250 to match transition-duration defined in html, for smooth recursive resize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addListItemWrapper<T extends ValueSpec>(
|
addListItemWrapper<T extends ValueSpec>(
|
||||||
@@ -121,20 +128,11 @@ export class FormObjectComponent {
|
|||||||
|
|
||||||
toggleExpandObject(key: string) {
|
toggleExpandObject(key: string) {
|
||||||
this.objectDisplay[key].expanded = !this.objectDisplay[key].expanded
|
this.objectDisplay[key].expanded = !this.objectDisplay[key].expanded
|
||||||
this.objectDisplay[key].height = this.objectDisplay[key].expanded
|
|
||||||
? this.getScrollHeight(key)
|
|
||||||
: '0px'
|
|
||||||
this.onResize.emit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleExpandListObject(key: string, i: number) {
|
toggleExpandListObject(key: string, i: number) {
|
||||||
this.objectListDisplay[key][i].expanded =
|
this.objectListDisplay[key][i].expanded =
|
||||||
!this.objectListDisplay[key][i].expanded
|
!this.objectListDisplay[key][i].expanded
|
||||||
this.objectListDisplay[key][i].height = this.objectListDisplay[key][i]
|
|
||||||
.expanded
|
|
||||||
? this.getScrollHeight(key, i)
|
|
||||||
: '0px'
|
|
||||||
this.onResize.emit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLabel(key: string, i: number, displayAs: string) {
|
updateLabel(key: string, i: number, displayAs: string) {
|
||||||
@@ -275,7 +273,6 @@ export class FormObjectComponent {
|
|||||||
'display-as'
|
'display-as'
|
||||||
]
|
]
|
||||||
this.objectListDisplay[key].push({
|
this.objectListDisplay[key].push({
|
||||||
height: '0px',
|
|
||||||
expanded: false,
|
expanded: false,
|
||||||
displayAs: displayAs ? Mustache.render(displayAs, newItem.value) : '',
|
displayAs: displayAs ? Mustache.render(displayAs, newItem.value) : '',
|
||||||
})
|
})
|
||||||
@@ -296,8 +293,8 @@ export class FormObjectComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private deleteListItem(key: string, index: number, markDirty = true): void {
|
private deleteListItem(key: string, index: number, markDirty = true): void {
|
||||||
if (this.objectListDisplay[key])
|
// if (this.objectListDisplay[key])
|
||||||
this.objectListDisplay[key][index].height = '0px'
|
// this.objectListDisplay[key][index].height = '0px'
|
||||||
const arr = this.formGroup.get(key) as UntypedFormArray
|
const arr = this.formGroup.get(key) as UntypedFormArray
|
||||||
if (markDirty) arr.markAsDirty()
|
if (markDirty) arr.markAsDirty()
|
||||||
pauseFor(250).then(() => {
|
pauseFor(250).then(() => {
|
||||||
@@ -328,13 +325,6 @@ export class FormObjectComponent {
|
|||||||
arr.markAsDirty()
|
arr.markAsDirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
private getScrollHeight(key: string, index = 0): string {
|
|
||||||
const element = this.document.getElementById(
|
|
||||||
getElementId(this.objectId, key, index),
|
|
||||||
)
|
|
||||||
return `${element?.scrollHeight}px`
|
|
||||||
}
|
|
||||||
|
|
||||||
asIsOrder() {
|
asIsOrder() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -352,8 +342,6 @@ export class FormUnionComponent {
|
|||||||
@Input() current?: Config
|
@Input() current?: Config
|
||||||
@Input() original?: Config
|
@Input() original?: Config
|
||||||
|
|
||||||
@Output() onResize = new EventEmitter<void>()
|
|
||||||
|
|
||||||
get unionValue() {
|
get unionValue() {
|
||||||
return this.formGroup.get(this.spec.tag.id)?.value
|
return this.formGroup.get(this.spec.tag.id)?.value
|
||||||
}
|
}
|
||||||
@@ -374,10 +362,7 @@ export class FormUnionComponent {
|
|||||||
|
|
||||||
objectId = v4()
|
objectId = v4()
|
||||||
|
|
||||||
constructor(
|
constructor(private readonly formService: FormService) {}
|
||||||
private readonly formService: FormService,
|
|
||||||
@Inject(DOCUMENT) private readonly document: Document,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
updateUnion(e: any): void {
|
updateUnion(e: any): void {
|
||||||
const tagId = this.spec.tag.id
|
const tagId = this.spec.tag.id
|
||||||
@@ -397,12 +382,6 @@ export class FormUnionComponent {
|
|||||||
this.formGroup.addControl(control, unionGroup.controls[control])
|
this.formGroup.addControl(control, unionGroup.controls[control])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
resize(): void {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.onResize.emit()
|
|
||||||
}, 250) // 250 to match transition-duration, defined in html
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
[formGroup]="formGroup"
|
[formGroup]="formGroup"
|
||||||
[current]="current"
|
[current]="current"
|
||||||
[original]="original"
|
[original]="original"
|
||||||
(onResize)="resize()"
|
|
||||||
></form-object>
|
></form-object>
|
||||||
</tui-elastic-container>
|
</tui-elastic-container>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1169,6 +1169,113 @@ export module Mock {
|
|||||||
} as any // @TODO why is this necessary?
|
} as any // @TODO why is this necessary?
|
||||||
|
|
||||||
export const ConfigSpec: RR.GetPackageConfigRes['spec'] = {
|
export const ConfigSpec: RR.GetPackageConfigRes['spec'] = {
|
||||||
|
bitcoin: {
|
||||||
|
type: 'object',
|
||||||
|
name: 'Bitcoin Settings',
|
||||||
|
description:
|
||||||
|
'RPC and P2P interface configuration options for Bitcoin Core',
|
||||||
|
spec: {
|
||||||
|
'bitcoind-p2p': {
|
||||||
|
type: 'union',
|
||||||
|
tag: {
|
||||||
|
id: 'type',
|
||||||
|
name: 'Bitcoin Core P2P',
|
||||||
|
description:
|
||||||
|
'<p>The Bitcoin Core node to connect to over the peer-to-peer (P2P) interface:</p><ul><li><strong>Bitcoin Core</strong>: The Bitcoin Core service installed on this device</li><li><strong>External Node</strong>: A Bitcoin node running on a different device</li></ul>',
|
||||||
|
'variant-names': {
|
||||||
|
internal: 'Bitcoin Core',
|
||||||
|
external: 'External Node',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: 'internal',
|
||||||
|
variants: {
|
||||||
|
internal: {},
|
||||||
|
external: {
|
||||||
|
'p2p-host': {
|
||||||
|
type: 'string',
|
||||||
|
name: 'Public Address',
|
||||||
|
description: 'The public address of your Bitcoin Core server',
|
||||||
|
nullable: false,
|
||||||
|
masked: false,
|
||||||
|
copyable: false,
|
||||||
|
},
|
||||||
|
'p2p-port': {
|
||||||
|
type: 'number',
|
||||||
|
name: 'P2P Port',
|
||||||
|
description:
|
||||||
|
'The port that your Bitcoin Core P2P server is bound to',
|
||||||
|
nullable: false,
|
||||||
|
range: '[0,65535]',
|
||||||
|
integral: true,
|
||||||
|
default: 8333,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
advanced: {
|
||||||
|
name: 'Advanced',
|
||||||
|
type: 'object',
|
||||||
|
description: 'Advanced settings',
|
||||||
|
spec: {
|
||||||
|
rpcsettings: {
|
||||||
|
name: 'RPC Settings',
|
||||||
|
type: 'object',
|
||||||
|
description: 'rpc username and password',
|
||||||
|
warning:
|
||||||
|
'Adding RPC users gives them special permissions on your node.',
|
||||||
|
spec: {
|
||||||
|
rpcuser2: {
|
||||||
|
name: 'RPC Username',
|
||||||
|
type: 'string',
|
||||||
|
description: 'rpc username',
|
||||||
|
nullable: false,
|
||||||
|
default: 'defaultrpcusername',
|
||||||
|
pattern: '^[a-zA-Z]+$',
|
||||||
|
'pattern-description': 'must contain only letters.',
|
||||||
|
masked: false,
|
||||||
|
copyable: true,
|
||||||
|
},
|
||||||
|
rpcuser: {
|
||||||
|
name: 'RPC Username',
|
||||||
|
type: 'string',
|
||||||
|
description: 'rpc username',
|
||||||
|
nullable: false,
|
||||||
|
default: 'defaultrpcusername',
|
||||||
|
pattern: '^[a-zA-Z]+$',
|
||||||
|
'pattern-description': 'must contain only letters.',
|
||||||
|
masked: false,
|
||||||
|
copyable: true,
|
||||||
|
},
|
||||||
|
rpcpass: {
|
||||||
|
name: 'RPC User Password',
|
||||||
|
type: 'string',
|
||||||
|
description: 'rpc password',
|
||||||
|
nullable: false,
|
||||||
|
default: {
|
||||||
|
charset: 'a-z,A-Z,2-9',
|
||||||
|
len: 20,
|
||||||
|
},
|
||||||
|
masked: true,
|
||||||
|
copyable: true,
|
||||||
|
},
|
||||||
|
rpcpass2: {
|
||||||
|
name: 'RPC User Password',
|
||||||
|
type: 'string',
|
||||||
|
description: 'rpc password',
|
||||||
|
nullable: false,
|
||||||
|
default: {
|
||||||
|
charset: 'a-z,A-Z,2-9',
|
||||||
|
len: 20,
|
||||||
|
},
|
||||||
|
masked: true,
|
||||||
|
copyable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
testnet: {
|
testnet: {
|
||||||
name: 'Testnet',
|
name: 'Testnet',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@@ -1449,6 +1556,29 @@ export module Mock {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
external: {
|
external: {
|
||||||
|
'emergency-contact': {
|
||||||
|
name: 'Emergency Contact',
|
||||||
|
type: 'object',
|
||||||
|
description: 'The person to contact in case of emergency.',
|
||||||
|
spec: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
name: 'Name',
|
||||||
|
nullable: false,
|
||||||
|
masked: false,
|
||||||
|
copyable: false,
|
||||||
|
pattern: '^[a-zA-Z]+$',
|
||||||
|
'pattern-description': 'Must contain only letters.',
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
name: 'Email',
|
||||||
|
nullable: false,
|
||||||
|
masked: false,
|
||||||
|
copyable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
'public-domain': {
|
'public-domain': {
|
||||||
name: 'Public Domain',
|
name: 'Public Domain',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -1520,8 +1650,8 @@ export module Mock {
|
|||||||
copyable: false,
|
copyable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
advanced: {
|
'more-advanced': {
|
||||||
name: 'Advanced',
|
name: 'More Advanced',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
description: 'Advanced settings',
|
description: 'Advanced settings',
|
||||||
spec: {
|
spec: {
|
||||||
@@ -1726,8 +1856,7 @@ export module Mock {
|
|||||||
rulemakers: [],
|
rulemakers: [],
|
||||||
},
|
},
|
||||||
'bitcoin-node': {
|
'bitcoin-node': {
|
||||||
type: 'external',
|
type: 'internal',
|
||||||
'public-domain': 'hello.com',
|
|
||||||
},
|
},
|
||||||
port: 20,
|
port: 20,
|
||||||
rpcallowip: undefined,
|
rpcallowip: undefined,
|
||||||
|
|||||||
@@ -21,13 +21,17 @@ export class ThemeSwitcherService extends BehaviorSubject<string> {
|
|||||||
.watch$('ui', 'theme')
|
.watch$('ui', 'theme')
|
||||||
.pipe(take(1), filter(Boolean))
|
.pipe(take(1), filter(Boolean))
|
||||||
.subscribe(theme => {
|
.subscribe(theme => {
|
||||||
this.next(theme)
|
this.updateTheme(theme)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override next(currentTheme: string): void {
|
override next(theme: string): void {
|
||||||
this.embassyApi.setDbValue(['theme'], currentTheme)
|
this.embassyApi.setDbValue(['theme'], theme)
|
||||||
this.windowRef.document.body.setAttribute('data-theme', currentTheme)
|
this.updateTheme(theme)
|
||||||
super.next(currentTheme)
|
}
|
||||||
|
|
||||||
|
private updateTheme(theme: string): void {
|
||||||
|
this.windowRef.document.body.setAttribute('data-theme', theme)
|
||||||
|
super.next(theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user