mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Subnav (#391)
* 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:
committed by
Aiden McClelland
parent
a43ff976a2
commit
5741cf084f
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user