@morscherlab/mint-sdk 1.0.0-rc.1 → 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.
Files changed (300) hide show
  1. package/README.md +9 -1
  2. package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +1 -0
  3. package/dist/__tests__/components/ProgressBar.test.d.ts +1 -0
  4. package/dist/__tests__/components/RackEditor.test.d.ts +1 -0
  5. package/dist/__tests__/components/SequenceProgressBar.test.d.ts +1 -0
  6. package/dist/__tests__/composables/useExperimentSamples.test.d.ts +1 -0
  7. package/dist/__tests__/utils/instrument.test.d.ts +1 -0
  8. package/dist/__tests__/utils/lcms.test.d.ts +1 -0
  9. package/dist/__tests__/utils/permissions.test.d.ts +1 -0
  10. package/dist/__tests__/utils/rack.test.d.ts +1 -0
  11. package/dist/{auth-CBG3bWEc.js → auth-B7g4J4ZF.js} +99 -5
  12. package/dist/auth-B7g4J4ZF.js.map +1 -0
  13. package/dist/components/AppSidebar.vue.d.ts +3 -3
  14. package/dist/components/AutoGroupModal.vue.d.ts +1 -1
  15. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  16. package/dist/components/BaseToggle.vue.d.ts +2 -2
  17. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
  18. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  19. package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +1 -1
  20. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  21. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +2 -2
  22. package/dist/components/FormulaInput.vue.d.ts +1 -1
  23. package/dist/components/InstrumentAlertLog.vue.d.ts +22 -0
  24. package/dist/components/InstrumentStateBadge.vue.d.ts +11 -0
  25. package/dist/components/InstrumentStatusCard.vue.d.ts +13 -0
  26. package/dist/components/LcmsSequenceTable.vue.d.ts +26 -0
  27. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -3
  28. package/dist/components/ProgressBar.vue.d.ts +1 -0
  29. package/dist/components/RackEditor.vue.d.ts +41 -3
  30. package/dist/components/ReagentList.vue.d.ts +1 -1
  31. package/dist/components/SampleSelector.vue.d.ts +5 -2
  32. package/dist/components/SegmentedControl.vue.d.ts +2 -0
  33. package/dist/components/SequenceInput.vue.d.ts +1 -1
  34. package/dist/components/SequenceProgressBar.vue.d.ts +15 -0
  35. package/dist/components/SettingsModal.vue.d.ts +3 -1
  36. package/dist/components/TagsInput.vue.d.ts +1 -1
  37. package/dist/components/WellPlate.vue.d.ts +42 -3
  38. package/dist/components/index.d.ts +5 -0
  39. package/dist/components/index.js +3 -3
  40. package/dist/{components-5KSfsVqf.js → components-DafPc4rM.js} +2091 -1051
  41. package/dist/components-DafPc4rM.js.map +1 -0
  42. package/dist/composables/controlComponentBindings.d.ts +7 -0
  43. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  44. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  45. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  46. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  47. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  48. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  49. package/dist/composables/experimentDesignData.d.ts +17 -0
  50. package/dist/composables/index.d.ts +2 -0
  51. package/dist/composables/index.js +4 -4
  52. package/dist/composables/useControlSchema.d.ts +15 -30
  53. package/dist/composables/useControlWorkspace.d.ts +5 -0
  54. package/dist/composables/useExperimentData.d.ts +11 -3
  55. package/dist/composables/useExperimentSamples.d.ts +42 -0
  56. package/dist/composables/usePlatformContext.d.ts +54 -0
  57. package/dist/{composables-D4Myb30a.js → composables-BMkPQhVK.js} +5 -3
  58. package/dist/composables-BMkPQhVK.js.map +1 -0
  59. package/dist/index.d.ts +4 -0
  60. package/dist/index.js +168 -6
  61. package/dist/index.js.map +1 -0
  62. package/dist/install.js +2 -2
  63. package/dist/instrument.d.ts +7 -0
  64. package/dist/lcms.d.ts +27 -0
  65. package/dist/permissions.d.ts +46 -0
  66. package/dist/stores/auth.d.ts +74 -2
  67. package/dist/stores/index.js +1 -1
  68. package/dist/styles.css +3316 -1216
  69. package/dist/templates/adapters.d.ts +14 -47
  70. package/dist/templates/assayLookups.d.ts +3 -0
  71. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  72. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  73. package/dist/templates/assayNormalizers.d.ts +4 -0
  74. package/dist/templates/builderDefaults.d.ts +1 -0
  75. package/dist/templates/builderIdUtils.d.ts +4 -0
  76. package/dist/templates/builderPresetControls.d.ts +10 -0
  77. package/dist/templates/builderReadUtils.d.ts +8 -0
  78. package/dist/templates/builders.d.ts +26 -63
  79. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  80. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  81. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  82. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  83. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  84. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  85. package/dist/templates/componentGenericProps.d.ts +8 -0
  86. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  87. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  88. package/dist/templates/componentPropsFactory.d.ts +3 -0
  89. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  90. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  91. package/dist/templates/componentTemplateProps.d.ts +3 -0
  92. package/dist/templates/controlSchemaClone.d.ts +4 -0
  93. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  94. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  95. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  96. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  97. package/dist/templates/controlSchemas.d.ts +4 -4
  98. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  99. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  100. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  101. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  102. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  103. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  104. package/dist/templates/flowNormalizers.d.ts +8 -0
  105. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  106. package/dist/templates/index.d.ts +2 -2
  107. package/dist/templates/index.js +2 -2
  108. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  109. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  110. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  111. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  112. package/dist/templates/plateGeometry.d.ts +4 -0
  113. package/dist/templates/plateMapAdapters.d.ts +3 -0
  114. package/dist/templates/plateMapBuilder.d.ts +2 -0
  115. package/dist/templates/presetControlSchemas.d.ts +534 -0
  116. package/dist/templates/presets.d.ts +12 -0
  117. package/dist/templates/protocolAdapters.d.ts +5 -0
  118. package/dist/templates/protocolNormalizers.d.ts +6 -0
  119. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  120. package/dist/templates/qpcrAdapters.d.ts +5 -0
  121. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  122. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  123. package/dist/templates/reagentAdapters.d.ts +5 -0
  124. package/dist/templates/reagentListBuilder.d.ts +2 -0
  125. package/dist/templates/runNormalizers.d.ts +10 -0
  126. package/dist/templates/sampleNormalizers.d.ts +4 -0
  127. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  128. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  129. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  130. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  131. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  132. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  133. package/dist/templates/templateControlSchemas.d.ts +400 -0
  134. package/dist/templates/templateEnvelopes.d.ts +9 -0
  135. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  136. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  137. package/dist/templates/templateValidators.d.ts +13 -0
  138. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  139. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  140. package/dist/templates/types.d.ts +16 -1
  141. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  142. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  143. package/dist/{templates-BSlxwV2c.js → templates-bUAWMn5L.js} +3610 -3154
  144. package/dist/templates-bUAWMn5L.js.map +1 -0
  145. package/dist/types/auth.d.ts +2 -0
  146. package/dist/types/components.d.ts +32 -3
  147. package/dist/types/form-builder.d.ts +2 -1
  148. package/dist/types/index.d.ts +4 -1
  149. package/dist/types/instrument.d.ts +56 -0
  150. package/dist/types/platform.d.ts +3 -0
  151. package/dist/{useExperimentData-BbbdI5xT.js → useProtocolTemplates-QZtHFFH2.js} +534 -359
  152. package/dist/useProtocolTemplates-QZtHFFH2.js.map +1 -0
  153. package/dist/utils/rack.d.ts +47 -0
  154. package/package.json +1 -1
  155. package/src/__tests__/components/AppTopBar.test.ts +15 -0
  156. package/src/__tests__/components/BaseTabs.test.ts +15 -0
  157. package/src/__tests__/components/LcmsSequenceTable.test.ts +57 -0
  158. package/src/__tests__/components/ProgressBar.test.ts +18 -0
  159. package/src/__tests__/components/RackEditor.test.ts +125 -0
  160. package/src/__tests__/components/SampleSelector.test.ts +25 -0
  161. package/src/__tests__/components/SegmentedControl.test.ts +45 -0
  162. package/src/__tests__/components/SequenceProgressBar.test.ts +39 -0
  163. package/src/__tests__/components/SettingsModal.test.ts +83 -2
  164. package/src/__tests__/composables/useControlSchema.test.ts +4 -0
  165. package/src/__tests__/composables/useExperimentData.test.ts +23 -0
  166. package/src/__tests__/composables/useExperimentSamples.test.ts +91 -0
  167. package/src/__tests__/templates/templates.test.ts +86 -0
  168. package/src/__tests__/utils/instrument.test.ts +47 -0
  169. package/src/__tests__/utils/lcms.test.ts +73 -0
  170. package/src/__tests__/utils/permissions.test.ts +50 -0
  171. package/src/__tests__/utils/rack.test.ts +120 -0
  172. package/src/components/AppTopBar.vue +1 -0
  173. package/src/components/BaseTabs.vue +22 -1
  174. package/src/components/InstrumentAlertLog.vue +191 -0
  175. package/src/components/InstrumentStateBadge.vue +50 -0
  176. package/src/components/InstrumentStatusCard.vue +188 -0
  177. package/src/components/LcmsSequenceTable.vue +191 -0
  178. package/src/components/ProgressBar.vue +3 -0
  179. package/src/components/RackEditor.vue +73 -2
  180. package/src/components/SampleSelector.vue +28 -9
  181. package/src/components/SegmentedControl.story.vue +17 -0
  182. package/src/components/SegmentedControl.vue +14 -3
  183. package/src/components/SequenceProgressBar.vue +71 -0
  184. package/src/components/SettingsModal.vue +42 -2
  185. package/src/components/WellPlate.vue +142 -21
  186. package/src/components/index.ts +5 -0
  187. package/src/components/internal/WellEditPopupInternal.vue +1 -0
  188. package/src/composables/controlComponentBindings.ts +80 -0
  189. package/src/composables/controlSchemaAdapters.ts +196 -0
  190. package/src/composables/controlSchemaFormFields.ts +61 -0
  191. package/src/composables/controlSchemaLayout.ts +59 -0
  192. package/src/composables/controlSchemaNormalize.ts +101 -0
  193. package/src/composables/controlSchemaUtils.ts +36 -0
  194. package/src/composables/controlWorkspaceOptions.ts +21 -0
  195. package/src/composables/experimentDesignData.ts +182 -0
  196. package/src/composables/index.ts +14 -0
  197. package/src/composables/useAuth.ts +4 -0
  198. package/src/composables/useAutoGroup.ts +5 -1
  199. package/src/composables/useControlSchema.ts +62 -618
  200. package/src/composables/useControlWorkspace.ts +207 -0
  201. package/src/composables/useExperimentData.ts +57 -16
  202. package/src/composables/useExperimentSamples.ts +142 -0
  203. package/src/index.ts +27 -0
  204. package/src/instrument.ts +90 -0
  205. package/src/lcms.ts +108 -0
  206. package/src/permissions.ts +143 -0
  207. package/src/stores/auth.ts +31 -3
  208. package/src/styles/components/instrument-monitor.css +478 -0
  209. package/src/styles/components/lcms-sequence-table.css +189 -0
  210. package/src/styles/components/sequence-progress-bar.css +63 -0
  211. package/src/styles/components/tabs.css +9 -0
  212. package/src/styles/components/well-edit-popup.css +7 -1
  213. package/src/styles/components/well-plate.css +5 -0
  214. package/src/styles/index.css +3 -0
  215. package/src/templates/adapters.ts +89 -930
  216. package/src/templates/assayLookups.ts +33 -0
  217. package/src/templates/assayMatrixAdapters.ts +78 -0
  218. package/src/templates/assayMatrixBuilder.ts +59 -0
  219. package/src/templates/assayNormalizers.ts +34 -0
  220. package/src/templates/builderDefaults.ts +11 -0
  221. package/src/templates/builderIdUtils.ts +20 -0
  222. package/src/templates/builderPresetControls.ts +165 -0
  223. package/src/templates/builderReadUtils.ts +57 -0
  224. package/src/templates/builders.ts +122 -2149
  225. package/src/templates/calibrationCurveAdapters.ts +59 -0
  226. package/src/templates/calibrationCurveBuilder.ts +99 -0
  227. package/src/templates/calibrationNormalizers.ts +60 -0
  228. package/src/templates/componentBindingCatalog.ts +90 -0
  229. package/src/templates/componentBindingHelpers.ts +93 -0
  230. package/src/templates/componentBindings.ts +12 -461
  231. package/src/templates/componentDoseResponseProps.ts +42 -0
  232. package/src/templates/componentGenericProps.ts +77 -0
  233. package/src/templates/componentPlateHelpers.ts +29 -0
  234. package/src/templates/componentPlateMapProps.ts +32 -0
  235. package/src/templates/componentPropsFactory.ts +21 -0
  236. package/src/templates/componentQpcrPlateProps.ts +28 -0
  237. package/src/templates/componentTargetResolvers.ts +69 -0
  238. package/src/templates/componentTemplateProps.ts +78 -0
  239. package/src/templates/controlSchemaClone.ts +32 -0
  240. package/src/templates/controlSchemaConstants.ts +11 -0
  241. package/src/templates/controlSchemaMerge.ts +40 -0
  242. package/src/templates/controlSchemaTargets.ts +87 -0
  243. package/src/templates/controlSchemaTypes.ts +20 -0
  244. package/src/templates/controlSchemas.ts +22 -636
  245. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  246. package/src/templates/doseResponseAdapters.ts +45 -0
  247. package/src/templates/doseResponseBuilder.ts +44 -0
  248. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  249. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  250. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  251. package/src/templates/flowNormalizers.ts +58 -0
  252. package/src/templates/flowPanelAdapters.ts +58 -0
  253. package/src/templates/index.ts +2 -0
  254. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  255. package/src/templates/instrumentRunAdapters.ts +163 -0
  256. package/src/templates/instrumentRunBuilder.ts +97 -0
  257. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  258. package/src/templates/plateGeometry.ts +62 -0
  259. package/src/templates/plateMapAdapters.ts +36 -0
  260. package/src/templates/plateMapBuilder.ts +43 -0
  261. package/src/templates/presetControlSchemas.ts +258 -0
  262. package/src/templates/presets.ts +23 -0
  263. package/src/templates/protocolAdapters.ts +69 -0
  264. package/src/templates/protocolNormalizers.ts +37 -0
  265. package/src/templates/protocolStepsBuilder.ts +36 -0
  266. package/src/templates/qpcrAdapters.ts +104 -0
  267. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  268. package/src/templates/qpcrPlateBuilder.ts +96 -0
  269. package/src/templates/reagentAdapters.ts +77 -0
  270. package/src/templates/reagentListBuilder.ts +30 -0
  271. package/src/templates/runNormalizers.ts +63 -0
  272. package/src/templates/sampleNormalizers.ts +58 -0
  273. package/src/templates/samplePrepAdapters.ts +63 -0
  274. package/src/templates/samplePrepBuilder.ts +51 -0
  275. package/src/templates/sampleSheetAdapters.ts +75 -0
  276. package/src/templates/sampleSheetBuilder.ts +23 -0
  277. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  278. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  279. package/src/templates/templateControlSchemas.ts +320 -0
  280. package/src/templates/templateEnvelopes.ts +137 -0
  281. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  282. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  283. package/src/templates/templateValidators.ts +414 -0
  284. package/src/templates/timeCourseAdapters.ts +73 -0
  285. package/src/templates/timeCourseBuilder.ts +64 -0
  286. package/src/templates/types.ts +17 -0
  287. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  288. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  289. package/src/types/auth.ts +3 -0
  290. package/src/types/components.ts +45 -3
  291. package/src/types/form-builder.ts +2 -1
  292. package/src/types/index.ts +35 -0
  293. package/src/types/instrument.ts +61 -0
  294. package/src/types/platform.ts +4 -0
  295. package/src/utils/rack.ts +209 -0
  296. package/dist/auth-CBG3bWEc.js.map +0 -1
  297. package/dist/components-5KSfsVqf.js.map +0 -1
  298. package/dist/composables-D4Myb30a.js.map +0 -1
  299. package/dist/templates-BSlxwV2c.js.map +0 -1
  300. package/dist/useExperimentData-BbbdI5xT.js.map +0 -1
