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

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 (324) 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 +9 -6
  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 +7 -2
  44. package/dist/components/BaseInput.vue.d.ts +2 -2
  45. package/dist/components/BasePill.vue.d.ts +2 -2
  46. package/dist/components/BaseRadioGroup.vue.d.ts +2 -2
  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 +7 -2
  51. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  52. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  53. package/dist/components/CollapsibleCard.vue.d.ts +9 -0
  54. package/dist/components/ColorSlider.vue.d.ts +2 -2
  55. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  56. package/dist/components/ControlWorkspaceView.vue.d.ts +4 -4
  57. package/dist/components/DatePicker.vue.d.ts +1 -1
  58. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  59. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  60. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +2 -2
  61. package/dist/components/DropdownButton.vue.d.ts +1 -1
  62. package/dist/components/FileUploader.vue.d.ts +2 -2
  63. package/dist/components/FormulaInput.vue.d.ts +2 -2
  64. package/dist/components/IconButton.vue.d.ts +1 -1
  65. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  66. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  67. package/dist/components/MultiSelect.vue.d.ts +1 -1
  68. package/dist/components/NumberInput.vue.d.ts +1 -1
  69. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  70. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  71. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  72. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  73. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  74. package/dist/components/PluginWorkspaceView.vue.d.ts +51 -196
  75. package/dist/components/ProgressBar.vue.d.ts +1 -1
  76. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  77. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  78. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  79. package/dist/components/ReagentList.presentation.d.ts +16 -0
  80. package/dist/components/ResourceCard.vue.d.ts +1 -1
  81. package/dist/components/SampleSelector.colors.d.ts +13 -0
  82. package/dist/components/SampleSelector.drag.d.ts +24 -0
  83. package/dist/components/SampleSelector.groups.d.ts +15 -0
  84. package/dist/components/SampleSelector.selection.d.ts +26 -0
  85. package/dist/components/SampleSelector.vue.d.ts +4 -1
  86. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  87. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  88. package/dist/components/SequenceInput.vue.d.ts +2 -2
  89. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  90. package/dist/components/SettingsModal.schema.d.ts +9 -0
  91. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  92. package/dist/components/TagsInput.vue.d.ts +2 -2
  93. package/dist/components/TimePicker.vue.d.ts +2 -2
  94. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  95. package/dist/components/UnitInput.vue.d.ts +2 -2
  96. package/dist/components/WellPlate.colors.d.ts +9 -0
  97. package/dist/components/WellPlate.conditions.d.ts +26 -0
  98. package/dist/components/WellPlate.geometry.d.ts +23 -0
  99. package/dist/components/WellPlate.interaction.d.ts +71 -0
  100. package/dist/components/WellPlate.legend.d.ts +2 -0
  101. package/dist/components/WellPlate.rendering.d.ts +24 -0
  102. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  103. package/dist/components/WellPlate.vue.d.ts +1 -1
  104. package/dist/components/index.js +2 -2
  105. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  106. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  107. package/dist/{components-DafPc4rM.js → components-Blx4MG--.js} +4073 -4222
  108. package/dist/components-Blx4MG--.js.map +1 -0
  109. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  110. package/dist/composables/autoGroup/classify.d.ts +28 -0
  111. package/dist/composables/autoGroup/colors.d.ts +2 -0
  112. package/dist/composables/autoGroup/columns.d.ts +10 -0
  113. package/dist/composables/autoGroup/compose.d.ts +8 -0
  114. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  115. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  116. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  117. package/dist/composables/autoGroup/index.d.ts +16 -0
  118. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  119. package/dist/composables/autoGroup/template.d.ts +15 -0
  120. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  121. package/dist/composables/autoGroupConstants.d.ts +1 -0
  122. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  123. package/dist/composables/controlComponentBindings.d.ts +1 -1
  124. package/dist/composables/controlSchemaAdapters.d.ts +1 -1
  125. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  126. package/dist/composables/controlSchemaLayout.d.ts +1 -1
  127. package/dist/composables/controlSchemaModel.d.ts +5 -0
  128. package/dist/composables/controlSchemaNormalize.d.ts +1 -1
  129. package/dist/composables/controlSchemaTypes.d.ts +311 -0
  130. package/dist/composables/controlWorkspaceOptions.d.ts +1 -1
  131. package/dist/composables/formBuilderSchema.d.ts +18 -0
  132. package/dist/composables/index.js +3 -3
  133. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  134. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  135. package/dist/composables/useAutoGroup.d.ts +61 -74
  136. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  137. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  138. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  139. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  140. package/dist/composables/useControlSchema.d.ts +4 -316
  141. package/dist/composables/useControlWorkspace.d.ts +1 -1
  142. package/dist/composables/useForm.d.ts +2 -33
  143. package/dist/composables/useFormBuilder.d.ts +2 -9
  144. package/dist/composables/useFormValidation.d.ts +34 -0
  145. package/dist/composables/usePluginClient.d.ts +1 -4
  146. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  147. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  148. package/dist/{composables-BMkPQhVK.js → composables-CHDjDIQT.js} +33 -31
  149. package/dist/composables-CHDjDIQT.js.map +1 -0
  150. package/dist/index.js +4 -4
  151. package/dist/install.js +2 -2
  152. package/dist/styles.css +1432 -660
  153. package/dist/templates/controlSchemaTypes.d.ts +1 -1
  154. package/dist/templates/index.js +1 -1
  155. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  156. package/dist/templates/templateCreateOptions.d.ts +165 -0
  157. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  158. package/dist/templates/types.d.ts +5 -250
  159. package/dist/{templates-bUAWMn5L.js → templates-DSbHJC4v.js} +1536 -297
  160. package/dist/templates-DSbHJC4v.js.map +1 -0
  161. package/dist/types/auto-group.d.ts +79 -9
  162. package/dist/types/componentLabTypes.d.ts +161 -0
  163. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  164. package/dist/types/components.d.ts +14 -311
  165. package/dist/types/form-builder.d.ts +3 -0
  166. package/dist/types/index.d.ts +1 -1
  167. package/dist/{useProtocolTemplates-QZtHFFH2.js → useProtocolTemplates-BbPOYPzO.js} +1220 -454
  168. package/dist/useProtocolTemplates-BbPOYPzO.js.map +1 -0
  169. package/package.json +1 -1
  170. package/src/__tests__/components/AppSidebar.test.ts +67 -0
  171. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  172. package/src/__tests__/components/CollapsibleCard.test.ts +47 -0
  173. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  174. package/src/__tests__/components/FormBuilder.test.ts +57 -0
  175. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  176. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  177. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  178. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +43 -0
  179. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  180. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  181. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  182. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  183. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  184. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  185. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  186. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  187. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  188. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  189. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  190. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  191. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  192. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  193. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  194. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  195. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  196. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  197. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  198. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  199. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  200. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  201. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  202. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  203. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  204. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  205. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  206. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  207. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  208. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  209. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  210. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  211. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  212. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  213. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  214. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  215. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  216. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  217. package/src/components/AppSidebar.story.vue +79 -6
  218. package/src/components/AppSidebar.vue +74 -6
  219. package/src/components/AppTopBar.navigation.ts +62 -0
  220. package/src/components/AppTopBar.vue +17 -44
  221. package/src/components/AutoGroupModal.story.vue +50 -0
  222. package/src/components/AutoGroupModal.vue +441 -158
  223. package/src/components/BaseCheckbox.story.vue +27 -0
  224. package/src/components/BaseCheckbox.vue +63 -1
  225. package/src/components/BaseToggle.story.vue +27 -0
  226. package/src/components/BaseToggle.vue +66 -1
  227. package/src/components/CollapsibleCard.vue +123 -45
  228. package/src/components/ControlWorkspaceView.vue +2 -6
  229. package/src/components/DoseCalculator.vue +13 -73
  230. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  231. package/src/components/ExperimentTimeline.vue +6 -31
  232. package/src/components/FormBuilder.story.vue +13 -0
  233. package/src/components/FormBuilder.vue +2 -7
  234. package/src/components/PlateMapEditor.vue +32 -106
  235. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  236. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  237. package/src/components/PluginWorkspaceView.props.ts +174 -0
  238. package/src/components/PluginWorkspaceView.shell.ts +67 -0
  239. package/src/components/PluginWorkspaceView.vue +88 -404
  240. package/src/components/ProtocolStep.presentation.ts +31 -0
  241. package/src/components/ProtocolStepEditor.state.ts +104 -0
  242. package/src/components/ProtocolStepEditor.vue +48 -179
  243. package/src/components/ProtocolStepParameterField.vue +134 -0
  244. package/src/components/ReagentList.presentation.ts +105 -0
  245. package/src/components/ReagentList.vue +16 -79
  246. package/src/components/SampleSelector.colors.ts +43 -0
  247. package/src/components/SampleSelector.drag.ts +164 -0
  248. package/src/components/SampleSelector.groups.ts +109 -0
  249. package/src/components/SampleSelector.selection.ts +103 -0
  250. package/src/components/SampleSelector.vue +82 -349
  251. package/src/components/SampleSelectorSampleRow.vue +64 -0
  252. package/src/components/ScheduleCalendar.vue +44 -199
  253. package/src/components/SettingsModal.schema.ts +71 -0
  254. package/src/components/SettingsModal.vue +16 -46
  255. package/src/components/WellPlate.colors.ts +56 -0
  256. package/src/components/WellPlate.conditions.ts +100 -0
  257. package/src/components/WellPlate.geometry.ts +91 -0
  258. package/src/components/WellPlate.interaction.ts +272 -0
  259. package/src/components/WellPlate.legend.ts +8 -0
  260. package/src/components/WellPlate.rendering.ts +105 -0
  261. package/src/components/WellPlate.sampleDrop.ts +73 -0
  262. package/src/components/WellPlate.vue +102 -550
  263. package/src/components/internal/FormFieldRendererInternal.vue +23 -5
  264. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  265. package/src/composables/autoGroup/classKey.ts +5 -0
  266. package/src/composables/autoGroup/classify.ts +205 -0
  267. package/src/composables/autoGroup/colors.ts +6 -0
  268. package/src/composables/autoGroup/columns.ts +226 -0
  269. package/src/composables/autoGroup/compose.ts +156 -0
  270. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  271. package/src/composables/autoGroup/csv-shim.ts +44 -0
  272. package/src/composables/autoGroup/fingerprint.ts +49 -0
  273. package/src/composables/autoGroup/index.ts +20 -0
  274. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  275. package/src/composables/autoGroup/template.ts +126 -0
  276. package/src/composables/autoGroup/tokenize.ts +41 -0
  277. package/src/composables/autoGroup/vocab.json +67 -0
  278. package/src/composables/autoGroupConstants.ts +4 -0
  279. package/src/composables/autoGroupGrouping.ts +148 -0
  280. package/src/composables/controlComponentBindings.ts +1 -1
  281. package/src/composables/controlSchemaAdapters.ts +4 -1
  282. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  283. package/src/composables/controlSchemaFormFields.ts +4 -1
  284. package/src/composables/controlSchemaLayout.ts +1 -1
  285. package/src/composables/controlSchemaModel.ts +163 -0
  286. package/src/composables/controlSchemaNormalize.ts +1 -1
  287. package/src/composables/controlSchemaTypes.ts +372 -0
  288. package/src/composables/controlWorkspaceOptions.ts +1 -1
  289. package/src/composables/formBuilderSchema.ts +153 -0
  290. package/src/composables/pluginEndpointBuilder.ts +203 -0
  291. package/src/composables/protocolTemplateCatalog.ts +325 -0
  292. package/src/composables/useAutoGroup.ts +395 -549
  293. package/src/composables/useAutoGroupInputSources.ts +147 -0
  294. package/src/composables/useBioTemplateControls.ts +1 -1
  295. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  296. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  297. package/src/composables/useControlSchema.ts +21 -692
  298. package/src/composables/useControlWorkspace.ts +7 -13
  299. package/src/composables/useForm.ts +5 -187
  300. package/src/composables/useFormBuilder.ts +11 -153
  301. package/src/composables/useFormValidation.ts +154 -0
  302. package/src/composables/usePluginClient.ts +10 -193
  303. package/src/composables/useProtocolTemplates.ts +10 -328
  304. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  305. package/src/styles/components/app-sidebar.css +134 -6
  306. package/src/styles/components/auto-group-modal.css +248 -310
  307. package/src/styles/components/checkbox.css +87 -0
  308. package/src/styles/components/collapsible-card.css +154 -14
  309. package/src/styles/components/toggle.css +80 -0
  310. package/src/templates/controlSchemaTypes.ts +1 -1
  311. package/src/templates/templateAdapterTypes.ts +58 -0
  312. package/src/templates/templateCreateOptions.ts +208 -0
  313. package/src/templates/templateQpcrTypes.ts +48 -0
  314. package/src/templates/types.ts +79 -275
  315. package/src/types/auto-group.ts +107 -9
  316. package/src/types/componentLabTypes.ts +235 -0
  317. package/src/types/componentWorkflowTypes.ts +190 -0
  318. package/src/types/components.ts +95 -424
  319. package/src/types/form-builder.ts +3 -0
  320. package/src/types/index.ts +2 -0
  321. package/dist/components-DafPc4rM.js.map +0 -1
  322. package/dist/composables-BMkPQhVK.js.map +0 -1
  323. package/dist/templates-bUAWMn5L.js.map +0 -1
  324. package/dist/useProtocolTemplates-QZtHFFH2.js.map +0 -1
