@morscherlab/mint-sdk 1.4.0-beta.2 → 1.4.0-beta.21

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 (353) hide show
  1. package/README.md +14 -3
  2. package/dist/{ActionMenu-CScINahU.js → AlertBox-DwgNTEqf.js} +40 -209
  3. package/dist/AlertBox-DwgNTEqf.js.map +1 -0
  4. package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-CZZaxni0.js} +1249 -239
  5. package/dist/AppSidebar-CZZaxni0.js.map +1 -0
  6. package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CjWoxAD1.js} +2 -2
  7. package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CjWoxAD1.js.map} +1 -1
  8. package/dist/ExperimentPopover-DujiuQIO.js +337 -0
  9. package/dist/ExperimentPopover-DujiuQIO.js.map +1 -0
  10. package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-B4j4eUOJ.js} +244 -211
  11. package/dist/ExperimentSelectorModal-B4j4eUOJ.js.map +1 -0
  12. package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-DyUPH3I5.js} +2 -2
  13. package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-DyUPH3I5.js.map} +1 -1
  14. package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-D2MOOtuO.js} +28 -27
  15. package/dist/SettingsModal-D2MOOtuO.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__/components/FloatingPanelsInModal.test.d.ts +1 -0
  19. package/dist/__tests__/composables/useFloatingPanel.test.d.ts +1 -0
  20. package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
  21. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  22. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  23. package/dist/components/AppSidebar.vue.d.ts +1 -1
  24. package/dist/components/AppTopBar.vue.d.ts +20 -5
  25. package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
  26. package/dist/components/AuditTrail.vue.d.ts +1 -1
  27. package/dist/components/BaseButton.vue.d.ts +4 -2
  28. package/dist/components/BaseSelect.vue.d.ts +2 -2
  29. package/dist/components/ChartContainer.vue.d.ts +2 -0
  30. package/dist/components/DatePicker.vue.d.ts +1 -1
  31. package/dist/components/ExperimentPopover.vue.d.ts +18 -0
  32. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -5
  33. package/dist/components/FilePicker.vue.d.ts +1 -1
  34. package/dist/components/FileUploader.vue.d.ts +2 -2
  35. package/dist/components/JobsStatusTray.vue.d.ts +15 -4
  36. package/dist/components/PluginIcon.vue.d.ts +2 -2
  37. package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
  38. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
  39. package/dist/components/SampleSelector.vue.d.ts +6 -6
  40. package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
  41. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -3
  42. package/dist/components/StepWizard.vue.d.ts +3 -0
  43. package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
  44. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  45. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +3 -3
  46. package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
  47. package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
  48. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
  49. package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
  50. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
  51. package/dist/composables/createClient.d.ts +2 -0
  52. package/dist/composables/index.d.ts +1 -0
  53. package/dist/composables/pluginIdentity.d.ts +24 -0
  54. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  55. package/dist/composables/useAppExperiment.d.ts +8 -0
  56. package/dist/composables/useCalendarGrid.d.ts +1 -1
  57. package/dist/composables/useExperimentSelector.d.ts +6 -2
  58. package/dist/composables/useFileImport.d.ts +7 -0
  59. package/dist/composables/useFloatingPanel.d.ts +29 -0
  60. package/dist/composables/useJobCenter.d.ts +41 -3
  61. package/dist/composables/useOnboarding.d.ts +119 -0
  62. package/dist/composables/usePlatform.d.ts +1 -0
  63. package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-Bsg0t5Ab.js} +2 -2
  64. package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-Bsg0t5Ab.js.map} +1 -1
  65. package/dist/{data-C2PwI_dn.js → data-Boeh4uPI.js} +180 -125
  66. package/dist/data-Boeh4uPI.js.map +1 -0
  67. package/dist/data.d.ts +1 -1
  68. package/dist/data.js +9 -9
  69. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  70. package/dist/experiment-DyO54FQB.js.map +1 -0
  71. package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-DCn2QKG7.js} +3 -3
  72. package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-DCn2QKG7.js.map} +1 -1
  73. package/dist/index.js +20 -20
  74. package/dist/{install-DAID6c2-.js → install-BEHp7Mo-.js} +15 -14
  75. package/dist/{install-DAID6c2-.js.map → install-BEHp7Mo-.js.map} +1 -1
  76. package/dist/install.js +1 -1
  77. package/dist/{lab-DLwRl_Ql.js → lab-D61eaX6f.js} +136 -148
  78. package/dist/lab-D61eaX6f.js.map +1 -0
  79. package/dist/lab.js +4 -3
  80. package/dist/{records-BzTcxekG.js → records-D4aQXyZu.js} +647 -389
  81. package/dist/records-D4aQXyZu.js.map +1 -0
  82. package/dist/{runtime-D6gVat6r.js → runtime-q-R0CNLh.js} +417 -54
  83. package/dist/runtime-q-R0CNLh.js.map +1 -0
  84. package/dist/runtime.d.ts +1 -1
  85. package/dist/runtime.js +7 -7
  86. package/dist/{shell-5ju97nOS.js → shell-6CGFvUUw.js} +10 -5
  87. package/dist/{shell-5ju97nOS.js.map → shell-6CGFvUUw.js.map} +1 -1
  88. package/dist/shell.d.ts +1 -0
  89. package/dist/shell.js +6 -6
  90. package/dist/stores/index.d.ts +1 -1
  91. package/dist/stores/index.js +2 -2
  92. package/dist/stores/settings.d.ts +4 -12
  93. package/dist/styles.css +2753 -2101
  94. package/dist/types/componentWorkflowTypes.d.ts +2 -0
  95. package/dist/types/components.d.ts +2 -0
  96. package/dist/types/generated/platformContext.d.ts +1 -0
  97. package/dist/types/generated-ui.d.ts +4 -0
  98. package/dist/types/index.d.ts +1 -1
  99. package/dist/types/jobs.d.ts +9 -0
  100. package/dist/types/platform.d.ts +1 -1
  101. package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-uFIz6Yv8.js} +75 -5
  102. package/dist/useDropdownState-uFIz6Yv8.js.map +1 -0
  103. package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-QEFoq4tf.js} +48 -6
  104. package/dist/useExperimentSamples-QEFoq4tf.js.map +1 -0
  105. package/dist/{useListReorder-CcbEYxX-.js → useListReorder-DsuzwWGS.js} +219 -437
  106. package/dist/useListReorder-DsuzwWGS.js.map +1 -0
  107. package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-KpZ4iJ6o.js} +85 -81
  108. package/dist/useRackEditor-KpZ4iJ6o.js.map +1 -0
  109. package/dist/useRealtime-B58Lo-Tm.js +508 -0
  110. package/dist/useRealtime-B58Lo-Tm.js.map +1 -0
  111. package/dist/useRequest-BuDmW8Jc.js +215 -0
  112. package/dist/useRequest-BuDmW8Jc.js.map +1 -0
  113. package/dist/utils/time.d.ts +7 -0
  114. package/package.json +3 -2
  115. package/src/__stories__/experiment-helpers.ts +3 -3
  116. package/src/__tests__/components/ActionMenu.test.ts +2 -2
  117. package/src/__tests__/components/AppTopBar.test.ts +257 -3
  118. package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
  119. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  120. package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
  121. package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
  122. package/src/__tests__/components/BaseButton.test.ts +19 -0
  123. package/src/__tests__/components/BaseModal.test.ts +13 -0
  124. package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
  125. package/src/__tests__/components/BaseSelect.test.ts +2 -1
  126. package/src/__tests__/components/BatchProgressList.test.ts +16 -0
  127. package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
  128. package/src/__tests__/components/ChartContainer.test.ts +11 -0
  129. package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
  130. package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
  131. package/src/__tests__/components/DatePicker.test.ts +21 -0
  132. package/src/__tests__/components/DatePicker.time.test.ts +2 -2
  133. package/src/__tests__/components/EmptyState.test.ts +1 -1
  134. package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
  135. package/src/__tests__/components/ExperimentSelectorModal.test.ts +153 -14
  136. package/src/__tests__/components/FloatingPanelsInModal.test.ts +94 -0
  137. package/src/__tests__/components/GeneratedPluginView.test.ts +23 -2
  138. package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
  139. package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
  140. package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
  141. package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
  142. package/src/__tests__/components/SampleSelector.test.ts +33 -8
  143. package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
  144. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  145. package/src/__tests__/components/StepWizard.test.ts +11 -0
  146. package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
  147. package/src/__tests__/components/deprecationTags.test.ts +1 -1
  148. package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
  149. package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
  150. package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
  151. package/src/__tests__/composables/useFileImport.test.ts +36 -0
  152. package/src/__tests__/composables/useFloatingPanel.test.ts +68 -0
  153. package/src/__tests__/composables/useJobCenter.test.ts +262 -3
  154. package/src/__tests__/composables/useOnboarding.test.ts +317 -0
  155. package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
  156. package/src/__tests__/fixtures/table-import/cells.xlsx +0 -0
  157. package/src/__tests__/fixtures/table-import/samples.xlsx +0 -0
  158. package/src/__tests__/stores/settings.test.ts +21 -21
  159. package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
  160. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  161. package/src/__tests__/styles/cssTokens.test.ts +6 -3
  162. package/src/__tests__/styles/menusShellRefresh.test.ts +22 -12
  163. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  164. package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
  165. package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
  166. package/src/__tests__/utils/time.test.ts +18 -1
  167. package/src/components/ActionMenu.vue +6 -37
  168. package/src/components/AdductText.story.vue +7 -0
  169. package/src/components/AdductText.vue +1 -1
  170. package/src/components/AlertBox.story.vue +2 -2
  171. package/src/components/AlertBox.vue +18 -16
  172. package/src/components/AppSidebar.story.vue +0 -28
  173. package/src/components/AppTopBar.onboarding.story.vue +69 -0
  174. package/src/components/AppTopBar.story.vue +105 -15
  175. package/src/components/AppTopBar.vue +248 -122
  176. package/src/components/ArtifactSaveDialog.story.vue +23 -0
  177. package/src/components/ArtifactSaveDialog.vue +102 -12
  178. package/src/components/AuditTrail.story.vue +2 -1
  179. package/src/components/AuditTrail.vue +2 -21
  180. package/src/components/Avatar.vue +10 -14
  181. package/src/components/BaseButton.vue +16 -2
  182. package/src/components/BaseModal.vue +2 -1
  183. package/src/components/BaseSelect.multiple.story.vue +13 -2
  184. package/src/components/BaseSelect.vue +4 -3
  185. package/src/components/BatchProgressList.vue +35 -25
  186. package/src/components/ChartContainer.story.vue +2 -1
  187. package/src/components/ChartContainer.vue +8 -6
  188. package/src/components/ConfirmDialog.story.vue +1 -1
  189. package/src/components/EmptyState.vue +1 -1
  190. package/src/components/ExperimentPopover.story.vue +165 -53
  191. package/src/components/ExperimentPopover.vue +169 -187
  192. package/src/components/ExperimentSelectorModal.story.vue +73 -31
  193. package/src/components/ExperimentSelectorModal.vue +144 -111
  194. package/src/components/FormField.story.vue +8 -48
  195. package/src/components/GeneratedPluginView.vue +11 -10
  196. package/src/components/GeneratedResultRenderer.vue +3 -4
  197. package/src/components/InstrumentStateBadge.vue +1 -1
  198. package/src/components/JobsStatusTray.story.vue +97 -43
  199. package/src/components/JobsStatusTray.vue +287 -290
  200. package/src/components/LayoutResizeHandle.story.vue +65 -4
  201. package/src/components/LoadingSpinner.vue +1 -1
  202. package/src/components/NumberInput.vue +3 -6
  203. package/src/components/PluginIcon.story.vue +2 -10
  204. package/src/components/PluginIcon.vue +2 -2
  205. package/src/components/PluginWorkspaceView.props.ts +3 -0
  206. package/src/components/PluginWorkspaceView.story.vue +1 -1
  207. package/src/components/PluginWorkspaceView.vue +17 -0
  208. package/src/components/RuntimeUpdateNotice.vue +1 -1
  209. package/src/components/SampleSelector.story.vue +22 -7
  210. package/src/components/SampleSelector.vue +34 -37
  211. package/src/components/SampleSelectorGroupNode.vue +1 -1
  212. package/src/components/SectionCard.story.vue +35 -2
  213. package/src/components/SequenceProgressBar.story.vue +9 -0
  214. package/src/components/SequenceProgressBar.vue +6 -1
  215. package/src/components/SettingsModal.schema.ts +1 -1
  216. package/src/components/SettingsModal.vue +9 -14
  217. package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
  218. package/src/components/SmartGroupManual.story.vue +1 -1
  219. package/src/components/StepWizard.story.vue +33 -0
  220. package/src/components/StepWizard.vue +8 -1
  221. package/src/components/Tooltip.vue +9 -32
  222. package/src/components/WellPlate.story.vue +3 -1
  223. package/src/components/WellPlate.vue +7 -0
  224. package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
  225. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  226. package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
  227. package/src/components/internal/DatePickerDateInternal.vue +23 -85
  228. package/src/components/internal/DatePickerDateTimeInternal.vue +10 -14
  229. package/src/components/internal/DatePickerTimeInternal.vue +13 -9
  230. package/src/components/internal/NumberUnitInputInternal.vue +4 -18
  231. package/src/components/internal/OnboardingLayerInternal.vue +173 -0
  232. package/src/components/internal/ResourcePickerListInternal.vue +45 -85
  233. package/src/components/internal/SelectMultipleInternal.vue +187 -65
  234. package/src/components/internal/SelectSearchableInternal.vue +8 -4
  235. package/src/components/internal/WellEditPopupInternal.vue +11 -22
  236. package/src/components/internal/WorkspaceShellInternal.vue +12 -0
  237. package/src/composables/createClient.ts +2 -0
  238. package/src/composables/index.ts +1 -0
  239. package/src/composables/pluginIdentity.ts +31 -0
  240. package/src/composables/pluginWorkspaceModel.ts +2 -2
  241. package/src/composables/useAppExperiment.ts +20 -0
  242. package/src/composables/useCalendarGrid.ts +4 -3
  243. package/src/composables/useExperimentSelector.ts +77 -31
  244. package/src/composables/useFileImport.ts +51 -1
  245. package/src/composables/useFloatingPanel.ts +107 -0
  246. package/src/composables/useJobCenter.ts +188 -6
  247. package/src/composables/useOnboarding.ts +465 -0
  248. package/src/composables/usePluginWorkspace.ts +1 -1
  249. package/src/data.ts +1 -0
  250. package/src/runtime.ts +2 -1
  251. package/src/shell.ts +17 -0
  252. package/src/stores/index.ts +0 -2
  253. package/src/stores/settings.ts +20 -50
  254. package/src/styles/components/action-menu.css +1 -1
  255. package/src/styles/components/adduct-text.css +13 -5
  256. package/src/styles/components/alert-box.css +39 -58
  257. package/src/styles/components/app-layout.css +10 -6
  258. package/src/styles/components/app-page-selector.css +121 -44
  259. package/src/styles/components/app-pill-nav.css +11 -12
  260. package/src/styles/components/app-sidebar.css +9 -18
  261. package/src/styles/components/app-top-bar.css +219 -55
  262. package/src/styles/components/artifact-save-dialog.css +153 -2
  263. package/src/styles/components/audit-trail.css +16 -19
  264. package/src/styles/components/avatar.css +6 -4
  265. package/src/styles/components/batch-progress-list.css +38 -36
  266. package/src/styles/components/button.css +36 -59
  267. package/src/styles/components/calendar.css +12 -12
  268. package/src/styles/components/chart-container.css +34 -23
  269. package/src/styles/components/checkbox.css +2 -12
  270. package/src/styles/components/collapsible-card.css +27 -29
  271. package/src/styles/components/confirm-dialog.css +13 -14
  272. package/src/styles/components/dataframe.css +13 -5
  273. package/src/styles/components/date-picker.css +84 -94
  274. package/src/styles/components/datetime-picker.css +35 -47
  275. package/src/styles/components/divider.css +20 -20
  276. package/src/styles/components/dose-calculator.css +3 -3
  277. package/src/styles/components/empty-state.css +20 -17
  278. package/src/styles/components/experiment-code-badge.css +2 -0
  279. package/src/styles/components/experiment-popover.css +174 -329
  280. package/src/styles/components/experiment-selector-modal.css +88 -56
  281. package/src/styles/components/file-picker.css +3 -3
  282. package/src/styles/components/file-uploader.css +38 -49
  283. package/src/styles/components/form-builder.css +3 -3
  284. package/src/styles/components/formula-input.css +1 -1
  285. package/src/styles/components/icon-button.css +18 -24
  286. package/src/styles/components/input.css +5 -4
  287. package/src/styles/components/instrument-monitor.css +13 -15
  288. package/src/styles/components/jobs-status-tray.css +140 -296
  289. package/src/styles/components/layout-resize-handle.css +59 -16
  290. package/src/styles/components/modal.css +5 -7
  291. package/src/styles/components/molecule-input.css +2 -2
  292. package/src/styles/components/multi-select.css +65 -117
  293. package/src/styles/components/number-input.css +26 -19
  294. package/src/styles/components/onboarding.css +368 -0
  295. package/src/styles/components/pill.css +3 -2
  296. package/src/styles/components/plate-editor.css +0 -1
  297. package/src/styles/components/plugin-icon.css +26 -23
  298. package/src/styles/components/popover.css +2 -2
  299. package/src/styles/components/presence-avatars.css +1 -1
  300. package/src/styles/components/progress-bar.css +3 -3
  301. package/src/styles/components/protocol-step-editor.css +1 -3
  302. package/src/styles/components/resource-card.css +2 -2
  303. package/src/styles/components/resource-picker-list.css +6 -57
  304. package/src/styles/components/sample-hierarchy-tree.css +4 -4
  305. package/src/styles/components/sample-selector.css +138 -79
  306. package/src/styles/components/schedule-calendar.css +8 -8
  307. package/src/styles/components/searchable-select.css +15 -19
  308. package/src/styles/components/section-card.css +54 -49
  309. package/src/styles/components/segmented-control.css +18 -15
  310. package/src/styles/components/select.css +3 -3
  311. package/src/styles/components/sequence-input.css +2 -2
  312. package/src/styles/components/sequence-progress-bar.css +17 -8
  313. package/src/styles/components/settings-modal.css +7 -2
  314. package/src/styles/components/smart-group.css +18 -18
  315. package/src/styles/components/step-wizard.css +52 -16
  316. package/src/styles/components/tabs.css +2 -2
  317. package/src/styles/components/textarea.css +3 -3
  318. package/src/styles/components/time-picker.css +37 -25
  319. package/src/styles/components/toast.css +13 -11
  320. package/src/styles/components/toggle.css +1 -11
  321. package/src/styles/components/tooltip.css +12 -11
  322. package/src/styles/components/unit-input.css +9 -8
  323. package/src/styles/components/well-edit-popup.css +2 -2
  324. package/src/styles/components/well-plate.css +9 -2
  325. package/src/styles/index.css +1 -0
  326. package/src/styles/variables.css +247 -78
  327. package/src/types/componentWorkflowTypes.ts +2 -0
  328. package/src/types/components.ts +2 -0
  329. package/src/types/generated/platformContext.ts +1 -0
  330. package/src/types/generated-ui.ts +4 -0
  331. package/src/types/index.ts +1 -0
  332. package/src/types/jobs.ts +10 -0
  333. package/src/types/platform.ts +1 -1
  334. package/src/utils/time.ts +21 -0
  335. package/dist/ActionMenu-CScINahU.js.map +0 -1
  336. package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
  337. package/dist/BaseModal-DfRIuVoj.js.map +0 -1
  338. package/dist/ExperimentPopover-C4sGw-is.js +0 -359
  339. package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
  340. package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
  341. package/dist/SettingsModal-CSLE31yg.js.map +0 -1
  342. package/dist/data-C2PwI_dn.js.map +0 -1
  343. package/dist/experiment-43OJtH7R.js.map +0 -1
  344. package/dist/lab-DLwRl_Ql.js.map +0 -1
  345. package/dist/records-BzTcxekG.js.map +0 -1
  346. package/dist/runtime-D6gVat6r.js.map +0 -1
  347. package/dist/useExperimentSamples-CxcnxZ8h.js.map +0 -1
  348. package/dist/useListReorder-CcbEYxX-.js.map +0 -1
  349. package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
  350. package/dist/useRealtime-PalKue84.js +0 -696
  351. package/dist/useRealtime-PalKue84.js.map +0 -1
  352. package/dist/useRequest-D5JDfsgZ.js +0 -76
  353. package/dist/useRequest-D5JDfsgZ.js.map +0 -1