@@ -1,4 +1,7 @@
1
- import { computed, reactive, ref, watch, type ComputedRef, type Ref } from 'vue'
1
+ import type {
2
+ ComputedRef,
3
+ Ref,
4
+ } from 'vue'
2
5
  import type {
3
6
  PillNavItem,
4
7
  SidebarToolSection,
@@ -6,6 +9,7 @@ import type {
6
9
  SettingsModalSchema,
7
10
  TopBarSettingsConfig,
8
11
  } from '../types'
12
+ import type { AccessPolicy, AccessAudienceInput } from '../permissions'
9
13
  import type {
10
14
  FieldCondition,
11
15
  FieldValidation,
@@ -14,9 +18,55 @@ import type {
14
18
  FormSchema,
15
19
  FormSectionSchema,
16
20
  } from '../types/form-builder'
17
- import { getTypeDefault } from './formBuilderRegistry'
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'
18
42
  import type { WellConcentration } from './useDoseCalculator'
19
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
+
20
70
  export type ControlOptionValue = string | number | boolean
21
71
  export type ControlOption = ControlOptionValue | SelectOption<unknown>
22
72
  export type ControlPrimitive = string | number | boolean
@@ -34,6 +84,11 @@ export interface ControlSectionConfig {
34
84
  iconBg?: string
35
85
  columns?: 1 | 2 | 3
36
86
  condition?: FieldCondition
87
+ access?: AccessPolicy
88
+ visibleFor?: AccessAudienceInput
89
+ requiresAdmin?: boolean
90
+ permissions?: readonly string[]
91
+ anyPermissions?: readonly string[]
37
92
  defaultOpen?: boolean
38
93
  showToggle?: boolean
39
94
  }
@@ -70,6 +125,11 @@ export interface ControlDefinition {
70
125
  pattern?: string | { value: string; message: string }
71
126
  validation?: FieldValidation
72
127
  condition?: FieldCondition
128
+ access?: AccessPolicy
129
+ visibleFor?: AccessAudienceInput
130
+ requiresAdmin?: boolean
131
+ permissions?: readonly string[]
132
+ anyPermissions?: readonly string[]
73
133
  options?: readonly ControlOption[]
74
134
  section?: string
75
135
  sectionLabel?: string
@@ -350,15 +410,6 @@ type ControlValue<TControl> =
350
410
 
351
411
  type OptionValue<TOption> = TOption extends SelectOption<infer TValue> ? TValue : TOption
352
412
 
353
- interface NormalizedControl {
354
- name: string
355
- definition: ControlDefinition
356
- type: FormFieldType
357
- sectionId: string
358
- viewId: string
359
- order: number
360
- }
361
-
362
413
  /** Preserve literal control keys while marking an object as a MINT control schema. */
363
414
  export function defineControls<TControls extends ControlSchema>(controls: TControls): TControls {
364
415
  return controls
@@ -470,52 +521,6 @@ export function getControlDefaults<TControls extends ControlSchema>(
470
521
  return values as ControlValues<TControls>
471
522
  }
472
523
 
473
- /** Map control workspace values into component props for direct `v-bind` usage. */
474
- export function controlValuesToComponentProps<TValues extends Record<string, unknown>>(
475
- values: TValues,
476
- mapping?: ControlComponentPropsMap<TValues>,
477
- ): Record<string, unknown> {
478
- if (mapping === undefined) return { ...values }
479
-
480
- if (Array.isArray(mapping)) {
481
- const props: Record<string, unknown> = {}
482
- for (const key of mapping) {
483
- props[key] = values[key]
484
- }
485
- return props
486
- }
487
-
488
- const props: Record<string, unknown> = {}
489
- for (const [prop, source] of Object.entries(mapping) as Array<[string, ControlComponentPropSource<TValues>]>) {
490
- props[prop] = typeof source === 'function' ? source(values) : values[source]
491
- }
492
- return props
493
- }
494
-
495
- /** Map control workspace values into named SDK component bindings for direct slot rendering. */
496
- export function controlValuesToComponentBindings<TValues extends Record<string, unknown>>(
497
- values: TValues,
498
- bindings?: ControlComponentBindingsConfig<TValues>,
499
- ): ControlComponentBinding[] {
500
- if (bindings === undefined) return []
501
-
502
- return normalizeControlComponentBindingConfigs(bindings).map(binding => ({
503
- id: binding.id,
504
- component: binding.component,
505
- props: controlValuesToComponentProps(values, binding.props),
506
- }))
507
- }
508
-
509
- /** Map control workspace values into SDK component bindings keyed by binding id. */
510
- export function controlValuesToComponentBindingsById<TValues extends Record<string, unknown>>(
511
- values: TValues,
512
- bindings?: ControlComponentBindingsConfig<TValues>,
513
- ): ControlComponentBindingsById {
514
- return Object.fromEntries(
515
- controlValuesToComponentBindings(values, bindings).map(binding => [binding.id, binding]),
516
- )
517
- }
518
-
519
524
  /** Return a default WellPlate prop mapping for generated control workspaces. */
520
525
  export function defineWellPlateControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
521
526
  options: WellPlateControlPropsOptions<TValues> = {},
@@ -649,196 +654,6 @@ export function defineDoseDesignControlModel(
649
654
  })
650
655
  }
651
656
 
652
- function isControlModelBindingInput<TControls extends ControlSchema>(
653
- value: TControls | (ControlModelBinding & { controls: TControls }),
654
- ): value is ControlModelBinding & { controls: TControls } {
655
- return (
656
- typeof value === 'object'
657
- && value !== null
658
- && 'controls' in value
659
- && 'controlOptions' in value
660
- )
661
- }
662
-
663
- export function mergeControlWorkspaceOptions(
664
- base?: ControlWorkspaceOptions,
665
- override?: ControlWorkspaceOptions,
666
- ): ControlWorkspaceOptions {
667
- return {
668
- ...(base ?? {}),
669
- ...(override ?? {}),
670
- initialValues: {
671
- ...(base?.initialValues ?? {}),
672
- ...(override?.initialValues ?? {}),
673
- },
674
- topBarSettings: {
675
- ...(base?.topBarSettings ?? {}),
676
- ...(override?.topBarSettings ?? {}),
677
- },
678
- }
679
- }
680
-
681
- /** Convert a compact control schema into a FormBuilder schema. */
682
- export function controlsToFormSchema(
683
- controls: ControlSchema,
684
- options: ControlSchemaOptions = {},
685
- ): ControlFormSchema {
686
- const normalized = normalizeControls(controls, options)
687
- const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
688
- const sections = sectionIds.map((sectionId): FormSectionSchema => {
689
- const sectionControls = normalized.filter(control => control.sectionId === sectionId)
690
- const config = sectionConfig(sectionId, sectionControls, options)
691
- return {
692
- id: sectionId,
693
- title: config.title ?? config.label ?? humanize(sectionId),
694
- description: config.description,
695
- columns: config.columns ?? options.columns ?? 1,
696
- defaultOpen: config.defaultOpen,
697
- condition: config.condition,
698
- fields: sectionControls.map(controlToFormField),
699
- }
700
- })
701
-
702
- return {
703
- sections,
704
- submitLabel: options.submitLabel,
705
- cancelLabel: options.cancelLabel,
706
- showCancel: options.showCancel,
707
- }
708
- }
709
-
710
- /** Convert controls into AppSidebar panels grouped by view and section. */
711
- export function controlsToSidebarPanels(
712
- controls: ControlSchema,
713
- options: ControlSchemaOptions = {},
714
- ): Record<string, SidebarToolSection[]> {
715
- const normalized = normalizeControls(controls, options)
716
- .filter(control => isSidebarEnabled(control.definition.sidebar))
717
- const viewIds = orderedUnique(normalized.map(control => control.viewId))
718
- const panels: Record<string, SidebarToolSection[]> = {}
719
-
720
- for (const viewId of viewIds) {
721
- const viewControls = normalized.filter(control => control.viewId === viewId)
722
- const sectionIds = orderedUnique(viewControls.map(control => control.sectionId))
723
- panels[viewId] = sectionIds.map((sectionId): SidebarToolSection => {
724
- const sectionControls = viewControls.filter(control => control.sectionId === sectionId)
725
- const config = sectionConfig(sectionId, sectionControls, options)
726
- const sidebarConfig = firstSidebarConfig(sectionControls)
727
- return {
728
- id: sectionId,
729
- label: sidebarConfig?.label ?? config.label ?? config.title ?? humanize(sectionId),
730
- subtitle: sidebarConfig?.subtitle ?? config.subtitle,
731
- icon: sidebarConfig?.icon ?? config.icon,
732
- iconColor: sidebarConfig?.iconColor ?? config.iconColor,
733
- iconBg: sidebarConfig?.iconBg ?? config.iconBg,
734
- defaultOpen: sidebarConfig?.defaultOpen ?? config.defaultOpen,
735
- showToggle: sidebarConfig?.showToggle ?? config.showToggle,
736
- }
737
- })
738
- }
739
-
740
- return panels
741
- }
742
-
743
- /** Convert controls into a SettingsModal schema grouped by the same sections. */
744
- export function controlsToSettingsSchema(
745
- controls: ControlSchema,
746
- options: ControlSchemaOptions = {},
747
- ): SettingsModalSchema {
748
- const normalized = normalizeControls(controls, options)
749
- const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
750
-
751
- return {
752
- groups: sectionIds.map((sectionId) => {
753
- const sectionControls = normalized.filter(control => control.sectionId === sectionId)
754
- const config = sectionConfig(sectionId, sectionControls, options)
755
- return {
756
- id: sectionId,
757
- label: config.label ?? config.title ?? humanize(sectionId),
758
- description: config.description ?? config.subtitle,
759
- icon: typeof config.icon === 'string' ? config.icon : undefined,
760
- fields: sectionControls.map(controlToFormField),
761
- columns: config.columns ?? options.columns ?? 1,
762
- condition: config.condition,
763
- }
764
- }),
765
- }
766
- }
767
-
768
- /** Convert controls into an AppTopBar settingsConfig object that passes compact controls through to SettingsModal. */
769
- export function controlsToTopBarSettingsConfig(
770
- controls: ControlSchema,
771
- options: ControlSchemaOptions = {},
772
- config: Omit<TopBarSettingsConfig, 'schema' | 'controls' | 'controlOptions'> = {},
773
- ): TopBarSettingsConfig {
774
- return {
775
- ...config,
776
- controls,
777
- controlOptions: options,
778
- }
779
- }
780
-
781
- /** Return generated control view IDs that have at least one sidebar panel. */
782
- export function controlsToViewIds(
783
- controls: ControlSchema,
784
- options: ControlSchemaOptions = {},
785
- ): string[] {
786
- return controlsToViewItems(controls, options).map(item => item.id)
787
- }
788
-
789
- /** Return AppTopBar pillNav-compatible view items for switching generated control sidebars. */
790
- export function controlsToViewItems(
791
- controls: ControlSchema,
792
- options: ControlSchemaOptions = {},
793
- ): PillNavItem[] {
794
- return Object.entries(controlsToSidebarPanels(controls, options))
795
- .filter(([, sections]) => sections.length > 0)
796
- .map(([id]) => controlViewItem(id, options))
797
- }
798
-
799
- /** Return the first generated sidebar view ID, or an empty string when controls render no sidebar panels. */
800
- export function getDefaultControlView(
801
- controls: ControlSchema,
802
- options: ControlSchemaOptions = {},
803
- ): string {
804
- return controlsToViewIds(controls, options)[0] ?? ''
805
- }
806
-
807
- /** Return a headerless single-section FormBuilder schema for rendering inside an AppSidebar section slot. */
808
- export function controlsToSectionFormSchema(
809
- controls: ControlSchema,
810
- sectionId: string,
811
- options: ControlSchemaOptions = {},
812
- ): ControlFormSchema {
813
- const schema = controlsToFormSchema(controls, options)
814
- return {
815
- sections: schema.sections
816
- .filter(section => section.id === sectionId)
817
- .map(section => ({ ...section, title: '', description: undefined })),
818
- submitLabel: schema.submitLabel,
819
- cancelLabel: schema.cancelLabel,
820
- showCancel: schema.showCancel,
821
- }
822
- }
823
-
824
- /** Return headerless FormBuilder schemas keyed by section ID for AppSidebar auto-rendering. */
825
- export function controlsToSectionFormSchemas(
826
- controls: ControlSchema,
827
- options: ControlSchemaOptions = {},
828
- ): Record<string, ControlFormSchema> {
829
- const schema = controlsToFormSchema(controls, options)
830
- const schemas: Record<string, ControlFormSchema> = {}
831
- for (const section of schema.sections) {
832
- schemas[section.id] = {
833
- sections: [{ ...section, title: '', description: undefined }],
834
- submitLabel: schema.submitLabel,
835
- cancelLabel: schema.cancelLabel,
836
- showCancel: schema.showCancel,
837
- }
838
- }
839
- return schemas
840
- }
841
-
842
657
  /** Prepare FormBuilder, SettingsModal, AppTopBar settings, AppSidebar, and initial values from one compact control model. */
843
658
  export function useControlSchema<TControls extends ControlSchema>(
844
659
  controls: TControls,
@@ -886,195 +701,6 @@ export function useControlSchema<TControls extends ControlSchema>(
886
701
  }
887
702
  }
888
703
 
889
- /** Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model. */
890
- export function useControlWorkspace<TControls extends ControlSchema>(
891
- controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),
892
- options: ControlWorkspaceOptions = {},
893
- ): UseControlWorkspaceReturn<TControls> {
894
- const model = isControlModelBindingInput<TControls>(controlsOrModel) ? controlsOrModel : undefined
895
- const controls: TControls = model ? model.controls : controlsOrModel as TControls
896
- const workspaceOptions = model
897
- ? mergeControlWorkspaceOptions(model.controlOptions, options)
898
- : options
899
- const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions
900
- const schema = useControlSchema(controls, schemaOptions)
901
- const activeView = ref(schema.defaultView)
902
- const values = reactive({
903
- ...schema.initialValues,
904
- ...(initialValues ?? {}),
905
- }) as ControlValues<TControls> & Record<string, unknown>
906
-
907
- function setActiveView(viewId: string) {
908
- syncActiveView(viewId)
909
- }
910
-
911
- function syncActiveView(viewId: string) {
912
- if (!schema.viewIds.includes(viewId)) return
913
- if (activeView.value !== viewId) activeView.value = viewId
914
- if (sidebar.activeView !== viewId) sidebar.activeView = viewId
915
- if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId
916
- }
917
-
918
- function setValues(nextValues: Record<string, unknown>) {
919
- Object.assign(values, nextValues)
920
- }
921
-
922
- function resetValues(nextValues: Record<string, unknown> = {}) {
923
- replaceRecord(values, {
924
- ...schema.initialValues,
925
- ...nextValues,
926
- })
927
- }
928
-
929
- function getComponentProps(
930
- mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,
931
- ): Record<string, unknown> {
932
- return controlValuesToComponentProps(values, mapping)
933
- }
934
-
935
- function getComponentPropsById(
936
- mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,
937
- ): Record<string, Record<string, unknown>> {
938
- if (mappings === undefined) return {}
939
-
940
- return Object.fromEntries(
941
- Object.entries(mappings).map(([id, mapping]) => [
942
- id,
943
- controlValuesToComponentProps(values, mapping),
944
- ]),
945
- )
946
- }
947
-
948
- function getComponentBindings(
949
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
950
- ): ControlComponentBinding[] {
951
- return controlValuesToComponentBindings(values, bindings)
952
- }
953
-
954
- function getComponentBindingsById(
955
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
956
- ): ControlComponentBindingsById {
957
- return controlValuesToComponentBindingsById(values, bindings)
958
- }
959
- const componentProps = computed(() => (
960
- model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)
961
- ))
962
- const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))
963
- const componentBindings = computed(() => getComponentBindings(model?.componentBindings))
964
- const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))
965
- const form = {
966
- ...schema.form,
967
- modelValue: values,
968
- 'onUpdate:modelValue': setValues,
969
- } as ControlWorkspaceFormBinding
970
-
971
- const topBarSettingsConfig: TopBarSettingsConfig = {
972
- ...schema.topBarSettingsConfig,
973
- ...(topBarSettings ?? {}),
974
- values,
975
- }
976
- const sidebar = reactive({
977
- ...schema.sidebar,
978
- activeView: activeView.value,
979
- modelValue: values,
980
- 'onUpdate:modelValue': setValues,
981
- values,
982
- 'onUpdate:values': setValues,
983
- }) as ControlWorkspaceSidebarBinding
984
- const pillNav = reactive({
985
- items: schema.viewItems,
986
- currentItemId: activeView.value,
987
- onSelect: (item: PillNavItem) => setActiveView(item.id),
988
- }) as ControlWorkspacePillNavBinding
989
- const topBarSettingsBinding = {
990
- showSettings: true,
991
- settingsConfig: topBarSettingsConfig,
992
- onSettingsValuesChange: setValues,
993
- } as ControlWorkspaceTopBarSettingsBinding
994
- const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({
995
- pillNav: pillNav.items,
996
- currentPillId: pillNav.currentItemId,
997
- onPillSelect: pillNav.onSelect,
998
- ...topBarSettingsBinding,
999
- }))
1000
- const bindings: ControlWorkspaceComponentBindings = {
1001
- form,
1002
- sidebar,
1003
- topBar: topBarProps,
1004
- topBarSettings: topBarSettingsBinding,
1005
- pillNav,
1006
- componentBindings,
1007
- componentBindingsById,
1008
- componentProps,
1009
- componentPropsById,
1010
- }
1011
-
1012
- watch(activeView, syncActiveView, { flush: 'sync' })
1013
- watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })
1014
- watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })
1015
-
1016
- return {
1017
- ...schema,
1018
- schema,
1019
- values,
1020
- activeView,
1021
- topBarSettingsConfig,
1022
- form,
1023
- sidebar,
1024
- topBar: topBarProps,
1025
- pillNav,
1026
- topBarSettings: topBarSettingsBinding,
1027
- bindings,
1028
- componentBindings,
1029
- componentBindingsById,
1030
- componentProps,
1031
- componentPropsById,
1032
- setActiveView,
1033
- setValues,
1034
- resetValues,
1035
- getComponentProps,
1036
- getComponentPropsById,
1037
- getComponentBindings,
1038
- getComponentBindingsById,
1039
- }
1040
- }
1041
-
1042
- function normalizeControls(
1043
- controls: ControlSchema,
1044
- options: ControlSchemaOptions = {},
1045
- ): NormalizedControl[] {
1046
- return Object.entries(controls)
1047
- .map(([name, input], index): NormalizedControl => {
1048
- const definition = normalizeControlDefinition(input)
1049
- const type = definition.type ?? inferControlType(definition)
1050
- return {
1051
- name,
1052
- definition,
1053
- type,
1054
- sectionId: definition.section ?? options.section ?? 'controls',
1055
- viewId: definition.view ?? options.view ?? 'default',
1056
- order: definition.order ?? index,
1057
- }
1058
- })
1059
- .sort((a, b) => a.order - b.order)
1060
- }
1061
-
1062
- function normalizeControlDefinition(input: ControlInput): ControlDefinition {
1063
- if (isControlOptionArray(input)) {
1064
- if (input.length === 0) return { type: 'tags', default: [] }
1065
- return {
1066
- default: optionValue(input[0]),
1067
- options: input,
1068
- }
1069
- }
1070
-
1071
- if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {
1072
- return { default: input }
1073
- }
1074
-
1075
- return input
1076
- }
1077
-
1078
704
  function appendModelControls(
1079
705
  target: ControlSchema,
1080
706
  source: ControlSchema,
@@ -1116,113 +742,6 @@ function registerSectionOptions(
1116
742
  })
