@morscherlab/mint-sdk 1.2.0-beta.8 → 1.2.0

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 (402) hide show
  1. package/README.md +60 -0
  2. package/dist/{ExperimentPopover-CfOdh5Rm.js → ExperimentPopover-CJdNlCZb.js} +24 -15
  3. package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DvIagrxY.js → ExperimentSelectorModal-DCXmwKNS.js} +5 -5
  5. package/dist/ExperimentSelectorModal-DCXmwKNS.js.map +1 -0
  6. package/dist/{SettingsModal-W3TYfnP9.js → SettingsModal-BYR20I4c.js} +5 -5
  7. package/dist/SettingsModal-BYR20I4c.js.map +1 -0
  8. package/dist/{EmptyState-NBqf2_8z.js → Skeleton-BAF3CKY7.js} +111 -93
  9. package/dist/Skeleton-BAF3CKY7.js.map +1 -0
  10. package/dist/__tests__/components/DataStates.test.d.ts +1 -0
  11. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  12. package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
  13. package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
  14. package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
  15. package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
  16. package/dist/__tests__/components/iconButtonIconSizing.test.d.ts +1 -0
  17. package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  19. package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
  20. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  21. package/dist/apiErrors.d.ts +26 -0
  22. package/dist/components/ActionMenu.vue.d.ts +1 -1
  23. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  24. package/dist/components/AuditTrail.vue.d.ts +13 -0
  25. package/dist/components/BaseInput.vue.d.ts +1 -1
  26. package/dist/components/BaseSelect.vue.d.ts +1 -1
  27. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  28. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  29. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  30. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
  31. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  32. package/dist/components/DataFrame.vue.d.ts +14 -2
  33. package/dist/components/DatePicker.vue.d.ts +2 -2
  34. package/dist/components/DateTimePicker.vue.d.ts +3 -1
  35. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  36. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  37. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  38. package/dist/components/FileBrowserModal.vue.d.ts +99 -0
  39. package/dist/components/FilePicker.vue.d.ts +32 -0
  40. package/dist/components/FileUploader.vue.d.ts +5 -2
  41. package/dist/components/FormulaInput.vue.d.ts +1 -1
  42. package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
  43. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  44. package/dist/components/MobileSupportGate.vue.d.ts +1 -1
  45. package/dist/components/MoleculeInput.vue.d.ts +1 -1
  46. package/dist/components/NumberInput.vue.d.ts +1 -1
  47. package/dist/components/PlotlyChart.vue.d.ts +59 -0
  48. package/dist/components/ProgressBar.vue.d.ts +1 -1
  49. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  50. package/dist/components/ReagentList.vue.d.ts +29 -1
  51. package/dist/components/ResourceCard.vue.d.ts +1 -1
  52. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  53. package/dist/components/SampleSelector.drag.d.ts +13 -0
  54. package/dist/components/SampleSelector.tree.d.ts +2 -0
  55. package/dist/components/SampleSelector.vue.d.ts +34 -1
  56. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  57. package/dist/components/SecretInput.vue.d.ts +1 -1
  58. package/dist/components/SequenceInput.vue.d.ts +1 -1
  59. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -0
  60. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  61. package/dist/components/TagsInput.vue.d.ts +1 -1
  62. package/dist/components/TimePicker.vue.d.ts +2 -1
  63. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  64. package/dist/components/UnitInput.vue.d.ts +1 -1
  65. package/dist/components/WellPlate.geometry.d.ts +15 -0
  66. package/dist/components/WellPlate.interaction.d.ts +13 -0
  67. package/dist/components/WellPlate.vue.d.ts +30 -1
  68. package/dist/components/fileBrowserPresentation.d.ts +10 -0
  69. package/dist/components/index.d.ts +4 -0
  70. package/dist/components/index.js +8 -8
  71. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  72. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  73. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
  74. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
  75. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
  76. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
  77. package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
  78. package/dist/{components-B80gV0P6.js → components-DIum5hkx.js} +5415 -2753
  79. package/dist/components-DIum5hkx.js.map +1 -0
  80. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  81. package/dist/composables/filePicker/localFiles.d.ts +3 -0
  82. package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
  83. package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
  84. package/dist/composables/filePicker/validation.d.ts +5 -0
  85. package/dist/composables/index.d.ts +3 -0
  86. package/dist/composables/index.js +10 -10
  87. package/dist/composables/useApi.d.ts +14 -7
  88. package/dist/composables/useDropdownState.d.ts +18 -2
  89. package/dist/composables/useEventStream.d.ts +9 -0
  90. package/dist/composables/useFileBrowser.d.ts +55 -0
  91. package/dist/composables/useFilePicker.d.ts +189 -0
  92. package/dist/composables/useListReorder.d.ts +90 -0
  93. package/dist/composables/useMenuKeyboard.d.ts +2 -2
  94. package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
  95. package/dist/composables/usePluginConfig.d.ts +3 -1
  96. package/dist/composables/useRequestSyncState.d.ts +42 -2
  97. package/dist/composables/useScheduleDrag.d.ts +1 -0
  98. package/dist/{composables-C8mmD5ta.js → composables-mFXsTA4g.js} +307 -74
  99. package/dist/composables-mFXsTA4g.js.map +1 -0
  100. package/dist/{useApi-CDBq6z23.js → errors-BLuqMee5.js} +178 -16
  101. package/dist/errors-BLuqMee5.js.map +1 -0
  102. package/dist/{experiment-Y9Iz7KYi.js → experiment-CVDRAnqp.js} +3 -8
  103. package/dist/experiment-CVDRAnqp.js.map +1 -0
  104. package/dist/{experiment-utils-DV3DrvE_.js → experiment-utils-CV2Wza3z.js} +1 -1
  105. package/dist/experiment-utils-CV2Wza3z.js.map +1 -0
  106. package/dist/index.d.ts +1 -0
  107. package/dist/index.js +15 -15
  108. package/dist/install.js +2 -7
  109. package/dist/install.js.map +1 -1
  110. package/dist/permissions.d.ts +42 -1
  111. package/dist/permissions.js +20 -10
  112. package/dist/permissions.js.map +1 -1
  113. package/dist/stores/index.d.ts +1 -1
  114. package/dist/stores/index.js +3 -3
  115. package/dist/stores/settings.d.ts +31 -1
  116. package/dist/styles.css +15162 -32475
  117. package/dist/templates/index.js +2 -4
  118. package/dist/{templates-CK72aKO1.js → templates-CmGfmBRA.js} +291 -85
  119. package/dist/templates-CmGfmBRA.js.map +1 -0
  120. package/dist/types/fileBrowserTypes.d.ts +77 -0
  121. package/dist/types/filePicker.d.ts +77 -0
  122. package/dist/types/index.d.ts +2 -0
  123. package/dist/{useControlSchema-_OVhavKq.js → useControlSchema-DldpxNOP.js} +234 -1121
  124. package/dist/useControlSchema-DldpxNOP.js.map +1 -0
  125. package/dist/{useDropdownState-D5G4UvWd.js → useDropdownState-C7hRiVQf.js} +22 -6
  126. package/dist/useDropdownState-C7hRiVQf.js.map +1 -0
  127. package/dist/{useExperimentSelector-DSEckf_g.js → useExperimentSelector-CEcIaueJ.js} +4 -4
  128. package/dist/{useExperimentSelector-DSEckf_g.js.map → useExperimentSelector-CEcIaueJ.js.map} +1 -1
  129. package/dist/{useFormBuilder-Bd714C7y.js → useFormBuilder-z5L_dUIy.js} +2 -2
  130. package/dist/{useFormBuilder-Bd714C7y.js.map → useFormBuilder-z5L_dUIy.js.map} +1 -1
  131. package/dist/utils/color.d.ts +13 -0
  132. package/dist/utils/errors.d.ts +9 -0
  133. package/dist/{useProtocolTemplates-Dq5Pzwyd.js → validation-uwoJGEb6.js} +231 -158
  134. package/dist/validation-uwoJGEb6.js.map +1 -0
  135. package/package.json +1 -1
  136. package/src/__tests__/apiErrors.test.ts +81 -0
  137. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  138. package/src/__tests__/components/DataFrame.test.ts +183 -11
  139. package/src/__tests__/components/DataStates.test.ts +176 -0
  140. package/src/__tests__/components/DatePicker.test.ts +76 -0
  141. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  142. package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
  143. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  144. package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
  145. package/src/__tests__/components/FilePicker.state.test.ts +287 -0
  146. package/src/__tests__/components/FilePicker.test.ts +487 -0
  147. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
  148. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  149. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  150. package/src/__tests__/components/PlotlyChart.test.ts +305 -0
  151. package/src/__tests__/components/RackEditor.test.ts +35 -0
  152. package/src/__tests__/components/ReagentList.test.ts +64 -2
  153. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  154. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  155. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  156. package/src/__tests__/components/SegmentedControl.test.ts +107 -0
  157. package/src/__tests__/components/TimePicker.test.ts +61 -0
  158. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  159. package/src/__tests__/components/iconButtonIconSizing.test.ts +18 -0
  160. package/src/__tests__/composables/useApi.test.ts +92 -9
  161. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  162. package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
  163. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
  164. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  165. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
  166. package/src/__tests__/composables/usePluginClient.test.ts +3 -0
  167. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  168. package/src/__tests__/stores/settings.test.ts +71 -1
  169. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  170. package/src/__tests__/utils/permissions.test.ts +68 -0
  171. package/src/apiErrors.ts +85 -0
  172. package/src/components/ActionMenu.vue +45 -88
  173. package/src/components/AlertBox.vue +0 -4
  174. package/src/components/AppAvatarMenu.vue +2 -14
  175. package/src/components/AppLayout.vue +0 -4
  176. package/src/components/AppPluginSwitcher.story.vue +87 -0
  177. package/src/components/AppPluginSwitcher.vue +2 -5
  178. package/src/components/AppSidebar.vue +0 -4
  179. package/src/components/AppToastContainer.vue +6 -8
  180. package/src/components/AppTopBar.vue +0 -4
  181. package/src/components/ArtifactSaveDialog.vue +0 -4
  182. package/src/components/ArtifactSelectorModal.vue +0 -4
  183. package/src/components/AuditTrail.story.vue +18 -0
  184. package/src/components/AuditTrail.vue +27 -7
  185. package/src/components/AutoGroupModal.vue +0 -4
  186. package/src/components/Avatar.vue +0 -4
  187. package/src/components/BaseButton.vue +0 -4
  188. package/src/components/BaseCheckbox.vue +0 -4
  189. package/src/components/BaseInput.vue +0 -4
  190. package/src/components/BaseModal.vue +0 -4
  191. package/src/components/BasePill.vue +0 -4
  192. package/src/components/BaseRadioGroup.vue +0 -4
  193. package/src/components/BaseSelect.vue +0 -4
  194. package/src/components/BaseSlider.vue +0 -4
  195. package/src/components/BaseTabs.vue +0 -4
  196. package/src/components/BaseTextarea.vue +0 -4
  197. package/src/components/BaseToggle.vue +0 -4
  198. package/src/components/BatchProgressList.story.vue +18 -0
  199. package/src/components/BatchProgressList.vue +32 -4
  200. package/src/components/Breadcrumb.vue +0 -4
  201. package/src/components/Calendar.vue +0 -4
  202. package/src/components/ChartContainer.story.vue +1 -1
  203. package/src/components/ChartContainer.vue +0 -4
  204. package/src/components/ChemicalFormula.vue +0 -4
  205. package/src/components/CollapsibleCard.vue +0 -4
  206. package/src/components/ColorSlider.vue +0 -4
  207. package/src/components/ConcentrationInput.vue +0 -4
  208. package/src/components/ConfirmDialog.vue +0 -4
  209. package/src/components/DataFrame.story.vue +14 -0
  210. package/src/components/DataFrame.vue +97 -23
  211. package/src/components/DatePicker.vue +73 -27
  212. package/src/components/DateTimePicker.vue +45 -17
  213. package/src/components/Divider.vue +0 -4
  214. package/src/components/DoseCalculator.vue +0 -4
  215. package/src/components/DropdownButton.vue +2 -14
  216. package/src/components/EmptyState.vue +0 -4
  217. package/src/components/ExperimentCodeBadge.vue +0 -4
  218. package/src/components/ExperimentDataViewer.story.vue +3 -0
  219. package/src/components/ExperimentDataViewer.vue +33 -13
  220. package/src/components/ExperimentPopover.vue +12 -7
  221. package/src/components/ExperimentSelectorModal.vue +0 -4
  222. package/src/components/ExperimentTimeline.story.vue +18 -0
  223. package/src/components/ExperimentTimeline.vue +81 -75
  224. package/src/components/FileBrowserModal.story.vue +203 -0
  225. package/src/components/FileBrowserModal.vue +384 -0
  226. package/src/components/FilePicker.story.vue +44 -0
  227. package/src/components/FilePicker.vue +284 -0
  228. package/src/components/FileUploader.vue +32 -18
  229. package/src/components/FitPanel.vue +0 -4
  230. package/src/components/FormActions.story.vue +96 -0
  231. package/src/components/FormActions.vue +0 -4
  232. package/src/components/FormBuilder.vue +0 -4
  233. package/src/components/FormField.vue +0 -4
  234. package/src/components/FormulaInput.vue +0 -4
  235. package/src/components/GeneratedPathInput.story.vue +68 -0
  236. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  237. package/src/components/GeneratedPlotlyResult.vue +34 -69
  238. package/src/components/GeneratedPluginView.story.vue +145 -0
  239. package/src/components/GeneratedPluginView.vue +10 -10
  240. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  241. package/src/components/GeneratedResultRenderer.vue +4 -9
  242. package/src/components/GroupAssigner.vue +67 -5
  243. package/src/components/IconButton.vue +0 -4
  244. package/src/components/InstrumentAlertLog.vue +0 -4
  245. package/src/components/InstrumentStateBadge.vue +0 -4
  246. package/src/components/InstrumentStatusCard.vue +0 -4
  247. package/src/components/JobsStatusTray.vue +0 -4
  248. package/src/components/LcmsSequenceTable.vue +81 -50
  249. package/src/components/LoadingSpinner.vue +0 -4
  250. package/src/components/MobileSupportGate.vue +0 -4
  251. package/src/components/MoleculeInput.vue +0 -4
  252. package/src/components/MultiSelect.vue +0 -4
  253. package/src/components/NumberInput.vue +0 -4
  254. package/src/components/PlateMapEditor.vue +3 -14
  255. package/src/components/PlotlyChart.story.vue +61 -0
  256. package/src/components/PlotlyChart.vue +233 -0
  257. package/src/components/PluginIcon.vue +0 -4
  258. package/src/components/ProgressBar.vue +0 -4
  259. package/src/components/ProtocolStepEditor.vue +2 -4
  260. package/src/components/RackEditor.vue +51 -70
  261. package/src/components/ReagentEditor.vue +0 -4
  262. package/src/components/ReagentList.story.vue +18 -0
  263. package/src/components/ReagentList.vue +127 -82
  264. package/src/components/ResourceCard.vue +0 -4
  265. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  266. package/src/components/RuntimeUpdateNotice.vue +4 -4
  267. package/src/components/SampleHierarchyTree.story.vue +18 -0
  268. package/src/components/SampleHierarchyTree.vue +32 -9
  269. package/src/components/SampleLegend.vue +2 -8
  270. package/src/components/SampleSelector.drag.ts +51 -0
  271. package/src/components/SampleSelector.story.vue +6 -0
  272. package/src/components/SampleSelector.tree.ts +2 -0
  273. package/src/components/SampleSelector.vue +49 -10
  274. package/src/components/SampleSelectorGroupNode.vue +19 -0
  275. package/src/components/ScheduleCalendar.story.vue +6 -0
  276. package/src/components/ScheduleCalendar.vue +82 -7
  277. package/src/components/ScientificNumber.vue +0 -4
  278. package/src/components/SectionCard.vue +0 -4
  279. package/src/components/SegmentedControl.vue +50 -7
  280. package/src/components/SequenceInput.vue +0 -4
  281. package/src/components/SequenceProgressBar.story.vue +110 -0
  282. package/src/components/SequenceProgressBar.vue +0 -4
  283. package/src/components/SettingsModal.vue +0 -4
  284. package/src/components/Skeleton.vue +0 -4
  285. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  286. package/src/components/SmartGroupManual.vue +0 -4
  287. package/src/components/StatusIndicator.vue +0 -4
  288. package/src/components/StepWizard.vue +0 -4
  289. package/src/components/TagsInput.vue +4 -6
  290. package/src/components/ThemeToggle.vue +0 -4
  291. package/src/components/TimePicker.vue +36 -7
  292. package/src/components/TimeRangeInput.vue +0 -4
  293. package/src/components/Tooltip.story.vue +3 -3
  294. package/src/components/Tooltip.vue +0 -4
  295. package/src/components/UnitInput.vue +0 -4
  296. package/src/components/WellPlate.geometry.ts +60 -1
  297. package/src/components/WellPlate.interaction.ts +44 -0
  298. package/src/components/WellPlate.story.vue +8 -0
  299. package/src/components/WellPlate.vue +53 -7
  300. package/src/components/fileBrowserPresentation.ts +39 -0
  301. package/src/components/index.ts +5 -0
  302. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  303. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  304. package/src/components/internal/DataStateInternal.vue +74 -0
  305. package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
  306. package/src/components/internal/FileBrowserListingInternal.vue +197 -0
  307. package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
  308. package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
  309. package/src/components/internal/FilePickerTreeInternal.vue +238 -0
  310. package/src/components/internal/FormSectionRenderer.vue +0 -4
  311. package/src/components/internal/WellEditPopupInternal.vue +0 -4
  312. package/src/composables/controlSchemaTypes.ts +34 -0
  313. package/src/composables/filePicker/localFiles.ts +58 -0
  314. package/src/composables/filePicker/usePickerNavigation.ts +220 -0
  315. package/src/composables/filePicker/usePickerSelection.ts +259 -0
  316. package/src/composables/filePicker/validation.ts +41 -0
  317. package/src/composables/index.ts +17 -0
  318. package/src/composables/useApi.ts +57 -13
  319. package/src/composables/useDropdownState.ts +35 -5
  320. package/src/composables/useEventStream.ts +14 -2
  321. package/src/composables/useFileBrowser.ts +314 -0
  322. package/src/composables/useFileImport.ts +2 -7
  323. package/src/composables/useFilePicker.ts +366 -0
  324. package/src/composables/useGeneratedAnalysis.ts +18 -26
  325. package/src/composables/useListReorder.story.vue +143 -0
  326. package/src/composables/useListReorder.ts +242 -0
  327. package/src/composables/useMenuKeyboard.ts +2 -2
  328. package/src/composables/useOptimisticMutation.ts +1 -15
  329. package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
  330. package/src/composables/usePluginClient.ts +3 -0
  331. package/src/composables/usePluginConfig.ts +3 -1
  332. package/src/composables/useRackEditor.ts +2 -11
  333. package/src/composables/useRequestSyncState.ts +98 -28
  334. package/src/composables/useResourceCrud.ts +1 -15
  335. package/src/composables/useScheduleDrag.ts +37 -0
  336. package/src/composables/useWellPainting.ts +5 -29
  337. package/src/composables/useWellPlateEditor.ts +1 -11
  338. package/src/index.ts +3 -0
  339. package/src/permissions.ts +48 -9
  340. package/src/stores/experiment.ts +2 -7
  341. package/src/stores/index.ts +9 -1
  342. package/src/stores/settings.ts +93 -1
  343. package/src/styles/components/audit-trail.css +5 -5
  344. package/src/styles/components/batch-progress-list.css +7 -0
  345. package/src/styles/components/color-slider.css +2 -2
  346. package/src/styles/components/data-state.css +30 -0
  347. package/src/styles/components/dataframe.css +29 -35
  348. package/src/styles/components/experiment-data-viewer.css +4 -4
  349. package/src/styles/components/experiment-timeline.css +3 -30
  350. package/src/styles/components/file-browser-modal.css +489 -0
  351. package/src/styles/components/file-picker.css +502 -0
  352. package/src/styles/components/form-builder.css +5 -5
  353. package/src/styles/components/icon-button.css +9 -0
  354. package/src/styles/components/lcms-sequence-table.css +16 -1
  355. package/src/styles/components/multi-select.css +1 -1
  356. package/src/styles/components/reagent-list.css +38 -31
  357. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  358. package/src/styles/components/sample-selector.css +9 -2
  359. package/src/styles/components/schedule-calendar.css +8 -0
  360. package/src/styles/components/scientific-number.css +1 -1
  361. package/src/styles/components/well-plate.css +8 -0
  362. package/src/styles/index.css +11 -0
  363. package/src/styles/variables.css +29 -0
  364. package/src/templates/builderPresetControls.ts +1 -1
  365. package/src/templates/componentPlateHelpers.ts +3 -1
  366. package/src/templates/doseResponseAdapters.ts +2 -13
  367. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  368. package/src/templates/plateMapBuilder.ts +2 -2
  369. package/src/templates/qpcrPlateBuilder.ts +1 -1
  370. package/src/templates/templateValidators.ts +1 -1
  371. package/src/templates/timeCourseBuilder.ts +2 -2
  372. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  373. package/src/types/fileBrowserTypes.ts +85 -0
  374. package/src/types/filePicker.ts +72 -0
  375. package/src/types/index.ts +14 -0
  376. package/src/utils/color.ts +51 -0
  377. package/src/utils/errors.ts +29 -0
  378. package/dist/EmptyState-NBqf2_8z.js.map +0 -1
  379. package/dist/ExperimentPopover-CfOdh5Rm.js.map +0 -1
  380. package/dist/ExperimentSelectorModal-DvIagrxY.js.map +0 -1
  381. package/dist/SettingsModal-W3TYfnP9.js.map +0 -1
  382. package/dist/components-B80gV0P6.js.map +0 -1
  383. package/dist/composables/autoGroupConstants.d.ts +0 -1
  384. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  385. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  386. package/dist/composables-C8mmD5ta.js.map +0 -1
  387. package/dist/experiment-Y9Iz7KYi.js.map +0 -1
  388. package/dist/experiment-utils-DV3DrvE_.js.map +0 -1
  389. package/dist/templates/builderDefaults.d.ts +0 -1
  390. package/dist/templates/plateGeometry.d.ts +0 -4
  391. package/dist/templates-CK72aKO1.js.map +0 -1
  392. package/dist/useApi-CDBq6z23.js.map +0 -1
  393. package/dist/useControlSchema-_OVhavKq.js.map +0 -1
  394. package/dist/useDropdownState-D5G4UvWd.js.map +0 -1
  395. package/dist/useProtocolTemplates-Dq5Pzwyd.js.map +0 -1
  396. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  397. package/src/composables/autoGroupConstants.ts +0 -4
  398. package/src/composables/autoGroupGrouping.ts +0 -148
  399. package/src/composables/useAutoGroupInputSources.ts +0 -147
  400. package/src/templates/builderDefaults.ts +0 -11
  401. package/src/templates/plateGeometry.ts +0 -62
  402. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → apiErrors.test.d.ts} +0 -0