@@ -3,15 +3,20 @@ import { ref } from 'vue'
3
3
  import LayoutResizeHandle from './LayoutResizeHandle.vue'
4
4
 
5
5
  const width = ref(320)
6
+ const gapWidth = ref(320)
7
+ const edgeWidth = ref(280)
8
+ const height = ref(50)
9
+
10
+ const panel = 'background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 0.75rem;'
11
+ const caption = 'margin: 0 0 0.5rem; font: 0.75rem var(--font-mono); color: var(--text-secondary);'
6
12
  </script>
7
13
 
8
14
  <template>
9
15
  <Story title="Layout/LayoutResizeHandle">
10
16
  <Variant title="Keyboard splitter">
17
+ <!-- Directly between two panels, the handle is the gutter. -->
11
18
  <div style="display: flex; height: 16rem; padding: 2rem;">
12
- <div :style="{ width: `${width}px`, background: 'var(--bg-secondary)', border: '1px solid var(--border-color)' }">
13
- Panel width: {{ width }}px
14
- </div>
19
+ <div :style="`${panel} width: ${width}px;`">Panel width: {{ width }}px</div>
15
20
  <LayoutResizeHandle
16
21
  v-model="width"
17
22
  orientation="vertical"
@@ -19,7 +24,63 @@ const width = ref(320)
19
24
  :min="240"
