@morscherlab/mint-sdk 1.2.0-beta.1 → 1.2.0-beta.11

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 (408) hide show
  1. package/README.md +35 -5
  2. package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-oL0fg_A0.js} +6 -4
  3. package/dist/ExperimentPopover-oL0fg_A0.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-BeEOomw_.js} +5 -5
  5. package/dist/ExperimentSelectorModal-BeEOomw_.js.map +1 -0
  6. package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-Dphh3RrI.js} +5 -8
  7. package/dist/SettingsModal-Dphh3RrI.js.map +1 -0
  8. package/dist/{EmptyState-p90quq8Z.js → Skeleton-DxtwJ5gt.js} +111 -93
  9. package/dist/Skeleton-DxtwJ5gt.js.map +1 -0
  10. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  11. package/dist/__tests__/components/PluginWorkspaceView.internal.test.d.ts +1 -0
  12. package/dist/__tests__/components/SecretInput.test.d.ts +1 -0
  13. package/dist/__tests__/components/WellEditPopupInternal.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  15. package/dist/__tests__/composables/usePluginConfig.test.d.ts +15 -0
  16. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  17. package/dist/components/ActionMenu.vue.d.ts +1 -1
  18. package/dist/components/AppAvatarMenu.vue.d.ts +4 -0
  19. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  20. package/dist/components/AppSidebar.vue.d.ts +1 -1
  21. package/dist/components/AuditTrail.vue.d.ts +13 -0
  22. package/dist/components/AutoGroupModal.vue.d.ts +1 -1
  23. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  24. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  25. package/dist/components/DataFrame.vue.d.ts +14 -2
  26. package/dist/components/DatePicker.vue.d.ts +1 -1
  27. package/dist/components/DateTimePicker.vue.d.ts +2 -0
  28. package/dist/components/DropdownButton.vue.d.ts +2 -0
  29. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  30. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  31. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  32. package/dist/components/FitPanel.vue.d.ts +1 -1
  33. package/dist/components/JobsStatusTray.vue.d.ts +9 -2
  34. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  35. package/dist/components/PluginWorkspaceView.props.d.ts +29 -1
  36. package/dist/components/PluginWorkspaceView.vue.d.ts +5 -5
  37. package/dist/components/ProgressBar.vue.d.ts +1 -1
  38. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  39. package/dist/components/ReagentList.vue.d.ts +29 -1
  40. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  41. package/dist/components/SampleLegend.vue.d.ts +1 -1
  42. package/dist/components/SampleSelector.drag.d.ts +13 -0
  43. package/dist/components/SampleSelector.tree.d.ts +2 -0
  44. package/dist/components/SampleSelector.vue.d.ts +35 -2
  45. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  46. package/dist/components/SecretInput.vue.d.ts +28 -0
  47. package/dist/components/SettingsModal.vue.d.ts +1 -1
  48. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -1
  49. package/dist/components/TimePicker.vue.d.ts +1 -0
  50. package/dist/components/WellPlate.geometry.d.ts +15 -0
  51. package/dist/components/WellPlate.interaction.d.ts +13 -0
  52. package/dist/components/WellPlate.vue.d.ts +29 -0
  53. package/dist/components/index.d.ts +9 -0
  54. package/dist/components/index.js +8 -8
  55. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  56. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  57. package/dist/components/internal/WellEditPopupInternal.vue.d.ts +3 -1
  58. package/dist/components/internal/WorkspaceControlsInternal.vue.d.ts +23 -0
  59. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +70 -0
  60. package/dist/components/internal/WorkspaceSidebarInternal.vue.d.ts +43 -0
  61. package/dist/{components-DkHddRMl.js → components-CgAUzF8F.js} +2497 -2235
  62. package/dist/components-CgAUzF8F.js.map +1 -0
  63. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  64. package/dist/composables/flattenWorkspaceBindings.d.ts +61 -0
  65. package/dist/composables/index.d.ts +9 -2
  66. package/dist/composables/index.js +10 -10
  67. package/dist/composables/pluginWorkspaceModel.d.ts +164 -0
  68. package/dist/composables/useAsync.d.ts +5 -1
  69. package/dist/composables/useBioTemplateWorkspace.d.ts +4 -20
  70. package/dist/composables/useCommandHistory.d.ts +5 -1
  71. package/dist/composables/useDropdownState.d.ts +18 -2
  72. package/dist/composables/useEventStream.d.ts +9 -0
  73. package/dist/composables/useFocusTrap.d.ts +21 -0
  74. package/dist/composables/useGeneratedAnalysis.d.ts +3 -1
  75. package/dist/composables/useJobsStatusTray.d.ts +25 -1
  76. package/dist/composables/useListReorder.d.ts +90 -0
  77. package/dist/composables/useMenuKeyboard.d.ts +29 -0
  78. package/dist/composables/useOptimisticMutation.d.ts +5 -1
  79. package/dist/composables/usePluginClient.d.ts +2 -0
  80. package/dist/composables/usePluginConfig.d.ts +27 -0
  81. package/dist/composables/usePluginWorkspace.d.ts +51 -0
  82. package/dist/composables/useRequestSyncState.d.ts +42 -2
  83. package/dist/composables/useResourceCrud.d.ts +5 -1
  84. package/dist/composables/useRovingFocus.d.ts +24 -0
  85. package/dist/composables/useScheduleDrag.d.ts +1 -0
  86. package/dist/composables/useWellPainting.d.ts +5 -1
  87. package/dist/composables/useWellPlateAdapter.d.ts +5 -1
  88. package/dist/composables/useWellPlateValidation.d.ts +5 -1
  89. package/dist/composables/workspaceRecipes.d.ts +188 -0
  90. package/dist/{composables-C_i90sGS.js → composables-B_pia3hO.js} +209 -82
  91. package/dist/composables-B_pia3hO.js.map +1 -0
  92. package/dist/{useApi-J6zFkHmn.js → errors-_W0-LbA6.js} +103 -3
  93. package/dist/errors-_W0-LbA6.js.map +1 -0
  94. package/dist/{experiment-Cq145oEW.js → experiment-Cwl9AYxw.js} +3 -8
  95. package/dist/experiment-Cwl9AYxw.js.map +1 -0
  96. package/dist/{experiment-utils-CLnzPPq5.js → experiment-utils-DV3DrvE_.js} +70 -51
  97. package/dist/experiment-utils-DV3DrvE_.js.map +1 -0
  98. package/dist/index.d.ts +1 -0
  99. package/dist/index.js +15 -15
  100. package/dist/install.js +2 -7
  101. package/dist/install.js.map +1 -1
  102. package/dist/permissions.d.ts +42 -1
  103. package/dist/permissions.js +20 -10
  104. package/dist/permissions.js.map +1 -1
  105. package/dist/stores/auth.d.ts +6 -0
  106. package/dist/stores/index.d.ts +1 -1
  107. package/dist/stores/index.js +3 -3
  108. package/dist/stores/settings.d.ts +31 -1
  109. package/dist/styles.css +11247 -29501
  110. package/dist/templates/builderReadUtils.d.ts +1 -1
  111. package/dist/templates/index.js +2 -4
  112. package/dist/{templates-DsP51i-S.js → templates-Qq113pyZ.js} +303 -106
  113. package/dist/templates-Qq113pyZ.js.map +1 -0
  114. package/dist/types/auth.d.ts +1 -0
  115. package/dist/types/form-builder.d.ts +1 -1
  116. package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-aMZlb4Sc.js} +462 -1130
  117. package/dist/useControlSchema-aMZlb4Sc.js.map +1 -0
  118. package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-DitCtrTT.js} +22 -6
  119. package/dist/useDropdownState-DitCtrTT.js.map +1 -0
  120. package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-I8HC8hUu.js} +4 -4
  121. package/dist/{useExperimentSelector-CV4iNfMS.js.map → useExperimentSelector-I8HC8hUu.js.map} +1 -1
  122. package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-TCxNnqeb.js} +2 -2
  123. package/dist/{useFormBuilder-BLxG3BOX.js.map → useFormBuilder-TCxNnqeb.js.map} +1 -1
  124. package/dist/{useProtocolTemplates-CS_SQl6U.js → useProtocolTemplates-BmX_iVBR.js} +766 -212
  125. package/dist/useProtocolTemplates-BmX_iVBR.js.map +1 -0
  126. package/dist/utils/color.d.ts +13 -0
  127. package/dist/utils/errors.d.ts +9 -0
  128. package/dist/utils/pluginSecrets.d.ts +53 -0
  129. package/dist/utils/records.d.ts +4 -0
  130. package/package.json +1 -1
  131. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  132. package/src/__tests__/components/AppAvatarMenu.test.ts +123 -0
  133. package/src/__tests__/components/BaseTabs.test.ts +67 -0
  134. package/src/__tests__/components/DataFrame.test.ts +183 -11
  135. package/src/__tests__/components/DataStates.test.ts +176 -0
  136. package/src/__tests__/components/DatePicker.test.ts +76 -0
  137. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  138. package/src/__tests__/components/DropdownButton.test.ts +134 -0
  139. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  140. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  141. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  142. package/src/__tests__/components/PluginWorkspaceView.internal.test.ts +230 -0
  143. package/src/__tests__/components/RackEditor.test.ts +35 -0
  144. package/src/__tests__/components/ReagentList.test.ts +64 -2
  145. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  146. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  147. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  148. package/src/__tests__/components/SecretInput.test.ts +87 -0
  149. package/src/__tests__/components/SegmentedControl.test.ts +88 -0
  150. package/src/__tests__/components/TimePicker.test.ts +61 -0
  151. package/src/__tests__/components/WellEditPopupInternal.test.ts +108 -0
  152. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  153. package/src/__tests__/composables/useAuth.test.ts +2 -0
  154. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  155. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  156. package/src/__tests__/composables/usePluginClient.test.ts +140 -0
  157. package/src/__tests__/composables/usePluginConfig.test.ts +497 -0
  158. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  159. package/src/__tests__/docs/frontendDocsCatalog.test.ts +39 -7
  160. package/src/__tests__/stores/settings.test.ts +71 -1
  161. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  162. package/src/__tests__/utils/permissions.test.ts +68 -0
  163. package/src/components/ActionMenu.vue +45 -88
  164. package/src/components/AlertBox.vue +0 -4
  165. package/src/components/AppAvatarMenu.vue +26 -7
  166. package/src/components/AppLayout.vue +0 -4
  167. package/src/components/AppPluginSwitcher.story.vue +87 -0
  168. package/src/components/AppPluginSwitcher.vue +2 -5
  169. package/src/components/AppSidebar.vue +0 -4
  170. package/src/components/AppToastContainer.vue +6 -8
  171. package/src/components/AppTopBar.vue +0 -4
  172. package/src/components/ArtifactSaveDialog.vue +0 -4
  173. package/src/components/ArtifactSelectorModal.vue +0 -4
  174. package/src/components/AuditTrail.story.vue +18 -0
  175. package/src/components/AuditTrail.vue +27 -7
  176. package/src/components/AutoGroupModal.vue +0 -4
  177. package/src/components/Avatar.vue +0 -4
  178. package/src/components/BaseButton.vue +0 -4
  179. package/src/components/BaseCheckbox.vue +0 -4
  180. package/src/components/BaseInput.vue +0 -4
  181. package/src/components/BaseModal.vue +8 -60
  182. package/src/components/BasePill.vue +0 -4
  183. package/src/components/BaseRadioGroup.vue +0 -4
  184. package/src/components/BaseSelect.vue +0 -4
  185. package/src/components/BaseSlider.vue +0 -4
  186. package/src/components/BaseTabs.vue +26 -5
  187. package/src/components/BaseTextarea.vue +0 -4
  188. package/src/components/BaseToggle.vue +0 -4
  189. package/src/components/BatchProgressList.story.vue +18 -0
  190. package/src/components/BatchProgressList.vue +32 -4
  191. package/src/components/BioTemplateExperimentWorkspaceView.vue +10 -21
  192. package/src/components/BioTemplatePackWorkspaceView.vue +11 -15
  193. package/src/components/BioTemplatePresetWorkspaceView.vue +8 -13
  194. package/src/components/Breadcrumb.vue +0 -4
  195. package/src/components/Calendar.vue +0 -4
  196. package/src/components/ChartContainer.story.vue +1 -1
  197. package/src/components/ChartContainer.vue +0 -4
  198. package/src/components/ChemicalFormula.vue +0 -4
  199. package/src/components/CollapsibleCard.vue +0 -4
  200. package/src/components/ColorSlider.vue +0 -4
  201. package/src/components/ComponentBindingRenderer.vue +1 -3
  202. package/src/components/ConcentrationInput.vue +0 -4
  203. package/src/components/ConfirmDialog.vue +0 -4
  204. package/src/components/ControlWorkspaceView.vue +11 -22
  205. package/src/components/DataFrame.story.vue +14 -0
  206. package/src/components/DataFrame.vue +97 -23
  207. package/src/components/DatePicker.vue +73 -27
  208. package/src/components/DateTimePicker.vue +45 -17
  209. package/src/components/Divider.vue +0 -4
  210. package/src/components/DoseCalculator.vue +0 -4
  211. package/src/components/DoseDesignWorkspaceView.vue +6 -25
  212. package/src/components/DropdownButton.vue +24 -6
  213. package/src/components/EmptyState.vue +0 -4
  214. package/src/components/ExperimentCodeBadge.vue +0 -4
  215. package/src/components/ExperimentDataViewer.story.vue +3 -0
  216. package/src/components/ExperimentDataViewer.vue +33 -13
  217. package/src/components/ExperimentPopover.vue +2 -5
  218. package/src/components/ExperimentSelectorModal.vue +0 -4
  219. package/src/components/ExperimentTimeline.story.vue +18 -0
  220. package/src/components/ExperimentTimeline.vue +81 -75
  221. package/src/components/FileUploader.vue +0 -4
  222. package/src/components/FitPanel.vue +0 -4
  223. package/src/components/FormActions.story.vue +96 -0
  224. package/src/components/FormActions.vue +0 -4
  225. package/src/components/FormBuilder.vue +0 -4
  226. package/src/components/FormField.vue +0 -4
  227. package/src/components/FormulaInput.vue +0 -4
  228. package/src/components/GeneratedPathInput.story.vue +68 -0
  229. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  230. package/src/components/GeneratedPlotlyResult.vue +3 -3
  231. package/src/components/GeneratedPluginView.story.vue +145 -0
  232. package/src/components/GeneratedPluginView.vue +10 -10
  233. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  234. package/src/components/GeneratedResultRenderer.vue +4 -4
  235. package/src/components/GroupAssigner.vue +67 -5
  236. package/src/components/IconButton.vue +0 -4
  237. package/src/components/InstrumentAlertLog.vue +0 -4
  238. package/src/components/InstrumentStateBadge.vue +0 -4
  239. package/src/components/InstrumentStatusCard.vue +0 -4
  240. package/src/components/JobsStatusTray.vue +16 -5
  241. package/src/components/LcmsSequenceTable.vue +81 -50
  242. package/src/components/LoadingSpinner.vue +0 -4
  243. package/src/components/MobileSupportGate.vue +0 -4
  244. package/src/components/MoleculeInput.vue +0 -4
  245. package/src/components/MultiSelect.vue +0 -4
  246. package/src/components/NumberInput.vue +0 -4
  247. package/src/components/PlateMapEditor.vue +3 -14
  248. package/src/components/PluginIcon.vue +0 -4
  249. package/src/components/PluginWorkspaceView.props.ts +38 -0
  250. package/src/components/PluginWorkspaceView.vue +53 -224
  251. package/src/components/ProgressBar.vue +0 -4
  252. package/src/components/ProtocolStepEditor.vue +2 -4
  253. package/src/components/RackEditor.vue +51 -70
  254. package/src/components/ReagentEditor.vue +0 -4
  255. package/src/components/ReagentList.story.vue +18 -0
  256. package/src/components/ReagentList.vue +127 -82
  257. package/src/components/ResourceCard.vue +0 -4
  258. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  259. package/src/components/RuntimeUpdateNotice.vue +4 -4
  260. package/src/components/SampleHierarchyTree.story.vue +18 -0
  261. package/src/components/SampleHierarchyTree.vue +32 -9
  262. package/src/components/SampleLegend.vue +2 -8
  263. package/src/components/SampleSelector.drag.ts +51 -0
  264. package/src/components/SampleSelector.story.vue +6 -0
  265. package/src/components/SampleSelector.tree.ts +2 -0
  266. package/src/components/SampleSelector.vue +49 -10
  267. package/src/components/SampleSelectorGroupNode.vue +19 -0
  268. package/src/components/ScheduleCalendar.story.vue +6 -0
  269. package/src/components/ScheduleCalendar.vue +82 -7
  270. package/src/components/ScientificNumber.vue +0 -4
  271. package/src/components/SecretInput.story.vue +79 -0
  272. package/src/components/SecretInput.vue +150 -0
  273. package/src/components/SectionCard.vue +0 -4
  274. package/src/components/SegmentedControl.vue +48 -5
  275. package/src/components/SequenceInput.vue +0 -4
  276. package/src/components/SequenceProgressBar.story.vue +110 -0
  277. package/src/components/SequenceProgressBar.vue +0 -4
  278. package/src/components/SettingsModal.vue +0 -4
  279. package/src/components/Skeleton.vue +0 -4
  280. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  281. package/src/components/SmartGroupManual.vue +0 -4
  282. package/src/components/StatusIndicator.vue +0 -4
  283. package/src/components/StepWizard.vue +0 -4
  284. package/src/components/TagsInput.vue +4 -6
  285. package/src/components/ThemeToggle.vue +0 -4
  286. package/src/components/TimePicker.vue +36 -7
  287. package/src/components/TimeRangeInput.vue +0 -4
  288. package/src/components/Tooltip.story.vue +3 -3
  289. package/src/components/Tooltip.vue +0 -4
  290. package/src/components/UnitInput.vue +0 -4
  291. package/src/components/WellPlate.geometry.ts +60 -1
  292. package/src/components/WellPlate.interaction.ts +44 -0
  293. package/src/components/WellPlate.story.vue +8 -0
  294. package/src/components/WellPlate.vue +53 -7
  295. package/src/components/index.ts +9 -0
  296. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  297. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  298. package/src/components/internal/DataStateInternal.vue +74 -0
  299. package/src/components/internal/FormSectionRenderer.vue +0 -4
  300. package/src/components/internal/WellEditPopupInternal.vue +20 -5
  301. package/src/components/internal/WorkspaceControlsInternal.vue +20 -0
  302. package/src/components/internal/WorkspaceShellInternal.vue +125 -0
  303. package/src/components/internal/WorkspaceSidebarInternal.vue +82 -0
  304. package/src/composables/controlSchemaTypes.ts +34 -0
  305. package/src/composables/experimentDesignData.ts +1 -3
  306. package/src/composables/flattenWorkspaceBindings.ts +104 -0
  307. package/src/composables/formBuilderRegistry.ts +5 -0
  308. package/src/composables/index.ts +43 -0
  309. package/src/composables/pluginWorkspaceModel.ts +182 -0
  310. package/src/composables/useAsync.ts +5 -1
  311. package/src/composables/useAuth.ts +3 -0
  312. package/src/composables/useBioTemplatePackWorkspace.ts +15 -9
  313. package/src/composables/useBioTemplatePresetWorkspace.ts +14 -15
  314. package/src/composables/useBioTemplateWorkspace.ts +18 -43
  315. package/src/composables/useCommandHistory.ts +5 -1
  316. package/src/composables/useDropdownState.ts +35 -5
  317. package/src/composables/useEventStream.ts +14 -2
  318. package/src/composables/useFileImport.ts +2 -7
  319. package/src/composables/useFocusTrap.ts +91 -0
  320. package/src/composables/useGeneratedAnalysis.ts +22 -10
  321. package/src/composables/useJobsStatusTray.ts +184 -17
  322. package/src/composables/useListReorder.story.vue +143 -0
  323. package/src/composables/useListReorder.ts +242 -0
  324. package/src/composables/useMenuKeyboard.ts +90 -0
  325. package/src/composables/useOptimisticMutation.ts +6 -16
  326. package/src/composables/usePluginClient.ts +47 -4
  327. package/src/composables/usePluginConfig.ts +252 -0
  328. package/src/composables/usePluginWorkspace.ts +208 -0
  329. package/src/composables/useRackEditor.ts +2 -11
  330. package/src/composables/useRequestSyncState.ts +98 -28
  331. package/src/composables/useResourceCrud.ts +6 -16
  332. package/src/composables/useRovingFocus.ts +66 -0
  333. package/src/composables/useScheduleDrag.ts +37 -0
  334. package/src/composables/useWellPainting.ts +10 -30
  335. package/src/composables/useWellPlateAdapter.ts +5 -1
  336. package/src/composables/useWellPlateEditor.ts +1 -11
  337. package/src/composables/useWellPlateValidation.ts +5 -1
  338. package/src/composables/workspaceRecipes.ts +267 -0
  339. package/src/index.ts +16 -0
  340. package/src/permissions.ts +48 -9
  341. package/src/stores/auth.ts +1 -0
  342. package/src/stores/experiment.ts +2 -7
  343. package/src/stores/index.ts +9 -1
  344. package/src/stores/settings.ts +93 -1
  345. package/src/styles/components/audit-trail.css +5 -5
  346. package/src/styles/components/batch-progress-list.css +7 -0
  347. package/src/styles/components/color-slider.css +2 -2
  348. package/src/styles/components/data-state.css +30 -0
  349. package/src/styles/components/dataframe.css +29 -35
  350. package/src/styles/components/experiment-data-viewer.css +4 -4
  351. package/src/styles/components/experiment-timeline.css +3 -30
  352. package/src/styles/components/form-builder.css +5 -5
  353. package/src/styles/components/lcms-sequence-table.css +16 -1
  354. package/src/styles/components/multi-select.css +1 -1
  355. package/src/styles/components/reagent-list.css +38 -31
  356. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  357. package/src/styles/components/sample-selector.css +9 -2
  358. package/src/styles/components/schedule-calendar.css +8 -0
  359. package/src/styles/components/scientific-number.css +1 -1
  360. package/src/styles/components/secret-input.css +60 -0
  361. package/src/styles/components/well-plate.css +8 -0
  362. package/src/styles/index.css +9 -0
  363. package/src/styles/variables.css +29 -0
  364. package/src/templates/builderPresetControls.ts +1 -1
  365. package/src/templates/builderReadUtils.ts +1 -3
  366. package/src/templates/componentPlateHelpers.ts +3 -1
  367. package/src/templates/componentTargetResolvers.ts +1 -3
  368. package/src/templates/controlSchemaTargets.ts +1 -3
  369. package/src/templates/doseResponseAdapters.ts +2 -13
  370. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  371. package/src/templates/plateMapBuilder.ts +2 -2
  372. package/src/templates/qpcrPlateBuilder.ts +1 -1
  373. package/src/templates/templateValidators.ts +1 -1
  374. package/src/templates/timeCourseBuilder.ts +2 -2
  375. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  376. package/src/types/auth.ts +1 -0
  377. package/src/types/form-builder.ts +1 -0
  378. package/src/utils/color.ts +51 -0
  379. package/src/utils/errors.ts +29 -0
  380. package/src/utils/formModelSync.ts +1 -3
  381. package/src/utils/pluginIcon.ts +1 -3
  382. package/src/utils/pluginSecrets.ts +102 -0
  383. package/src/utils/records.ts +9 -0
  384. package/dist/EmptyState-p90quq8Z.js.map +0 -1
  385. package/dist/ExperimentPopover-tLwJ7XF4.js.map +0 -1
  386. package/dist/ExperimentSelectorModal-DyPAUCLw.js.map +0 -1
  387. package/dist/SettingsModal-BgKY93zh.js.map +0 -1
  388. package/dist/components-DkHddRMl.js.map +0 -1
  389. package/dist/composables/autoGroupConstants.d.ts +0 -1
  390. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  391. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  392. package/dist/composables-C_i90sGS.js.map +0 -1
  393. package/dist/experiment-Cq145oEW.js.map +0 -1
  394. package/dist/experiment-utils-CLnzPPq5.js.map +0 -1
  395. package/dist/templates/builderDefaults.d.ts +0 -1
  396. package/dist/templates/plateGeometry.d.ts +0 -4
  397. package/dist/templates-DsP51i-S.js.map +0 -1
  398. package/dist/useApi-J6zFkHmn.js.map +0 -1
  399. package/dist/useControlSchema-BDx2Olha.js.map +0 -1
  400. package/dist/useDropdownState-DSb3BC3N.js.map +0 -1
  401. package/dist/useProtocolTemplates-CS_SQl6U.js.map +0 -1
  402. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  403. package/src/composables/autoGroupConstants.ts +0 -4
  404. package/src/composables/autoGroupGrouping.ts +0 -148
  405. package/src/composables/useAutoGroupInputSources.ts +0 -147
  406. package/src/templates/builderDefaults.ts +0 -11
  407. package/src/templates/plateGeometry.ts +0 -62
  408. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → components/DataStates.test.d.ts} +0 -0
