@morscherlab/mint-sdk 1.2.10 → 1.3.0-beta.10

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 (841) hide show
  1. package/README.md +45 -137
  2. package/dist/ResourcePickerListInternal-CFAw4vTZ.js +605 -0
  3. package/dist/ResourcePickerListInternal-CFAw4vTZ.js.map +1 -0
  4. package/dist/__stories__/experiment-helpers.d.ts +12 -1
  5. package/dist/__tests__/components/ScientificNumber.test.d.ts +1 -0
  6. package/dist/__tests__/components/SequenceInput.test.d.ts +1 -0
  7. package/dist/__tests__/components/Skeleton.test.d.ts +1 -0
  8. package/dist/__tests__/components/SmartGroupFieldRecipe.test.d.ts +1 -0
  9. package/dist/__tests__/components/SmartGroupModal.test.d.ts +1 -0
  10. package/dist/__tests__/components/StepWizard.test.d.ts +1 -0
  11. package/dist/__tests__/components/TimeRangeInput.test.d.ts +1 -0
  12. package/dist/__tests__/components/UnitInput.test.d.ts +1 -0
  13. package/dist/__tests__/components/WellPlate.keyboard.test.d.ts +1 -0
  14. package/dist/__tests__/components/WellPlate.sampleTypeIndicator.test.d.ts +1 -0
  15. package/dist/__tests__/composables/useChemicalFormula.test.d.ts +1 -0
  16. package/dist/__tests__/composables/useRackEditor.test.d.ts +1 -0
  17. package/dist/__tests__/composables/useSequenceUtils.test.d.ts +1 -0
  18. package/dist/__tests__/styles/baseControlsRules.test.d.ts +1 -0
  19. package/dist/__tests__/styles/controlRefreshRules.test.d.ts +1 -0
  20. package/dist/__tests__/styles/darkModeRules.test.d.ts +1 -0
  21. package/dist/__tests__/styles/menusShellRefresh.test.d.ts +1 -0
  22. package/dist/__tests__/templates/templatesDeprecation.test.d.ts +1 -0
  23. package/dist/__tests__/utils/plotlyTemplate.test.d.ts +1 -0
  24. package/dist/__tests__/utils/sampleTypeMarker.test.d.ts +1 -0
  25. package/dist/{analysisArtifactTypes-DQ0MjwHZ.js → analysisArtifactTypes-Cy3D0Ipg.js} +1 -1
  26. package/dist/{analysisArtifactTypes-DQ0MjwHZ.js.map → analysisArtifactTypes-Cy3D0Ipg.js.map} +1 -1
  27. package/dist/components/ActionMenu.vue.d.ts +17 -5
  28. package/dist/components/AdductText.vue.d.ts +3 -2
  29. package/dist/components/AlertBox.vue.d.ts +11 -14
  30. package/dist/components/AppAvatarMenu.vue.d.ts +18 -28
  31. package/dist/components/AppContainer.vue.d.ts +7 -11
  32. package/dist/components/AppLayout.vue.d.ts +11 -13
  33. package/dist/components/AppSidebar.vue.d.ts +30 -28
  34. package/dist/components/AppToastContainer.vue.d.ts +2 -1
  35. package/dist/components/AppTopBar.vue.d.ts +45 -44
  36. package/dist/components/ArtifactSaveDialog.vue.d.ts +3 -2
  37. package/dist/components/ArtifactSelectorModal.vue.d.ts +5 -6
  38. package/dist/components/AuditTrail.vue.d.ts +17 -18
  39. package/dist/components/AutoGroupModal.vue.d.ts +4 -3
  40. package/dist/components/Avatar.vue.d.ts +2 -1
  41. package/dist/components/BaseButton.vue.d.ts +11 -13
  42. package/dist/components/BaseCheckbox.vue.d.ts +7 -1
  43. package/dist/components/BaseInput.vue.d.ts +15 -2
  44. package/dist/components/BaseModal.vue.d.ts +20 -23
  45. package/dist/components/BasePill.vue.d.ts +10 -13
  46. package/dist/components/BaseRadioGroup.vue.d.ts +2 -1
  47. package/dist/components/BaseSelect.vue.d.ts +3 -2
  48. package/dist/components/BaseSlider.vue.d.ts +18 -1
  49. package/dist/components/BaseTabs.vue.d.ts +2 -1
  50. package/dist/components/BaseTextarea.vue.d.ts +2 -1
  51. package/dist/components/BaseToggle.vue.d.ts +2 -1
  52. package/dist/components/BatchProgressList.vue.d.ts +22 -26
  53. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +7 -14
  54. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +6 -13
  55. package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +7 -14
  56. package/dist/components/BioTemplateRenderer.vue.d.ts +2 -1
  57. package/dist/components/Breadcrumb.vue.d.ts +13 -16
  58. package/dist/components/Calendar.vue.d.ts +21 -23
  59. package/dist/components/ChartContainer.vue.d.ts +19 -25
  60. package/dist/components/ChemicalFormula.vue.d.ts +7 -11
  61. package/dist/components/CollapsibleCard.vue.d.ts +7 -11
  62. package/dist/components/ComponentBindingRenderer.vue.d.ts +2 -1
  63. package/dist/components/ConcentrationInput.vue.d.ts +2 -1
  64. package/dist/components/ConfirmDialog.vue.d.ts +10 -13
  65. package/dist/components/ControlWorkspaceView.vue.d.ts +9 -18
  66. package/dist/components/DataFrame.vue.d.ts +27 -24
  67. package/dist/components/DatePicker.vue.d.ts +3 -6
  68. package/dist/components/DateTimePicker.vue.d.ts +3 -6
  69. package/dist/components/Divider.vue.d.ts +3 -2
  70. package/dist/components/DoseCalculator.vue.d.ts +2 -1
  71. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +2 -1
  72. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +9 -18
  73. package/dist/components/EmptyState.vue.d.ts +9 -12
  74. package/dist/components/ExperimentCodeBadge.vue.d.ts +2 -1
  75. package/dist/components/ExperimentDataViewer.vue.d.ts +13 -15
  76. package/dist/components/ExperimentPopover.vue.d.ts +3 -5
  77. package/dist/components/ExperimentSelectorModal.vue.d.ts +3 -4
  78. package/dist/components/ExperimentTimeline.vue.d.ts +13 -15
  79. package/dist/components/FilePicker.vue.d.ts +10 -5
  80. package/dist/components/FileUploader.vue.d.ts +8 -16
  81. package/dist/components/FitPanel.vue.d.ts +26 -16
  82. package/dist/components/FormActions.vue.d.ts +2 -1
  83. package/dist/components/FormBuilder.vue.d.ts +54 -250
  84. package/dist/components/FormField.vue.d.ts +14 -16
  85. package/dist/components/FormulaInput.vue.d.ts +2 -1
  86. package/dist/components/GeneratedPathInput.vue.d.ts +6 -5
  87. package/dist/components/GeneratedPlotlyResult.vue.d.ts +2 -1
  88. package/dist/components/GeneratedPluginView.vue.d.ts +2 -1
  89. package/dist/components/GeneratedResultRenderer.vue.d.ts +2 -1
  90. package/dist/components/GroupAssigner.vue.d.ts +2 -1
  91. package/dist/components/IconButton.vue.d.ts +7 -11
  92. package/dist/components/InstrumentStateBadge.vue.d.ts +4 -3
  93. package/dist/components/JobsStatusTray.vue.d.ts +13 -29
  94. package/dist/components/LayoutResizeHandle.vue.d.ts +2 -1
  95. package/dist/components/LoadingSpinner.vue.d.ts +2 -1
  96. package/dist/components/MobileSupportGate.vue.d.ts +5 -13
  97. package/dist/components/MoleculeInput.vue.d.ts +3 -4
  98. package/dist/components/MultiSelect.vue.d.ts +2 -1
  99. package/dist/components/NumberInput.vue.d.ts +2 -1
  100. package/dist/components/PlateEditor.vue.d.ts +147 -0
  101. package/dist/components/PlotlyChart.vue.d.ts +21 -31
  102. package/dist/components/PluginIcon.vue.d.ts +2 -1
  103. package/dist/components/PluginWorkspaceView.props.d.ts +2 -6
  104. package/dist/components/PluginWorkspaceView.vue.d.ts +23 -51
  105. package/dist/components/ProgressBar.vue.d.ts +4 -9
  106. package/dist/components/ProtocolStepEditor.vue.d.ts +7 -5
  107. package/dist/components/ProtocolStepParameterField.vue.d.ts +2 -1
  108. package/dist/components/ReagentEditor.vue.d.ts +2 -1
  109. package/dist/components/ReagentList.presentation.d.ts +2 -1
  110. package/dist/components/ReagentList.vue.d.ts +15 -17
  111. package/dist/components/ResourceCard.vue.d.ts +18 -17
  112. package/dist/components/RuntimeUpdateNotice.vue.d.ts +3 -2
  113. package/dist/components/SampleHierarchyTree.vue.d.ts +21 -15
  114. package/dist/components/SampleLegend.vue.d.ts +2 -1
  115. package/dist/components/SampleSelector.vue.d.ts +15 -21
  116. package/dist/components/SampleSelectorGroupNode.vue.d.ts +2 -1
  117. package/dist/components/SampleSelectorSampleRow.vue.d.ts +2 -5
  118. package/dist/components/ScheduleCalendar.vue.d.ts +34 -36
  119. package/dist/components/ScientificNumber.vue.d.ts +3 -2
  120. package/dist/components/SearchableSelect.vue.d.ts +14 -32
  121. package/dist/components/SecretInput.vue.d.ts +2 -1
  122. package/dist/components/SectionCard.vue.d.ts +13 -14
  123. package/dist/components/SegmentedControl.vue.d.ts +2 -1
  124. package/dist/components/SequenceInput.vue.d.ts +10 -21
  125. package/dist/components/SequenceProgressBar.vue.d.ts +2 -1
  126. package/dist/components/SettingsModal.schema.d.ts +1 -1
  127. package/dist/components/SettingsModal.vue.d.ts +28 -25
  128. package/dist/components/Skeleton.vue.d.ts +2 -1
  129. package/dist/components/SmartGroup.types.d.ts +2 -2
  130. package/dist/components/SmartGroupFieldRecipe.groups.d.ts +2 -0
  131. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +4 -7
  132. package/dist/components/SmartGroupManual.vue.d.ts +3 -2
  133. package/dist/components/SmartGroupModal.vue.d.ts +6 -4
  134. package/dist/components/StatusIndicator.vue.d.ts +2 -1
  135. package/dist/components/StepWizard.vue.d.ts +26 -27
  136. package/dist/components/TagsInput.vue.d.ts +3 -5
  137. package/dist/components/ThemeToggle.vue.d.ts +2 -1
  138. package/dist/components/TimePicker.vue.d.ts +6 -6
  139. package/dist/components/TimeRangeInput.vue.d.ts +9 -2
  140. package/dist/components/Tooltip.vue.d.ts +8 -18
  141. package/dist/components/UnitInput.vue.d.ts +2 -1
  142. package/dist/components/WellPlate.colors.d.ts +2 -4
  143. package/dist/components/WellPlate.rendering.d.ts +7 -1
  144. package/dist/components/WellPlate.sampleDrop.d.ts +2 -0
  145. package/dist/components/WellPlate.vue.d.ts +22 -39
  146. package/dist/components/index.d.ts +34 -31
  147. package/dist/components/index.js +5 -8
  148. package/dist/components/internal/ActionItemInternal.vue.d.ts +11 -13
  149. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +14 -23
  150. package/dist/components/internal/AppTopBarPillNavInternal.vue.d.ts +2 -1
  151. package/dist/components/internal/CalendarGridPanelInternal.vue.d.ts +2 -1
  152. package/dist/components/internal/DataStateInternal.vue.d.ts +7 -11
  153. package/dist/components/internal/{FilePickerTreeInternal.vue.d.ts → FilePickerListInternal.vue.d.ts} +9 -6
  154. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +4 -3
  155. package/dist/components/internal/FormFieldRendererInternal.vue.d.ts +16 -18
  156. package/dist/components/internal/FormSectionRenderer.vue.d.ts +36 -32
  157. package/dist/components/internal/PlateEditorBindingInternal.vue.d.ts +8 -0
  158. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +65 -0
  159. package/dist/components/internal/SettingsPaneHeadInternal.vue.d.ts +15 -0
  160. package/dist/components/internal/WellEditPopupInternal.vue.d.ts +12 -4
  161. package/dist/components/internal/WorkspaceControlsInternal.vue.d.ts +6 -13
  162. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +19 -42
  163. package/dist/components/internal/WorkspaceSidebarInternal.vue.d.ts +9 -19
  164. package/dist/components/internal/filePickerPresentation.d.ts +8 -0
  165. package/dist/components/internal/generatedJobsApi.d.ts +9 -0
  166. package/dist/{components-Bbg_gtzF.js → components-GDDvof8D.js} +7088 -5955
  167. package/dist/components-GDDvof8D.js.map +1 -0
  168. package/dist/composables/controlSchemaTypes.d.ts +4 -43
  169. package/dist/composables/createFilePickerAdapter.d.ts +5 -1
  170. package/dist/composables/filePicker/usePickerNavigation.d.ts +7 -2
  171. package/dist/composables/index.d.ts +2 -13
  172. package/dist/composables/index.js +7 -11
  173. package/dist/composables/pluginWorkspaceModel.d.ts +1 -3
  174. package/dist/composables/useAutoGroup.d.ts +10 -0
  175. package/dist/composables/useBioTemplateComponents.d.ts +15 -3
  176. package/dist/composables/useBioTemplateControls.d.ts +5 -1
  177. package/dist/composables/useBioTemplatePackWorkspace.d.ts +2 -0
  178. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +5 -1
  179. package/dist/composables/useBioTemplateWorkspace.d.ts +5 -1
  180. package/dist/composables/useChemicalFormula.d.ts +2 -1
  181. package/dist/composables/useDropdownState.d.ts +5 -0
  182. package/dist/composables/useExperimentSave.d.ts +5 -1
  183. package/dist/composables/useFileBrowser.d.ts +3 -2
  184. package/dist/composables/useFilePicker.d.ts +25 -13
  185. package/dist/composables/useFocusTrap.d.ts +2 -1
  186. package/dist/composables/useGroupAssignment.d.ts +5 -1
  187. package/dist/composables/useJobsStatusTray.d.ts +5 -5
  188. package/dist/composables/useMenuKeyboard.d.ts +3 -3
  189. package/dist/composables/usePlatformContext.d.ts +3 -0
  190. package/dist/composables/usePluginClient.d.ts +1 -1
  191. package/dist/composables/useRackEditor.d.ts +36 -1
  192. package/dist/composables/useSequenceUtils.d.ts +8 -0
  193. package/dist/composables/useTemplateCollection.d.ts +5 -1
  194. package/dist/composables/workspaceRecipes.d.ts +1 -0
  195. package/dist/composables-D6uqp0UF.js +591 -0
  196. package/dist/composables-D6uqp0UF.js.map +1 -0
  197. package/dist/{errors-BLuqMee5.js → experiment-DgllIc3I.js} +89 -333
  198. package/dist/experiment-DgllIc3I.js.map +1 -0
  199. package/dist/{experiment-utils-CV2Wza3z.js → experiment-utils-DTANyVKV.js} +68 -37
  200. package/dist/experiment-utils-DTANyVKV.js.map +1 -0
  201. package/dist/index.d.ts +2 -0
  202. package/dist/index.js +122 -17
  203. package/dist/index.js.map +1 -1
  204. package/dist/install.js +1 -2
  205. package/dist/install.js.map +1 -1
  206. package/dist/instrument.d.ts +6 -0
  207. package/dist/lcms.d.ts +11 -0
  208. package/dist/permissions.d.ts +2 -47
  209. package/dist/permissions.js +2 -26
  210. package/dist/permissions.js.map +1 -1
  211. package/dist/settings-BLr8lzw6.js +341 -0
  212. package/dist/settings-BLr8lzw6.js.map +1 -0
  213. package/dist/stores/auth.d.ts +2 -150
  214. package/dist/stores/experiment.d.ts +2 -106
  215. package/dist/stores/index.js +2 -2
  216. package/dist/stores/settings.d.ts +2 -44
  217. package/dist/styles.css +8608 -6950
  218. package/dist/tailwind.preset.js.map +1 -1
  219. package/dist/templates/adapters.d.ts +3 -0
  220. package/dist/templates/assayMatrixAdapters.d.ts +8 -1
  221. package/dist/templates/assayMatrixBuilder.d.ts +1 -0
  222. package/dist/templates/builderPresetControls.d.ts +1 -0
  223. package/dist/templates/calibrationCurveAdapters.d.ts +3 -0
  224. package/dist/templates/calibrationCurveBuilder.d.ts +1 -0
  225. package/dist/templates/catalog.d.ts +6 -2
  226. package/dist/templates/componentBindings.d.ts +31 -5
  227. package/dist/templates/componentPlateHelpers.d.ts +7 -1
  228. package/dist/templates/controlSchemas.d.ts +9 -0
  229. package/dist/templates/defaultBioTemplateBuilder.d.ts +1 -0
  230. package/dist/templates/doseResponseAdapters.d.ts +2 -0
  231. package/dist/templates/doseResponseBuilder.d.ts +1 -0
  232. package/dist/templates/elisaAssayCollectionBuilder.d.ts +1 -0
  233. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +1 -0
  234. package/dist/templates/flowCytometryPanelBuilder.d.ts +1 -0
  235. package/dist/templates/flowPanelAdapters.d.ts +3 -0
  236. package/dist/templates/index.d.ts +1 -1
  237. package/dist/templates/index.js +2 -3
  238. package/dist/templates/instrumentRunAdapters.d.ts +13 -2
  239. package/dist/templates/instrumentRunBuilder.d.ts +1 -0
  240. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +1 -0
  241. package/dist/templates/packs.d.ts +4 -0
  242. package/dist/templates/plateMapAdapters.d.ts +2 -0
  243. package/dist/templates/plateMapBuilder.d.ts +1 -0
  244. package/dist/templates/presets.d.ts +6 -2
  245. package/dist/templates/protocolAdapters.d.ts +4 -0
  246. package/dist/templates/protocolStepsBuilder.d.ts +1 -0
  247. package/dist/templates/qpcrAdapters.d.ts +4 -0
  248. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +1 -0
  249. package/dist/templates/qpcrPlateBuilder.d.ts +1 -0
  250. package/dist/templates/reagentAdapters.d.ts +4 -0
  251. package/dist/templates/reagentListBuilder.d.ts +1 -0
  252. package/dist/templates/samplePrepAdapters.d.ts +3 -0
  253. package/dist/templates/samplePrepBuilder.d.ts +1 -0
  254. package/dist/templates/sampleSheetAdapters.d.ts +4 -0
  255. package/dist/templates/sampleSheetBuilder.d.ts +1 -0
  256. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +1 -0
  257. package/dist/templates/templateEnvelopes.d.ts +8 -0
  258. package/dist/templates/templatePackCollectionBuilder.d.ts +1 -0
  259. package/dist/templates/templatePresetCollectionBuilder.d.ts +2 -0
  260. package/dist/templates/templateValidators.d.ts +12 -0
  261. package/dist/templates/timeCourseAdapters.d.ts +4 -0
  262. package/dist/templates/timeCourseBuilder.d.ts +1 -0
  263. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +1 -0
  264. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +1 -0
  265. package/dist/templates-BU1pet28.js +12304 -0
  266. package/dist/templates-BU1pet28.js.map +1 -0
  267. package/dist/types/auth.d.ts +0 -27
  268. package/dist/types/componentLabTypes.d.ts +14 -7
  269. package/dist/types/componentWorkflowTypes.d.ts +26 -0
  270. package/dist/types/components.d.ts +40 -17
  271. package/dist/types/fileBrowserTypes.d.ts +13 -0
  272. package/dist/types/filePicker.d.ts +19 -1
  273. package/dist/types/generated-ui.d.ts +13 -0
  274. package/dist/types/index.d.ts +4 -4
  275. package/dist/types/index.js +1 -1
  276. package/dist/types/instrument.d.ts +43 -15
  277. package/dist/types/platform.d.ts +2 -0
  278. package/dist/utils/color.d.ts +6 -1
  279. package/dist/utils/formModelSync.d.ts +1 -0
  280. package/dist/utils/plotlyTemplate.d.ts +3 -0
  281. package/dist/utils/rack.d.ts +16 -0
  282. package/dist/utils/sampleTypeMarker.d.ts +23 -0
  283. package/dist/{validation-ChMyixAf.js → validation-Dmp9Q5W0.js} +3032 -838
  284. package/dist/validation-Dmp9Q5W0.js.map +1 -0
  285. package/package.json +17 -23
  286. package/src/__stories__/experiment-helpers.ts +8 -4
  287. package/src/__tests__/components/ActionMenu.test.ts +66 -0
  288. package/src/__tests__/components/AlertBox.test.ts +21 -0
  289. package/src/__tests__/components/AppAvatarMenu.test.ts +25 -0
  290. package/src/__tests__/components/AppTopBar.test.ts +79 -0
  291. package/src/__tests__/components/AppTopBarPageSelector.test.ts +20 -0
  292. package/src/__tests__/components/AppTopBarPillNav.test.ts +74 -0
  293. package/src/__tests__/components/ArtifactSelectorModal.test.ts +20 -6
  294. package/src/__tests__/components/AuditTrail.test.ts +38 -0
  295. package/src/__tests__/components/BaseCheckbox.test.ts +43 -0
  296. package/src/__tests__/components/BaseInput.test.ts +43 -0
  297. package/src/__tests__/components/BaseModal.test.ts +90 -0
  298. package/src/__tests__/components/BaseRadioGroup.test.ts +8 -0
  299. package/src/__tests__/components/BaseSlider.test.ts +116 -0
  300. package/src/__tests__/components/BaseToggle.test.ts +7 -0
  301. package/src/__tests__/components/BatchProgressList.test.ts +22 -14
  302. package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +4 -4
  303. package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +1 -1
  304. package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +8 -8
  305. package/src/__tests__/components/BioTemplateRenderer.test.ts +2 -2
  306. package/src/__tests__/components/Breadcrumb.test.ts +45 -0
  307. package/src/__tests__/components/CalendarGridPanel.test.ts +14 -0
  308. package/src/__tests__/components/ChartContainer.test.ts +23 -0
  309. package/src/__tests__/components/ChemicalFormula.test.ts +15 -0
  310. package/src/__tests__/components/CollapsibleCard.test.ts +12 -9
  311. package/src/__tests__/components/ComponentBindingRenderer.test.ts +45 -17
  312. package/src/__tests__/components/ConcentrationInput.test.ts +17 -2
  313. package/src/__tests__/components/DataFrame.test.ts +107 -4
  314. package/src/__tests__/components/DataStates.test.ts +0 -16
  315. package/src/__tests__/components/DatePicker.test.ts +10 -0
  316. package/src/__tests__/components/DoseCalculator.test.ts +47 -0
  317. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +37 -34
  318. package/src/__tests__/components/EmptyState.test.ts +16 -1
  319. package/src/__tests__/components/ExperimentSelectorModal.test.ts +31 -3
  320. package/src/__tests__/components/ExperimentTimeline.test.ts +45 -0
  321. package/src/__tests__/components/FilePicker.state.test.ts +2 -2
  322. package/src/__tests__/components/FilePicker.test.ts +360 -13
  323. package/src/__tests__/components/FileUploader.test.ts +15 -0
  324. package/src/__tests__/components/FitPanel.test.ts +96 -0
  325. package/src/__tests__/components/FormulaInput.test.ts +97 -0
  326. package/src/__tests__/components/GeneratedPathInput.test.ts +168 -41
  327. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +1 -1
  328. package/src/__tests__/components/GeneratedResultRenderer.test.ts +47 -2
  329. package/src/__tests__/components/InstrumentStateBadge.test.ts +50 -0
  330. package/src/__tests__/components/JobsStatusTray.test.ts +27 -0
  331. package/src/__tests__/components/MoleculeInput.test.ts +78 -0
  332. package/src/__tests__/components/MultiSelect.test.ts +6 -0
  333. package/src/__tests__/components/PlateEditor.test.ts +1134 -0
  334. package/src/__tests__/components/PlateEditorBindingInternal.test.ts +64 -0
  335. package/src/__tests__/components/PlotlyChart.test.ts +147 -1
  336. package/src/__tests__/components/ProgressBar.test.ts +18 -0
  337. package/src/__tests__/components/ProtocolStepEditor.test.ts +106 -18
  338. package/src/__tests__/components/ProtocolStepParameterField.test.ts +74 -29
  339. package/src/__tests__/components/ReagentList.presentation.test.ts +10 -5
  340. package/src/__tests__/components/ReagentList.test.ts +23 -0
  341. package/src/__tests__/components/ResourcePickerListInternal.test.ts +141 -0
  342. package/src/__tests__/components/RetiredStyles.test.ts +0 -6
  343. package/src/__tests__/components/SampleHierarchyTree.test.ts +102 -0
  344. package/src/__tests__/components/SampleLegend.test.ts +18 -0
  345. package/src/__tests__/components/SampleSelector.test.ts +92 -1
  346. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +5 -2
  347. package/src/__tests__/components/ScheduleCalendar.test.ts +32 -0
  348. package/src/__tests__/components/ScientificNumber.test.ts +113 -0
  349. package/src/__tests__/components/SearchableSelect.test.ts +21 -0
  350. package/src/__tests__/components/SecretInput.test.ts +6 -0
  351. package/src/__tests__/components/SegmentedControl.test.ts +14 -0
  352. package/src/__tests__/components/SequenceInput.test.ts +81 -0
  353. package/src/__tests__/components/SettingsModal.schema.test.ts +5 -5
  354. package/src/__tests__/components/SettingsModal.test.ts +371 -23
  355. package/src/__tests__/components/Skeleton.test.ts +23 -0
  356. package/src/__tests__/components/SmartGroupFieldRecipe.test.ts +12 -0
  357. package/src/__tests__/components/SmartGroupModal.test.ts +69 -0
  358. package/src/__tests__/components/StepWizard.test.ts +75 -0
  359. package/src/__tests__/components/TagsInput.test.ts +16 -0
  360. package/src/__tests__/components/TimePicker.test.ts +66 -0
  361. package/src/__tests__/components/TimeRangeInput.test.ts +83 -0
  362. package/src/__tests__/components/UnitInput.test.ts +147 -0
  363. package/src/__tests__/components/WellEditPopupInternal.test.ts +434 -2
  364. package/src/__tests__/components/WellPlate.decoration.test.ts +18 -0
  365. package/src/__tests__/components/WellPlate.geometry.test.ts +13 -0
  366. package/src/__tests__/components/WellPlate.interaction.test.ts +213 -0
  367. package/src/__tests__/components/WellPlate.keyboard.test.ts +24 -0
  368. package/src/__tests__/components/WellPlate.rendering.test.ts +38 -19
  369. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +19 -0
  370. package/src/__tests__/components/WellPlate.sampleTypeIndicator.test.ts +58 -0
  371. package/src/__tests__/composables/createFilePickerAdapter.test.ts +114 -1
  372. package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +1 -1
  373. package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +1 -1
  374. package/src/__tests__/composables/useChemicalFormula.test.ts +60 -0
  375. package/src/__tests__/composables/useControlSchema.test.ts +15 -5
  376. package/src/__tests__/composables/useDropdownState.test.ts +20 -1
  377. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +52 -0
  378. package/src/__tests__/composables/usePickerNavigation.test.ts +61 -1
  379. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +18 -6
  380. package/src/__tests__/composables/useRackEditor.test.ts +270 -0
  381. package/src/__tests__/composables/useSequenceUtils.test.ts +28 -0
  382. package/src/__tests__/docs/frontendDocsCatalog.test.ts +44 -9
  383. package/src/__tests__/styles/baseControlsRules.test.ts +115 -0
  384. package/src/__tests__/styles/controlRefreshRules.test.ts +218 -0
  385. package/src/__tests__/styles/cssTokens.test.ts +7 -5
  386. package/src/__tests__/styles/darkModeRules.test.ts +47 -0
  387. package/src/__tests__/styles/menusShellRefresh.test.ts +75 -0
  388. package/src/__tests__/templates/templates.test.ts +65 -15
  389. package/src/__tests__/templates/templatesDeprecation.test.ts +78 -0
  390. package/src/__tests__/utils/permissions.test.ts +0 -68
  391. package/src/__tests__/utils/plotlyTemplate.test.ts +69 -0
  392. package/src/__tests__/utils/sampleTypeMarker.test.ts +54 -0
  393. package/src/components/ActionMenu.vue +44 -23
  394. package/src/components/AdductText.story.vue +18 -0
  395. package/src/components/AdductText.vue +7 -1
  396. package/src/components/AlertBox.vue +3 -7
  397. package/src/components/AppAvatarMenu.vue +12 -10
  398. package/src/components/AppSidebar.vue +1 -1
  399. package/src/components/AppTopBar.story.vue +47 -4
  400. package/src/components/AppTopBar.vue +16 -22
  401. package/src/components/ArtifactSelectorModal.story.vue +1 -1
  402. package/src/components/ArtifactSelectorModal.vue +48 -160
  403. package/src/components/AuditTrail.vue +26 -12
  404. package/src/components/AutoGroupModal.vue +1 -1
  405. package/src/components/BaseCheckbox.story.vue +58 -2
  406. package/src/components/BaseCheckbox.vue +21 -3
  407. package/src/components/BaseInput.story.vue +51 -0
  408. package/src/components/BaseInput.vue +62 -1
  409. package/src/components/BaseModal.story.vue +55 -0
  410. package/src/components/BaseModal.vue +83 -50
  411. package/src/components/BaseRadioGroup.vue +1 -1
  412. package/src/components/BaseSlider.story.vue +36 -0
  413. package/src/components/BaseSlider.vue +56 -8
  414. package/src/components/BaseToggle.vue +1 -7
  415. package/src/components/BatchProgressList.vue +50 -52
  416. package/src/components/BioTemplatePresetWorkspaceView.vue +1 -1
  417. package/src/components/Breadcrumb.story.vue +1 -1
  418. package/src/components/Breadcrumb.vue +50 -15
  419. package/src/components/ChartContainer.story.vue +42 -0
  420. package/src/components/ChartContainer.vue +22 -1
  421. package/src/components/ChemicalFormula.story.vue +11 -11
  422. package/src/components/ChemicalFormula.vue +1 -0
  423. package/src/components/CollapsibleCard.vue +12 -32
  424. package/src/components/ComponentBindingRenderer.vue +6 -8
  425. package/src/components/ConcentrationInput.story.vue +1 -1
  426. package/src/components/ConcentrationInput.vue +8 -14
  427. package/src/components/ControlWorkspaceView.vue +1 -1
  428. package/src/components/DataFrame.story.vue +45 -2
  429. package/src/components/DataFrame.vue +28 -13
  430. package/src/components/DatePicker.story.vue +11 -0
  431. package/src/components/DatePicker.vue +5 -5
  432. package/src/components/DateTimePicker.story.vue +1 -1
  433. package/src/components/DateTimePicker.vue +8 -5
  434. package/src/components/Divider.story.vue +1 -1
  435. package/src/components/DoseCalculator.vue +44 -51
  436. package/src/components/DoseCalculatorVolumeField.vue +22 -35
  437. package/src/components/DoseDesignWorkspaceView.vue +1 -1
  438. package/src/components/EmptyState.story.vue +4 -4
  439. package/src/components/EmptyState.vue +4 -2
  440. package/src/components/ExperimentPopover.story.vue +2 -2
  441. package/src/components/ExperimentPopover.vue +6 -4
  442. package/src/components/ExperimentSelectorModal.story.vue +2 -1
  443. package/src/components/ExperimentSelectorModal.vue +91 -261
  444. package/src/components/ExperimentTimeline.story.vue +29 -0
  445. package/src/components/ExperimentTimeline.vue +20 -0
  446. package/src/components/FilePicker.story.vue +65 -10
  447. package/src/components/FilePicker.vue +203 -121
  448. package/src/components/FitPanel.story.vue +72 -6
  449. package/src/components/FitPanel.vue +70 -18
  450. package/src/components/FormField.vue +2 -0
  451. package/src/components/FormulaInput.story.vue +6 -0
  452. package/src/components/FormulaInput.vue +49 -70
  453. package/src/components/GeneratedPathInput.story.vue +121 -8
  454. package/src/components/GeneratedPathInput.vue +155 -86
  455. package/src/components/GeneratedPlotlyResult.vue +1 -1
  456. package/src/components/GeneratedPluginView.vue +4 -4
  457. package/src/components/GeneratedResultRenderer.vue +19 -0
  458. package/src/components/InstrumentStateBadge.story.vue +41 -0
  459. package/src/components/InstrumentStateBadge.vue +24 -14
  460. package/src/components/JobsStatusTray.vue +30 -8
  461. package/src/components/MoleculeInput.vue +12 -7
  462. package/src/components/MultiSelect.vue +3 -3
  463. package/src/components/PlateEditor.story.vue +333 -0
  464. package/src/components/PlateEditor.vue +793 -0
  465. package/src/components/PlotlyChart.story.vue +37 -1
  466. package/src/components/PlotlyChart.vue +86 -16
  467. package/src/components/PluginWorkspaceView.props.ts +1 -7
  468. package/src/components/PluginWorkspaceView.vue +0 -4
  469. package/src/components/ProgressBar.story.vue +0 -30
  470. package/src/components/ProgressBar.vue +3 -53
  471. package/src/components/ProtocolStepEditor.story.vue +8 -0
  472. package/src/components/ProtocolStepEditor.vue +55 -145
  473. package/src/components/ProtocolStepParameterField.vue +55 -93
  474. package/src/components/ReagentList.presentation.ts +7 -6
  475. package/src/components/ReagentList.vue +18 -17
  476. package/src/components/SampleHierarchyTree.story.vue +19 -0
  477. package/src/components/SampleHierarchyTree.vue +47 -14
  478. package/src/components/SampleLegend.vue +12 -4
  479. package/src/components/SampleSelector.story.vue +5 -1
  480. package/src/components/SampleSelector.vue +25 -15
  481. package/src/components/SampleSelectorGroupNode.vue +10 -20
  482. package/src/components/SampleSelectorSampleRow.vue +7 -18
  483. package/src/components/ScheduleCalendar.story.vue +14 -0
  484. package/src/components/ScheduleCalendar.vue +13 -1
  485. package/src/components/ScientificNumber.story.vue +15 -2
  486. package/src/components/ScientificNumber.vue +22 -26
  487. package/src/components/SearchableSelect.vue +14 -9
  488. package/src/components/SecretInput.vue +1 -1
  489. package/src/components/SegmentedControl.story.vue +23 -0
  490. package/src/components/SegmentedControl.vue +6 -1
  491. package/src/components/SequenceInput.story.vue +27 -5
  492. package/src/components/SequenceInput.vue +74 -29
  493. package/src/components/SequenceProgressBar.vue +0 -1
  494. package/src/components/SettingsModal.schema.ts +4 -2
  495. package/src/components/SettingsModal.story.vue +83 -22
  496. package/src/components/SettingsModal.vue +338 -79
  497. package/src/components/Skeleton.vue +6 -35
  498. package/src/components/SmartGroup.types.ts +2 -2
  499. package/src/components/SmartGroupFieldRecipe.groups.ts +4 -1
  500. package/src/components/SmartGroupFieldRecipe.vue +14 -8
  501. package/src/components/SmartGroupManual.vue +14 -11
  502. package/src/components/StepWizard.vue +16 -19
  503. package/src/components/TagsInput.story.vue +16 -11
  504. package/src/components/TagsInput.vue +20 -3
  505. package/src/components/TimePicker.story.vue +38 -3
  506. package/src/components/TimePicker.vue +26 -11
  507. package/src/components/TimeRangeInput.story.vue +50 -1
  508. package/src/components/TimeRangeInput.vue +36 -17
  509. package/src/components/UnitInput.story.vue +1 -1
  510. package/src/components/UnitInput.vue +173 -107
  511. package/src/components/WellPlate.colors.ts +7 -6
  512. package/src/components/WellPlate.geometry.ts +3 -0
  513. package/src/components/WellPlate.interaction.ts +39 -5
  514. package/src/components/WellPlate.rendering.ts +21 -27
  515. package/src/components/WellPlate.sampleDrop.ts +20 -12
  516. package/src/components/WellPlate.story.vue +18 -7
  517. package/src/components/WellPlate.vue +28 -22
  518. package/src/components/index.ts +34 -31
  519. package/src/components/internal/AppTopBarPageSelectorInternal.vue +13 -7
  520. package/src/components/internal/AppTopBarPillNavInternal.vue +12 -7
  521. package/src/components/internal/CalendarGridPanelInternal.vue +1 -1
  522. package/src/components/internal/FilePickerListInternal.vue +318 -0
  523. package/src/components/internal/FilePickerPreviewInternal.vue +54 -52
  524. package/src/components/internal/PlateEditorBindingInternal.vue +37 -0
  525. package/src/components/internal/ResourcePickerListInternal.vue +237 -0
  526. package/src/components/internal/SettingsPaneHeadInternal.vue +41 -0
  527. package/src/components/internal/WellEditPopupInternal.vue +219 -146
  528. package/src/components/internal/WorkspaceShellInternal.vue +0 -6
  529. package/src/components/internal/filePickerPresentation.ts +30 -0
  530. package/src/components/internal/generatedJobsApi.ts +12 -0
  531. package/src/composables/autoGroup/index.ts +3 -0
  532. package/src/composables/controlSchemaAdapters.ts +0 -4
  533. package/src/composables/controlSchemaFormFields.ts +0 -4
  534. package/src/composables/controlSchemaTypes.ts +4 -43
  535. package/src/composables/createFilePickerAdapter.ts +90 -22
  536. package/src/composables/filePicker/localFiles.ts +1 -0
  537. package/src/composables/filePicker/usePickerNavigation.ts +29 -2
  538. package/src/composables/index.ts +2 -71
  539. package/src/composables/pluginWorkspaceModel.ts +0 -3
  540. package/src/composables/useAutoGroup.ts +10 -0
  541. package/src/composables/useBioTemplateComponents.ts +15 -3
  542. package/src/composables/useBioTemplateControls.ts +5 -1
  543. package/src/composables/useBioTemplatePackWorkspace.ts +2 -0
  544. package/src/composables/useBioTemplatePresetWorkspace.ts +5 -1
  545. package/src/composables/useBioTemplateWorkspace.ts +5 -1
  546. package/src/composables/useChemicalFormula.ts +39 -13
  547. package/src/composables/useDropdownState.ts +6 -1
  548. package/src/composables/useExperimentSave.ts +5 -1
  549. package/src/composables/useFileBrowser.ts +3 -2
  550. package/src/composables/useFilePicker.ts +98 -13
  551. package/src/composables/useFocusTrap.ts +9 -6
  552. package/src/composables/useGeneratedAnalysis.ts +38 -0
  553. package/src/composables/useGroupAssignment.ts +5 -1
  554. package/src/composables/useJobsStatusTray.ts +5 -5
  555. package/src/composables/useMenuKeyboard.ts +5 -3
  556. package/src/composables/usePlatformFilePickerAdapter.ts +26 -4
  557. package/src/composables/usePluginClient.ts +1 -1
  558. package/src/composables/usePluginWorkspace.ts +0 -1
  559. package/src/composables/useRackEditor.ts +202 -12
  560. package/src/composables/useSequenceUtils.ts +20 -2
  561. package/src/composables/useTemplateCollection.ts +5 -1
  562. package/src/composables/workspaceRecipes.ts +1 -0
  563. package/src/index.ts +9 -3
  564. package/src/instrument.ts +6 -0
  565. package/src/lcms.ts +11 -0
  566. package/src/permissions.ts +2 -59
  567. package/src/styles/components/action-menu.css +9 -38
  568. package/src/styles/components/adduct-text.css +15 -3
  569. package/src/styles/components/alert-box.css +19 -70
  570. package/src/styles/components/app-avatar-menu.css +22 -57
  571. package/src/styles/components/app-container.css +4 -4
  572. package/src/styles/components/app-layout.css +18 -18
  573. package/src/styles/components/app-page-selector.css +50 -105
  574. package/src/styles/components/app-pill-nav.css +24 -42
  575. package/src/styles/components/app-sidebar.css +2 -2
  576. package/src/styles/components/app-top-bar.css +78 -55
  577. package/src/styles/components/artifact-selector-modal.css +1 -211
  578. package/src/styles/components/audit-trail.css +45 -38
  579. package/src/styles/components/avatar.css +1 -1
  580. package/src/styles/components/batch-progress-list.css +179 -95
  581. package/src/styles/components/breadcrumb.css +34 -15
  582. package/src/styles/components/calendar.css +2 -8
  583. package/src/styles/components/chart-container.css +81 -38
  584. package/src/styles/components/checkbox.css +8 -6
  585. package/src/styles/components/chemical-formula.css +8 -6
  586. package/src/styles/components/collapsible-card.css +6 -46
  587. package/src/styles/components/concentration-input.css +1 -10
  588. package/src/styles/components/dataframe.css +48 -67
  589. package/src/styles/components/date-picker.css +124 -62
  590. package/src/styles/components/datetime-picker.css +81 -47
  591. package/src/styles/components/divider.css +2 -4
  592. package/src/styles/components/dose-calculator.css +9 -135
  593. package/src/styles/components/empty-state.css +26 -35
  594. package/src/styles/components/experiment-code-badge.css +1 -1
  595. package/src/styles/components/experiment-popover.css +16 -83
  596. package/src/styles/components/experiment-selector-modal.css +9 -226
  597. package/src/styles/components/experiment-timeline.css +120 -50
  598. package/src/styles/components/file-picker.css +323 -299
  599. package/src/styles/components/file-uploader.css +4 -6
  600. package/src/styles/components/fit-panel.css +108 -22
  601. package/src/styles/components/form-field.css +6 -4
  602. package/src/styles/components/formula-input.css +121 -48
  603. package/src/styles/components/group-assigner.css +1 -3
  604. package/src/styles/components/icon-button.css +15 -37
  605. package/src/styles/components/input.css +91 -2
  606. package/src/styles/components/instrument-monitor.css +37 -447
  607. package/src/styles/components/jobs-status-tray.css +82 -61
  608. package/src/styles/components/loading-spinner.css +18 -0
  609. package/src/styles/components/mobile-support-gate.css +15 -17
  610. package/src/styles/components/modal.css +44 -33
  611. package/src/styles/components/molecule-input.css +31 -16
  612. package/src/styles/components/multi-select.css +33 -29
  613. package/src/styles/components/number-input.css +1 -1
  614. package/src/styles/components/plate-editor.css +497 -0
  615. package/src/styles/components/popover.css +162 -0
  616. package/src/styles/components/progress-bar.css +1 -70
  617. package/src/styles/components/protocol-step-editor.css +21 -333
  618. package/src/styles/components/radio-group.css +9 -18
  619. package/src/styles/components/reagent-editor.css +3 -7
  620. package/src/styles/components/reagent-list.css +63 -69
  621. package/src/styles/components/resource-card.css +4 -6
  622. package/src/styles/components/resource-picker-list.css +212 -0
  623. package/src/styles/components/sample-hierarchy-tree.css +83 -65
  624. package/src/styles/components/sample-legend.css +18 -7
  625. package/src/styles/components/sample-selector.css +41 -68
  626. package/src/styles/components/schedule-calendar.css +59 -54
  627. package/src/styles/components/scientific-number.css +72 -18
  628. package/src/styles/components/searchable-select.css +17 -26
  629. package/src/styles/components/secret-input.css +20 -23
  630. package/src/styles/components/section-card.css +3 -5
  631. package/src/styles/components/segmented-control.css +14 -1
  632. package/src/styles/components/select.css +19 -8
  633. package/src/styles/components/sequence-input.css +85 -37
  634. package/src/styles/components/sequence-progress-bar.css +18 -37
  635. package/src/styles/components/settings-modal.css +683 -34
  636. package/src/styles/components/skeleton.css +24 -23
  637. package/src/styles/components/slider.css +74 -8
  638. package/src/styles/components/smart-group.css +27 -39
  639. package/src/styles/components/status-indicator.css +1 -1
  640. package/src/styles/components/step-wizard.css +62 -99
  641. package/src/styles/components/tabs.css +2 -6
  642. package/src/styles/components/tags-input.css +64 -54
  643. package/src/styles/components/textarea.css +2 -2
  644. package/src/styles/components/time-picker.css +67 -38
  645. package/src/styles/components/time-range-input.css +16 -18
  646. package/src/styles/components/toast.css +1 -1
  647. package/src/styles/components/toggle.css +21 -31
  648. package/src/styles/components/tooltip.css +13 -15
  649. package/src/styles/components/unit-input.css +86 -36
  650. package/src/styles/components/well-edit-popup.css +111 -189
  651. package/src/styles/components/well-plate.css +7 -7
  652. package/src/styles/index.css +5 -7
  653. package/src/styles/variables.css +35 -7
  654. package/src/templates/adapters.ts +4 -0
  655. package/src/templates/assayMatrixAdapters.ts +8 -1
  656. package/src/templates/assayMatrixBuilder.ts +1 -0
  657. package/src/templates/builderPresetControls.ts +1 -0
  658. package/src/templates/calibrationCurveAdapters.ts +3 -0
  659. package/src/templates/calibrationCurveBuilder.ts +1 -0
  660. package/src/templates/catalog.ts +6 -2
  661. package/src/templates/componentBindingCatalog.ts +1 -1
  662. package/src/templates/componentBindings.ts +31 -5
  663. package/src/templates/componentDoseResponseProps.ts +0 -1
  664. package/src/templates/componentPlateHelpers.ts +22 -1
  665. package/src/templates/componentPlateMapProps.ts +7 -5
  666. package/src/templates/componentQpcrPlateProps.ts +0 -1
  667. package/src/templates/controlSchemas.ts +9 -0
  668. package/src/templates/defaultBioTemplateBuilder.ts +1 -0
  669. package/src/templates/doseResponseAdapters.ts +2 -0
  670. package/src/templates/doseResponseBuilder.ts +1 -0
  671. package/src/templates/elisaAssayCollectionBuilder.ts +1 -0
  672. package/src/templates/flowCytometryAssayCollectionBuilder.ts +1 -0
  673. package/src/templates/flowCytometryPanelBuilder.ts +1 -0
  674. package/src/templates/flowPanelAdapters.ts +3 -0
  675. package/src/templates/index.ts +4 -0
  676. package/src/templates/instrumentRunAdapters.ts +13 -2
  677. package/src/templates/instrumentRunBuilder.ts +1 -0
  678. package/src/templates/lcmsBatchCollectionBuilder.ts +1 -0
  679. package/src/templates/packs.ts +4 -0
  680. package/src/templates/plateMapAdapters.ts +2 -0
  681. package/src/templates/plateMapBuilder.ts +1 -0
  682. package/src/templates/presets.ts +6 -2
  683. package/src/templates/protocolAdapters.ts +4 -0
  684. package/src/templates/protocolStepsBuilder.ts +1 -0
  685. package/src/templates/qpcrAdapters.ts +4 -0
  686. package/src/templates/qpcrExpressionCollectionBuilder.ts +1 -0
  687. package/src/templates/qpcrPlateBuilder.ts +1 -0
  688. package/src/templates/reagentAdapters.ts +4 -0
  689. package/src/templates/reagentListBuilder.ts +1 -0
  690. package/src/templates/samplePrepAdapters.ts +3 -0
  691. package/src/templates/samplePrepBuilder.ts +1 -0
  692. package/src/templates/sampleSheetAdapters.ts +4 -0
  693. package/src/templates/sampleSheetBuilder.ts +1 -0
  694. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +1 -0
  695. package/src/templates/templateEnvelopes.ts +8 -0
  696. package/src/templates/templatePackCollectionBuilder.ts +1 -0
  697. package/src/templates/templatePresetCollectionBuilder.ts +2 -0
  698. package/src/templates/templateValidators.ts +12 -0
  699. package/src/templates/timeCourseAdapters.ts +4 -0
  700. package/src/templates/timeCourseBuilder.ts +1 -0
  701. package/src/templates/wellPlateScreenCollectionBuilder.ts +1 -0
  702. package/src/templates/westernBlotAssayCollectionBuilder.ts +1 -0
  703. package/src/types/auth.ts +0 -37
  704. package/src/types/componentLabTypes.ts +16 -13
  705. package/src/types/componentWorkflowTypes.ts +29 -0
  706. package/src/types/components.ts +43 -20
  707. package/src/types/fileBrowserTypes.ts +15 -0
  708. package/src/types/filePicker.ts +19 -1
  709. package/src/types/generated-ui.ts +15 -0
  710. package/src/types/index.ts +12 -11
  711. package/src/types/instrument.ts +47 -15
  712. package/src/types/platform.ts +2 -0
  713. package/src/utils/color.ts +16 -1
  714. package/src/utils/formModelSync.ts +1 -1
  715. package/src/utils/plotlyTemplate.ts +39 -0
  716. package/src/utils/rack.ts +16 -0
  717. package/src/utils/sampleTypeMarker.ts +44 -0
  718. package/dist/ExperimentPopover-CJdNlCZb.js +0 -451
  719. package/dist/ExperimentPopover-CJdNlCZb.js.map +0 -1
  720. package/dist/ExperimentSelectorModal-DHE9k8TP.js +0 -507
  721. package/dist/ExperimentSelectorModal-DHE9k8TP.js.map +0 -1
  722. package/dist/SettingsModal-DELMkUFR.js +0 -492
  723. package/dist/SettingsModal-DELMkUFR.js.map +0 -1
  724. package/dist/Skeleton-jhF9wUkU.js +0 -485
  725. package/dist/Skeleton-jhF9wUkU.js.map +0 -1
  726. package/dist/__tests__/composables/usePluginConfig.test.d.ts +0 -15
  727. package/dist/chunk-BoAXSpZd.js +0 -33
  728. package/dist/components/AppPluginSwitcher.vue.d.ts +0 -40
  729. package/dist/components/ColorSlider.vue.d.ts +0 -34
  730. package/dist/components/DropdownButton.vue.d.ts +0 -49
  731. package/dist/components/FileBrowserModal.vue.d.ts +0 -99
  732. package/dist/components/InstrumentAlertLog.vue.d.ts +0 -22
  733. package/dist/components/InstrumentStatusCard.vue.d.ts +0 -13
  734. package/dist/components/LcmsSequenceTable.vue.d.ts +0 -54
  735. package/dist/components/PlateMapEditor.vue.d.ts +0 -50
  736. package/dist/components/RackEditor.vue.d.ts +0 -78
  737. package/dist/components/fileBrowserPresentation.d.ts +0 -10
  738. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +0 -34
  739. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +0 -25
  740. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +0 -26
  741. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +0 -28
  742. package/dist/components-Bbg_gtzF.js.map +0 -1
  743. package/dist/composables/useAsync.d.ts +0 -132
  744. package/dist/composables/useAuth.d.ts +0 -47
  745. package/dist/composables/useCommandHistory.d.ts +0 -33
  746. package/dist/composables/useOptimisticMutation.d.ts +0 -32
  747. package/dist/composables/usePasskey.d.ts +0 -10
  748. package/dist/composables/usePluginConfig.d.ts +0 -27
  749. package/dist/composables/useResourceCrud.d.ts +0 -44
  750. package/dist/composables/useWellPainting.d.ts +0 -39
  751. package/dist/composables/useWellPlateAdapter.d.ts +0 -40
  752. package/dist/composables/useWellPlateEditor.d.ts +0 -33
  753. package/dist/composables/useWellPlateValidation.d.ts +0 -31
  754. package/dist/composables-BCbYb2lA.js +0 -2356
  755. package/dist/composables-BCbYb2lA.js.map +0 -1
  756. package/dist/errors-BLuqMee5.js.map +0 -1
  757. package/dist/experiment-CVDRAnqp.js +0 -90
  758. package/dist/experiment-CVDRAnqp.js.map +0 -1
  759. package/dist/experiment-utils-CV2Wza3z.js.map +0 -1
  760. package/dist/plotly.min-c2Sez60c.js +0 -180634
  761. package/dist/plotly.min-c2Sez60c.js.map +0 -1
  762. package/dist/templates-NuaNHohp.js +0 -5260
  763. package/dist/templates-NuaNHohp.js.map +0 -1
  764. package/dist/useControlSchema-vLiRPUmj.js +0 -7301
  765. package/dist/useControlSchema-vLiRPUmj.js.map +0 -1
  766. package/dist/useDropdownState-C7hRiVQf.js +0 -63
  767. package/dist/useDropdownState-C7hRiVQf.js.map +0 -1
  768. package/dist/useExperimentSelector-G_CAOFTX.js +0 -328
  769. package/dist/useExperimentSelector-G_CAOFTX.js.map +0 -1
  770. package/dist/useFormBuilder-D37ajgS8.js +0 -729
  771. package/dist/useFormBuilder-D37ajgS8.js.map +0 -1
  772. package/dist/validation-ChMyixAf.js.map +0 -1
  773. package/src/__tests__/components/AppPluginSwitcher.test.ts +0 -44
  774. package/src/__tests__/components/DropdownButton.test.ts +0 -628
  775. package/src/__tests__/components/FileBrowserModal.test.ts +0 -460
  776. package/src/__tests__/components/InstrumentAlertLog.test.ts +0 -59
  777. package/src/__tests__/components/LcmsSequenceTable.test.ts +0 -79
  778. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +0 -54
  779. package/src/__tests__/components/RackEditor.test.ts +0 -169
  780. package/src/__tests__/composables/useAuth.test.ts +0 -233
  781. package/src/__tests__/composables/useCommandHistory.test.ts +0 -43
  782. package/src/__tests__/composables/useOptimisticMutation.test.ts +0 -40
  783. package/src/__tests__/composables/usePluginConfig.test.ts +0 -497
  784. package/src/__tests__/composables/useResourceCrud.test.ts +0 -56
  785. package/src/__tests__/composables/useWellPainting.test.ts +0 -52
  786. package/src/__tests__/composables/useWellPlateAdapter.test.ts +0 -50
  787. package/src/__tests__/composables/useWellPlateValidation.test.ts +0 -42
  788. package/src/components/AppPluginSwitcher.story.vue +0 -87
  789. package/src/components/AppPluginSwitcher.vue +0 -134
  790. package/src/components/ColorSlider.story.vue +0 -120
  791. package/src/components/ColorSlider.vue +0 -160
  792. package/src/components/DropdownButton.story.vue +0 -102
  793. package/src/components/DropdownButton.vue +0 -181
  794. package/src/components/FileBrowserModal.story.vue +0 -203
  795. package/src/components/FileBrowserModal.vue +0 -384
  796. package/src/components/InstrumentAlertLog.vue +0 -187
  797. package/src/components/InstrumentStatusCard.vue +0 -184
  798. package/src/components/LcmsSequenceTable.vue +0 -222
  799. package/src/components/PlateMapEditor.story.vue +0 -92
  800. package/src/components/PlateMapEditor.vue +0 -423
  801. package/src/components/RackEditor.story.vue +0 -100
  802. package/src/components/RackEditor.vue +0 -429
  803. package/src/components/fileBrowserPresentation.ts +0 -39
  804. package/src/components/internal/FileBrowserDialogInternal.vue +0 -75
  805. package/src/components/internal/FileBrowserListingInternal.vue +0 -197
  806. package/src/components/internal/FileBrowserToolbarInternal.vue +0 -136
  807. package/src/components/internal/FilePickerTreeInternal.vue +0 -238
  808. package/src/components/internal/PlateMapEditorToolbarInternal.vue +0 -128
  809. package/src/composables/useAsync.ts +0 -327
  810. package/src/composables/useAuth.ts +0 -458
  811. package/src/composables/useCommandHistory.ts +0 -117
  812. package/src/composables/useOptimisticMutation.ts +0 -97
  813. package/src/composables/usePasskey.ts +0 -216
  814. package/src/composables/usePluginConfig.ts +0 -252
  815. package/src/composables/useResourceCrud.ts +0 -235
  816. package/src/composables/useWellPainting.ts +0 -167
  817. package/src/composables/useWellPlateAdapter.ts +0 -151
  818. package/src/composables/useWellPlateEditor.ts +0 -415
  819. package/src/composables/useWellPlateValidation.ts +0 -89
  820. package/src/plotly-dist.d.ts +0 -3
  821. package/src/styles/components/app-plugin-switcher.css +0 -196
  822. package/src/styles/components/color-slider.css +0 -110
  823. package/src/styles/components/dropdown-button.css +0 -280
  824. package/src/styles/components/file-browser-modal.css +0 -489
  825. package/src/styles/components/lcms-sequence-table.css +0 -204
  826. package/src/styles/components/plate-map-editor.css +0 -464
  827. package/src/styles/components/rack-editor.css +0 -287
  828. /package/dist/__tests__/components/{AppPluginSwitcher.test.d.ts → AlertBox.test.d.ts} +0 -0
  829. /package/dist/__tests__/components/{DropdownButton.test.d.ts → AuditTrail.test.d.ts} +0 -0
  830. /package/dist/__tests__/components/{FileBrowserModal.test.d.ts → BaseCheckbox.test.d.ts} +0 -0
  831. /package/dist/__tests__/components/{InstrumentAlertLog.test.d.ts → BaseSlider.test.d.ts} +0 -0
  832. /package/dist/__tests__/components/{LcmsSequenceTable.test.d.ts → DoseCalculator.test.d.ts} +0 -0
  833. /package/dist/__tests__/components/{PlateMapEditorToolbarInternal.test.d.ts → FileUploader.test.d.ts} +0 -0
  834. /package/dist/__tests__/components/{RackEditor.test.d.ts → FitPanel.test.d.ts} +0 -0
  835. /package/dist/__tests__/{composables/useAuth.test.d.ts → components/FormulaInput.test.d.ts} +0 -0
  836. /package/dist/__tests__/{composables/useCommandHistory.test.d.ts → components/InstrumentStateBadge.test.d.ts} +0 -0
  837. /package/dist/__tests__/{composables/useOptimisticMutation.test.d.ts → components/MoleculeInput.test.d.ts} +0 -0
  838. /package/dist/__tests__/{composables/useResourceCrud.test.d.ts → components/PlateEditor.test.d.ts} +0 -0
  839. /package/dist/__tests__/{composables/useWellPainting.test.d.ts → components/PlateEditorBindingInternal.test.d.ts} +0 -0
  840. /package/dist/__tests__/{composables/useWellPlateAdapter.test.d.ts → components/ResourcePickerListInternal.test.d.ts} +0 -0
  841. /package/dist/__tests__/{composables/useWellPlateValidation.test.d.ts → components/SampleLegend.test.d.ts} +0 -0
