@morscherlab/mint-sdk 1.0.0-rc.4 → 1.0.0-rc.5

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 (304) hide show
  1. package/dist/__tests__/components/AppTopBar.navigation.test.d.ts +1 -0
  2. package/dist/__tests__/components/DoseCalculatorVolumeField.test.d.ts +1 -0
  3. package/dist/__tests__/components/PlateMapEditorToolbarInternal.test.d.ts +1 -0
  4. package/dist/__tests__/components/PluginWorkspaceView.controls.test.d.ts +1 -0
  5. package/dist/__tests__/components/PluginWorkspaceView.navigation.test.d.ts +1 -0
  6. package/dist/__tests__/components/PluginWorkspaceView.shell.test.d.ts +1 -0
  7. package/dist/__tests__/components/ProtocolStep.presentation.test.d.ts +1 -0
  8. package/dist/__tests__/components/ProtocolStepEditor.state.test.d.ts +1 -0
  9. package/dist/__tests__/components/ProtocolStepParameterField.test.d.ts +1 -0
  10. package/dist/__tests__/components/ReagentList.presentation.test.d.ts +1 -0
  11. package/dist/__tests__/components/SampleSelector.colors.test.d.ts +1 -0
  12. package/dist/__tests__/components/SampleSelector.drag.test.d.ts +1 -0
  13. package/dist/__tests__/components/SampleSelector.groups.test.d.ts +1 -0
  14. package/dist/__tests__/components/SampleSelector.selection.test.d.ts +1 -0
  15. package/dist/__tests__/components/SampleSelectorSampleRow.test.d.ts +1 -0
  16. package/dist/__tests__/components/ScheduleCalendar.test.d.ts +1 -0
  17. package/dist/__tests__/components/SettingsModal.schema.test.d.ts +1 -0
  18. package/dist/__tests__/components/WellPlate.colors.test.d.ts +1 -0
  19. package/dist/__tests__/components/WellPlate.conditions.test.d.ts +1 -0
  20. package/dist/__tests__/components/WellPlate.geometry.test.d.ts +1 -0
  21. package/dist/__tests__/components/WellPlate.interaction.test.d.ts +1 -0
  22. package/dist/__tests__/components/WellPlate.legend.test.d.ts +1 -0
  23. package/dist/__tests__/components/WellPlate.rendering.test.d.ts +1 -0
  24. package/dist/__tests__/components/WellPlate.sampleDrop.test.d.ts +1 -0
  25. package/dist/__tests__/composables/autoGroup/classify.test.d.ts +1 -0
  26. package/dist/__tests__/composables/autoGroup/columns.test.d.ts +1 -0
  27. package/dist/__tests__/composables/autoGroup/compose.test.d.ts +1 -0
  28. package/dist/__tests__/composables/autoGroup/cooccurrence.test.d.ts +1 -0
  29. package/dist/__tests__/composables/autoGroup/fingerprint.test.d.ts +1 -0
  30. package/dist/__tests__/composables/autoGroup/integration.test.d.ts +1 -0
  31. package/dist/__tests__/composables/autoGroup/template.test.d.ts +1 -0
  32. package/dist/__tests__/composables/autoGroup/tokenize.test.d.ts +1 -0
  33. package/dist/__tests__/composables/useAutoGroupInputSources.test.d.ts +1 -0
  34. package/dist/__tests__/composables/useScheduleCalendarLayout.test.d.ts +1 -0
  35. package/dist/__tests__/docs/extractDocsComponents.test.d.ts +1 -0
  36. package/dist/__tests__/docs/extractDocsExports.test.d.ts +1 -0
  37. package/dist/__tests__/docs/extractDocsParsing.test.d.ts +1 -0
  38. package/dist/__tests__/docs/extractDocsTemplates.test.d.ts +1 -0
  39. package/dist/__tests__/docs/extractDocsTheme.test.d.ts +1 -0
  40. package/dist/components/AppSidebar.vue.d.ts +3 -3
  41. package/dist/components/AppTopBar.navigation.d.ts +11 -0
  42. package/dist/components/BaseButton.vue.d.ts +1 -1
  43. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  44. package/dist/components/BaseInput.vue.d.ts +2 -2
  45. package/dist/components/BasePill.vue.d.ts +1 -1
  46. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  47. package/dist/components/BaseSelect.vue.d.ts +1 -1
  48. package/dist/components/BaseSlider.vue.d.ts +2 -2
  49. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  50. package/dist/components/BaseToggle.vue.d.ts +1 -1
  51. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  52. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  53. package/dist/components/ColorSlider.vue.d.ts +2 -2
  54. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  55. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  56. package/dist/components/DatePicker.vue.d.ts +1 -1
  57. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  58. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  59. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
  60. package/dist/components/DropdownButton.vue.d.ts +1 -1
  61. package/dist/components/FileUploader.vue.d.ts +2 -2
  62. package/dist/components/FormulaInput.vue.d.ts +2 -2
  63. package/dist/components/IconButton.vue.d.ts +1 -1
  64. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  65. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  66. package/dist/components/MultiSelect.vue.d.ts +1 -1
  67. package/dist/components/NumberInput.vue.d.ts +1 -1
  68. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  69. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  70. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  71. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  72. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  73. package/dist/components/PluginWorkspaceView.vue.d.ts +46 -195
  74. package/dist/components/ProgressBar.vue.d.ts +1 -1
  75. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  76. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  77. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  78. package/dist/components/ReagentList.presentation.d.ts +16 -0
  79. package/dist/components/ResourceCard.vue.d.ts +1 -1
  80. package/dist/components/SampleSelector.colors.d.ts +13 -0
  81. package/dist/components/SampleSelector.drag.d.ts +24 -0
  82. package/dist/components/SampleSelector.groups.d.ts +15 -0
  83. package/dist/components/SampleSelector.selection.d.ts +26 -0
  84. package/dist/components/SampleSelector.vue.d.ts +4 -1
  85. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  86. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  87. package/dist/components/SequenceInput.vue.d.ts +2 -2
  88. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  89. package/dist/components/SettingsModal.schema.d.ts +9 -0
  90. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  91. package/dist/components/TagsInput.vue.d.ts +2 -2
  92. package/dist/components/TimePicker.vue.d.ts +2 -2
  93. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  94. package/dist/components/UnitInput.vue.d.ts +2 -2
  95. package/dist/components/WellPlate.colors.d.ts +9 -0
  96. package/dist/components/WellPlate.conditions.d.ts +26 -0
  97. package/dist/components/WellPlate.geometry.d.ts +23 -0
  98. package/dist/components/WellPlate.interaction.d.ts +71 -0
  99. package/dist/components/WellPlate.legend.d.ts +2 -0
  100. package/dist/components/WellPlate.rendering.d.ts +24 -0
  101. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  102. package/dist/components/WellPlate.vue.d.ts +1 -1
  103. package/dist/components/index.js +2 -2
  104. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  105. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  106. package/dist/{components-DafPc4rM.js → components-DtHA2bgp.js} +3754 -2991
  107. package/dist/components-DtHA2bgp.js.map +1 -0
  108. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  109. package/dist/composables/autoGroup/classify.d.ts +28 -0
  110. package/dist/composables/autoGroup/colors.d.ts +2 -0
  111. package/dist/composables/autoGroup/columns.d.ts +10 -0
  112. package/dist/composables/autoGroup/compose.d.ts +8 -0
  113. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  114. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  115. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  116. package/dist/composables/autoGroup/index.d.ts +16 -0
  117. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  118. package/dist/composables/autoGroup/template.d.ts +15 -0
  119. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  120. package/dist/composables/autoGroupConstants.d.ts +1 -0
  121. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  122. package/dist/composables/controlComponentBindings.d.ts +1 -1
  123. package/dist/composables/controlSchemaAdapters.d.ts +1 -1
  124. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  125. package/dist/composables/controlSchemaLayout.d.ts +1 -1
  126. package/dist/composables/controlSchemaModel.d.ts +5 -0
  127. package/dist/composables/controlSchemaNormalize.d.ts +1 -1
  128. package/dist/composables/controlSchemaTypes.d.ts +305 -0
  129. package/dist/composables/controlWorkspaceOptions.d.ts +1 -1
  130. package/dist/composables/formBuilderSchema.d.ts +18 -0
  131. package/dist/composables/index.js +3 -3
  132. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  133. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  134. package/dist/composables/useAutoGroup.d.ts +61 -74
  135. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  136. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  137. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  138. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  139. package/dist/composables/useControlSchema.d.ts +4 -316
  140. package/dist/composables/useControlWorkspace.d.ts +1 -1
  141. package/dist/composables/useForm.d.ts +2 -33
  142. package/dist/composables/useFormBuilder.d.ts +2 -9
  143. package/dist/composables/useFormValidation.d.ts +34 -0
  144. package/dist/composables/usePluginClient.d.ts +1 -4
  145. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  146. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  147. package/dist/{composables-BMkPQhVK.js → composables-Dlg8jenH.js} +33 -31
  148. package/dist/composables-Dlg8jenH.js.map +1 -0
  149. package/dist/index.js +4 -4
  150. package/dist/install.js +2 -2
  151. package/dist/styles.css +547 -516
  152. package/dist/templates/controlSchemaTypes.d.ts +1 -1
  153. package/dist/templates/index.js +1 -1
  154. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  155. package/dist/templates/templateCreateOptions.d.ts +165 -0
  156. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  157. package/dist/templates/types.d.ts +5 -250
  158. package/dist/{templates-bUAWMn5L.js → templates-DtdUvJ4c.js} +144 -136
  159. package/dist/templates-DtdUvJ4c.js.map +1 -0
  160. package/dist/types/auto-group.d.ts +79 -9
  161. package/dist/types/componentLabTypes.d.ts +161 -0
  162. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  163. package/dist/types/components.d.ts +2 -311
  164. package/dist/{useProtocolTemplates-QZtHFFH2.js → useProtocolTemplates-Bm5vyH4_.js} +1220 -454
  165. package/dist/useProtocolTemplates-Bm5vyH4_.js.map +1 -0
  166. package/package.json +1 -1
  167. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  168. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  169. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  170. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  171. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  172. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +41 -0
  173. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  174. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  175. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  176. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  177. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  178. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  179. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  180. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  181. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  182. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  183. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  184. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  185. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  186. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  187. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  188. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  189. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  190. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  191. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  192. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  193. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  194. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  195. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  196. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  197. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  198. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  199. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  200. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  201. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  202. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  203. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  204. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  205. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  206. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  207. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  208. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  209. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  210. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  211. package/src/components/AppSidebar.vue +2 -6
  212. package/src/components/AppTopBar.navigation.ts +62 -0
  213. package/src/components/AppTopBar.vue +17 -44
  214. package/src/components/AutoGroupModal.story.vue +50 -0
  215. package/src/components/AutoGroupModal.vue +441 -158
  216. package/src/components/ControlWorkspaceView.vue +2 -6
  217. package/src/components/DoseCalculator.vue +13 -73
  218. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  219. package/src/components/ExperimentTimeline.vue +6 -31
  220. package/src/components/FormBuilder.vue +2 -7
  221. package/src/components/PlateMapEditor.vue +32 -106
  222. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  223. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  224. package/src/components/PluginWorkspaceView.props.ts +174 -0
  225. package/src/components/PluginWorkspaceView.shell.ts +66 -0
  226. package/src/components/PluginWorkspaceView.vue +85 -404
  227. package/src/components/ProtocolStep.presentation.ts +31 -0
  228. package/src/components/ProtocolStepEditor.state.ts +104 -0
  229. package/src/components/ProtocolStepEditor.vue +48 -179
  230. package/src/components/ProtocolStepParameterField.vue +134 -0
  231. package/src/components/ReagentList.presentation.ts +105 -0
  232. package/src/components/ReagentList.vue +16 -79
  233. package/src/components/SampleSelector.colors.ts +43 -0
  234. package/src/components/SampleSelector.drag.ts +164 -0
  235. package/src/components/SampleSelector.groups.ts +109 -0
  236. package/src/components/SampleSelector.selection.ts +103 -0
  237. package/src/components/SampleSelector.vue +82 -349
  238. package/src/components/SampleSelectorSampleRow.vue +64 -0
  239. package/src/components/ScheduleCalendar.vue +44 -199
  240. package/src/components/SettingsModal.schema.ts +71 -0
  241. package/src/components/SettingsModal.vue +16 -46
  242. package/src/components/WellPlate.colors.ts +56 -0
  243. package/src/components/WellPlate.conditions.ts +100 -0
  244. package/src/components/WellPlate.geometry.ts +91 -0
  245. package/src/components/WellPlate.interaction.ts +272 -0
  246. package/src/components/WellPlate.legend.ts +8 -0
  247. package/src/components/WellPlate.rendering.ts +105 -0
  248. package/src/components/WellPlate.sampleDrop.ts +73 -0
  249. package/src/components/WellPlate.vue +102 -550
  250. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  251. package/src/composables/autoGroup/classKey.ts +5 -0
  252. package/src/composables/autoGroup/classify.ts +205 -0
  253. package/src/composables/autoGroup/colors.ts +6 -0
  254. package/src/composables/autoGroup/columns.ts +226 -0
  255. package/src/composables/autoGroup/compose.ts +156 -0
  256. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  257. package/src/composables/autoGroup/csv-shim.ts +44 -0
  258. package/src/composables/autoGroup/fingerprint.ts +49 -0
  259. package/src/composables/autoGroup/index.ts +20 -0
  260. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  261. package/src/composables/autoGroup/template.ts +126 -0
  262. package/src/composables/autoGroup/tokenize.ts +41 -0
  263. package/src/composables/autoGroup/vocab.json +67 -0
  264. package/src/composables/autoGroupConstants.ts +4 -0
  265. package/src/composables/autoGroupGrouping.ts +148 -0
  266. package/src/composables/controlComponentBindings.ts +1 -1
  267. package/src/composables/controlSchemaAdapters.ts +1 -1
  268. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  269. package/src/composables/controlSchemaFormFields.ts +1 -1
  270. package/src/composables/controlSchemaLayout.ts +1 -1
  271. package/src/composables/controlSchemaModel.ts +163 -0
  272. package/src/composables/controlSchemaNormalize.ts +1 -1
  273. package/src/composables/controlSchemaTypes.ts +364 -0
  274. package/src/composables/controlWorkspaceOptions.ts +1 -1
  275. package/src/composables/formBuilderSchema.ts +153 -0
  276. package/src/composables/pluginEndpointBuilder.ts +203 -0
  277. package/src/composables/protocolTemplateCatalog.ts +325 -0
  278. package/src/composables/useAutoGroup.ts +395 -549
  279. package/src/composables/useAutoGroupInputSources.ts +147 -0
  280. package/src/composables/useBioTemplateControls.ts +1 -1
  281. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  282. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  283. package/src/composables/useControlSchema.ts +21 -692
  284. package/src/composables/useControlWorkspace.ts +7 -13
  285. package/src/composables/useForm.ts +5 -187
  286. package/src/composables/useFormBuilder.ts +11 -153
  287. package/src/composables/useFormValidation.ts +154 -0
  288. package/src/composables/usePluginClient.ts +10 -193
  289. package/src/composables/useProtocolTemplates.ts +10 -328
  290. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  291. package/src/styles/components/auto-group-modal.css +248 -310
  292. package/src/templates/controlSchemaTypes.ts +1 -1
  293. package/src/templates/templateAdapterTypes.ts +58 -0
  294. package/src/templates/templateCreateOptions.ts +208 -0
  295. package/src/templates/templateQpcrTypes.ts +48 -0
  296. package/src/templates/types.ts +79 -275
  297. package/src/types/auto-group.ts +107 -9
  298. package/src/types/componentLabTypes.ts +235 -0
  299. package/src/types/componentWorkflowTypes.ts +190 -0
  300. package/src/types/components.ts +74 -424
  301. package/dist/components-DafPc4rM.js.map +0 -1
  302. package/dist/composables-BMkPQhVK.js.map +0 -1
  303. package/dist/templates-bUAWMn5L.js.map +0 -1
  304. package/dist/useProtocolTemplates-QZtHFFH2.js.map +0 -1
