@morscherlab/mint-sdk 1.0.0-beta.1 → 1.0.0-beta.3

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 (421) hide show
  1. package/README.md +218 -6
  2. package/dist/__tests__/components/ActionItem.test.d.ts +1 -0
  3. package/dist/__tests__/components/AppAvatarMenu.test.d.ts +1 -0
  4. package/dist/__tests__/components/AppPageSelector.test.d.ts +1 -0
  5. package/dist/__tests__/components/AppPillNav.test.d.ts +1 -0
  6. package/dist/__tests__/components/AppPluginSwitcher.test.d.ts +1 -0
  7. package/dist/__tests__/components/AppToastContainer.test.d.ts +1 -0
  8. package/dist/__tests__/components/BaseRadioGroup.test.d.ts +1 -0
  9. package/dist/__tests__/components/BaseSelect.test.d.ts +1 -0
  10. package/dist/__tests__/components/BaseTabs.test.d.ts +1 -0
  11. package/dist/__tests__/components/BatchProgressList.test.d.ts +1 -0
  12. package/dist/__tests__/components/BioTemplateExperimentWorkspaceView.test.d.ts +1 -0
  13. package/dist/__tests__/components/BioTemplatePackWorkspaceView.test.d.ts +1 -0
  14. package/dist/__tests__/components/BioTemplatePresetWorkspaceView.test.d.ts +1 -0
  15. package/dist/__tests__/components/BioTemplateRenderer.test.d.ts +1 -0
  16. package/dist/__tests__/components/Breadcrumb.test.d.ts +1 -0
  17. package/dist/__tests__/components/CalendarGridPanel.test.d.ts +1 -0
  18. package/dist/__tests__/components/ConcentrationInput.test.d.ts +1 -0
  19. package/dist/__tests__/components/ControlWorkspaceView.test.d.ts +1 -0
  20. package/dist/__tests__/components/DatePicker.test.d.ts +1 -0
  21. package/dist/__tests__/components/DateTimePicker.test.d.ts +1 -0
  22. package/dist/__tests__/components/EmptyState.test.d.ts +1 -0
  23. package/dist/__tests__/components/ExperimentPopover.test.d.ts +1 -0
  24. package/dist/__tests__/components/FormBuilder.test.d.ts +1 -0
  25. package/dist/__tests__/components/FormCompatibility.test.d.ts +1 -0
  26. package/dist/__tests__/components/GroupAssigner.test.d.ts +1 -0
  27. package/dist/__tests__/components/GroupingModal.test.d.ts +1 -0
  28. package/dist/__tests__/components/MultiSelect.test.d.ts +1 -0
  29. package/dist/__tests__/components/PluginIcon.test.d.ts +1 -0
  30. package/dist/__tests__/components/ProtocolStepEditor.test.d.ts +1 -0
  31. package/dist/__tests__/components/ReagentList.test.d.ts +1 -0
  32. package/dist/__tests__/components/SampleHierarchyTree.test.d.ts +1 -0
  33. package/dist/__tests__/components/SampleSelector.test.d.ts +1 -0
  34. package/dist/__tests__/components/SegmentedControl.test.d.ts +1 -0
  35. package/dist/__tests__/components/SettingsButton.test.d.ts +1 -0
  36. package/dist/__tests__/components/SettingsModal.test.d.ts +1 -0
  37. package/dist/__tests__/components/TagsInput.test.d.ts +1 -0
  38. package/dist/__tests__/components/ThemeToggle.test.d.ts +1 -0
  39. package/dist/__tests__/components/TimePicker.test.d.ts +1 -0
  40. package/dist/__tests__/composables/useBioTemplatePackWorkspace.test.d.ts +1 -0
  41. package/dist/__tests__/composables/useBioTemplatePresetWorkspace.test.d.ts +1 -0
  42. package/dist/__tests__/composables/useBioTemplateWorkspace.test.d.ts +1 -0
  43. package/dist/__tests__/composables/useCalendarGrid.test.d.ts +1 -0
  44. package/dist/__tests__/composables/useControlSchema.test.d.ts +1 -0
  45. package/dist/__tests__/composables/useDebouncedWatch.test.d.ts +1 -0
  46. package/dist/__tests__/composables/useDropdownState.test.d.ts +1 -0
  47. package/dist/__tests__/composables/useEventListener.test.d.ts +1 -0
  48. package/dist/__tests__/composables/useExpansionSet.test.d.ts +1 -0
  49. package/dist/__tests__/composables/useExperimentData.test.d.ts +1 -0
  50. package/dist/__tests__/composables/useExperimentSelector.test.d.ts +1 -0
  51. package/dist/__tests__/composables/useGroupAssignment.test.d.ts +1 -0
  52. package/dist/__tests__/composables/useListSelection.test.d.ts +1 -0
  53. package/dist/__tests__/composables/usePluginClient.test.d.ts +1 -0
  54. package/dist/__tests__/composables/usePluginConfig.test.d.ts +1 -0
  55. package/dist/__tests__/composables/useRequestSyncState.test.d.ts +1 -0
  56. package/dist/__tests__/composables/useSampleGroups.test.d.ts +1 -0
  57. package/dist/__tests__/composables/useSelectionLimit.test.d.ts +1 -0
  58. package/dist/__tests__/composables/useSortedItems.test.d.ts +1 -0
  59. package/dist/__tests__/composables/useTemplateCollection.test.d.ts +1 -0
  60. package/dist/__tests__/composables/useTextSearch.test.d.ts +1 -0
  61. package/dist/__tests__/composables/useTheme.test.d.ts +1 -0
  62. package/dist/__tests__/composables/useTimeUtils.test.d.ts +1 -0
  63. package/dist/__tests__/docs/frontendDocsCatalog.test.d.ts +1 -0
  64. package/dist/__tests__/templates/templates.test.d.ts +1 -0
  65. package/dist/{auth-DsI0rQ7_.js → auth-QQj2kkze.js} +12 -5
  66. package/dist/auth-QQj2kkze.js.map +1 -0
  67. package/dist/components/ActionItem.vue.d.ts +32 -0
  68. package/dist/components/AppAvatarMenu.vue.d.ts +2 -7
  69. package/dist/components/AppPageSelector.vue.d.ts +3 -6
  70. package/dist/components/AppPillNav.vue.d.ts +2 -2
  71. package/dist/components/AppSidebar.vue.d.ts +56 -3
  72. package/dist/components/AppToastContainer.vue.d.ts +2 -0
  73. package/dist/components/AppTopBar.vue.d.ts +43 -10
  74. package/dist/components/BaseButton.vue.d.ts +2 -2
  75. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  76. package/dist/components/BaseInput.vue.d.ts +2 -2
  77. package/dist/components/BasePill.vue.d.ts +3 -3
  78. package/dist/components/BaseRadioGroup.vue.d.ts +4 -4
  79. package/dist/components/BaseSelect.vue.d.ts +4 -4
  80. package/dist/components/BaseSlider.vue.d.ts +1 -1
  81. package/dist/components/BaseTabs.vue.d.ts +2 -2
  82. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  83. package/dist/components/BaseToggle.vue.d.ts +1 -1
  84. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +117 -0
  85. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +92 -0
  86. package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +82 -0
  87. package/dist/components/BioTemplateRenderer.vue.d.ts +29 -0
  88. package/dist/components/Breadcrumb.vue.d.ts +2 -2
  89. package/dist/components/Calendar.vue.d.ts +1 -1
  90. package/dist/components/CalendarGridPanel.vue.d.ts +25 -0
  91. package/dist/components/CollapsibleCard.vue.d.ts +1 -1
  92. package/dist/components/ColorSlider.vue.d.ts +1 -1
  93. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  94. package/dist/components/ConfirmDialog.vue.d.ts +2 -2
  95. package/dist/components/ControlWorkspaceView.vue.d.ts +130 -0
  96. package/dist/components/DatePicker.vue.d.ts +2 -2
  97. package/dist/components/DateTimePicker.vue.d.ts +3 -3
  98. package/dist/components/DropdownButton.vue.d.ts +4 -4
  99. package/dist/components/EmptyState.vue.d.ts +1 -2
  100. package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
  101. package/dist/components/ExperimentTimeline.vue.d.ts +2 -2
  102. package/dist/components/FileUploader.vue.d.ts +2 -2
  103. package/dist/components/FitPanel.vue.d.ts +1 -1
  104. package/dist/components/FormActions.vue.d.ts +4 -4
  105. package/dist/components/FormBuilder.vue.d.ts +22 -8
  106. package/dist/components/FormFieldRenderer.vue.d.ts +7 -10
  107. package/dist/components/FormSection.vue.d.ts +11 -24
  108. package/dist/components/FormulaInput.vue.d.ts +2 -2
  109. package/dist/components/IconButton.vue.d.ts +1 -1
  110. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  111. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  112. package/dist/components/MultiSelect.vue.d.ts +3 -3
  113. package/dist/components/NumberInput.vue.d.ts +2 -2
  114. package/dist/components/PluginIcon.vue.d.ts +11 -0
  115. package/dist/components/ProgressBar.vue.d.ts +2 -2
  116. package/dist/components/ProtocolStepEditor.vue.d.ts +3 -1
  117. package/dist/components/RackEditor.vue.d.ts +2 -2
  118. package/dist/components/ReagentEditor.vue.d.ts +1 -1
  119. package/dist/components/ResourceCard.vue.d.ts +1 -1
  120. package/dist/components/SampleLegend.vue.d.ts +2 -2
  121. package/dist/components/SampleSelector.vue.d.ts +1 -1
  122. package/dist/components/ScheduleCalendar.vue.d.ts +2 -2
  123. package/dist/components/ScientificNumber.vue.d.ts +1 -1
  124. package/dist/components/SegmentedControl.vue.d.ts +3 -3
  125. package/dist/components/SequenceInput.vue.d.ts +3 -3
  126. package/dist/components/SettingsButton.vue.d.ts +2 -2
  127. package/dist/components/SettingsModal.vue.d.ts +32 -4
  128. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  129. package/dist/components/TagsInput.vue.d.ts +3 -2
  130. package/dist/components/TimePicker.vue.d.ts +3 -3
  131. package/dist/components/TimeRangeInput.vue.d.ts +2 -2
  132. package/dist/components/UnitInput.vue.d.ts +2 -2
  133. package/dist/components/WellPlate.vue.d.ts +8 -8
  134. package/dist/components/index.d.ts +12 -1
  135. package/dist/components/index.js +3 -3
  136. package/dist/components/internal/FormFieldRendererInternal.vue.d.ts +31 -0
  137. package/dist/components/internal/FormSectionRenderer.vue.d.ts +43 -0
  138. package/dist/{components-CzbQQPCb.js → components-D_Sr0adg.js} +9629 -8647
  139. package/dist/components-D_Sr0adg.js.map +1 -0
  140. package/dist/composables/index.d.ts +21 -2
  141. package/dist/composables/index.js +4 -3
  142. package/dist/composables/platformContextHelpers.d.ts +14 -0
  143. package/dist/composables/useBioTemplateComponents.d.ts +20 -0
  144. package/dist/composables/useBioTemplateControls.d.ts +6 -0
  145. package/dist/composables/useBioTemplatePackWorkspace.d.ts +45 -0
  146. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +74 -0
  147. package/dist/composables/useBioTemplateWorkspace.d.ts +50 -0
  148. package/dist/composables/useCalendarGrid.d.ts +26 -0
  149. package/dist/composables/useControlSchema.d.ts +321 -0
  150. package/dist/composables/useDebouncedWatch.d.ts +20 -0
  151. package/dist/composables/useDropdownState.d.ts +19 -0
  152. package/dist/composables/useEventListener.d.ts +13 -0
  153. package/dist/composables/useExpansionSet.d.ts +21 -0
  154. package/dist/composables/useExperimentData.d.ts +10 -0
  155. package/dist/composables/useExperimentSave.d.ts +31 -2
  156. package/dist/composables/useExperimentSelector.d.ts +20 -0
  157. package/dist/composables/useForm.d.ts +2 -0
  158. package/dist/composables/useGroupAssignment.d.ts +31 -0
  159. package/dist/composables/useListSelection.d.ts +35 -0
  160. package/dist/composables/usePlatformContext.d.ts +24 -3
  161. package/dist/composables/usePluginApi.d.ts +7 -14
  162. package/dist/composables/usePluginClient.d.ts +109 -0
  163. package/dist/composables/usePluginConfig.d.ts +12 -0
  164. package/dist/composables/useRequestSyncState.d.ts +34 -0
  165. package/dist/composables/useSampleGroups.d.ts +32 -0
  166. package/dist/composables/useSelectionLimit.d.ts +17 -0
  167. package/dist/composables/useSortedItems.d.ts +32 -0
  168. package/dist/composables/useTemplateCollection.d.ts +58 -0
  169. package/dist/composables/useTextSearch.d.ts +18 -0
  170. package/dist/composables/useTimeUtils.d.ts +8 -0
  171. package/dist/{composables-BXklV5ii.js → composables-C3dpXQN5.js} +228 -146
  172. package/dist/composables-C3dpXQN5.js.map +1 -0
  173. package/dist/index.d.ts +12 -3
  174. package/dist/index.js +6 -5
  175. package/dist/install.d.ts +7 -2
  176. package/dist/install.js +2 -2
  177. package/dist/install.js.map +1 -1
  178. package/dist/stores/auth.d.ts +1 -1
  179. package/dist/stores/index.js +1 -1
  180. package/dist/stores/settings.d.ts +4 -1
  181. package/dist/styles.css +5255 -5654
  182. package/dist/templates/adapters.d.ts +43 -0
  183. package/dist/templates/builders.d.ts +63 -0
  184. package/dist/templates/catalog.d.ts +188 -0
  185. package/dist/templates/componentBindings.d.ts +58 -0
  186. package/dist/templates/controlSchemas.d.ts +25 -0
  187. package/dist/templates/index.d.ts +15 -0
  188. package/dist/templates/index.js +2 -0
  189. package/dist/templates/lookup.d.ts +4 -0
  190. package/dist/templates/packs.d.ts +18 -0
  191. package/dist/templates/presets.d.ts +90 -0
  192. package/dist/templates/types.d.ts +531 -0
  193. package/dist/templates-50NPjaxL.js +9333 -0
  194. package/dist/templates-50NPjaxL.js.map +1 -0
  195. package/dist/types/components.d.ts +62 -1
  196. package/dist/types/form-builder.d.ts +6 -8
  197. package/dist/types/index.d.ts +2 -2
  198. package/dist/types/platform.d.ts +8 -1
  199. package/dist/useScheduleDrag-D4oWdh41.js +4371 -0
  200. package/dist/useScheduleDrag-D4oWdh41.js.map +1 -0
  201. package/dist/utils/formModelSync.d.ts +5 -0
  202. package/dist/utils/items.d.ts +8 -0
  203. package/dist/utils/options.d.ts +6 -0
  204. package/dist/utils/pluginIcon.d.ts +9 -0
  205. package/package.json +7 -2
  206. package/src/__tests__/components/ActionItem.test.ts +99 -0
  207. package/src/__tests__/components/AppAvatarMenu.test.ts +27 -0
  208. package/src/__tests__/components/AppPageSelector.test.ts +134 -0
  209. package/src/__tests__/components/AppPillNav.test.ts +78 -0
  210. package/src/__tests__/components/AppPluginSwitcher.test.ts +44 -0
  211. package/src/__tests__/components/AppSidebar.test.ts +370 -0
  212. package/src/__tests__/components/AppToastContainer.test.ts +48 -0
  213. package/src/__tests__/components/AppTopBar.test.ts +414 -13
  214. package/src/__tests__/components/BaseRadioGroup.test.ts +25 -0
  215. package/src/__tests__/components/BaseSelect.test.ts +21 -0
  216. package/src/__tests__/components/BaseTabs.test.ts +25 -0
  217. package/src/__tests__/components/BatchProgressList.test.ts +52 -0
  218. package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +153 -0
  219. package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +161 -0
  220. package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +281 -0
  221. package/src/__tests__/components/BioTemplateRenderer.test.ts +71 -0
  222. package/src/__tests__/components/Breadcrumb.test.ts +23 -0
  223. package/src/__tests__/components/CalendarGridPanel.test.ts +36 -0
  224. package/src/__tests__/components/ConcentrationInput.test.ts +45 -0
  225. package/src/__tests__/components/ControlWorkspaceView.test.ts +1031 -0
  226. package/src/__tests__/components/DataFrame.test.ts +11 -0
  227. package/src/__tests__/components/DatePicker.test.ts +45 -0
  228. package/src/__tests__/components/DateTimePicker.test.ts +48 -0
  229. package/src/__tests__/components/DropdownButton.test.ts +23 -0
  230. package/src/__tests__/components/EmptyState.test.ts +23 -0
  231. package/src/__tests__/components/ExperimentPopover.test.ts +56 -0
  232. package/src/__tests__/components/FormBuilder.test.ts +296 -0
  233. package/src/__tests__/components/FormCompatibility.test.ts +94 -0
  234. package/src/__tests__/components/GroupAssigner.test.ts +30 -0
  235. package/src/__tests__/components/GroupingModal.test.ts +73 -0
  236. package/src/__tests__/components/MultiSelect.test.ts +48 -0
  237. package/src/__tests__/components/PluginIcon.test.ts +119 -0
  238. package/src/__tests__/components/ProtocolStepEditor.test.ts +33 -0
  239. package/src/__tests__/components/ReagentList.test.ts +82 -0
  240. package/src/__tests__/components/SampleHierarchyTree.test.ts +53 -0
  241. package/src/__tests__/components/SampleSelector.test.ts +60 -0
  242. package/src/__tests__/components/SegmentedControl.test.ts +24 -0
  243. package/src/__tests__/components/SettingsButton.test.ts +44 -0
  244. package/src/__tests__/components/SettingsModal.test.ts +296 -0
  245. package/src/__tests__/components/TagsInput.test.ts +75 -0
  246. package/src/__tests__/components/ThemeToggle.test.ts +47 -0
  247. package/src/__tests__/components/TimePicker.test.ts +38 -0
  248. package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +122 -0
  249. package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +199 -0
  250. package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +99 -0
  251. package/src/__tests__/composables/useCalendarGrid.test.ts +38 -0
  252. package/src/__tests__/composables/useControlSchema.test.ts +919 -0
  253. package/src/__tests__/composables/useDebouncedWatch.test.ts +93 -0
  254. package/src/__tests__/composables/useDropdownState.test.ts +95 -0
  255. package/src/__tests__/composables/useEventListener.test.ts +116 -0
  256. package/src/__tests__/composables/useExpansionSet.test.ts +62 -0
  257. package/src/__tests__/composables/useExperimentData.test.ts +4 -0
  258. package/src/__tests__/composables/useExperimentSave.test.ts +203 -8
  259. package/src/__tests__/composables/useExperimentSelector.test.ts +164 -0
  260. package/src/__tests__/composables/useForm.test.ts +58 -0
  261. package/src/__tests__/composables/useFormBuilder.test.ts +77 -0
  262. package/src/__tests__/composables/useGroupAssignment.test.ts +73 -0
  263. package/src/__tests__/composables/useListSelection.test.ts +66 -0
  264. package/src/__tests__/composables/usePluginClient.test.ts +444 -0
  265. package/src/__tests__/composables/usePluginConfig.test.ts +5 -0
  266. package/src/__tests__/composables/useRequestSyncState.test.ts +92 -0
  267. package/src/__tests__/composables/useSampleGroups.test.ts +66 -0
  268. package/src/__tests__/composables/useSelectionLimit.test.ts +41 -0
  269. package/src/__tests__/composables/useSortedItems.test.ts +87 -0
  270. package/src/__tests__/composables/useTemplateCollection.test.ts +147 -0
  271. package/src/__tests__/composables/useTextSearch.test.ts +55 -0
  272. package/src/__tests__/composables/useTheme.test.ts +91 -0
  273. package/src/__tests__/composables/useTimeUtils.test.ts +35 -0
  274. package/src/__tests__/docs/frontendDocsCatalog.test.ts +229 -0
  275. package/src/__tests__/fixtures/templates/dose-response.json +81 -0
  276. package/src/__tests__/fixtures/templates/plate-map.json +54 -0
  277. package/src/__tests__/fixtures/templates/qpcr-plate.json +96 -0
  278. package/src/__tests__/fixtures/templates/sample-sheet.json +71 -0
  279. package/src/__tests__/templates/templates.test.ts +1043 -0
  280. package/src/components/ActionItem.vue +82 -0
  281. package/src/components/AppAvatarMenu.vue +15 -69
  282. package/src/components/AppLayout.story.vue +25 -25
  283. package/src/components/AppPageSelector.vue +63 -94
  284. package/src/components/AppPillNav.vue +44 -39
  285. package/src/components/AppPluginSwitcher.vue +41 -145
  286. package/src/components/AppSidebar.story.vue +94 -0
  287. package/src/components/AppSidebar.vue +187 -12
  288. package/src/components/{ToastNotification.story.vue → AppToastContainer.story.vue} +6 -6
  289. package/src/components/AppToastContainer.vue +62 -0
  290. package/src/components/AppTopBar.story.vue +7 -30
  291. package/src/components/AppTopBar.vue +283 -84
  292. package/src/components/BaseModal.vue +3 -5
  293. package/src/components/BaseRadioGroup.vue +7 -3
  294. package/src/components/BaseSelect.vue +11 -7
  295. package/src/components/BaseTabs.vue +6 -4
  296. package/src/components/BatchProgressList.vue +5 -8
  297. package/src/components/BioTemplateExperimentWorkspaceView.story.vue +123 -0
  298. package/src/components/BioTemplateExperimentWorkspaceView.vue +337 -0
  299. package/src/components/BioTemplatePackWorkspaceView.story.vue +107 -0
  300. package/src/components/BioTemplatePackWorkspaceView.vue +176 -0
  301. package/src/components/BioTemplatePresetWorkspaceView.story.vue +151 -0
  302. package/src/components/BioTemplatePresetWorkspaceView.vue +392 -0
  303. package/src/components/BioTemplateRenderer.story.vue +57 -0
  304. package/src/components/BioTemplateRenderer.vue +269 -0
  305. package/src/components/Breadcrumb.vue +14 -8
  306. package/src/components/CalendarGridPanel.vue +120 -0
  307. package/src/components/ConcentrationInput.vue +27 -64
  308. package/src/components/ControlWorkspaceView.story.vue +336 -0
  309. package/src/components/ControlWorkspaceView.vue +347 -0
  310. package/src/components/DataFrame.vue +34 -50
  311. package/src/components/DatePicker.vue +59 -192
  312. package/src/components/DateTimePicker.vue +50 -171
  313. package/src/components/DropdownButton.vue +14 -32
  314. package/src/components/EmptyState.vue +4 -2
  315. package/src/components/ExperimentPopover.vue +5 -22
  316. package/src/components/FormBuilder.vue +124 -27
  317. package/src/components/FormFieldRenderer.vue +15 -38
  318. package/src/components/FormSection.vue +20 -73
  319. package/src/components/GroupAssigner.vue +24 -56
  320. package/src/components/GroupingModal.story.vue +3 -3
  321. package/src/components/GroupingModal.vue +30 -391
  322. package/src/components/MultiSelect.vue +17 -12
  323. package/src/components/PlateMapEditor.vue +3 -8
  324. package/src/components/PluginIcon.story.vue +71 -0
  325. package/src/components/PluginIcon.vue +68 -0
  326. package/src/components/ProtocolStepEditor.vue +13 -22
  327. package/src/components/ReagentList.vue +25 -33
  328. package/src/components/SampleHierarchyTree.vue +12 -23
  329. package/src/components/SampleSelector.vue +42 -122
  330. package/src/components/SegmentedControl.vue +7 -3
  331. package/src/components/SettingsButton.story.vue +1 -1
  332. package/src/components/SettingsButton.vue +15 -27
  333. package/src/components/SettingsModal.story.vue +337 -45
  334. package/src/components/SettingsModal.vue +344 -66
  335. package/src/components/TagsInput.vue +29 -14
  336. package/src/components/ThemeToggle.vue +9 -7
  337. package/src/components/TimePicker.vue +19 -41
  338. package/src/components/ToastNotification.vue +4 -57
  339. package/src/components/Tooltip.vue +7 -12
  340. package/src/components/WellEditPopup.vue +3 -8
  341. package/src/components/WellPlate.vue +4 -10
  342. package/src/components/index.ts +12 -1
  343. package/src/components/internal/FormFieldRendererInternal.vue +50 -0
  344. package/src/components/internal/FormSectionRenderer.vue +78 -0
  345. package/src/composables/index.ts +212 -0
  346. package/src/composables/platformContextHelpers.ts +74 -0
  347. package/src/composables/useBioTemplateComponents.ts +93 -0
  348. package/src/composables/useBioTemplateControls.ts +41 -0
  349. package/src/composables/useBioTemplatePackWorkspace.ts +181 -0
  350. package/src/composables/useBioTemplatePresetWorkspace.ts +337 -0
  351. package/src/composables/useBioTemplateWorkspace.ts +139 -0
  352. package/src/composables/useCalendarGrid.ts +140 -0
  353. package/src/composables/useControlSchema.ts +1274 -0
  354. package/src/composables/useDebouncedWatch.ts +119 -0
  355. package/src/composables/useDropdownState.ts +83 -0
  356. package/src/composables/useEventListener.ts +111 -0
  357. package/src/composables/useExpansionSet.ts +117 -0
  358. package/src/composables/useExperimentData.ts +20 -11
  359. package/src/composables/useExperimentSave.ts +202 -50
  360. package/src/composables/useExperimentSelector.ts +86 -72
  361. package/src/composables/useForm.ts +49 -4
  362. package/src/composables/useFormBuilder.ts +93 -42
  363. package/src/composables/useGroupAssignment.ts +148 -0
  364. package/src/composables/useListSelection.ts +158 -0
  365. package/src/composables/usePluginApi.ts +7 -14
  366. package/src/composables/usePluginClient.ts +425 -0
  367. package/src/composables/usePluginConfig.ts +34 -13
  368. package/src/composables/useRequestSyncState.ts +126 -0
  369. package/src/composables/useSampleGroups.ts +126 -0
  370. package/src/composables/useSelectionLimit.ts +57 -0
  371. package/src/composables/useSortedItems.ts +118 -0
  372. package/src/composables/useTemplateCollection.ts +229 -0
  373. package/src/composables/useTextSearch.ts +60 -0
  374. package/src/composables/useTheme.ts +2 -28
  375. package/src/composables/useTimeUtils.ts +26 -2
  376. package/src/composables/useWellPlateEditor.ts +13 -9
  377. package/src/index.ts +228 -4
  378. package/src/install.ts +11 -4
  379. package/src/stores/settings.ts +13 -9
  380. package/src/styles/components/app-page-selector.css +23 -0
  381. package/src/styles/components/app-pill-nav.css +8 -2
  382. package/src/styles/components/app-top-bar.css +35 -2
  383. package/src/styles/components/button.css +3 -7
  384. package/src/styles/components/concentration-input.css +3 -142
  385. package/src/styles/components/dropdown-button.css +4 -4
  386. package/src/styles/components/empty-state.css +0 -16
  387. package/src/styles/components/input.css +4 -5
  388. package/src/styles/components/number-input.css +3 -3
  389. package/src/styles/components/plugin-icon.css +38 -0
  390. package/src/styles/components/segmented-control.css +4 -7
  391. package/src/styles/components/settings-button.css +3 -66
  392. package/src/styles/components/settings-modal.css +184 -0
  393. package/src/styles/components/tabs.css +1 -2
  394. package/src/styles/components/textarea.css +4 -5
  395. package/src/styles/components/theme-toggle.css +3 -66
  396. package/src/styles/components/unit-input.css +3 -3
  397. package/src/styles/index.css +0 -1
  398. package/src/templates/adapters.ts +785 -0
  399. package/src/templates/builders.ts +2149 -0
  400. package/src/templates/catalog.ts +245 -0
  401. package/src/templates/componentBindings.ts +615 -0
  402. package/src/templates/controlSchemas.ts +718 -0
  403. package/src/templates/index.ts +314 -0
  404. package/src/templates/lookup.ts +18 -0
  405. package/src/templates/packs.ts +156 -0
  406. package/src/templates/presets.ts +146 -0
  407. package/src/templates/types.ts +668 -0
  408. package/src/types/components.ts +80 -1
  409. package/src/types/form-builder.ts +7 -2
  410. package/src/types/index.ts +17 -0
  411. package/src/types/platform.ts +8 -1
  412. package/src/utils/formModelSync.ts +52 -0
  413. package/src/utils/items.ts +28 -0
  414. package/src/utils/options.ts +23 -0
  415. package/src/utils/pluginIcon.ts +30 -0
  416. package/dist/auth-DsI0rQ7_.js.map +0 -1
  417. package/dist/components-CzbQQPCb.js.map +0 -1
  418. package/dist/composables-BXklV5ii.js.map +0 -1
  419. package/dist/useScheduleDrag-CxBeqYcu.js +0 -7181
  420. package/dist/useScheduleDrag-CxBeqYcu.js.map +0 -1
  421. package/src/styles/components/grouping-modal.css +0 -323