@@ -1,127 +0,0 @@
1
- import { computed, ref } from 'vue'
2
- import { describe, expect, it } from 'vitest'
3
- import { useAutoGroup } from '../../composables/useAutoGroup'
4
- import { useAutoGroupInputSources } from '../../composables/useAutoGroupInputSources'
5
- import type { WizardStep } from '../../types/components'
6
-
7
- function makeSources(options: {
8
- samples?: string[]
9
- experimentId?: number
10
- designData?: Record<string, unknown>
11
- apiGet?: (url: string) => Promise<Record<string, unknown>>
12
- } = {}) {
13
- const autoGroup = useAutoGroup()
14
- const currentStep = ref(0)
15
- const dynamicSteps = ref<WizardStep[]>([
16
- { id: 'input', label: 'Input' },
17
- { id: 'fields', label: 'Fields' },
18
- { id: 'preview', label: 'Preview' },
19
- ])
20
- const sources = useAutoGroupInputSources({
21
- autoGroup,
22
- samples: computed(() => options.samples ?? []),
23
- experimentId: computed(() => options.experimentId),
24
- designData: computed(() => options.designData),
25
- currentStep,
26
- dynamicSteps,
27
- api: {
28
- get: async <T>(url: string): Promise<T> => {
29
- const value = options.apiGet
30
- ? await options.apiGet(url)
31
- : { data: undefined }
32
- return value as T
33
- },
34
- },
35
- })
36
-
37
- return { autoGroup, currentStep, dynamicSteps, sources }
38
- }
39
-
40
- describe('useAutoGroupInputSources', () => {
41
- it('initializes pasted sample input when samples are provided', async () => {
42
- const { autoGroup, currentStep, sources } = makeSources({
43
- samples: ['S1_Control', 'S2_Treated'],
44
- })
45
- currentStep.value = 2
46
-
47
- await sources.initializeInputSources()
48
-
49
- expect(currentStep.value).toBe(0)
50
- expect(autoGroup.rawText.value).toBe('S1_Control\nS2_Treated')
51
- expect(sources.csvFileName.value).toBe('')
52
- expect(sources.experimentError.value).toBeNull()
53
- })
54
-
55
- it('loads experiment design data and advances to the fields step', async () => {
56
- const { autoGroup, currentStep, sources } = makeSources({
57
- designData: {
58
- samples: [
59
- { sample_name: 'S1', sample_type: 'sample', conditions: { Treatment: 'Control' } },
60
- { sample_name: 'S2', sample_type: 'sample', conditions: { Treatment: 'Drug' } },
61
- ],
62
- },
63
- })
64
-
65
- await sources.initializeInputSources()
66
-
67
- expect(autoGroup.inputMode.value).toBe('experiment')
68
- expect(autoGroup.csvData.value?.rows).toHaveLength(2)
69
- expect(sources.experimentFieldNames.value).toEqual(['Treatment', 'sample_type'])
70
- expect(currentStep.value).toBe(1)
71
- expect(sources.experimentLoading.value).toBe(false)
72
- })
73
-
74
- it('filters loaded experiment metadata to the provided sample subset', async () => {
75
- const { autoGroup, sources } = makeSources({
76
- samples: ['S2', 'MissingFromDesign'],
77
- designData: {
78
- samples: [
79
- { sample_name: 'S1', sample_type: 'sample', conditions: { Tissue: 'Kidney', Treatment: 'Control' } },
80
- { sample_name: 'S2', sample_type: 'sample', conditions: { Tissue: 'Liver', Treatment: 'Drug' } },
81
- ],
82
- },
83
- })
84
-
85
- await sources.initializeInputSources()
86
-
87
- expect(autoGroup.samples.value).toEqual(['S2', 'MissingFromDesign'])
88
- expect(autoGroup.groups.value.map(g => g.name).sort()).toEqual([
89
- 'Liver / Drug',
90
- 'Outlier',
91
- ])
92
- })
93
-
94
- it('parses uploaded CSV files and can clear them back to paste mode', async () => {
95
- const { autoGroup, sources } = makeSources()
96
- const file = {
97
- name: 'samples.csv',
98
- text: async () => 'sample_name,Treatment\nS1,Control\nS2,Drug',
99
- } as File
100
-
101
- await sources.processFile(file)
102
-
103
- expect(autoGroup.inputMode.value).toBe('csv')
104
- expect(autoGroup.csvData.value?.rows).toHaveLength(2)
105
- expect(sources.csvFileName.value).toBe('samples.csv')
106
-
107
- sources.clearCsvFile()
108
-
109
- expect(autoGroup.inputMode.value).toBe('paste')
110
- expect(autoGroup.csvData.value).toBeNull()
111
- expect(sources.csvFileName.value).toBe('')
112
- })
113
-
114
- it('surfaces API errors when experiment metadata cannot be fetched', async () => {
115
- const { sources } = makeSources({
116
- experimentId: 42,
117
- apiGet: async () => {
118
- throw new Error('offline')
119
- },
120
- })
121
-
122
- await sources.initializeInputSources()
123
-
124
- expect(sources.experimentLoading.value).toBe(false)
125
- expect(sources.experimentError.value).toBe('offline')
126
- })
127
- })
@@ -1,4 +0,0 @@
1
- export const DEFAULT_COLORS = [
2
- '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',
3
- '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',
4
- ]
@@ -1,148 +0,0 @@
1
- import type {
2
- AutoGroupResult,
3
- ColumnInfo,
4
- MetadataRow,
5
- OutlierAction,
6
- ParsedCsvData,
7
- } from '../types/auto-group'
8
- import type { SampleGroup } from '../types/components'
9
- import { DEFAULT_COLORS } from './autoGroupConstants'
10
-
11
- export function computeGroups(
12
- allSamples: string[],
13
- columns: ColumnInfo[],
14
- enabledFields: Set<number>,
15
- outlierActions: Map<number, OutlierAction>,
16
- delimiter: string,
17
- minFieldCount: number,
18
- ): AutoGroupResult {
19
- const excludedSamples: string[] = []
20
- const qcSamples: string[] = []
21
- const conformingSamples: string[] = []
22
-
23
- for (let i = 0; i < allSamples.length; i++) {
24
- const action = outlierActions.get(i)
25
- if (action === 'exclude') {
26
- excludedSamples.push(allSamples[i])
27
- } else if (action === 'qc') {
28
- qcSamples.push(allSamples[i])
29
- } else {
30
- conformingSamples.push(allSamples[i])
31
- }
32
- }
33
-
34
- // Build group map
35
- const groupMap = new Map<string, string[]>()
36
- const metadata: MetadataRow[] = []
37
- const enabledIndices = [...enabledFields].sort((a, b) => a - b)
38
- const suffixCount = minFieldCount - 1
39
-
40
- for (const sample of conformingSamples) {
41
- const parts = sample.split(delimiter)
42
- const splitAt = Math.max(1, parts.length - suffixCount)
43
- const row = [
44
- parts.slice(0, splitAt).join(delimiter),
45
- ...parts.slice(splitAt),
46
- ]
47
-
48
- // Build group key from enabled columns
49
- const keyParts: string[] = []
50
- for (const idx of enabledIndices) {
51
- if (idx < row.length && idx < columns.length) {
52
- keyParts.push(row[idx])
53
- }
54
- }
55
- const groupKey = keyParts.join(' / ')
56
-
57
- const group = groupMap.get(groupKey)
58
- if (group) {
59
- group.push(sample)
60
- } else {
61
- groupMap.set(groupKey, [sample])
62
- }
63
-
64
- // Build metadata row with ALL columns
65
- const fields: Record<string, string> = {}
66
- for (const col of columns) {
67
- if (col.index < row.length) {
68
- fields[col.name] = row[col.index]
69
- }
70
- }
71
- metadata.push({ sampleName: sample, fields, group: groupKey })
72
- }
73
-
74
- // Convert to SampleGroup[]
75
- const groups: SampleGroup[] = []
76
- let colorIdx = 0
77
- for (const [name, samples] of groupMap) {
78
- groups.push({
79
- name,
80
- color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],
81
- samples,
82
- })
83
- colorIdx++
84
- }
85
-
86
- // QC group
87
- if (qcSamples.length > 0) {
88
- groups.push({
89
- name: 'QC',
90
- color: '#6B7280',
91
- samples: qcSamples,
92
- })
93
- for (const sample of qcSamples) {
94
- metadata.push({ sampleName: sample, fields: {}, group: 'QC' })
95
- }
96
- }
97
-
98
- return { groups, metadata, excludedSamples }
99
- }
100
-
101
- export function computeGroupsFromCsv(
102
- csvData: ParsedCsvData,
103
- columns: ColumnInfo[],
104
- enabledFields: Set<number>,
105
- ): AutoGroupResult {
106
- const groupMap = new Map<string, string[]>()
107
- const metadata: MetadataRow[] = []
108
- const enabledCols = columns
109
- .filter(c => enabledFields.has(c.index))
110
- .sort((a, b) => a.index - b.index)
111
-
112
- for (const row of csvData.rows) {
113
- const sampleName = row[csvData.sampleColumn]
114
-
115
- // Build group key from enabled CSV column values
116
- // Use originalName for CSV row lookup (survives user renames), display name for group key
117
- const keyParts = enabledCols.map(col => row[col.originalName ?? col.name])
118
- const groupKey = keyParts.join(' / ')
119
-
120
- const group = groupMap.get(groupKey)
121
- if (group) {
122
- group.push(sampleName)
123
- } else {
124
- groupMap.set(groupKey, [sampleName])
125
- }
126
-
127
- // Build metadata row with ALL columns - use display name as key, original for lookup
128
- const fields: Record<string, string> = {}
129
- for (const col of columns) {
130
- fields[col.name] = row[col.originalName ?? col.name]
131
- }
132
- metadata.push({ sampleName, fields, group: groupKey })
133
- }
134
-
135
- // Convert to SampleGroup[]
136
- const groups: SampleGroup[] = []
137
- let colorIdx = 0
138
- for (const [name, samples] of groupMap) {
139
- groups.push({
140
- name,
141
- color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],
142
- samples,
143
- })
144
- colorIdx++
145
- }
146
-
147
- return { groups, metadata, excludedSamples: [] }
148
- }
@@ -1,147 +0,0 @@
1
- import { computed, nextTick, ref, type Ref } from 'vue'
2
- import { parseCSV, type useAutoGroup } from './useAutoGroup'
3
- import { useApi, type UseApiReturn } from './useApi'
4
- import type { WizardStep } from '../types/components'
5
-
6
- type AutoGroupController = ReturnType<typeof useAutoGroup>
7
- type ReadableRef<T> = Readonly<Ref<T>>
8
- type AutoGroupApi = Pick<UseApiReturn, 'get'>
9
-
10
- export interface UseAutoGroupInputSourcesOptions {
11
- autoGroup: AutoGroupController
12
- samples: ReadableRef<readonly string[]>
13
- experimentId: ReadableRef<number | undefined>
14
- designData: ReadableRef<Record<string, unknown> | undefined>
15
- currentStep: Ref<number>
16
- dynamicSteps: ReadableRef<readonly WizardStep[]>
17
- api?: AutoGroupApi
18
- }
19
-
20
- /** Manages AutoGroupModal input sources: pasted samples, CSV/TSV files, and experiment metadata. */
21
- export function useAutoGroupInputSources(options: UseAutoGroupInputSourcesOptions) {
22
- const api = options.api ?? useApi()
23
- const isDragOver = ref(false)
24
- const csvFileName = ref('')
25
- const experimentLoading = ref(false)
26
- const experimentError = ref<string | null>(null)
27
- const csvError = ref<string | null>(null)
28
-
29
- const experimentFieldNames = computed(() =>
30
- options.autoGroup.csvData.value?.columns.filter(c => c !== 'sample_name') ?? [],
31
- )
32
-
33
- async function initializeInputSources() {
34
- options.autoGroup.reset()
35
- options.currentStep.value = 0
36
- resetInputSourceState()
37
-
38
- if (options.experimentId.value || options.designData.value) {
39
- await fetchExperimentData()
40
- } else if (options.samples.value.length > 0) {
41
- options.autoGroup.rawText.value = options.samples.value.join('\n')
42
- }
43
- }
44
-
45
- function resetInputSourceState() {
46
- csvFileName.value = ''
47
- experimentError.value = null
48
- csvError.value = null
49
- isDragOver.value = false
50
- }
51
-
52
- async function fetchExperimentData() {
53
- if (!options.experimentId.value && !options.designData.value) return
54
-
55
- options.autoGroup.inputMode.value = 'experiment'
56
- experimentLoading.value = true
57
- experimentError.value = null
58
-
59
- try {
60
- const pluginData = await loadExperimentPluginData()
61
-
62
- if (!pluginData || typeof pluginData !== 'object') {
63
- experimentError.value = 'No design data found for this experiment'
64
- return
65
- }
66
-
67
- const success = options.autoGroup.loadExperimentData(pluginData, { samples: options.samples.value })
68
- if (!success) {
69
- experimentError.value = 'No sample metadata found in this experiment'
70
- return
71
- }
72
-
73
- await nextTick()
74
- const fieldsIdx = options.dynamicSteps.value.findIndex(s => s.id === 'fields')
75
- if (fieldsIdx >= 0) {
76
- options.currentStep.value = fieldsIdx
77
- }
78
- } catch (e) {
79
- experimentError.value = e instanceof Error ? e.message : 'Failed to fetch experiment data'
80
- } finally {
81
- experimentLoading.value = false
82
- }
83
- }
84
-
85
- async function loadExperimentPluginData(): Promise<Record<string, unknown> | undefined> {
86
- if (options.designData.value) {
87
- return options.designData.value
88
- }
89
-
90
- const result = await api.get<Record<string, unknown>>(
91
- `/experiments/${options.experimentId.value}/data`,
92
- )
93
- return result.data as Record<string, unknown> | undefined
94
- }
95
-
96
- function handleFileDrop(event: DragEvent) {
97
- event.preventDefault()
98
- isDragOver.value = false
99
- const files = event.dataTransfer?.files
100
- if (files && files.length > 0) {
101
- void processFile(files[0])
102
- }
103
- }
104
-
105
- function handleFileInput(event: Event) {
106
- const target = event.target as HTMLInputElement
107
- if (target.files && target.files.length > 0) {
108
- void processFile(target.files[0])
109
- }
110
- }
111
-
112
- async function processFile(file: File) {
113
- if (!file.name.endsWith('.csv') && !file.name.endsWith('.tsv')) return
114
-
115
- csvError.value = null
116
- try {
117
- const text = await file.text()
118
- const parsed = parseCSV(text)
119
- options.autoGroup.inputMode.value = 'csv'
120
- options.autoGroup.csvData.value = parsed
121
- csvFileName.value = file.name
122
- } catch (e) {
123
- csvError.value = e instanceof Error ? e.message : 'Failed to parse file'
124
- }
125
- }
126
-
127
- function clearCsvFile() {
128
- options.autoGroup.csvData.value = null
129
- options.autoGroup.inputMode.value = 'paste'
130
- csvFileName.value = ''
131
- }
132
-
133
- return {
134
- isDragOver,
135
- csvFileName,
136
- experimentLoading,
137
- experimentError,
138
- csvError,
139
- experimentFieldNames,
140
- initializeInputSources,
141
- fetchExperimentData,
142
- handleFileDrop,
143
- handleFileInput,
144
- processFile,
145
- clearCsvFile,
146
- }
147
- }
@@ -1,11 +0,0 @@
1
- export const DEFAULT_SAMPLE_COLORS = [
2
- '#3B82F6',
3
- '#10B981',
4
- '#EF4444',
5
- '#F59E0B',
6
- '#8B5CF6',
7
- '#F97316',
8
- '#06B6D4',
9
- '#14B8A6',
10
- '#6B7280',
11
- ]
@@ -1,62 +0,0 @@
1
- import type { WellPlateFormat } from '../types'
2
-
3
- const PLATE_DIMENSIONS: Record<number, readonly [number, number]> = {
4
- 6: [2, 3],
5
- 12: [3, 4],
6
- 24: [4, 6],
7
- 48: [6, 8],
8
- 54: [6, 9],
9
- 96: [8, 12],
10
- 384: [16, 24],
11
- }
12
-
13
- export function wellIdsForFormat(format: number): string[] {
14
- const dimensions = PLATE_DIMENSIONS[format]
15
- if (!dimensions) {
16
- throw new Error(`Unsupported plate format '${format}'.`)
17
- }
18
- const [rows, cols] = dimensions
19
- return Array.from({ length: rows }, (_, row) =>
20
- Array.from({ length: cols }, (_col, col) => `${rowLabel(row)}${col + 1}`)
21
- ).flat()
22
- }
23
-
24
- export function assertWellInFormat(wellId: string, format: number): void {
25
- const dimensions = PLATE_DIMENSIONS[format]
26
- if (!dimensions) {
27
- throw new Error(`Unsupported plate format '${format}'.`)
28
- }
29
- const match = /^([A-Z]+)([1-9][0-9]*)$/.exec(wellId.toUpperCase())
30
- if (!match) {
31
- throw new Error(`Invalid well id '${wellId}'.`)
32
- }
33
- const row = rowIndex(match[1])
34
- const col = Number(match[2]) - 1
35
- const [rows, cols] = dimensions
36
- if (row < 0 || col < 0 || row >= rows || col >= cols) {
37
- throw new Error(`Well '${wellId}' is outside a ${format}-well plate.`)
38
- }
39
- }
40
-
41
- export function readPlateFormat(value: unknown, fallback: WellPlateFormat): WellPlateFormat {
42
- const parsed = typeof value === 'number'
43
- ? value
44
- : typeof value === 'string'
45
- ? Number(value)
46
- : Number.NaN
47
- return parsed in PLATE_DIMENSIONS ? (parsed as WellPlateFormat) : fallback
48
- }
49
-
50
- function rowLabel(index: number): string {
51
- let label = ''
52
- let current = index
53
- while (true) {
54
- label = String.fromCharCode(65 + (current % 26)) + label
55
- current = Math.floor(current / 26) - 1
56
- if (current < 0) return label
57
- }
58
- }
59
-
60
- function rowIndex(label: string): number {
61
- return [...label].reduce((value, char) => value * 26 + char.charCodeAt(0) - 64, 0) - 1
62
- }