@@ -0,0 +1,148 @@
1
+ import type {
2
+ AutoGroupResult,
3
+ ColumnInfo,
4
+ MetadataRow,
5
+ OutlierAction,
6
+ ParsedCsvData,
7
+ } from '../types/auto-group'
8
+ import type { SampleGroup } from '../types/components'
9
+ import { DEFAULT_COLORS } from './autoGroupConstants'
10
+
11
+ export function computeGroups(
12
+ allSamples: string[],
13
+ columns: ColumnInfo[],
14
+ enabledFields: Set<number>,
15
+ outlierActions: Map<number, OutlierAction>,
16
+ delimiter: string,
17
+ minFieldCount: number,
18
+ ): AutoGroupResult {
19
+ const excludedSamples: string[] = []
20
+ const qcSamples: string[] = []
21
+ const conformingSamples: string[] = []
22
+
23
+ for (let i = 0; i < allSamples.length; i++) {
24
+ const action = outlierActions.get(i)
25
+ if (action === 'exclude') {
26
+ excludedSamples.push(allSamples[i])
27
+ } else if (action === 'qc') {
28
+ qcSamples.push(allSamples[i])
29
+ } else {
30
+ conformingSamples.push(allSamples[i])
31
+ }
32
+ }
33
+
34
+ // Build group map
35
+ const groupMap = new Map<string, string[]>()
36
+ const metadata: MetadataRow[] = []
37
+ const enabledIndices = [...enabledFields].sort((a, b) => a - b)
38
+ const suffixCount = minFieldCount - 1
39
+
40
+ for (const sample of conformingSamples) {
41
+ const parts = sample.split(delimiter)
42
+ const splitAt = Math.max(1, parts.length - suffixCount)
43
+ const row = [
44
+ parts.slice(0, splitAt).join(delimiter),
45
+ ...parts.slice(splitAt),
46
+ ]
47
+
48
+ // Build group key from enabled columns
49
+ const keyParts: string[] = []
50
+ for (const idx of enabledIndices) {
51
+ if (idx < row.length && idx < columns.length) {
52
+ keyParts.push(row[idx])
53
+ }
54
+ }
55
+ const groupKey = keyParts.join(' / ')
56
+
57
+ const group = groupMap.get(groupKey)
58
+ if (group) {
59
+ group.push(sample)
60
+ } else {
61
+ groupMap.set(groupKey, [sample])
62
+ }
63
+
64
+ // Build metadata row with ALL columns
65
+ const fields: Record<string, string> = {}
66
+ for (const col of columns) {
67
+ if (col.index < row.length) {
68
+ fields[col.name] = row[col.index]
69
+ }
70
+ }
71
+ metadata.push({ sampleName: sample, fields, group: groupKey })
72
+ }
73
+
74
+ // Convert to SampleGroup[]
75
+ const groups: SampleGroup[] = []
76
+ let colorIdx = 0
77
+ for (const [name, samples] of groupMap) {
78
+ groups.push({
79
+ name,
80
+ color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],
81
+ samples,
82
+ })
83
+ colorIdx++
84
+ }
85
+
86
+ // QC group
87
+ if (qcSamples.length > 0) {
88
+ groups.push({
89
+ name: 'QC',
90
+ color: '#6B7280',
91
+ samples: qcSamples,
92
+ })
93
+ for (const sample of qcSamples) {
94
+ metadata.push({ sampleName: sample, fields: {}, group: 'QC' })
95
+ }
96
+ }
97
+
98
+ return { groups, metadata, excludedSamples }
99
+ }
100
+
101
+ export function computeGroupsFromCsv(
102
+ csvData: ParsedCsvData,
103
+ columns: ColumnInfo[],
104
+ enabledFields: Set<number>,
105
+ ): AutoGroupResult {
106
+ const groupMap = new Map<string, string[]>()
107
+ const metadata: MetadataRow[] = []
108
+ const enabledCols = columns
109
+ .filter(c => enabledFields.has(c.index))
110
+ .sort((a, b) => a.index - b.index)
111
+
112
+ for (const row of csvData.rows) {
113
+ const sampleName = row[csvData.sampleColumn]
114
+
115
+ // Build group key from enabled CSV column values
116
+ // Use originalName for CSV row lookup (survives user renames), display name for group key
117
+ const keyParts = enabledCols.map(col => row[col.originalName ?? col.name])
118
+ const groupKey = keyParts.join(' / ')
119
+
120
+ const group = groupMap.get(groupKey)
121
+ if (group) {
122
+ group.push(sampleName)
123
+ } else {
124
+ groupMap.set(groupKey, [sampleName])
125
+ }
126
+
127
+ // Build metadata row with ALL columns - use display name as key, original for lookup
128
+ const fields: Record<string, string> = {}
129
+ for (const col of columns) {
130
+ fields[col.name] = row[col.originalName ?? col.name]
131
+ }
132
+ metadata.push({ sampleName, fields, group: groupKey })
133
+ }
134
+
135
+ // Convert to SampleGroup[]
136
+ const groups: SampleGroup[] = []
137
+ let colorIdx = 0
138
+ for (const [name, samples] of groupMap) {
139
+ groups.push({
140
+ name,
141
+ color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],
142
+ samples,
143
+ })
144
+ colorIdx++
145
+ }
146
+
147
+ return { groups, metadata, excludedSamples: [] }
148
+ }
@@ -6,7 +6,7 @@ import type {
6
6
  ControlComponentBindingsConfig,
7
7
  ControlComponentPropsMap,
8
8
  ControlComponentPropSource,
9
- } from './useControlSchema'
9
+ } from './controlSchemaTypes'
10
10
 
