@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
@@ -1,7 +1,8 @@
1
1
  <script setup lang="ts">
2
- import { ref, watch, computed } from 'vue'
2
+ import { onBeforeUnmount, onMounted, ref, watch, computed } from 'vue'
3
3
  import type { Well, WellEditData, WellEditField } from '../../types'
4
4
  import { useEventListener } from '../../composables/useEventListener'
5
+ import { useFocusTrap } from '../../composables/useFocusTrap'
5
6
 
6
7
  interface Props {
7
8
  wellId: string
@@ -86,6 +87,22 @@ function handleKeydown(e: KeyboardEvent) {
86
87
 
87
88
  useEventListener(() => document, 'keydown', handleKeydown)
88
89
 
90
+ // The popup has no open/close prop of its own — the parent mounts and unmounts it —
91
+ // so the trap activates on mount and releases (restoring focus) just before unmount,
92
+ // the same lifecycle BaseModal drives off `modelValue`.
93
+ const containerRef = ref<HTMLElement | null>(null)
94
+ const trapActive = ref(false)
95
+
96
+ useFocusTrap({ containerRef, active: trapActive })
97
+
98
+ onMounted(() => {
99
+ trapActive.value = true
100
+ })
101
+
102
+ onBeforeUnmount(() => {
103
+ trapActive.value = false
104
+ })
105
+
89
106
  const sampleTypeButtons = [
90
107
  { type: 'sample', label: 'S', tooltip: 'Sample' },
91
108
  { type: 'blank', label: 'B', tooltip: 'Blank' },
@@ -101,8 +118,10 @@ const sampleTypeButtons = [
101
118
 
102
119
  <!-- Popup -->
103
120
  <div
121
+ ref="containerRef"
104
122
  class="mint-well-edit-popup"
105
123
  :style="popupStyle"
124
+ tabindex="-1"
106
125
  @click.stop
107
126
  >
108
127
  <!-- Header -->
@@ -224,7 +243,3 @@ const sampleTypeButtons = [
224
243
  </div>
225
244
  </Teleport>
226
245
  </template>
227
-
228
- <style>
229
- @import '../../styles/components/well-edit-popup.css';
230
- </style>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Internal: renders PluginWorkspaceView's default (main content) slot bound to the
4
+ * control-schema-derived scoped-slot payload (active view, values, component bindings/props).
5
+ * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.
6
+ */
7
+ import type { PluginWorkspaceControlsModel } from '../../composables/pluginWorkspaceModel'
8
+
9
+ defineProps<{
10
+ controls: PluginWorkspaceControlsModel
11
+ }>()
12
+
13
+ defineSlots<{
14
+ default?: (props: PluginWorkspaceControlsModel) => unknown
15
+ }>()
16
+ </script>
17
+
18
+ <template>
19
+ <slot v-bind="controls" />
20
+ </template>
@@ -0,0 +1,125 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Internal: AppLayout + AppTopBar for PluginWorkspaceView, driven by a single `shell` model.
4
+ * Owns the responsive/collapse layout props and the top bar's default rendering; the caller
5
+ * decides whether to override the `topbar`/`sidebar` slots and supplies the sidebar content.
6
+ * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.
7
+ */
8
+ import type {
9
+ AccountMenuItem,
10
+ PageSelectorItem,
11
+ PillNavItem,
12
+ PillNavOption,
13
+ PluginSwitcherPlugin,
14
+ } from '../../types'
15
+ import AppLayout from '../AppLayout.vue'
16
+ import AppTopBar from '../AppTopBar.vue'
17
+ import type { PluginWorkspaceShellModel } from '../../composables/pluginWorkspaceModel'
18
+
19
+ defineProps<{
20
+ shell: PluginWorkspaceShellModel
21
+ }>()
22
+
23
+ const emit = defineEmits<{
24
+ 'page-selector-select': [page: PageSelectorItem]
25
+ 'pill-select': [item: PillNavItem]
26
+ 'pill-option-select': [option: PillNavOption, item: PillNavItem]
27
+ 'plugin-switcher-select': [plugin: PluginSwitcherPlugin]
28
+ 'plugin-switcher-install': []
29
+ 'account-menu-select': [item: AccountMenuItem]
30
+ 'sign-out': []
31
+ 'notifications-click': []
32
+ 'settings-values-change': [data: Record<string, unknown>]
33
+ 'admin-click': []
34
+ }>()
35
+
36
+ function handlePillOptionSelect(option: PillNavOption, item: PillNavItem) {
37
+ emit('pill-option-select', option, item)
38
+ }
39
+
40
+ defineSlots<{
41
+ topbar?: (props: PluginWorkspaceShellModel['controls']) => unknown
42
+ sidebar?: (props: PluginWorkspaceShellModel['controls']) => unknown
43
+ default?: (props: PluginWorkspaceShellModel['controls']) => unknown
44
+ icon?: (props: Record<string, unknown>) => unknown
45
+ logo?: (props: Record<string, unknown>) => unknown
46
+ 'page-selector-icon'?: (props: Record<string, unknown>) => unknown
47
+ 'page-selector-item-icon'?: (props: Record<string, unknown>) => unknown
48
+ nav?: (props: Record<string, unknown>) => unknown
49
+ center?: (props: Record<string, unknown>) => unknown
50
+ actions?: (props: Record<string, unknown>) => unknown
51
+ 'account-menu-items'?: (props: Record<string, unknown>) => unknown
52
+ 'account-menu-item-icon'?: (props: Record<string, unknown>) => unknown
53
+ 'settings-appearance'?: (props: Record<string, unknown>) => unknown
54
+ }>()
55
+ </script>
56
+
57
+ <template>
58
+ <AppLayout
59
+ class="mint-plugin-workspace-view"
60
+ :sidebar-position="shell.sidebarPosition"
61
+ :sidebar-width="shell.sidebarWidth"
62
+ :floating="shell.floating"
63
+ :responsive-sidebar="shell.responsiveSidebar"
64
+ :sidebar-toggle-label="shell.sidebarToggleLabel"
65
+ :sidebar-close-label="shell.sidebarCloseLabel"
66
+ >
67
+ <template #topbar>
68
+ <slot name="topbar" v-bind="shell.controls">
69
+ <AppTopBar
70
+ :title="shell.title"
71
+ :subtitle="shell.subtitle"
72
+ :variant="shell.topBarVariant"
73
+ :home-path="shell.homePath"
74
+ :show-logo="shell.showLogo"
75
+ :page-selector="shell.pageSelector"
76
+ :current-page-selector-id="shell.currentPageSelectorId"
77
+ :plugin-switcher="shell.pluginSwitcher"
78
+ :pill-nav="shell.pillNav"
79
+ :current-pill-id="shell.currentPillId"
80
+ :show-theme-toggle="shell.showThemeToggle"
81
+ :show-settings="shell.showSettings"
82
+ :settings-config="shell.settingsConfig"
83
+ :show-standalone-label="shell.showStandaloneLabel"
84
+ :standalone-label="shell.standaloneLabel"
85
+ :account-menu="shell.accountMenu"
86
+ :show-notifications="shell.showNotifications"
87
+ :has-notification-dot="shell.hasNotificationDot"
88
+ :show-admin="shell.showAdmin"
89
+ :admin-path="shell.adminPath"
90
+ :user-name="shell.userName"
91
+ :user-initial="shell.userInitial"
92
+ :user-email="shell.userEmail"
93
+ @page-selector-select="emit('page-selector-select', $event)"
94
+ @pill-select="emit('pill-select', $event)"
95
+ @pill-option-select="handlePillOptionSelect"
96
+ @plugin-switcher-select="emit('plugin-switcher-select', $event)"
97
+ @plugin-switcher-install="emit('plugin-switcher-install')"
98
+ @account-menu-select="emit('account-menu-select', $event)"
99
+ @sign-out="emit('sign-out')"
100
+ @notifications-click="emit('notifications-click')"
101
+ @settings-values-change="emit('settings-values-change', $event)"
102
+ @admin-click="emit('admin-click')"
103
+ >
104
+ <template
105
+ v-for="slotName in shell.topBarSlotNames"
106
+ :key="slotName"
107
+ #[slotName]="slotProps"
108
+ >
109
+ <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->
110
+ <slot
111
+ :name="slotName"
112
+ v-bind="slotProps ?? {}"
113
+ />
114
+ </template>
115
+ </AppTopBar>
116
+ </slot>
117
+ </template>
118
+
119
+ <template v-if="shell.hasSidebarSurface" #sidebar>
120
+ <slot name="sidebar" v-bind="shell.controls" />
121
+ </template>
122
+
123
+ <slot v-bind="shell.controls" />
124
+ </AppLayout>
125
+ </template>
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Internal: AppSidebar for PluginWorkspaceView, driven by a single `sidebar` model covering
4
+ * chrome, panels/forms, collapse behavior, and the compact control-schema props that drive
5
+ * AppSidebar's auto-generated form.
6
+ * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.
7
+ */
8
+ import AppSidebar from '../AppSidebar.vue'
9
+ import type { PluginWorkspaceSidebarModel } from '../../composables/pluginWorkspaceModel'
10
+
11
+ defineProps<{
12
+ sidebar: PluginWorkspaceSidebarModel
13
+ }>()
14
+
15
+ defineEmits<{
16
+ 'update:modelValue': [values: Record<string, unknown>]
17
+ 'update:collapsed': [value: boolean]
18
+ 'update:toggle': [sectionId: string, value: boolean]
19
+ 'section-action': [sectionId: string, actionId: string]
20
+ 'form-submit': [sectionId: string, values: Record<string, unknown>]
21
+ 'form-cancel': [sectionId: string]
22
+ }>()
23
+
24
+ defineSlots<{
25
+ header?: (props: Record<string, unknown>) => unknown
26
+ collapsed?: (props: Record<string, unknown>) => unknown
27
+ 'collapsed-footer'?: (props: Record<string, unknown>) => unknown
28
+ footer?: (props: Record<string, unknown>) => unknown
29
+ }>()
30
+ </script>
31
+
32
+ <template>
33
+ <AppSidebar
34
+ :title="sidebar.title"
35
+ :subtitle="sidebar.subtitle"
36
+ :badge="sidebar.badge"
37
+ :variant="sidebar.variant"
38
+ :panels="sidebar.panels"
39
+ :active-view="sidebar.activeView"
40
+ :floating="sidebar.floating"
41
+ :dense="sidebar.dense"
42
+ :width="sidebar.width"
43
+ :side="sidebar.side"
44
+ :forms="sidebar.forms"
45
+ :content-id="sidebar.contentId"
46
+ :show-when-empty="sidebar.showWhenEmpty"
47
+ :model="sidebar.model"
48
+ :controls="sidebar.controlSchema"
49
+ :control-options="sidebar.controlOptions"
50
+ :values="sidebar.values"
51
+ :form-enhancements="sidebar.formEnhancements"
52
+ :show-form-actions="sidebar.showFormActions"
53
+ :form-loading="sidebar.formLoading"
54
+ :form-disabled="sidebar.formDisabled"
55
+ :form-readonly="sidebar.formReadonly"
56
+ :form-size="sidebar.formSize"
57
+ :collapsible="sidebar.collapsible"
58
+ :collapsed="sidebar.collapsed"
59
+ :default-collapsed="sidebar.defaultCollapsed"
60
+ :collapsed-width="sidebar.collapsedWidth"
61
+ :collapse-button-label="sidebar.collapseButtonLabel"
62
+ :expand-button-label="sidebar.expandButtonLabel"
63
+ @update:model-value="$emit('update:modelValue', $event)"
64
+ @update:collapsed="$emit('update:collapsed', $event)"
65
+ @update:toggle="(sectionId, value) => $emit('update:toggle', sectionId, value)"
66
+ @section-action="(sectionId, actionId) => $emit('section-action', sectionId, actionId)"
67
+ @form-submit="(sectionId, values) => $emit('form-submit', sectionId, values)"
68
+ @form-cancel="$emit('form-cancel', $event)"
69
+ >
70
+ <template
71
+ v-for="slotName in sidebar.slotNames"
72
+ :key="slotName"
73
+ #[slotName]="slotProps"
74
+ >
75
+ <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->
76
+ <slot
77
+ :name="slotName"
78
+ v-bind="slotProps ?? {}"
79
+ />
80
+ </template>
81
+ </AppSidebar>
82
+ </template>
@@ -42,10 +42,27 @@ export interface ControlSectionConfig {
42
42
  actions?: SidebarToolSectionAction[]
43
43
  columns?: 1 | 2 | 3
44
44
  condition?: FieldCondition
45
+ /** The access policy. Preferred over the flat fields below. */
45
46
  access?: AccessPolicy
47
+ /**
48
+ * @deprecated Since MINT 1.2; use `access.visibleFor` instead. The flat
49
+ * duplicate is removed in 1.3.
50
+ */
46
51
  visibleFor?: AccessAudienceInput
52
+ /**
53
+ * @deprecated Since MINT 1.2; use `access.requiresAdmin` instead. The flat
54
+ * duplicate is removed in 1.3.
55
+ */
47
56
  requiresAdmin?: boolean
57
+ /**
58
+ * @deprecated Since MINT 1.2; use `access.permissions` instead. The flat
59
+ * duplicate is removed in 1.3.
60
+ */
48
61
  permissions?: readonly string[]
62
+ /**
63
+ * @deprecated Since MINT 1.2; use `access.anyPermissions` instead. The flat
64
+ * duplicate is removed in 1.3.
65
+ */
49
66
  anyPermissions?: readonly string[]
50
67
  defaultOpen?: boolean
51
68
  showToggle?: boolean
@@ -86,10 +103,27 @@ export interface ControlDefinition {
86
103
  pattern?: string | { value: string; message: string }
87
104
  validation?: FieldValidation
88
105
  condition?: FieldCondition
106
+ /** The access policy. Preferred over the flat fields below. */
89
107
  access?: AccessPolicy
108
+ /**
109
+ * @deprecated Since MINT 1.2; use `access.visibleFor` instead. The flat
110
+ * duplicate is removed in 1.3.
111
+ */
90
112
  visibleFor?: AccessAudienceInput
113
+ /**
114
+ * @deprecated Since MINT 1.2; use `access.requiresAdmin` instead. The flat
115
+ * duplicate is removed in 1.3.
116
+ */
91
117
  requiresAdmin?: boolean
118
+ /**
119
+ * @deprecated Since MINT 1.2; use `access.permissions` instead. The flat
120
+ * duplicate is removed in 1.3.
121
+ */
92
122
  permissions?: readonly string[]
123
+ /**
124
+ * @deprecated Since MINT 1.2; use `access.anyPermissions` instead. The flat
125
+ * duplicate is removed in 1.3.
126
+ */
93
127
  anyPermissions?: readonly string[]
94
128
  options?: readonly ControlOption[]
95
129
  section?: string
@@ -1,4 +1,5 @@
1
1
  import type { SelectOption } from '../types'
2
+ import { isRecord } from '../utils/records'
2
3
 
3
4
  export interface ExperimentDesignDataResponse {
4
5
  experiment_id?: number
@@ -12,9 +13,6 @@ export interface ExtractExperimentSamplesOptions {
12
13
  includeControls?: boolean
13
14
  }
14
15
 
15
- function isRecord(value: unknown): value is Record<string, unknown> {
16
- return value !== null && typeof value === 'object' && !Array.isArray(value)
17
- }
18
16
 
19
17
  function isPlatformDesignDataResponse(value: Record<string, unknown>): boolean {
20
18
  return (
@@ -0,0 +1,58 @@
1
+ import type { PickerAdapter, PickerFile, PickerNode } from '../../types/filePicker'
2
+ import { pickerFormat } from './validation'
3
+
4
+ /** Construct metadata only: no FileReader, arrayBuffer or upload. */
5
+ export function localFilesAdapter(
6
+ files: File[],
7
+ relativePaths?: (string | undefined)[],
8
+ ): PickerAdapter {
9
+ const nodes = new Map<string, PickerNode>()
10
+ for (const [index, file] of files.entries()) {
11
+ const relative = relativePaths?.[index] || file.webkitRelativePath || file.name
12
+ const parts = relative.split('/')
13
+ let parent: string | null = null
14
+ for (let i = 0; i < parts.length - 1; i++) {
15
+ const path = parts.slice(0, i + 1).join('/')
16
+ if (!nodes.has(path))
17
+ nodes.set(path, { kind: 'folder', name: parts[i]!, path, parentPath: parent })
18
+ parent = path
19
+ }
20
+ // Plain file picks can have equal names; preserve both File objects.
21
+ let path = relative
22
+ for (let n = 2; nodes.has(path); n++) path = `${relative} (${n})`
23
+ nodes.set(path, {
24
+ kind: 'file',
25
+ name: file.name,
26
+ path,
27
+ parentPath: parent,
28
+ bytes: file.size,
29
+ format: pickerFormat(file.name),
30
+ file,
31
+ })
32
+ }
33
+ for (const node of nodes.values()) {
34
+ if (node.kind !== 'folder') continue
35
+ const descendants = [...nodes.values()].filter(
36
+ (item): item is PickerFile => item.kind === 'file' && item.path.startsWith(`${node.path}/`),
37
+ )
38
+ node.fileCount = descendants.length
39
+ node.bytes = descendants.reduce((sum, file) => sum + (file.bytes ?? 0), 0)
40
+ node.formats = {}
41
+ descendants.forEach((file) => {
42
+ node.formats![file.format] = (node.formats![file.format] ?? 0) + 1
43
+ })
44
+ }
45
+ const list = (path: string) =>
46
+ [...nodes.values()].filter((node) => (node.parentPath ?? '') === path)
47
+ return {
48
+ listRoot: async () => list(''),
49
+ listChildren: async (path) => list(path),
50
+ search: async (query, scope) =>
51
+ [...nodes.values()].filter((node) => {
52
+ const inScope = scope.recursive
53
+ ? !scope.path || node.path.startsWith(`${scope.path}/`)
54
+ : (node.parentPath ?? '') === scope.path
55
+ return inScope && node.name.toLowerCase().includes(query.toLowerCase())
56
+ }),
57
+ }
58
+ }
@@ -0,0 +1,220 @@
1
+ import { computed, onScopeDispose, ref, shallowRef } from 'vue'
2
+ import type {
3
+ PickerAdapter,
4
+ PickerNode,
5
+ PickerRequest,
6
+ PickerTreeRow,
7
+ } from '../../types/filePicker'
8
+
9
+ export function usePickerNavigation(
10
+ adapter: () => PickerAdapter,
11
+ request: () => PickerRequest,
12
+ systemFilter: (node: PickerNode) => boolean = () => true,
13
+ ) {
14
+ const path = shallowRef('')
15
+ const trail = ref<{ path: string; label: string }[]>([])
16
+ const entries = shallowRef<PickerNode[]>([])
17
+ const nodes = ref(new Map<string, PickerNode>())
18
+ const children = shallowRef(new Map<string, PickerNode[]>())
19
+ const expanded = ref(new Set<string>())
20
+ const expanding = ref(new Set<string>())
21
+ const expansionErrors = ref(new Map<string, string>())
22
+ const loading = shallowRef(false)
23
+ const error = shallowRef('')
24
+ let epoch = 0
25
+ let navigation = 0
26
+ let controller: AbortController | undefined
27
+ const pending = new Map<string, Promise<PickerNode[]>>()
28
+ const childControllers = new Set<AbortController>()
29
+
30
+ function isAllowed(node: PickerNode): boolean {
31
+ const seen = new Set<string>()
32
+ let current: PickerNode | undefined = node
33
+ while (current && !seen.has(current.path)) {
34
+ if (!systemFilter(current)) return false
35
+ seen.add(current.path)
36
+ current = current.parentPath ? nodes.value.get(current.parentPath) : undefined
37
+ }
38
+ return true
39
+ }
40
+
41
+ function register(items: PickerNode[], parent?: string) {
42
+ for (const item of items)
43
+ nodes.value.set(item.path, {
44
+ ...item,
45
+ parentPath:
46
+ item.parentPath !== undefined
47
+ ? item.parentPath
48
+ : parent !== undefined
49
+ ? parent || null
50
+ : (nodes.value.get(item.path)?.parentPath ?? null),
51
+ })
52
+ }
53
+ function invalidate() {
54
+ ++epoch
55
+ ++navigation
56
+ controller?.abort()
57
+ childControllers.forEach((item) => item.abort())
58
+ childControllers.clear()
59
+ pending.clear()
60
+ children.value = new Map()
61
+ expanding.value.clear()
62
+ expansionErrors.value.clear()
63
+ }
64
+ function clear() {
65
+ invalidate()
66
+ nodes.value.clear()
67
+ expanded.value.clear()
68
+ expanding.value.clear()
69
+ expansionErrors.value.clear()
70
+ entries.value = []
71
+ loading.value = false
72
+ error.value = ''
73
+ }
74
+ async function loadChildren(
75
+ folder: string,
76
+ ancestors: string[] = [],
77
+ refresh = false,
78
+ ): Promise<PickerNode[]> {
79
+ if (ancestors.includes(folder)) throw new Error('The adapter returned a circular folder tree.')
80
+ const cached = children.value.get(folder)
81
+ if (cached) return cached
82
+ const existing = pending.get(folder)
83
+ if (existing) return existing
84
+ const token = epoch
85
+ const abort = new AbortController()
86
+ childControllers.add(abort)
87
+ const task = adapter()
88
+ .listChildren(folder, { ...request(), ...(refresh && { refresh }), signal: abort.signal })
89
+ .then((items) => {
90
+ if (token !== epoch) throw new DOMException('Cancelled', 'AbortError')
91
+ const retained = new Set(items.map((item) => item.path))
92
+ function remove(path: string, seen = new Set<string>()) {
93
+ if (seen.has(path) || path === folder) return
94
+ seen.add(path)
95
+ for (const node of nodes.value.values())
96
+ if (node.parentPath === path) remove(node.path, seen)
97
+ nodes.value.delete(path)
98
+ children.value.delete(path)
99
+ }
100
+ for (const node of nodes.value.values())
101
+ if (node.parentPath === folder && !retained.has(node.path)) remove(node.path)
102
+ register(items, folder)
103
+ children.value = new Map(children.value).set(folder, items)
104
+ return items
105
+ })
106
+ .finally(() => {
107
+ childControllers.delete(abort)
108
+ if (token === epoch) pending.delete(folder)
109
+ })
110
+ pending.set(folder, task)
111
+ return task
112
+ }
113
+ async function load(query = '', recursive = false, refresh = false) {
114
+ const token = ++navigation
115
+ controller?.abort()
116
+ controller = new AbortController()
117
+ const options = { ...request(), ...(refresh && { refresh }), signal: controller.signal }
118
+ loading.value = true
119
+ error.value = ''
120
+ entries.value = []
121
+ try {
122
+ const items = query.trim()
123
+ ? await adapter().search(query.trim(), { path: path.value, recursive }, options)
124
+ : path.value
125
+ ? await loadChildren(path.value, [], refresh)
126
+ : await adapter().listRoot(options)
127
+ if (token !== navigation) return
128
+ register(items, query.trim() ? undefined : path.value)
129
+ entries.value = items
130
+ } catch (cause) {
131
+ if (token === navigation)
132
+ error.value = cause instanceof Error ? cause.message : 'Could not read this location.'
133
+ } finally {
134
+ if (token === navigation) loading.value = false
135
+ }
136
+ }
137
+ async function expand(node: PickerNode) {
138
+ if (node.kind !== 'folder' || node.unavailableReason || !isAllowed(node)) return
139
+ if (expanded.value.has(node.path)) {
140
+ expanded.value.delete(node.path)
141
+ return
142
+ }
143
+ expanded.value.add(node.path)
144
+ expanding.value.add(node.path)
145
+ expansionErrors.value.delete(node.path)
146
+ const token = epoch
147
+ try {
148
+ await loadChildren(node.path)
149
+ } catch (cause) {
150
+ if (token === epoch)
151
+ expansionErrors.value.set(
152
+ node.path,
153
+ cause instanceof Error ? cause.message : 'Could not read this folder.',
154
+ )
155
+ } finally {
156
+ if (token === epoch) expanding.value.delete(node.path)
157
+ }
158
+ }
159
+ function enter(node: PickerNode) {
160
+ if (node.kind !== 'folder' || node.unavailableReason || !isAllowed(node)) return
161
+ const index = trail.value.findIndex((crumb) => crumb.path === node.path)
162
+ trail.value =
163
+ index >= 0
164
+ ? trail.value.slice(0, index + 1)
165
+ : [...trail.value, { path: node.path, label: node.name }]
166
+ path.value = node.path
167
+ }
168
+ function up(target?: string) {
169
+ const index =
170
+ target !== undefined
171
+ ? trail.value.findIndex((crumb) => crumb.path === target)
172
+ : trail.value.length - 2
173
+ trail.value = index < 0 ? [] : trail.value.slice(0, index + 1)
174
+ path.value = trail.value[trail.value.length - 1]?.path ?? ''
175
+ }
176
+ const rows = computed(() => {
177
+ const result: PickerTreeRow[] = []
178
+ function visit(items: PickerNode[], depth: number, ancestors: Set<string>) {
179
+ for (const item of items) {
180
+ if (ancestors.has(item.path) || depth > 30) continue
181
+ const node = nodes.value.get(item.path) ?? item
182
+ if (!isAllowed(node)) continue
183
+ result.push({
184
+ node,
185
+ depth,
186
+ expanded: expanded.value.has(item.path),
187
+ loading: expanding.value.has(item.path),
188
+ error: expansionErrors.value.get(item.path),
189
+ })
190
+ if (expanded.value.has(item.path))
191
+ visit(children.value.get(item.path) ?? [], depth + 1, new Set([...ancestors, item.path]))
192
+ }
193
+ }
194
+ visit(entries.value, 0, new Set())
195
+ return result
196
+ })
197
+ onScopeDispose(clear)
198
+ return {
199
+ path,
200
+ trail,
201
+ entries,
202
+ nodes,
203
+ children,
204
+ expanded,
205
+ expanding,
206
+ expansionErrors,
207
+ loading,
208
+ error,
209
+ rows,
210
+ isAllowed,
211
+ clear,
212
+ invalidate,
213
+ register,
214
+ loadChildren,
215
+ load,
216
+ expand,
217
+ enter,
218
+ up,
219
+ }
220
+ }