20
25
  :max="480"
21
26
  />
22
- <div style="flex: 1; background: var(--bg-tertiary);" />
27
+ <div :style="`${panel} flex: 1;`" />
28
+ </div>
29
+ </Variant>
30
+
31
+ <Variant title="Gaps and edge">
32
+ <div style="display: grid; gap: 1.5rem; padding: 2rem;">
33
+ <div data-gap="flex-8">
34
+ <p :style="caption">flex, 8px gutter (compact), handle between the panels</p>
35
+ <div style="display: flex; height: 8rem; --mint-gutter: 0.5rem;">
36
+ <div :style="`${panel} width: ${gapWidth}px;`">Left panel</div>
37
+ <LayoutResizeHandle v-model="gapWidth" orientation="vertical" label="Resize left panel (8px)" :min="200" :max="480" />
38
+ <div :style="`${panel} flex: 1;`">Right panel</div>
39
+ </div>
40
+ </div>
41
+ <div data-gap="wrapper-12">
42
+ <p :style="caption">flex, 12px gutter, handle in a gutter-wide wrapper</p>
43
+ <div style="display: flex; height: 8rem; --mint-gutter: 0.75rem;">
44
+ <div :style="`${panel} width: ${gapWidth}px;`">Left panel</div>
45
+ <div style="display: flex; justify-content: center; flex-shrink: 0; width: var(--mint-gutter);">
46
+ <LayoutResizeHandle v-model="gapWidth" orientation="vertical" label="Resize left panel (12px)" :min="200" :max="480" />
47
+ </div>
48
+ <div :style="`${panel} flex: 1;`">Right panel</div>
49
+ </div>
50
+ </div>
51
+ <div data-gap="grid-8">
52
+ <p :style="caption">grid, 8px track</p>
53
+ <div :style="`display: grid; grid-template-columns: ${gapWidth}px 0.5rem 1fr; height: 8rem;`">
54
+ <div :style="panel">Left panel</div>
55
+ <LayoutResizeHandle
56
+ v-model="gapWidth"
57
+ orientation="vertical"
58
+ label="Resize left panel (grid)"
59
+ :min="200"
60
+ :max="480"
61
+ style="--mint-layout-resize-gap: 0.5rem;"
62
+ />
63
+ <div :style="panel">Right panel</div>
64
+ </div>
65
+ </div>
66
+ <div data-gap="edge">
67
+ <p :style="caption">edge="right", 12px gutter</p>
68
+ <div style="display: flex; gap: var(--mint-gutter); height: 8rem; --mint-gutter: 0.75rem;">
69
+ <aside :style="`${panel} position: relative; width: ${edgeWidth}px;`">
70
+ Sidebar
71
+ <LayoutResizeHandle v-model="edgeWidth" orientation="vertical" edge="right" label="Resize sidebar" :min="200" :max="480" />
72
+ </aside>
73
+ <div :style="`${panel} flex: 1;`">Main</div>
74
+ </div>
75
+ </div>
76
+ <div data-gap="horizontal">
77
+ <p :style="caption">horizontal, 8px gutter</p>
78
+ <div style="display: flex; flex-direction: column; height: 14rem; --mint-gutter: 0.5rem;">
79
+ <div :style="`${panel} flex: 0 0 ${height}%;`">Top panel</div>
80
+ <LayoutResizeHandle v-model="height" orientation="horizontal" label="Resize top panel" :min="20" :max="80" :step="1" />
81
+ <div :style="`${panel} flex: 1;`">Bottom panel</div>
82
+ </div>
83
+ </div>
23
84
  </div>
