@morscherlab/mint-sdk 1.0.0-rc.2 → 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 (443) 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/AppTopBar.navigation.d.ts +11 -0
  41. package/dist/components/BaseButton.vue.d.ts +1 -1
  42. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  43. package/dist/components/BaseInput.vue.d.ts +2 -2
  44. package/dist/components/BasePill.vue.d.ts +1 -1
  45. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  46. package/dist/components/BaseSelect.vue.d.ts +1 -1
  47. package/dist/components/BaseSlider.vue.d.ts +2 -2
  48. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  49. package/dist/components/BaseToggle.vue.d.ts +1 -1
  50. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  51. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  52. package/dist/components/ColorSlider.vue.d.ts +2 -2
  53. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  54. package/dist/components/DatePicker.vue.d.ts +1 -1
  55. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  56. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  57. package/dist/components/DropdownButton.vue.d.ts +1 -1
  58. package/dist/components/FileUploader.vue.d.ts +2 -2
  59. package/dist/components/FormulaInput.vue.d.ts +2 -2
  60. package/dist/components/IconButton.vue.d.ts +1 -1
  61. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  62. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  63. package/dist/components/MultiSelect.vue.d.ts +1 -1
  64. package/dist/components/NumberInput.vue.d.ts +1 -1
  65. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  66. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  67. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  68. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  69. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  70. package/dist/components/PluginWorkspaceView.vue.d.ts +46 -195
  71. package/dist/components/ProgressBar.vue.d.ts +1 -1
  72. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  73. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  74. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  75. package/dist/components/ReagentList.presentation.d.ts +16 -0
  76. package/dist/components/ResourceCard.vue.d.ts +1 -1
  77. package/dist/components/SampleSelector.colors.d.ts +13 -0
  78. package/dist/components/SampleSelector.drag.d.ts +24 -0
  79. package/dist/components/SampleSelector.groups.d.ts +15 -0
  80. package/dist/components/SampleSelector.selection.d.ts +26 -0
  81. package/dist/components/SampleSelector.vue.d.ts +4 -1
  82. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  83. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  84. package/dist/components/SequenceInput.vue.d.ts +2 -2
  85. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  86. package/dist/components/SettingsModal.schema.d.ts +9 -0
  87. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  88. package/dist/components/TagsInput.vue.d.ts +2 -2
  89. package/dist/components/TimePicker.vue.d.ts +2 -2
  90. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  91. package/dist/components/UnitInput.vue.d.ts +2 -2
  92. package/dist/components/WellPlate.colors.d.ts +9 -0
  93. package/dist/components/WellPlate.conditions.d.ts +26 -0
  94. package/dist/components/WellPlate.geometry.d.ts +23 -0
  95. package/dist/components/WellPlate.interaction.d.ts +71 -0
  96. package/dist/components/WellPlate.legend.d.ts +2 -0
  97. package/dist/components/WellPlate.rendering.d.ts +24 -0
  98. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  99. package/dist/components/WellPlate.vue.d.ts +1 -1
  100. package/dist/components/index.js +2 -2
  101. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  102. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  103. package/dist/{components-BhK-dW99.js → components-DtHA2bgp.js} +3754 -2991
  104. package/dist/components-DtHA2bgp.js.map +1 -0
  105. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  106. package/dist/composables/autoGroup/classify.d.ts +28 -0
  107. package/dist/composables/autoGroup/colors.d.ts +2 -0
  108. package/dist/composables/autoGroup/columns.d.ts +10 -0
  109. package/dist/composables/autoGroup/compose.d.ts +8 -0
  110. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  111. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  112. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  113. package/dist/composables/autoGroup/index.d.ts +16 -0
  114. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  115. package/dist/composables/autoGroup/template.d.ts +15 -0
  116. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  117. package/dist/composables/autoGroupConstants.d.ts +1 -0
  118. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  119. package/dist/composables/controlComponentBindings.d.ts +7 -0
  120. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  121. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  122. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  123. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  124. package/dist/composables/controlSchemaModel.d.ts +5 -0
  125. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  126. package/dist/composables/controlSchemaTypes.d.ts +305 -0
  127. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  128. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  129. package/dist/composables/formBuilderSchema.d.ts +18 -0
  130. package/dist/composables/index.js +3 -3
  131. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  132. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  133. package/dist/composables/useAutoGroup.d.ts +61 -74
  134. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  135. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  136. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  137. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  138. package/dist/composables/useControlSchema.d.ts +8 -346
  139. package/dist/composables/useControlWorkspace.d.ts +5 -0
  140. package/dist/composables/useForm.d.ts +2 -33
  141. package/dist/composables/useFormBuilder.d.ts +2 -9
  142. package/dist/composables/useFormValidation.d.ts +34 -0
  143. package/dist/composables/usePluginClient.d.ts +1 -4
  144. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  145. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  146. package/dist/{composables-Bg7CFuNz.js → composables-Dlg8jenH.js} +33 -31
  147. package/dist/composables-Dlg8jenH.js.map +1 -0
  148. package/dist/index.js +4 -4
  149. package/dist/install.js +2 -2
  150. package/dist/styles.css +547 -516
  151. package/dist/templates/adapters.d.ts +14 -47
  152. package/dist/templates/assayLookups.d.ts +3 -0
  153. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  154. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  155. package/dist/templates/assayNormalizers.d.ts +4 -0
  156. package/dist/templates/builderDefaults.d.ts +1 -0
  157. package/dist/templates/builderIdUtils.d.ts +4 -0
  158. package/dist/templates/builderPresetControls.d.ts +10 -0
  159. package/dist/templates/builderReadUtils.d.ts +8 -0
  160. package/dist/templates/builders.d.ts +26 -67
  161. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  162. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  163. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  164. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  165. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  166. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  167. package/dist/templates/componentGenericProps.d.ts +8 -0
  168. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  169. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  170. package/dist/templates/componentPropsFactory.d.ts +3 -0
  171. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  172. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  173. package/dist/templates/componentTemplateProps.d.ts +3 -0
  174. package/dist/templates/controlSchemaClone.d.ts +4 -0
  175. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  176. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  177. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  178. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  179. package/dist/templates/controlSchemas.d.ts +4 -4
  180. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  181. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  182. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  183. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  184. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  185. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  186. package/dist/templates/flowNormalizers.d.ts +8 -0
  187. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  188. package/dist/templates/index.js +1 -1
  189. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  190. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  191. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  192. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  193. package/dist/templates/plateGeometry.d.ts +4 -0
  194. package/dist/templates/plateMapAdapters.d.ts +3 -0
  195. package/dist/templates/plateMapBuilder.d.ts +2 -0
  196. package/dist/templates/presetControlSchemas.d.ts +534 -0
  197. package/dist/templates/protocolAdapters.d.ts +5 -0
  198. package/dist/templates/protocolNormalizers.d.ts +6 -0
  199. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  200. package/dist/templates/qpcrAdapters.d.ts +5 -0
  201. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  202. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  203. package/dist/templates/reagentAdapters.d.ts +5 -0
  204. package/dist/templates/reagentListBuilder.d.ts +2 -0
  205. package/dist/templates/runNormalizers.d.ts +10 -0
  206. package/dist/templates/sampleNormalizers.d.ts +4 -0
  207. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  208. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  209. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  210. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  211. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  212. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  213. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  214. package/dist/templates/templateControlSchemas.d.ts +400 -0
  215. package/dist/templates/templateCreateOptions.d.ts +165 -0
  216. package/dist/templates/templateEnvelopes.d.ts +9 -0
  217. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  218. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  219. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  220. package/dist/templates/templateValidators.d.ts +13 -0
  221. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  222. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  223. package/dist/templates/types.d.ts +5 -250
  224. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  225. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  226. package/dist/{templates-BorLR_7p.js → templates-DtdUvJ4c.js} +3565 -3411
  227. package/dist/templates-DtdUvJ4c.js.map +1 -0
  228. package/dist/types/auto-group.d.ts +79 -9
  229. package/dist/types/componentLabTypes.d.ts +161 -0
  230. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  231. package/dist/types/components.d.ts +2 -311
  232. package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-Bm5vyH4_.js} +1220 -454
  233. package/dist/useProtocolTemplates-Bm5vyH4_.js.map +1 -0
  234. package/package.json +1 -1
  235. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  236. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  237. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  238. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  239. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  240. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +41 -0
  241. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  242. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  243. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  244. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  245. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  246. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  247. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  248. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  249. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  250. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  251. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  252. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  253. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  254. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  255. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  256. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  257. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  258. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  259. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  260. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  261. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  262. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  263. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  264. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  265. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  266. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  267. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  268. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  269. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  270. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  271. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  272. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  273. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  274. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  275. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  276. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  277. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  278. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  279. package/src/components/AppSidebar.vue +2 -6
  280. package/src/components/AppTopBar.navigation.ts +62 -0
  281. package/src/components/AppTopBar.vue +17 -44
  282. package/src/components/AutoGroupModal.story.vue +50 -0
  283. package/src/components/AutoGroupModal.vue +441 -158
  284. package/src/components/ControlWorkspaceView.vue +2 -6
  285. package/src/components/DoseCalculator.vue +13 -73
  286. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  287. package/src/components/ExperimentTimeline.vue +6 -31
  288. package/src/components/FormBuilder.vue +2 -7
  289. package/src/components/PlateMapEditor.vue +32 -106
  290. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  291. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  292. package/src/components/PluginWorkspaceView.props.ts +174 -0
  293. package/src/components/PluginWorkspaceView.shell.ts +66 -0
  294. package/src/components/PluginWorkspaceView.vue +85 -404
  295. package/src/components/ProtocolStep.presentation.ts +31 -0
  296. package/src/components/ProtocolStepEditor.state.ts +104 -0
  297. package/src/components/ProtocolStepEditor.vue +48 -179
  298. package/src/components/ProtocolStepParameterField.vue +134 -0
  299. package/src/components/ReagentList.presentation.ts +105 -0
  300. package/src/components/ReagentList.vue +16 -79
  301. package/src/components/SampleSelector.colors.ts +43 -0
  302. package/src/components/SampleSelector.drag.ts +164 -0
  303. package/src/components/SampleSelector.groups.ts +109 -0
  304. package/src/components/SampleSelector.selection.ts +103 -0
  305. package/src/components/SampleSelector.vue +82 -349
  306. package/src/components/SampleSelectorSampleRow.vue +64 -0
  307. package/src/components/ScheduleCalendar.vue +44 -199
  308. package/src/components/SettingsModal.schema.ts +71 -0
  309. package/src/components/SettingsModal.vue +16 -46
  310. package/src/components/WellPlate.colors.ts +56 -0
  311. package/src/components/WellPlate.conditions.ts +100 -0
  312. package/src/components/WellPlate.geometry.ts +91 -0
  313. package/src/components/WellPlate.interaction.ts +272 -0
  314. package/src/components/WellPlate.legend.ts +8 -0
  315. package/src/components/WellPlate.rendering.ts +105 -0
  316. package/src/components/WellPlate.sampleDrop.ts +73 -0
  317. package/src/components/WellPlate.vue +102 -550
  318. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  319. package/src/composables/autoGroup/classKey.ts +5 -0
  320. package/src/composables/autoGroup/classify.ts +205 -0
  321. package/src/composables/autoGroup/colors.ts +6 -0
  322. package/src/composables/autoGroup/columns.ts +226 -0
  323. package/src/composables/autoGroup/compose.ts +156 -0
  324. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  325. package/src/composables/autoGroup/csv-shim.ts +44 -0
  326. package/src/composables/autoGroup/fingerprint.ts +49 -0
  327. package/src/composables/autoGroup/index.ts +20 -0
  328. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  329. package/src/composables/autoGroup/template.ts +126 -0
  330. package/src/composables/autoGroup/tokenize.ts +41 -0
  331. package/src/composables/autoGroup/vocab.json +67 -0
  332. package/src/composables/autoGroupConstants.ts +4 -0
  333. package/src/composables/autoGroupGrouping.ts +148 -0
  334. package/src/composables/controlComponentBindings.ts +80 -0
  335. package/src/composables/controlSchemaAdapters.ts +196 -0
  336. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  337. package/src/composables/controlSchemaFormFields.ts +61 -0
  338. package/src/composables/controlSchemaLayout.ts +59 -0
  339. package/src/composables/controlSchemaModel.ts +163 -0
  340. package/src/composables/controlSchemaNormalize.ts +101 -0
  341. package/src/composables/controlSchemaTypes.ts +364 -0
  342. package/src/composables/controlSchemaUtils.ts +36 -0
  343. package/src/composables/controlWorkspaceOptions.ts +21 -0
  344. package/src/composables/formBuilderSchema.ts +153 -0
  345. package/src/composables/pluginEndpointBuilder.ts +203 -0
  346. package/src/composables/protocolTemplateCatalog.ts +325 -0
  347. package/src/composables/useAutoGroup.ts +395 -549
  348. package/src/composables/useAutoGroupInputSources.ts +147 -0
  349. package/src/composables/useBioTemplateControls.ts +1 -1
  350. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  351. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  352. package/src/composables/useControlSchema.ts +64 -1312
  353. package/src/composables/useControlWorkspace.ts +201 -0
  354. package/src/composables/useForm.ts +5 -187
  355. package/src/composables/useFormBuilder.ts +11 -153
  356. package/src/composables/useFormValidation.ts +154 -0
  357. package/src/composables/usePluginClient.ts +10 -193
  358. package/src/composables/useProtocolTemplates.ts +10 -328
  359. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  360. package/src/styles/components/auto-group-modal.css +248 -310
  361. package/src/templates/adapters.ts +89 -930
  362. package/src/templates/assayLookups.ts +33 -0
  363. package/src/templates/assayMatrixAdapters.ts +78 -0
  364. package/src/templates/assayMatrixBuilder.ts +59 -0
  365. package/src/templates/assayNormalizers.ts +34 -0
  366. package/src/templates/builderDefaults.ts +11 -0
  367. package/src/templates/builderIdUtils.ts +20 -0
  368. package/src/templates/builderPresetControls.ts +165 -0
  369. package/src/templates/builderReadUtils.ts +57 -0
  370. package/src/templates/builders.ts +122 -2350
  371. package/src/templates/calibrationCurveAdapters.ts +59 -0
  372. package/src/templates/calibrationCurveBuilder.ts +99 -0
  373. package/src/templates/calibrationNormalizers.ts +60 -0
  374. package/src/templates/componentBindingCatalog.ts +90 -0
  375. package/src/templates/componentBindingHelpers.ts +93 -0
  376. package/src/templates/componentBindings.ts +12 -461
  377. package/src/templates/componentDoseResponseProps.ts +42 -0
  378. package/src/templates/componentGenericProps.ts +77 -0
  379. package/src/templates/componentPlateHelpers.ts +29 -0
  380. package/src/templates/componentPlateMapProps.ts +32 -0
  381. package/src/templates/componentPropsFactory.ts +21 -0
  382. package/src/templates/componentQpcrPlateProps.ts +28 -0
  383. package/src/templates/componentTargetResolvers.ts +69 -0
  384. package/src/templates/componentTemplateProps.ts +78 -0
  385. package/src/templates/controlSchemaClone.ts +32 -0
  386. package/src/templates/controlSchemaConstants.ts +11 -0
  387. package/src/templates/controlSchemaMerge.ts +40 -0
  388. package/src/templates/controlSchemaTargets.ts +87 -0
  389. package/src/templates/controlSchemaTypes.ts +20 -0
  390. package/src/templates/controlSchemas.ts +22 -704
  391. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  392. package/src/templates/doseResponseAdapters.ts +45 -0
  393. package/src/templates/doseResponseBuilder.ts +44 -0
  394. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  395. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  396. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  397. package/src/templates/flowNormalizers.ts +58 -0
  398. package/src/templates/flowPanelAdapters.ts +58 -0
  399. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  400. package/src/templates/instrumentRunAdapters.ts +163 -0
  401. package/src/templates/instrumentRunBuilder.ts +97 -0
  402. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  403. package/src/templates/plateGeometry.ts +62 -0
  404. package/src/templates/plateMapAdapters.ts +36 -0
  405. package/src/templates/plateMapBuilder.ts +43 -0
  406. package/src/templates/presetControlSchemas.ts +258 -0
  407. package/src/templates/protocolAdapters.ts +69 -0
  408. package/src/templates/protocolNormalizers.ts +37 -0
  409. package/src/templates/protocolStepsBuilder.ts +36 -0
  410. package/src/templates/qpcrAdapters.ts +104 -0
  411. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  412. package/src/templates/qpcrPlateBuilder.ts +96 -0
  413. package/src/templates/reagentAdapters.ts +77 -0
  414. package/src/templates/reagentListBuilder.ts +30 -0
  415. package/src/templates/runNormalizers.ts +63 -0
  416. package/src/templates/sampleNormalizers.ts +58 -0
  417. package/src/templates/samplePrepAdapters.ts +63 -0
  418. package/src/templates/samplePrepBuilder.ts +51 -0
  419. package/src/templates/sampleSheetAdapters.ts +75 -0
  420. package/src/templates/sampleSheetBuilder.ts +23 -0
  421. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  422. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  423. package/src/templates/templateAdapterTypes.ts +58 -0
  424. package/src/templates/templateControlSchemas.ts +320 -0
  425. package/src/templates/templateCreateOptions.ts +208 -0
  426. package/src/templates/templateEnvelopes.ts +137 -0
  427. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  428. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  429. package/src/templates/templateQpcrTypes.ts +48 -0
  430. package/src/templates/templateValidators.ts +414 -0
  431. package/src/templates/timeCourseAdapters.ts +73 -0
  432. package/src/templates/timeCourseBuilder.ts +64 -0
  433. package/src/templates/types.ts +79 -275
  434. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  435. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  436. package/src/types/auto-group.ts +107 -9
  437. package/src/types/componentLabTypes.ts +235 -0
  438. package/src/types/componentWorkflowTypes.ts +190 -0
  439. package/src/types/components.ts +74 -424
  440. package/dist/components-BhK-dW99.js.map +0 -1
  441. package/dist/composables-Bg7CFuNz.js.map +0 -1
  442. package/dist/templates-BorLR_7p.js.map +0 -1
  443. package/dist/useProtocolTemplates-n6AJqSqv.js.map +0 -1
