automatically clean up defaults from the config file

This commit is contained in:
Eugene Pankov
2021-07-11 00:06:52 +02:00
parent 67bbbd7f65
commit 908f90cd52
11 changed files with 155 additions and 44 deletions

View File

@@ -20,7 +20,7 @@ export { ProfileProvider, Profile, ProfileSettingsComponent } from './profilePro
export { PromptModalComponent } from '../components/promptModal.component'
export { AppService } from '../services/app.service'
export { ConfigService } from '../services/config.service'
export { ConfigService, configMerge, ConfigProxy } from '../services/config.service'
export { DockingService, Screen } from '../services/docking.service'
export { Logger, ConsoleLogger, LogService } from '../services/log.service'
export { HomeBaseService } from '../services/homeBase.service'

View File

@@ -29,6 +29,7 @@ export abstract class ProfileProvider {
name: string
supportsQuickConnect = false
settingsComponent: new (...args: any[]) => ProfileSettingsComponent
configDefaults = {}
abstract getBuiltinProfiles (): Promise<Profile[]>

View File

@@ -1,3 +1,4 @@
import deepEqual from 'deep-equal'
import { v4 as uuidv4 } from 'uuid'
import * as yaml from 'js-yaml'
import { Observable, Subject, AsyncSubject } from 'rxjs'
@@ -8,7 +9,8 @@ import { HostAppService } from '../api/hostApp'
import { Vault, VaultService } from './vault.service'
const deepmerge = require('deepmerge')
const configMerge = (a, b) => deepmerge(a, b, { arrayMerge: (_d, s) => s }) // eslint-disable-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const configMerge = (a, b) => deepmerge(a, b, { arrayMerge: (_d, s) => s }) // eslint-disable-line @typescript-eslint/no-var-requires
const LATEST_VERSION = 1
@@ -46,24 +48,24 @@ export class ConfigProxy {
{
enumerable: true,
configurable: false,
get: () => this.getValue(key),
get: () => this.__getValue(key),
set: (value) => {
this.setValue(key, value)
this.__setValue(key, value)
},
}
)
}
}
this.getValue = (key: string) => { // eslint-disable-line @typescript-eslint/unbound-method
this.__getValue = (key: string) => { // eslint-disable-line @typescript-eslint/unbound-method
if (real[key] !== undefined) {
return real[key]
} else {
return this.getDefault(key)
return this.__getDefault(key)
}
}
this.getDefault = (key: string) => { // eslint-disable-line @typescript-eslint/unbound-method
this.__getDefault = (key: string) => { // eslint-disable-line @typescript-eslint/unbound-method
if (isNonStructuralObjectMember(defaults[key])) {
real[key] = { ...defaults[key] }
delete real[key].__nonStructural
@@ -73,22 +75,36 @@ export class ConfigProxy {
}
}
this.setValue = (key: string, value: any) => { // eslint-disable-line @typescript-eslint/unbound-method
if (value === this.getDefault(key)) {
this.__setValue = (key: string, value: any) => { // eslint-disable-line @typescript-eslint/unbound-method
if (deepEqual(value, this.__getDefault(key))) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete real[key]
} else {
real[key] = value
}
}
this.__cleanup = () => { // eslint-disable-line @typescript-eslint/unbound-method
// Trigger removal of default values
for (const key in defaults) {
if (isStructuralMember(defaults[key])) {
this[key].__cleanup()
} else {
const v = this.__getValue(key)
this.__setValue(key, v)
}
}
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
getValue (_key: string): any { }
__getValue (_key: string): any { }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
setValue (_key: string, _value: any) { }
__setValue (_key: string, _value: any) { }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
getDefault (_key: string): any { }
__getDefault (_key: string): any { }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
__cleanup () { }
}
@Injectable({ providedIn: 'root' })
@@ -177,6 +193,7 @@ export class ConfigService {
}
async save (): Promise<void> {
this.store.__cleanup()
// Scrub undefined values
let cleanStore = JSON.parse(JSON.stringify(this._store))
cleanStore = await this.maybeEncryptConfig(cleanStore)

View File

@@ -4,12 +4,26 @@ import { BaseTabComponent } from '../components/baseTab.component'
import { Profile, ProfileProvider } from '../api/profileProvider'
import { SelectorOption } from '../api/selector'
import { AppService } from './app.service'
import { ConfigService } from './config.service'
import { configMerge, ConfigProxy, ConfigService } from './config.service'
import { NotificationsService } from './notifications.service'
import { SelectorService } from './selector.service'
@Injectable({ providedIn: 'root' })
export class ProfilesService {
private profileDefaults = {
id: '',
type: '',
name: '',
group: '',
options: {},
icon: '',
color: '',
disableDynamicTitle: false,
weight: 0,
isBuiltin: false,
isTemplate: false,
}
constructor (
private app: AppService,
private config: ConfigService,
@@ -19,6 +33,7 @@ export class ProfilesService {
) { }
async openNewTabForProfile (profile: Profile): Promise<BaseTabComponent|null> {
profile = this.getConfigProxyForProfile(profile)
const params = await this.newTabParametersForProfile(profile)
if (params) {
const tab = this.app.openNewTab(params)
@@ -33,6 +48,7 @@ export class ProfilesService {
}
async newTabParametersForProfile (profile: Profile): Promise<NewTabParameters<BaseTabComponent>|null> {
profile = this.getConfigProxyForProfile(profile)
return this.providerForProfile(profile)?.getNewTabParameters(profile) ?? null
}
@@ -150,4 +166,10 @@ export class ProfilesService {
this.notifications.error(`Could not parse "${query}"`)
return null
}
getConfigProxyForProfile (profile: Profile): Profile {
const provider = this.providerForProfile(profile)
const defaults = configMerge(this.profileDefaults, provider?.configDefaults ?? {})
return new ConfigProxy(profile, defaults) as unknown as Profile
}
}