24
85
  </Variant>
25
86
  </Story>
@@ -40,7 +40,7 @@ withDefaults(defineProps<Props>(), {
40
40
  <path
41
41
  style="opacity: 0.75"
42
42
  fill="currentColor"
43
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
43
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
44
44
  />
45
45
  </svg>
46
46
  <span class="mint-spinner__label">{{ label }}</span>
@@ -10,6 +10,7 @@
10
10
  * ```
11
11
  */
12
12
  import { computed, onBeforeUnmount, useAttrs, type StyleValue } from 'vue'
13
+ import { ChevronDown, ChevronUp } from 'lucide-vue-next'
13
14
  import type { UnitOption } from '../types'
14
15
  import NumberUnitInputInternal from './internal/NumberUnitInputInternal.vue'
15
16
 
@@ -287,9 +288,7 @@ function handleScrubStart(event: PointerEvent) {
287
288
  class="mint-number-input__stepper mint-number-input__stepper--down"
288
289
  @click="decrement"
289
290
  >
290
- <svg viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
291
- <path d="M2 5h6" />
292
- </svg>
291
+ <ChevronDown :size="12" :stroke-width="2.25" />
293
292
  </button>
294
293
  <button
295
294
  type="button"
@@ -299,9 +298,7 @@ function handleScrubStart(event: PointerEvent) {
299
298
  class="mint-number-input__stepper mint-number-input__stepper--up"
300
299
  @click="increment"
301
300
  >
302
- <svg viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
303
- <path d="M5 2v6" /><path d="M2 5h6" />
304
- </svg>
301
+ <ChevronUp :size="12" :stroke-width="2.25" />
305
302
  </button>
306
303
  </div>
307
304
  </div>
@@ -52,8 +52,8 @@ function initState() {
52
52
  <HstText v-model="state.icon" title="icon" />
53
53
  <HstSelect v-model="state.size" title="size" :options="['sm', 'md', 'topbar', 'lg']" />
54
54
  <HstSelect v-model="state.variant" title="variant" :options="['solid', 'tinted']" />
55
- <HstSelect v-model="state.tone" title="tone" :options="['', 'neutral', 'primary', 'cta', 'success', 'warning', 'error', 'info']" />
56
- <HstText v-model="state.color" title="color (CSS color)" />
55
+ <HstSelect v-model="state.tone" title="tone (deprecated, no effect; removed in 1.5)" :options="['', 'neutral', 'primary', 'cta', 'success', 'warning', 'error', 'info']" />
56
+ <HstText v-model="state.color" title="color (deprecated, no effect; removed in 1.5)" />
57
57
  </template>
58
58
  </Variant>
59
59
 
@@ -94,13 +94,5 @@ function initState() {
94
94
  <PluginIcon :icon="SAMPLE_STRUCTURED" size="lg" />
95
95
  </div>
96
96
  </Variant>
97
-
98
- <Variant title="Tone overrides">
99
- <div style="padding: 2rem; display: flex; gap: 1rem; align-items: center;">
100
- <PluginIcon :icon="SAMPLE_PATH" size="lg" variant="solid" color="#0EA5E9" />
101
- <PluginIcon :icon="SAMPLE_PATH" size="lg" variant="solid" color="#F97316" />
102
- <PluginIcon :icon="SAMPLE_PATH" size="lg" variant="solid" color="#22C55E" />
103
- </div>
104
- </Variant>
105
97
  </Story>
106
98
  </template>
@@ -18,9 +18,9 @@ interface Props {
18
18
  icon?: string
19
19
  size?: 'sm' | 'md' | 'topbar' | 'lg'
20
20
  variant?: 'solid' | 'tinted'
21
- /** Semantic color; without it the chip uses the primary color. */
21
+ /** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the tone has no visible effect. Removed in 1.5. */
22
22
  tone?: Tone
23
- /** Custom chip color (any CSS color, such as a plugin's manifest color); replaces the tone. */
23
+ /** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the color has no visible effect. Removed in 1.5. */
24
24
  color?: string
25
25
  }
26
26
 
@@ -4,6 +4,7 @@ import type {
4
4
  PillNavOption,
5
5
  PluginWorkspaceViewSpec,
6
6
  } from '../types'
7
+ import type { JobState } from '../types/jobs'
7
8
  import type {
8
9
  ControlComponentBinding,
9
10
  ControlComponentBindingsById,
@@ -46,6 +47,8 @@ export interface PluginWorkspaceViewEmits {
46
47
  'section-action': [sectionId: string, actionId: string]
47
48
  'form-submit': [sectionId: string, values: Record<string, unknown>]
48
49
  'form-cancel': [sectionId: string]
50
+ /** A job row in the jobs tray, or the just-completed job on the top-bar chip, was chosen. */
51
+ 'job-select': [job: JobState]
49
52
  }
50
53
 
51
54
  /** Typed `emit` function shape produced by `defineEmits<PluginWorkspaceViewEmits>()`. */
@@ -274,7 +274,7 @@ async function saveDoseDesign() {
274
274
  </PluginWorkspaceView>
275
275
  <p
276
276
  v-if="lastExperimentEvent"
277
- style="padding: 0.75rem 1rem; margin: 0; font-family: 'Fira Code', monospace; font-size: 0.75rem; color: var(--text-muted);"
277
+ style="padding: 0.75rem 1rem; margin: 0; font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-muted);"
278
278
  >
279
279
  Last shell event: {{ lastExperimentEvent }}
280
280
  </p>
@@ -20,9 +20,12 @@ import type {
20
20
  PillNavItem,
21
21
  PillNavOption,
22
22
  } from '../types'
23
+ import type { JobState } from '../types/jobs'
23
24
  import { useAppExperiment } from '../composables/useAppExperiment'
25
+ import { useJobCenter } from '../composables/useJobCenter'
24
26
  import { usePluginWorkspace } from '../composables/usePluginWorkspace'
25
27
  import AppToastContainer from './AppToastContainer.vue'
28
+ import JobsStatusTray from './JobsStatusTray.vue'
26
29
  import WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'
27
30
  import WorkspaceShellInternal from './internal/WorkspaceShellInternal.vue'
28
31
  import WorkspaceSidebarInternal from './internal/WorkspaceSidebarInternal.vue'
@@ -76,6 +79,14 @@ if (props.spec.experiment) {
76
79
  })
77
80
  }
78
81
 
82
+ // The job center is setup-time structure too: no `jobs`, no jobs control.
83
+ const jobs = props.spec.jobs
84
+ const jobCenter = jobs ? useJobCenter({ source: jobs }) : null
85
+
86
+ function handleJobSelect(job: JobState) {
87
+ emit('job-select', job)
88
+ }
89
+
79
90
  const {
80
91
  shell,
81
92
  sidebar,
@@ -105,6 +116,11 @@ function handleFormCancel(sectionId: string) {
105
116
  <template>
106
117
  <WorkspaceShellInternal
107
118
  :shell="shell"
119
+ :job="jobCenter ? jobCenter.topBarJob.value : undefined"
120
+ :jobs-done="jobCenter?.completedCount.value"
121
+ :jobs-open="jobCenter?.isOpen.value"
122
+ :jobs-panel-id="jobCenter?.panelId"
123
+ @job-click="jobCenter?.handleTopBarClick(handleJobSelect)"
108
124
  @pill-select="handlePillSelect"
109
125
  @pill-option-select="(option: PillNavOption, item: PillNavItem) => emit('pill-option-select', option, item)"
110
126
  @settings-values-change="emit('settings-values-change', $event)"
@@ -158,6 +174,7 @@ function handleFormCancel(sectionId: string) {
158
174
  </template>
159
175
  </WorkspaceControlsInternal>
160
176
  <AppToastContainer v-if="spec.toasts !== false" />
177
+ <JobsStatusTray v-if="jobCenter" :center="jobCenter" @select="handleJobSelect" />
161
178
  </template>
162
179
  </WorkspaceShellInternal>
163
180
  </template>
@@ -41,7 +41,7 @@ const emit = defineEmits<{
41
41
 
42
42
  .mint-runtime-update button {
43
43
  padding: 5px 9px;
44
- color: #fff;
44
+ color: var(--text-on-accent);
45
45
  background: var(--color-primary);
46
46
  border: 0;
47
47
  border-radius: 6px;
@@ -21,6 +21,13 @@ const mockGroups: SampleGroup[] = [
21
21
  { name: 'Vehicle', color: '#F59E0B', samples: ['Vehicle_Rep1', 'Vehicle_Rep2', 'Vehicle_Rep3'] },
22
22
  ]
23
23
 
24
+ // 1024 selected runs in two groups: the long count must not push the actions out.
25
+ const manyRuns = Array.from({ length: 1024 }, (_, i) => `Run_${String(i + 1).padStart(4, '0')}`)
26
+ const manyGroups: SampleGroup[] = [
27
+ { name: 'Batch A', color: '#3B82F6', samples: manyRuns.slice(0, 512) },
28
+ { name: 'Batch B', color: '#10B981', samples: manyRuns.slice(512) },
29
+ ]
30
+
24
31
  const manualSamples = [
25
32
  'Pt001_TumorA_d7_rep1',
26
33
  'Pt001_TumorA_d7_rep1_reseq2024',
@@ -135,13 +142,21 @@ function handleSmartGroup(result: AutoGroupResult, state: { groups: SampleGroup[
135
142
  </div>
136
143
  </Variant>
137
144
 
138
- <Variant title="Narrow Action Bar">
139
- <div style="padding: 2rem; width: 320px;">
140
- <SampleSelector
141
- :model-value="['Control_Rep1']"
142
- :samples="mockSamples"
143
- :groups="mockGroups"
144
- />
145
+ <Variant title="Narrow Header">
146
+ <!-- At 17.625rem of header content width and below, the grouping button shows only its icon and the count shortens. -->
147
+ <div style="display: flex; align-items: flex-start; gap: 2rem; padding: 2rem;">
148
+ <div v-for="width in [220, 300, 340]" :key="width" :data-width="width" :style="{ width: `${width}px` }">
149
+ <p style="margin: 0 0 0.5rem; font: 0.75rem var(--font-mono); color: var(--text-secondary);">{{ width }}px</p>
150
+ <SampleSelector
151
+ :model-value="['Control_Rep1']"
152
+ :samples="mockSamples"
153
+ :groups="mockGroups"
154
+ />
155
+ </div>
156
+ <div data-width="320-long" style="width: 320px; height: 22rem;">
157
+ <p style="margin: 0 0 0.5rem; font: 0.75rem var(--font-mono); color: var(--text-secondary);">320px, 1024 selected</p>
158
+ <SampleSelector :model-value="manyRuns" :samples="manyRuns" :groups="manyGroups" />
159
+ </div>
145
160
  </div>
146
161
  </Variant>
147
162
 
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  /** Interactive sample list with drag-and-drop group assignment, color labeling, and smart-group support. */
3
3
  import { ref, computed } from 'vue'
4
+ import { Layers, RotateCcw, WandSparkles } from 'lucide-vue-next'
4
5
  import BaseButton from './BaseButton.vue'
5
6
  import BaseCheckbox from './BaseCheckbox.vue'
6
7
  import BaseInput from './BaseInput.vue'
@@ -255,6 +256,8 @@ function addNewGroup() {
255
256
  newGroupName.value = ''
256
257
  }
257
258
 
259
+ const groupingLabel = computed(() => (props.enableSmartGroup ? 'Smart group' : 'Group'))
260
+
258
261
  /** Selected samples among the resolved list, for the select-all header. */
259
262
  const selectedCount = computed(() => resolvedSamples.value.filter(s => props.modelValue.includes(s)).length)
260
263
 
@@ -268,6 +271,36 @@ defineExpose({ handleSmartGroupApply })
268
271
 
269
272
  <template>
270
273
  <div class="mint-sample-selector">
274
+ <div class="mint-sample-selector__header">
275
+ <span class="mint-sample-selector__title">Samples</span>
276
+ <!-- A narrow selector shows "N sel."; screen readers keep "N selected". -->
277
+ <span class="mint-sample-selector__selected">
278
+ <span class="mint-sample-selector__selected-full">{{ selectedCount }} selected</span>
279
+ <span class="mint-sample-selector__selected-short" aria-hidden="true">{{ selectedCount }} sel.</span>
280
+ </span>
281
+ <div v-if="!isPlaceholderState && enableGrouping" class="mint-sample-selector__header-actions">
282
+ <BaseButton
283
+ variant="ghost"
284
+ size="sm"
285
+ :icon="enableSmartGroup ? WandSparkles : Layers"
286
+ :title="groupingLabel"
287
+ class="mint-sample-selector__action-btn mint-sample-selector__group-btn"
288
+ @click="openGroupingModal(groupingActionMode)"
289
+ >
290
+ {{ groupingLabel }}
291
+ </BaseButton>
292
+ <BaseButton
293
+ v-if="internalGroups.length > 0"
294
+ variant="ghost"
295
+ size="sm"
296
+ :icon="RotateCcw"
297
+ label="Clear all groups"
298
+ class="mint-sample-selector__action-btn"
299
+ @click="clearGroups"
300
+ />
301
+ </div>
302
+ </div>
303
+
271
304
  <div v-if="error" class="mint-sample-selector__state">
272
305
  <slot name="error" :error="error">
273
306
  <DataStateInternal state="error" size="sm" :title="error" />
@@ -302,43 +335,7 @@ defineExpose({ handleSmartGroupApply })
302
335
  @update:model-value="toggleSelectAll"
303
336
  />
304
337
  <span class="mint-sample-selector__select-all-label">All samples</span>
305
- <span class="mint-sample-selector__select-all-count">{{ selectedCount }} / {{ resolvedSamples.length }}</span>
306
- </div>
307
-
308
- <!-- Action Buttons Row -->
309
- <div v-if="!isPlaceholderState && enableGrouping" class="mint-sample-selector__actions">
310
- <div class="mint-sample-selector__actions-row">
311
- <!-- Grouping Button -->
312
- <BaseButton
313
- :variant="enableSmartGroup && groupingEnabled ? 'primary' : 'secondary'"
314
- size="sm"
315
- :disabled="resolvedSamples.length === 0"
316
- class="mint-sample-selector__action-btn"
317
- @click="openGroupingModal(groupingActionMode)"
318
- >
319
- <svg v-if="enableSmartGroup" class="mint-sample-selector__action-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
320
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
321
- </svg>
322
- <svg v-else class="mint-sample-selector__action-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
323
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3 3 7.5l9 4.5 9-4.5L12 3ZM3 12l9 4.5 9-4.5M3 16.5l9 4.5 9-4.5" />
324
- </svg>
325
- <span class="mint-sample-selector__action-label">Grouping</span>
326
- </BaseButton>
327
-
328
- <!-- Reset Button -->
329
- <BaseButton
330
- variant="ghost"
331
- size="sm"
332
- :disabled="internalGroups.length === 0"
333
- class="mint-sample-selector__action-btn mint-sample-selector__action-btn--reset"
334
- @click="clearGroups"
335
- title="Clear all groups"
336
- >
337
- <svg class="mint-sample-selector__action-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
338
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
339
- </svg>
340
- </BaseButton>
341
- </div>
338
+ <span class="mint-sample-selector__select-all-count">{{ selectedCount }}/{{ resolvedSamples.length }}</span>
342
339
  </div>
343
340
 
344
341
  <!-- Grouped View -->
@@ -153,7 +153,7 @@ function onHeaderKeydown(event: KeyboardEvent) {
153
153
  :title="node.group?.name ?? node.label"
154
154
  >{{ node.label }}</span>
155
155
 
156
- <span class="mint-sample-selector__count-badge">{{ selectedCount }} / {{ node.allSamples.length }}</span>
156
+ <span class="mint-sample-selector__count-badge">{{ selectedCount }}/{{ node.allSamples.length }}</span>
157
157
 
158
158
  <button
159
159
  type="button"
@@ -46,7 +46,7 @@ function initPlayground() {
46
46
  >
47
47
  <span style="flex: 1; min-width: 0">
48
48
  <span style="display: block; font-size: 0.8125rem; font-weight: 500; color: var(--text-primary)">{{ e.name }}</span>
49
- <span style="display: block; font-family: 'Fira Code', monospace; font-size: 0.65625rem; color: var(--text-muted)">{{ e.code }}</span>
49
+ <span style="display: block; font-family: var(--font-mono); font-size: 0.65625rem; color: var(--text-muted)">{{ e.code }}</span>
50
50
  </span>
51
51
  <span style="flex-shrink: 0; font-size: 0.71875rem; color: var(--text-muted)">{{ e.updated }}</span>
52
52
  </a>
@@ -107,6 +107,39 @@ function initPlayground() {
107
107
  </div>
108
108
  </Variant>
109
109
 
110
+ <Variant title="Rows with lead">
111
+ <div style="padding: 2rem; max-width: 600px; display: grid; gap: 1rem;">
112
+ <SectionCard title="Experiments" count="3 total" :icon="flaskIcon" accent="experiment" uppercase>
113
+ <div class="mint-section-card__rows">
114
+ <a v-for="e in experiments" :key="e.code" href="#" class="mint-section-card__row">
115
+ <span class="mint-section-card__row-lead">
116
+ <span style="width: 0.375rem; height: 0.375rem; border-radius: 50%; background: var(--mint-success)" />
117
+ </span>
118
+ <span style="flex: 1; min-width: 0">
119
+ <span style="display: block; font-size: 0.8125rem; font-weight: 500; color: var(--text-primary)">{{ e.name }}</span>
120
+ <span style="display: block; font-family: var(--font-mono); font-size: 0.65625rem; color: var(--text-muted)">{{ e.code }}</span>
121
+ </span>
122
+ <span style="flex-shrink: 0; font-size: 0.71875rem; color: var(--text-muted)">{{ e.updated }}</span>
123
+ </a>
124
+ </div>
125
+ </SectionCard>
126
+ <SectionCard title="Projects" count="2 active" :icon="folderIcon" accent="project" uppercase>
127
+ <div class="mint-section-card__rows">
128
+ <a href="#" class="mint-section-card__row">
129
+ <span class="mint-section-card__row-lead" aria-hidden="true" />
130
+ <span style="flex: 1; font-size: 0.8125rem; font-weight: 500; color: var(--text-primary)">Hypoxia metabolic rewiring</span>
131
+ <span style="font-size: 0.71875rem; color: var(--text-muted)">12 experiments</span>
132
+ </a>
133
+ <a href="#" class="mint-section-card__row">
134
+ <span class="mint-section-card__row-lead" aria-hidden="true" />
135
+ <span style="flex: 1; font-size: 0.8125rem; font-weight: 500; color: var(--text-primary)">Serine one-carbon flux</span>
136
+ <span style="font-size: 0.71875rem; color: var(--text-muted)">7 experiments</span>
137
+ </a>
138
+ </div>
139
+ </SectionCard>
140
+ </div>
141
+ </Variant>
142
+
110
143
  <Variant title="Detail card with footer">
111
144
  <div style="padding: 2rem; max-width: 600px;">
112
145
  <SectionCard title="Analysis artifacts" :count="4" divider="light">
@@ -139,7 +172,7 @@ function initPlayground() {
139
172
  <div class="mint-section-card__rows">
140
173
  <div v-for="n in 20" :key="n" class="mint-section-card__row">
141
174
  <span style="flex: 1; font-size: 0.8125rem; color: var(--text-primary)">Row {{ n }}</span>
142
- <span style="font-family: 'Fira Code', monospace; font-size: 0.71875rem; color: var(--text-muted)">MM-2026-{{ String(n).padStart(3, '0') }}</span>
175
+ <span style="font-family: var(--font-mono); font-size: 0.71875rem; color: var(--text-muted)">MM-2026-{{ String(n).padStart(3, '0') }}</span>
143
176
  </div>
144
177
  </div>
145
178
  <template #footer>
@@ -40,6 +40,7 @@ function initState() {
40
40
  showEta: true,
41
41
  showRemaining: true,
42
42
  label: 'samples',
43
+ failed: 0,
43
44
  }
44
45
  }
45
46
  </script>
@@ -60,6 +61,7 @@ function initState() {
60
61
  :label="state.label"
61
62
  :show-eta="state.showEta"
62
63
  :show-remaining="state.showRemaining"
64
+ :failed="state.failed"
63
65
  />
64
66
  </div>
65
67
  </template>
@@ -69,6 +71,7 @@ function initState() {
69
71
  <HstNumber v-model="state.total" title="Total samples" />
70
72
  <HstNumber v-model="state.remaining" title="Remaining (s)" />
71
73
  <HstText v-model="state.label" title="Unit label" />
74
+ <HstNumber v-model="state.failed" title="Failed" />
72
75
  <HstCheckbox v-model="state.compact" title="Compact" />
73
76
  <HstCheckbox v-model="state.showEta" title="Show ETA" />
74
77
  <HstCheckbox v-model="state.showRemaining" title="Show remaining" />
@@ -81,6 +84,12 @@ function initState() {
81
84
  </div>
82
85
  </Variant>
83
86
 
87
+ <Variant title="With failures">
88
+ <div style="padding: 2rem; max-width: 600px;">
89
+ <SequenceProgressBar :progress="running" :failed="1" />
90
+ </div>
91
+ </Variant>
92
+
84
93
  <Variant title="Compact (no footer)">
85
94
  <!-- Compact drops the remaining/ETA row for dense instrument tables. -->
86
95
  <div style="padding: 2rem; max-width: 600px;">
@@ -15,6 +15,8 @@ interface Props {
15
15
  label?: string
16
16
  showEta?: boolean
17
17
  showRemaining?: boolean
18
+ /** Failed injections so far; shown as "N failed" in the head when above 0. */
19
+ failed?: number
18
20
  }
19
21
 
20
22
  const props = withDefaults(defineProps<Props>(), {
@@ -22,6 +24,7 @@ const props = withDefaults(defineProps<Props>(), {
22
24
  label: 'samples',
23
25
  showEta: true,
24
26
  showRemaining: true,
27
+ failed: 0,
25
28
  })
26
29
 
27
30
  const percent = computed(() => sequenceProgressPercent(props.progress))
@@ -37,8 +40,10 @@ const hasFooter = computed(() => {
37
40
  <div class="mint-sequence-progress">
38
41
  <div class="mint-sequence-progress__header">
39
42
  <span class="mint-sequence-progress__label">
40
- {{ progress.current_sample }} / {{ progress.total_samples }} {{ label }}
43
+ <span class="mint-sequence-progress__count">{{ progress.current_sample }} / {{ progress.total_samples }}</span>
44
+ {{ label }}
41
45
  </span>
46
+ <span v-if="failed > 0" class="mint-sequence-progress__failed">{{ failed }} failed</span>
42
47
  <span class="mint-sequence-progress__percent">{{ percent }}%</span>
43
48
  </div>
44
49
 
@@ -17,7 +17,7 @@ export const APPEARANCE_TAB: SettingsTab = {
17
17
  // Heroicons "swatch" — the built-in tab sits beside plugin tabs that all
18
18
  // carry icons, so it needs one of its own to keep the rail consistent.
19
19
  icon: '<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.098 19.902a3.75 3.75 0 0 0 5.304 0l6.401-6.402M6.75 21A3.75 3.75 0 0 1 3 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 0 0 3.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008Z"></path></svg>',
20
- description: 'Theme, color palette, and table density',
20
+ description: 'Theme, color palette, and density',
21
21
  }
22
22
 
23
23
  // Map settings groups onto the form-builder's flat-section shape.
@@ -358,13 +358,8 @@ const themeOptions: { value: ThemeMode; label: string; halves: ('light' | 'dark'
358
358
  { value: 'system', label: 'System', halves: ['light', 'dark'] },
359
359
  ]
360
360
 
361
- /** Five stops along the palette's primary → accent hue arc (shortest way round), as in the board. */
362
- function paletteSwatches(key: ColorPalette): string[] {
363
- const [from, to] = colorPalettes[key].hues
364
- const span = ((to - from + 540) % 360) - 180
365
- const tone = key === 'pastel' ? '60% 72%' : '65% 48%'
366
- return Array.from({ length: 5 }, (_, i) => `hsl(${Math.round(from + (span * i) / 4)} ${tone})`)
367
- }
361
+ /** Accent tokens a palette swatch shows; `data-palette` on the strip resolves them per palette. */
362
+ const paletteSwatchTokens = ['--color-primary', '--color-primary-hover', '--color-primary-soft', '--color-primary-border']
368
363
 
369
364
  const densityPreviewRows = [
370
365
  ['S-0012', '2.41', '12.5'],
@@ -562,7 +557,7 @@ function canShowForCurrentUser(item: AccessControlled): boolean {
562
557
  <div class="mint-settings-modal__setting">
563
558
  <div class="mint-settings-modal__setting-text">
564
559
  <span class="mint-settings-modal__setting-label">Color palette</span>
565
- <span class="mint-settings-modal__setting-hint">Primary and accent hues across the interface</span>
560
+ <span class="mint-settings-modal__setting-hint">Accent colour across the interface</span>
566
561
  </div>
567
562
  <div class="mint-settings-modal__palettes">
568
563
  <button
@@ -573,12 +568,12 @@ function canShowForCurrentUser(item: AccessControlled): boolean {
573
568
  :class="['mint-settings-modal__palette', { 'mint-settings-modal__palette--active': settings.colorPalette === key }]"
574
569
  @click="settings.colorPalette = key as ColorPalette"
575
570
  >
576
- <span class="mint-settings-modal__swatches" aria-hidden="true">
571
+ <span class="mint-settings-modal__swatches" :data-palette="key" aria-hidden="true">
577
572
  <span
578
- v-for="color in paletteSwatches(key as ColorPalette)"
579
- :key="color"
573
+ v-for="token in paletteSwatchTokens"
574
+ :key="token"
580
575
  class="mint-settings-modal__swatch"
581
- :style="{ backgroundColor: color }"
576
+ :style="{ backgroundColor: `var(${token})` }"
582
577
  />
583
578
  </span>
584
579
  <span class="mint-settings-modal__palette-name">{{ palette.name }}</span>
@@ -591,8 +586,8 @@ function canShowForCurrentUser(item: AccessControlled): boolean {
591
586
 
592
587
  <div class="mint-settings-modal__setting mint-settings-modal__setting--inline">
593
588
  <div class="mint-settings-modal__setting-text">
594
- <span class="mint-settings-modal__setting-label">Table density</span>
595
- <span class="mint-settings-modal__setting-hint">Adjusts row height in data tables</span>
589
+ <span class="mint-settings-modal__setting-label">Density</span>
590
+ <span class="mint-settings-modal__setting-hint">Adjusts control and table row height</span>
596
591
  </div>
597
592
  <SegmentedControl
598
593
  :model-value="settings.tableDensity"
@@ -51,7 +51,7 @@ import type { FieldRecipeApplyPayload } from './SmartGroup.types'
51
51
  }
52
52
  .sg-story__log {
53
53
  margin: 0;
54
- font-family: 'Fira Code', monospace;
54
+ font-family: var(--font-mono);
55
55
  font-size: 0.8125rem;
56
56
  color: var(--text-secondary, #64748b);
57
57
  }
@@ -48,7 +48,7 @@ import type { ManualDonePayload } from './SmartGroup.types'
48
48
  }
49
49
  .sg-story__log {
50
50
  margin: 0;
51
- font-family: 'Fira Code', monospace;
51
+ font-family: var(--font-mono);
52
52
  font-size: 0.8125rem;
53
53
  color: var(--text-secondary, #64748b);
54
54
  }