1117
743
  }
1118
744
 
1119
- function isControlOptionArray(input: ControlInput): input is readonly ControlOption[] {
1120
- return Array.isArray(input)
1121
- }
1122
-
1123
- function inferControlType(definition: ControlDefinition): FormFieldType {
1124
- const value = definition.default ?? definition.defaultValue
1125
- if (definition.options?.length) return Array.isArray(value) ? 'multiselect' : 'select'
1126
- if (typeof value === 'boolean') return 'toggle'
1127
- if (typeof value === 'number') return 'number'
1128
- if (Array.isArray(value)) return 'tags'
1129
- return 'text'
1130
- }
1131
-
1132
- function defaultValueForControl(definition: ControlDefinition, type: FormFieldType): unknown {
1133
- if (definition.default !== undefined) return definition.default
1134
- if (definition.defaultValue !== undefined) return definition.defaultValue
1135
- return getTypeDefault(type)
1136
- }
1137
-
1138
- function controlToFormField(control: NormalizedControl): FormFieldSchema {
1139
- const { name, definition, type } = control
1140
- const props = fieldProps(definition)
1141
- return {
1142
- name,
1143
- label: definition.label ?? humanize(name),
1144
- type,
1145
- defaultValue: defaultValueForControl(definition, type),
1146
- placeholder: definition.placeholder,
1147
- hint: definition.hint,
1148
- size: definition.size,
1149
- disabled: definition.disabled,
1150
- readonly: definition.readonly,
1151
- validation: validationForControl(definition),
1152
- condition: definition.condition,
1153
- colSpan: definition.colSpan,
1154
- props,
1155
- }
1156
- }
1157
-
1158
- function fieldProps(definition: ControlDefinition): Record<string, unknown> {
1159
- const props: Record<string, unknown> = {}
1160
- if (definition.min !== undefined) props.min = numericValue(definition.min)
1161
- if (definition.max !== undefined) props.max = numericValue(definition.max)
1162
- if (definition.options) props.options = definition.options.map(normalizeOption)
1163
- return { ...props, ...(definition.props ?? {}) }
1164
- }
1165
-
1166
- function validationForControl(definition: ControlDefinition): FieldValidation | undefined {
1167
- const validation: FieldValidation = { ...(definition.validation ?? {}) }
1168
- if (definition.required !== undefined) validation.required = definition.required
1169
- if (definition.min !== undefined) validation.min = definition.min
1170
- if (definition.max !== undefined) validation.max = definition.max
1171
- if (definition.minLength !== undefined) validation.minLength = definition.minLength
1172
- if (definition.maxLength !== undefined) validation.maxLength = definition.maxLength
1173
- if (definition.email !== undefined) validation.email = definition.email
1174
- if (definition.pattern !== undefined) validation.pattern = definition.pattern
1175
- return Object.keys(validation).length > 0 ? validation : undefined
1176
- }
1177
-
1178
- function sectionConfig(
1179
- sectionId: string,
1180
- controls: NormalizedControl[],
1181
- options: ControlSchemaOptions,
1182
- ): ControlSectionConfig {
1183
- const configured = options.sections?.[sectionId]
1184
- const first = controls[0]?.definition
1185
- return {
1186
- ...configured,
1187
- id: sectionId,
1188
- label: configured?.label ?? first?.sectionLabel,
1189
- title: configured?.title ?? first?.sectionLabel,
1190
- description: configured?.description ?? first?.sectionDescription,
1191
- subtitle: configured?.subtitle ?? first?.sectionSubtitle,
1192
- }
1193
- }
1194
-
1195
- function firstSidebarConfig(controls: NormalizedControl[]): ControlSidebarConfig | undefined {
1196
- for (const control of controls) {
1197
- const sidebar = control.definition.sidebar
1198
- if (sidebar && typeof sidebar === 'object' && sidebar.enabled !== false) return sidebar
1199
- }
1200
- return undefined
1201
- }
1202
-
1203
- function isSidebarEnabled(sidebar: ControlDefinition['sidebar']): boolean {
1204
- if (sidebar === false) return false
1205
- if (sidebar && typeof sidebar === 'object') return sidebar.enabled !== false
1206
- return true
1207
- }
1208
-
1209
- function normalizeOption(option: ControlOption): SelectOption<unknown> {
1210
- if (typeof option === 'object' && option !== null && 'label' in option) {
1211
- return option
1212
- }
1213
- return {
1214
- value: option,
1215
- label: humanize(String(option)),
1216
- }
1217
- }
1218
-
1219
- function optionValue(option: ControlOption): ControlOptionValue | unknown {
1220
- if (typeof option === 'object' && option !== null && 'value' in option) {
1221
- return option.value
1222
- }
1223
- return option
1224
- }
1225
-
1226
745
  function compactComponentPropsMap<TValues extends Record<string, unknown>>(
1227
746
  mapping: Record<string, ControlComponentPropSource<TValues> | undefined>,
1228
747
  ): ControlComponentPropsMap<TValues> {
@@ -1233,31 +752,6 @@ function compactComponentPropsMap<TValues extends Record<string, unknown>>(
1233
752
  )
1234
753
  }
