* begin subnav implementation

* implement subnav AND angular forms for comparison

* unions working-ish, list of enums working

* new form approach almost complete

* finish new forms approach for action inputs and config

* expandable list items and handlebars display

* Config animation (#394)

* config cammel

* config animation

Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com>

* improve server settings inputs, still needs work

* delete all notifications, styling, and bugs

* contracted by default

Co-authored-by: Drew Ansbacher <drew.ansbacher@gmail.com>
Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com>
This commit is contained in:
Matt Hill
2021-08-06 09:25:20 -06:00
committed by Aiden McClelland
parent a43ff976a2
commit 5741cf084f
117 changed files with 1967 additions and 1271 deletions

View File

@@ -93,9 +93,9 @@ export class ConfigCursor<T extends ValueType> {
case 'number':
return `${config}${spec.units ? ' ' + spec.units : ''}`
case 'object':
return spec.displayAs ? handlebars.compile(spec.displayAs)(config) : ''
return spec['display-as'] ? handlebars.compile(spec['display-as'])(config) : ''
case 'union':
return spec.displayAs ? handlebars.compile(spec.displayAs)(config) : config[spec.tag.id]
return spec['display-as'] ? handlebars.compile(spec['display-as'])(config) : config[spec.tag.id]
case 'pointer':
return 'System Defined'
default:
@@ -121,11 +121,9 @@ export class ConfigCursor<T extends ValueType> {
let ret: ValueSpec = {
type: 'object',
spec: this.rootSpec,
nullable: false,
nullByDefault: false,
name: 'Config',
displayAs: 'Config',
uniqueBy: null,
'display-as': 'Config',
'unique-by': null,
}
let ptr = []
for (let seg of parsed) {
@@ -141,7 +139,7 @@ export class ConfigCursor<T extends ValueType> {
values: Object.keys(ret.variants),
name: ret.tag.name,
description: ret.tag.description,
valueNames: ret.tag.variantNames,
'value-names': ret.tag['variant-names'],
}
} else {
const cfg = this.unseek().seek(pointer.compile(ptr))
@@ -176,7 +174,7 @@ export class ConfigCursor<T extends ValueType> {
if (!spec.pattern || new RegExp(spec.pattern).test(cfg)) {
return null
} else {
return spec.patternDescription
return spec['pattern-description']
}
} else {
throw new TypeError(`${this.ptr}: expected string, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
@@ -205,8 +203,8 @@ export class ConfigCursor<T extends ValueType> {
}
case 'enum':
if (typeof cfg === 'string') {
spec.valuesSet = spec.valuesSet || new Set(spec.values)
return spec.valuesSet.has(cfg) ? null : `${cfg} is not a valid selection.`
spec['values-set'] = spec['values-set'] || new Set(spec.values)
return spec['values-set'].has(cfg) ? null : `${cfg} is not a valid selection.`
} else {
throw new TypeError(`${this.ptr}: expected string, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
}
@@ -233,7 +231,7 @@ export class ConfigCursor<T extends ValueType> {
if (cursor.equals(this.seekNext(idx2))) {
return `Item #${idx + 1} is not unique.` + ('uniqueBy' in cursor.spec()) ? `${
displayUniqueBy(
(cursor.spec() as ValueSpecObject | ValueSpecUnion).uniqueBy,
(cursor.spec() as ValueSpecObject | ValueSpecUnion)['unique-by'],
(cursor.spec() as ValueSpecObject | ValueSpecUnion),
cursor.config(),
)
@@ -247,7 +245,7 @@ export class ConfigCursor<T extends ValueType> {
}
case 'object':
if (!cfg) {
return spec.nullable ? null : `${spec.name} is missing.`
return `${spec.name} is missing.`
} else if (typeof cfg === 'object' && !Array.isArray(cfg)) {
for (let idx in spec.spec) {
if (this.seekNext(idx).checkInvalid()) {
@@ -328,7 +326,7 @@ export class ConfigCursor<T extends ValueType> {
return lhs === rhs
case 'object':
case 'union':
return isEqual(spec.uniqueBy, this as ConfigCursor<'object' | 'union'>, cursor as ConfigCursor<'object' | 'union'>)
return isEqual(spec['unique-by'], this as ConfigCursor<'object' | 'union'>, cursor as ConfigCursor<'object' | 'union'>)
case 'list':
if (lhs.length !== rhs.length) {
return false

View File

@@ -52,14 +52,12 @@ export interface ValueSpecPointer extends WithStandalone {
export interface ValueSpecObject extends ListValueSpecObject, WithStandalone {
type: 'object'
nullable: boolean
nullByDefault: boolean
}
export interface WithStandalone {
name: string
description?: string
changeWarning?: string
'change-warning'?: string
}
// no lists of booleans, lists, pointers
@@ -90,8 +88,9 @@ export function isValueSpecListOf<S extends ListValueSpecType> (t: ValueSpecList
}
export interface ListValueSpecString {
// @TODO add masked?
pattern?: string
patternDescription?: string
'pattern-description'?: string
}
export interface ListValueSpecNumber {
@@ -102,14 +101,14 @@ export interface ListValueSpecNumber {
export interface ListValueSpecEnum {
values: string[]
valuesSet?: Set<string>
valueNames: { [value: string]: string }
'values-set'?: Set<string>
'value-names': { [value: string]: string }
}
export interface ListValueSpecObject {
spec: ConfigSpec //this is a mapped type of the config object at this level, replacing the object's values with specs on those values
uniqueBy: UniqueBy //indicates whether duplicates can be permitted in the list
displayAs?: string //this should be a handlebars template which can make use of the entire config which corresponds to 'spec'
spec: ConfigSpec // this is a mapped type of the config object at this level, replacing the object's values with specs on those values
'unique-by': UniqueBy // indicates whether duplicates can be permitted in the list
'display-as'?: string // this should be a handlebars template which can make use of the entire config which corresponds to 'spec'
}
export type UniqueBy = null | string | { any: UniqueBy[] } | { all: UniqueBy[] }
@@ -117,16 +116,16 @@ export type UniqueBy = null | string | { any: UniqueBy[] } | { all: UniqueBy[] }
export interface ListValueSpecUnion {
tag: UnionTagSpec
variants: { [key: string]: ConfigSpec }
displayAs?: string //this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id
uniqueBy: UniqueBy
default: string //this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list
'display-as'?: string // this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id
'unique-by': UniqueBy
default: string // this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list
}
export interface UnionTagSpec {
id: string //The name of the field containing one of the union variants
id: string // The name of the field containing one of the union variants
name: string
description?: string
variantNames: { //the name of each variant
'variant-names': { // the name of each variant
[variant: string]: string
}
}

View File

@@ -114,7 +114,7 @@ export function listInnerSpec (listSpec: ValueSpecList): ValueSpecOf<ListValueSp
nullable: false,
name: listSpec.name,
description: listSpec.description,
changeWarning: listSpec.changeWarning,
changeWarning: listSpec['change-warning'],
...listSpec.spec as any, //listSpec.spec is a ListValueSpecOf listSpec.subtype
}
}
@@ -162,7 +162,7 @@ export function mapUnionSpec (spec: ValueSpecUnion, value: any): object {
type: 'enum',
default: spec.default,
values: Object.keys(spec.variants),
valueNames: spec.tag.variantNames,
'value-names': spec.tag['variant-names'],
}, value[spec.tag.id])
value = mapConfigSpec(spec.variants[variant], value)
value[spec.tag.id] = variant
@@ -216,7 +216,7 @@ export function mapBooleanSpec (spec: ValueSpecBoolean, value: any): boolean {
export function getDefaultConfigValue (spec: ValueSpec): string | number | object | string[] | number[] | object[] | boolean | null {
switch (spec.type) {
case 'object':
return spec.nullByDefault ? null : getDefaultObject(spec.spec)
return getDefaultObject(spec.spec)
case 'union':
return getDefaultUnion(spec)
case 'string':
@@ -306,7 +306,7 @@ export function getDefaultDescription (spec: ValueSpec): string {
toReturn = spec.default === true ? 'True' : 'False'
break
case 'enum':
toReturn = spec.valueNames[spec.default]
toReturn = spec['value-names'][spec.default]
break
}

View File

@@ -1,30 +0,0 @@
import { ConfigCursor } from './config-cursor'
import { TrackingModalController } from '../services/tracking-modal-controller.service'
export class ModalPresentable {
constructor (
private readonly trackingModalCtrl: TrackingModalController,
) { }
async presentModal (cursor: ConfigCursor<any>, callback: () => any) {
const modal = await this.trackingModalCtrl.createConfigModal({
backdropDismiss: false,
presentingElement: await this.trackingModalCtrl.getTop(),
componentProps: {
cursor,
},
}, cursor.spec().type)
modal.onWillDismiss().then(res => {
cursor.injectModalData(res)
callback()
})
await modal.present()
}
dismissModal (a: any) {
return this.trackingModalCtrl.dismiss(a)
}
}