@morscherlab/mint-sdk 1.2.0-beta.2 → 1.2.0-beta.20

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 (493) hide show
  1. package/README.md +65 -5
  2. package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-CJdNlCZb.js} +24 -15
  3. package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-DCXmwKNS.js} +5 -5
  5. package/dist/ExperimentSelectorModal-DCXmwKNS.js.map +1 -0
  6. package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-BYR20I4c.js} +5 -8
  7. package/dist/SettingsModal-BYR20I4c.js.map +1 -0
  8. package/dist/{EmptyState-p90quq8Z.js → Skeleton-BAF3CKY7.js} +111 -93
  9. package/dist/Skeleton-BAF3CKY7.js.map +1 -0
  10. package/dist/__tests__/components/DataStates.test.d.ts +1 -0
  11. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  12. package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
  13. package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
  14. package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
  15. package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
  16. package/dist/__tests__/components/PluginWorkspaceView.internal.test.d.ts +1 -0
  17. package/dist/__tests__/components/SecretInput.test.d.ts +1 -0
  18. package/dist/__tests__/components/WellEditPopupInternal.test.d.ts +1 -0
  19. package/dist/__tests__/components/iconButtonIconSizing.test.d.ts +1 -0
  20. package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
  21. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  22. package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
  23. package/dist/__tests__/composables/usePluginConfig.test.d.ts +15 -0
  24. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  25. package/dist/apiErrors.d.ts +26 -0
  26. package/dist/components/ActionMenu.vue.d.ts +1 -1
  27. package/dist/components/AppAvatarMenu.vue.d.ts +4 -0
  28. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  29. package/dist/components/AppSidebar.vue.d.ts +1 -1
  30. package/dist/components/AuditTrail.vue.d.ts +13 -0
  31. package/dist/components/AutoGroupModal.vue.d.ts +1 -1
  32. package/dist/components/BaseInput.vue.d.ts +1 -1
  33. package/dist/components/BaseSelect.vue.d.ts +1 -1
  34. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  35. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  36. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +4 -4
  37. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
  38. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  39. package/dist/components/DataFrame.vue.d.ts +14 -2
  40. package/dist/components/DatePicker.vue.d.ts +2 -2
  41. package/dist/components/DateTimePicker.vue.d.ts +3 -1
  42. package/dist/components/DropdownButton.vue.d.ts +2 -0
  43. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  44. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  45. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  46. package/dist/components/FileBrowserModal.vue.d.ts +99 -0
  47. package/dist/components/FilePicker.vue.d.ts +32 -0
  48. package/dist/components/FileUploader.vue.d.ts +5 -2
  49. package/dist/components/FitPanel.vue.d.ts +1 -1
  50. package/dist/components/FormulaInput.vue.d.ts +1 -1
  51. package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
  52. package/dist/components/JobsStatusTray.vue.d.ts +9 -2
  53. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  54. package/dist/components/MobileSupportGate.vue.d.ts +1 -1
  55. package/dist/components/MoleculeInput.vue.d.ts +1 -1
  56. package/dist/components/NumberInput.vue.d.ts +1 -1
  57. package/dist/components/PlotlyChart.vue.d.ts +59 -0
  58. package/dist/components/PluginWorkspaceView.props.d.ts +29 -1
  59. package/dist/components/PluginWorkspaceView.vue.d.ts +5 -5
  60. package/dist/components/ProgressBar.vue.d.ts +1 -1
  61. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  62. package/dist/components/ReagentList.vue.d.ts +29 -1
  63. package/dist/components/ResourceCard.vue.d.ts +1 -1
  64. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  65. package/dist/components/SampleLegend.vue.d.ts +1 -1
  66. package/dist/components/SampleSelector.drag.d.ts +13 -0
  67. package/dist/components/SampleSelector.tree.d.ts +2 -0
  68. package/dist/components/SampleSelector.vue.d.ts +35 -2
  69. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  70. package/dist/components/SecretInput.vue.d.ts +28 -0
  71. package/dist/components/SequenceInput.vue.d.ts +1 -1
  72. package/dist/components/SettingsModal.vue.d.ts +1 -1
  73. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -1
  74. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  75. package/dist/components/TagsInput.vue.d.ts +1 -1
  76. package/dist/components/TimePicker.vue.d.ts +2 -1
  77. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  78. package/dist/components/UnitInput.vue.d.ts +1 -1
  79. package/dist/components/WellPlate.geometry.d.ts +15 -0
  80. package/dist/components/WellPlate.interaction.d.ts +13 -0
  81. package/dist/components/WellPlate.vue.d.ts +30 -1
  82. package/dist/components/fileBrowserPresentation.d.ts +10 -0
  83. package/dist/components/index.d.ts +13 -0
  84. package/dist/components/index.js +8 -8
  85. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  86. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  87. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
  88. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
  89. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
  90. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
  91. package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
  92. package/dist/components/internal/WellEditPopupInternal.vue.d.ts +3 -1
  93. package/dist/components/internal/WorkspaceControlsInternal.vue.d.ts +23 -0
  94. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +70 -0
  95. package/dist/components/internal/WorkspaceSidebarInternal.vue.d.ts +43 -0
  96. package/dist/{components-DkHddRMl.js → components-DIum5hkx.js} +5882 -3200
  97. package/dist/components-DIum5hkx.js.map +1 -0
  98. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  99. package/dist/composables/filePicker/localFiles.d.ts +3 -0
  100. package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
  101. package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
  102. package/dist/composables/filePicker/validation.d.ts +5 -0
  103. package/dist/composables/flattenWorkspaceBindings.d.ts +61 -0
  104. package/dist/composables/index.d.ts +11 -2
  105. package/dist/composables/index.js +10 -10
  106. package/dist/composables/pluginWorkspaceModel.d.ts +164 -0
  107. package/dist/composables/useApi.d.ts +14 -7
  108. package/dist/composables/useAsync.d.ts +5 -1
  109. package/dist/composables/useBioTemplateWorkspace.d.ts +4 -20
  110. package/dist/composables/useCommandHistory.d.ts +5 -1
  111. package/dist/composables/useDropdownState.d.ts +18 -2
  112. package/dist/composables/useEventStream.d.ts +9 -0
  113. package/dist/composables/useFileBrowser.d.ts +55 -0
  114. package/dist/composables/useFilePicker.d.ts +189 -0
  115. package/dist/composables/useFocusTrap.d.ts +21 -0
  116. package/dist/composables/useGeneratedAnalysis.d.ts +3 -1
  117. package/dist/composables/useJobsStatusTray.d.ts +25 -1
  118. package/dist/composables/useListReorder.d.ts +90 -0
  119. package/dist/composables/useMenuKeyboard.d.ts +29 -0
  120. package/dist/composables/useOptimisticMutation.d.ts +5 -1
  121. package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
  122. package/dist/composables/usePluginClient.d.ts +2 -0
  123. package/dist/composables/usePluginConfig.d.ts +27 -0
  124. package/dist/composables/usePluginWorkspace.d.ts +51 -0
  125. package/dist/composables/useRequestSyncState.d.ts +42 -2
  126. package/dist/composables/useResourceCrud.d.ts +5 -1
  127. package/dist/composables/useRovingFocus.d.ts +24 -0
  128. package/dist/composables/useScheduleDrag.d.ts +1 -0
  129. package/dist/composables/useWellPainting.d.ts +5 -1
  130. package/dist/composables/useWellPlateAdapter.d.ts +5 -1
  131. package/dist/composables/useWellPlateValidation.d.ts +5 -1
  132. package/dist/composables/workspaceRecipes.d.ts +188 -0
  133. package/dist/{composables-C_i90sGS.js → composables-mFXsTA4g.js} +502 -86
  134. package/dist/composables-mFXsTA4g.js.map +1 -0
  135. package/dist/{useApi-J6zFkHmn.js → errors-BLuqMee5.js} +179 -16
  136. package/dist/errors-BLuqMee5.js.map +1 -0
  137. package/dist/{experiment-Cq145oEW.js → experiment-CVDRAnqp.js} +3 -8
  138. package/dist/experiment-CVDRAnqp.js.map +1 -0
  139. package/dist/{experiment-utils-CLnzPPq5.js → experiment-utils-CV2Wza3z.js} +70 -51
  140. package/dist/experiment-utils-CV2Wza3z.js.map +1 -0
  141. package/dist/index.d.ts +2 -0
  142. package/dist/index.js +15 -15
  143. package/dist/install.js +2 -7
  144. package/dist/install.js.map +1 -1
  145. package/dist/permissions.d.ts +42 -1
  146. package/dist/permissions.js +20 -10
  147. package/dist/permissions.js.map +1 -1
  148. package/dist/stores/auth.d.ts +6 -0
  149. package/dist/stores/index.d.ts +1 -1
  150. package/dist/stores/index.js +3 -3
  151. package/dist/stores/settings.d.ts +31 -1
  152. package/dist/styles.css +15135 -32397
  153. package/dist/templates/builderReadUtils.d.ts +1 -1
  154. package/dist/templates/index.js +2 -4
  155. package/dist/{templates-DsP51i-S.js → templates-CmGfmBRA.js} +303 -106
  156. package/dist/templates-CmGfmBRA.js.map +1 -0
  157. package/dist/types/auth.d.ts +1 -0
  158. package/dist/types/fileBrowserTypes.d.ts +77 -0
  159. package/dist/types/filePicker.d.ts +77 -0
  160. package/dist/types/form-builder.d.ts +1 -1
  161. package/dist/types/index.d.ts +2 -0
  162. package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-DldpxNOP.js} +499 -1162
  163. package/dist/useControlSchema-DldpxNOP.js.map +1 -0
  164. package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-C7hRiVQf.js} +22 -6
  165. package/dist/useDropdownState-C7hRiVQf.js.map +1 -0
  166. package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-CEcIaueJ.js} +4 -4
  167. package/dist/{useExperimentSelector-CV4iNfMS.js.map → useExperimentSelector-CEcIaueJ.js.map} +1 -1
  168. package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-z5L_dUIy.js} +2 -2
  169. package/dist/{useFormBuilder-BLxG3BOX.js.map → useFormBuilder-z5L_dUIy.js.map} +1 -1
  170. package/dist/utils/color.d.ts +13 -0
  171. package/dist/utils/errors.d.ts +9 -0
  172. package/dist/utils/pluginSecrets.d.ts +53 -0
  173. package/dist/utils/records.d.ts +4 -0
  174. package/dist/{useProtocolTemplates-CS_SQl6U.js → validation-uwoJGEb6.js} +811 -212
  175. package/dist/validation-uwoJGEb6.js.map +1 -0
  176. package/package.json +1 -1
  177. package/src/__tests__/apiErrors.test.ts +81 -0
  178. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  179. package/src/__tests__/components/AppAvatarMenu.test.ts +123 -0
  180. package/src/__tests__/components/BaseTabs.test.ts +67 -0
  181. package/src/__tests__/components/DataFrame.test.ts +183 -11
  182. package/src/__tests__/components/DataStates.test.ts +176 -0
  183. package/src/__tests__/components/DatePicker.test.ts +76 -0
  184. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  185. package/src/__tests__/components/DropdownButton.test.ts +134 -0
  186. package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
  187. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  188. package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
  189. package/src/__tests__/components/FilePicker.state.test.ts +287 -0
  190. package/src/__tests__/components/FilePicker.test.ts +487 -0
  191. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
  192. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  193. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  194. package/src/__tests__/components/PlotlyChart.test.ts +305 -0
  195. package/src/__tests__/components/PluginWorkspaceView.internal.test.ts +230 -0
  196. package/src/__tests__/components/RackEditor.test.ts +35 -0
  197. package/src/__tests__/components/ReagentList.test.ts +64 -2
  198. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  199. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  200. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  201. package/src/__tests__/components/SecretInput.test.ts +87 -0
  202. package/src/__tests__/components/SegmentedControl.test.ts +107 -0
  203. package/src/__tests__/components/TimePicker.test.ts +61 -0
  204. package/src/__tests__/components/WellEditPopupInternal.test.ts +108 -0
  205. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  206. package/src/__tests__/components/iconButtonIconSizing.test.ts +18 -0
  207. package/src/__tests__/composables/useApi.test.ts +92 -9
  208. package/src/__tests__/composables/useAuth.test.ts +2 -0
  209. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  210. package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
  211. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
  212. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  213. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
  214. package/src/__tests__/composables/usePluginClient.test.ts +143 -0
  215. package/src/__tests__/composables/usePluginConfig.test.ts +497 -0
  216. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  217. package/src/__tests__/docs/frontendDocsCatalog.test.ts +39 -7
  218. package/src/__tests__/stores/settings.test.ts +71 -1
  219. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  220. package/src/__tests__/utils/permissions.test.ts +68 -0
  221. package/src/apiErrors.ts +85 -0
  222. package/src/components/ActionMenu.vue +45 -88
  223. package/src/components/AlertBox.vue +0 -4
  224. package/src/components/AppAvatarMenu.vue +26 -7
  225. package/src/components/AppLayout.vue +0 -4
  226. package/src/components/AppPluginSwitcher.story.vue +87 -0
  227. package/src/components/AppPluginSwitcher.vue +2 -5
  228. package/src/components/AppSidebar.vue +0 -4
  229. package/src/components/AppToastContainer.vue +6 -8
  230. package/src/components/AppTopBar.vue +0 -4
  231. package/src/components/ArtifactSaveDialog.vue +0 -4
  232. package/src/components/ArtifactSelectorModal.vue +0 -4
  233. package/src/components/AuditTrail.story.vue +18 -0
  234. package/src/components/AuditTrail.vue +27 -7
  235. package/src/components/AutoGroupModal.vue +0 -4
  236. package/src/components/Avatar.vue +0 -4
  237. package/src/components/BaseButton.vue +0 -4
  238. package/src/components/BaseCheckbox.vue +0 -4
  239. package/src/components/BaseInput.vue +0 -4
  240. package/src/components/BaseModal.vue +8 -60
  241. package/src/components/BasePill.vue +0 -4
  242. package/src/components/BaseRadioGroup.vue +0 -4
  243. package/src/components/BaseSelect.vue +0 -4
  244. package/src/components/BaseSlider.vue +0 -4
  245. package/src/components/BaseTabs.vue +26 -5
  246. package/src/components/BaseTextarea.vue +0 -4
  247. package/src/components/BaseToggle.vue +0 -4
  248. package/src/components/BatchProgressList.story.vue +18 -0
  249. package/src/components/BatchProgressList.vue +32 -4
  250. package/src/components/BioTemplateExperimentWorkspaceView.vue +10 -21
  251. package/src/components/BioTemplatePackWorkspaceView.vue +11 -15
  252. package/src/components/BioTemplatePresetWorkspaceView.vue +8 -13
  253. package/src/components/Breadcrumb.vue +0 -4
  254. package/src/components/Calendar.vue +0 -4
  255. package/src/components/ChartContainer.story.vue +1 -1
  256. package/src/components/ChartContainer.vue +0 -4
  257. package/src/components/ChemicalFormula.vue +0 -4
  258. package/src/components/CollapsibleCard.vue +0 -4
  259. package/src/components/ColorSlider.vue +0 -4
  260. package/src/components/ComponentBindingRenderer.vue +1 -3
  261. package/src/components/ConcentrationInput.vue +0 -4
  262. package/src/components/ConfirmDialog.vue +0 -4
  263. package/src/components/ControlWorkspaceView.vue +11 -22
  264. package/src/components/DataFrame.story.vue +14 -0
  265. package/src/components/DataFrame.vue +97 -23
  266. package/src/components/DatePicker.vue +73 -27
  267. package/src/components/DateTimePicker.vue +45 -17
  268. package/src/components/Divider.vue +0 -4
  269. package/src/components/DoseCalculator.vue +0 -4
  270. package/src/components/DoseDesignWorkspaceView.vue +6 -25
  271. package/src/components/DropdownButton.vue +24 -6
  272. package/src/components/EmptyState.vue +0 -4
  273. package/src/components/ExperimentCodeBadge.vue +0 -4
  274. package/src/components/ExperimentDataViewer.story.vue +3 -0
  275. package/src/components/ExperimentDataViewer.vue +33 -13
  276. package/src/components/ExperimentPopover.vue +12 -7
  277. package/src/components/ExperimentSelectorModal.vue +0 -4
  278. package/src/components/ExperimentTimeline.story.vue +18 -0
  279. package/src/components/ExperimentTimeline.vue +81 -75
  280. package/src/components/FileBrowserModal.story.vue +203 -0
  281. package/src/components/FileBrowserModal.vue +384 -0
  282. package/src/components/FilePicker.story.vue +44 -0
  283. package/src/components/FilePicker.vue +284 -0
  284. package/src/components/FileUploader.vue +32 -18
  285. package/src/components/FitPanel.vue +0 -4
  286. package/src/components/FormActions.story.vue +96 -0
  287. package/src/components/FormActions.vue +0 -4
  288. package/src/components/FormBuilder.vue +0 -4
  289. package/src/components/FormField.vue +0 -4
  290. package/src/components/FormulaInput.vue +0 -4
  291. package/src/components/GeneratedPathInput.story.vue +68 -0
  292. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  293. package/src/components/GeneratedPlotlyResult.vue +34 -69
  294. package/src/components/GeneratedPluginView.story.vue +145 -0
  295. package/src/components/GeneratedPluginView.vue +10 -10
  296. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  297. package/src/components/GeneratedResultRenderer.vue +4 -9
  298. package/src/components/GroupAssigner.vue +67 -5
  299. package/src/components/IconButton.vue +0 -4
  300. package/src/components/InstrumentAlertLog.vue +0 -4
  301. package/src/components/InstrumentStateBadge.vue +0 -4
  302. package/src/components/InstrumentStatusCard.vue +0 -4
  303. package/src/components/JobsStatusTray.vue +16 -5
  304. package/src/components/LcmsSequenceTable.vue +81 -50
  305. package/src/components/LoadingSpinner.vue +0 -4
  306. package/src/components/MobileSupportGate.vue +0 -4
  307. package/src/components/MoleculeInput.vue +0 -4
  308. package/src/components/MultiSelect.vue +0 -4
  309. package/src/components/NumberInput.vue +0 -4
  310. package/src/components/PlateMapEditor.vue +3 -14
  311. package/src/components/PlotlyChart.story.vue +61 -0
  312. package/src/components/PlotlyChart.vue +233 -0
  313. package/src/components/PluginIcon.vue +0 -4
  314. package/src/components/PluginWorkspaceView.props.ts +38 -0
  315. package/src/components/PluginWorkspaceView.vue +53 -224
  316. package/src/components/ProgressBar.vue +0 -4
  317. package/src/components/ProtocolStepEditor.vue +2 -4
  318. package/src/components/RackEditor.vue +51 -70
  319. package/src/components/ReagentEditor.vue +0 -4
  320. package/src/components/ReagentList.story.vue +18 -0
  321. package/src/components/ReagentList.vue +127 -82
  322. package/src/components/ResourceCard.vue +0 -4
  323. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  324. package/src/components/RuntimeUpdateNotice.vue +4 -4
  325. package/src/components/SampleHierarchyTree.story.vue +18 -0
  326. package/src/components/SampleHierarchyTree.vue +32 -9
  327. package/src/components/SampleLegend.vue +2 -8
  328. package/src/components/SampleSelector.drag.ts +51 -0
  329. package/src/components/SampleSelector.story.vue +6 -0
  330. package/src/components/SampleSelector.tree.ts +2 -0
  331. package/src/components/SampleSelector.vue +49 -10
  332. package/src/components/SampleSelectorGroupNode.vue +19 -0
  333. package/src/components/ScheduleCalendar.story.vue +6 -0
  334. package/src/components/ScheduleCalendar.vue +82 -7
  335. package/src/components/ScientificNumber.vue +0 -4
  336. package/src/components/SecretInput.story.vue +79 -0
  337. package/src/components/SecretInput.vue +150 -0
  338. package/src/components/SectionCard.vue +0 -4
  339. package/src/components/SegmentedControl.vue +50 -7
  340. package/src/components/SequenceInput.vue +0 -4
  341. package/src/components/SequenceProgressBar.story.vue +110 -0
  342. package/src/components/SequenceProgressBar.vue +0 -4
  343. package/src/components/SettingsModal.vue +0 -4
  344. package/src/components/Skeleton.vue +0 -4
  345. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  346. package/src/components/SmartGroupManual.vue +0 -4
  347. package/src/components/StatusIndicator.vue +0 -4
  348. package/src/components/StepWizard.vue +0 -4
  349. package/src/components/TagsInput.vue +4 -6
  350. package/src/components/ThemeToggle.vue +0 -4
  351. package/src/components/TimePicker.vue +36 -7
  352. package/src/components/TimeRangeInput.vue +0 -4
  353. package/src/components/Tooltip.story.vue +3 -3
  354. package/src/components/Tooltip.vue +0 -4
  355. package/src/components/UnitInput.vue +0 -4
  356. package/src/components/WellPlate.geometry.ts +60 -1
  357. package/src/components/WellPlate.interaction.ts +44 -0
  358. package/src/components/WellPlate.story.vue +8 -0
  359. package/src/components/WellPlate.vue +53 -7
  360. package/src/components/fileBrowserPresentation.ts +39 -0
  361. package/src/components/index.ts +14 -0
  362. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  363. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  364. package/src/components/internal/DataStateInternal.vue +74 -0
  365. package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
  366. package/src/components/internal/FileBrowserListingInternal.vue +197 -0
  367. package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
  368. package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
  369. package/src/components/internal/FilePickerTreeInternal.vue +238 -0
  370. package/src/components/internal/FormSectionRenderer.vue +0 -4
  371. package/src/components/internal/WellEditPopupInternal.vue +20 -5
  372. package/src/components/internal/WorkspaceControlsInternal.vue +20 -0
  373. package/src/components/internal/WorkspaceShellInternal.vue +125 -0
  374. package/src/components/internal/WorkspaceSidebarInternal.vue +82 -0
  375. package/src/composables/controlSchemaTypes.ts +34 -0
  376. package/src/composables/experimentDesignData.ts +1 -3
  377. package/src/composables/filePicker/localFiles.ts +58 -0
  378. package/src/composables/filePicker/usePickerNavigation.ts +220 -0
  379. package/src/composables/filePicker/usePickerSelection.ts +259 -0
  380. package/src/composables/filePicker/validation.ts +41 -0
  381. package/src/composables/flattenWorkspaceBindings.ts +104 -0
  382. package/src/composables/formBuilderRegistry.ts +5 -0
  383. package/src/composables/index.ts +50 -0
  384. package/src/composables/pluginWorkspaceModel.ts +182 -0
  385. package/src/composables/useApi.ts +57 -13
  386. package/src/composables/useAsync.ts +5 -1
  387. package/src/composables/useAuth.ts +3 -0
  388. package/src/composables/useBioTemplatePackWorkspace.ts +15 -9
  389. package/src/composables/useBioTemplatePresetWorkspace.ts +14 -15
  390. package/src/composables/useBioTemplateWorkspace.ts +18 -43
  391. package/src/composables/useCommandHistory.ts +5 -1
  392. package/src/composables/useDropdownState.ts +35 -5
  393. package/src/composables/useEventStream.ts +14 -2
  394. package/src/composables/useFileBrowser.ts +314 -0
  395. package/src/composables/useFileImport.ts +2 -7
  396. package/src/composables/useFilePicker.ts +366 -0
  397. package/src/composables/useFocusTrap.ts +91 -0
  398. package/src/composables/useGeneratedAnalysis.ts +32 -27
  399. package/src/composables/useJobsStatusTray.ts +184 -17
  400. package/src/composables/useListReorder.story.vue +143 -0
  401. package/src/composables/useListReorder.ts +242 -0
  402. package/src/composables/useMenuKeyboard.ts +90 -0
  403. package/src/composables/useOptimisticMutation.ts +6 -16
  404. package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
  405. package/src/composables/usePluginClient.ts +50 -4
  406. package/src/composables/usePluginConfig.ts +252 -0
  407. package/src/composables/usePluginWorkspace.ts +208 -0
  408. package/src/composables/useRackEditor.ts +2 -11
  409. package/src/composables/useRequestSyncState.ts +98 -28
  410. package/src/composables/useResourceCrud.ts +6 -16
  411. package/src/composables/useRovingFocus.ts +66 -0
  412. package/src/composables/useScheduleDrag.ts +37 -0
  413. package/src/composables/useWellPainting.ts +10 -30
  414. package/src/composables/useWellPlateAdapter.ts +5 -1
  415. package/src/composables/useWellPlateEditor.ts +1 -11
  416. package/src/composables/useWellPlateValidation.ts +5 -1
  417. package/src/composables/workspaceRecipes.ts +267 -0
  418. package/src/index.ts +19 -0
  419. package/src/permissions.ts +48 -9
  420. package/src/stores/auth.ts +1 -0
  421. package/src/stores/experiment.ts +2 -7
  422. package/src/stores/index.ts +9 -1
  423. package/src/stores/settings.ts +93 -1
  424. package/src/styles/components/audit-trail.css +5 -5
  425. package/src/styles/components/batch-progress-list.css +7 -0
  426. package/src/styles/components/color-slider.css +2 -2
  427. package/src/styles/components/data-state.css +30 -0
  428. package/src/styles/components/dataframe.css +29 -35
  429. package/src/styles/components/experiment-data-viewer.css +4 -4
  430. package/src/styles/components/experiment-timeline.css +3 -30
  431. package/src/styles/components/file-browser-modal.css +489 -0
  432. package/src/styles/components/file-picker.css +502 -0
  433. package/src/styles/components/form-builder.css +5 -5
  434. package/src/styles/components/icon-button.css +9 -0
  435. package/src/styles/components/lcms-sequence-table.css +16 -1
  436. package/src/styles/components/multi-select.css +1 -1
  437. package/src/styles/components/reagent-list.css +38 -31
  438. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  439. package/src/styles/components/sample-selector.css +9 -2
  440. package/src/styles/components/schedule-calendar.css +8 -0
  441. package/src/styles/components/scientific-number.css +1 -1
  442. package/src/styles/components/secret-input.css +60 -0
  443. package/src/styles/components/well-plate.css +8 -0
  444. package/src/styles/index.css +12 -0
  445. package/src/styles/variables.css +29 -0
  446. package/src/templates/builderPresetControls.ts +1 -1
  447. package/src/templates/builderReadUtils.ts +1 -3
  448. package/src/templates/componentPlateHelpers.ts +3 -1
  449. package/src/templates/componentTargetResolvers.ts +1 -3
  450. package/src/templates/controlSchemaTargets.ts +1 -3
  451. package/src/templates/doseResponseAdapters.ts +2 -13
  452. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  453. package/src/templates/plateMapBuilder.ts +2 -2
  454. package/src/templates/qpcrPlateBuilder.ts +1 -1
  455. package/src/templates/templateValidators.ts +1 -1
  456. package/src/templates/timeCourseBuilder.ts +2 -2
  457. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  458. package/src/types/auth.ts +1 -0
  459. package/src/types/fileBrowserTypes.ts +85 -0
  460. package/src/types/filePicker.ts +72 -0
  461. package/src/types/form-builder.ts +1 -0
  462. package/src/types/index.ts +14 -0
  463. package/src/utils/color.ts +51 -0
  464. package/src/utils/errors.ts +29 -0
  465. package/src/utils/formModelSync.ts +1 -3
  466. package/src/utils/pluginIcon.ts +1 -3
  467. package/src/utils/pluginSecrets.ts +102 -0
  468. package/src/utils/records.ts +9 -0
  469. package/dist/EmptyState-p90quq8Z.js.map +0 -1
  470. package/dist/ExperimentPopover-tLwJ7XF4.js.map +0 -1
  471. package/dist/ExperimentSelectorModal-DyPAUCLw.js.map +0 -1
  472. package/dist/SettingsModal-BgKY93zh.js.map +0 -1
  473. package/dist/components-DkHddRMl.js.map +0 -1
  474. package/dist/composables/autoGroupConstants.d.ts +0 -1
  475. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  476. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  477. package/dist/composables-C_i90sGS.js.map +0 -1
  478. package/dist/experiment-Cq145oEW.js.map +0 -1
  479. package/dist/experiment-utils-CLnzPPq5.js.map +0 -1
  480. package/dist/templates/builderDefaults.d.ts +0 -1
  481. package/dist/templates/plateGeometry.d.ts +0 -4
  482. package/dist/templates-DsP51i-S.js.map +0 -1
  483. package/dist/useApi-J6zFkHmn.js.map +0 -1
  484. package/dist/useControlSchema-BDx2Olha.js.map +0 -1
  485. package/dist/useDropdownState-DSb3BC3N.js.map +0 -1
  486. package/dist/useProtocolTemplates-CS_SQl6U.js.map +0 -1
  487. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  488. package/src/composables/autoGroupConstants.ts +0 -4
  489. package/src/composables/autoGroupGrouping.ts +0 -148
  490. package/src/composables/useAutoGroupInputSources.ts +0 -147
  491. package/src/templates/builderDefaults.ts +0 -11
  492. package/src/templates/plateGeometry.ts +0 -62
  493. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → apiErrors.test.d.ts} +0 -0
