@morscherlab/mint-sdk 1.0.0-rc.2 → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AppSidebar.vue.d.ts +3 -3
- package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
- package/dist/components/PluginWorkspaceView.vue.d.ts +3 -3
- package/dist/components/index.js +2 -2
- package/dist/{components-BhK-dW99.js → components-DafPc4rM.js} +3 -3
- package/dist/{components-BhK-dW99.js.map → components-DafPc4rM.js.map} +1 -1
- package/dist/composables/controlComponentBindings.d.ts +7 -0
- package/dist/composables/controlSchemaAdapters.d.ts +20 -0
- package/dist/composables/controlSchemaFormFields.d.ts +3 -0
- package/dist/composables/controlSchemaLayout.d.ts +7 -0
- package/dist/composables/controlSchemaNormalize.d.ts +15 -0
- package/dist/composables/controlSchemaUtils.d.ts +9 -0
- package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
- package/dist/composables/index.js +3 -3
- package/dist/composables/useControlSchema.d.ts +4 -30
- package/dist/composables/useControlWorkspace.d.ts +5 -0
- package/dist/{composables-Bg7CFuNz.js → composables-BMkPQhVK.js} +2 -2
- package/dist/{composables-Bg7CFuNz.js.map → composables-BMkPQhVK.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/install.js +2 -2
- package/dist/templates/adapters.d.ts +14 -47
- package/dist/templates/assayLookups.d.ts +3 -0
- package/dist/templates/assayMatrixAdapters.d.ts +6 -0
- package/dist/templates/assayMatrixBuilder.d.ts +2 -0
- package/dist/templates/assayNormalizers.d.ts +4 -0
- package/dist/templates/builderDefaults.d.ts +1 -0
- package/dist/templates/builderIdUtils.d.ts +4 -0
- package/dist/templates/builderPresetControls.d.ts +10 -0
- package/dist/templates/builderReadUtils.d.ts +8 -0
- package/dist/templates/builders.d.ts +26 -67
- package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
- package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
- package/dist/templates/calibrationNormalizers.d.ts +5 -0
- package/dist/templates/componentBindingCatalog.d.ts +25 -0
- package/dist/templates/componentBindingHelpers.d.ts +17 -0
- package/dist/templates/componentDoseResponseProps.d.ts +3 -0
- package/dist/templates/componentGenericProps.d.ts +8 -0
- package/dist/templates/componentPlateHelpers.d.ts +5 -0
- package/dist/templates/componentPlateMapProps.d.ts +3 -0
- package/dist/templates/componentPropsFactory.d.ts +3 -0
- package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
- package/dist/templates/componentTargetResolvers.d.ts +5 -0
- package/dist/templates/componentTemplateProps.d.ts +3 -0
- package/dist/templates/controlSchemaClone.d.ts +4 -0
- package/dist/templates/controlSchemaConstants.d.ts +10 -0
- package/dist/templates/controlSchemaMerge.d.ts +3 -0
- package/dist/templates/controlSchemaTargets.d.ts +17 -0
- package/dist/templates/controlSchemaTypes.d.ts +4 -0
- package/dist/templates/controlSchemas.d.ts +4 -4
- package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
- package/dist/templates/doseResponseAdapters.d.ts +4 -0
- package/dist/templates/doseResponseBuilder.d.ts +2 -0
- package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
- package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
- package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
- package/dist/templates/flowNormalizers.d.ts +8 -0
- package/dist/templates/flowPanelAdapters.d.ts +4 -0
- package/dist/templates/index.js +1 -1
- package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
- package/dist/templates/instrumentRunAdapters.d.ts +8 -0
- package/dist/templates/instrumentRunBuilder.d.ts +2 -0
- package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
- package/dist/templates/plateGeometry.d.ts +4 -0
- package/dist/templates/plateMapAdapters.d.ts +3 -0
- package/dist/templates/plateMapBuilder.d.ts +2 -0
- package/dist/templates/presetControlSchemas.d.ts +534 -0
- package/dist/templates/protocolAdapters.d.ts +5 -0
- package/dist/templates/protocolNormalizers.d.ts +6 -0
- package/dist/templates/protocolStepsBuilder.d.ts +2 -0
- package/dist/templates/qpcrAdapters.d.ts +5 -0
- package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
- package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
- package/dist/templates/reagentAdapters.d.ts +5 -0
- package/dist/templates/reagentListBuilder.d.ts +2 -0
- package/dist/templates/runNormalizers.d.ts +10 -0
- package/dist/templates/sampleNormalizers.d.ts +4 -0
- package/dist/templates/samplePrepAdapters.d.ts +4 -0
- package/dist/templates/samplePrepBuilder.d.ts +2 -0
- package/dist/templates/sampleSheetAdapters.d.ts +5 -0
- package/dist/templates/sampleSheetBuilder.d.ts +2 -0
- package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
- package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
- package/dist/templates/templateControlSchemas.d.ts +400 -0
- package/dist/templates/templateEnvelopes.d.ts +9 -0
- package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
- package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
- package/dist/templates/templateValidators.d.ts +13 -0
- package/dist/templates/timeCourseAdapters.d.ts +5 -0
- package/dist/templates/timeCourseBuilder.d.ts +2 -0
- package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
- package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
- package/dist/{templates-BorLR_7p.js → templates-bUAWMn5L.js} +3574 -3428
- package/dist/templates-bUAWMn5L.js.map +1 -0
- package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-QZtHFFH2.js} +2 -2
- package/dist/{useProtocolTemplates-n6AJqSqv.js.map → useProtocolTemplates-QZtHFFH2.js.map} +1 -1
- package/package.json +1 -1
- package/src/composables/controlComponentBindings.ts +80 -0
- package/src/composables/controlSchemaAdapters.ts +196 -0
- package/src/composables/controlSchemaFormFields.ts +61 -0
- package/src/composables/controlSchemaLayout.ts +59 -0
- package/src/composables/controlSchemaNormalize.ts +101 -0
- package/src/composables/controlSchemaUtils.ts +36 -0
- package/src/composables/controlWorkspaceOptions.ts +21 -0
- package/src/composables/useControlSchema.ts +51 -628
- package/src/composables/useControlWorkspace.ts +207 -0
- package/src/templates/adapters.ts +89 -930
- package/src/templates/assayLookups.ts +33 -0
- package/src/templates/assayMatrixAdapters.ts +78 -0
- package/src/templates/assayMatrixBuilder.ts +59 -0
- package/src/templates/assayNormalizers.ts +34 -0
- package/src/templates/builderDefaults.ts +11 -0
- package/src/templates/builderIdUtils.ts +20 -0
- package/src/templates/builderPresetControls.ts +165 -0
- package/src/templates/builderReadUtils.ts +57 -0
- package/src/templates/builders.ts +122 -2350
- package/src/templates/calibrationCurveAdapters.ts +59 -0
- package/src/templates/calibrationCurveBuilder.ts +99 -0
- package/src/templates/calibrationNormalizers.ts +60 -0
- package/src/templates/componentBindingCatalog.ts +90 -0
- package/src/templates/componentBindingHelpers.ts +93 -0
- package/src/templates/componentBindings.ts +12 -461
- package/src/templates/componentDoseResponseProps.ts +42 -0
- package/src/templates/componentGenericProps.ts +77 -0
- package/src/templates/componentPlateHelpers.ts +29 -0
- package/src/templates/componentPlateMapProps.ts +32 -0
- package/src/templates/componentPropsFactory.ts +21 -0
- package/src/templates/componentQpcrPlateProps.ts +28 -0
- package/src/templates/componentTargetResolvers.ts +69 -0
- package/src/templates/componentTemplateProps.ts +78 -0
- package/src/templates/controlSchemaClone.ts +32 -0
- package/src/templates/controlSchemaConstants.ts +11 -0
- package/src/templates/controlSchemaMerge.ts +40 -0
- package/src/templates/controlSchemaTargets.ts +87 -0
- package/src/templates/controlSchemaTypes.ts +20 -0
- package/src/templates/controlSchemas.ts +22 -704
- package/src/templates/defaultBioTemplateBuilder.ts +124 -0
- package/src/templates/doseResponseAdapters.ts +45 -0
- package/src/templates/doseResponseBuilder.ts +44 -0
- package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
- package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
- package/src/templates/flowCytometryPanelBuilder.ts +53 -0
- package/src/templates/flowNormalizers.ts +58 -0
- package/src/templates/flowPanelAdapters.ts +58 -0
- package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
- package/src/templates/instrumentRunAdapters.ts +163 -0
- package/src/templates/instrumentRunBuilder.ts +97 -0
- package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
- package/src/templates/plateGeometry.ts +62 -0
- package/src/templates/plateMapAdapters.ts +36 -0
- package/src/templates/plateMapBuilder.ts +43 -0
- package/src/templates/presetControlSchemas.ts +258 -0
- package/src/templates/protocolAdapters.ts +69 -0
- package/src/templates/protocolNormalizers.ts +37 -0
- package/src/templates/protocolStepsBuilder.ts +36 -0
- package/src/templates/qpcrAdapters.ts +104 -0
- package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
- package/src/templates/qpcrPlateBuilder.ts +96 -0
- package/src/templates/reagentAdapters.ts +77 -0
- package/src/templates/reagentListBuilder.ts +30 -0
- package/src/templates/runNormalizers.ts +63 -0
- package/src/templates/sampleNormalizers.ts +58 -0
- package/src/templates/samplePrepAdapters.ts +63 -0
- package/src/templates/samplePrepBuilder.ts +51 -0
- package/src/templates/sampleSheetAdapters.ts +75 -0
- package/src/templates/sampleSheetBuilder.ts +23 -0
- package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
- package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
- package/src/templates/templateControlSchemas.ts +320 -0
- package/src/templates/templateEnvelopes.ts +137 -0
- package/src/templates/templatePackCollectionBuilder.ts +23 -0
- package/src/templates/templatePresetCollectionBuilder.ts +139 -0
- package/src/templates/templateValidators.ts +414 -0
- package/src/templates/timeCourseAdapters.ts +73 -0
- package/src/templates/timeCourseBuilder.ts +64 -0
- package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
- package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
- package/dist/templates-BorLR_7p.js.map +0 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type {
|
|
2
|
+
ComputedRef,
|
|
3
|
+
Ref,
|
|
4
|
+
} from 'vue'
|
|
2
5
|
import type {
|
|
3
6
|
PillNavItem,
|
|
4
7
|
SidebarToolSection,
|
|
@@ -15,9 +18,55 @@ import type {
|
|
|
15
18
|
FormSchema,
|
|
16
19
|
FormSectionSchema,
|
|
17
20
|
} from '../types/form-builder'
|
|
18
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
defaultValueForControl,
|
|
23
|
+
normalizeControls,
|
|
24
|
+
normalizeControlDefinition,
|
|
25
|
+
} from './controlSchemaNormalize'
|
|
26
|
+
import {
|
|
27
|
+
controlToFormField,
|
|
28
|
+
} from './controlSchemaFormFields'
|
|
29
|
+
import {
|
|
30
|
+
controlsToFormSchema,
|
|
31
|
+
controlsToSectionFormSchema,
|
|
32
|
+
controlsToSectionFormSchemas,
|
|
33
|
+
controlsToSettingsSchema,
|
|
34
|
+
controlsToSidebarPanels,
|
|
35
|
+
controlsToTopBarSettingsConfig,
|
|
36
|
+
controlsToViewItems,
|
|
37
|
+
} from './controlSchemaAdapters'
|
|
38
|
+
import {
|
|
39
|
+
omitUndefined,
|
|
40
|
+
recordValue,
|
|
41
|
+
} from './controlSchemaUtils'
|
|
19
42
|
import type { WellConcentration } from './useDoseCalculator'
|
|
20
43
|
|
|
44
|
+
export {
|
|
45
|
+
mergeControlWorkspaceOptions,
|
|
46
|
+
} from './controlWorkspaceOptions'
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
useControlWorkspace,
|
|
50
|
+
} from './useControlWorkspace'
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
controlValuesToComponentBindings,
|
|
54
|
+
controlValuesToComponentBindingsById,
|
|
55
|
+
controlValuesToComponentProps,
|
|
56
|
+
} from './controlComponentBindings'
|
|
57
|
+
|
|
58
|
+
export {
|
|
59
|
+
controlsToFormSchema,
|
|
60
|
+
controlsToSectionFormSchema,
|
|
61
|
+
controlsToSectionFormSchemas,
|
|
62
|
+
controlsToSettingsSchema,
|
|
63
|
+
controlsToSidebarPanels,
|
|
64
|
+
controlsToTopBarSettingsConfig,
|
|
65
|
+
controlsToViewIds,
|
|
66
|
+
controlsToViewItems,
|
|
67
|
+
getDefaultControlView,
|
|
68
|
+
} from './controlSchemaAdapters'
|
|
69
|
+
|
|
21
70
|
export type ControlOptionValue = string | number | boolean
|
|
22
71
|
export type ControlOption = ControlOptionValue | SelectOption<unknown>
|
|
23
72
|
export type ControlPrimitive = string | number | boolean
|
|
@@ -361,15 +410,6 @@ type ControlValue<TControl> =
|
|
|
361
410
|
|
|
362
411
|
type OptionValue<TOption> = TOption extends SelectOption<infer TValue> ? TValue : TOption
|
|
363
412
|
|
|
364
|
-
interface NormalizedControl {
|
|
365
|
-
name: string
|
|
366
|
-
definition: ControlDefinition
|
|
367
|
-
type: FormFieldType
|
|
368
|
-
sectionId: string
|
|
369
|
-
viewId: string
|
|
370
|
-
order: number
|
|
371
|
-
}
|
|
372
|
-
|
|
373
413
|
/** Preserve literal control keys while marking an object as a MINT control schema. */
|
|
374
414
|
export function defineControls<TControls extends ControlSchema>(controls: TControls): TControls {
|
|
375
415
|
return controls
|
|
@@ -481,52 +521,6 @@ export function getControlDefaults<TControls extends ControlSchema>(
|
|
|
481
521
|
return values as ControlValues<TControls>
|
|
482
522
|
}
|
|
483
523
|
|
|
484
|
-
/** Map control workspace values into component props for direct `v-bind` usage. */
|
|
485
|
-
export function controlValuesToComponentProps<TValues extends Record<string, unknown>>(
|
|
486
|
-
values: TValues,
|
|
487
|
-
mapping?: ControlComponentPropsMap<TValues>,
|
|
488
|
-
): Record<string, unknown> {
|
|
489
|
-
if (mapping === undefined) return { ...values }
|
|
490
|
-
|
|
491
|
-
if (Array.isArray(mapping)) {
|
|
492
|
-
const props: Record<string, unknown> = {}
|
|
493
|
-
for (const key of mapping) {
|
|
494
|
-
props[key] = values[key]
|
|
495
|
-
}
|
|
496
|
-
return props
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const props: Record<string, unknown> = {}
|
|
500
|
-
for (const [prop, source] of Object.entries(mapping) as Array<[string, ControlComponentPropSource<TValues>]>) {
|
|
501
|
-
props[prop] = typeof source === 'function' ? source(values) : values[source]
|
|
502
|
-
}
|
|
503
|
-
return props
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/** Map control workspace values into named SDK component bindings for direct slot rendering. */
|
|
507
|
-
export function controlValuesToComponentBindings<TValues extends Record<string, unknown>>(
|
|
508
|
-
values: TValues,
|
|
509
|
-
bindings?: ControlComponentBindingsConfig<TValues>,
|
|
510
|
-
): ControlComponentBinding[] {
|
|
511
|
-
if (bindings === undefined) return []
|
|
512
|
-
|
|
513
|
-
return normalizeControlComponentBindingConfigs(bindings).map(binding => ({
|
|
514
|
-
id: binding.id,
|
|
515
|
-
component: binding.component,
|
|
516
|
-
props: controlValuesToComponentProps(values, binding.props),
|
|
517
|
-
}))
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
/** Map control workspace values into SDK component bindings keyed by binding id. */
|
|
521
|
-
export function controlValuesToComponentBindingsById<TValues extends Record<string, unknown>>(
|
|
522
|
-
values: TValues,
|
|
523
|
-
bindings?: ControlComponentBindingsConfig<TValues>,
|
|
524
|
-
): ControlComponentBindingsById {
|
|
525
|
-
return Object.fromEntries(
|
|
526
|
-
controlValuesToComponentBindings(values, bindings).map(binding => [binding.id, binding]),
|
|
527
|
-
)
|
|
528
|
-
}
|
|
529
|
-
|
|
530
524
|
/** Return a default WellPlate prop mapping for generated control workspaces. */
|
|
531
525
|
export function defineWellPlateControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
|
|
532
526
|
options: WellPlateControlPropsOptions<TValues> = {},
|
|
@@ -660,201 +654,6 @@ export function defineDoseDesignControlModel(
|
|
|
660
654
|
})
|
|
661
655
|
}
|
|
662
656
|
|
|
663
|
-
function isControlModelBindingInput<TControls extends ControlSchema>(
|
|
664
|
-
value: TControls | (ControlModelBinding & { controls: TControls }),
|
|
665
|
-
): value is ControlModelBinding & { controls: TControls } {
|
|
666
|
-
return (
|
|
667
|
-
typeof value === 'object'
|
|
668
|
-
&& value !== null
|
|
669
|
-
&& 'controls' in value
|
|
670
|
-
&& 'controlOptions' in value
|
|
671
|
-
)
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
export function mergeControlWorkspaceOptions(
|
|
675
|
-
base?: ControlWorkspaceOptions,
|
|
676
|
-
override?: ControlWorkspaceOptions,
|
|
677
|
-
): ControlWorkspaceOptions {
|
|
678
|
-
return {
|
|
679
|
-
...(base ?? {}),
|
|
680
|
-
...(override ?? {}),
|
|
681
|
-
initialValues: {
|
|
682
|
-
...(base?.initialValues ?? {}),
|
|
683
|
-
...(override?.initialValues ?? {}),
|
|
684
|
-
},
|
|
685
|
-
topBarSettings: {
|
|
686
|
-
...(base?.topBarSettings ?? {}),
|
|
687
|
-
...(override?.topBarSettings ?? {}),
|
|
688
|
-
},
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
/** Convert a compact control schema into a FormBuilder schema. */
|
|
693
|
-
export function controlsToFormSchema(
|
|
694
|
-
controls: ControlSchema,
|
|
695
|
-
options: ControlSchemaOptions = {},
|
|
696
|
-
): ControlFormSchema {
|
|
697
|
-
const normalized = normalizeControls(controls, options)
|
|
698
|
-
const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
|
|
699
|
-
const sections = sectionIds.map((sectionId): FormSectionSchema => {
|
|
700
|
-
const sectionControls = normalized.filter(control => control.sectionId === sectionId)
|
|
701
|
-
const config = sectionConfig(sectionId, sectionControls, options)
|
|
702
|
-
return {
|
|
703
|
-
id: sectionId,
|
|
704
|
-
title: config.title ?? config.label ?? humanize(sectionId),
|
|
705
|
-
description: config.description,
|
|
706
|
-
columns: config.columns ?? options.columns ?? 1,
|
|
707
|
-
defaultOpen: config.defaultOpen,
|
|
708
|
-
condition: config.condition,
|
|
709
|
-
fields: sectionControls.map(controlToFormField),
|
|
710
|
-
}
|
|
711
|
-
})
|
|
712
|
-
|
|
713
|
-
return {
|
|
714
|
-
sections,
|
|
715
|
-
submitLabel: options.submitLabel,
|
|
716
|
-
cancelLabel: options.cancelLabel,
|
|
717
|
-
showCancel: options.showCancel,
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
/** Convert controls into AppSidebar panels grouped by view and section. */
|
|
722
|
-
export function controlsToSidebarPanels(
|
|
723
|
-
controls: ControlSchema,
|
|
724
|
-
options: ControlSchemaOptions = {},
|
|
725
|
-
): Record<string, SidebarToolSection[]> {
|
|
726
|
-
const normalized = normalizeControls(controls, options)
|
|
727
|
-
.filter(control => isSidebarEnabled(control.definition.sidebar))
|
|
728
|
-
const viewIds = orderedUnique(normalized.map(control => control.viewId))
|
|
729
|
-
const panels: Record<string, SidebarToolSection[]> = {}
|
|
730
|
-
|
|
731
|
-
for (const viewId of viewIds) {
|
|
732
|
-
const viewControls = normalized.filter(control => control.viewId === viewId)
|
|
733
|
-
const sectionIds = orderedUnique(viewControls.map(control => control.sectionId))
|
|
734
|
-
panels[viewId] = sectionIds.map((sectionId): SidebarToolSection => {
|
|
735
|
-
const sectionControls = viewControls.filter(control => control.sectionId === sectionId)
|
|
736
|
-
const config = sectionConfig(sectionId, sectionControls, options)
|
|
737
|
-
const sidebarConfig = firstSidebarConfig(sectionControls)
|
|
738
|
-
return {
|
|
739
|
-
id: sectionId,
|
|
740
|
-
label: sidebarConfig?.label ?? config.label ?? config.title ?? humanize(sectionId),
|
|
741
|
-
subtitle: sidebarConfig?.subtitle ?? config.subtitle,
|
|
742
|
-
icon: sidebarConfig?.icon ?? config.icon,
|
|
743
|
-
iconColor: sidebarConfig?.iconColor ?? config.iconColor,
|
|
744
|
-
iconBg: sidebarConfig?.iconBg ?? config.iconBg,
|
|
745
|
-
defaultOpen: sidebarConfig?.defaultOpen ?? config.defaultOpen,
|
|
746
|
-
showToggle: sidebarConfig?.showToggle ?? config.showToggle,
|
|
747
|
-
}
|
|
748
|
-
})
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
return panels
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
/** Convert controls into a SettingsModal schema grouped by the same sections. */
|
|
755
|
-
export function controlsToSettingsSchema(
|
|
756
|
-
controls: ControlSchema,
|
|
757
|
-
options: ControlSchemaOptions = {},
|
|
758
|
-
): SettingsModalSchema {
|
|
759
|
-
const normalized = normalizeControls(controls, options)
|
|
760
|
-
const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
|
|
761
|
-
|
|
762
|
-
return {
|
|
763
|
-
groups: sectionIds.map((sectionId) => {
|
|
764
|
-
const sectionControls = normalized.filter(control => control.sectionId === sectionId)
|
|
765
|
-
const config = sectionConfig(sectionId, sectionControls, options)
|
|
766
|
-
return {
|
|
767
|
-
id: sectionId,
|
|
768
|
-
label: config.label ?? config.title ?? humanize(sectionId),
|
|
769
|
-
description: config.description ?? config.subtitle,
|
|
770
|
-
icon: typeof config.icon === 'string' ? config.icon : undefined,
|
|
771
|
-
fields: sectionControls.map(controlToFormField),
|
|
772
|
-
columns: config.columns ?? options.columns ?? 1,
|
|
773
|
-
condition: config.condition,
|
|
774
|
-
access: config.access,
|
|
775
|
-
visibleFor: config.visibleFor,
|
|
776
|
-
requiresAdmin: config.requiresAdmin,
|
|
777
|
-
permissions: config.permissions,
|
|
778
|
-
anyPermissions: config.anyPermissions,
|
|
779
|
-
}
|
|
780
|
-
}),
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
/** Convert controls into an AppTopBar settingsConfig object that passes compact controls through to SettingsModal. */
|
|
785
|
-
export function controlsToTopBarSettingsConfig(
|
|
786
|
-
controls: ControlSchema,
|
|
787
|
-
options: ControlSchemaOptions = {},
|
|
788
|
-
config: Omit<TopBarSettingsConfig, 'schema' | 'controls' | 'controlOptions'> = {},
|
|
789
|
-
): TopBarSettingsConfig {
|
|
790
|
-
return {
|
|
791
|
-
...config,
|
|
792
|
-
controls,
|
|
793
|
-
controlOptions: options,
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
/** Return generated control view IDs that have at least one sidebar panel. */
|
|
798
|
-
export function controlsToViewIds(
|
|
799
|
-
controls: ControlSchema,
|
|
800
|
-
options: ControlSchemaOptions = {},
|
|
801
|
-
): string[] {
|
|
802
|
-
return controlsToViewItems(controls, options).map(item => item.id)
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
/** Return AppTopBar pillNav-compatible view items for switching generated control sidebars. */
|
|
806
|
-
export function controlsToViewItems(
|
|
807
|
-
controls: ControlSchema,
|
|
808
|
-
options: ControlSchemaOptions = {},
|
|
809
|
-
): PillNavItem[] {
|
|
810
|
-
return Object.entries(controlsToSidebarPanels(controls, options))
|
|
811
|
-
.filter(([, sections]) => sections.length > 0)
|
|
812
|
-
.map(([id]) => controlViewItem(id, options))
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
/** Return the first generated sidebar view ID, or an empty string when controls render no sidebar panels. */
|
|
816
|
-
export function getDefaultControlView(
|
|
817
|
-
controls: ControlSchema,
|
|
818
|
-
options: ControlSchemaOptions = {},
|
|
819
|
-
): string {
|
|
820
|
-
return controlsToViewIds(controls, options)[0] ?? ''
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
/** Return a headerless single-section FormBuilder schema for rendering inside an AppSidebar section slot. */
|
|
824
|
-
export function controlsToSectionFormSchema(
|
|
825
|
-
controls: ControlSchema,
|
|
826
|
-
sectionId: string,
|
|
827
|
-
options: ControlSchemaOptions = {},
|
|
828
|
-
): ControlFormSchema {
|
|
829
|
-
const schema = controlsToFormSchema(controls, options)
|
|
830
|
-
return {
|
|
831
|
-
sections: schema.sections
|
|
832
|
-
.filter(section => section.id === sectionId)
|
|
833
|
-
.map(section => ({ ...section, title: '', description: undefined })),
|
|
834
|
-
submitLabel: schema.submitLabel,
|
|
835
|
-
cancelLabel: schema.cancelLabel,
|
|
836
|
-
showCancel: schema.showCancel,
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
/** Return headerless FormBuilder schemas keyed by section ID for AppSidebar auto-rendering. */
|
|
841
|
-
export function controlsToSectionFormSchemas(
|
|
842
|
-
controls: ControlSchema,
|
|
843
|
-
options: ControlSchemaOptions = {},
|
|
844
|
-
): Record<string, ControlFormSchema> {
|
|
845
|
-
const schema = controlsToFormSchema(controls, options)
|
|
846
|
-
const schemas: Record<string, ControlFormSchema> = {}
|
|
847
|
-
for (const section of schema.sections) {
|
|
848
|
-
schemas[section.id] = {
|
|
849
|
-
sections: [{ ...section, title: '', description: undefined }],
|
|
850
|
-
submitLabel: schema.submitLabel,
|
|
851
|
-
cancelLabel: schema.cancelLabel,
|
|
852
|
-
showCancel: schema.showCancel,
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
return schemas
|
|
856
|
-
}
|
|
857
|
-
|
|
858
657
|
/** Prepare FormBuilder, SettingsModal, AppTopBar settings, AppSidebar, and initial values from one compact control model. */
|
|
859
658
|
export function useControlSchema<TControls extends ControlSchema>(
|
|
860
659
|
controls: TControls,
|
|
@@ -902,195 +701,6 @@ export function useControlSchema<TControls extends ControlSchema>(
|
|
|
902
701
|
}
|
|
903
702
|
}
|
|
904
703
|
|
|
905
|
-
/** Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model. */
|
|
906
|
-
export function useControlWorkspace<TControls extends ControlSchema>(
|
|
907
|
-
controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),
|
|
908
|
-
options: ControlWorkspaceOptions = {},
|
|
909
|
-
): UseControlWorkspaceReturn<TControls> {
|
|
910
|
-
const model = isControlModelBindingInput<TControls>(controlsOrModel) ? controlsOrModel : undefined
|
|
911
|
-
const controls: TControls = model ? model.controls : controlsOrModel as TControls
|
|
912
|
-
const workspaceOptions = model
|
|
913
|
-
? mergeControlWorkspaceOptions(model.controlOptions, options)
|
|
914
|
-
: options
|
|
915
|
-
const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions
|
|
916
|
-
const schema = useControlSchema(controls, schemaOptions)
|
|
917
|
-
const activeView = ref(schema.defaultView)
|
|
918
|
-
const values = reactive({
|
|
919
|
-
...schema.initialValues,
|
|
920
|
-
...(initialValues ?? {}),
|
|
921
|
-
}) as ControlValues<TControls> & Record<string, unknown>
|
|
922
|
-
|
|
923
|
-
function setActiveView(viewId: string) {
|
|
924
|
-
syncActiveView(viewId)
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
function syncActiveView(viewId: string) {
|
|
928
|
-
if (!schema.viewIds.includes(viewId)) return
|
|
929
|
-
if (activeView.value !== viewId) activeView.value = viewId
|
|
930
|
-
if (sidebar.activeView !== viewId) sidebar.activeView = viewId
|
|
931
|
-
if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
function setValues(nextValues: Record<string, unknown>) {
|
|
935
|
-
Object.assign(values, nextValues)
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
function resetValues(nextValues: Record<string, unknown> = {}) {
|
|
939
|
-
replaceRecord(values, {
|
|
940
|
-
...schema.initialValues,
|
|
941
|
-
...nextValues,
|
|
942
|
-
})
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
function getComponentProps(
|
|
946
|
-
mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,
|
|
947
|
-
): Record<string, unknown> {
|
|
948
|
-
return controlValuesToComponentProps(values, mapping)
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
function getComponentPropsById(
|
|
952
|
-
mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,
|
|
953
|
-
): Record<string, Record<string, unknown>> {
|
|
954
|
-
if (mappings === undefined) return {}
|
|
955
|
-
|
|
956
|
-
return Object.fromEntries(
|
|
957
|
-
Object.entries(mappings).map(([id, mapping]) => [
|
|
958
|
-
id,
|
|
959
|
-
controlValuesToComponentProps(values, mapping),
|
|
960
|
-
]),
|
|
961
|
-
)
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
function getComponentBindings(
|
|
965
|
-
bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
|
|
966
|
-
): ControlComponentBinding[] {
|
|
967
|
-
return controlValuesToComponentBindings(values, bindings)
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
function getComponentBindingsById(
|
|
971
|
-
bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
|
|
972
|
-
): ControlComponentBindingsById {
|
|
973
|
-
return controlValuesToComponentBindingsById(values, bindings)
|
|
974
|
-
}
|
|
975
|
-
const componentProps = computed(() => (
|
|
976
|
-
model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)
|
|
977
|
-
))
|
|
978
|
-
const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))
|
|
979
|
-
const componentBindings = computed(() => getComponentBindings(model?.componentBindings))
|
|
980
|
-
const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))
|
|
981
|
-
const form = {
|
|
982
|
-
...schema.form,
|
|
983
|
-
modelValue: values,
|
|
984
|
-
'onUpdate:modelValue': setValues,
|
|
985
|
-
} as ControlWorkspaceFormBinding
|
|
986
|
-
|
|
987
|
-
const topBarSettingsConfig: TopBarSettingsConfig = {
|
|
988
|
-
...schema.topBarSettingsConfig,
|
|
989
|
-
...(topBarSettings ?? {}),
|
|
990
|
-
values,
|
|
991
|
-
}
|
|
992
|
-
const sidebar = reactive({
|
|
993
|
-
...schema.sidebar,
|
|
994
|
-
activeView: activeView.value,
|
|
995
|
-
modelValue: values,
|
|
996
|
-
'onUpdate:modelValue': setValues,
|
|
997
|
-
values,
|
|
998
|
-
'onUpdate:values': setValues,
|
|
999
|
-
}) as ControlWorkspaceSidebarBinding
|
|
1000
|
-
const pillNav = reactive({
|
|
1001
|
-
items: schema.viewItems,
|
|
1002
|
-
currentItemId: activeView.value,
|
|
1003
|
-
onSelect: (item: PillNavItem) => setActiveView(item.id),
|
|
1004
|
-
}) as ControlWorkspacePillNavBinding
|
|
1005
|
-
const topBarSettingsBinding = {
|
|
1006
|
-
showSettings: true,
|
|
1007
|
-
settingsConfig: topBarSettingsConfig,
|
|
1008
|
-
onSettingsValuesChange: setValues,
|
|
1009
|
-
} as ControlWorkspaceTopBarSettingsBinding
|
|
1010
|
-
const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({
|
|
1011
|
-
pillNav: pillNav.items,
|
|
1012
|
-
currentPillId: pillNav.currentItemId,
|
|
1013
|
-
onPillSelect: pillNav.onSelect,
|
|
1014
|
-
...topBarSettingsBinding,
|
|
1015
|
-
}))
|
|
1016
|
-
const bindings: ControlWorkspaceComponentBindings = {
|
|
1017
|
-
form,
|
|
1018
|
-
sidebar,
|
|
1019
|
-
topBar: topBarProps,
|
|
1020
|
-
topBarSettings: topBarSettingsBinding,
|
|
1021
|
-
pillNav,
|
|
1022
|
-
componentBindings,
|
|
1023
|
-
componentBindingsById,
|
|
1024
|
-
componentProps,
|
|
1025
|
-
componentPropsById,
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
watch(activeView, syncActiveView, { flush: 'sync' })
|
|
1029
|
-
watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })
|
|
1030
|
-
watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })
|
|
1031
|
-
|
|
1032
|
-
return {
|
|
1033
|
-
...schema,
|
|
1034
|
-
schema,
|
|
1035
|
-
values,
|
|
1036
|
-
activeView,
|
|
1037
|
-
topBarSettingsConfig,
|
|
1038
|
-
form,
|
|
1039
|
-
sidebar,
|
|
1040
|
-
topBar: topBarProps,
|
|
1041
|
-
pillNav,
|
|
1042
|
-
topBarSettings: topBarSettingsBinding,
|
|
1043
|
-
bindings,
|
|
1044
|
-
componentBindings,
|
|
1045
|
-
componentBindingsById,
|
|
1046
|
-
componentProps,
|
|
1047
|
-
componentPropsById,
|
|
1048
|
-
setActiveView,
|
|
1049
|
-
setValues,
|
|
1050
|
-
resetValues,
|
|
1051
|
-
getComponentProps,
|
|
1052
|
-
getComponentPropsById,
|
|
1053
|
-
getComponentBindings,
|
|
1054
|
-
getComponentBindingsById,
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
function normalizeControls(
|
|
1059
|
-
controls: ControlSchema,
|
|
1060
|
-
options: ControlSchemaOptions = {},
|
|
1061
|
-
): NormalizedControl[] {
|
|
1062
|
-
return Object.entries(controls)
|
|
1063
|
-
.map(([name, input], index): NormalizedControl => {
|
|
1064
|
-
const definition = normalizeControlDefinition(input)
|
|
1065
|
-
const type = definition.type ?? inferControlType(definition)
|
|
1066
|
-
return {
|
|
1067
|
-
name,
|
|
1068
|
-
definition,
|
|
1069
|
-
type,
|
|
1070
|
-
sectionId: definition.section ?? options.section ?? 'controls',
|
|
1071
|
-
viewId: definition.view ?? options.view ?? 'default',
|
|
1072
|
-
order: definition.order ?? index,
|
|
1073
|
-
}
|
|
1074
|
-
})
|
|
1075
|
-
.sort((a, b) => a.order - b.order)
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
function normalizeControlDefinition(input: ControlInput): ControlDefinition {
|
|
1079
|
-
if (isControlOptionArray(input)) {
|
|
1080
|
-
if (input.length === 0) return { type: 'tags', default: [] }
|
|
1081
|
-
return {
|
|
1082
|
-
default: optionValue(input[0]),
|
|
1083
|
-
options: input,
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {
|
|
1088
|
-
return { default: input }
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
return input
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
704
|
function appendModelControls(
|
|
1095
705
|
target: ControlSchema,
|
|
1096
706
|
source: ControlSchema,
|
|
@@ -1132,118 +742,6 @@ function registerSectionOptions(
|
|
|
1132
742
|
})
|
|
1133
743
|
}
|
|
1134
744
|
|
|
1135
|
-
function isControlOptionArray(input: ControlInput): input is readonly ControlOption[] {
|
|
1136
|
-
return Array.isArray(input)
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
function inferControlType(definition: ControlDefinition): FormFieldType {
|
|
1140
|
-
const value = definition.default ?? definition.defaultValue
|
|
1141
|
-
if (definition.options?.length) return Array.isArray(value) ? 'multiselect' : 'select'
|
|
1142
|
-
if (typeof value === 'boolean') return 'toggle'
|
|
1143
|
-
if (typeof value === 'number') return 'number'
|
|
1144
|
-
if (Array.isArray(value)) return 'tags'
|
|
1145
|
-
return 'text'
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
function defaultValueForControl(definition: ControlDefinition, type: FormFieldType): unknown {
|
|
1149
|
-
if (definition.default !== undefined) return definition.default
|
|
1150
|
-
if (definition.defaultValue !== undefined) return definition.defaultValue
|
|
1151
|
-
return getTypeDefault(type)
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
function controlToFormField(control: NormalizedControl): FormFieldSchema {
|
|
1155
|
-
const { name, definition, type } = control
|
|
1156
|
-
const props = fieldProps(definition)
|
|
1157
|
-
return {
|
|
1158
|
-
name,
|
|
1159
|
-
label: definition.label ?? humanize(name),
|
|
1160
|
-
type,
|
|
1161
|
-
defaultValue: defaultValueForControl(definition, type),
|
|
1162
|
-
placeholder: definition.placeholder,
|
|
1163
|
-
hint: definition.hint,
|
|
1164
|
-
size: definition.size,
|
|
1165
|
-
disabled: definition.disabled,
|
|
1166
|
-
readonly: definition.readonly,
|
|
1167
|
-
validation: validationForControl(definition),
|
|
1168
|
-
condition: definition.condition,
|
|
1169
|
-
access: definition.access,
|
|
1170
|
-
visibleFor: definition.visibleFor,
|
|
1171
|
-
requiresAdmin: definition.requiresAdmin,
|
|
1172
|
-
permissions: definition.permissions,
|
|
1173
|
-
anyPermissions: definition.anyPermissions,
|
|
1174
|
-
colSpan: definition.colSpan,
|
|
1175
|
-
props,
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
function fieldProps(definition: ControlDefinition): Record<string, unknown> {
|
|
1180
|
-
const props: Record<string, unknown> = {}
|
|
1181
|
-
if (definition.min !== undefined) props.min = numericValue(definition.min)
|
|
1182
|
-
if (definition.max !== undefined) props.max = numericValue(definition.max)
|
|
1183
|
-
if (definition.options) props.options = definition.options.map(normalizeOption)
|
|
1184
|
-
return { ...props, ...(definition.props ?? {}) }
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
function validationForControl(definition: ControlDefinition): FieldValidation | undefined {
|
|
1188
|
-
const validation: FieldValidation = { ...(definition.validation ?? {}) }
|
|
1189
|
-
if (definition.required !== undefined) validation.required = definition.required
|
|
1190
|
-
if (definition.min !== undefined) validation.min = definition.min
|
|
1191
|
-
if (definition.max !== undefined) validation.max = definition.max
|
|
1192
|
-
if (definition.minLength !== undefined) validation.minLength = definition.minLength
|
|
1193
|
-
if (definition.maxLength !== undefined) validation.maxLength = definition.maxLength
|
|
1194
|
-
if (definition.email !== undefined) validation.email = definition.email
|
|
1195
|
-
if (definition.pattern !== undefined) validation.pattern = definition.pattern
|
|
1196
|
-
return Object.keys(validation).length > 0 ? validation : undefined
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
function sectionConfig(
|
|
1200
|
-
sectionId: string,
|
|
1201
|
-
controls: NormalizedControl[],
|
|
1202
|
-
options: ControlSchemaOptions,
|
|
1203
|
-
): ControlSectionConfig {
|
|
1204
|
-
const configured = options.sections?.[sectionId]
|
|
1205
|
-
const first = controls[0]?.definition
|
|
1206
|
-
return {
|
|
1207
|
-
...configured,
|
|
1208
|
-
id: sectionId,
|
|
1209
|
-
label: configured?.label ?? first?.sectionLabel,
|
|
1210
|
-
title: configured?.title ?? first?.sectionLabel,
|
|
1211
|
-
description: configured?.description ?? first?.sectionDescription,
|
|
1212
|
-
subtitle: configured?.subtitle ?? first?.sectionSubtitle,
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
function firstSidebarConfig(controls: NormalizedControl[]): ControlSidebarConfig | undefined {
|
|
1217
|
-
for (const control of controls) {
|
|
1218
|
-
const sidebar = control.definition.sidebar
|
|
1219
|
-
if (sidebar && typeof sidebar === 'object' && sidebar.enabled !== false) return sidebar
|
|
1220
|
-
}
|
|
1221
|
-
return undefined
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
function isSidebarEnabled(sidebar: ControlDefinition['sidebar']): boolean {
|
|
1225
|
-
if (sidebar === false) return false
|
|
1226
|
-
if (sidebar && typeof sidebar === 'object') return sidebar.enabled !== false
|
|
1227
|
-
return true
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
function normalizeOption(option: ControlOption): SelectOption<unknown> {
|
|
1231
|
-
if (typeof option === 'object' && option !== null && 'label' in option) {
|
|
1232
|
-
return option
|
|
1233
|
-
}
|
|
1234
|
-
return {
|
|
1235
|
-
value: option,
|
|
1236
|
-
label: humanize(String(option)),
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
function optionValue(option: ControlOption): ControlOptionValue | unknown {
|
|
1241
|
-
if (typeof option === 'object' && option !== null && 'value' in option) {
|
|
1242
|
-
return option.value
|
|
1243
|
-
}
|
|
1244
|
-
return option
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
745
|
function compactComponentPropsMap<TValues extends Record<string, unknown>>(
|
|
1248
746
|
mapping: Record<string, ControlComponentPropSource<TValues> | undefined>,
|
|
1249
747
|
): ControlComponentPropsMap<TValues> {
|
|
@@ -1254,31 +752,6 @@ function compactComponentPropsMap<TValues extends Record<string, unknown>>(
|
|
|
1254
752
|
)
|
|
1255
753
|
}
|
|
1256
754
|
|
|
1257
|
-
function normalizeControlComponentBindingConfigs<TValues extends Record<string, unknown>>(
|
|
1258
|
-
bindings: ControlComponentBindingsConfig<TValues>,
|
|
1259
|
-
): Array<Required<Pick<ControlComponentBindingConfig<TValues>, 'id' | 'component'>> & Pick<ControlComponentBindingConfig<TValues>, 'props'>> {
|
|
1260
|
-
if (Array.isArray(bindings)) {
|
|
1261
|
-
const usedIds = new Map<string, number>()
|
|
1262
|
-
return bindings.map(binding => ({
|
|
1263
|
-
id: uniqueComponentBindingId(binding.id ?? binding.component, usedIds),
|
|
1264
|
-
component: binding.component,
|
|
1265
|
-
props: binding.props,
|
|
1266
|
-
}))
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
return Object.entries(bindings).map(([id, binding]) => ({
|
|
1270
|
-
id,
|
|
1271
|
-
component: binding.component,
|
|
1272
|
-
props: binding.props,
|
|
1273
|
-
}))
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
function uniqueComponentBindingId(id: string, usedIds: Map<string, number>): string {
|
|
1277
|
-
const count = usedIds.get(id) ?? 0
|
|
1278
|
-
usedIds.set(id, count + 1)
|
|
1279
|
-
return count === 0 ? id : `${id}-${count + 1}`
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
755
|
function sourceKey<TValues extends Record<string, unknown>>(key: string): keyof TValues & string {
|
|
1283
756
|
return key as keyof TValues & string
|
|
1284
757
|
}
|
|
@@ -1331,53 +804,3 @@ function updateWellsFromDoseResults<TValues extends Record<string, unknown>>(
|
|
|
1331
804
|
writableValues[source] = nextWells
|
|
1332
805
|
}
|
|
1333
806
|
}
|
|
1334
|
-
|
|
1335
|
-
function recordValue(value: unknown): Record<string, unknown> {
|
|
1336
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
1337
|
-
? value as Record<string, unknown>
|
|
1338
|
-
: {}
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
function numericValue(value: number | { value: number; message: string }): number {
|
|
1342
|
-
return typeof value === 'number' ? value : value.value
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
function orderedUnique(values: string[]): string[] {
|
|
1346
|
-
return [...new Set(values)]
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
function controlViewItem(viewId: string, options: ControlSchemaOptions): PillNavItem {
|
|
1350
|
-
const config = options.views?.[viewId]
|
|
1351
|
-
return {
|
|
1352
|
-
id: viewId,
|
|
1353
|
-
label: config?.label ?? humanize(viewId),
|
|
1354
|
-
...(config?.icon !== undefined ? { icon: config.icon } : {}),
|
|
1355
|
-
...(config?.to !== undefined ? { to: config.to } : {}),
|
|
1356
|
-
...(config?.href !== undefined ? { href: config.href } : {}),
|
|
1357
|
-
...(config?.disabled !== undefined ? { disabled: config.disabled } : {}),
|
|
1358
|
-
...(config?.children !== undefined ? { children: config.children } : {}),
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
function replaceRecord(target: Record<string, unknown>, values: Record<string, unknown>) {
|
|
1363
|
-
for (const key of Object.keys(target)) {
|
|
1364
|
-
delete target[key]
|
|
1365
|
-
}
|
|
1366
|
-
Object.assign(target, values)
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
function omitUndefined<T extends object>(record: T): T {
|
|
1370
|
-
const next: Record<string, unknown> = {}
|
|
1371
|
-
for (const [key, value] of Object.entries(record as Record<string, unknown>)) {
|
|
1372
|
-
if (value !== undefined) next[key] = value
|
|
1373
|
-
}
|
|
1374
|
-
return next as T
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
function humanize(value: string): string {
|
|
1378
|
-
return value
|
|
1379
|
-
.replace(/[_-]+/g, ' ')
|
|
1380
|
-
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
1381
|
-
.trim()
|
|
1382
|
-
.replace(/\w\S*/g, word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
1383
|
-
}
|