11
11
  /** Map control workspace values into component props for direct `v-bind` usage. */
12
12
  export function controlValuesToComponentProps<TValues extends Record<string, unknown>>(
@@ -27,7 +27,7 @@ import type {
27
27
  ControlFormSchema,
28
28
  ControlSchema,
29
29
  ControlSchemaOptions,
30
- } from './useControlSchema'
30
+ } from './controlSchemaTypes'
31
31
 
32
32
  /** Convert a compact control schema into a FormBuilder schema. */
33
33
  export function controlsToFormSchema(
@@ -0,0 +1,215 @@
1
+ import type {
2
+ ControlComponentBindingsConfig,
3
+ ControlComponentPropSource,
4
+ ControlComponentPropsByIdMap,
5
+ ControlComponentPropsMap,
6
+ ControlModelBinding,
7
+ ControlSchema,
8
+ DoseCalculatorControlPropsOptions,
9
+ DoseDesignControlModelOptions,
10
+ WellPlateControlPropsOptions,
11
+ WellPlateDoseControlPropsOptions,
12
+ } from './controlSchemaTypes'
13
+ import type { WellConcentration } from './useDoseCalculator'
14
+ import {
15
+ defineControlModel,
16
+ } from './controlSchemaModel'
17
+ import {
18
+ recordValue,
19
+ } from './controlSchemaUtils'
20
+
21
+ /** Return a default WellPlate prop mapping for generated control workspaces. */
22
+ export function defineWellPlateControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
23
+ options: WellPlateControlPropsOptions<TValues> = {},
24
+ ): ControlComponentPropsMap<TValues> {
25
+ const selectedWells = options.selectedWells ?? sourceKey<TValues>('selectedWells')
26
+ const onUpdateModelValue = options.onUpdateModelValue === false
27
+ ? undefined
28
+ : options.onUpdateModelValue ?? updateControlValueSource(selectedWells)
29
+
30
+ return compactComponentPropsMap<TValues>({
31
+ modelValue: selectedWells,
32
+ 'onUpdate:modelValue': onUpdateModelValue,
33
+ format: options.format ?? sourceKey<TValues>('plateFormat'),
34
+ wells: options.wells ?? sourceKey<TValues>('wells'),
35
+ disabled: options.disabled ?? sourceKey<TValues>('disabled'),
36
+ readonly: options.readonly ?? sourceKey<TValues>('readonly'),
37
+ showLegend: options.showLegend,
38
+ showSampleTypeIndicator: options.showSampleTypeIndicator,
39
+ })
40
+ }
41
+
42
+ /** Return a default DoseCalculator prop mapping for generated control workspaces. */
43
+ export function defineDoseCalculatorControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
44
+ options: DoseCalculatorControlPropsOptions<TValues> = {},
45
+ ): ControlComponentPropsMap<TValues> {
46
+ const targetWells = options.targetWells ?? sourceKey<TValues>('selectedWells')
47
+ const wells = options.wells ?? sourceKey<TValues>('wells')
48
+ const onApplyToWells = options.onApplyToWells === false
49
+ ? undefined
50
+ : options.onApplyToWells ?? defaultDoseApplyHandler(wells, targetWells)
51
+
52
+ return compactComponentPropsMap<TValues>({
53
+ mode: options.mode ?? sourceKey<TValues>('doseMode'),
54
+ targetWells,
55
+ disabled: options.disabled ?? sourceKey<TValues>('disabled'),
56
+ molecularWeight: options.molecularWeight,
57
+ onApplyToWells,
58
+ })
59
+ }
60
+
61
+ /** Return named WellPlate + DoseCalculator prop mappings for one dose-design control model. */
62
+ export function defineWellPlateDoseControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
63
+ options: WellPlateDoseControlPropsOptions<TValues> = {},
64
+ ): ControlComponentPropsByIdMap<TValues> {
65
+ return {
66
+ [options.plateId ?? 'plate']: defineWellPlateControlProps(options.plate),
67
+ [options.doseId ?? 'dose']: defineDoseCalculatorControlProps(options.dose),
68
+ }
69
+ }
70
+
71
+ /** Return named WellPlate + DoseCalculator component bindings for one dose-design control model. */
72
+ export function defineWellPlateDoseComponentBindings<TValues extends Record<string, unknown> = Record<string, unknown>>(
73
+ options: WellPlateDoseControlPropsOptions<TValues> = {},
74
+ ): ControlComponentBindingsConfig<TValues> {
75
+ return [
76
+ {
77
+ id: options.plateId ?? 'plate',
78
+ component: 'WellPlate',
79
+ props: defineWellPlateControlProps(options.plate),
80
+ },
81
+ {
82
+ id: options.doseId ?? 'dose',
83
+ component: 'DoseCalculator',
84
+ props: defineDoseCalculatorControlProps(options.dose),
85
+ },
86
+ ]
87
+ }
88
+
89
+ /** Return a complete ControlWorkspaceView model for WellPlate + DoseCalculator dose design. */
90
+ export function defineDoseDesignControlModel(
91
+ options: DoseDesignControlModelOptions = {},
92
+ ): ControlModelBinding {
93
+ const viewId = options.viewId ?? 'design'
94
+ const sectionId = options.sectionId ?? 'dose'
95
+ const doseControls: ControlSchema = {
96
+ selectedWells: {
97
+ type: 'tags',
98
+ label: 'Selected wells',
99
+ default: [...(options.selectedWells ?? ['A1', 'A2'])],
100
+ },
101
+ plateFormat: {
102
+ label: 'Plate format',
103
+ default: options.plateFormat ?? 96,
104
+ options: options.plateFormats ?? [96, 384],
105
+ },
106
+ doseMode: {
107
+ label: 'Dose mode',
108
+ default: options.doseMode ?? 'serial',
109
+ options: options.doseModes ?? ['serial', 'dilution', 'conversion'],
110
+ },
111
+ disabled: {
112
+ label: 'Disable tools',
113
+ default: options.disabled ?? false,
114
+ },
115
+ }
116
+
117
+ if (options.includeMolecularWeight) {
118
+ doseControls.molecularWeight = {
119
+ type: 'number',
120
+ label: 'Molecular weight',
121
+ default: options.molecularWeight ?? 300,
122
+ min: 0,
123
+ }
124
+ }
125
+
126
+ const componentProps: WellPlateDoseControlPropsOptions = {
127
+ ...options.componentProps,
128
+ dose: {
129
+ ...(options.componentProps?.dose ?? {}),
130
+ ...(options.includeMolecularWeight && options.componentProps?.dose?.molecularWeight === undefined
131
+ ? { molecularWeight: 'molecularWeight' }
132
+ : {}),
133
+ },
134
+ }
135
+
136
+ return defineControlModel({
137
+ componentBindings: defineWellPlateDoseComponentBindings(componentProps),
138
+ componentPropsById: defineWellPlateDoseControlProps(componentProps),
139
+ views: {
140
+ [viewId]: {
141
+ label: options.viewLabel ?? 'Design',
142
+ sections: {
143
+ [sectionId]: {
144
+ label: options.sectionLabel ?? 'Dose design',
145
+ description: options.sectionDescription ?? 'Well selection and dose calculator controls',
146
+ controls: doseControls,
147
+ },
148
+ },
149
+ },
150
+ },
151
+ })
152
+ }
153
+
154
+ function compactComponentPropsMap<TValues extends Record<string, unknown>>(
155
+ mapping: Record<string, ControlComponentPropSource<TValues> | undefined>,
156
+ ): ControlComponentPropsMap<TValues> {
157
+ return Object.fromEntries(
158
+ Object.entries(mapping).filter((entry): entry is [string, ControlComponentPropSource<TValues>] =>
159
+ entry[1] !== undefined
160
+ ),
161
+ )
162
+ }
163
+
164
+ function sourceKey<TValues extends Record<string, unknown>>(key: string): keyof TValues & string {
165
+ return key as keyof TValues & string
166
+ }
167
+
168
+ function updateControlValueSource<TValues extends Record<string, unknown>>(
169
+ source: ControlComponentPropSource<TValues>,
170
+ ): ((values: TValues) => (value: string[]) => void) | undefined {
171
+ if (typeof source !== 'string') return undefined
172
+ return values => (value: string[]) => {
173
+ const writableValues = values as Record<string, unknown>
174
+ writableValues[source] = value
175
+ }
176
+ }
177
+
178
+ function defaultDoseApplyHandler<TValues extends Record<string, unknown>>(
179
+ wells: ControlComponentPropSource<TValues>,
180
+ targetWells: ControlComponentPropSource<TValues>,
181
+ ): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {
182
+ if (wells === targetWells) return undefined
183
+ return updateWellsFromDoseResults(wells)
184
+ }
185
+
186
+ function updateWellsFromDoseResults<TValues extends Record<string, unknown>>(
187
+ source: ControlComponentPropSource<TValues>,
188
+ ): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {
189
+ if (typeof source !== 'string') return undefined
190
+ return values => (results: WellConcentration[]) => {
191
+ const writableValues = values as Record<string, unknown>
192
+ const currentWells = recordValue(writableValues[source])
193
+ const nextWells: Record<string, Record<string, unknown>> = {}
194
+ for (const [wellId, well] of Object.entries(currentWells)) {
195
+ nextWells[wellId] = recordValue(well)
196
+ }
197
+
198
+ for (const result of results) {
199
+ const existing = recordValue(nextWells[result.wellId])
200
+ const metadata = recordValue(existing.metadata)
201
+ nextWells[result.wellId] = {
202
+ ...existing,
203
+ state: 'filled',
204
+ value: result.concentration.value,
205
+ metadata: {
206
+ ...metadata,
207
+ concentration: result.concentration,
208
+ ...(result.volume === undefined ? {} : { volume: result.volume }),
209
+ },
210
+ }
211
+ }
212
+
213
+ writableValues[source] = nextWells
214
+ }
215
+ }
@@ -13,7 +13,7 @@ import {
13
13
  } from './controlSchemaUtils'