@@ -21,6 +21,8 @@ const allCompleted = [
21
21
 
22
22
  function initState() {
23
23
  return {
24
+ loading: false,
25
+ error: '',
24
26
  items: mixedItems,
25
27
  showSummary: true,
26
28
  title: 'Processing Raw Data Files',
@@ -35,6 +37,8 @@ function initState() {
35
37
  <template #default="{ state }">
36
38
  <div style="padding: 2rem; max-width: 500px;">
37
39
  <BatchProgressList
40
+ :loading="state.loading"
41
+ :error="state.error || null"
38
42
  :items="state.items"
39
43
  :show-summary="state.showSummary"
40
44
  :title="state.title"
@@ -45,6 +49,8 @@ function initState() {
45
49
  </div>
46
50
  </template>
47
51
  <template #controls="{ state }">
52
+ <HstCheckbox v-model="state.loading" title="Loading" />
53
+ <HstText v-model="state.error" title="Error Message" />
48
54
  <HstCheckbox v-model="state.showSummary" title="Show Summary" />
49
55
  <HstText v-model="state.title" title="Title" />
50
56
  <HstCheckbox v-model="state.autoScroll" title="Auto Scroll" />
@@ -88,5 +94,17 @@ function initState() {
88
94
  />
89
95
  </div>
90
96
  </Variant>
97
+
98
+ <Variant title="Loading">
99
+ <div style="padding: 2rem; max-width: 600px;">
100
+ <BatchProgressList :items="[]" loading />
101
+ </div>
102
+ </Variant>
103
+
104
+ <Variant title="Error">
105
+ <div style="padding: 2rem; max-width: 600px;">
106
+ <BatchProgressList :items="[]" error="Could not load the batch." />
107
+ </div>
108
+ </Variant>
91
109
  </Story>
92
110
  </template>
@@ -3,6 +3,7 @@
3
3
  import { computed, ref, watch, nextTick } from 'vue'
4
4
  import type { BatchItem, BatchSummary } from '../types'
5
5
  import { useExpansionSet } from '../composables/useExpansionSet'
6
+ import DataStateInternal from './internal/DataStateInternal.vue'
6
7
 
7
8
  interface Props {
8
9
  items: BatchItem[]
@@ -10,11 +11,23 @@ interface Props {
10
11
  title?: string
11
12
  maxHeight?: string
12
13
  autoScroll?: boolean
14
+ /** Replace the item list with a loading placeholder. */
15
+ loading?: boolean
16
+ /**
17
+ * Error message. When set, the item list is replaced by an error state.
18
+ * `null`/`undefined` renders normally.
19
+ */
20
+ error?: string | null
21
+ /** Empty-state headline shown when there are no batch items. */
22
+ emptyMessage?: string
13
23
  }
14
24
 
15
25
  const props = withDefaults(defineProps<Props>(), {
16
26
  showSummary: true,
17
27
  autoScroll: true,
28
+ loading: false,
29
+ error: null,
30
+ emptyMessage: 'No items in this batch',
18
31
  })
19
32
 
20
33
  const emit = defineEmits<{
@@ -91,7 +104,26 @@ watch(
91
104
  </div>
92
105
  </slot>
93
106
 
107
+ <div v-if="error" class="mint-batch-progress__state">
108
+ <slot name="error" :error="error">
109
+ <DataStateInternal state="error" size="sm" :title="error" />
110
+ </slot>
111
+ </div>
112
+
113
+ <div v-else-if="loading" class="mint-batch-progress__state">
114
+ <slot name="loading">
115
+ <DataStateInternal state="loading" size="sm" loading-label="Loading batch" />
116
+ </slot>
117
+ </div>
118
+
119
+ <div v-else-if="items.length === 0" class="mint-batch-progress__state">
120
+ <slot name="empty">
121
+ <DataStateInternal state="empty" size="sm" :title="emptyMessage" />
122
+ </slot>
123
+ </div>
124
+
94
125
  <div
126
+ v-else
95
127
  ref="listRef"
96
128
  class="mint-batch-progress__list"
97
129
  :style="maxHeight ? { maxHeight, overflowY: 'auto' } : {}"
@@ -175,7 +207,3 @@ watch(
175
207
  </div>
176
208
  </div>
177
209
  </template>
178
-
179
- <style>
180
- @import '../styles/components/batch-progress-list.css';
181
- </style>
@@ -19,6 +19,7 @@ import {
19
19
  type BioTemplateComponentPropsLookupOptions,
20
20
  type TemplateCollectionEnvelope,
21
21
  } from '../templates'
22
+ import { bioTemplateExperimentWorkspaceProps } from '../composables/workspaceRecipes'
22
23
  import AlertBox from './AlertBox.vue'
23
24
  import BaseButton from './BaseButton.vue'
24
25
  import BioTemplateRenderer from './BioTemplateRenderer.vue'
@@ -114,27 +115,15 @@ const statusMessage = computed(() => {
114
115
  return `${props.label} template data saves to experiment design_data.`
115
116
  })
116
117
 
117
- const resolvedLoading = computed(() => {
118
- if (props.status?.loading !== undefined || props.status?.saving !== undefined) {
119
- return Boolean(props.status.loading) || Boolean(props.status.saving)
120
- }
121
- return props.loading
122
- })
123
- const resolvedError = computed(() =>
124
- props.status?.error !== undefined ? props.status.error : props.error,
125
- )
126
- const resolvedHasExperiment = computed(() =>
127
- props.status?.hasExperiment ?? props.hasExperiment,
128
- )
129
- const resolvedCurrentExperimentId = computed(() =>
130
- props.status?.currentExperimentId ?? props.currentExperimentId,
131
- )
132
- const resolvedLastLoadedAt = computed(() =>
133
- props.status?.lastLoadedAt !== undefined ? props.status.lastLoadedAt : props.lastLoadedAt,
134
- )
135
- const resolvedLastSavedAt = computed(() =>
136
- props.status?.lastSavedAt !== undefined ? props.status.lastSavedAt : props.lastSavedAt,
137
- )
118
+ // Thin recipe over bioTemplateExperimentWorkspaceProps(): merges the grouped `status` prop
119
+ // over the individual loading/error/experiment props (see workspaceRecipes.ts).
120
+ const resolvedStatus = computed(() => bioTemplateExperimentWorkspaceProps(props))
121
+ const resolvedLoading = computed(() => resolvedStatus.value.loading)
122
+ const resolvedError = computed(() => resolvedStatus.value.error)
123
+ const resolvedHasExperiment = computed(() => resolvedStatus.value.hasExperiment)
124
+ const resolvedCurrentExperimentId = computed(() => resolvedStatus.value.currentExperimentId)
125
+ const resolvedLastLoadedAt = computed(() => resolvedStatus.value.lastLoadedAt)
126
+ const resolvedLastSavedAt = computed(() => resolvedStatus.value.lastSavedAt)
138
127
 
139
128
  const templateSummaries = computed(() =>
140
129
  Object.values(extractTemplateCollection(props.target)).map(template => ({
@@ -14,6 +14,7 @@ import type {
14
14
  UseBioTemplatePackWorkspaceReturn,
15
15
  } from '../composables/useBioTemplatePackWorkspace'
16
16
  import { useBioTemplatePackWorkspace } from '../composables/useBioTemplatePackWorkspace'
17
+ import { bioTemplatePackWorkspaceProps } from '../composables/workspaceRecipes'
17
18
  import BioTemplateExperimentWorkspaceView from './BioTemplateExperimentWorkspaceView.vue'
18
19
 
19
20
  interface BioTemplatePackWorkspaceSlotProps {
@@ -140,6 +141,15 @@ const resolvedActions = computed<PackWorkspaceActions>(() => ({
140
141
  save: props.actions?.save ?? (() => resolvedWorkspace.value.saveCurrent()),
141
142
  }))
142
143
 
144
+ // Thin recipe over bioTemplatePackWorkspaceProps(): forwards this view's own display props
145
+ // plus the pack-derived target/label/status/actions to BioTemplateExperimentWorkspaceView.
146
+ const experimentWorkspaceRecipe = computed(() => bioTemplatePackWorkspaceProps(props, {
147
+ target: target.value,
148
+ label: label.value,
149
+ status: resolvedStatus.value,
150
+ actions: resolvedActions.value,
151
+ }))
152
+
143
153
  watch(
144
154
  [() => props.pack, () => props.workspaceOptions],
145
155
  () => {
@@ -152,21 +162,7 @@ onScopeDispose(() => generatedWorkspaceScope?.stop())
152
162
  </script>
153
163
 
154
164
  <template>
155
- <BioTemplateExperimentWorkspaceView
156
- :target="target"
157
- kind="collection"
158
- :label="label"
159
- :message="message"
160
- :status="resolvedStatus"
161
- :actions="resolvedActions"
162
- :dense="dense"
163
- :readonly="readonly"
164
- :show-status="showStatus"
165
- :show-template-summary="showTemplateSummary"
166
- :load-label="loadLabel"
167
- :reset-label="resetLabel"
168
- :save-label="saveLabel"
169
- >
165
+ <BioTemplateExperimentWorkspaceView v-bind="experimentWorkspaceRecipe">
170
166
  <template v-if="hasDefaultSlot" #default="slotProps">
171
167
  <slot
172
168
  v-bind="slotProps"
@@ -14,6 +14,7 @@ import type {
14
14
  UseBioTemplatePresetWorkspaceReturn,
15
15
  } from '../composables/useBioTemplatePresetWorkspace'
16
16
  import { useBioTemplatePresetWorkspace } from '../composables/useBioTemplatePresetWorkspace'
17
+ import { bioTemplatePresetWorkspaceProps } from '../composables/workspaceRecipes'
17
18
  import AlertBox from './AlertBox.vue'
18
19
  import AppSidebar from './AppSidebar.vue'
19
20
  import BaseButton from './BaseButton.vue'
@@ -96,19 +97,13 @@ const props = withDefaults(defineProps<Props>(), {
96
97
  resetLabel: 'Reset defaults',
97
98
  })
98
99
 
99
- const externalValues = computed(() => props.modelValue ?? props.values)
100
- const resolvedWorkspaceOptions = computed<UseBioTemplatePresetWorkspaceOptions>(() => {
101
- if (props.initialValues === undefined && externalValues.value === undefined) return props.workspaceOptions
102
-
103
- return {
104
- ...props.workspaceOptions,
105
- initialValues: {
106
- ...(props.workspaceOptions.initialValues ?? {}),
107
- ...(props.initialValues ?? {}),
108
- ...(externalValues.value ?? {}),
109
- },
110
- }
111
- })
100
+ // Thin recipe over bioTemplatePresetWorkspaceProps(): merges workspaceOptions/initialValues/
101
+ // v-model into the options useBioTemplatePresetWorkspace() consumes (see workspaceRecipes.ts).
102
+ const resolvedPresetProps = computed(() => bioTemplatePresetWorkspaceProps(props))
103
+ const externalValues = computed(() => resolvedPresetProps.value.externalValues)
104
+ const resolvedWorkspaceOptions = computed<UseBioTemplatePresetWorkspaceOptions>(() =>
105
+ resolvedPresetProps.value.resolvedWorkspaceOptions
106
+ )
112
107
 
113
108
  let generatedWorkspaceScope: EffectScope | undefined
114
109
 
@@ -75,7 +75,3 @@ function handleClick(item: BreadcrumbItem) {
75
75
  </ol>
76
76
  </nav>
77
77
  </template>
78
-
79
- <style>
80
- @import '../styles/components/breadcrumb.css';
81
- </style>
@@ -361,7 +361,3 @@ function nextMonth() {
361
361
  </div>
362
362
  </div>
363
363
  </template>
364
-
365
- <style>
366
- @import '../styles/components/calendar.css';
367
- </style>
@@ -75,7 +75,7 @@ import ChartContainer from './ChartContainer.vue'
75
75
  <button type="button" style="padding: 0.25rem 0.75rem; font-size: 0.8125rem; border: 1px solid var(--border-color, #e2e8f0); border-radius: 0.375rem; background: var(--bg-card, #fff); color: var(--text-primary, #1e293b); cursor: pointer;">
76
76
  Linear
77
77
  </button>
78
- <button type="button" style="padding: 0.25rem 0.75rem; font-size: 0.8125rem; border: 1px solid var(--mint-primary, #3B82F6); border-radius: 0.375rem; background: var(--mint-primary, #3B82F6); color: #fff; cursor: pointer;">
78
+ <button type="button" style="padding: 0.25rem 0.75rem; font-size: 0.8125rem; border: 1px solid var(--color-primary); border-radius: 0.375rem; background: var(--color-primary); color: #fff; cursor: pointer;">
79
79
  Log
80
80
  </button>
81
81
  </div>
@@ -58,7 +58,3 @@ withDefaults(defineProps<Props>(), {
58
58
  </div>
59
59
  </div>
60
60
  </template>
61
-
62
- <style>
63
- @import '../styles/components/chart-container.css';
64
- </style>
@@ -33,7 +33,3 @@ function getParts(f: string): FormulaPart[] {
33
33
  </template>
34
34
  </component>
35
35
  </template>
36
-
37
- <style>
38
- @import '../styles/components/chemical-formula.css';
39
- </style>
@@ -239,7 +239,3 @@ function handleActionClick(action: SidebarToolSectionAction) {
239
239
  </Transition>
240
240
  </div>
241
241
  </template>
242
-
243
- <style>
244
- @import '../styles/components/collapsible-card.css';
245
- </style>
@@ -158,7 +158,3 @@ function handleInput(event: Event) {
158
158
  </div>
159
159
  </div>
160
160
  </template>
161
-
162
- <style>
163
- @import '../styles/components/color-slider.css';
164
- </style>
@@ -16,6 +16,7 @@ import ReagentList from './ReagentList.vue'
16
16
  import SampleSelector from './SampleSelector.vue'
17
17
  import ScheduleCalendar from './ScheduleCalendar.vue'
18
18
  import WellPlate from './WellPlate.vue'
19
+ import { isRecord } from '../utils/records'
19
20
 
20
21
  export interface ComponentBindingRendererBinding {
21
22
  id?: string
@@ -173,9 +174,6 @@ function normalizeProps(binding: ComponentBindingRendererBinding): Record<string
173
174
  }
174
175
  }
175
176
 
176
- function isRecord(value: unknown): value is Record<string, unknown> {
177
- return typeof value === 'object' && value !== null && !Array.isArray(value)
178
- }
179
177
  </script>
180
178
 
181
179
  <template>
@@ -143,7 +143,3 @@ watch(availableUnits, (units) => {
143
143
  </div>
144
144
  </div>
145
145
  </template>
146
-
147
- <style>
148
- @import '../styles/components/concentration-input.css';
149
- </style>
@@ -94,7 +94,3 @@ const confirmVariant = computed<ButtonVariant>(() => {
94
94
  </template>
95
95
  </BaseModal>
96
96
  </template>
97
-
98
- <style>
99
- @import '../styles/components/confirm-dialog.css';
100
- </style>
@@ -20,7 +20,8 @@ import type {
20
20
  ControlWorkspaceOptions,
21
21
  UseControlWorkspaceReturn,
22
22
  } from '../composables/useControlSchema'
23
- import { mergeControlWorkspaceOptions, resolveControlModel, useControlWorkspace } from '../composables/useControlSchema'
23
+ import { useControlWorkspace } from '../composables/useControlSchema'
24
+ import { controlWorkspaceProps } from '../composables/workspaceRecipes'
24
25
  import AppLayout from './AppLayout.vue'
25
26
  import AppSidebar from './AppSidebar.vue'
26
27
  import AppTopBar from './AppTopBar.vue'
@@ -161,27 +162,15 @@ const props = withDefaults(defineProps<Props>(), {
161
162
  formSize: 'md',
162
163
  })
163
164
 
164
- const externalValues = computed(() => props.modelValue ?? props.values)
165
- const resolvedModel = computed<ControlModelBinding | undefined>(() => {
166
- return resolveControlModel(props.model)
167
- })
168
- const resolvedControls = computed<ControlSchema>(() => props.controls ?? resolvedModel.value?.controls ?? {})
169
- const baseControlOptions = computed<ControlWorkspaceOptions>(() =>
170
- mergeControlWorkspaceOptions(resolvedModel.value?.controlOptions ?? {}, props.controlOptions)
171
- )
172
-
173
- const resolvedControlOptions = computed<ControlWorkspaceOptions>(() => {
174
- if (props.initialValues === undefined && externalValues.value === undefined) return baseControlOptions.value
175
-
176
- return {
177
- ...baseControlOptions.value,
178
- initialValues: {
179
- ...(baseControlOptions.value.initialValues ?? {}),
180
- ...(props.initialValues ?? {}),
181
- ...(externalValues.value ?? {}),
182
- },
183
- }
184
- })
165
+ // Thin recipe over controlWorkspaceProps(): resolves model/controls/controlOptions/v-model
166
+ // into the schema + options pair useControlWorkspace() consumes, shared with
167
+ // DoseDesignWorkspaceView (which forwards its own props here) and
168
+ // BioTemplatePresetWorkspaceView's equivalent options merge.
169
+ const resolvedWorkspaceModel = computed(() => controlWorkspaceProps(props))
170
+ const externalValues = computed(() => resolvedWorkspaceModel.value.externalValues)
171
+ const resolvedModel = computed(() => resolvedWorkspaceModel.value.resolvedModel)
172
+ const resolvedControls = computed(() => resolvedWorkspaceModel.value.resolvedControls)
173
+ const resolvedControlOptions = computed(() => resolvedWorkspaceModel.value.resolvedControlOptions)
185
174
 
186
175
  let generatedWorkspaceScope: EffectScope | undefined
187
176
 
@@ -37,6 +37,7 @@ const pagination = ref<PaginationState>({ page: 1, pageSize: 5, total: data.leng
37
37
  <template #default="{ state }">
38
38
  <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
39
39
  <DataFrame
40
+ :error="state.error || null"
40
41
  :data="data"
41
42
  :columns="columns"
42
43
  row-key="id"
@@ -55,6 +56,8 @@ const pagination = ref<PaginationState>({ page: 1, pageSize: 5, total: data.leng
55
56
  </template>
56
57
 
57
58
  <template #controls="{ state }">
59
+
60
+ <HstText v-model="state.error" title="Error Message" />
58
61
  <HstSelect
59
62
  v-model="state.size"
60
63
  title="Size"
@@ -144,5 +147,16 @@ const pagination = ref<PaginationState>({ page: 1, pageSize: 5, total: data.leng
144
147
  />
145
148
  </div>
146
149
  </Variant>
150
+
151
+ <Variant title="Error">
152
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
153
+ <DataFrame
154
+ :data="data"
155
+ :columns="columns"
156
+ row-key="id"
157
+ error="Could not load the result table."
158
+ />
159
+ </div>
160
+ </Variant>
147
161
  </Story>
148
162
  </template>
@@ -5,6 +5,14 @@ import type { DataFrameColumn, SortState, PaginationState } from '../types'
5
5
  import { useSortedItems } from '../composables/useSortedItems'
6
6
  import { useTextSearch } from '../composables/useTextSearch'
7
7
  import { useListSelection } from '../composables/useListSelection'
8
+ import DataStateInternal from './internal/DataStateInternal.vue'
9
+ import LoadingSpinner from './LoadingSpinner.vue'
10
+ import { tableDensityToSize, tryUseSettingsStore } from '../stores/settings'
11
+
12
+ /** Inbox glyph kept from the pre-1.2 hand-rolled empty state. */
13
+ const EMPTY_ICON_PATH
14
+ = 'M22 12L16 12L14 15L10 15L8 12L2 12'
15
+ + 'M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'
8
16
 
9
17
  /**
10
18
  * DataFrame - Data table with sorting, searching, pagination, and row selection.
@@ -34,7 +42,11 @@ interface Props {
34
42
  striped?: boolean
35
43
  /** Show table borders */
36
44
  bordered?: boolean
37
- /** Table size */
45
+ /**
46
+ * Table size. Left unset, it follows the platform's `tableDensity` setting
47
+ * (compact → `sm`, normal → `md`, comfortable → `lg`) and falls back to
48
+ * `md` when no settings store is installed.
49
+ */
38
50
  size?: 'sm' | 'md' | 'lg'
39
51
  /** Make header sticky on scroll */
40
52
  stickyHeader?: boolean
@@ -42,6 +54,11 @@ interface Props {
42
54
  maxHeight?: string | number
43
55
  /** Show loading overlay */
44
56
  loading?: boolean
57
+ /**
58
+ * Error message. When set, the table body is replaced by an error state
59
+ * instead of the empty state. `null`/`undefined` renders normally.
60
+ */
61
+ error?: string | null
45
62
  /** Empty state message */
46
63
  emptyText?: string
47
64
  /** Enable column sorting */
@@ -75,9 +92,9 @@ interface Props {
75
92
  const props = withDefaults(defineProps<Props>(), {
76
93
  striped: true,
77
94
  bordered: true,
78
- size: 'md',
79
95
  stickyHeader: false,
80
96
  loading: false,
97
+ error: null,
81
98
  emptyText: 'No data',
82
99
  sortable: false,
83
100
  pagination: false,
@@ -108,6 +125,13 @@ const emit = defineEmits<{
108
125
  'delete-row': [row: Record<string, unknown>, index: number]
109
126
  }>()
110
127
 
128
+ const settings = tryUseSettingsStore()
129
+
130
+ /** Explicit `size` wins; otherwise the user's table density, else `md`. */
131
+ const size = computed<'sm' | 'md' | 'lg'>(() =>
132
+ props.size ?? (settings ? tableDensityToSize(settings.tableDensity) : 'md'),
133
+ )
134
+
111
135
  const searchQuery = ref('')
112
136
  const internalSort = ref<SortState | null>(null)
113
137
 
@@ -219,6 +243,21 @@ function isColumnSortable(col: DataFrameColumn): boolean {
219
243
  return col.sortable === true || (props.sortable && col.sortable !== false)
220
244
  }
221
245
 
246
+ /** `aria-sort` for the header cell, omitted on columns that cannot be sorted. */
247
+ function columnAriaSort(col: DataFrameColumn): 'ascending' | 'descending' | 'none' | undefined {
248
+ if (!isColumnSortable(col)) return undefined
249
+ if (activeSort.value?.key !== col.key || !activeSort.value.direction) return 'none'
250
+ return activeSort.value.direction === 'asc' ? 'ascending' : 'descending'
251
+ }
252
+
253
+ // Native buttons activate on Enter/Space, but the default is prevented here so
254
+ // the header sorts exactly once per key press in every engine.
255
+ function handleSortKeydown(event: KeyboardEvent, col: DataFrameColumn) {
256
+ if (event.key !== 'Enter' && event.key !== ' ') return
257
+ event.preventDefault()
258
+ handleSort(col)
259
+ }
260
+
222
261
  // Selection
223
262
  const pageRowKeys = computed(() =>
224
263
  paginatedData.value.map((row, i) => getRowKey(row, i))
@@ -264,6 +303,35 @@ function columnStyle(col: DataFrameColumn) {
264
303
  }
265
304
  }
266
305
 
306
+ const RESIZE_KEY_STEP = 16
307
+
308
+ function columnMinWidth(col: DataFrameColumn): number {
309
+ return Math.max(MIN_COL_WIDTH, typeof col.minWidth === 'number' ? col.minWidth : 0)
310
+ }
311
+
312
+ /** Current px width of a column when one is known (resized, or a numeric `width`). */
313
+ function columnWidthValue(col: DataFrameColumn): number | undefined {
314
+ const width = activeWidths.value[col.key] ?? col.width
315
+ return typeof width === 'number' ? width : undefined
316
+ }
317
+
318
+ function applyColumnWidth(key: string, width: number) {
319
+ const widths = { ...activeWidths.value, [key]: width }
320
+ if (props.columnWidths === undefined) internalWidths.value = widths
321
+ emit('update:columnWidths', widths)
322
+ }
323
+
324
+ /** Left/Right resize the column by a fixed step; the handle is a `role="slider"`. */
325
+ function handleResizeKeydown(event: KeyboardEvent, col: DataFrameColumn) {
326
+ if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return
327
+ event.preventDefault()
328
+ const th = (event.target as HTMLElement).closest('th')
329
+ const base =
330
+ columnWidthValue(col) ?? (th instanceof HTMLElement ? th.offsetWidth : MIN_COL_WIDTH)
331
+ const delta = event.key === 'ArrowRight' ? RESIZE_KEY_STEP : -RESIZE_KEY_STEP
332
+ applyColumnWidth(col.key, Math.max(columnMinWidth(col), base + delta))
333
+ }
334
+
267
335
  let resizeState: { key: string; startX: number; startWidth: number; min: number } | null = null
268
336
 
269
337
  function startResize(col: DataFrameColumn, event: MouseEvent) {
@@ -272,8 +340,7 @@ function startResize(col: DataFrameColumn, event: MouseEvent) {
272
340
  const th = (event.target as HTMLElement).closest('th')
273
341
  const startWidth =
274
342
  th instanceof HTMLElement ? th.offsetWidth : (typeof col.width === 'number' ? col.width : MIN_COL_WIDTH)
275
- const min = Math.max(MIN_COL_WIDTH, typeof col.minWidth === 'number' ? col.minWidth : 0)
276
- resizeState = { key: col.key, startX: event.clientX, startWidth, min }
343
+ resizeState = { key: col.key, startX: event.clientX, startWidth, min: columnMinWidth(col) }
277
344
  window.addEventListener('mousemove', onResizeMove)
278
345
  window.addEventListener('mouseup', stopResize)
279
346
  }
@@ -281,9 +348,7 @@ function startResize(col: DataFrameColumn, event: MouseEvent) {
281
348
  function onResizeMove(event: MouseEvent) {
282
349
  if (!resizeState) return
283
350
  const next = Math.max(resizeState.min, resizeState.startWidth + (event.clientX - resizeState.startX))
284
- const widths = { ...activeWidths.value, [resizeState.key]: next }
285
- if (props.columnWidths === undefined) internalWidths.value = widths
286
- emit('update:columnWidths', widths)
351
+ applyColumnWidth(resizeState.key, next)
287
352
  }
288
353
 
289
354
  function stopResize() {
@@ -355,8 +420,15 @@ const wrapperStyle = computed(() => {
355
420
  },
356
421
  ]"
357
422
  :style="columnStyle(col)"
358
- @click="isColumnSortable(col) ? handleSort(col) : undefined"
423
+ :aria-sort="columnAriaSort(col)"
359
424
  >
425
+ <component
426
+ :is="isColumnSortable(col) ? 'button' : 'div'"
427
+ :type="isColumnSortable(col) ? 'button' : undefined"
428
+ class="mint-dataframe__th-button"
429
+ @click="isColumnSortable(col) ? handleSort(col) : undefined"
430
+ @keydown="isColumnSortable(col) ? handleSortKeydown($event, col) : undefined"
431
+ >
360
432
  <slot :name="`header-${col.key}`" :column="col">
361
433
  <div class="mint-dataframe__th-content">
362
434
  <span>{{ col.label }}</span>
@@ -380,13 +452,18 @@ const wrapperStyle = computed(() => {
380
452
  </svg>
381
453
  </div>
382
454
  </slot>
455
+ </component>
383
456
  <span
384
457
  v-if="resizable"
385
458
  class="mint-dataframe__resize-handle"
386
- role="separator"
459
+ role="slider"
460
+ tabindex="0"
387
461
  aria-orientation="vertical"
388
- aria-label="Resize column"
462
+ :aria-label="`Resize ${col.label} column`"
463
+ :aria-valuemin="columnMinWidth(col)"
464
+ :aria-valuenow="columnWidthValue(col)"
389
465
  @mousedown="startResize(col, $event)"
466
+ @keydown="handleResizeKeydown($event, col)"
390
467
  @click.stop
391
468
  />
392
469
  </th>
@@ -459,23 +536,24 @@ const wrapperStyle = computed(() => {
459
536
  </tbody>
460
537
  </table>
461
538
 
539
+ <!-- Error state -->
540
+ <div v-if="error" class="mint-dataframe__state">
541
+ <slot name="error" :error="error">
542
+ <DataStateInternal state="error" :title="error" />
543
+ </slot>
544
+ </div>
545
+
462
546
  <!-- Empty state -->
463
- <div v-if="paginatedData.length === 0 && !loading" class="mint-dataframe__empty">
547
+ <div v-else-if="paginatedData.length === 0 && !loading" class="mint-dataframe__state">
464
548
  <slot name="empty">
465
- <svg class="mint-dataframe__empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
466
- <polyline points="22 12 16 12 14 15 10 15 8 12 2 12" /><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
467
- </svg>
468
- <p class="mint-dataframe__empty-text">{{ emptyText }}</p>
549
+ <DataStateInternal state="empty" :title="emptyText" :icon-path="EMPTY_ICON_PATH" />
469
550
  </slot>
470
551
  </div>
471
552
 
472
553
  <!-- Loading overlay -->
473
554
  <div v-if="loading" class="mint-dataframe__loading">
474
555
  <slot name="loading">
475
- <svg class="mint-dataframe__loading-spinner" viewBox="0 0 24 24" fill="none" aria-hidden="true">
476
- <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" opacity="0.25" />
477
- <path d="M12 2a10 10 0 0 1 10 10" stroke="currentColor" stroke-width="3" stroke-linecap="round" />
478
- </svg>
556
+ <LoadingSpinner size="lg" />
479
557
  </slot>
480
558
  </div>
481
559
  </div>
@@ -514,7 +592,3 @@ const wrapperStyle = computed(() => {
514
592
  </div>
515
593
  </div>
516
594
  </template>
517
-
518
- <style>
519
- @import '../styles/components/dataframe.css';
520
- </style>