@morscherlab/mint-sdk 1.4.0-beta.2 → 1.4.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 (330) hide show
  1. package/README.md +14 -3
  2. package/dist/{ActionMenu-CScINahU.js → AlertBox-CzLg0UaL.js} +40 -209
  3. package/dist/AlertBox-CzLg0UaL.js.map +1 -0
  4. package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-6oTT-gPO.js} +1249 -239
  5. package/dist/AppSidebar-6oTT-gPO.js.map +1 -0
  6. package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CSls2Nuv.js} +2 -2
  7. package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CSls2Nuv.js.map} +1 -1
  8. package/dist/ExperimentPopover-9l4QZlvQ.js +337 -0
  9. package/dist/ExperimentPopover-9l4QZlvQ.js.map +1 -0
  10. package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-pR5fK3pA.js} +244 -211
  11. package/dist/ExperimentSelectorModal-pR5fK3pA.js.map +1 -0
  12. package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-CJ7EAmOq.js} +2 -2
  13. package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-CJ7EAmOq.js.map} +1 -1
  14. package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-Dyitgzfp.js} +28 -27
  15. package/dist/SettingsModal-Dyitgzfp.js.map +1 -0
  16. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  17. package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
  19. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  20. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  21. package/dist/components/AppSidebar.vue.d.ts +1 -1
  22. package/dist/components/AppTopBar.vue.d.ts +20 -5
  23. package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
  24. package/dist/components/AuditTrail.vue.d.ts +1 -1
  25. package/dist/components/BaseButton.vue.d.ts +4 -2
  26. package/dist/components/BaseSelect.vue.d.ts +2 -2
  27. package/dist/components/ChartContainer.vue.d.ts +2 -0
  28. package/dist/components/DatePicker.vue.d.ts +1 -1
  29. package/dist/components/ExperimentPopover.vue.d.ts +18 -0
  30. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -5
  31. package/dist/components/FilePicker.vue.d.ts +1 -1
  32. package/dist/components/FileUploader.vue.d.ts +2 -2
  33. package/dist/components/JobsStatusTray.vue.d.ts +15 -4
  34. package/dist/components/PluginIcon.vue.d.ts +2 -2
  35. package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
  36. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
  37. package/dist/components/SampleSelector.vue.d.ts +6 -6
  38. package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
  39. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -1
  40. package/dist/components/StepWizard.vue.d.ts +3 -0
  41. package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
  42. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  43. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +1 -1
  44. package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
  45. package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
  46. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
  47. package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
  48. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
  49. package/dist/composables/createClient.d.ts +2 -0
  50. package/dist/composables/index.d.ts +1 -0
  51. package/dist/composables/pluginIdentity.d.ts +24 -0
  52. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  53. package/dist/composables/useAppExperiment.d.ts +8 -0
  54. package/dist/composables/useCalendarGrid.d.ts +1 -1
  55. package/dist/composables/useExperimentSelector.d.ts +6 -2
  56. package/dist/composables/useJobCenter.d.ts +41 -3
  57. package/dist/composables/useOnboarding.d.ts +119 -0
  58. package/dist/composables/usePlatform.d.ts +1 -0
  59. package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-DCUOx8ll.js} +2 -2
  60. package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-DCUOx8ll.js.map} +1 -1
  61. package/dist/{data-C2PwI_dn.js → data-DBnmeBZX.js} +179 -125
  62. package/dist/data-DBnmeBZX.js.map +1 -0
  63. package/dist/data.js +8 -8
  64. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  65. package/dist/experiment-DyO54FQB.js.map +1 -0
  66. package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-BFrKpHAH.js} +3 -3
  67. package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-BFrKpHAH.js.map} +1 -1
  68. package/dist/index.js +20 -20
  69. package/dist/{install-DAID6c2-.js → install-qjELyNwc.js} +15 -14
  70. package/dist/{install-DAID6c2-.js.map → install-qjELyNwc.js.map} +1 -1
  71. package/dist/install.js +1 -1
  72. package/dist/{lab-DLwRl_Ql.js → lab-UyTbokQC.js} +136 -148
  73. package/dist/lab-UyTbokQC.js.map +1 -0
  74. package/dist/lab.js +4 -3
  75. package/dist/{records-BzTcxekG.js → records-CR_pYzIP.js} +533 -335
  76. package/dist/records-CR_pYzIP.js.map +1 -0
  77. package/dist/{runtime-D6gVat6r.js → runtime-CoHhBP10.js} +417 -54
  78. package/dist/runtime-CoHhBP10.js.map +1 -0
  79. package/dist/runtime.d.ts +1 -1
  80. package/dist/runtime.js +7 -7
  81. package/dist/{shell-5ju97nOS.js → shell-BDuZf2zb.js} +10 -5
  82. package/dist/{shell-5ju97nOS.js.map → shell-BDuZf2zb.js.map} +1 -1
  83. package/dist/shell.d.ts +1 -0
  84. package/dist/shell.js +6 -6
  85. package/dist/stores/index.d.ts +1 -1
  86. package/dist/stores/index.js +2 -2
  87. package/dist/stores/settings.d.ts +4 -12
  88. package/dist/styles.css +2732 -2083
  89. package/dist/types/componentWorkflowTypes.d.ts +2 -0
  90. package/dist/types/components.d.ts +2 -0
  91. package/dist/types/generated/platformContext.d.ts +1 -0
  92. package/dist/types/generated-ui.d.ts +4 -0
  93. package/dist/types/index.d.ts +1 -1
  94. package/dist/types/jobs.d.ts +9 -0
  95. package/dist/types/platform.d.ts +1 -1
  96. package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-Bb2N4m40.js} +74 -4
  97. package/dist/useDropdownState-Bb2N4m40.js.map +1 -0
  98. package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-Dno1fFMq.js} +4 -4
  99. package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-Dno1fFMq.js.map} +1 -1
  100. package/dist/{useListReorder-CcbEYxX-.js → useListReorder-CQ9OCScc.js} +183 -351
  101. package/dist/useListReorder-CQ9OCScc.js.map +1 -0
  102. package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-wL3kPrRT.js} +73 -59
  103. package/dist/useRackEditor-wL3kPrRT.js.map +1 -0
  104. package/dist/useRealtime-C3whhVvb.js +508 -0
  105. package/dist/useRealtime-C3whhVvb.js.map +1 -0
  106. package/dist/useRequest-CDkrXNU7.js +244 -0
  107. package/dist/useRequest-CDkrXNU7.js.map +1 -0
  108. package/dist/utils/time.d.ts +7 -0
  109. package/package.json +1 -1
  110. package/src/__stories__/experiment-helpers.ts +3 -3
  111. package/src/__tests__/components/AppTopBar.test.ts +257 -3
  112. package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
  113. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  114. package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
  115. package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
  116. package/src/__tests__/components/BaseButton.test.ts +19 -0
  117. package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
  118. package/src/__tests__/components/BaseSelect.test.ts +2 -1
  119. package/src/__tests__/components/BatchProgressList.test.ts +16 -0
  120. package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
  121. package/src/__tests__/components/ChartContainer.test.ts +11 -0
  122. package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
  123. package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
  124. package/src/__tests__/components/DatePicker.test.ts +21 -0
  125. package/src/__tests__/components/DatePicker.time.test.ts +2 -2
  126. package/src/__tests__/components/EmptyState.test.ts +1 -1
  127. package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
  128. package/src/__tests__/components/ExperimentSelectorModal.test.ts +153 -14
  129. package/src/__tests__/components/GeneratedPluginView.test.ts +23 -2
  130. package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
  131. package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
  132. package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
  133. package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
  134. package/src/__tests__/components/SampleSelector.test.ts +33 -8
  135. package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
  136. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  137. package/src/__tests__/components/StepWizard.test.ts +11 -0
  138. package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
  139. package/src/__tests__/components/deprecationTags.test.ts +1 -1
  140. package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
  141. package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
  142. package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
  143. package/src/__tests__/composables/useJobCenter.test.ts +262 -3
  144. package/src/__tests__/composables/useOnboarding.test.ts +317 -0
  145. package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
  146. package/src/__tests__/stores/settings.test.ts +21 -21
  147. package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
  148. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  149. package/src/__tests__/styles/cssTokens.test.ts +6 -3
  150. package/src/__tests__/styles/menusShellRefresh.test.ts +22 -12
  151. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  152. package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
  153. package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
  154. package/src/__tests__/utils/time.test.ts +18 -1
  155. package/src/components/AdductText.story.vue +7 -0
  156. package/src/components/AdductText.vue +1 -1
  157. package/src/components/AlertBox.story.vue +2 -2
  158. package/src/components/AlertBox.vue +18 -16
  159. package/src/components/AppSidebar.story.vue +0 -28
  160. package/src/components/AppTopBar.onboarding.story.vue +69 -0
  161. package/src/components/AppTopBar.story.vue +105 -15
  162. package/src/components/AppTopBar.vue +248 -122
  163. package/src/components/ArtifactSaveDialog.story.vue +23 -0
  164. package/src/components/ArtifactSaveDialog.vue +102 -12
  165. package/src/components/AuditTrail.story.vue +2 -1
  166. package/src/components/AuditTrail.vue +2 -21
  167. package/src/components/Avatar.vue +10 -14
  168. package/src/components/BaseButton.vue +16 -2
  169. package/src/components/BaseSelect.multiple.story.vue +13 -2
  170. package/src/components/BaseSelect.vue +4 -3
  171. package/src/components/BatchProgressList.vue +35 -25
  172. package/src/components/ChartContainer.story.vue +2 -1
  173. package/src/components/ChartContainer.vue +8 -6
  174. package/src/components/ConfirmDialog.story.vue +1 -1
  175. package/src/components/EmptyState.vue +1 -1
  176. package/src/components/ExperimentPopover.story.vue +165 -53
  177. package/src/components/ExperimentPopover.vue +169 -187
  178. package/src/components/ExperimentSelectorModal.story.vue +73 -31
  179. package/src/components/ExperimentSelectorModal.vue +144 -111
  180. package/src/components/FormField.story.vue +8 -48
  181. package/src/components/GeneratedPluginView.vue +11 -10
  182. package/src/components/GeneratedResultRenderer.vue +3 -4
  183. package/src/components/InstrumentStateBadge.vue +1 -1
  184. package/src/components/JobsStatusTray.story.vue +97 -43
  185. package/src/components/JobsStatusTray.vue +287 -290
  186. package/src/components/LayoutResizeHandle.story.vue +65 -4
  187. package/src/components/LoadingSpinner.vue +1 -1
  188. package/src/components/NumberInput.vue +3 -6
  189. package/src/components/PluginIcon.story.vue +2 -10
  190. package/src/components/PluginIcon.vue +2 -2
  191. package/src/components/PluginWorkspaceView.props.ts +3 -0
  192. package/src/components/PluginWorkspaceView.story.vue +1 -1
  193. package/src/components/PluginWorkspaceView.vue +17 -0
  194. package/src/components/RuntimeUpdateNotice.vue +1 -1
  195. package/src/components/SampleSelector.story.vue +22 -7
  196. package/src/components/SampleSelector.vue +34 -37
  197. package/src/components/SampleSelectorGroupNode.vue +1 -1
  198. package/src/components/SectionCard.story.vue +35 -2
  199. package/src/components/SequenceProgressBar.story.vue +9 -0
  200. package/src/components/SequenceProgressBar.vue +6 -1
  201. package/src/components/SettingsModal.schema.ts +1 -1
  202. package/src/components/SettingsModal.vue +9 -14
  203. package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
  204. package/src/components/SmartGroupManual.story.vue +1 -1
  205. package/src/components/StepWizard.story.vue +33 -0
  206. package/src/components/StepWizard.vue +8 -1
  207. package/src/components/WellPlate.story.vue +3 -1
  208. package/src/components/WellPlate.vue +7 -0
  209. package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
  210. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  211. package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
  212. package/src/components/internal/DatePickerDateInternal.vue +16 -40
  213. package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
  214. package/src/components/internal/DatePickerTimeInternal.vue +5 -8
  215. package/src/components/internal/OnboardingLayerInternal.vue +173 -0
  216. package/src/components/internal/ResourcePickerListInternal.vue +45 -85
  217. package/src/components/internal/SelectMultipleInternal.vue +182 -65
  218. package/src/components/internal/SelectSearchableInternal.vue +2 -3
  219. package/src/components/internal/WorkspaceShellInternal.vue +12 -0
  220. package/src/composables/createClient.ts +2 -0
  221. package/src/composables/index.ts +1 -0
  222. package/src/composables/pluginIdentity.ts +31 -0
  223. package/src/composables/pluginWorkspaceModel.ts +2 -2
  224. package/src/composables/useAppExperiment.ts +20 -0
  225. package/src/composables/useCalendarGrid.ts +4 -3
  226. package/src/composables/useExperimentSelector.ts +77 -31
  227. package/src/composables/useJobCenter.ts +188 -6
  228. package/src/composables/useOnboarding.ts +465 -0
  229. package/src/composables/usePluginWorkspace.ts +1 -1
  230. package/src/runtime.ts +2 -1
  231. package/src/shell.ts +17 -0
  232. package/src/stores/index.ts +0 -2
  233. package/src/stores/settings.ts +20 -50
  234. package/src/styles/components/adduct-text.css +13 -5
  235. package/src/styles/components/alert-box.css +39 -58
  236. package/src/styles/components/app-layout.css +7 -5
  237. package/src/styles/components/app-page-selector.css +121 -44
  238. package/src/styles/components/app-pill-nav.css +11 -12
  239. package/src/styles/components/app-sidebar.css +9 -18
  240. package/src/styles/components/app-top-bar.css +219 -55
  241. package/src/styles/components/artifact-save-dialog.css +153 -2
  242. package/src/styles/components/audit-trail.css +16 -19
  243. package/src/styles/components/avatar.css +6 -4
  244. package/src/styles/components/batch-progress-list.css +38 -36
  245. package/src/styles/components/button.css +36 -59
  246. package/src/styles/components/calendar.css +12 -12
  247. package/src/styles/components/chart-container.css +34 -23
  248. package/src/styles/components/checkbox.css +2 -12
  249. package/src/styles/components/collapsible-card.css +27 -29
  250. package/src/styles/components/confirm-dialog.css +13 -14
  251. package/src/styles/components/dataframe.css +13 -5
  252. package/src/styles/components/date-picker.css +80 -92
  253. package/src/styles/components/datetime-picker.css +31 -43
  254. package/src/styles/components/divider.css +20 -20
  255. package/src/styles/components/dose-calculator.css +3 -3
  256. package/src/styles/components/empty-state.css +20 -17
  257. package/src/styles/components/experiment-code-badge.css +2 -0
  258. package/src/styles/components/experiment-popover.css +174 -329
  259. package/src/styles/components/experiment-selector-modal.css +88 -56
  260. package/src/styles/components/file-picker.css +3 -3
  261. package/src/styles/components/file-uploader.css +38 -49
  262. package/src/styles/components/form-builder.css +3 -3
  263. package/src/styles/components/formula-input.css +1 -1
  264. package/src/styles/components/icon-button.css +18 -24
  265. package/src/styles/components/input.css +5 -4
  266. package/src/styles/components/instrument-monitor.css +13 -15
  267. package/src/styles/components/jobs-status-tray.css +140 -296
  268. package/src/styles/components/layout-resize-handle.css +59 -16
  269. package/src/styles/components/modal.css +4 -6
  270. package/src/styles/components/molecule-input.css +2 -2
  271. package/src/styles/components/multi-select.css +65 -117
  272. package/src/styles/components/number-input.css +26 -19
  273. package/src/styles/components/onboarding.css +368 -0
  274. package/src/styles/components/pill.css +3 -2
  275. package/src/styles/components/plate-editor.css +0 -1
  276. package/src/styles/components/plugin-icon.css +26 -23
  277. package/src/styles/components/popover.css +2 -2
  278. package/src/styles/components/presence-avatars.css +1 -1
  279. package/src/styles/components/progress-bar.css +3 -3
  280. package/src/styles/components/protocol-step-editor.css +1 -3
  281. package/src/styles/components/resource-card.css +2 -2
  282. package/src/styles/components/resource-picker-list.css +6 -57
  283. package/src/styles/components/sample-hierarchy-tree.css +4 -4
  284. package/src/styles/components/sample-selector.css +138 -79
  285. package/src/styles/components/schedule-calendar.css +8 -8
  286. package/src/styles/components/searchable-select.css +12 -12
  287. package/src/styles/components/section-card.css +54 -49
  288. package/src/styles/components/segmented-control.css +18 -15
  289. package/src/styles/components/select.css +3 -3
  290. package/src/styles/components/sequence-input.css +2 -2
  291. package/src/styles/components/sequence-progress-bar.css +17 -8
  292. package/src/styles/components/settings-modal.css +7 -2
  293. package/src/styles/components/smart-group.css +18 -18
  294. package/src/styles/components/step-wizard.css +52 -16
  295. package/src/styles/components/tabs.css +2 -2
  296. package/src/styles/components/textarea.css +3 -3
  297. package/src/styles/components/time-picker.css +36 -21
  298. package/src/styles/components/toast.css +12 -10
  299. package/src/styles/components/toggle.css +1 -11
  300. package/src/styles/components/tooltip.css +10 -9
  301. package/src/styles/components/unit-input.css +8 -7
  302. package/src/styles/components/well-plate.css +9 -2
  303. package/src/styles/index.css +1 -0
  304. package/src/styles/variables.css +241 -78
  305. package/src/types/componentWorkflowTypes.ts +2 -0
  306. package/src/types/components.ts +2 -0
  307. package/src/types/generated/platformContext.ts +1 -0
  308. package/src/types/generated-ui.ts +4 -0
  309. package/src/types/index.ts +1 -0
  310. package/src/types/jobs.ts +10 -0
  311. package/src/types/platform.ts +1 -1
  312. package/src/utils/time.ts +21 -0
  313. package/dist/ActionMenu-CScINahU.js.map +0 -1
  314. package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
  315. package/dist/BaseModal-DfRIuVoj.js.map +0 -1
  316. package/dist/ExperimentPopover-C4sGw-is.js +0 -359
  317. package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
  318. package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
  319. package/dist/SettingsModal-CSLE31yg.js.map +0 -1
  320. package/dist/data-C2PwI_dn.js.map +0 -1
  321. package/dist/experiment-43OJtH7R.js.map +0 -1
  322. package/dist/lab-DLwRl_Ql.js.map +0 -1
  323. package/dist/records-BzTcxekG.js.map +0 -1
  324. package/dist/runtime-D6gVat6r.js.map +0 -1
  325. package/dist/useListReorder-CcbEYxX-.js.map +0 -1
  326. package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
  327. package/dist/useRealtime-PalKue84.js +0 -696
  328. package/dist/useRealtime-PalKue84.js.map +0 -1
  329. package/dist/useRequest-D5JDfsgZ.js +0 -76
  330. package/dist/useRequest-D5JDfsgZ.js.map +0 -1