@@ -0,0 +1,96 @@
1
+ <script setup lang="ts">
2
+ import GeneratedPlotlyResult from './GeneratedPlotlyResult.vue'
3
+
4
+ const scatterSpec: Record<string, unknown> = {
5
+ data: [
6
+ {
7
+ type: 'scatter',
8
+ mode: 'markers',
9
+ name: 'Control',
10
+ x: [1.2, 2.4, 3.1, 4.8, 5.5, 6.9],
11
+ y: [0.9, 1.8, 2.6, 3.9, 4.4, 5.8],
12
+ marker: { size: 9 },
13
+ },
14
+ {
15
+ type: 'scatter',
16
+ mode: 'markers',
17
+ name: 'Treated',
18
+ x: [1.1, 2.2, 3.4, 4.5, 5.9, 6.4],
19
+ y: [2.1, 3.4, 3.9, 5.2, 6.4, 7.1],
20
+ marker: { size: 9 },
21
+ },
22
+ ],
23
+ layout: {
24
+ margin: { t: 24, r: 16, b: 40, l: 48 },
25
+ xaxis: { title: 'log2 intensity (control)' },
26
+ yaxis: { title: 'log2 intensity (treated)' },
27
+ },
28
+ }
29
+
30
+ const barSpec: Record<string, unknown> = {
31
+ data: [
32
+ {
33
+ type: 'bar',
34
+ x: ['Glycolysis', 'TCA', 'PPP', 'Urea cycle'],
35
+ y: [12, 27, 8, 4],
36
+ },
37
+ ],
38
+ layout: { margin: { t: 24, r: 16, b: 40, l: 48 } },
39
+ }
40
+
41
+ // Not a valid Plotly spec — exercises the static-image fallback branch.
42
+ const brokenSpec: Record<string, unknown> = { data: 'not-an-array' }
43
+
44
+ const PIXEL_PNG
45
+ = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='
46
+
47
+ function initState() {
48
+ return { chart: 'scatter' as 'scatter' | 'bar' }
49
+ }
50
+ </script>
51
+
52
+ <template>
53
+ <Story title="Workflow/GeneratedPlotlyResult">
54
+ <Variant title="Playground" :init-state="initState">
55
+ <template #default="{ state }">
56
+ <div style="padding: 2rem; max-width: 720px;">
57
+ <GeneratedPlotlyResult :spec="state.chart === 'bar' ? barSpec : scatterSpec" />
58
+ </div>
59
+ </template>
60
+
61
+ <template #controls="{ state }">
62
+ <HstSelect
63
+ v-model="state.chart"
64
+ title="Chart"
65
+ :options="[
66
+ { label: 'scatter', value: 'scatter' },
67
+ { label: 'bar', value: 'bar' },
68
+ ]"
69
+ />
70
+ </template>
71
+ </Variant>
72
+
73
+ <Variant title="Scatter">
74
+ <div style="padding: 2rem; max-width: 720px;">
75
+ <GeneratedPlotlyResult :spec="scatterSpec" />
76
+ </div>
77
+ </Variant>
78
+
79
+ <Variant title="Bar">
80
+ <div style="padding: 2rem; max-width: 720px;">
81
+ <GeneratedPlotlyResult :spec="barSpec" />
82
+ </div>
83
+ </Variant>
84
+
85
+ <Variant title="Render failure → PNG fallback">
86
+ <!-- When Plotly cannot render the spec the component swaps in the
87
+ server-rendered static image, if the job supplied one. -->
88
+ <div style="padding: 2rem; max-width: 720px;">
89
+ <GeneratedPlotlyResult
90
+ :spec="brokenSpec"
91
+ :fallback="{ media_type: 'image/png', data: PIXEL_PNG }"
92
+ />
93
+ </div>
94
+ </Variant>
95
+ </Story>
96
+ </template>
@@ -79,9 +79,9 @@ onBeforeUnmount(() => {
79
79
  .mint-generated-result__plotly-error {
80
80
  margin: 0;
81
81
  padding: 1rem;
82
- border: 1px solid var(--color-danger-border, var(--color-border));
82
+ border: 1px solid var(--mint-error-border);
83
83
  border-radius: 0.75rem;
84
- background: var(--color-danger-bg, var(--color-bg-secondary));
85
- color: var(--color-danger-text, var(--color-text-primary));
84
+ background: var(--mint-error-bg);
85
+ color: var(--mint-error);
86
86
  }
87
87
  </style>
@@ -0,0 +1,145 @@
1
+ <script setup lang="ts">
2
+ import GeneratedPluginView from './GeneratedPluginView.vue'
3
+ import type { GeneratedAnalysisTransport } from '../composables/useGeneratedAnalysis'
4
+ import type { GeneratedAnalysisManifest } from '../types/generated-ui'
5
+
6
+ const manifest: GeneratedAnalysisManifest = {
7
+ schema_version: '1',
8
+ plugin: {
9
+ name: 'peak-qc',
10
+ version: '1.2.0',
11
+ description: 'Peak-picking quality control',
12
+ routes_prefix: '/api/peak-qc',
13
+ },
14
+ ui: {
15
+ title: 'Peak QC',
16
+ description: 'Score peak-picking output and flag features that need review.',
17
+ },
18
+ jobs: [
19
+ {
20
+ id: 'score-features',
21
+ title: 'Score features',
22
+ description: 'Compute RSD, blank ratio and detection rate for every feature.',
23
+ cpu: 4,
24
+ input_schema: {
25
+ type: 'object',
26
+ title: 'Scoring parameters',
27
+ properties: {
28
+ rsd_threshold: {
29
+ type: 'number',
30
+ title: 'QC RSD threshold',
31
+ description: 'Features above this relative standard deviation are flagged.',
32
+ default: 0.3,
33
+ minimum: 0,
34
+ maximum: 1,
35
+ },
36
+ blank_ratio: {
37
+ type: 'number',
38
+ title: 'Minimum blank ratio',
39
+ default: 3,
40
+ minimum: 1,
41
+ },
42
+ drop_flagged: {
43
+ type: 'boolean',
44
+ title: 'Drop flagged features',
45
+ default: false,
46
+ },
47
+ },
48
+ required: ['rsd_threshold'],
49
+ },
50
+ output_schema: { type: 'object' },
51
+ },
52
+ {
53
+ id: 'align-batches',
54
+ title: 'Align batches',
55
+ description: 'Retention-time align acquisition batches before merging.',
56
+ cpu: 8,
57
+ input_schema: {
58
+ type: 'object',
59
+ properties: {
60
+ tolerance_seconds: { type: 'number', title: 'RT tolerance (s)', default: 6 },
61
+ reference_batch: { type: 'string', title: 'Reference batch', default: 'batch-1' },
62
+ },
63
+ },
64
+ output_schema: { type: 'object' },
65
+ },
66
+ ],
67
+ }
68
+
69
+ const session = {
70
+ id: 'sess_story',
71
+ tab_id: 'tab_story',
72
+ created_at: new Date().toISOString(),
73
+ last_seen_at: new Date().toISOString(),
74
+ active_job_ids: [],
75
+ }
76
+
77
+ function json(body: unknown): Response {
78
+ return new Response(JSON.stringify(body), {
79
+ status: 200,
80
+ headers: { 'Content-Type': 'application/json' },
81
+ })
82
+ }
83
+
84
+ /** Serves the manifest, one session and an empty job list — no network. */
85
+ const readyTransport: GeneratedAnalysisTransport = async (input) => {
86
+ const url = String(input)
87
+ if (url.includes('/generated/manifest')) return json(manifest)
88
+ if (url.includes('/jobs/sessions')) return json({ sessions: [session] })
89
+ if (url.includes('/jobs')) return json({ jobs: [] })
90
+ return json({})
91
+ }
92
+
93
+ /** Never settles, so the workspace stays in its loading state. */
94
+ const loadingTransport: GeneratedAnalysisTransport = () => new Promise<Response>(() => {})
95
+
96
+ /** Fails the manifest request, so the workspace surfaces its error banner. */
97
+ const failingTransport: GeneratedAnalysisTransport = async () => (
98
+ new Response(JSON.stringify({ detail: 'Plugin runtime is not reachable' }), {
99
+ status: 503,
100
+ headers: { 'Content-Type': 'application/json' },
101
+ })
102
+ )
103
+
104
+ function initState() {
105
+ return { showStandaloneLabel: false }
106
+ }
107
+ </script>
108
+
109
+ <template>
110
+ <Story title="Workflow/GeneratedPluginView">
111
+ <Variant title="Playground" :init-state="initState">
112
+ <template #default="{ state }">
113
+ <div style="height: 42rem;">
114
+ <GeneratedPluginView
115
+ base-url="/story/peak-qc"
116
+ :transport="readyTransport"
117
+ :show-standalone-label="state.showStandaloneLabel"
118
+ />
119
+ </div>
120
+ </template>
121
+
122
+ <template #controls="{ state }">
123
+ <HstCheckbox v-model="state.showStandaloneLabel" title="Standalone label" />
124
+ </template>
125
+ </Variant>
126
+
127
+ <Variant title="Ready — two job definitions">
128
+ <div style="height: 42rem;">
129
+ <GeneratedPluginView base-url="/story/peak-qc" :transport="readyTransport" />
130
+ </div>
131
+ </Variant>
132
+
133
+ <Variant title="Loading">
134
+ <div style="height: 42rem;">
135
+ <GeneratedPluginView base-url="/story/loading" :transport="loadingTransport" />
136
+ </div>
137
+ </Variant>
138
+
139
+ <Variant title="Runtime unreachable">
140
+ <div style="height: 42rem;">
141
+ <GeneratedPluginView base-url="/story/failing" :transport="failingTransport" />
142
+ </div>
143
+ </Variant>
144
+ </Story>
145
+ </template>
@@ -207,7 +207,7 @@ onMounted(() => {
207
207
  min-width: 0;
208
208
  min-height: calc(100vh - 5rem);
209
209
  padding: clamp(1rem, 2.5vw, 2.5rem);
210
- background: var(--color-bg-primary);
210
+ background: var(--bg-primary);
211
211
  }
212
212
 
213
213
  .mint-generated-workspace__loading {
@@ -216,7 +216,7 @@ onMounted(() => {
216
216
  align-items: center;
217
217
  justify-content: center;
218
218
  gap: 0.75rem;
219
- color: var(--color-text-secondary);
219
+ color: var(--text-secondary);
220
220
  }
221
221
 
222
222
  .mint-generated-workspace__header {
@@ -230,19 +230,19 @@ onMounted(() => {
230
230
 
231
231
  .mint-generated-workspace__header h1 {
232
232
  margin: 0;
233
- color: var(--color-text-primary);
233
+ color: var(--text-primary);
234
234
  font-size: clamp(1.35rem, 2vw, 1.8rem);
235
235
  line-height: 1.2;
236
236
  }
237
237
 
238
238
  .mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {
239
239
  margin: 0.4rem 0 0;
240
- color: var(--color-text-secondary);
240
+ color: var(--text-secondary);
241
241
  }
242
242
 
243
243
  .mint-generated-workspace__eyebrow {
244
244
  margin: 0 0 0.35rem;
245
- color: var(--color-text-muted);
245
+ color: var(--text-muted);
246
246
  font-size: 0.72rem;
247
247
  font-weight: 700;
248
248
  letter-spacing: 0.08em;
@@ -258,10 +258,10 @@ onMounted(() => {
258
258
 
259
259
  .mint-generated-workspace__resources span {
260
260
  padding: 0.3rem 0.55rem;
261
- border: 1px solid var(--color-border);
261
+ border: 1px solid var(--border-color);
262
262
  border-radius: 999px;
263
- background: var(--color-bg-secondary);
264
- color: var(--color-text-secondary);
263
+ background: var(--bg-secondary);
264
+ color: var(--text-secondary);
265
265
  font-size: 0.75rem;
266
266
  font-weight: 600;
267
267
  }
@@ -271,9 +271,9 @@ onMounted(() => {
271
271
  min-height: 24rem;
272
272
  margin: 0 auto;
273
273
  padding: clamp(1rem, 2vw, 1.75rem);
274
- border: 1px solid var(--color-border);
274
+ border: 1px solid var(--border-color);
275
275
  border-radius: 1rem;
276
- background: var(--color-bg-secondary);
276
+ background: var(--bg-secondary);
277
277
  box-shadow: var(--shadow-sm);
278
278
  }
279
279
 
@@ -0,0 +1,117 @@
1
+ <script setup lang="ts">
2
+ import GeneratedResultRenderer from './GeneratedResultRenderer.vue'
3
+ import type { GeneratedAnalysisResult } from '../types/generated-ui'
4
+
5
+ const textResult: GeneratedAnalysisResult = {
6
+ kind: 'text',
7
+ text: 'Peak integration finished: 1,284 features across 96 samples, 12 flagged for manual review.',
8
+ }
9
+
10
+ const jsonResult: GeneratedAnalysisResult = {
11
+ kind: 'json',
12
+ value: {
13
+ method: 'HILIC_neg_12min',
14
+ features: 1284,
15
+ qc: { rsd_median: 0.041, blanks_removed: 37 },
16
+ flagged: ['M241T118', 'M317T204'],
17
+ },
18
+ }
19
+
20
+ const tableResult: GeneratedAnalysisResult = {
21
+ kind: 'table',
22
+ columns: ['feature_id', 'mz', 'retention_time', 'fold_change', 'p_value'],
23
+ rows: [
24
+ { feature_id: 'M180T204', mz: 180.0634, retention_time: 3.42, fold_change: 2.14, p_value: 0.0012 },
25
+ { feature_id: 'M241T118', mz: 241.0311, retention_time: 1.97, fold_change: -1.83, p_value: 0.0044 },
26
+ { feature_id: 'M317T204', mz: 317.0521, retention_time: 3.41, fold_change: 1.07, p_value: 0.2310 },
27
+ { feature_id: 'M146T092', mz: 146.0453, retention_time: 1.53, fold_change: -3.02, p_value: 0.0001 },
28
+ ],
29
+ }
30
+
31
+ // 1x1 transparent PNG — enough to exercise the image branch without a fixture.
32
+ const PIXEL_PNG
33
+ = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='
34
+
35
+ const imageResult: GeneratedAnalysisResult = {
36
+ kind: 'image',
37
+ media_type: 'image/png',
38
+ data: PIXEL_PNG,
39
+ alt: 'Static QC overview rendered by the plugin',
40
+ }
41
+
42
+ const artifactResult: GeneratedAnalysisResult = {
43
+ kind: 'artifact',
44
+ id: 'art_01J9',
45
+ name: 'peak_table.parquet',
46
+ media_type: 'application/vnd.apache.parquet',
47
+ size: 4_812_390,
48
+ download_url: '#download',
49
+ managed: true,
50
+ }
51
+
52
+ type ResultKind = 'text' | 'json' | 'table' | 'image' | 'artifact'
53
+
54
+ const kinds: ResultKind[] = ['text', 'json', 'table', 'image', 'artifact']
55
+
56
+ const byKind: Record<ResultKind, GeneratedAnalysisResult> = {
57
+ text: textResult,
58
+ json: jsonResult,
59
+ table: tableResult,
60
+ image: imageResult,
61
+ artifact: artifactResult,
62
+ }
63
+
64
+ function initState() {
65
+ return { kind: 'table' as ResultKind }
66
+ }
67
+ </script>
68
+
69
+ <template>
70
+ <Story title="Workflow/GeneratedResultRenderer">
71
+ <Variant title="Playground" :init-state="initState">
72
+ <template #default="{ state }">
73
+ <div style="padding: 2rem; max-width: 720px;">
74
+ <GeneratedResultRenderer :result="byKind[state.kind as ResultKind]" />
75
+ </div>
76
+ </template>
77
+
78
+ <template #controls="{ state }">
79
+ <HstSelect
80
+ v-model="state.kind"
81
+ title="Result kind"
82
+ :options="kinds.map(k => ({ label: k, value: k }))"
83
+ />
84
+ </template>
85
+ </Variant>
86
+
87
+ <Variant title="Text">
88
+ <div style="padding: 2rem; max-width: 720px;">
89
+ <GeneratedResultRenderer :result="textResult" />
90
+ </div>
91
+ </Variant>
92
+
93
+ <Variant title="Table">
94
+ <div style="padding: 2rem; max-width: 720px;">
95
+ <GeneratedResultRenderer :result="tableResult" />
96
+ </div>
97
+ </Variant>
98
+
99
+ <Variant title="JSON">
100
+ <div style="padding: 2rem; max-width: 720px;">
101
+ <GeneratedResultRenderer :result="jsonResult" />
102
+ </div>
103
+ </Variant>
104
+
105
+ <Variant title="Image">
106
+ <div style="padding: 2rem; max-width: 720px;">
107
+ <GeneratedResultRenderer :result="imageResult" />
108
+ </div>
109
+ </Variant>
110
+
111
+ <Variant title="Artifact download">
112
+ <div style="padding: 2rem; max-width: 720px;">
113
+ <GeneratedResultRenderer :result="artifactResult" />
114
+ </div>
115
+ </Variant>
116
+ </Story>
117
+ </template>
@@ -101,7 +101,7 @@ function humanize(value: string): string {
101
101
  .mint-generated-result__text,
102
102
  .mint-generated-result__json {
103
103
  margin: 0;
104
- color: var(--color-text-primary);
104
+ color: var(--text-primary);
105
105
  }
106
106
 
107
107
  .mint-generated-result__text {
@@ -113,9 +113,9 @@ function humanize(value: string): string {
113
113
  .mint-generated-result__json {
114
114
  overflow: auto;
115
115
  padding: 1rem;
116
- border: 1px solid var(--color-border);
116
+ border: 1px solid var(--border-color);
117
117
  border-radius: 0.75rem;
118
- background: var(--color-bg-secondary);
118
+ background: var(--bg-secondary);
119
119
  font-size: 0.8125rem;
120
120
  line-height: 1.55;
121
121
  white-space: pre-wrap;
@@ -139,7 +139,7 @@ function humanize(value: string): string {
139
139
  justify-content: space-between;
140
140
  gap: 1rem;
141
141
  padding: 1rem;
142
- border: 1px solid var(--color-border);
142
+ border: 1px solid var(--border-color);
143
143
  border-radius: 0.75rem;
144
144
  color: var(--color-primary);
145
145
  text-decoration: none;
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  /** Drag-and-drop two-zone assigner for splitting sample groups into control and treatment arms. */
3
- import { ref } from 'vue'
3
+ import { nextTick, ref, type ComponentPublicInstance } from 'vue'
4
4
  import type { GroupItem } from '../types'
5
5
  import { useGroupAssignment, type GroupAssignmentState, type GroupAssignmentZone } from '../composables/useGroupAssignment'
6
+ import { useReorderAnnouncer } from '../composables/useListReorder'
6
7
 
7
8
  interface Props {
8
9
  groups: GroupItem[]
@@ -98,6 +99,56 @@ function emitAssignment(state: GroupAssignmentState) {
98
99
  emit('update:group1', state.group1)
99
100
  emit('update:group2', state.group2)
100
101
  }
102
+
103
+ // Keyboard alternative to the pointer drag. GroupAssigner moves items between
104
+ // zones rather than reordering one list, so it shares the announcer (and the
105
+ // Alt+Arrow idiom) with useListReorder without its index maths.
106
+ const { announcement, announce, announcerStyle } = useReorderAnnouncer()
107
+ const pillRefs = new Map<string, HTMLElement>()
108
+
109
+ function setPillRef(name: string, el: Element | ComponentPublicInstance | null) {
110
+ if (el instanceof HTMLElement) {
111
+ pillRefs.set(name, el)
112
+ } else {
113
+ pillRefs.delete(name)
114
+ }
115
+ }
116
+
117
+ function zoneLabel(zone: GroupAssignmentZone | null): string {
118
+ if (zone === 'zone1') return props.label1
119
+ if (zone === 'zone2') return props.label2
120
+ return 'Available Groups'
121
+ }
122
+
123
+ /** Alt+Left / Alt+Right walk a group through Control → unassigned → Treatment. */
124
+ function handlePillKeydown(event: KeyboardEvent, groupName: string) {
125
+ if (!event.altKey) return
126
+ const direction =
127
+ event.key === 'ArrowLeft' ? -1 : event.key === 'ArrowRight' ? 1 : 0
128
+ if (direction === 0) return
129
+
130
+ event.preventDefault()
131
+ const order: Array<GroupAssignmentZone | null> = ['zone1', null, 'zone2']
132
+ const current = order.indexOf(assignment.getZoneForGroup(groupName))
133
+ const next = order[current + direction]
134
+ if (current === -1 || next === undefined) return
135
+
136
+ if (next === null) {
137
+ const from = assignment.getZoneForGroup(groupName)
138
+ if (from) removeFromZone(groupName, from)
139
+ } else {
140
+ assignToZone(groupName, next)
141
+ }
142
+
143
+ announce(`${groupName} moved to ${zoneLabel(next)}.`)
144
+ void nextTick(() => pillRefs.get(groupName)?.focus())
145
+ }
146
+
147
+ /** Instructions read out with each pill. */
148
+ function pillLabel(group: GroupItem): string {
149
+ const zone = assignment.getZoneForGroup(group.name)
150
+ return `${group.name}, ${zoneLabel(zone)}. Press Alt with the left or right arrow keys to move it.`
151
+ }
101
152
  </script>
102
153
 
103
154
  <template>
@@ -125,10 +176,14 @@ function emitAssignment(state: GroupAssignmentState) {
125
176
  <div
126
177
  v-for="group in zone1Groups"
127
178
  :key="group.name"
179
+ :ref="(el) => setPillRef(group.name, el)"
128
180
  class="mint-group-assigner__pill"
129
181
  draggable="true"
182
+ tabindex="0"
183
+ :aria-label="pillLabel(group)"
130
184
  @dragstart="handleDragStart($event, group.name)"
131
185
  @dragend="handleDragEnd"
186
+ @keydown="handlePillKeydown($event, group.name)"
132
187
  >
133
188
  <span
134
189
  class="mint-group-assigner__pill-color"
@@ -174,10 +229,14 @@ function emitAssignment(state: GroupAssignmentState) {
174
229
  <div
175
230
  v-for="group in zone2Groups"
176
231
  :key="group.name"
232
+ :ref="(el) => setPillRef(group.name, el)"
177
233
  class="mint-group-assigner__pill"
178
234
  draggable="true"
235
+ tabindex="0"
236
+ :aria-label="pillLabel(group)"
179
237
  @dragstart="handleDragStart($event, group.name)"
180
238
  @dragend="handleDragEnd"
239
+ @keydown="handlePillKeydown($event, group.name)"
181
240
  >
182
241
  <span
183
242
  class="mint-group-assigner__pill-color"
@@ -221,14 +280,18 @@ function emitAssignment(state: GroupAssignmentState) {
221
280
  <div
222
281
  v-for="group in unassignedGroups"
223
282
  :key="group.name"
283
+ :ref="(el) => setPillRef(group.name, el)"
224
284
  :class="[
225
285
  'mint-group-assigner__pill',
226
286
  'mint-group-assigner__pill--unassigned',
227
287
  draggingGroup === group.name ? 'mint-group-assigner__pill--dragging' : '',
228
288
  ]"
229
289
  draggable="true"
290
+ tabindex="0"
291
+ :aria-label="pillLabel(group)"
230
292
  @dragstart="handleDragStart($event, group.name)"
231
293
  @dragend="handleDragEnd"
294
+ @keydown="handlePillKeydown($event, group.name)"
232
295
  >
233
296
  <span
234
297
  class="mint-group-assigner__pill-color"
@@ -240,6 +303,9 @@ function emitAssignment(state: GroupAssignmentState) {
240
303
  </div>
241
304
  </div>
242
305
 
306
+ <!-- Assignment announcements for screen readers -->
307
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ announcement }}</div>
308
+
243
309
  <!-- Validation message -->
244
310
  <div v-if="validationMessage" class="mint-group-assigner__validation">
245
311
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -251,7 +317,3 @@ function emitAssignment(state: GroupAssignmentState) {
251
317
  </div>
252
318
  </div>
253
319
  </template>
254
-
255
- <style>
256
- @import '../styles/components/group-assigner.css';
257
- </style>
@@ -67,7 +67,3 @@ function handleClick(event: MouseEvent) {
67
67
  </span>
68
68
  </button>
69
69
  </template>
70
-
71
- <style>
72
- @import '../styles/components/icon-button.css';
73
- </style>
@@ -185,7 +185,3 @@ function alertDetail(alert: InstrumentAlert): string {
185
185
  </TransitionGroup>
186
186
  </div>
187
187
  </template>
188
-
189
- <style>
190
- @import '../styles/components/instrument-monitor.css';
191
- </style>
@@ -44,7 +44,3 @@ const shouldPulse = computed(() => props.pulseWhenRunning && normalizedState.val
44
44
  {{ label ?? config.label }}
45
45
  </span>
46
46
  </template>
47
-
48
- <style>
49
- @import '../styles/components/instrument-monitor.css';
50
- </style>
@@ -182,7 +182,3 @@ function hasRemaining(progress: SequenceProgress | null | undefined): boolean {
182
182
  </template>
183
183
  </div>
184
184
  </template>
185
-
186
- <style>
187
- @import '../styles/components/instrument-monitor.css';
188
- </style>
@@ -15,12 +15,24 @@ import {
15
15
  } from '../jobs'
16
16
  import {
17
17
  usePluginJobCenter,
18
+ type JobsStatusTrayAdapter,
18
19
  type PluginJobCenterSource,
19
20
  } from '../composables/useJobsStatusTray'
20
- import type { JobState } from '../types/jobs'
21
+ import type { UsePluginEventStreamReturn } from '../composables/usePluginClient'
22
+ import type {
23
+ JobState,
24
+ JobStateInput,
25
+ JobStreamData,
26
+ } from '../types/jobs'
21
27
 
22
28
  interface Props {
23
29
  source?: PluginJobCenterSource
30
+ /** @deprecated Pass a source instead. */
31
+ jobs?: readonly JobStateInput[]
32
+ /** @deprecated Pass source actions instead. */
33
+ adapter?: JobsStatusTrayAdapter
34
+ /** @deprecated Event streams belong to the source runtime. */
35
+ eventStream?: UsePluginEventStreamReturn<JobStreamData>
24
36
  loadOnMount?: boolean
25
37
  title?: string
26
38
  teleportTo?: string | HTMLElement | false
@@ -49,6 +61,9 @@ const panelRef = ref<HTMLElement | null>(null)
49
61
  const teleportTarget = computed(() => props.teleportTo || 'body')
50
62
  const tray = usePluginJobCenter({
51
63
  source: toRef(props, 'source'),
64
+ jobs: toRef(props, 'jobs'),
65
+ adapter: toRef(props, 'adapter'),
66
+ eventStream: toRef(props, 'eventStream'),
52
67
  loadOnMount: props.loadOnMount,
53
68
  })
54
69
  const canClear = computed(() => (
@@ -386,7 +401,3 @@ async function clearFinished(): Promise<void> {
386
401
  </div>
387
402
  </Teleport>
388
403
  </template>
389
-
390
- <style>
391
- @import '../styles/components/jobs-status-tray.css';
392
- </style>