@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.
- package/README.md +14 -3
- package/dist/{ActionMenu-CScINahU.js → AlertBox-DwgNTEqf.js} +40 -209
- package/dist/AlertBox-DwgNTEqf.js.map +1 -0
- package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-CZZaxni0.js} +1249 -239
- package/dist/AppSidebar-CZZaxni0.js.map +1 -0
- package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CjWoxAD1.js} +2 -2
- package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CjWoxAD1.js.map} +1 -1
- package/dist/ExperimentPopover-DujiuQIO.js +337 -0
- package/dist/ExperimentPopover-DujiuQIO.js.map +1 -0
- package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-B4j4eUOJ.js} +244 -211
- package/dist/ExperimentSelectorModal-B4j4eUOJ.js.map +1 -0
- package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-DyUPH3I5.js} +2 -2
- package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-DyUPH3I5.js.map} +1 -1
- package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-D2MOOtuO.js} +28 -27
- package/dist/SettingsModal-D2MOOtuO.js.map +1 -0
- package/dist/__stories__/experiment-helpers.d.ts +10 -0
- package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
- package/dist/__tests__/components/FloatingPanelsInModal.test.d.ts +1 -0
- package/dist/__tests__/composables/useFloatingPanel.test.d.ts +1 -0
- package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
- package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
- package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/AppTopBar.vue.d.ts +20 -5
- package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
- package/dist/components/AuditTrail.vue.d.ts +1 -1
- package/dist/components/BaseButton.vue.d.ts +4 -2
- package/dist/components/BaseSelect.vue.d.ts +2 -2
- package/dist/components/ChartContainer.vue.d.ts +2 -0
- package/dist/components/DatePicker.vue.d.ts +1 -1
- package/dist/components/ExperimentPopover.vue.d.ts +18 -0
- package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -5
- package/dist/components/FilePicker.vue.d.ts +1 -1
- package/dist/components/FileUploader.vue.d.ts +2 -2
- package/dist/components/JobsStatusTray.vue.d.ts +15 -4
- package/dist/components/PluginIcon.vue.d.ts +2 -2
- package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
- package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
- package/dist/components/SampleSelector.vue.d.ts +6 -6
- package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -3
- package/dist/components/StepWizard.vue.d.ts +3 -0
- package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
- package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
- package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +3 -3
- package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
- package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
- package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
- package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
- package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
- package/dist/composables/createClient.d.ts +2 -0
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/pluginIdentity.d.ts +24 -0
- package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
- package/dist/composables/useAppExperiment.d.ts +8 -0
- package/dist/composables/useCalendarGrid.d.ts +1 -1
- package/dist/composables/useExperimentSelector.d.ts +6 -2
- package/dist/composables/useFileImport.d.ts +7 -0
- package/dist/composables/useFloatingPanel.d.ts +29 -0
- package/dist/composables/useJobCenter.d.ts +41 -3
- package/dist/composables/useOnboarding.d.ts +119 -0
- package/dist/composables/usePlatform.d.ts +1 -0
- package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-Bsg0t5Ab.js} +2 -2
- package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-Bsg0t5Ab.js.map} +1 -1
- package/dist/{data-C2PwI_dn.js → data-Boeh4uPI.js} +180 -125
- package/dist/data-Boeh4uPI.js.map +1 -0
- package/dist/data.d.ts +1 -1
- package/dist/data.js +9 -9
- package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
- package/dist/experiment-DyO54FQB.js.map +1 -0
- package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-DCn2QKG7.js} +3 -3
- package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-DCn2QKG7.js.map} +1 -1
- package/dist/index.js +20 -20
- package/dist/{install-DAID6c2-.js → install-BEHp7Mo-.js} +15 -14
- package/dist/{install-DAID6c2-.js.map → install-BEHp7Mo-.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-DLwRl_Ql.js → lab-D61eaX6f.js} +136 -148
- package/dist/lab-D61eaX6f.js.map +1 -0
- package/dist/lab.js +4 -3
- package/dist/{records-BzTcxekG.js → records-D4aQXyZu.js} +647 -389
- package/dist/records-D4aQXyZu.js.map +1 -0
- package/dist/{runtime-D6gVat6r.js → runtime-q-R0CNLh.js} +417 -54
- package/dist/runtime-q-R0CNLh.js.map +1 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +7 -7
- package/dist/{shell-5ju97nOS.js → shell-6CGFvUUw.js} +10 -5
- package/dist/{shell-5ju97nOS.js.map → shell-6CGFvUUw.js.map} +1 -1
- package/dist/shell.d.ts +1 -0
- package/dist/shell.js +6 -6
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js +2 -2
- package/dist/stores/settings.d.ts +4 -12
- package/dist/styles.css +2753 -2101
- package/dist/types/componentWorkflowTypes.d.ts +2 -0
- package/dist/types/components.d.ts +2 -0
- package/dist/types/generated/platformContext.d.ts +1 -0
- package/dist/types/generated-ui.d.ts +4 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/jobs.d.ts +9 -0
- package/dist/types/platform.d.ts +1 -1
- package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-uFIz6Yv8.js} +75 -5
- package/dist/useDropdownState-uFIz6Yv8.js.map +1 -0
- package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-QEFoq4tf.js} +48 -6
- package/dist/useExperimentSamples-QEFoq4tf.js.map +1 -0
- package/dist/{useListReorder-CcbEYxX-.js → useListReorder-DsuzwWGS.js} +219 -437
- package/dist/useListReorder-DsuzwWGS.js.map +1 -0
- package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-KpZ4iJ6o.js} +85 -81
- package/dist/useRackEditor-KpZ4iJ6o.js.map +1 -0
- package/dist/useRealtime-B58Lo-Tm.js +508 -0
- package/dist/useRealtime-B58Lo-Tm.js.map +1 -0
- package/dist/useRequest-BuDmW8Jc.js +215 -0
- package/dist/useRequest-BuDmW8Jc.js.map +1 -0
- package/dist/utils/time.d.ts +7 -0
- package/package.json +3 -2
- package/src/__stories__/experiment-helpers.ts +3 -3
- package/src/__tests__/components/ActionMenu.test.ts +2 -2
- package/src/__tests__/components/AppTopBar.test.ts +257 -3
- package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
- package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
- package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
- package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
- package/src/__tests__/components/BaseButton.test.ts +19 -0
- package/src/__tests__/components/BaseModal.test.ts +13 -0
- package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
- package/src/__tests__/components/BaseSelect.test.ts +2 -1
- package/src/__tests__/components/BatchProgressList.test.ts +16 -0
- package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
- package/src/__tests__/components/ChartContainer.test.ts +11 -0
- package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
- package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
- package/src/__tests__/components/DatePicker.test.ts +21 -0
- package/src/__tests__/components/DatePicker.time.test.ts +2 -2
- package/src/__tests__/components/EmptyState.test.ts +1 -1
- package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
- package/src/__tests__/components/ExperimentSelectorModal.test.ts +153 -14
- package/src/__tests__/components/FloatingPanelsInModal.test.ts +94 -0
- package/src/__tests__/components/GeneratedPluginView.test.ts +23 -2
- package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
- package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
- package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
- package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
- package/src/__tests__/components/SampleSelector.test.ts +33 -8
- package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
- package/src/__tests__/components/SettingsModal.test.ts +9 -2
- package/src/__tests__/components/StepWizard.test.ts +11 -0
- package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
- package/src/__tests__/components/deprecationTags.test.ts +1 -1
- package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
- package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
- package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
- package/src/__tests__/composables/useFileImport.test.ts +36 -0
- package/src/__tests__/composables/useFloatingPanel.test.ts +68 -0
- package/src/__tests__/composables/useJobCenter.test.ts +262 -3
- package/src/__tests__/composables/useOnboarding.test.ts +317 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
- package/src/__tests__/fixtures/table-import/cells.xlsx +0 -0
- package/src/__tests__/fixtures/table-import/samples.xlsx +0 -0
- package/src/__tests__/stores/settings.test.ts +21 -21
- package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
- package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
- package/src/__tests__/styles/cssTokens.test.ts +6 -3
- package/src/__tests__/styles/menusShellRefresh.test.ts +22 -12
- package/src/__tests__/styles/paletteTokens.test.ts +44 -0
- package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
- package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
- package/src/__tests__/utils/time.test.ts +18 -1
- package/src/components/ActionMenu.vue +6 -37
- package/src/components/AdductText.story.vue +7 -0
- package/src/components/AdductText.vue +1 -1
- package/src/components/AlertBox.story.vue +2 -2
- package/src/components/AlertBox.vue +18 -16
- package/src/components/AppSidebar.story.vue +0 -28
- package/src/components/AppTopBar.onboarding.story.vue +69 -0
- package/src/components/AppTopBar.story.vue +105 -15
- package/src/components/AppTopBar.vue +248 -122
- package/src/components/ArtifactSaveDialog.story.vue +23 -0
- package/src/components/ArtifactSaveDialog.vue +102 -12
- package/src/components/AuditTrail.story.vue +2 -1
- package/src/components/AuditTrail.vue +2 -21
- package/src/components/Avatar.vue +10 -14
- package/src/components/BaseButton.vue +16 -2
- package/src/components/BaseModal.vue +2 -1
- package/src/components/BaseSelect.multiple.story.vue +13 -2
- package/src/components/BaseSelect.vue +4 -3
- package/src/components/BatchProgressList.vue +35 -25
- package/src/components/ChartContainer.story.vue +2 -1
- package/src/components/ChartContainer.vue +8 -6
- package/src/components/ConfirmDialog.story.vue +1 -1
- package/src/components/EmptyState.vue +1 -1
- package/src/components/ExperimentPopover.story.vue +165 -53
- package/src/components/ExperimentPopover.vue +169 -187
- package/src/components/ExperimentSelectorModal.story.vue +73 -31
- package/src/components/ExperimentSelectorModal.vue +144 -111
- package/src/components/FormField.story.vue +8 -48
- package/src/components/GeneratedPluginView.vue +11 -10
- package/src/components/GeneratedResultRenderer.vue +3 -4
- package/src/components/InstrumentStateBadge.vue +1 -1
- package/src/components/JobsStatusTray.story.vue +97 -43
- package/src/components/JobsStatusTray.vue +287 -290
- package/src/components/LayoutResizeHandle.story.vue +65 -4
- package/src/components/LoadingSpinner.vue +1 -1
- package/src/components/NumberInput.vue +3 -6
- package/src/components/PluginIcon.story.vue +2 -10
- package/src/components/PluginIcon.vue +2 -2
- package/src/components/PluginWorkspaceView.props.ts +3 -0
- package/src/components/PluginWorkspaceView.story.vue +1 -1
- package/src/components/PluginWorkspaceView.vue +17 -0
- package/src/components/RuntimeUpdateNotice.vue +1 -1
- package/src/components/SampleSelector.story.vue +22 -7
- package/src/components/SampleSelector.vue +34 -37
- package/src/components/SampleSelectorGroupNode.vue +1 -1
- package/src/components/SectionCard.story.vue +35 -2
- package/src/components/SequenceProgressBar.story.vue +9 -0
- package/src/components/SequenceProgressBar.vue +6 -1
- package/src/components/SettingsModal.schema.ts +1 -1
- package/src/components/SettingsModal.vue +9 -14
- package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
- package/src/components/SmartGroupManual.story.vue +1 -1
- package/src/components/StepWizard.story.vue +33 -0
- package/src/components/StepWizard.vue +8 -1
- package/src/components/Tooltip.vue +9 -32
- package/src/components/WellPlate.story.vue +3 -1
- package/src/components/WellPlate.vue +7 -0
- package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
- package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
- package/src/components/internal/DatePickerDateInternal.vue +23 -85
- package/src/components/internal/DatePickerDateTimeInternal.vue +10 -14
- package/src/components/internal/DatePickerTimeInternal.vue +13 -9
- package/src/components/internal/NumberUnitInputInternal.vue +4 -18
- package/src/components/internal/OnboardingLayerInternal.vue +173 -0
- package/src/components/internal/ResourcePickerListInternal.vue +45 -85
- package/src/components/internal/SelectMultipleInternal.vue +187 -65
- package/src/components/internal/SelectSearchableInternal.vue +8 -4
- package/src/components/internal/WellEditPopupInternal.vue +11 -22
- package/src/components/internal/WorkspaceShellInternal.vue +12 -0
- package/src/composables/createClient.ts +2 -0
- package/src/composables/index.ts +1 -0
- package/src/composables/pluginIdentity.ts +31 -0
- package/src/composables/pluginWorkspaceModel.ts +2 -2
- package/src/composables/useAppExperiment.ts +20 -0
- package/src/composables/useCalendarGrid.ts +4 -3
- package/src/composables/useExperimentSelector.ts +77 -31
- package/src/composables/useFileImport.ts +51 -1
- package/src/composables/useFloatingPanel.ts +107 -0
- package/src/composables/useJobCenter.ts +188 -6
- package/src/composables/useOnboarding.ts +465 -0
- package/src/composables/usePluginWorkspace.ts +1 -1
- package/src/data.ts +1 -0
- package/src/runtime.ts +2 -1
- package/src/shell.ts +17 -0
- package/src/stores/index.ts +0 -2
- package/src/stores/settings.ts +20 -50
- package/src/styles/components/action-menu.css +1 -1
- package/src/styles/components/adduct-text.css +13 -5
- package/src/styles/components/alert-box.css +39 -58
- package/src/styles/components/app-layout.css +10 -6
- package/src/styles/components/app-page-selector.css +121 -44
- package/src/styles/components/app-pill-nav.css +11 -12
- package/src/styles/components/app-sidebar.css +9 -18
- package/src/styles/components/app-top-bar.css +219 -55
- package/src/styles/components/artifact-save-dialog.css +153 -2
- package/src/styles/components/audit-trail.css +16 -19
- package/src/styles/components/avatar.css +6 -4
- package/src/styles/components/batch-progress-list.css +38 -36
- package/src/styles/components/button.css +36 -59
- package/src/styles/components/calendar.css +12 -12
- package/src/styles/components/chart-container.css +34 -23
- package/src/styles/components/checkbox.css +2 -12
- package/src/styles/components/collapsible-card.css +27 -29
- package/src/styles/components/confirm-dialog.css +13 -14
- package/src/styles/components/dataframe.css +13 -5
- package/src/styles/components/date-picker.css +84 -94
- package/src/styles/components/datetime-picker.css +35 -47
- package/src/styles/components/divider.css +20 -20
- package/src/styles/components/dose-calculator.css +3 -3
- package/src/styles/components/empty-state.css +20 -17
- package/src/styles/components/experiment-code-badge.css +2 -0
- package/src/styles/components/experiment-popover.css +174 -329
- package/src/styles/components/experiment-selector-modal.css +88 -56
- package/src/styles/components/file-picker.css +3 -3
- package/src/styles/components/file-uploader.css +38 -49
- package/src/styles/components/form-builder.css +3 -3
- package/src/styles/components/formula-input.css +1 -1
- package/src/styles/components/icon-button.css +18 -24
- package/src/styles/components/input.css +5 -4
- package/src/styles/components/instrument-monitor.css +13 -15
- package/src/styles/components/jobs-status-tray.css +140 -296
- package/src/styles/components/layout-resize-handle.css +59 -16
- package/src/styles/components/modal.css +5 -7
- package/src/styles/components/molecule-input.css +2 -2
- package/src/styles/components/multi-select.css +65 -117
- package/src/styles/components/number-input.css +26 -19
- package/src/styles/components/onboarding.css +368 -0
- package/src/styles/components/pill.css +3 -2
- package/src/styles/components/plate-editor.css +0 -1
- package/src/styles/components/plugin-icon.css +26 -23
- package/src/styles/components/popover.css +2 -2
- package/src/styles/components/presence-avatars.css +1 -1
- package/src/styles/components/progress-bar.css +3 -3
- package/src/styles/components/protocol-step-editor.css +1 -3
- package/src/styles/components/resource-card.css +2 -2
- package/src/styles/components/resource-picker-list.css +6 -57
- package/src/styles/components/sample-hierarchy-tree.css +4 -4
- package/src/styles/components/sample-selector.css +138 -79
- package/src/styles/components/schedule-calendar.css +8 -8
- package/src/styles/components/searchable-select.css +15 -19
- package/src/styles/components/section-card.css +54 -49
- package/src/styles/components/segmented-control.css +18 -15
- package/src/styles/components/select.css +3 -3
- package/src/styles/components/sequence-input.css +2 -2
- package/src/styles/components/sequence-progress-bar.css +17 -8
- package/src/styles/components/settings-modal.css +7 -2
- package/src/styles/components/smart-group.css +18 -18
- package/src/styles/components/step-wizard.css +52 -16
- package/src/styles/components/tabs.css +2 -2
- package/src/styles/components/textarea.css +3 -3
- package/src/styles/components/time-picker.css +37 -25
- package/src/styles/components/toast.css +13 -11
- package/src/styles/components/toggle.css +1 -11
- package/src/styles/components/tooltip.css +12 -11
- package/src/styles/components/unit-input.css +9 -8
- package/src/styles/components/well-edit-popup.css +2 -2
- package/src/styles/components/well-plate.css +9 -2
- package/src/styles/index.css +1 -0
- package/src/styles/variables.css +247 -78
- package/src/types/componentWorkflowTypes.ts +2 -0
- package/src/types/components.ts +2 -0
- package/src/types/generated/platformContext.ts +1 -0
- package/src/types/generated-ui.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/jobs.ts +10 -0
- package/src/types/platform.ts +1 -1
- package/src/utils/time.ts +21 -0
- package/dist/ActionMenu-CScINahU.js.map +0 -1
- package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
- package/dist/BaseModal-DfRIuVoj.js.map +0 -1
- package/dist/ExperimentPopover-C4sGw-is.js +0 -359
- package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
- package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
- package/dist/SettingsModal-CSLE31yg.js.map +0 -1
- package/dist/data-C2PwI_dn.js.map +0 -1
- package/dist/experiment-43OJtH7R.js.map +0 -1
- package/dist/lab-DLwRl_Ql.js.map +0 -1
- package/dist/records-BzTcxekG.js.map +0 -1
- package/dist/runtime-D6gVat6r.js.map +0 -1
- package/dist/useExperimentSamples-CxcnxZ8h.js.map +0 -1
- package/dist/useListReorder-CcbEYxX-.js.map +0 -1
- package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
- package/dist/useRealtime-PalKue84.js +0 -696
- package/dist/useRealtime-PalKue84.js.map +0 -1
- package/dist/useRequest-D5JDfsgZ.js +0 -76
- package/dist/useRequest-D5JDfsgZ.js.map +0 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
|
|
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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
!!
|
|
107
|
-
!!
|
|
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
|
-
!!
|
|
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-
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
<
|
|
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="
|
|
218
|
+
v-if="isIntegrated"
|
|
158
219
|
class="mint-topbar__plugin-icon"
|
|
159
|
-
:icon="
|
|
160
|
-
:color="pluginIcon.color"
|
|
220
|
+
:icon="plugin?.icon"
|
|
161
221
|
size="topbar"
|
|
162
222
|
variant="solid"
|
|
163
223
|
/>
|
|
164
|
-
<slot v-else name="
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
</
|
|
238
|
+
</slot>
|
|
170
239
|
</slot>
|
|
171
|
-
</
|
|
172
|
-
</
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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="
|
|
249
|
+
v-if="isIntegrated"
|
|
191
250
|
class="mint-topbar__plugin-icon"
|
|
192
|
-
:icon="
|
|
193
|
-
:color="pluginIcon.color"
|
|
251
|
+
:icon="plugin?.icon"
|
|
194
252
|
size="topbar"
|
|
195
253
|
variant="solid"
|
|
196
254
|
/>
|
|
197
|
-
<slot v-else name="
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
</
|
|
269
|
+
</slot>
|
|
203
270
|
</slot>
|
|
204
|
-
</
|
|
205
|
-
</
|
|
206
|
-
|
|
207
|
-
|
|
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="
|
|
276
|
+
v-if="isIntegrated"
|
|
220
277
|
class="mint-topbar__plugin-icon"
|
|
221
|
-
:icon="
|
|
222
|
-
:color="pluginIcon.color"
|
|
278
|
+
:icon="plugin?.icon"
|
|
223
279
|
size="topbar"
|
|
224
280
|
variant="solid"
|
|
225
281
|
/>
|
|
226
|
-
<slot v-else name="
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
</
|
|
296
|
+
</slot>
|
|
232
297
|
</slot>
|
|
233
|
-
</
|
|
234
|
-
</
|
|
235
|
-
</
|
|
236
|
-
</div>
|
|
298
|
+
</span>
|
|
299
|
+
</template>
|
|
300
|
+
</div>
|
|
237
301
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
332
|
+
<span v-else-if="hasTitleOnly" class="mint-topbar__title-only">{{ titleText }}</span>
|
|
266
333
|
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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"
|