@@ -1,14 +1,25 @@
1
1
  <script setup lang="ts">
2
2
  /** Form for creating or editing a single protocol step (incubation, wash, addition, centrifuge, etc.) with template picker, typed parameters, and duration. */
3
3
  import { ref, computed, watch, onMounted } from 'vue'
4
- import type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'
4
+ import type { ProtocolStep } from '../types'
5
5
  import { useDropdownState } from '../composables/useDropdownState'
6
6
  import {
7
7
  useProtocolTemplates,
8
8
  type StepTemplate,
9
9
  } from '../composables/useProtocolTemplates'
10
- import ConcentrationInput from './ConcentrationInput.vue'
11
- import type { ConcentrationValue } from '../composables/useConcentrationUnits'
10
+ import {
11
+ PROTOCOL_STEP_TYPE_ICONS as stepTypeIcons,
12
+ formatProtocolDuration as formatDuration,
13
+ } from './ProtocolStep.presentation'
14
+ import ProtocolStepParameterField from './ProtocolStepParameterField.vue'
15
+ import {
16
+ buildCustomProtocolTemplate,
17
+ buildProtocolPreviewParams,
18
+ buildProtocolStepEditorState,
19
+ buildProtocolStepPreview,
20
+ buildProtocolTemplateDefaults,
21
+ type ProtocolStepEditorFields,
22
+ } from './ProtocolStepEditor.state'
12
23
 