1235
754
 
1236
- function normalizeControlComponentBindingConfigs<TValues extends Record<string, unknown>>(
1237
- bindings: ControlComponentBindingsConfig<TValues>,
1238
- ): Array<Required<Pick<ControlComponentBindingConfig<TValues>, 'id' | 'component'>> & Pick<ControlComponentBindingConfig<TValues>, 'props'>> {
1239
- if (Array.isArray(bindings)) {
1240
- const usedIds = new Map<string, number>()
1241
- return bindings.map(binding => ({
1242
- id: uniqueComponentBindingId(binding.id ?? binding.component, usedIds),
1243
- component: binding.component,
1244
- props: binding.props,
1245
- }))
1246
- }
1247
-
1248
- return Object.entries(bindings).map(([id, binding]) => ({
1249
- id,
1250
- component: binding.component,
1251
- props: binding.props,
1252
- }))
1253
- }
1254
-
1255
- function uniqueComponentBindingId(id: string, usedIds: Map<string, number>): string {
1256
- const count = usedIds.get(id) ?? 0
1257
- usedIds.set(id, count + 1)
1258
- return count === 0 ? id : `${id}-${count + 1}`
1259
- }
1260
-
1261
755
  function sourceKey<TValues extends Record<string, unknown>>(key: string): keyof TValues & string {
1262
756
  return key as keyof TValues & string
1263
757
  }
