@morscherlab/mint-sdk 1.4.0-beta.2 → 1.4.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -3
- package/dist/{ActionMenu-CScINahU.js → AlertBox-CzLg0UaL.js} +40 -209
- package/dist/AlertBox-CzLg0UaL.js.map +1 -0
- package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-6oTT-gPO.js} +1249 -239
- package/dist/AppSidebar-6oTT-gPO.js.map +1 -0
- package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CSls2Nuv.js} +2 -2
- package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CSls2Nuv.js.map} +1 -1
- package/dist/ExperimentPopover-9l4QZlvQ.js +337 -0
- package/dist/ExperimentPopover-9l4QZlvQ.js.map +1 -0
- package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-pR5fK3pA.js} +244 -211
- package/dist/ExperimentSelectorModal-pR5fK3pA.js.map +1 -0
- package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-CJ7EAmOq.js} +2 -2
- package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-CJ7EAmOq.js.map} +1 -1
- package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-Dyitgzfp.js} +28 -27
- package/dist/SettingsModal-Dyitgzfp.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__/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 +1 -1
- 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 +1 -1
- 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/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-DCUOx8ll.js} +2 -2
- package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-DCUOx8ll.js.map} +1 -1
- package/dist/{data-C2PwI_dn.js → data-DBnmeBZX.js} +179 -125
- package/dist/data-DBnmeBZX.js.map +1 -0
- package/dist/data.js +8 -8
- package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
- package/dist/experiment-DyO54FQB.js.map +1 -0
- package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-BFrKpHAH.js} +3 -3
- package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-BFrKpHAH.js.map} +1 -1
- package/dist/index.js +20 -20
- package/dist/{install-DAID6c2-.js → install-qjELyNwc.js} +15 -14
- package/dist/{install-DAID6c2-.js.map → install-qjELyNwc.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-DLwRl_Ql.js → lab-UyTbokQC.js} +136 -148
- package/dist/lab-UyTbokQC.js.map +1 -0
- package/dist/lab.js +4 -3
- package/dist/{records-BzTcxekG.js → records-CR_pYzIP.js} +533 -335
- package/dist/records-CR_pYzIP.js.map +1 -0
- package/dist/{runtime-D6gVat6r.js → runtime-CoHhBP10.js} +417 -54
- package/dist/runtime-CoHhBP10.js.map +1 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +7 -7
- package/dist/{shell-5ju97nOS.js → shell-BDuZf2zb.js} +10 -5
- package/dist/{shell-5ju97nOS.js.map → shell-BDuZf2zb.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 +2732 -2083
- 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-Bb2N4m40.js} +74 -4
- package/dist/useDropdownState-Bb2N4m40.js.map +1 -0
- package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-Dno1fFMq.js} +4 -4
- package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-Dno1fFMq.js.map} +1 -1
- package/dist/{useListReorder-CcbEYxX-.js → useListReorder-CQ9OCScc.js} +183 -351
- package/dist/useListReorder-CQ9OCScc.js.map +1 -0
- package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-wL3kPrRT.js} +73 -59
- package/dist/useRackEditor-wL3kPrRT.js.map +1 -0
- package/dist/useRealtime-C3whhVvb.js +508 -0
- package/dist/useRealtime-C3whhVvb.js.map +1 -0
- package/dist/useRequest-CDkrXNU7.js +244 -0
- package/dist/useRequest-CDkrXNU7.js.map +1 -0
- package/dist/utils/time.d.ts +7 -0
- package/package.json +1 -1
- package/src/__stories__/experiment-helpers.ts +3 -3
- 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/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/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/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__/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/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/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/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 +16 -40
- package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
- package/src/components/internal/DatePickerTimeInternal.vue +5 -8
- package/src/components/internal/OnboardingLayerInternal.vue +173 -0
- package/src/components/internal/ResourcePickerListInternal.vue +45 -85
- package/src/components/internal/SelectMultipleInternal.vue +182 -65
- package/src/components/internal/SelectSearchableInternal.vue +2 -3
- 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/useJobCenter.ts +188 -6
- package/src/composables/useOnboarding.ts +465 -0
- package/src/composables/usePluginWorkspace.ts +1 -1
- 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/adduct-text.css +13 -5
- package/src/styles/components/alert-box.css +39 -58
- package/src/styles/components/app-layout.css +7 -5
- 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 +80 -92
- package/src/styles/components/datetime-picker.css +31 -43
- 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 +4 -6
- 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 +12 -12
- 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 +36 -21
- package/src/styles/components/toast.css +12 -10
- package/src/styles/components/toggle.css +1 -11
- package/src/styles/components/tooltip.css +10 -9
- package/src/styles/components/unit-input.css +8 -7
- package/src/styles/components/well-plate.css +9 -2
- package/src/styles/index.css +1 -0
- package/src/styles/variables.css +241 -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/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"
|