@@ -2,6 +2,8 @@ import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
2
2
  import { afterEach, describe, expect, it, vi } from 'vitest'
3
3
  import FilePicker from '../../components/FilePicker.vue'
4
4
  import FileUploader from '../../components/FileUploader.vue'
5
+ import BaseModal from '../../components/BaseModal.vue'
6
+ import { formatModified } from '../../components/internal/filePickerPresentation'
5
7
  import type { PickerAdapter, PickerNode, PickerSelection } from '../../types/filePicker'
6
8
  import { localFilesAdapter } from '../../composables/filePicker/localFiles'
7
9
  import { pickerExclusion } from '../../composables/filePicker/validation'
@@ -58,6 +60,7 @@ async function setup(props: Record<string, unknown> = {}) {
58
60
  open: true,
59
61
  adapter: adapter(),
60
62
  capabilities: { server: { formats: ['raw'] } },
63
+ view: 'tree',
61
64
  ...props,
62
65
  },
63
66
  global: { stubs: { teleport: true } },
@@ -66,17 +69,38 @@ async function setup(props: Record<string, unknown> = {}) {
66
69
  return wrapper
67
70
  }
68
71
  function row(wrapper: Awaited<ReturnType<typeof setup>>, path: string) {
69
- return wrapper.findAll('[role="treeitem"]').find((item) => item.attributes('data-path') === path)!
72
+ return wrapper
73
+ .findAll('[role="treeitem"],[role="option"]')
74
+ .find((item) => item.attributes('data-path') === path)!
70
75
  }