@@ -1310,53 +804,3 @@ function updateWellsFromDoseResults<TValues extends Record<string, unknown>>(
1310
804
  writableValues[source] = nextWells
1311
805
  }
1312
806
  }
1313
-
1314
- function recordValue(value: unknown): Record<string, unknown> {
1315
- return typeof value === 'object' && value !== null && !Array.isArray(value)
1316
- ? value as Record<string, unknown>
1317
- : {}
1318
- }
1319
-
1320
- function numericValue(value: number | { value: number; message: string }): number {
1321
- return typeof value === 'number' ? value : value.value
1322
- }
1323
-
1324
- function orderedUnique(values: string[]): string[] {
1325
- return [...new Set(values)]
1326
- }
1327
-
1328
- function controlViewItem(viewId: string, options: ControlSchemaOptions): PillNavItem {
1329
- const config = options.views?.[viewId]
1330
- return {
1331
- id: viewId,
1332
- label: config?.label ?? humanize(viewId),
1333
- ...(config?.icon !== undefined ? { icon: config.icon } : {}),
1334
- ...(config?.to !== undefined ? { to: config.to } : {}),
1335
- ...(config?.href !== undefined ? { href: config.href } : {}),
1336
- ...(config?.disabled !== undefined ? { disabled: config.disabled } : {}),
1337
- ...(config?.children !== undefined ? { children: config.children } : {}),
1338
- }
1339
- }
1340
-
1341
- function replaceRecord(target: Record<string, unknown>, values: Record<string, unknown>) {
1342
- for (const key of Object.keys(target)) {
1343
- delete target[key]
1344
- }
1345
- Object.assign(target, values)
1346
- }
1347
-
1348
- function omitUndefined<T extends object>(record: T): T {
1349
- const next: Record<string, unknown> = {}
1350
- for (const [key, value] of Object.entries(record as Record<string, unknown>)) {
1351
- if (value !== undefined) next[key] = value
1352
- }
1353
- return next as T
1354
- }
1355
-
1356
- function humanize(value: string): string {
1357
- return value
1358
- .replace(/[_-]+/g, ' ')
1359
- .replace(/([a-z])([A-Z])/g, '$1 $2')
1360
- .trim()
1361
- .replace(/\w\S*/g, word => word.charAt(0).toUpperCase() + word.slice(1))
1362
- }