@@ -4,6 +4,7 @@ import { computed, ref } from 'vue'
4
4
  import { createPinia } from 'pinia'
5
5
  import AppTopBar from '../../components/AppTopBar.vue'
6
6
  import { usePlatformContext } from '../../composables/usePlatformContext'
7
+ import { controlsToTopBarTabs, defineControlModel, defineControls } from '../../composables/useControlSchema'
7
8
  import ThemeToggle from '../../components/ThemeToggle.vue'
8
9
  import SettingsModal from '../../components/SettingsModal.vue'
9
10
  import type { TopBarSettingsConfig } from '../../types/components'
@@ -223,6 +224,123 @@ describe('AppTopBar', () => {
223
224
  expect(settingsModal.props('tabs')).toEqual(settingsConfig.tabs)
224
225
  })
225
226
 
227
+ it('should normalize shorthand settings tabs for SettingsModal', () => {
228
+ const wrapper = createWrapper({
229
+ title: 'Test App',
230
+ showSettings: true,
231
+ settingsConfig: {
232
+ tabs: ['General', 'Advanced'],
233
+ showAppearance: false,
234
+ },
235
+ })
236
+
237
+ const settingsModal = wrapper.findComponent(SettingsModal)
238
+ expect(settingsModal.props('tabs')).toEqual([
239
+ { id: 'General', label: 'General' },
240
+ { id: 'Advanced', label: 'Advanced' },
241
+ ])
242
+ })
243
+
244
+ it('should sync external schema values into SettingsModal fields', async () => {
245
+ const schema = {
246
+ groups: [
247
+ {
248
+ id: 'general',
249
+ label: 'General',
250
+ fields: [
251
+ { name: 'threshold', label: 'Threshold', type: 'number' as const },
252
+ {
253
+ name: 'method',
254
+ label: 'Method',
255
+ type: 'select' as const,
256
+ props: {
257
+ options: [
258
+ { value: 'linear', label: 'Linear' },
259
+ { value: 'logistic', label: 'Logistic' },
260
+ ],
261
+ },
262
+ },
263
+ ],
264
+ },
265
+ ],
266
+ }
267
+ const settingsConfig: TopBarSettingsConfig = {
268
+ showAppearance: false,
269
+ schema,
270
+ values: { threshold: 0.25, method: 'linear', externalContext: 'experiment-1' },
271
+ }
272
+
273
+ const wrapper = createWrapper({
274
+ title: 'Test App',
275
+ showSettings: true,
276
+ settingsConfig,
277
+ })
278
+
279
+ await wrapper.setProps({
280
+ settingsConfig: {
281
+ ...settingsConfig,
282
+ values: { threshold: 0.75, method: 'logistic', externalContext: 'experiment-2' },
283
+ },
284
+ })
285
+
286
+ expect((wrapper.find('input').element as HTMLInputElement).value).toBe('0.75')
287
+ expect((wrapper.find('select').element as HTMLSelectElement).value).toBe('logistic')
288
+ })
289
+
290
+ it('should render compact controls in SettingsModal', () => {
291
+ const controls = defineControls({
292
+ threshold: {
293
+ label: 'Threshold',
294
+ default: 0.25,
295
+ section: 'parameters',
296
+ sectionLabel: 'Parameters',
297
+ },
298
+ })
299
+ const settingsConfig: TopBarSettingsConfig = {
300
+ showAppearance: false,
301
+ controls,
302
+ }
303
+
304
+ const wrapper = createWrapper({
305
+ title: 'Test App',
306
+ showSettings: true,
307
+ settingsConfig,
308
+ })
309
+
310
+ const settingsModal = wrapper.findComponent(SettingsModal)
311
+ expect(settingsModal.props('controls')).toStrictEqual(controls)
312
+ expect(wrapper.text()).toContain('Threshold')
313
+ expect((wrapper.find('input').element as HTMLInputElement).value).toBe('0.25')
314
+ })
315
+
316
+ it('should pass control model to SettingsModal', () => {
317
+ const model = defineControlModel({
318
+ controls: {
319
+ threshold: {
320
+ label: 'Threshold',
321
+ default: 0.25,
322
+ section: 'parameters',
323
+ sectionLabel: 'Parameters',
324
+ },
325
+ },
326
+ })
327
+ const settingsConfig: TopBarSettingsConfig = {
328
+ showAppearance: false,
329
+ model,
330
+ }
331
+
332
+ const wrapper = createWrapper({
333
+ title: 'Test App',
334
+ showSettings: true,
335
+ settingsConfig,
336
+ })
337
+
338
+ const settingsModal = wrapper.findComponent(SettingsModal)
339
+ expect(settingsModal.props('model')).toStrictEqual(model)
340
+ expect(wrapper.text()).toContain('Threshold')
341
+ expect((wrapper.find('input').element as HTMLInputElement).value).toBe('0.25')
342
+ })
343
+
226
344
  it('should pass showAppearance to SettingsModal', () => {
227
345
  const settingsConfig: TopBarSettingsConfig = {
228
346
  showAppearance: false,
@@ -294,6 +412,22 @@ describe('AppTopBar', () => {
294
412
  expect(settingsModal.vm.$slots['tab-general']).toBeDefined()
295
413
  })
296
414
 
415
+ it('should forward shorthand settings-tab slots to SettingsModal', () => {
416
+ const wrapper = createWrapper({
417
+ title: 'Test App',
418
+ showSettings: true,
419
+ settingsConfig: {
420
+ tabs: ['General'],
421
+ showAppearance: false,
422
+ },
423
+ }, {
424
+ 'settings-tab-General': '<div>General Content</div>',
425
+ })
426
+
427
+ const settingsModal = wrapper.findComponent(SettingsModal)
428
+ expect(settingsModal.vm.$slots['tab-General']).toBeDefined()
429
+ })
430
+
297
431
  it('should forward multiple settings-tab slots', () => {
298
432
  const settingsConfig: TopBarSettingsConfig = {
299
433
  tabs: [
@@ -492,6 +626,100 @@ describe('AppTopBar', () => {
492
626
  expect(wrapper.findComponent(ThemeToggle).exists()).toBe(true)
493
627
  expect(wrapper.find('.mint-topbar__settings-btn').exists()).toBe(true)
494
628
  })
629
+
630
+ it('renders tabs generated from a compact control schema', async () => {
631
+ const runIcon = 'M8 5v14l11-7z'
632
+ const controls = defineControls({
633
+ threshold: {
634
+ default: 0.05,
635
+ section: 'parameters',
636
+ view: 'analysis',
637
+ },
638
+ chartScale: {
639
+ default: 'linear',
640
+ section: 'display',
641
+ view: 'results',
642
+ },
643
+ })
644
+ const wrapper = createWrapper({
645
+ tabs: controlsToTopBarTabs(controls, {
646
+ views: {
647
+ analysis: { label: 'Run', icon: runIcon },
648
+ results: { label: 'Results' },
649
+ },
650
+ }),
651
+ currentTabId: 'analysis',
652
+ })
653
+
654
+ const tabs = wrapper.findAll('.mint-topbar-tab')
655
+ expect(tabs.map(tab => tab.text())).toEqual(['Run', 'Results'])
656
+ expect(tabs[0].classes()).toContain('mint-topbar-tab--active')
657
+ expect(tabs[0].get('.mint-topbar-tab-icon path').attributes('d')).toBe(runIcon)
658
+ expect(tabs[1].find('.mint-topbar-tab-icon').exists()).toBe(false)
659
+
660
+ await tabs[1].trigger('click')
661
+ expect(wrapper.emitted('tab-select')?.[0][0]).toMatchObject({ id: 'results', label: 'Results' })
662
+ })
663
+
664
+ it('uses shared dropdown state for the legacy page menu', async () => {
665
+ const wrapper = createWrapper({
666
+ pluginName: 'Test Plugin',
667
+ pages: [
668
+ { id: 'dashboard', label: 'Dashboard' },
669
+ { id: 'settings', label: 'Settings' },
670
+ ],
671
+ })
672
+ const dropdown = () => wrapper.get('.mint-topbar-dropdown')
673
+
674
+ expect(dropdown().attributes('style')).toContain('display: none')
675
+
676
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
677
+ expect(dropdown().attributes('style') ?? '').not.toContain('display: none')
678
+
679
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
680
+ await wrapper.vm.$nextTick()
681
+ expect(dropdown().attributes('style')).toContain('display: none')
682
+
683
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
684
+ expect(dropdown().attributes('style') ?? '').not.toContain('display: none')
685
+
686
+ document.body.dispatchEvent(new MouseEvent('click', { bubbles: true }))
687
+ await wrapper.vm.$nextTick()
688
+ expect(dropdown().attributes('style')).toContain('display: none')
689
+
690
+ wrapper.unmount()
691
+ })
692
+
693
+ it('renders PluginIcon-compatible metadata icons in the legacy page menu', async () => {
694
+ const iconPath = 'M4 19h16M7 16V8m5 8V4m5 12v-6'
695
+ const pngIcon = 'data:image/png;base64,iVBORw0KGgo='
696
+ const wrapper = createWrapper({
697
+ pluginName: 'Test Plugin',
698
+ pages: [
699
+ { id: 'dashboard', label: 'Dashboard', to: '/', icon: iconPath, description: 'Overview' },
700
+ { id: 'image', label: 'Image', to: '/image', icon: pngIcon },
701
+ { id: 'legacy', label: 'Legacy', icon: 'home' },
702
+ ],
703
+ currentPageId: 'dashboard',
704
+ })
705
+
706
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
707
+
708
+ const icons = wrapper.findAllComponents({ name: 'PluginIcon' })
709
+ expect(icons).toHaveLength(2)
710
+ expect(icons[0].props('icon')).toBe(iconPath)
711
+ expect(icons[1].props('icon')).toBe(pngIcon)
712
+ expect(icons.every((icon) => icon.props('variant') === 'tinted')).toBe(true)
713
+
714
+ const pathIcons = wrapper.findAll('.mint-plugin-icon__svg')
715
+ expect(pathIcons).toHaveLength(1)
716
+ expect(pathIcons[0].find('path').attributes('d')).toBe(iconPath)
717
+
718
+ const imageIcons = wrapper.findAll('.mint-plugin-icon__img')
719
+ expect(imageIcons).toHaveLength(1)
720
+ expect(imageIcons[0].attributes('src')).toBe(pngIcon)
721
+ expect(wrapper.find('.mint-topbar-dropdown-item__description').text()).toBe('Overview')
722
+ })
495
723
  })
496
724
 
497
725
  describe('edge cases', () => {
@@ -621,10 +849,10 @@ describe('AppTopBar', () => {
621
849
 
622
850
  expect(wrapper.find('.mint-topbar__logo-text').exists()).toBe(true)
623
851
  expect(wrapper.find('.mint-topbar__logo-text').text()).toBe('M')
624
- expect(wrapper.find('.mint-topbar__logo-svg').exists()).toBe(false)
852
+ expect(wrapper.findComponent({ name: 'PluginIcon' }).exists()).toBe(false)
625
853
  })
626
854
 
627
- it('should render plugin metadata icon SVG when plugin has icon', () => {
855
+ it('should render PluginIcon when plugin metadata has an icon', () => {
628
856
  const iconPath = 'M13 10V3L4 14h7v7l9-11h-7z'
629
857
  mockPlatformCtx({
630
858
  isIntegrated: true,
@@ -633,13 +861,31 @@ describe('AppTopBar', () => {
633
861
 
634
862
  const wrapper = createWrapper({ title: 'Test App' })
635
863
 
636
- const svg = wrapper.find('.mint-topbar__logo-svg')
637
- expect(svg.exists()).toBe(true)
638
- expect(svg.find('path').attributes('d')).toBe(iconPath)
864
+ const pluginIcon = wrapper.findComponent({ name: 'PluginIcon' })
865
+ expect(pluginIcon.exists()).toBe(true)
866
+ expect(pluginIcon.props('icon')).toBe(iconPath)
867
+ expect(pluginIcon.props('variant')).toBe('solid')
868
+ expect(pluginIcon.props('size')).toBe('md')
639
869
  expect(wrapper.find('.mint-topbar__logo-text').exists()).toBe(false)
640
870
  })
641
871
 
642
- it('should not render plugin icon when #icon slot is provided', () => {
872
+ it('should pass plugin.color to PluginIcon as tone', () => {
873
+ const iconPath = 'M13 10V3L4 14h7v7l9-11h-7z'
874
+ mockPlatformCtx({
875
+ isIntegrated: true,
876
+ plugin: {
877
+ id: 'test', name: 'Test', version: '1.0',
878
+ icon: iconPath, color: '#22C55E',
879
+ route_prefix: '/test', api_prefix: '/api/test',
880
+ },
881
+ })
882
+
883
+ const wrapper = createWrapper({ title: 'Test App' })
884
+
885
+ expect(wrapper.findComponent({ name: 'PluginIcon' }).props('tone')).toBe('#22C55E')
886
+ })
887
+
888
+ it('should not render PluginIcon when #icon slot is provided', () => {
643
889
  const iconPath = 'M13 10V3L4 14h7v7l9-11h-7z'
644
890
  mockPlatformCtx({
645
891
  isIntegrated: true,
@@ -651,10 +897,10 @@ describe('AppTopBar', () => {
651
897
  })
652
898
 
653
899
  expect(wrapper.find('.custom-icon').exists()).toBe(true)
654
- expect(wrapper.find('.mint-topbar__logo-svg').exists()).toBe(false)
900
+ expect(wrapper.findComponent({ name: 'PluginIcon' }).exists()).toBe(false)
655
901
  })
656
902
 
657
- it('should not render plugin icon when icon does not start with M', () => {
903
+ it('should still render PluginIcon when icon does not start with M (PluginIcon shows fallback)', () => {
658
904
  mockPlatformCtx({
659
905
  isIntegrated: true,
660
906
  plugin: { id: 'test', name: 'Test', version: '1.0', icon: 'invalid-path', route_prefix: '/test', api_prefix: '/api/test' },
@@ -662,12 +908,12 @@ describe('AppTopBar', () => {
662
908
 
663
909
  const wrapper = createWrapper({ title: 'Test App' })
664
910
 
665
- expect(wrapper.find('.mint-topbar__logo-svg').exists()).toBe(false)
666
- expect(wrapper.find('.mint-topbar__logo-text').exists()).toBe(true)
667
- expect(wrapper.find('.mint-topbar__logo-text').text()).toBe('M')
911
+ // Topbar passes any non-empty icon string to PluginIcon, which decides what to render.
912
+ expect(wrapper.findComponent({ name: 'PluginIcon' }).exists()).toBe(true)
913
+ expect(wrapper.find('.mint-topbar__logo-text').exists()).toBe(false)
668
914
  })
669
915
 
670
- it('should not render plugin icon when icon is empty string', () => {
916
+ it('should not render PluginIcon when icon is empty string', () => {
671
917
  mockPlatformCtx({
672
918
  isIntegrated: true,
673
919
  plugin: { id: 'test', name: 'Test', version: '1.0', icon: '', route_prefix: '/test', api_prefix: '/api/test' },
@@ -675,9 +921,164 @@ describe('AppTopBar', () => {
675
921
 
676
922
  const wrapper = createWrapper({ title: 'Test App' })
677
923
 
678
- expect(wrapper.find('.mint-topbar__logo-svg').exists()).toBe(false)
924
+ expect(wrapper.findComponent({ name: 'PluginIcon' }).exists()).toBe(false)
679
925
  expect(wrapper.find('.mint-topbar__logo-text').exists()).toBe(true)
680
926
  expect(wrapper.find('.mint-topbar__logo-text').text()).toBe('M')
681
927
  })
928
+
929
+ it('uses platform plugin nav metadata when pluginName and pages are omitted', async () => {
930
+ const previousPath = window.location.pathname
931
+ window.history.pushState({}, '', '/test/analysis')
932
+ try {
933
+ const pluginIcon = 'M13 10V3L4 14h7v7l9-11h-7z'
934
+ const analysisIcon = 'M4 19h16M7 16V8m5 8V4m5 12v-6'
935
+ mockPlatformCtx({
936
+ isIntegrated: true,
937
+ plugin: {
938
+ id: 'test',
939
+ name: 'Dose Designer',
940
+ version: '1.0',
941
+ icon: pluginIcon,
942
+ route_prefix: '/test',
943
+ api_prefix: '/api/test',
944
+ nav_items: [
945
+ { path: '/', label: 'Dashboard' },
946
+ { path: '/analysis', label: 'Analysis', icon: analysisIcon },
947
+ ],
948
+ },
949
+ })
950
+
951
+ const wrapper = createWrapper()
952
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
953
+
954
+ expect(wrapper.get('.mint-topbar-plugin-name').text()).toContain('Dose Designer')
955
+ expect(wrapper.get('.mint-topbar-current-page').text()).toBe('Analysis')
956
+ expect(wrapper.findAll('.mint-topbar-dropdown-item__label').map(item => item.text())).toEqual([
957
+ 'Dashboard',
958
+ 'Analysis',
959
+ ])
960
+ const dropdownIcons = wrapper
961
+ .findAllComponents({ name: 'PluginIcon' })
962
+ .filter(icon => icon.classes().includes('mint-topbar-dropdown-item__icon'))
963
+ expect(dropdownIcons.map(icon => icon.props('icon'))).toEqual([pluginIcon, analysisIcon])
964
+ expect(wrapper.findAll('.mint-topbar-dropdown-item')[1].classes()).toContain('mint-topbar-dropdown-item--active')
965
+ } finally {
966
+ window.history.pushState({}, '', previousPath)
967
+ }
968
+ })
969
+
970
+ it('keeps explicit legacy pages ahead of platform plugin nav metadata', async () => {
971
+ mockPlatformCtx({
972
+ isIntegrated: true,
973
+ plugin: {
974
+ id: 'test',
975
+ name: 'Dose Designer',
976
+ version: '1.0',
977
+ route_prefix: '/test',
978
+ api_prefix: '/api/test',
979
+ nav_items: [{ path: '/stale', label: 'Stale' }],
980
+ },
981
+ })
982
+
983
+ const wrapper = createWrapper({
984
+ pluginName: 'Explicit Plugin',
985
+ pages: [{ id: 'overview', label: 'Overview', to: '/' }],
986
+ })
987
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
988
+
989
+ expect(wrapper.get('.mint-topbar-plugin-name').text()).toContain('Explicit Plugin')
990
+ expect(wrapper.findAll('.mint-topbar-dropdown-item__label').map(item => item.text())).toEqual(['Overview'])
991
+ })
992
+ })
993
+
994
+ describe('shorthand navigation items', () => {
995
+ it('accepts string shorthand for pageSelector', async () => {
996
+ const wrapper = createWrapper({
997
+ currentPageSelectorId: 'Workspace',
998
+ pageSelector: ['Workspace', 'Results'],
999
+ })
1000
+
1001
+ expect(wrapper.find('.mint-page-selector__label').text()).toBe('Workspace')
1002
+
1003
+ await wrapper.get('.mint-page-selector__trigger').trigger('click')
1004
+ await wrapper.findAll('.mint-page-selector__item')[1].trigger('click')
1005
+
1006
+ expect(wrapper.emitted('page-selector-select')).toEqual([
1007
+ [{ id: 'Results', label: 'Results' }],
1008
+ ])
1009
+ })
1010
+
1011
+ it('accepts string shorthand for pillNav', async () => {
1012
+ const wrapper = createWrapper({
1013
+ currentPillId: 'Run',
1014
+ pillNav: ['Run', 'Results'],
1015
+ })
1016
+
1017
+ expect(wrapper.findAll('.mint-pill-nav__item').map(item => item.text())).toEqual([
1018
+ 'Run',
1019
+ 'Results',
1020
+ ])
1021
+
1022
+ await wrapper.findAll('.mint-pill-nav__item')[1].trigger('click')
1023
+
1024
+ expect(wrapper.emitted('pill-select')).toEqual([
1025
+ [{ id: 'Results', label: 'Results' }],
1026
+ ])
1027
+ })
1028
+
1029
+ it('accepts string shorthand for legacy pages', async () => {
1030
+ const wrapper = createWrapper({
1031
+ pluginName: 'Analysis',
1032
+ currentPageId: 'Overview',
1033
+ pages: ['Overview', 'Settings'],
1034
+ })
1035
+
1036
+ await wrapper.get('.mint-topbar-plugin-name').trigger('click')
1037
+ await wrapper.findAll('.mint-topbar-dropdown-item')[1].trigger('click')
1038
+
1039
+ expect(wrapper.emitted('page-select')).toEqual([
1040
+ [{ id: 'Settings', label: 'Settings' }],
1041
+ ])
1042
+ })
1043
+
1044
+ it('accepts string shorthand for legacy tabs', async () => {
1045
+ const wrapper = createWrapper({
1046
+ currentTabId: 'Run',
1047
+ tabs: ['Run', 'Results'],
1048
+ })
1049
+
1050
+ expect(wrapper.findAll('.mint-topbar-tab').map(tab => tab.text())).toEqual([
1051
+ 'Run',
1052
+ 'Results',
1053
+ ])
1054
+
1055
+ await wrapper.findAll('.mint-topbar-tab')[1].trigger('click')
1056
+
1057
+ expect(wrapper.emitted('tab-select')).toEqual([
1058
+ [{ id: 'Results', label: 'Results' }],
1059
+ ])
1060
+ })
1061
+
1062
+ it('accepts string shorthand for legacy tab dropdown options', async () => {
1063
+ const wrapper = createWrapper({
1064
+ currentTabId: 'Summary',
1065
+ tabs: [
1066
+ { id: 'analysis', label: 'Analysis', children: ['Summary', 'Details'] },
1067
+ ],
1068
+ })
1069
+
1070
+ await wrapper.get('.mint-topbar-tab').trigger('click')
1071
+ expect(wrapper.findAll('.mint-topbar-dropdown-item').map(item => item.text())).toEqual([
1072
+ 'Summary',
1073
+ 'Details',
1074
+ ])
1075
+
1076
+ await wrapper.findAll('.mint-topbar-dropdown-item')[1].trigger('click')
1077
+
1078
+ expect(wrapper.emitted('tab-option-select')?.[0]?.[0]).toEqual({
1079
+ id: 'Details',
1080
+ label: 'Details',
1081
+ })
1082
+ })
682
1083
  })
683
1084
  })
@@ -0,0 +1,25 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import BaseRadioGroup from '../../components/BaseRadioGroup.vue'
4
+
5
+ describe('BaseRadioGroup', () => {
6
+ it('accepts string and number shorthand options', async () => {
7
+ const wrapper = mount(BaseRadioGroup, {
8
+ props: {
9
+ name: 'plate-format',
10
+ modelValue: 96,
11
+ options: [96, 384, { value: 'custom', label: 'Custom' }],
12
+ },
13
+ })
14
+
15
+ expect(wrapper.findAll('.mint-radio-option__label').map(label => label.text())).toEqual([
16
+ '96',
17
+ '384',
18
+ 'Custom',
19
+ ])
20
+
21
+ await wrapper.findAll('input')[1].setValue(true)
22
+
23
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([384])
24
+ })
25
+ })
@@ -0,0 +1,21 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import BaseSelect from '../../components/BaseSelect.vue'
4
+
5
+ describe('BaseSelect', () => {
6
+ it('accepts string and number shorthand options', async () => {
7
+ const wrapper = mount(BaseSelect, {
8
+ props: {
9
+ modelValue: 'linear',
10
+ options: ['linear', 96, { value: 'log', label: 'Log scale' }],
11
+ },
12
+ })
13
+
14
+ const options = wrapper.findAll('option')
15
+ expect(options.map(option => option.text())).toEqual(['linear', '96', 'Log scale'])
16
+
17
+ await wrapper.get('select').setValue('96')
18
+
19
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([96])
20
+ })
21
+ })
@@ -0,0 +1,25 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import BaseTabs from '../../components/BaseTabs.vue'
4
+
5
+ describe('BaseTabs', () => {
6
+ it('accepts string shorthand tabs', async () => {
7
+ const wrapper = mount(BaseTabs, {
8
+ props: {
9
+ modelValue: 'Run',
10
+ tabs: ['Run', 'Results', { id: 'settings', label: 'Settings', disabled: true }],
11
+ },
12
+ })
13
+
14
+ expect(wrapper.findAll('.mint-tab').map(tab => tab.text())).toEqual([
15
+ 'Run',
16
+ 'Results',
17
+ 'Settings',
18
+ ])
19
+
20
+ await wrapper.findAll('.mint-tab')[1].trigger('click')
21
+ await wrapper.findAll('.mint-tab')[2].trigger('click')
22
+
23
+ expect(wrapper.emitted('update:modelValue')).toEqual([['Results']])
24
+ })
25
+ })
@@ -0,0 +1,52 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, expect, it } from 'vitest'
3
+ import BatchProgressList from '../../components/BatchProgressList.vue'
4
+ import type { BatchItem } from '../../types'
5
+
6
+ const items: BatchItem[] = [
7
+ { id: 'a', label: 'Sample A', status: 'completed' },
8
+ { id: 'b', label: 'Sample B', status: 'error', message: 'Import failed' },
9
+ { id: 'c', label: 'Sample C', status: 'processing', progress: 50 },
10
+ ]
11
+
12
+ describe('BatchProgressList', () => {
13
+ it('summarizes progress and emits row actions', async () => {
14
+ const wrapper = mount(BatchProgressList, {
15
+ props: {
16
+ title: 'Import',
17
+ items,
18
+ autoScroll: false,
19
+ },
20
+ })
21
+
22
+ expect(wrapper.find('.mint-batch-progress__percent').text()).toBe('33%')
23
+ expect(wrapper.text()).toContain('1 completed')
24
+ expect(wrapper.text()).toContain('1 failed')
25
+ expect(wrapper.text()).toContain('1 processing')
26
+
27
+ await wrapper.get('.mint-batch-progress__retry-btn').trigger('click')
28
+ await wrapper.get('.mint-batch-progress__cancel-btn').trigger('click')
29
+
30
+ expect(wrapper.emitted('retry')).toEqual([[items[1].id]])
31
+ expect(wrapper.emitted('cancel')).toEqual([[items[2].id]])
32
+ })
33
+
34
+ it('uses shared expansion state for error messages', async () => {
35
+ const wrapper = mount(BatchProgressList, {
36
+ props: {
37
+ items,
38
+ autoScroll: false,
39
+ },
40
+ })
41
+
42
+ expect(wrapper.find('.mint-batch-progress__item-message').exists()).toBe(false)
43
+
44
+ await wrapper.get('.mint-batch-progress__error-toggle').trigger('click')
45
+ expect(wrapper.get('.mint-batch-progress__error-toggle').text()).toBe('Hide error')
46
+ expect(wrapper.get('.mint-batch-progress__item-message').text()).toBe('Import failed')
47
+
48
+ await wrapper.get('.mint-batch-progress__error-toggle').trigger('click')
49
+ expect(wrapper.get('.mint-batch-progress__error-toggle').text()).toBe('Show error')
50
+ expect(wrapper.find('.mint-batch-progress__item-message').exists()).toBe(false)
51
+ })
52
+ })