@@ -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
+ }
@@ -0,0 +1,164 @@
1
+ import { ref } from 'vue'
2
+ import type { SampleGroup } from '../types'
3
+ import {
4
+ detectSampleGroupSeparator,
5
+ getSampleGroupMajorPrefix,
6
+ moveSampleToGroup,
7
+ reorderSampleGroup,
8
+ reorderSampleMajorGroup,
9
+ type GroupDragKind,
10
+ type GroupReorderPosition,
11
+ } from './SampleSelector.groups'
12
+
13
+ interface MutableSampleGroups {
14
+ value: SampleGroup[]
15
+ }
16
+
17
+ export function useSampleSelectorDrag(groups: MutableSampleGroups) {
18
+ const draggingSample = ref<string | null>(null)
19
+ const dragSourceGroup = ref<string | null>(null)
20
+ const dragOverGroup = ref<string | null>(null)
21
+
22
+ const draggingGroup = ref<string | null>(null)
23
+ const draggingGroupKind = ref<GroupDragKind | null>(null)
24
+ const reorderTarget = ref<string | null>(null)
25
+ const reorderPosition = ref<GroupReorderPosition | null>(null)
26
+
27
+ function handleDragStart(sample: string, sourceGroup: string | null, event: DragEvent) {
28
+ draggingSample.value = sample
29
+ dragSourceGroup.value = sourceGroup
30
+ if (event.dataTransfer) {
31
+ event.dataTransfer.effectAllowed = 'move'
32
+ event.dataTransfer.setData('text/plain', sample)
33
+ }
34
+ }
35
+
36
+ function resetDragState() {
37
+ draggingSample.value = null
38
+ dragSourceGroup.value = null
39
+ dragOverGroup.value = null
40
+ }
41
+
42
+ function handleDragEnd() {
43
+ resetDragState()
44
+ }
45
+
46
+ function handleDragOver(groupName: string, event: DragEvent) {
47
+ // Only accept this drop target when a sample is being dragged; group drags are handled separately.
48
+ if (!draggingSample.value) return
49
+ event.preventDefault()
50
+ if (event.dataTransfer) {
51
+ event.dataTransfer.dropEffect = 'move'
52
+ }
53
+ dragOverGroup.value = groupName
54
+ }
55
+
56
+ function handleDragLeave() {
57
+ dragOverGroup.value = null
58
+ }
59
+
60
+ function handleDrop(targetGroupName: string, event: DragEvent) {
61
+ if (!draggingSample.value) return
62
+ event.preventDefault()
63
+
64
+ const sample = draggingSample.value
65
+ const sourceGroup = dragSourceGroup.value
66
+
67
+ if (sourceGroup === targetGroupName) {
68
+ resetDragState()
69
+ return
70
+ }
71
+
72
+ groups.value = moveSampleToGroup(groups.value, sample, sourceGroup, targetGroupName)
73
+ resetDragState()
74
+ }
75
+
76
+ function handleGroupDragStart(name: string, kind: GroupDragKind, event: DragEvent) {
77
+ draggingGroup.value = name
78
+ draggingGroupKind.value = kind
79
+ if (event.dataTransfer) {
80
+ event.dataTransfer.effectAllowed = 'move'
81
+ event.dataTransfer.setData('text/plain', `mint-group:${name}`)
82
+ }
83
+ }
84
+
85
+ function handleGroupDragEnd() {
86
+ draggingGroup.value = null
87
+ draggingGroupKind.value = null
88
+ reorderTarget.value = null
89
+ reorderPosition.value = null
90
+ }
91
+
92
+ function handleGroupDragOver(name: string, kind: GroupDragKind, event: DragEvent) {
93
+ if (!draggingGroup.value || draggingGroupKind.value !== kind) return
94
+ if (draggingGroup.value === name) return
95
+
96
+ // Sub-group reorder is restricted to siblings under the same major prefix;
97
+ // crossing majors would silently rename the group, which is too magical.
98
+ if (kind === 'sub') {
99
+ const separator = detectSampleGroupSeparator(groups.value)
100
+ if (
101
+ getSampleGroupMajorPrefix(draggingGroup.value, separator) !==
102
+ getSampleGroupMajorPrefix(name, separator)
103
+ ) return
104
+ }
105
+
106
+ event.preventDefault()
107
+ if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'
108
+
109
+ const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()
110
+ reorderTarget.value = name
111
+ reorderPosition.value = event.clientY < rect.top + rect.height / 2 ? 'before' : 'after'
112
+ }
113
+
114
+ function handleGroupDragLeave(event: DragEvent) {
115
+ const cur = event.currentTarget as HTMLElement
116
+ const rel = event.relatedTarget as Node | null
117
+ if (rel && cur.contains(rel)) return
118
+ reorderTarget.value = null
119
+ reorderPosition.value = null
120
+ }
121
+
122
+ function handleGroupDrop(name: string, kind: GroupDragKind, event: DragEvent) {
123
+ if (!draggingGroup.value || draggingGroupKind.value !== kind) {
124
+ handleGroupDragEnd()
125
+ return
126
+ }
127
+ const position = reorderPosition.value
128
+ if (!position || draggingGroup.value === name) {
129
+ handleGroupDragEnd()
130
+ return
131
+ }
132
+
133
+ event.preventDefault()
134
+
135
+ if (kind === 'major') {
136
+ const nextGroups = reorderSampleMajorGroup(groups.value, draggingGroup.value, name, position)
137
+ if (nextGroups !== groups.value) groups.value = nextGroups
138
+ } else {
139
+ const nextGroups = reorderSampleGroup(groups.value, draggingGroup.value, name, position)
140
+ if (nextGroups !== groups.value) groups.value = nextGroups
141
+ }
142
+
143
+ handleGroupDragEnd()
144
+ }
145
+
146
+ return {
147
+ draggingSample,
148
+ dragOverGroup,
149
+ draggingGroup,
150
+ draggingGroupKind,
151
+ reorderTarget,
152
+ reorderPosition,
153
+ handleDragStart,
154
+ handleDragEnd,
155
+ handleDragOver,
156
+ handleDragLeave,
157
+ handleDrop,
158
+ handleGroupDragStart,
159
+ handleGroupDragEnd,
160
+ handleGroupDragOver,
161
+ handleGroupDragLeave,
162
+ handleGroupDrop,
163
+ }
164
+ }
@@ -0,0 +1,109 @@
1
+ import type { SampleGroup } from '../types'
2
+
3
+ export type GroupDragKind = 'major' | 'sub' | 'flat'
4
+ export type GroupReorderPosition = 'before' | 'after'
5
+
6
+ export function detectSampleGroupSeparator(groups: SampleGroup[]): string {
7
+ return groups.some(group => group.name.includes('/')) ? '/' : '_'
8
+ }
9
+
10
+ export function getSampleGroupMajorPrefix(groupName: string, separator: string): string {
11
+ const parts = groupName.split(separator)
12
+ return parts.length > 1 ? parts[0] : groupName
13
+ }
14
+
15
+ export function moveSampleToGroup(
16
+ groups: SampleGroup[],
17
+ sample: string,
18
+ sourceGroup: string | null,
19
+ targetGroup: string,
20
+ ): SampleGroup[] {
21
+ if (sourceGroup === targetGroup) return groups
22
+
23
+ return groups.map(group => {
24
+ if (sourceGroup && group.name === sourceGroup) {
25
+ return { ...group, samples: group.samples.filter(item => item !== sample) }
26
+ }
27
+ if (group.name === targetGroup && !group.samples.includes(sample)) {
28
+ return { ...group, samples: [...group.samples, sample] }
29
+ }
30
+ return group
31
+ })
32
+ }
33
+
34
+ export function removeSampleGroup(groups: SampleGroup[], groupName: string): SampleGroup[] {
35
+ return groups.filter(group => group.name !== groupName)
36
+ }
37
+
38
+ export function removeSampleMajorGroup(
39
+ groups: SampleGroup[],
40
+ majorGroup: { subGroups: Array<{ name: string }> },
41
+ ): SampleGroup[] {
42
+ const groupNames = new Set(majorGroup.subGroups.map(group => group.name))
43
+ return groups.filter(group => !groupNames.has(group.name))
44
+ }
45
+
46
+ export function removeSampleFromGroup(
47
+ groups: SampleGroup[],
48
+ sample: string,
49
+ groupName: string,
50
+ ): SampleGroup[] {
51
+ return groups.map(group =>
52
+ group.name === groupName
53
+ ? { ...group, samples: group.samples.filter(item => item !== sample) }
54
+ : group,
55
+ )
56
+ }
57
+
58
+ export function reorderSampleGroup(
59
+ groups: SampleGroup[],
60
+ source: string,
61
+ target: string,
62
+ position: GroupReorderPosition,
63
+ ): SampleGroup[] {
64
+ if (source === target) return groups
65
+
66
+ const nextGroups = [...groups]
67
+ const sourceIndex = nextGroups.findIndex(group => group.name === source)
68
+ if (sourceIndex === -1) return groups
69
+
70
+ const [item] = nextGroups.splice(sourceIndex, 1)
71
+ const targetIndex = nextGroups.findIndex(group => group.name === target)
72
+ if (targetIndex === -1) return groups
73
+
74
+ nextGroups.splice(position === 'before' ? targetIndex : targetIndex + 1, 0, item)
75
+ return nextGroups
76
+ }
77
+
78
+ export function reorderSampleMajorGroup(
79
+ groups: SampleGroup[],
80
+ source: string,
81
+ target: string,
82
+ position: GroupReorderPosition,
83
+ ): SampleGroup[] {
84
+ if (source === target) return groups
85
+
86
+ const separator = detectSampleGroupSeparator(groups)
87
+ const isSource = (group: SampleGroup) => getSampleGroupMajorPrefix(group.name, separator) === source
88
+ const isTarget = (group: SampleGroup) => getSampleGroupMajorPrefix(group.name, separator) === target
89
+
90
+ const sourceGroups = groups.filter(isSource)
91
+ if (sourceGroups.length === 0) return groups
92
+
93
+ const remainingGroups = groups.filter(group => !isSource(group))
94
+ let firstTargetIndex = -1
95
+ let lastTargetIndex = -1
96
+
97
+ remainingGroups.forEach((group, index) => {
98
+ if (isTarget(group)) {
99
+ if (firstTargetIndex === -1) firstTargetIndex = index
100
+ lastTargetIndex = index
101
+ }
102
+ })
103
+
104
+ if (firstTargetIndex === -1) return groups
105
+
106
+ const insertIndex = position === 'before' ? firstTargetIndex : lastTargetIndex + 1
107
+ remainingGroups.splice(insertIndex, 0, ...sourceGroups)
108
+ return remainingGroups
109
+ }
@@ -0,0 +1,103 @@
1
+ import type { ComputedRef } from 'vue'
2
+ import { useListSelection } from '../composables/useListSelection'
3
+ import type { SampleMajorGroup } from '../composables/useSampleGroups'
4
+
5
+ interface SampleGroupSelectionSource {
6
+ samples: string[]
7
+ }
8
+
9
+ export interface UseSampleSelectorSelectionOptions {
10
+ selected: () => string[]
11
+ samples: () => string[]
12
+ findGroup: (groupName: string) => SampleGroupSelectionSource | undefined
13
+ emitSelected: (samples: string[]) => void
14
+ }
15
+
16
+ export interface UseSampleSelectorSelectionReturn {
17
+ isAllSelected: ComputedRef<boolean>
18
+ toggleSelectAll: () => void
19
+ toggleSample: (sample: string) => void
20
+ toggleGroupSamples: (groupName: string) => void
21
+ toggleMajorGroupSamples: (majorGroup: SampleMajorGroup) => void
22
+ isFullySelected: (samples: string[]) => boolean
23
+ isPartiallySelected: (samples: string[]) => boolean
24
+ isGroupFullySelected: (groupName: string) => boolean
25
+ isGroupPartiallySelected: (groupName: string) => boolean
26
+ isMajorGroupFullySelected: (majorGroup: SampleMajorGroup) => boolean
27
+ isMajorGroupPartiallySelected: (majorGroup: SampleMajorGroup) => boolean
28
+ }
29
+
30
+ export function useSampleSelectorSelection(
31
+ options: UseSampleSelectorSelectionOptions,
32
+ ): UseSampleSelectorSelectionReturn {
33
+ const sampleSelection = useListSelection({
34
+ selected: options.selected,
35
+ items: options.samples,
36
+ })
37
+
38
+ function emitSelection(samples: string[]) {
39
+ options.emitSelected(samples)
40
+ }
41
+
42
+ function toggleSelectAll() {
43
+ emitSelection(sampleSelection.toggleAll())
44
+ }
45
+
46
+ function toggleSample(sample: string) {
47
+ emitSelection(sampleSelection.toggleValue(sample))
48
+ }
49
+
50
+ function toggleSamplesSelection(samples: string[]) {
51
+ emitSelection(sampleSelection.toggleValues(samples))
52
+ }
53
+
54
+ function toggleGroupSamples(groupName: string) {
55
+ const group = options.findGroup(groupName)
56
+ if (!group) return
57
+ toggleSamplesSelection(group.samples)
58
+ }
59
+
60
+ function toggleMajorGroupSamples(majorGroup: SampleMajorGroup) {
61
+ toggleSamplesSelection(majorGroup.allSamples)
62
+ }
63
+
64
+ function isFullySelected(samples: string[]): boolean {
65
+ return sampleSelection.isFullySelected(samples)
66
+ }
67
+
68
+ function isPartiallySelected(samples: string[]): boolean {
69
+ return sampleSelection.isPartiallySelected(samples)
70
+ }
71
+
72
+ function isGroupFullySelected(groupName: string): boolean {
73
+ const group = options.findGroup(groupName)
74
+ return group ? isFullySelected(group.samples) : false
75
+ }
76
+
77
+ function isGroupPartiallySelected(groupName: string): boolean {
78
+ const group = options.findGroup(groupName)
79
+ return group ? isPartiallySelected(group.samples) : false
80
+ }
81
+
82
+ function isMajorGroupFullySelected(majorGroup: SampleMajorGroup): boolean {
83
+ return isFullySelected(majorGroup.allSamples)
84
+ }
85
+
86
+ function isMajorGroupPartiallySelected(majorGroup: SampleMajorGroup): boolean {
87
+ return isPartiallySelected(majorGroup.allSamples)
88
+ }
89
+
90
+ return {
91
+ isAllSelected: sampleSelection.isAllSelected,
92
+ toggleSelectAll,
93
+ toggleSample,
94
+ toggleGroupSamples,
95
+ toggleMajorGroupSamples,
96
+ isFullySelected,
97
+ isPartiallySelected,
98
+ isGroupFullySelected,
99
+ isGroupPartiallySelected,
100
+ isMajorGroupFullySelected,
101
+ isMajorGroupPartiallySelected,
102
+ }
103
+ }