13
24
  interface Props {
14
25
  modelValue?: ProtocolStep
@@ -69,51 +80,41 @@ const selectedTemplate = computed(() => {
69
80
  return availableTemplates.value.find((t) => t.id === selectedTemplateId.value) || null
70
81
  })
71
82
 
72
- // Step type icons (same as ExperimentTimeline)
73
- const stepTypeIcons: Record<ProtocolStepType, string> = {
74
- incubation: 'M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z',
75
- wash: 'M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z',
76
- addition: 'M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z',
77
- measurement: 'M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z',
78
- transfer: 'M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4',
79
- centrifuge: 'M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15',
80
- mix: 'M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z',
81
- custom: 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z',
82
- }
83
-
84
83
  // Preview computed
85
84
  const previewStep = computed<ProtocolStep | null>(() => {
86
85
  if (!selectedTemplate.value) return null
87
- return {
88
- id: props.modelValue?.id || 'preview',
89
- type: selectedTemplate.value.type,
90
- name: stepName.value || selectedTemplate.value.name,
91
- description: stepDescription.value,
92
- duration: stepDuration.value ?? selectedTemplate.value.defaultDuration,
93
- status: (props.modelValue?.status || 'pending') as ProtocolStepStatus,
94
- parameters: { ...parameters.value },
95
- order: props.modelValue?.order || 0,
96
- }
86
+ return buildProtocolStepPreview(selectedTemplate.value, editorFields(), props.modelValue)
97
87
  })
98
88
 
99
89
  const previewParams = computed(() => {
100
90
  if (!selectedTemplate.value || !previewStep.value) return ''
101
- return selectedTemplate.value.parameters
102
- .filter((p) => parameters.value[p.key] !== undefined && parameters.value[p.key] !== '')
103
- .map((p) => formatParameterValue(parameters.value[p.key], p))
104
- .join(', ')
91
+ return buildProtocolPreviewParams(
92
+ selectedTemplate.value,
93
+ parameters.value,
94
+ formatParameterValue
95
+ )
105
96
  })
106
97
 
107
- // Initialize from modelValue
108
- function initFromStep(step: ProtocolStep) {
109
- const template = getTemplateByType(step.type)
110
- if (template) {
111
- selectedTemplateId.value = template.id
98
+ function editorFields(): ProtocolStepEditorFields {
99
+ return {
100
+ name: stepName.value,
101
+ description: stepDescription.value,
102
+ duration: stepDuration.value,
103
+ parameters: parameters.value,
112
104
  }
113
- stepName.value = step.name
114
- stepDescription.value = step.description || ''
115
- stepDuration.value = step.duration
116
- parameters.value = { ...(step.parameters || {}) }
105
+ }
106
+
107
+ function applyEditorFields(fields: ProtocolStepEditorFields) {
108
+ stepName.value = fields.name
109
+ stepDescription.value = fields.description
110
+ stepDuration.value = fields.duration
111
+ parameters.value = { ...fields.parameters }
112
+ }
113
+
114
+ function initFromStep(step: ProtocolStep) {
115
+ const state = buildProtocolStepEditorState(step, getTemplateByType)
116
+ selectedTemplateId.value = state.selectedTemplateId
117
+ applyEditorFields(state.fields)
117
118
  }
118
119
 
119
120
  // Handle template selection
@@ -123,16 +124,7 @@ function selectTemplate(template: StepTemplate) {
123
124
 
124
125
  // Reset to template defaults if creating new
125
126
  if (props.mode === 'create') {
126
- stepName.value = template.name
127
- stepDescription.value = template.description || ''
128
- stepDuration.value = template.defaultDuration
129
-
130
- parameters.value = {}
131
- for (const param of template.parameters) {
132
- if (param.default !== undefined) {
133
- parameters.value[param.key] = param.default
134
- }
135
- }
127
+ applyEditorFields(buildProtocolTemplateDefaults(template))
136
128
  }
137
129
  }
138
130
 
@@ -145,14 +137,6 @@ function handleParamChange(key: string, value: unknown) {
145
137
  }
146
138
  }
147
139
 
148
- // Handle concentration change
149
- function handleConcentrationChange(key: string, value: ConcentrationValue | undefined) {
150
- parameters.value[key] = value
151
- if (validationErrors.value[key]) {
152
- delete validationErrors.value[key]
153
- }
154
- }
155
-
156
140
  // Validate and save
157
141
  function handleSave() {
158
142
  if (!selectedTemplate.value || !previewStep.value) return
@@ -169,21 +153,7 @@ function handleSave() {
169
153
  // Save as template
170
154
  function handleSaveTemplate() {
171
155
  if (!selectedTemplate.value) return
172
-
173
- const newTemplate: StepTemplate = {
174
- id: `custom-${Date.now()}`,
175
- type: selectedTemplate.value.type,
176
- name: stepName.value || selectedTemplate.value.name,
177
- description: stepDescription.value,
178
- defaultDuration: stepDuration.value,
179
- parameters: selectedTemplate.value.parameters.map((p) => ({
180
- ...p,
181
- default: parameters.value[p.key],
182
- })),
183
- isBuiltIn: false,
184
- }
185
-
186
- emit('save-template', newTemplate)
156
+ emit('save-template', buildCustomProtocolTemplate(selectedTemplate.value, editorFields()))
187
157
  }
188
158
 
189
159
  // Handle cancel
@@ -191,15 +161,6 @@ function handleCancel() {
191
161
  emit('cancel')
192
162
  }
193
163
 
194
- // Format duration
195
- function formatDuration(minutes: number | undefined): string {
196
- if (minutes === undefined) return ''
197
- if (minutes < 60) return `${minutes}m`
198
- const hours = Math.floor(minutes / 60)
199
- const mins = minutes % 60
200
- return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`
201
- }
202
-
203
164
  onMounted(() => {
204
165
  if (props.modelValue) {
205
166
  initFromStep(props.modelValue)
@@ -335,106 +296,14 @@ watch(
335
296
 
336
297
  <!-- Dynamic parameters -->
337
298
  <template v-if="selectedTemplate">
338
- <div
339
- v-for="(param, index) in selectedTemplate.parameters"
299
+ <ProtocolStepParameterField
300
+ v-for="param in selectedTemplate.parameters"
340
301
  :key="param.key"
341
- :class="[
342
- 'mint-protocol-editor__field',
343
- index % 2 === 0 && selectedTemplate.parameters[index + 1]
344
- ? ''
345
- : '',
346
- ]"
347
- >
348
- <label
349
- :class="[
350
- 'mint-protocol-editor__field-label',
351
- param.required ? 'mint-protocol-editor__field-label--required' : '',
352
- ]"
353
- >
354
- {{ param.label }}
355
- </label>
356
-
357
- <!-- Number input with unit -->
358
- <div
359
- v-if="param.type === 'number' || param.type === 'temperature' || param.type === 'duration'"
360
- class="mint-protocol-editor__input-unit"
361
- >
362
- <input
363
- type="number"
364
- :value="parameters[param.key]"
365
- :min="param.min"
366
- :max="param.max"
367
- :placeholder="param.placeholder || `Enter ${param.label.toLowerCase()}`"
368
- :class="[
369
- 'mint-protocol-editor__input',
370
- validationErrors[param.key] ? 'mint-protocol-editor__input--error' : '',
371
- ]"
372
- @input="handleParamChange(param.key, ($event.target as HTMLInputElement).valueAsNumber)"
373
- />
374
- <span v-if="param.unit" class="mint-protocol-editor__unit-suffix">
375
- {{ param.unit }}
376
- </span>
377
- </div>
378
-
379
- <!-- Text input -->
380
- <input
381
- v-else-if="param.type === 'text'"
382
- type="text"
383
- :value="parameters[param.key]"
384
- :placeholder="param.placeholder || `Enter ${param.label.toLowerCase()}`"
385
- :class="[
386
- 'mint-protocol-editor__input',
387
- validationErrors[param.key] ? 'mint-protocol-editor__input--error' : '',
388
- ]"
389
- @input="handleParamChange(param.key, ($event.target as HTMLInputElement).value)"
390
- />
391
-
392
- <!-- Select -->
393
- <select
394
- v-else-if="param.type === 'select'"
395
- :value="parameters[param.key]"
396
- :class="[
397
- 'mint-protocol-editor__select',
398
- validationErrors[param.key] ? 'mint-protocol-editor__input--error' : '',
399
- ]"
400
- @change="handleParamChange(param.key, ($event.target as HTMLSelectElement).value)"
401
- >
402
- <option value="" disabled>Select {{ param.label.toLowerCase() }}</option>
403
- <option
404
- v-for="option in param.options"
405
- :key="option.value"
406
- :value="option.value"
407
- >
408
- {{ option.label }}
409
- </option>
410
- </select>
411
-
412
- <!-- Concentration input -->
413
- <ConcentrationInput
414
- v-else-if="param.type === 'concentration'"
415
- :model-value="parameters[param.key] as ConcentrationValue | undefined"
416
- :error="!!validationErrors[param.key]"
417
- size="md"
418
- @update:model-value="handleConcentrationChange(param.key, $event)"
419
- />
420
-
421
- <!-- Reagent input (text for now) -->
422
- <input
423
- v-else-if="param.type === 'reagent'"
424
- type="text"
425
- :value="parameters[param.key]"
426
- :placeholder="param.placeholder || 'Enter reagent name'"
427
- :class="[
428
- 'mint-protocol-editor__input',
429
- validationErrors[param.key] ? 'mint-protocol-editor__input--error' : '',
430
- ]"
431
- @input="handleParamChange(param.key, ($event.target as HTMLInputElement).value)"
432
- />
433
-
434
- <span v-if="validationErrors[param.key]" class="mint-protocol-editor__field-error">
435
- {{ validationErrors[param.key] }}
436
- </span>
437
- </div>
302
+ :parameter="param"
303
+ :model-value="parameters[param.key]"
304
+ :error="validationErrors[param.key]"
305
+ @update:model-value="handleParamChange(param.key, $event)"
306
+ />
438
307
  </template>
439
308
 
440
309
  <!-- Description -->
@@ -0,0 +1,134 @@
1
+ <script setup lang="ts">
2
+ /** Renders one typed parameter control for ProtocolStepEditor. */
3
+ import { computed } from 'vue'
4
+ import type { ParameterDefinition } from '../composables/useProtocolTemplates'
5
+ import type { ConcentrationValue } from '../composables/useConcentrationUnits'
6
+ import ConcentrationInput from './ConcentrationInput.vue'
7
+
8
+ interface Props {
9
+ parameter: ParameterDefinition
10
+ modelValue?: unknown
11
+ error?: string
12
+ }
13
+
14
+ const props = defineProps<Props>()
15
+
16
+ const emit = defineEmits<{
17
+ 'update:modelValue': [value: unknown]
18
+ }>()
19
+
20
+ const scalarValue = computed(() => (
21
+ props.modelValue as string | number | undefined
22
+ ))
23
+
24
+ const concentrationValue = computed(() => (
25
+ props.modelValue as ConcentrationValue | undefined
26
+ ))
27
+
28
+ const hasError = computed(() => !!props.error)
29
+
30
+ function handleNumberInput(event: Event) {
31
+ emit('update:modelValue', (event.target as HTMLInputElement).valueAsNumber)
32
+ }
33
+
34
+ function handleTextInput(event: Event) {
35
+ emit('update:modelValue', (event.target as HTMLInputElement).value)
36
+ }
37
+
38
+ function handleSelectChange(event: Event) {
39
+ emit('update:modelValue', (event.target as HTMLSelectElement).value)
40
+ }
41
+
42
+ function handleConcentrationChange(value: ConcentrationValue | undefined) {
43
+ emit('update:modelValue', value)
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <div class="mint-protocol-editor__field">
49
+ <label
50
+ :class="[
51
+ 'mint-protocol-editor__field-label',
52
+ parameter.required ? 'mint-protocol-editor__field-label--required' : '',
53
+ ]"
54
+ >
55
+ {{ parameter.label }}
56
+ </label>
57
+
58
+ <div
59
+ v-if="parameter.type === 'number' || parameter.type === 'temperature' || parameter.type === 'duration'"
60
+ class="mint-protocol-editor__input-unit"
61
+ >
62
+ <input
63
+ type="number"
64
+ :value="scalarValue"
65
+ :min="parameter.min"
66
+ :max="parameter.max"
67
+ :placeholder="parameter.placeholder || `Enter ${parameter.label.toLowerCase()}`"
68
+ :class="[
69
+ 'mint-protocol-editor__input',
70
+ hasError ? 'mint-protocol-editor__input--error' : '',
71
+ ]"
72
+ @input="handleNumberInput"
73
+ />
74
+ <span v-if="parameter.unit" class="mint-protocol-editor__unit-suffix">
75
+ {{ parameter.unit }}
76
+ </span>
77
+ </div>
78
+
79
+ <input
80
+ v-else-if="parameter.type === 'text'"
81
+ type="text"
82
+ :value="scalarValue"
83
+ :placeholder="parameter.placeholder || `Enter ${parameter.label.toLowerCase()}`"
84
+ :class="[
85
+ 'mint-protocol-editor__input',
86
+ hasError ? 'mint-protocol-editor__input--error' : '',
87
+ ]"
88
+ @input="handleTextInput"
89
+ />
90
+
91
+ <select
92
+ v-else-if="parameter.type === 'select'"
93
+ :value="scalarValue"
94
+ :class="[
95
+ 'mint-protocol-editor__select',
96
+ hasError ? 'mint-protocol-editor__input--error' : '',
97
+ ]"
98
+ @change="handleSelectChange"
99
+ >
100
+ <option value="" disabled>Select {{ parameter.label.toLowerCase() }}</option>
101
+ <option
102
+ v-for="option in parameter.options"
103
+ :key="option.value"
104
+ :value="option.value"
105
+ >
106
+ {{ option.label }}
107
+ </option>
108
+ </select>
109
+
110
+ <ConcentrationInput
111
+ v-else-if="parameter.type === 'concentration'"
112
+ :model-value="concentrationValue"
113
+ :error="hasError"
114
+ size="md"
115
+ @update:model-value="handleConcentrationChange"
116
+ />
117
+
118
+ <input
119
+ v-else-if="parameter.type === 'reagent'"
120
+ type="text"
121
+ :value="scalarValue"
122
+ :placeholder="parameter.placeholder || 'Enter reagent name'"
123
+ :class="[
124
+ 'mint-protocol-editor__input',
125
+ hasError ? 'mint-protocol-editor__input--error' : '',
126
+ ]"
127
+ @input="handleTextInput"
128
+ />
129
+
130
+ <span v-if="error" class="mint-protocol-editor__field-error">
131
+ {{ error }}
132
+ </span>
133
+ </div>
134
+ </template>
@@ -0,0 +1,105 @@
1
+ import type { Reagent, ReagentColumn } from '../types'
2
+
3
+ export const REAGENT_COLUMN_LABELS: Record<ReagentColumn, string> = {
4
+ name: 'Name',
5
+ catalog: 'Catalog #',
6
+ lot: 'Lot #',
7
+ expiry: 'Expiry',
8
+ storage: 'Storage',
9
+ location: 'Location',
10
+ stock: 'Stock',
11
+ supplier: 'Supplier',
12
+ }
13
+
14
+ export interface ReagentRowClassOptions {
15
+ lowStockThreshold: number
16
+ draggedId?: string | null
17
+ dragOverId?: string | null
18
+ now?: Date
19
+ }
20
+
21
+ export function getReagentColumnValue(reagent: Reagent, column: ReagentColumn): unknown {
22
+ switch (column) {
23
+ case 'name':
24
+ return reagent.name
25
+ case 'catalog':
26
+ return reagent.catalogNumber
27
+ case 'lot':
28
+ return reagent.lotNumber
29
+ case 'expiry':
30
+ return reagent.expiryDate ? new Date(reagent.expiryDate).getTime() : null
31
+ case 'storage':
32
+ return reagent.storageCondition
33
+ case 'location':
34
+ return reagent.location
35
+ case 'stock':
36
+ return reagent.stockLevel
37
+ case 'supplier':
38
+ return reagent.supplier
39
+ default:
40
+ return null
41
+ }
42
+ }
43
+
44
+ export function isReagentExpired(reagent: Reagent, now = new Date()): boolean {
45
+ if (!reagent.expiryDate) return false
46
+ const expiry = new Date(reagent.expiryDate)
47
+ return expiry < now
48
+ }
49
+
50
+ export function isReagentExpiringSoon(
51
+ reagent: Reagent,
52
+ daysThreshold = 30,
53
+ now = new Date()
54
+ ): boolean {
55
+ if (!reagent.expiryDate) return false
56
+ const expiry = new Date(reagent.expiryDate)
57
+ const daysUntilExpiry = (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
58
+ return daysUntilExpiry > 0 && daysUntilExpiry <= daysThreshold
59
+ }
60
+
61
+ export function isReagentLowStock(reagent: Reagent, lowStockThreshold: number): boolean {
62
+ if (reagent.stockLevel === undefined) return false
63
+ return reagent.stockLevel <= lowStockThreshold
64
+ }
65
+
66
+ export function formatReagentExpiryDate(date: Date | string | undefined): string {
67
+ if (!date) return '-'
68
+ const parsed = new Date(date)
69
+ return parsed.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
70
+ }
71
+
72
+ export function getReagentStockLevel(reagent: Reagent): number {
73
+ return reagent.stockLevel ?? 0
74
+ }
75
+
76
+ export function getReagentStockFillClass(level: number): string {
77
+ if (level >= 50) return 'mint-reagent-list__stock-fill--good'
78
+ if (level >= 20) return 'mint-reagent-list__stock-fill--warning'
79
+ return 'mint-reagent-list__stock-fill--low'
80
+ }
81
+
82
+ export function getReagentRowClasses(
83
+ reagent: Reagent,
84
+ options: ReagentRowClassOptions
85
+ ): string[] {
86
+ const classes: string[] = ['mint-reagent-list__row']
87
+
88
+ if (isReagentExpired(reagent, options.now)) {
89
+ classes.push('mint-reagent-list__row--expired')
90
+ } else if (isReagentExpiringSoon(reagent, 30, options.now)) {
91
+ classes.push('mint-reagent-list__row--expiring-soon')
92
+ }
93
+
94
+ if (isReagentLowStock(reagent, options.lowStockThreshold)) {
95
+ classes.push('mint-reagent-list__row--low-stock')
96
+ }
97
+ if (options.draggedId === reagent.id) {
98
+ classes.push('mint-reagent-list__row--dragging')
99
+ }
100
+ if (options.dragOverId === reagent.id) {
101
+ classes.push('mint-reagent-list__row--drag-over')
102
+ }
103
+
104
+ return classes
105
+ }
@@ -4,6 +4,16 @@ import { ref, computed } from 'vue'
4
4
  import type { ReagentColumn, Reagent } from '../types'
5
5
  import { useSortedItems } from '../composables/useSortedItems'
6
6
  import { useTextSearch } from '../composables/useTextSearch'
7
+ import {
8
+ REAGENT_COLUMN_LABELS as columnLabels,
9
+ formatReagentExpiryDate as formatExpiryDate,
10
+ getReagentColumnValue,
11
+ getReagentRowClasses,
12
+ getReagentStockFillClass as getStockFillClass,
13
+ getReagentStockLevel as getStockLevel,
14
+ isReagentExpired as isExpired,
15
+ isReagentExpiringSoon as isExpiringSoon,
16
+ } from './ReagentList.presentation'
7
17
 
8
18
  interface Props {
9
19
  modelValue?: Reagent[]
@@ -40,18 +50,6 @@ const sortDirection = ref<'asc' | 'desc'>('asc')
40
50
  const draggedId = ref<string | null>(null)
41
51
  const dragOverId = ref<string | null>(null)
42
52
 
43
- // Column configuration
44
- const columnLabels: Record<ReagentColumn, string> = {
45
- name: 'Name',
46
- catalog: 'Catalog #',
47
- lot: 'Lot #',
48
- expiry: 'Expiry',
49
- storage: 'Storage',
50
- location: 'Location',
51
- stock: 'Stock',
52
- supplier: 'Supplier',
53
- }
54
-
55
53
  const reagentSearch = useTextSearch({
56
54
  items: () => props.modelValue || [],
57
55
  query: searchQuery,
@@ -76,77 +74,16 @@ const sortedReagents = useSortedItems<Reagent, ReagentColumn>({
76
74
  items: reagentSearch.filteredItems,
77
75
  sort: reagentSort,
78
76
  caseSensitive: false,
79
- getValue: (reagent, column) => getColumnValue(reagent, column),
77
+ getValue: (reagent, column) => getReagentColumnValue(reagent, column),
80
78
  })
81
79
  const filteredReagents = sortedReagents.sortedItems
82
80
 
83
- function getColumnValue(reagent: Reagent, column: ReagentColumn): unknown {
84
- switch (column) {
85
- case 'name':
86
- return reagent.name
87
- case 'catalog':
88
- return reagent.catalogNumber
89
- case 'lot':
90
- return reagent.lotNumber
91
- case 'expiry':
92
- return reagent.expiryDate ? new Date(reagent.expiryDate).getTime() : null
93
- case 'storage':
94
- return reagent.storageCondition
95
- case 'location':
96
- return reagent.location
97
- case 'stock':
98
- return reagent.stockLevel
99
- case 'supplier':
100
- return reagent.supplier
101
- default:
102
- return null
103
- }
104
- }
105
-
106
- // Helpers
107
- function isExpired(reagent: Reagent): boolean {
108
- if (!reagent.expiryDate) return false
109
- const expiry = new Date(reagent.expiryDate)
110
- return expiry < new Date()
111
- }
112
-
113
- function isExpiringSoon(reagent: Reagent, daysThreshold = 30): boolean {
114
- if (!reagent.expiryDate) return false
115
- const expiry = new Date(reagent.expiryDate)
116
- const now = new Date()
117
- const daysUntilExpiry = (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
118
- return daysUntilExpiry > 0 && daysUntilExpiry <= daysThreshold
119
- }
120
-
121
- function isLowStock(reagent: Reagent): boolean {
122
- if (reagent.stockLevel === undefined) return false
123
- return reagent.stockLevel <= props.lowStockThreshold
124
- }
125
-
126
- function formatExpiryDate(date: Date | string | undefined): string {
127
- if (!date) return '-'
128
- const d = new Date(date)
129
- return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })
130
- }
131
-
132
- function getStockLevel(reagent: Reagent): number {
133
- return reagent.stockLevel ?? 0
134
- }
135
-
136
- function getStockFillClass(level: number): string {
137
- if (level >= 50) return 'mint-reagent-list__stock-fill--good'
138
- if (level >= 20) return 'mint-reagent-list__stock-fill--warning'
139
- return 'mint-reagent-list__stock-fill--low'
140
- }
141
-
142
81
  function getRowClass(reagent: Reagent): string[] {
143
- const classes: string[] = ['mint-reagent-list__row']
144
- if (isExpired(reagent)) classes.push('mint-reagent-list__row--expired')
145
- else if (isExpiringSoon(reagent)) classes.push('mint-reagent-list__row--expiring-soon')
146
- if (isLowStock(reagent)) classes.push('mint-reagent-list__row--low-stock')
147
- if (draggedId.value === reagent.id) classes.push('mint-reagent-list__row--dragging')
148
- if (dragOverId.value === reagent.id) classes.push('mint-reagent-list__row--drag-over')
149
- return classes
82
+ return getReagentRowClasses(reagent, {
83
+ lowStockThreshold: props.lowStockThreshold,
84
+ draggedId: draggedId.value,
85
+ dragOverId: dragOverId.value,
86
+ })
150
87
  }
151
88
 
152
89
  // Actions
@@ -0,0 +1,43 @@
1
+ import { DEFAULT_COLORS } from '../composables/useAutoGroup'
2
+ import type { SampleGroup } from '../types'
3
+
4
+ export type ColorEdit =
5
+ | { kind: 'single'; name: string }
6
+ | { kind: 'family'; names: string[] }
7
+
8
+ export const DEFAULT_COLOR_PICKER_SEED = '#3B82F6'
9
+
10
+ export function applySampleGroupColorEdit(
11
+ groups: SampleGroup[],
12
+ edit: ColorEdit,
13
+ color: string,
14
+ ): SampleGroup[] {
15
+ const targets = edit.kind === 'family' ? new Set(edit.names) : new Set([edit.name])
16
+ return groups.map(group =>
17
+ targets.has(group.name) ? { ...group, color } : group,
18
+ )
19
+ }
20
+
21
+ export function getSampleGroupColorEditSeed(
22
+ edit: ColorEdit | null,
23
+ getGroupColor: (groupName: string) => string,
24
+ ): string {
25
+ if (!edit) return DEFAULT_COLOR_PICKER_SEED
26
+ return getGroupColor(edit.kind === 'family' ? edit.names[0] : edit.name)
27
+ }
28
+
29
+ export function pickUnusedSampleGroupColor(groups: SampleGroup[]): string {
30
+ const usedColors = new Set(groups.map(group => group.color))
31
+ return DEFAULT_COLORS.find(color => !usedColors.has(color)) || DEFAULT_COLORS[0]
32
+ }
33
+
34
+ export function createSampleGroup(name: string, existingGroups: SampleGroup[]): SampleGroup | null {
35
+ const trimmedName = name.trim()
36
+ if (!trimmedName) return null
37
+
38
+ return {
39
+ name: trimmedName,
40
+ color: pickUnusedSampleGroupColor(existingGroups),
41
+ samples: [],
42
+ }
43
+ }