71
76
  function confirm(wrapper: Awaited<ReturnType<typeof setup>>) {
72
77
  return wrapper.findAll('.mint-picker__actions button').at(-1)!
73
78
  }
79
+ function sources(wrapper: Awaited<ReturnType<typeof setup>>) {
80
+ return wrapper.findAll('[aria-label="Data source"] button')
81
+ }
74
82
  async function expand(wrapper: Awaited<ReturnType<typeof setup>>) {
75
83
  await wrapper.get('[aria-label="Expand Tissue liver"]').trigger('click')
76
84
  await flushPromises()
77
85
  }
78
86
 
79
87
  describe('FilePicker', () => {
88
+ it('should focus the search input when / is pressed in the source panel', async () => {
89
+ const wrapper = await setup()
90
+ wrapper.element.ownerDocument.body.appendChild(wrapper.element)
91
+ await wrapper.get('.mint-picker__source-panel').trigger('keydown', { key: '/' })
92
+
93
+ expect(document.activeElement).toBe(wrapper.get('.mint-picker__search input').element)
94
+ })
95
+
96
+ it('should focus the search input when / is pressed on the source switcher', async () => {
97
+ const wrapper = await setup({ sources: ['server', 'localFile'] })
98
+ wrapper.element.ownerDocument.body.appendChild(wrapper.element)
99
+ await sources(wrapper)[0]!.trigger('keydown', { key: '/' })
100
+
101
+ expect(document.activeElement).toBe(wrapper.get('.mint-picker__search input').element)
102
+ })
103
+
80
104
  it('selects a folder without navigating, resolves metadata and excludes unsupported files', async () => {
81
105
  const wrapper = await setup()
82
106
  await row(wrapper, folder.path).trigger('click')
@@ -276,16 +300,12 @@ describe('FilePicker', () => {
276
300
 
277
301
  it('offers only server and local files and has a text-only confirm action', async () => {
278
302
  const wrapper = await setup({ sources: ['server', 'localFile'] })
279
- expect(
280
- wrapper
281
- .findAll('[aria-label="Data source"] button')
282
- .map((button) => button.attributes('aria-label')),
283
- ).toEqual(['Server', 'Local files'])
303
+ expect(sources(wrapper).map((button) => button.text())).toEqual(['Server', 'Local files'])
284
304
  expect(confirm(wrapper).text()).toBe('Use selection')
285
- expect(wrapper.get('.mint-picker__receipt > span').text()).toBe('No selection')
286
- await wrapper.get('[aria-label="Local files"]').trigger('click')
305
+ expect(wrapper.get('.mint-picker__summary').text()).toBe('No selection')
306
+ await sources(wrapper)[1]!.trigger('click')
287
307
  await flushPromises()
288
- expect(wrapper.get('[aria-label="Local files"]').attributes('aria-pressed')).toBe('true')
308
+ expect(sources(wrapper)[1]!.attributes('aria-checked')).toBe('true')
289
309
  expect(wrapper.find('[aria-label="Absolute path"]').exists()).toBe(false)
290
310
  expect(wrapper.text()).toContain('Drop files or a folder')
291
311
  })
@@ -436,7 +456,7 @@ describe('FilePicker', () => {
436
456
 
437
457
  it('does not render sources the host did not supply', async () => {
438
458
  const wrapper = await setup({ sources: ['server'] })
439
- expect(wrapper.find('[aria-label="Local files"]').exists()).toBe(false)
459
+ expect(wrapper.find('[aria-label="Data source"]').exists()).toBe(false)
440
460
  expect(wrapper.find('[aria-label="This machine"]').exists()).toBe(false)
441
461
  })
442
462
 
@@ -453,14 +473,12 @@ describe('FilePicker', () => {
453
473
  expect(confirm(wrapper).attributes('disabled')).toBeUndefined()
454
474
  })
455
475
 
456
- it('keyboard disclosure never selects and Escape cancels', async () => {
476
+ it('keyboard disclosure never selects', async () => {
457
477
  const wrapper = await setup()
458
478
  await row(wrapper, folder.path).trigger('keydown', { key: 'ArrowRight' })
459
479
  await flushPromises()
460
480
  expect(row(wrapper, folder.path).attributes('aria-expanded')).toBe('true')
461
481
  expect(row(wrapper, folder.path).attributes('aria-selected')).toBe('false')
462
- await row(wrapper, folder.path).trigger('keydown', { key: 'Escape' })
463
- expect(wrapper.emitted('cancel')).toHaveLength(1)
464
482
  })
465
483
  })
466
484
 
@@ -485,3 +503,332 @@ describe('local metadata and capability validation', () => {
485
503
  expect(nodes.map((node) => node.kind === 'file' && node.file)).toEqual(files)
486
504
  })
487
505
  })
506
+
507
+ describe('local file modification time', () => {
508
+ it('should expose the browser file lastModified as an ISO timestamp', async () => {
509
+ const file = new File(['a'], 'run.raw', { lastModified: Date.UTC(2026, 8, 24, 14, 32) })
510
+ const [node] = await localFilesAdapter([file]).listRoot()
511
+ expect(node!.modifiedAt).toBe('2026-09-24T14:32:00.000Z')
512
+ })
513
+ })
514
+
515
+ const mountA: PickerNode = { kind: 'folder', path: 'mount:a', name: 'Instrument', parentPath: null }
516
+ const mountB: PickerNode = { kind: 'folder', path: 'mount:b', name: 'Shared', parentPath: null }
517
+ const offline: PickerNode = {
518
+ kind: 'folder',
519
+ path: 'mount:c',
520
+ name: 'Archive',
521
+ parentPath: null,
522
+ unavailableReason: 'This mount is offline.',
523
+ }
524
+ const inA: PickerNode = { kind: 'file', path: 'a/run.raw', name: 'run.raw', format: 'raw', bytes: 20 }
525
+ const inB: PickerNode = { kind: 'file', path: 'b/qc.raw', name: 'qc.raw', format: 'raw', bytes: 30 }
526
+ function mountAdapter(): PickerAdapter {
527
+ return {
528
+ mounts: true,
529
+ listRoot: vi.fn(async () => [mountA, mountB, offline]),
530
+ listChildren: vi.fn(async (path) => (path === mountA.path ? [inA] : path === mountB.path ? [inB] : [])),
531
+ search: vi.fn(async () => []),
532
+ }
533
+ }
534
+
535
+ describe('FilePicker list view', () => {
536
+ it('should render a flat list without disclosure controls by default', async () => {
537
+ const wrapper = await setup({ view: undefined })
538
+ expect(wrapper.find('[aria-label="Expand Tissue liver"]').exists()).toBe(false)
539
+ })
540
+
541
+ it('should expose list rows as listbox options', async () => {
542
+ const wrapper = await setup({ view: undefined })
543
+ expect(wrapper.findAll('[role="listbox"] [role="option"]')).toHaveLength(2)
544
+ })
545
+
546
+ it('should enter a folder on double-click', async () => {
547
+ const wrapper = await setup({ view: undefined })
548
+ await row(wrapper, folder.path).trigger('dblclick')
549
+ await flushPromises()
550
+ expect(wrapper.findAll('[role="option"]').map((item) => item.attributes('data-path'))).toEqual([
551
+ // Undated rows fall back to name order under the default newest-first sort.
552
+ unsupported.path,
553
+ one.path,
554
+ two.path,
555
+ ])
556
+ })
557
+
558
+ it('should not select a folder opened by double-click', async () => {
559
+ const wrapper = await setup({ view: undefined })
560
+ await row(wrapper, folder.path).trigger('click', { detail: 1 })
561
+ await row(wrapper, folder.path).trigger('click', { detail: 2 })
562
+ await row(wrapper, folder.path).trigger('dblclick')
563
+ await flushPromises()
564
+ expect(wrapper.get('.mint-picker__summary').text()).toBe('No selection')
565
+ })
566
+
567
+ it('should keep a folder opened by double-click selected in folder mode', async () => {
568
+ const wrapper = await setup({ view: undefined, selectionMode: 'folder' })
569
+ await row(wrapper, folder.path).trigger('click', { detail: 1 })
570
+ await row(wrapper, folder.path).trigger('click', { detail: 2 })
571
+ await row(wrapper, folder.path).trigger('dblclick')
572
+ await flushPromises()
573
+ expect(wrapper.get('.mint-picker__summary').text()).not.toBe('No selection')
574
+ })
575
+
576
+ it('should not confirm a file on ArrowRight', async () => {
577
+ const wrapper = await setup({ view: undefined, selectionMode: 'single-file' })
578
+ await row(wrapper, folder.path).trigger('dblclick')
579
+ await flushPromises()
580
+ await row(wrapper, one.path).trigger('keydown', { key: 'ArrowRight' })
581
+ await flushPromises()
582
+ expect(wrapper.emitted('select')).toBeUndefined()
583
+ })
584
+
585
+ it('should render a checkbox on every selectable row in multi modes', async () => {
586
+ const wrapper = await setup({ view: undefined })
587
+ expect(wrapper.findAll('[role="option"] .mint-checkbox')).toHaveLength(2)
588
+ })
589
+
590
+ it('should reflect the row selection in its checkbox', async () => {
591
+ const wrapper = await setup({ view: undefined })
592
+ await row(wrapper, folder.path).trigger('click')
593
+ await flushPromises()
594
+ expect(row(wrapper, folder.path).find<HTMLInputElement>('input[type="checkbox"]').element.checked).toBe(true)
595
+ })
596
+
597
+ it('should show a lock instead of a checkbox on an unreadable row', async () => {
598
+ const locked: PickerNode = { ...other, unavailableReason: 'No read permission' }
599
+ const data = adapter()
600
+ vi.mocked(data.listRoot).mockResolvedValue([folder, locked])
601
+ const wrapper = await setup({ view: undefined, adapter: data })
602
+ expect(row(wrapper, locked.path).find('.mint-picker__lock').exists()).toBe(true)
603
+ })
604
+
605
+ it('should name the reason on an unreadable row', async () => {
606
+ const locked: PickerNode = { ...other, unavailableReason: 'No read permission' }
607
+ const data = adapter()
608
+ vi.mocked(data.listRoot).mockResolvedValue([folder, locked])
609
+ const wrapper = await setup({ view: undefined, adapter: data })
610
+ expect(row(wrapper, locked.path).get('.mint-picker__reason').text()).toBe('No read permission')
611
+ })
612
+
613
+ it('should show the modification time in its own column', async () => {
614
+ const stamped: PickerNode = { ...folder, modifiedAt: '2026-09-24T14:32:00' }
615
+ const data = adapter()
616
+ vi.mocked(data.listRoot).mockResolvedValue([stamped])
617
+ const wrapper = await setup({ view: undefined, adapter: data })
618
+ expect(row(wrapper, stamped.path).get('.mint-picker__cell--time').text()).toBe(
619
+ formatModified(stamped.modifiedAt),
620
+ )
621
+ })
622
+
623
+ it('should render in an extra-large BaseModal', async () => {
624
+ const wrapper = await setup()
625
+ expect(wrapper.getComponent(BaseModal).props('size')).toBe('xl')
626
+ })
627
+
628
+ it('should cancel on Escape', async () => {
629
+ const wrapper = await setup()
630
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
631
+ expect(wrapper.emitted('cancel')).toHaveLength(1)
632
+ })
633
+ })
634
+
635
+ describe('FilePicker receipt', () => {
636
+ it('should summarise the selected files and their total size', async () => {
637
+ const wrapper = await setup({ view: undefined, selectionMode: 'multi-file' })
638
+ await row(wrapper, folder.path).trigger('dblclick')
639
+ await flushPromises()
640
+ await row(wrapper, one.path).trigger('click')
641
+ await row(wrapper, two.path).trigger('click')
642
+ await flushPromises()
643
+ expect(wrapper.get('.mint-picker__summary').text()).toBe('2 files selected · 40 B')
644
+ })
645
+
646
+ it('should render the footer clear as a text link when files are selected', async () => {
647
+ const wrapper = await setup()
648
+ await row(wrapper, folder.path).trigger('click')
649
+ await flushPromises()
650
+ expect(wrapper.get('.mint-picker__clear').classes()).toContain('mint-picker__link')
651
+ })
652
+
653
+ it('should render the scope toggle at path-bar scale when the source is a server', async () => {
654
+ const wrapper = await setup()
655
+ expect(wrapper.get('.mint-picker__scope').classes()).not.toContain('mint-button')
656
+ })
657
+
658
+ it('should render the refresh action at path-bar scale when the source is a server', async () => {
659
+ const wrapper = await setup()
660
+ expect(wrapper.get('[aria-label="Refresh location"]').classes()).not.toContain('mint-icon-button')
661
+ })
662
+
663
+ it('should clear the selection from the footer', async () => {
664
+ const wrapper = await setup()
665
+ await row(wrapper, folder.path).trigger('click')
666
+ await flushPromises()
667
+ await wrapper.get('.mint-picker__clear').trigger('click')
668
+ await flushPromises()
669
+ expect(wrapper.get('.mint-picker__summary').text()).toBe('No selection')
670
+ })
671
+ })
672
+
673
+ describe('FilePicker mounts', () => {
674
+ it('should offer each mount as a header source', async () => {
675
+ const wrapper = await setup({ adapter: mountAdapter() })
676
+ expect(sources(wrapper).map((button) => button.text())).toEqual([
677
+ 'Instrument',
678
+ 'Shared',
679
+ 'Archive',
680
+ ])
681
+ })
682
+
683
+ it('should disable an offline mount', async () => {
684
+ const wrapper = await setup({ adapter: mountAdapter() })
685
+ expect(sources(wrapper)[2]!.attributes('disabled')).toBeDefined()
686
+ })
687
+
688
+ it('should open the first reachable mount', async () => {
689
+ const wrapper = await setup({ adapter: mountAdapter(), view: undefined })
690
+ expect(wrapper.findAll('[role="option"]').map((item) => item.attributes('data-path'))).toEqual([
691
+ inA.path,
692
+ ])
693
+ })
694
+
695
+ it('should list another mount when its source is chosen', async () => {
696
+ const wrapper = await setup({ adapter: mountAdapter(), view: undefined })
697
+ await sources(wrapper)[1]!.trigger('click')
698
+ await flushPromises()
699
+ expect(wrapper.findAll('[role="option"]').map((item) => item.attributes('data-path'))).toEqual([
700
+ inB.path,
701
+ ])
702
+ })
703
+
704
+ it('should keep the selection when switching mounts', async () => {
705
+ const wrapper = await setup({ adapter: mountAdapter(), view: undefined })
706
+ await row(wrapper, inA.path).trigger('click')
707
+ await sources(wrapper)[1]!.trigger('click')
708
+ await flushPromises()
709
+ await row(wrapper, inB.path).trigger('click')
710
+ await flushPromises()
711
+ expect(wrapper.get('.mint-picker__summary').text()).toBe('2 files selected · 50 B')
712
+ })
713
+
714
+ it('should name the previewed file’s own mount as its source after switching mounts', async () => {
715
+ const wrapper = await setup({ adapter: mountAdapter(), view: undefined })
716
+ await row(wrapper, inA.path).trigger('click')
717
+ await sources(wrapper)[1]!.trigger('click')
718
+ await flushPromises()
719
+ expect(wrapper.get('.mint-picker__metadata dd:last-of-type').text()).toBe(mountA.name)
720
+ })
721
+
722
+ it('should start the breadcrumb at the mount instead of the mount list', async () => {
723
+ const wrapper = await setup({ adapter: mountAdapter() })
724
+ expect(wrapper.get('[aria-label="Breadcrumb"]').text()).toBe('Instrument')
725
+ })
726
+
727
+ it('should reach the mount list from an initial folder inside a mount', async () => {
728
+ const adapter = mountAdapter()
729
+ vi.mocked(adapter.listChildren).mockImplementation(async (path) => (path === 'a/sub' ? [inA] : []))
730
+ const wrapper = await setup({ adapter, view: undefined, initialPath: 'a/sub' })
731
+ await row(wrapper, inA.path).trigger('keydown', { key: 'ArrowLeft' })
732
+ await flushPromises()
733
+ expect(wrapper.findAll('[role="option"]').map((item) => item.attributes('data-path'))).toContain(
734
+ mountA.path,
735
+ )
736
+ })
737
+
738
+ it('should mark the containing mount selected for an initial folder inside it', async () => {
739
+ const adapter = { ...mountAdapter(), mountOf: (path: string) => `mount:${path.split('/')[0]}` }
740
+ vi.mocked(adapter.listChildren).mockImplementation(async (path) => (path === 'a/sub' ? [inA] : []))
741
+ const wrapper = await setup({ adapter, view: undefined, initialPath: 'a/sub' })
742
+ expect(sources(wrapper)[0]!.attributes('aria-checked')).toBe('true')
743
+ })
744
+
745
+ it('should name the containing mount as the source of a file under an initial folder', async () => {
746
+ const adapter = { ...mountAdapter(), mountOf: (path: string) => `mount:${path.split('/')[0]}` }
747
+ vi.mocked(adapter.listChildren).mockImplementation(async (path) =>
748
+ path === 'a/sub' ? [{ ...inA, parentPath: 'a/sub' }] : [],
749
+ )
750
+ const wrapper = await setup({ adapter, view: undefined, initialPath: 'a/sub' })
751
+ await row(wrapper, inA.path).trigger('click')
752
+ await flushPromises()
753
+ expect(wrapper.get('.mint-picker__metadata dd:last-of-type').text()).toBe(mountA.name)
754
+ })
755
+
756
+ it('should add local files as a source after the mounts', async () => {
757
+ const wrapper = await setup({ adapter: mountAdapter(), sources: ['server', 'localFile'] })
758
+ expect(sources(wrapper).at(-1)!.text()).toBe('Local files')
759
+ })
760
+ })
761
+
762
+ describe('formatModified', () => {
763
+ const now = new Date(2026, 8, 25)
764
+ it('should show month, day and time within the current year', () => {
765
+ expect(formatModified('2026-09-24T14:32:00', now)).toBe('09-24 14:32')
766
+ })
767
+
768
+ it('should show the full date outside the current year', () => {
769
+ expect(formatModified('2025-01-02T08:00:00', now)).toBe('2025-01-02')
770
+ })
771
+
772
+ it('should list the newest folder first when opened', async () => {
773
+ const wrapper = await setup({
774
+ adapter: {
775
+ ...adapter(),
776
+ listRoot: vi.fn(async () => [
777
+ { ...folder, modifiedAt: '2026-01-01T00:00:00Z' },
778
+ { ...other, modifiedAt: '2026-09-29T00:00:00Z' },
779
+ ]),
780
+ },
781
+ })
782
+ expect(wrapper.findAll('[role="treeitem"]').map((item) => item.attributes('data-path'))).toEqual([
783
+ other.path, folder.path,
784
+ ])
785
+ })
786
+
787
+ it('should reorder rows by name when Name A–Z is chosen from the sort menu', async () => {
788
+ const wrapper = await setup({ defaultSort: 'name-desc' })
789
+ await wrapper.get('.mint-picker__sort').trigger('click')
790
+ await wrapper.findAll('[role="menuitemradio"]').find((item) => item.text() === 'Name A–Z')!.trigger('click')
791
+ expect(wrapper.findAll('[role="treeitem"]').map((item) => item.attributes('data-path'))).toEqual([
792
+ other.path, folder.path,
793
+ ])
794
+ })
795
+
796
+ it('should label the sort trigger with the active order', async () => {
797
+ const wrapper = await setup()
798
+ expect(wrapper.get('.mint-picker__sort').text()).toContain('Newest first')
799
+ })
800
+
801
+ it('should tell the user when search results are partial', async () => {
802
+ vi.useFakeTimers()
803
+ const base = adapter()
804
+ const wrapper = await setup({
805
+ adapter: { ...base, search: vi.fn(async () => ({ nodes: [one], truncated: true })) },
806
+ })
807
+ await wrapper.get('[aria-label="Search folders and files"]').setValue('sample')
808
+ await vi.advanceTimersByTimeAsync(400)
809
+ await flushPromises()
810
+ expect(wrapper.get('.mint-picker__truncated').text()).toContain('first 1')
811
+ })
812
+
813
+ it('should still list the partial search results', async () => {
814
+ vi.useFakeTimers()
815
+ const wrapper = await setup({
816
+ adapter: { ...adapter(), search: vi.fn(async () => ({ nodes: [one], truncated: true })) },
817
+ })
818
+ await wrapper.get('[aria-label="Search folders and files"]').setValue('sample')
819
+ await vi.advanceTimersByTimeAsync(400)
820
+ await flushPromises()
821
+ expect(wrapper.findAll('[role="treeitem"]').map((item) => item.attributes('data-path'))).toEqual([one.path])
822
+ })
823
+
824
+ it('should say the search stopped early when a truncated search found nothing', async () => {
825
+ vi.useFakeTimers()
826
+ const wrapper = await setup({
827
+ adapter: { ...adapter(), search: vi.fn(async () => ({ nodes: [], truncated: true })) },
828
+ })
829
+ await wrapper.get('[aria-label="Search folders and files"]').setValue('sample')
830
+ await vi.advanceTimersByTimeAsync(400)
831
+ await flushPromises()
832
+ expect(wrapper.get('.mint-picker__empty').text()).toContain('stopped')
833
+ })
834
+ })
@@ -0,0 +1,15 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import FileUploader from '../../components/FileUploader.vue'
4
+
5
+ describe('FileUploader', () => {
6
+ it('should name the accepted formats in the prompt when accept is set', () => {
7
+ const wrapper = mount(FileUploader, { props: { accept: '.raw, .mzML' } })
8
+ expect(wrapper.get('.mint-file-uploader__text').text()).toBe('Drop RAW, MZML or click')
9
+ })
10
+
11
+ it('should prompt for any file when accept is not set', () => {
12
+ const wrapper = mount(FileUploader)
13
+ expect(wrapper.get('.mint-file-uploader__text').text()).toBe('Drop any file or click')
14
+ })
15
+ })
@@ -0,0 +1,96 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import FitPanel from '../../components/FitPanel.vue'
4
+ import type { FitResultSummary, FitSeries } from '../../types'
5
+
6
+ const results: FitResultSummary[] = [
7
+ { label: 'IC50 (nM)', value: '42.7' },
8
+ { label: 'Hill slope', value: '-1.12', variant: 'success' },
9
+ { label: 'R²', value: '0.982', variant: 'success', verdict: true },
10
+ ]
11
+
12
+ function mountCompleted() {
13
+ return mount(FitPanel, { props: { state: 'completed', results } })
14
+ }
15
+
16
+ describe('FitPanel', () => {
17
+ it('should list results as table rows when they carry no verdict, even with a variant', () => {
18
+ expect(mountCompleted().findAll('.mint-fit-panel__result-row').map(row => row.text()))
19
+ .toEqual(['IC50 (nM)42.7', 'Hill slope-1.12'])
20
+ })
21
+
22
+ it('should move a result into the check row when it is marked as a verdict', () => {
23
+ expect(mountCompleted().get('.mint-fit-panel__check--success').text()).toBe('R² 0.982')
24
+ })
25
+ })
26
+
27
+ const parameters: FitResultSummary[] = [
28
+ { label: 'IC50', unit: 'nM', value: '631', ci: '512 – 778' },
29
+ { label: 'Hill slope', value: '1.10', ci: '0.94 – 1.26' },
30
+ ]
31
+
32
+ const series: FitSeries[] = [
33
+ { label: 'Control', results: parameters },
34
+ { label: 'Treatment A', color: 'var(--mint-sample-4)', results: [{ label: 'IC50', unit: 'nM', value: '39.8' }] },
35
+ ]
36
+
37
+ describe('FitPanel parameter table (9b)', () => {
38
+ it('should render the unit in its own element when a result has a unit', () => {
39
+ const wrapper = mount(FitPanel, { props: { state: 'completed', results: parameters } })
40
+ expect(wrapper.get('.mint-fit-panel__result-unit').text()).toBe('nM')
41
+ })
42
+
43
+ it('should render a header row when results are shown', () => {
44
+ const wrapper = mount(FitPanel, { props: { state: 'completed', results: parameters } })
45
+ expect(wrapper.get('.mint-fit-panel__result-head').text()).toBe('ParameterValue95% CI')
46
+ })
47
+
48
+ it('should render the confidence interval when a result has one', () => {
49
+ const wrapper = mount(FitPanel, { props: { state: 'completed', results: parameters } })
50
+ expect(wrapper.get('.mint-fit-panel__result-ci').text()).toBe('512 – 778')
51
+ })
52
+
53
+ it('should omit the CI column when no result has a confidence interval', () => {
54
+ expect(mountCompleted().get('.mint-fit-panel__result-head').text()).toBe('ParameterValue')
55
+ })
56
+
57
+ it('should use custom column labels when columnLabels is set', () => {
58
+ const wrapper = mount(FitPanel, {
59
+ props: { state: 'completed', results: parameters, columnLabels: { parameter: '参数', value: '值' } },
60
+ })
61
+ expect(wrapper.get('.mint-fit-panel__result-head').text()).toBe('参数值95% CI')
62
+ })
63
+ })
64
+
65
+ describe('FitPanel series switch (9b)', () => {
66
+ it('should show the first series when series are given', () => {
67
+ const wrapper = mount(FitPanel, { props: { state: 'completed', series } })
68
+ expect(wrapper.findAll('.mint-fit-panel__result-row')).toHaveLength(2)
69
+ })
70
+
71
+ it('should show another series when its segment is selected', async () => {
72
+ const wrapper = mount(FitPanel, { props: { state: 'completed', series } })
73
+ await wrapper.findAll('[role="radio"]')[1].trigger('click')
74
+ expect(wrapper.findAll('.mint-fit-panel__result-row')).toHaveLength(1)
75
+ })
76
+
77
+ it('should emit the selected series index when a segment is selected', async () => {
78
+ const wrapper = mount(FitPanel, { props: { state: 'completed', series } })
79
+ await wrapper.findAll('[role="radio"]')[1].trigger('click')
80
+ expect(wrapper.emitted('update:activeSeries')?.[0]).toEqual([1])
81
+ })
82
+
83
+ it('should color a series segment with the group palette when the series has no color', () => {
84
+ const wrapper = mount(FitPanel, { props: { state: 'completed', series } })
85
+ expect(wrapper.get('.mint-segmented-control__swatch').attributes('style')).toContain('var(--mint-sample-1)')
86
+ })
87
+
88
+ it('should render no series switch when series are not given', () => {
89
+ expect(mountCompleted().find('.mint-fit-panel__series').exists()).toBe(false)
90
+ })
91
+
92
+ it('should keep the series switch when the active series has no results', () => {
93
+ const wrapper = mount(FitPanel, { props: { state: 'completed', series: [{ label: 'Empty', results: [] }, ...series] } })
94
+ expect(wrapper.find('.mint-fit-panel__series').exists()).toBe(true)
95
+ })
96
+ })
@@ -0,0 +1,97 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import FormulaInput from '../../components/FormulaInput.vue'
4
+
5
+ function mountFormula(props: Record<string, unknown> = {}) {
6
+ return mount(FormulaInput, { props: { modelValue: 'C6H12O6', ...props } })
7
+ }
8
+
9
+ describe('FormulaInput inline rendering (4b)', () => {
10
+ it('should render the formula inside the field when blurred', () => {
11
+ const wrapper = mountFormula()
12
+ expect(wrapper.find('.mint-formula-input__rendered').exists()).toBe(true)
13
+ })
14
+
15
+ it('should render counts as subscripts when blurred', () => {
16
+ const wrapper = mountFormula()
17
+ expect(wrapper.findAll('.mint-formula-input__sub').map(n => n.text())).toEqual(['6', '12', '6'])
18
+ })
19
+
20
+ it('should show the raw text instead of the rendering when focused', async () => {
21
+ const wrapper = mountFormula()
22
+ await wrapper.find('input').trigger('focus')
23
+ expect(wrapper.find('.mint-formula-input__rendered').exists()).toBe(false)
24
+ })
25
+
26
+ it('should render the formula again when blurred after focus', async () => {
27
+ const wrapper = mountFormula()
28
+ await wrapper.find('input').trigger('focus')
29
+ await wrapper.find('input').trigger('blur')
30
+ expect(wrapper.find('.mint-formula-input__rendered').exists()).toBe(true)
31
+ })
32
+
33
+ it('should not render the formula when showPreview is false', () => {
34
+ const wrapper = mountFormula({ showPreview: false })
35
+ expect(wrapper.find('.mint-formula-input__rendered').exists()).toBe(false)
36
+ })
37
+
38
+ it('should render the hydrate coefficient full size when blurred', () => {
39
+ const wrapper = mountFormula({ modelValue: 'CuSO4·5H2O' })
40
+ expect(wrapper.findAll('.mint-formula-input__sub').map(n => n.text())).toEqual(['4', '2'])
41
+ })
42
+ })
43
+
44
+ describe('FormulaInput molecular weight segment (4b)', () => {
45
+ it('should show MW, the value and g/mol as text when the formula is valid', () => {
46
+ const wrapper = mountFormula()
47
+ expect(wrapper.find('.mint-formula-input__mw').text()).toBe('MW 180.16 g/mol')
48
+ })
49
+
50
+ it('should show a dash for the value when the field is empty', () => {
51
+ const wrapper = mountFormula({ modelValue: '' })
52
+ expect(wrapper.find('.mint-formula-input__mw-value').text()).toBe('—')
53
+ })
54
+
55
+ it('should hide the segment when showMW is false', () => {
56
+ const wrapper = mountFormula({ showMW: false })
57
+ expect(wrapper.find('.mint-formula-input__mw').exists()).toBe(false)
58
+ })
59
+
60
+ it('should emit the molecular weight when the formula changes', async () => {
61
+ const wrapper = mountFormula({ modelValue: '' })
62
+ await wrapper.find('input').setValue('H2O')
63
+ expect(wrapper.emitted('mw')?.[0]?.[0]).toBeCloseTo(18.015, 2)
64
+ })
65
+ })
66
+
67
+ describe('FormulaInput error state (4b)', () => {
68
+ it('should put the field in the error state when a symbol is unknown', () => {
69
+ const wrapper = mountFormula({ modelValue: 'C6Xx2' })
70
+ expect(wrapper.classes()).toContain('mint-formula-input--error')
71
+ })
72
+
73
+ it('should mark the input invalid when a symbol is unknown', () => {
74
+ const wrapper = mountFormula({ modelValue: 'C6Xx2' })
75
+ expect(wrapper.find('input').attributes('aria-invalid')).toBe('true')
76
+ })
77
+
78
+ it('should name the unknown symbol when parsing fails', () => {
79
+ const wrapper = mountFormula({ modelValue: 'C6Xx2' })
80
+ expect(wrapper.find('.mint-formula-input__error-text').text()).toBe('Unknown element: Xx')
81
+ })
82
+
83
+ it('should show the raw text when the formula is invalid', () => {
84
+ const wrapper = mountFormula({ modelValue: 'C6Xx2' })
85
+ expect(wrapper.find('.mint-formula-input__rendered').exists()).toBe(false)
86
+ })
87
+
88
+ it('should accept an element outside the common set when the symbol is real', () => {
89
+ const wrapper = mountFormula({ modelValue: 'SeO2' })
90
+ expect(wrapper.find('input').attributes('aria-invalid')).toBeUndefined()
91
+ })
92
+
93
+ it('should accept a trailing charge when the formula is an ion', () => {
94
+ const wrapper = mountFormula({ modelValue: 'SO4^2-' })
95
+ expect(wrapper.find('input').attributes('aria-invalid')).toBeUndefined()
96
+ })
97
+ })