@@ -1,6 +1,10 @@
1
1
  <script setup lang="ts">
2
- /** Full application top bar with brand logo, static plugin identity, page selector, centered pill nav, experiment popover, and an account slot. */
3
- import { ref, computed, inject, defineAsyncComponent, onMounted, onBeforeUnmount, toValue, watch } from 'vue'
2
+ /**
3
+ * Full application top bar with brand logo, static plugin identity, page selector, centered pill nav, experiment popover, and an account slot.
4
+ *
5
+ * The `#icon` slot applies in standalone mode only; integrated branding comes from `Metadata.icon`.
6
+ */
7
+ import { ref, computed, inject, defineAsyncComponent, onMounted, onBeforeUnmount, toValue, useSlots, watch, type Component } from 'vue'
4
8
  import type {
5
9
  PillNavOption,
6
10
  PillNavItem,
@@ -15,11 +19,17 @@ import { applySpecDefaults } from '../composables/componentSpecs'
15
19
  import ThemeToggle from './ThemeToggle.vue'
16
20
  import AppTopBarPageSelectorInternal from './internal/AppTopBarPageSelectorInternal.vue'
17
21
  import AppTopBarPillNavInternal from './internal/AppTopBarPillNavInternal.vue'
22
+ import AppTopBarOnboardingInternal from './internal/AppTopBarOnboardingInternal.vue'
18
23
  import PluginIcon from './PluginIcon.vue'
19
24
  import { usePlatform } from '../composables/usePlatform'
20
25
  import { APP_EXPERIMENT_KEY } from '../composables/useAppExperiment'
26
+ import { useOnboarding } from '../composables/useOnboarding'
27
+ import { pluginIdentity } from '../composables/pluginIdentity'
21
28
  import { integrationHost } from '../utils/integrationHost'
22
29
  import { trackTopBarForToasts } from './AppTopBar.toastOffset'
30
+ import { CircleAlert, CircleCheck, CircleX, ListChecks, LoaderCircle } from 'lucide-vue-next'
31
+ import type { JobStatus, TopBarJob } from '../types/jobs'
32
+ import type { Tone } from '../types/components'
23
33
 
24
34
  interface Props {
25
35
  /** App or plugin title shown in the left title group when no page selector is present. */
@@ -34,10 +44,23 @@ interface Props {
34
44
  pageSelector?: PageSelectorItemInput[]
35
45
  /** Active id of the platform page selector. */
36
46
  currentPageSelectorId?: string
47
+ /**
48
+ * The viewer's own job, joined to the experiment chip. Omit it for no jobs control;
49
+ * `null` shows the idle Jobs button. Both emit `job-click`.
50
+ */
51
+ job?: TopBarJob | null
52
+ /** Completed jobs, shown as a small count on the idle Jobs button. Hidden when 0. */
53
+ jobsDone?: number
54
+ /** Whether the jobs panel is open; `aria-expanded` of the job control. */
55
+ jobsOpen?: boolean
56
+ /** DOM id of the jobs panel; `aria-controls` of the job control. */
57
+ jobsPanelId?: string
37
58
  }
38
59
 
39
60
  const props = withDefaults(defineProps<Props>(), {
40
61
  spec: () => ({}),
62
+ // No boolean cast: without a jobs panel the control has no aria-expanded.
63
+ jobsOpen: undefined,
41
64
  })
42
65
 
43
66
  const config = computed(() => applySpecDefaults({
@@ -61,6 +84,7 @@ const emit = defineEmits<{
61
84
  'pill-select': [item: PillNavItem]
62
85
  'pill-option-select': [option: PillNavOption, item: PillNavItem]
63
86
  'settings-values-change': [data: Record<string, unknown>]
87
+ 'job-click': []
64
88
  }>()
65
89
 
66
90
  const settingsOpen = ref(false)
@@ -73,14 +97,53 @@ onBeforeUnmount(() => untrackToastOffset?.())
73
97
  const { integrated: isIntegrated, plugin } = usePlatform()
74
98
  const isStandalone = computed(() => !isIntegrated.value)
75
99
  const appExperiment = inject(APP_EXPERIMENT_KEY, null)
100
+ const onboarding = useOnboarding()
76
101
  const canBindExperiment = computed(() => plugin.value?.plugin_type !== 'static')
102
+ const showExperiment = computed(() => !!appExperiment && !isStandalone.value && canBindExperiment.value)
103
+ // The border joins only once the job is on screen and stays until it has left,
104
+ // so the name and the job never show at the same time.
105
+ const runSlotJoined = ref(!!props.job)
106
+ const JOB_STATUS_TEXT: Record<JobStatus, string> = {
107
+ queued: 'Job queued',
108
+ running: 'Job running',
109
+ awaiting_input: 'Job needs input',
110
+ completed: 'Job completed',
111
+ failed: 'Job failed',
112
+ cancelled: 'Job cancelled',
113
+ }
114
+ const jobPercent = computed(() =>
115
+ props.job?.percent == null ? null : Math.min(100, Math.max(0, Math.round(props.job.percent))),
116
+ )
117
+ const jobName = computed(() => props.job
118
+ ? (jobPercent.value != null ? `${props.job.label} ${jobPercent.value}%` : props.job.label)
119
+ : undefined)
120
+ function syncRunSlotJoined() {
121
+ runSlotJoined.value = !!props.job
122
+ }
77
123
 
78
- const pluginIcon = computed(() => {
79
- const currentPlugin = plugin.value
80
- return currentPlugin?.icon
81
- ? { icon: currentPlugin.icon, color: currentPlugin.color }
82
- : null
83
- })
124
+ const JOB_TONES: Record<JobStatus, Tone> = {
125
+ queued: 'primary',
126
+ running: 'primary',
127
+ awaiting_input: 'warning',
128
+ completed: 'success',
129
+ failed: 'error',
130
+ cancelled: 'neutral',
131
+ }
132
+ const JOB_ICONS: Record<JobStatus, Component> = {
133
+ queued: LoaderCircle,
134
+ running: LoaderCircle,
135
+ awaiting_input: CircleAlert,
136
+ completed: CircleCheck,
137
+ failed: CircleX,
138
+ cancelled: CircleX,
139
+ }
140
+
141
+ const slots = useSlots()
142
+ // Standalone: the seeded identity (providePluginIdentity) stands in for a missing icon and title.
143
+ const pluginIcon = computed(() => plugin.value?.icon || (slots.logo ? undefined : pluginIdentity.icon))
144
+ const seeded = computed(() => isStandalone.value && !props.title && !props.subtitle)
145
+ const titleText = computed(() => props.title || (seeded.value ? pluginIdentity.name : undefined))
146
+ const subtitleText = computed(() => props.subtitle || (seeded.value ? pluginIdentity.subtitle : undefined))
84
147
 
85
148
  const hasPlatformPageSelector = computed(() =>
86
149
  props.pageSelector === undefined && (plugin.value?.nav_items?.length ?? 0) > 1,
@@ -98,20 +161,26 @@ watch(platformPageSelectorEl, (element, _previous, onCleanup) => {
98
161
  const identityName = computed(() =>
99
162
  isIntegrated.value && !hasPageSelector.value ? plugin.value?.display_name || plugin.value?.name : undefined,
100
163
  )
164
+ /** The page selector crumb reads "<plugin> / <page>". */
165
+ const pageSelectorPluginName = computed(() =>
166
+ isIntegrated.value ? plugin.value?.display_name || plugin.value?.name : props.title || pluginIdentity.name,
167
+ )
168
+ // Platforms before 1.4 send no subtitle; the description fills line 2.
169
+ const identitySubtitle = computed(() => plugin.value?.subtitle || plugin.value?.description)
101
170
  const hasPillNav = computed(() => !!config.value.pills?.length)
102
171
  const hasTitleGroup = computed(
103
172
  () =>
104
173
  !hasPageSelector.value &&
105
174
  !identityName.value &&
106
- !!props.title &&
107
- !!props.subtitle
175
+ !!titleText.value &&
176
+ !!subtitleText.value
108
177
  )
109
178
  const hasTitleOnly = computed(
110
179
  () =>
111
180
  !hasPageSelector.value &&
112
181
  !identityName.value &&
113
182
  !hasTitleGroup.value &&
114
- !!props.title,
183
+ !!titleText.value,
115
184
  )
116
185
  const normalizedPageSelector = computed<PageSelectorItem[]>(() =>
117
186
  props.pageSelector?.map(normalizeItemInput) ?? [],
@@ -137,138 +206,137 @@ const normalizedSettingsTabs = computed<SettingsTab[]>(() =>
137
206
  >
138
207
  <div class="mint-topbar__container">
139
208
  <!-- Left: brand -->
140
- <div class="mint-topbar__brand">
141
- <a
142
- v-if="config.homePath && (config.homePath.startsWith('http') || config.homePath.startsWith('/'))"
143
- :href="config.homePath"
144
- class="mint-topbar-home-link"
145
- >
146
- <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
147
- <PluginIcon
148
- v-if="isIntegrated"
149
- class="mint-topbar__plugin-icon"
150
- :icon="plugin?.icon"
151
- :color="plugin?.color"
152
- size="topbar"
153
- variant="solid"
154
- />
155
- <slot v-else name="icon">
209
+ <div class="mint-topbar__start">
210
+ <div class="mint-topbar__brand">
211
+ <a
212
+ v-if="config.homePath && (config.homePath.startsWith('http') || config.homePath.startsWith('/'))"
213
+ :href="config.homePath"
214
+ class="mint-topbar-home-link"
215
+ >
216
+ <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
156
217
  <PluginIcon
157
- v-if="pluginIcon"
218
+ v-if="isIntegrated"
158
219
  class="mint-topbar__plugin-icon"
159
- :icon="pluginIcon.icon"
160
- :color="pluginIcon.color"
220
+ :icon="plugin?.icon"
161
221
  size="topbar"
162
222
  variant="solid"
163
223
  />
164
- <slot v-else name="logo">
165
- <div v-if="config.logo" class="mint-topbar__logo">
166
- <div class="mint-topbar__logo-icon">
167
- <span class="mint-topbar__logo-text">M</span>
224
+ <slot v-else name="icon">
225
+ <PluginIcon
226
+ v-if="pluginIcon"
227
+ class="mint-topbar__plugin-icon"
228
+ :icon="pluginIcon"
229
+ size="topbar"
230
+ variant="solid"
231
+ />
232
+ <slot v-else name="logo">
233
+ <div v-if="config.logo" class="mint-topbar__logo">
234
+ <div class="mint-topbar__logo-icon">
235
+ <span class="mint-topbar__logo-text">M</span>
236
+ </div>
168
237
  </div>
169
- </div>
238
+ </slot>
170
239
  </slot>
171
- </slot>
172
- </span>
173
- </a>
174
- <router-link
175
- v-else-if="config.homePath"
176
- :to="config.homePath"
177
- class="mint-topbar-home-link"
178
- >
179
- <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
180
- <PluginIcon
181
- v-if="isIntegrated"
182
- class="mint-topbar__plugin-icon"
183
- :icon="plugin?.icon"
184
- :color="plugin?.color"
185
- size="topbar"
186
- variant="solid"
187
- />
188
- <slot v-else name="icon">
240
+ </span>
241
+ </a>
242
+ <router-link
243
+ v-else-if="config.homePath"
244
+ :to="config.homePath"
245
+ class="mint-topbar-home-link"
246
+ >
247
+ <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
189
248
  <PluginIcon
190
- v-if="pluginIcon"
249
+ v-if="isIntegrated"
191
250
  class="mint-topbar__plugin-icon"
192
- :icon="pluginIcon.icon"
193
- :color="pluginIcon.color"
251
+ :icon="plugin?.icon"
194
252
  size="topbar"
195
253
  variant="solid"
196
254
  />
197
- <slot v-else name="logo">
198
- <div v-if="config.logo" class="mint-topbar__logo">
199
- <div class="mint-topbar__logo-icon">
200
- <span class="mint-topbar__logo-text">M</span>
255
+ <slot v-else name="icon">
256
+ <PluginIcon
257
+ v-if="pluginIcon"
258
+ class="mint-topbar__plugin-icon"
259
+ :icon="pluginIcon"
260
+ size="topbar"
261
+ variant="solid"
262
+ />
263
+ <slot v-else name="logo">
264
+ <div v-if="config.logo" class="mint-topbar__logo">
265
+ <div class="mint-topbar__logo-icon">
266
+ <span class="mint-topbar__logo-text">M</span>
267
+ </div>
201
268
  </div>
202
- </div>
269
+ </slot>
203
270
  </slot>
204
- </slot>
205
- </span>
206
- </router-link>
207
- <template v-else>
208
- <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
209
- <PluginIcon
210
- v-if="isIntegrated"
211
- class="mint-topbar__plugin-icon"
212
- :icon="plugin?.icon"
213
- :color="plugin?.color"
214
- size="topbar"
215
- variant="solid"
216
- />
217
- <slot v-else name="icon">
271
+ </span>
272
+ </router-link>
273
+ <template v-else>
274
+ <span v-if="isIntegrated || $slots.icon || $slots.logo || pluginIcon || config.logo" class="mint-topbar__identity">
218
275
  <PluginIcon
219
- v-if="pluginIcon"
276
+ v-if="isIntegrated"
220
277
  class="mint-topbar__plugin-icon"
221
- :icon="pluginIcon.icon"
222
- :color="pluginIcon.color"
278
+ :icon="plugin?.icon"
223
279
  size="topbar"
224
280
  variant="solid"
225
281
  />
226
- <slot v-else name="logo">
227
- <div v-if="config.logo" class="mint-topbar__logo">
228
- <div class="mint-topbar__logo-icon">
229
- <span class="mint-topbar__logo-text">M</span>
282
+ <slot v-else name="icon">
283
+ <PluginIcon
284
+ v-if="pluginIcon"
285
+ class="mint-topbar__plugin-icon"
286
+ :icon="pluginIcon"
287
+ size="topbar"
288
+ variant="solid"
289
+ />
290
+ <slot v-else name="logo">
291
+ <div v-if="config.logo" class="mint-topbar__logo">
292
+ <div class="mint-topbar__logo-icon">
293
+ <span class="mint-topbar__logo-text">M</span>
294
+ </div>
230
295
  </div>
231
- </div>
296
+ </slot>
232
297
  </slot>
233
- </slot>
234
- </span>
235
- </template>
236
- </div>
298
+ </span>
299
+ </template>
300
+ </div>
237
301
 
238
- <!-- Left: static plugin identity (not a control) -->
239
- <span v-if="identityName" class="mint-topbar__plugin-identity">
240
- <span class="mint-topbar__plugin-name">{{ identityName }}</span>
241
- </span>
302
+ <!-- Left: static plugin identity (not a control) -->
303
+ <span v-if="identityName" class="mint-topbar__plugin-identity">
304
+ <span class="mint-topbar__plugin-name">{{ identityName }}</span>
305
+ <span v-if="identitySubtitle" class="mint-topbar__plugin-subtitle">{{ identitySubtitle }}</span>
306
+ </span>
242
307
 
243
- <!-- Left: page selector (the platform integration script renders the nav_items one) -->
244
- <span v-if="hasPlatformPageSelector" ref="platformPageSelectorEl" class="mint-topbar__platform-page-selector" />
245
- <AppTopBarPageSelectorInternal
246
- v-else-if="hasPropPageSelector"
247
- :pages="normalizedPageSelector"
248
- :current-page-id="currentPageSelectorId"
249
- @select="emit('page-selector-select', $event)"
250
- >
251
- <template v-if="$slots['page-selector-icon']" #icon="slotProps">
252
- <slot name="page-selector-icon" v-bind="slotProps" />
253
- </template>
254
- <template v-if="$slots['page-selector-item-icon']" #item-icon="slotProps">
255
- <slot name="page-selector-item-icon" v-bind="slotProps" />
256
- </template>
257
- </AppTopBarPageSelectorInternal>
308
+ <!-- Left: page selector (the platform integration script renders the nav_items one) -->
309
+ <span v-if="hasPlatformPageSelector" ref="platformPageSelectorEl" class="mint-topbar__platform-page-selector" data-onboarding="topbar-page-selector" />
310
+ <AppTopBarPageSelectorInternal
311
+ v-else-if="hasPropPageSelector"
312
+ data-onboarding="topbar-page-selector"
313
+ :pages="normalizedPageSelector"
314
+ :current-page-id="currentPageSelectorId"
315
+ :plugin-name="pageSelectorPluginName"
316
+ @select="emit('page-selector-select', $event)"
317
+ >
318
+ <template v-if="$slots['page-selector-icon']" #icon="slotProps">
319
+ <slot name="page-selector-icon" v-bind="slotProps" />
320
+ </template>
321
+ <template v-if="$slots['page-selector-item-icon']" #item-icon="slotProps">
322
+ <slot name="page-selector-item-icon" v-bind="slotProps" />
323
+ </template>
324
+ </AppTopBarPageSelectorInternal>
258
325
 
259
- <!-- Left: title -->
260
- <div v-if="hasTitleGroup" class="mint-topbar-title-group">
261
- <span class="mint-topbar-title">{{ title }}</span>
262
- <span class="mint-topbar-subtitle">{{ subtitle }}</span>
263
- </div>
326
+ <!-- Left: title -->
327
+ <div v-if="hasTitleGroup" class="mint-topbar-title-group">
328
+ <span class="mint-topbar-title">{{ titleText }}</span>
329
+ <span class="mint-topbar-subtitle">{{ subtitleText }}</span>
330
+ </div>
264
331
 
265
- <span v-else-if="hasTitleOnly" class="mint-topbar__title-only">{{ title }}</span>
332
+ <span v-else-if="hasTitleOnly" class="mint-topbar__title-only">{{ titleText }}</span>
266
333
 
267
- <!-- Nav slot (inline, after brand/selector) -->
268
- <slot name="nav" />
334
+ <!-- Nav slot (inline, after brand/selector) -->
335
+ <slot name="nav" />
336
+ </div>
269
337
 
270
338
  <!-- Center: pill nav -->
271
- <div v-if="hasPillNav || $slots.center" class="mint-topbar__center">
339
+ <div v-if="hasPillNav || $slots.center" class="mint-topbar__center" data-onboarding="topbar-pills">
272
340
  <slot name="center">
273
341
  <AppTopBarPillNavInternal
274
342
  v-if="hasPillNav"
@@ -286,16 +354,73 @@ const normalizedSettingsTabs = computed<SettingsTab[]>(() =>
286
354
  {{ config.standaloneLabel }}
287
355
  </span>
288
356
 
289
- <ExperimentPopover
290
- v-if="appExperiment && !isStandalone && canBindExperiment"
291
- v-bind="appExperiment.popover.value"
292
- @select="appExperiment.openModal()"
293
- @save="appExperiment.handleSave()"
294
- @detach="appExperiment.handleDetach()"
295
- />
357
+ <!-- Run slot: while a job shows, its progress takes the place of the experiment name and Save:
358
+ [ EXP-0142 ▾ | job ]. The idle Jobs button stands apart. -->
359
+ <div
360
+ v-if="showExperiment || job !== undefined || runSlotJoined"
361
+ :class="['mint-topbar__run-slot', { 'mint-topbar__run-slot--joined': runSlotJoined }]"
362
+ data-onboarding="topbar-run"
363
+ >
364
+ <ExperimentPopover
365
+ v-if="showExperiment && appExperiment"
366
+ v-bind="job ? { ...appExperiment.popover.value, showSave: false } : appExperiment.popover.value"
367
+ @select="appExperiment.openModal()"
368
+ @save="appExperiment.handleSave()"
369
+ @detach="appExperiment.handleDetach()"
370
+ />
371
+ <!-- Status words only, so a moving percent does not repeat. -->
372
+ <span class="mint-topbar__job-status" aria-live="polite">{{ job ? JOB_STATUS_TEXT[job.status] : '' }}</span>
373
+ <!-- appear: the slot can mount together with its first job; before-enter then joins it. -->
374
+ <Transition
375
+ name="mint-topbar-job"
376
+ mode="out-in"
377
+ appear
378
+ @before-enter="syncRunSlotJoined"
379
+ @after-leave="syncRunSlotJoined"
380
+ >
381
+ <button
382
+ v-if="job"
383
+ key="run"
384
+ type="button"
385
+ :class="['mint-topbar__job', `mint-topbar__job--${JOB_TONES[job.status]}`]"
386
+ :title="jobName"
387
+ :aria-label="jobName"
388
+ :aria-expanded="jobsOpen"
389
+ :aria-controls="jobsPanelId"
390
+ @click="emit('job-click')"
391
+ >
392
+ <component
393
+ :is="JOB_ICONS[job.status]"
394
+ :class="['mint-topbar__job-icon', { 'mint-topbar__job-icon--spin': job.status === 'running' || job.status === 'queued' }]"
395
+ :size="14"
396
+ aria-hidden="true"
397
+ />
398
+ <span v-if="jobPercent != null" class="mint-topbar__job-bar" aria-hidden="true">
399
+ <span :style="{ width: `${jobPercent}%` }" />
400
+ </span>
401
+ </button>
402
+ <button
403
+ v-else-if="job === null"
404
+ key="idle"
405
+ type="button"
406
+ class="mint-topbar__job mint-topbar__job--idle"
407
+ :aria-label="jobsDone ? `Jobs, ${jobsDone} completed` : undefined"
408
+ :aria-expanded="jobsOpen"
409
+ :aria-controls="jobsPanelId"
410
+ @click="emit('job-click')"
411
+ >
412
+ <ListChecks class="mint-topbar__job-icon" :size="14" aria-hidden="true" />
413
+ <span class="mint-topbar__job-label">Jobs</span>
414
+ <span v-if="jobsDone" class="mint-topbar__job-count" aria-hidden="true">{{ jobsDone }}</span>
415
+ </button>
416
+ </Transition>
417
+ </div>
296
418
 
297
419
  <slot name="actions" />
298
420
 
421
+ <!-- Onboarding: checklist chip, Help button and tour layer, when the app provides onboarding -->
422
+ <AppTopBarOnboardingInternal v-if="onboarding?.enabled.value" :state="onboarding" />
423
+
299
424
  <!-- Theme toggle -->
300
425
  <ThemeToggle v-if="config.themeToggle" size="sm" />
301
426
 
@@ -305,6 +430,7 @@ const normalizedSettingsTabs = computed<SettingsTab[]>(() =>
305
430
  type="button"
306
431
  class="mint-topbar__settings-btn"
307
432
  aria-label="Open settings"
433
+ data-onboarding="topbar-settings"
308
434
  @click="settingsOpen = true"
309
435
  >
310
436
  <svg class="mint-topbar__settings-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -6,6 +6,7 @@ import {
6
6
  type AnalysisArtifactDetail,
7
7
  type ArtifactSaveDialogPayload,
8
8
  } from '../types/analysisArtifactTypes'
9
+ import type { ExperimentSummary } from '../types'
9
10
 
10
11
  // -- Mock JSON result a plugin would hand the dialog --
11
12
  const mockResult: Record<string, unknown> = {
@@ -47,6 +48,19 @@ const existingJsonArtifact: AnalysisArtifactDetail = {
47
48
  result: mockResult,
48
49
  }
49
50
 
51
+ // -- Experiment shown in the strip at the top of the dialog --
52
+ const mockExperiment: ExperimentSummary = {
53
+ id: 42,
54
+ experiment_code: 'EXP-042',
55
+ name: 'Doxorubicin dose response, HeLa',
56
+ status: 'ongoing',
57
+ experiment_type: 'dose_response',
58
+ created_at: '2026-07-01T09:00:00Z',
59
+ updated_at: '2026-07-02T14:00:00Z',
60
+ has_design_data: true,
61
+ }
62
+ const changeCount = ref(0)
63
+
50
64
  // -- Mock handlers standing in for a generated plugin-client call --
51
65
  const lastPayload = ref<ArtifactSaveDialogPayload | null>(null)
52
66
 
@@ -103,10 +117,15 @@ const isOpenError = ref(false)
103
117
  v-if="lastPayload"
104
118
  style="margin-top: 1rem; padding: 0.75rem 1rem; background: var(--bg-secondary, #f8fafc); border: 1px solid var(--border-color, #e2e8f0); border-radius: 6px; font-size: 0.75rem; overflow-x: auto;"
105
119
  >{{ formatPayload(lastPayload) }}</pre>
120
+ <p v-if="changeCount" style="margin-top: 0.5rem; font-size: 0.75rem;">
121
+ change-experiment emitted {{ changeCount }}×
122
+ </p>
106
123
 
107
124
  <ArtifactSaveDialog
108
125
  v-model:open="isOpenFile"
109
126
  :experiment-id="42"
127
+ :experiment="mockExperiment"
128
+ @change-experiment="changeCount++"
110
129
  :mode="state.mode"
111
130
  :result="mockResult"
112
131
  :default-artifact-key="state.defaultArtifactKey"
@@ -190,6 +209,8 @@ const isOpenError = ref(false)
190
209
  <ArtifactSaveDialog
191
210
  v-model:open="isOpenUpdateFile"
192
211
  :experiment-id="42"
212
+ :experiment="mockExperiment"
213
+ @change-experiment="changeCount++"
193
214
  :existing-artifact="existingFileArtifact"
194
215
  accept=".pdf"
195
216
  :save-handler="saveHandler"
@@ -237,6 +258,8 @@ const isOpenError = ref(false)
237
258
  <ArtifactSaveDialog
238
259
  v-model:open="isOpenUpdateJson"
239
260
  :experiment-id="42"
261
+ :experiment="mockExperiment"
262
+ @change-experiment="changeCount++"
240
263
  :existing-artifact="existingJsonArtifact"
241
264
  :result="mockResult"
242
265
  :save-handler="saveHandler"