14
14
  import type {
15
15
  ControlDefinition,
16
- } from './useControlSchema'
16
+ } from './controlSchemaTypes'
17
17
 
18
18
  export function controlToFormField(control: NormalizedControl): FormFieldSchema {
19
19
  const { name, definition, type } = control
@@ -12,7 +12,7 @@ import type {
12
12
  ControlSchemaOptions,
13
13
  ControlSectionConfig,
14
14
  ControlSidebarConfig,
15
- } from './useControlSchema'
15
+ } from './controlSchemaTypes'
16
16
 
17
17
  export function sectionConfig(
18
18
  sectionId: string,
@@ -0,0 +1,163 @@
1
+ import type {
2
+ ControlModel,
3
+ ControlModelBinding,
4
+ ControlModelSectionConfig,
5
+ ControlSchema,
6
+ ControlSectionConfig,
7
+ ControlSidebarConfig,
8
+ ControlViewConfig,
9
+ ControlWorkspaceOptions,
10
+ } from './controlSchemaTypes'
11
+ import {
12
+ normalizeControlDefinition,
13
+ } from './controlSchemaNormalize'
14
+ import {
15
+ omitUndefined,
16
+ } from './controlSchemaUtils'
17
+
18
+ export function isControlModelBinding<TBinding extends ControlModelBinding = ControlModelBinding>(
19
+ model: unknown,
20
+ ): model is TBinding {
21
+ return (
22
+ typeof model === 'object'
23
+ && model !== null
24
+ && 'controls' in model
25
+ && 'controlOptions' in model
26
+ )
27
+ }
28
+
29
+ export function resolveControlModel(
30
+ model: ControlModel | ControlModelBinding | undefined,
31
+ ): ControlModelBinding | undefined {
32
+ if (model === undefined) return undefined
33
+ return isControlModelBinding(model) ? model : defineControlModel(model)
34
+ }
35
+
36
+ /** Create a complete workspace component binding from a simple controls data model for ControlWorkspaceView, generated forms, and sidebars. */
37
+ export function defineControlModel(model: ControlModel): ControlModelBinding {
38
+ const {
39
+ controls: rootControls,
40
+ sections: rootSections,
41
+ views: modelViews,
42
+ components,
43
+ componentBindings,
44
+ componentProps,
45
+ componentPropsById,
46
+ ...baseOptions
47
+ } = model
48
+ const resolvedComponentBindings = componentBindings ?? components
49
+ const controls: ControlSchema = {}
50
+ const views: Record<string, ControlViewConfig> = {}
51
+ const sections: Record<string, ControlSectionConfig> = {}
52
+
53
+ const defaultViewId = model.view ?? 'default'
54
+ const defaultSectionId = model.section ?? 'controls'
55
+
56
+ if (rootControls) {
57
+ registerSectionOptions(sections, defaultSectionId, {
58
+ id: defaultSectionId,
59
+ label: model.sectionLabel,
60
+ title: model.sectionLabel,
61
+ columns: model.columns,
62
+ })
63
+ appendModelControls(controls, rootControls, defaultViewId, defaultSectionId)
64
+ }
65
+
66
+ for (const [sectionId, section] of Object.entries(rootSections ?? {})) {
67
+ registerSectionOptions(sections, sectionId, controlModelSectionOptions(section))
68
+ appendModelControls(controls, section.controls, defaultViewId, sectionId, section.sidebar)
69
+ }
70
+
71
+ for (const [viewId, view] of Object.entries(modelViews ?? {})) {
72
+ const {
73
+ controls: viewControls,
74
+ sections: viewSections,
75
+ section,
76
+ sectionLabel,
77
+ sectionDescription,
78
+ ...viewConfig
79
+ } = view
80
+
81
+ views[viewId] = omitUndefined(viewConfig)
82
+
83
+ if (viewControls) {
84
+ const sectionId = section ?? `${viewId}-controls`
85
+ const label = sectionLabel ?? view.label
86
+ registerSectionOptions(sections, sectionId, {
87
+ id: sectionId,
88
+ label,
89
+ title: label,
90
+ description: sectionDescription,
91
+ columns: model.columns,
92
+ })
93
+ appendModelControls(controls, viewControls, viewId, sectionId)
94
+ }
95
+
96
+ for (const [sectionKey, sectionConfig] of Object.entries(viewSections ?? {})) {
97
+ const sectionId = sectionConfig.id ?? `${viewId}-${sectionKey}`
98
+ registerSectionOptions(sections, sectionId, controlModelSectionOptions(sectionConfig))
99
+ appendModelControls(controls, sectionConfig.controls, viewId, sectionId, sectionConfig.sidebar)
100
+ }
101
+ }
102
+
103
+ const controlOptions: ControlWorkspaceOptions = {
104
+ ...baseOptions,
105
+ }
106
+
107
+ if (Object.keys(views).length > 0) {
108
+ controlOptions.views = views
109
+ }
110
+
111
+ if (Object.keys(sections).length > 0) {
112
+ controlOptions.sections = sections
113
+ }
114
+
115
+ return {
116
+ controls,
117
+ controlOptions,
118
+ ...(resolvedComponentBindings === undefined ? {} : { componentBindings: resolvedComponentBindings }),
119
+ ...(componentProps === undefined ? {} : { componentProps }),
120
+ ...(componentPropsById === undefined ? {} : { componentPropsById }),
121
+ }
122
+ }
123
+
124
+ function appendModelControls(
125
+ target: ControlSchema,
126
+ source: ControlSchema,
127
+ viewId: string,
128
+ sectionId: string,
129
+ sidebar?: boolean | ControlSidebarConfig,
130
+ ): void {
131
+ for (const [name, input] of Object.entries(source)) {
132
+ if (Object.prototype.hasOwnProperty.call(target, name)) {
133
+ throw new Error(
134
+ `Duplicate control "${name}" in defineControlModel(). Control names must be unique across views and sections.`,
135
+ )
136
+ }
137
+
138
+ const definition = normalizeControlDefinition(input)
139
+ target[name] = omitUndefined({
140
+ ...definition,
141
+ view: definition.view ?? viewId,
142
+ section: definition.section ?? sectionId,
143
+ sidebar: definition.sidebar ?? sidebar,
144
+ })
145
+ }
146
+ }
147
+
148
+ function controlModelSectionOptions(section: ControlModelSectionConfig): ControlSectionConfig {
149
+ const { controls: _controls, sidebar: _sidebar, ...options } = section
150
+ return omitUndefined(options)
151
+ }
152
+
153
+ function registerSectionOptions(
154
+ target: Record<string, ControlSectionConfig>,
155
+ sectionId: string,
156
+ options: ControlSectionConfig,
157
+ ): void {
158
+ target[sectionId] = omitUndefined({
159
+ ...(target[sectionId] ?? {}),
160
+ ...options,
161
+ id: sectionId,
162
+ })
163
+ }
@@ -17,7 +17,7 @@ import type {
17
17
  ControlOptionValue,
18
18
  ControlSchema,
19
19
  ControlSchemaOptions,
20
- } from './useControlSchema'
20
+ } from './controlSchemaTypes'
21
21
 
22
22
  export interface NormalizedControl {
23
23
  name: string