@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
|
@@ -107,17 +107,6 @@ describe('ResourcePickerListInternal', () => {
|
|
|
107
107
|
expect(wrapper.emitted('update:search')?.[0]).toEqual(['plasma'])
|
|
108
108
|
})
|
|
109
109
|
|
|
110
|
-
it('should head each group with its label and a count', () => {
|
|
111
|
-
const wrapper = setup({ groups: [{ label: 'Recent', items }] })
|
|
112
|
-
expect(wrapper.get('.mint-resource-picker__group').text()).toBe('Recent2')
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should hide the rows of a collapsed group', async () => {
|
|
116
|
-
const wrapper = setup({ groups: [{ label: 'Recent', items }] })
|
|
117
|
-
await wrapper.get('.mint-resource-picker__group').trigger('click')
|
|
118
|
-
expect(wrapper.findAll('[role="option"]')).toHaveLength(0)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
110
|
it('should show skeleton rows while loading', () => {
|
|
122
111
|
expect(setup({ loading: true }).findAll('.mint-resource-picker__skeleton-row')).toHaveLength(4)
|
|
123
112
|
})
|
|
@@ -129,13 +118,4 @@ describe('ResourcePickerListInternal', () => {
|
|
|
129
118
|
it('should show the empty title when there are no items', () => {
|
|
130
119
|
expect(setup({ items: [], emptyTitle: 'Nothing here' }).text()).toContain('Nothing here')
|
|
131
120
|
})
|
|
132
|
-
|
|
133
|
-
it('should leave Enter to a group header while a row is highlighted', async () => {
|
|
134
|
-
const wrapper = setup({ groups: [{ label: 'Recent', items }] })
|
|
135
|
-
await wrapper.findAll('[role="option"]')[0]!.trigger('mouseenter')
|
|
136
|
-
|
|
137
|
-
await wrapper.get('.mint-resource-picker__group').trigger('keydown', { key: 'Enter' })
|
|
138
|
-
|
|
139
|
-
expect(wrapper.emitted('select')).toBeUndefined()
|
|
140
|
-
})
|
|
141
121
|
})
|
|
@@ -97,7 +97,7 @@ describe('SampleSelector', () => {
|
|
|
97
97
|
},
|
|
98
98
|
})
|
|
99
99
|
|
|
100
|
-
expect(wrapper.find('.mint-sample-selector__select-all-count').text()).toBe('0
|
|
100
|
+
expect(wrapper.find('.mint-sample-selector__select-all-count').text()).toBe('0/2')
|
|
101
101
|
expect(wrapper.findAll('.mint-sample-selector__flat-name').map(item => item.text())).toEqual(['S1', 'S2'])
|
|
102
102
|
})
|
|
103
103
|
|
|
@@ -115,9 +115,9 @@ describe('SampleSelector', () => {
|
|
|
115
115
|
},
|
|
116
116
|
})
|
|
117
117
|
|
|
118
|
-
const
|
|
119
|
-
expect(
|
|
120
|
-
expect(wrapper.
|
|
118
|
+
const buttons = wrapper.findAll('.mint-sample-selector__header-actions > .mint-sample-selector__action-btn')
|
|
119
|
+
expect(buttons.map(button => button.text())).toEqual(['Smart group'])
|
|
120
|
+
expect(wrapper.find('.mint-sample-selector__header').text()).toContain('Samples0 selected')
|
|
121
121
|
|
|
122
122
|
await wrapper.findAllComponents({ name: 'BaseButton' })[0].trigger('click')
|
|
123
123
|
|
|
@@ -125,6 +125,26 @@ describe('SampleSelector', () => {
|
|
|
125
125
|
expect(modal.props('initialMode')).toBe('auto')
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
+
it.each([
|
|
129
|
+
[true, 'Smart group'],
|
|
130
|
+
[false, 'Group'],
|
|
131
|
+
])('should keep the grouping label as accessible name and tooltip when smart group is %s', (enableSmartGroup, label) => {
|
|
132
|
+
const wrapper = mount(SampleSelector, {
|
|
133
|
+
props: { samples: ['S1', 'S2'], modelValue: ['S1'], groups: [], enableSmartGroup },
|
|
134
|
+
global: { stubs: { AutoGroupModalInternal: true } },
|
|
135
|
+
})
|
|
136
|
+
const button = wrapper.get('.mint-sample-selector__header-actions > .mint-sample-selector__action-btn')
|
|
137
|
+
const count = wrapper.get('.mint-sample-selector__selected')
|
|
138
|
+
|
|
139
|
+
expect({
|
|
140
|
+
name: button.text(),
|
|
141
|
+
title: button.attributes('title'),
|
|
142
|
+
full: count.get('.mint-sample-selector__selected-full').text(),
|
|
143
|
+
short: count.get('.mint-sample-selector__selected-short').text(),
|
|
144
|
+
shortHidden: count.get('.mint-sample-selector__selected-short').attributes('aria-hidden'),
|
|
145
|
+
}).toEqual({ name: label, title: label, full: '1 selected', short: '1 sel.', shortHidden: 'true' })
|
|
146
|
+
})
|
|
147
|
+
|
|
128
148
|
it('opens the grouping modal in manual mode', async () => {
|
|
129
149
|
const wrapper = mount(SampleSelector, {
|
|
130
150
|
props: {
|
|
@@ -140,8 +160,8 @@ describe('SampleSelector', () => {
|
|
|
140
160
|
},
|
|
141
161
|
})
|
|
142
162
|
|
|
143
|
-
const
|
|
144
|
-
expect(
|
|
163
|
+
const buttons = wrapper.findAll('.mint-sample-selector__header-actions > .mint-sample-selector__action-btn')
|
|
164
|
+
expect(buttons.map(button => button.text())).toEqual(['Group'])
|
|
145
165
|
|
|
146
166
|
await wrapper.findAllComponents({ name: 'BaseButton' })[0].trigger('click')
|
|
147
167
|
|
|
@@ -472,9 +492,14 @@ describe('SampleSelector checkboxes (7c)', () => {
|
|
|
472
492
|
}
|
|
473
493
|
const stubs = { global: { stubs: { AutoGroupModalInternal: true } } }
|
|
474
494
|
|
|
475
|
-
it('should show the mono selected
|
|
495
|
+
it('should show the mono selected/total count when some samples are selected', () => {
|
|
476
496
|
const wrapper = mount(SampleSelector, { props: grouped, ...stubs })
|
|
477
|
-
expect(wrapper.find('.mint-sample-selector__select-all-count').text()).toBe('1
|
|
497
|
+
expect(wrapper.find('.mint-sample-selector__select-all-count').text()).toBe('1/3')
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
it('should offer clear-all-groups in the header when groups exist', () => {
|
|
501
|
+
const wrapper = mount(SampleSelector, { props: { ...grouped, enableGrouping: true }, ...stubs })
|
|
502
|
+
expect(wrapper.find('.mint-sample-selector__header-actions [aria-label="Clear all groups"]').exists()).toBe(true)
|
|
478
503
|
})
|
|
479
504
|
|
|
480
505
|
it('should mark the select-all checkbox mixed when some samples are selected', () => {
|
|
@@ -36,4 +36,16 @@ describe('SequenceProgressBar', () => {
|
|
|
36
36
|
expect(wrapper.get('.mint-sequence-progress__label').text()).toBe('2 / 4 injections')
|
|
37
37
|
expect(wrapper.find('.mint-sequence-progress__footer').exists()).toBe(false)
|
|
38
38
|
})
|
|
39
|
+
|
|
40
|
+
it.each([
|
|
41
|
+
[0, null],
|
|
42
|
+
[2, '2 failed'],
|
|
43
|
+
])('should show the failed count when %i injections failed', (failed, expected) => {
|
|
44
|
+
const wrapper = mount(SequenceProgressBar, {
|
|
45
|
+
props: { failed, progress: { current_sample: 3, total_samples: 6 } },
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const node = wrapper.find('.mint-sequence-progress__failed')
|
|
49
|
+
expect(node.exists() ? node.text() : null).toBe(expected)
|
|
50
|
+
})
|
|
39
51
|
})
|
|
@@ -728,10 +728,17 @@ describe('SettingsModal', () => {
|
|
|
728
728
|
expect(useSettingsStore(pinia).theme).toBe('dark')
|
|
729
729
|
})
|
|
730
730
|
|
|
731
|
-
it('should
|
|
731
|
+
it('should preview each palette with its own tokens when appearance is shown', () => {
|
|
732
732
|
const wrapper = mountSettingsModal({ showAppearance: true })
|
|
733
733
|
|
|
734
|
-
|
|
734
|
+
const strips = wrapper.findAll('.mint-settings-modal__swatches')
|
|
735
|
+
expect(strips.map((strip) => strip.attributes('data-palette'))).toEqual(Object.keys(colorPalettes))
|
|
736
|
+
expect(strips[0].findAll('.mint-settings-modal__swatch').map((swatch) => swatch.attributes('style'))).toEqual([
|
|
737
|
+
'background-color: var(--color-primary);',
|
|
738
|
+
'background-color: var(--color-primary-hover);',
|
|
739
|
+
'background-color: var(--color-primary-soft);',
|
|
740
|
+
'background-color: var(--color-primary-border);',
|
|
741
|
+
])
|
|
735
742
|
})
|
|
736
743
|
|
|
737
744
|
it('should resize the density preview when the density changes', async () => {
|
|
@@ -73,3 +73,14 @@ describe('StepWizard navigation (2c)', () => {
|
|
|
73
73
|
expect(wrapper.find('.mint-wizard__counter').text()).toBe('2 / 2')
|
|
74
74
|
})
|
|
75
75
|
})
|
|
76
|
+
|
|
77
|
+
describe('StepWizard orientation', () => {
|
|
78
|
+
it.each([
|
|
79
|
+
['horizontal', false],
|
|
80
|
+
['vertical', true],
|
|
81
|
+
] as const)('should toggle the vertical modifier when orientation is %s', (orientation, vertical) => {
|
|
82
|
+
const wrapper = mount(StepWizard, { props: { steps, orientation } })
|
|
83
|
+
|
|
84
|
+
expect(wrapper.classes('mint-wizard--vertical')).toBe(vertical)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -28,15 +28,22 @@ describe('WellPlate per-well decoration', () => {
|
|
|
28
28
|
.toEqual(['2px', 'solid', 'var(--mint-warning)'])
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
it(
|
|
31
|
+
it.each([
|
|
32
|
+
['qc', {}, 'Q'],
|
|
33
|
+
['iqc', {}, 'i'],
|
|
34
|
+
['sample', {}, ''],
|
|
35
|
+
['qc', { showWellIds: true }, 'A1'],
|
|
36
|
+
] as const)('should render the %s glyph when the well has no label (spec %o)', (sampleType, spec, text) => {
|
|
32
37
|
const wrapper = mount(WellPlate, {
|
|
33
38
|
props: {
|
|
34
|
-
spec: { format: 6 },
|
|
35
|
-
wells: { A1: { id: 'A1', row: 0, col: 0, state: 'filled', sampleType
|
|
39
|
+
spec: { format: 6, ...spec },
|
|
40
|
+
wells: { A1: { id: 'A1', row: 0, col: 0, state: 'filled', sampleType } },
|
|
36
41
|
},
|
|
37
42
|
})
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
const well = wrapper.findAll('.mint-well-plate__well')[0]
|
|
45
|
+
expect(well.text()).toBe(text)
|
|
46
|
+
expect(well.find('.mint-well-plate__indicator').exists()).toBe(text === 'Q' || text === 'i')
|
|
40
47
|
})
|
|
41
48
|
|
|
42
49
|
it('should draw plain legend swatches when the legend is shown', () => {
|
|
@@ -68,7 +68,7 @@ describe('root exports outside L1 and L2', () => {
|
|
|
68
68
|
|
|
69
69
|
expect(values.sort()).toEqual([
|
|
70
70
|
'defineControlModel', 'defineDataFrame', 'definePluginWorkspaceView', 'downloadBlob',
|
|
71
|
-
'resolvePluginFrontendBase', 'useExperiment', 'usePlatform', 'useRequest', 'useTheme', 'useToast',
|
|
71
|
+
'providePluginIdentity', 'resolvePluginFrontendBase', 'useExperiment', 'usePlatform', 'useRequest', 'useTheme', 'useToast',
|
|
72
72
|
])
|
|
73
73
|
})
|
|
74
74
|
|
|
@@ -490,6 +490,20 @@ describe('useAppExperiment', () => {
|
|
|
490
490
|
expect(state.saveLoading.value).toBe(false)
|
|
491
491
|
})
|
|
492
492
|
|
|
493
|
+
it('should show the refetched update time after a successful save', async () => {
|
|
494
|
+
const store = useExperimentStore()
|
|
495
|
+
useAppExperiment({ onSave: vi.fn().mockResolvedValue('Saved') })
|
|
496
|
+
const state = getState()
|
|
497
|
+
store.select(makeExperiment({ updated_at: '2025-01-01T00:00:00Z' }))
|
|
498
|
+
|
|
499
|
+
const fetch = stubExperimentFetch()
|
|
500
|
+
const saving = state.handleSave()
|
|
501
|
+
fetch.resolveWith(makeExperiment({ updated_at: '2026-10-28T09:30:00Z' }))
|
|
502
|
+
await saving
|
|
503
|
+
|
|
504
|
+
expect(state.popover.value.experimentUpdatedAt).toBe('2026-10-28T09:30:00Z')
|
|
505
|
+
})
|
|
506
|
+
|
|
493
507
|
it('should not set saveSuccessMessage when onSave returns null', async () => {
|
|
494
508
|
const onSave = vi.fn().mockResolvedValue(null)
|
|
495
509
|
useAppExperiment({ onSave })
|
|
@@ -716,8 +730,9 @@ describe('useAppExperiment', () => {
|
|
|
716
730
|
it('exposes live ExperimentPopover props from the provided state', async () => {
|
|
717
731
|
const saveDisabled = ref(false)
|
|
718
732
|
const saveDisabledMessage = ref<string | undefined>('Ready to save')
|
|
733
|
+
const dirty = ref(false)
|
|
719
734
|
const onSave = vi.fn().mockResolvedValue('Saved')
|
|
720
|
-
useAppExperiment({ onSave, saveDisabled, saveDisabledMessage })
|
|
735
|
+
useAppExperiment({ onSave, saveDisabled, saveDisabledMessage, dirty })
|
|
721
736
|
const state = getState()
|
|
722
737
|
|
|
723
738
|
useExperimentStore().select(makeExperiment({
|
|
@@ -725,26 +740,37 @@ describe('useAppExperiment', () => {
|
|
|
725
740
|
name: 'Dose response',
|
|
726
741
|
status: 'ongoing',
|
|
727
742
|
experiment_code: 'EXP-012',
|
|
743
|
+
project: 'legacy-project',
|
|
744
|
+
project_name: 'Hypoxia atlas',
|
|
745
|
+
created_by_user: { id: 3, username: 'jdoe', first_name: 'Jane', last_name: 'Doe' },
|
|
746
|
+
updated_at: '2026-10-28T10:00:00Z',
|
|
728
747
|
}))
|
|
729
748
|
|
|
730
749
|
expect(state.popover.value).toMatchObject({
|
|
731
750
|
experimentName: 'Dose response',
|
|
732
751
|
experimentCode: 'EXP-012',
|
|
733
752
|
experimentStatus: 'ongoing',
|
|
753
|
+
experimentId: 12,
|
|
754
|
+
experimentProject: 'Hypoxia atlas',
|
|
755
|
+
experimentOwner: 'Jane Doe',
|
|
756
|
+
experimentUpdatedAt: '2026-10-28T10:00:00Z',
|
|
734
757
|
isResolving: false,
|
|
735
758
|
showSave: true,
|
|
736
759
|
showDetach: true,
|
|
737
760
|
saveDisabled: false,
|
|
738
761
|
saveDisabledMessage: 'Ready to save',
|
|
739
762
|
saveLoading: false,
|
|
763
|
+
dirty: false,
|
|
740
764
|
})
|
|
741
765
|
expect(state.popover.value.error).toBeUndefined()
|
|
742
766
|
|
|
743
767
|
saveDisabled.value = true
|
|
744
768
|
saveDisabledMessage.value = 'Locked'
|
|
769
|
+
dirty.value = true
|
|
745
770
|
|
|
746
771
|
expect(state.popover.value.saveDisabled).toBe(true)
|
|
747
772
|
expect(state.popover.value.saveDisabledMessage).toBe('Locked')
|
|
773
|
+
expect(state.popover.value.dirty).toBe(true)
|
|
748
774
|
|
|
749
775
|
await state.handleSave()
|
|
750
776
|
|
|
@@ -2,14 +2,16 @@ import { describe, expect, it } from 'vitest'
|
|
|
2
2
|
import { useCalendarGrid } from '../../composables/useCalendarGrid'
|
|
3
3
|
|
|
4
4
|
describe('useCalendarGrid', () => {
|
|
5
|
-
it('builds a stable 42-day month grid with previous and next month padding', () => {
|
|
5
|
+
it('builds a stable Monday-first 42-day month grid with previous and next month padding', () => {
|
|
6
6
|
const calendar = useCalendarGrid()
|
|
7
7
|
calendar.setCurrentMonthFromDate(new Date('2026-05-07T12:00:00'))
|
|
8
8
|
|
|
9
|
-
expect(calendar.weekDays).toEqual(['
|
|
9
|
+
expect(calendar.weekDays).toEqual(['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'])
|
|
10
10
|
expect(calendar.monthYear.value).toBe('May 2026')
|
|
11
11
|
expect(calendar.calendarDays.value).toHaveLength(42)
|
|
12
12
|
expect(calendar.calendarDays.value[0].date.getMonth()).toBe(3)
|
|
13
|
+
expect(calendar.calendarDays.value[0].date.getDate()).toBe(27)
|
|
14
|
+
expect(calendar.calendarDays.value[0].date.getDay()).toBe(1)
|
|
13
15
|
expect(calendar.calendarDays.value.some(day => day.isCurrentMonth && day.date.getDate() === 7)).toBe(true)
|
|
14
16
|
})
|
|
15
17
|
|
|
@@ -194,6 +194,117 @@ describe('useExperimentSelector', () => {
|
|
|
194
194
|
])
|
|
195
195
|
})
|
|
196
196
|
|
|
197
|
+
it('should send the scope filters but not status to the stats route when counting', async () => {
|
|
198
|
+
fakeResponse = { total: 3, by_status: { planned: 1, ongoing: 2, completed: 0, cancelled: 0 } } as never
|
|
199
|
+
const hook = useExperimentSelector()
|
|
200
|
+
Object.assign(hook.filters, { search: 'glu', project: 'Screen', mine: true, status: 'planned' })
|
|
201
|
+
|
|
202
|
+
await hook.fetchStatusCounts()
|
|
203
|
+
|
|
204
|
+
const url = new URL(recordedUrls[0], 'http://mint.test')
|
|
205
|
+
expect(url.pathname).toBe('/experiments/stats')
|
|
206
|
+
expect(Object.fromEntries(url.searchParams)).toEqual({ search: 'glu', project: 'Screen', mine: 'true' })
|
|
207
|
+
expect(hook.statusCounts.value).toEqual({ planned: 1, ongoing: 2, completed: 0, cancelled: 0 })
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('should send mine=true on the list request when the mine filter is set', async () => {
|
|
211
|
+
const hook = useExperimentSelector()
|
|
212
|
+
hook.filters.mine = true
|
|
213
|
+
|
|
214
|
+
await hook.fetch()
|
|
215
|
+
|
|
216
|
+
expect(recordedUrls[0]).toContain('mine=true')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should sum the per-type stats when several experiment types are allowed', async () => {
|
|
220
|
+
vi.spyOn(useApi().client, 'get').mockImplementation(async (url: string) => {
|
|
221
|
+
recordedUrls.push(url)
|
|
222
|
+
const type = new URL(url, 'http://mint.test').searchParams.get('experiment_type')
|
|
223
|
+
return { data: { total: 2, by_status: { planned: type === 'drug-response' ? 2 : 0, ongoing: type === 'metabolomics' ? 2 : 0 } } }
|
|
224
|
+
})
|
|
225
|
+
const hook = useExperimentSelector({ allowedExperimentTypes: ['drug-response', 'metabolomics'] })
|
|
226
|
+
|
|
227
|
+
await hook.fetchStatusCounts()
|
|
228
|
+
|
|
229
|
+
expect(recordedUrls).toHaveLength(2)
|
|
230
|
+
expect(hook.statusCounts.value).toEqual({ planned: 2, ongoing: 2 })
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('should not query the stats route when the selected type is not allowed', async () => {
|
|
234
|
+
const hook = useExperimentSelector({ experimentType: 'proteomics', allowedExperimentTypes: ['drug-response'] })
|
|
235
|
+
|
|
236
|
+
await hook.fetchStatusCounts()
|
|
237
|
+
|
|
238
|
+
expect(recordedUrls).toEqual([])
|
|
239
|
+
expect(hook.statusCounts.value).toEqual({})
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('should refetch status counts with the list when a filter or the search changes and counts are on', async () => {
|
|
243
|
+
vi.useFakeTimers()
|
|
244
|
+
const hook = useExperimentSelector({ withStatusCounts: true })
|
|
245
|
+
const statsUrls = () => recordedUrls.filter(url => url.includes('/experiments/stats'))
|
|
246
|
+
|
|
247
|
+
hook.filters.project = 'Screen'
|
|
248
|
+
await nextTick()
|
|
249
|
+
|
|
250
|
+
expect(statsUrls()).toHaveLength(1)
|
|
251
|
+
expect(recordedUrls.filter(url => url.includes('/experiments?'))).toHaveLength(1)
|
|
252
|
+
|
|
253
|
+
hook.filters.search = 'glu'
|
|
254
|
+
await vi.advanceTimersByTimeAsync(300)
|
|
255
|
+
|
|
256
|
+
expect(statsUrls()).toHaveLength(2)
|
|
257
|
+
expect(statsUrls()[1]).toContain('search=glu')
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it.each([
|
|
261
|
+
['status', (hook: ReturnType<typeof useExperimentSelector>) => { hook.filters.status = 'planned' }, 1],
|
|
262
|
+
['sort', (hook: ReturnType<typeof useExperimentSelector>) => { hook.sortKey.value = 'name:asc' }, 1],
|
|
263
|
+
['project', (hook: ReturnType<typeof useExperimentSelector>) => { hook.filters.project = 'Screen' }, 2],
|
|
264
|
+
] as const)('should refetch status counts on a %s change only when it changes the counts', async (_name, change, statsCalls) => {
|
|
265
|
+
// One body that serves both routes, so the first stats request succeeds.
|
|
266
|
+
fakeResponse = { ...fakeResponse, by_status: { planned: 1 } } as never
|
|
267
|
+
const hook = useExperimentSelector({ withStatusCounts: true })
|
|
268
|
+
await hook.fetchStatusCounts()
|
|
269
|
+
|
|
270
|
+
change(hook)
|
|
271
|
+
await nextTick()
|
|
272
|
+
|
|
273
|
+
expect(recordedUrls.filter(url => url.includes('/experiments/stats'))).toHaveLength(statsCalls)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('should refetch status counts on a status change when the previous stats request failed', async () => {
|
|
277
|
+
const stats = vi.fn()
|
|
278
|
+
.mockRejectedValueOnce(new Error('offline'))
|
|
279
|
+
.mockResolvedValue({ data: { total: 1, by_status: { planned: 1 } } })
|
|
280
|
+
vi.spyOn(useApi().client, 'get').mockImplementation(async (url: string) =>
|
|
281
|
+
url.includes('/experiments/stats') ? stats() : { data: fakeResponse })
|
|
282
|
+
const hook = useExperimentSelector({ withStatusCounts: true })
|
|
283
|
+
await hook.fetchStatusCounts()
|
|
284
|
+
expect(hook.statusCounts.value).toEqual({})
|
|
285
|
+
|
|
286
|
+
hook.filters.status = 'planned'
|
|
287
|
+
await nextTick()
|
|
288
|
+
|
|
289
|
+
expect(stats).toHaveBeenCalledTimes(2)
|
|
290
|
+
await vi.waitFor(() => expect(hook.statusCounts.value).toEqual({ planned: 1 }))
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('should refetch status counts when a status change flushes a pending search', async () => {
|
|
294
|
+
vi.useFakeTimers()
|
|
295
|
+
const hook = useExperimentSelector({ withStatusCounts: true })
|
|
296
|
+
await hook.fetchStatusCounts()
|
|
297
|
+
const statsUrls = () => recordedUrls.filter(url => url.includes('/experiments/stats'))
|
|
298
|
+
|
|
299
|
+
hook.filters.search = 'glu'
|
|
300
|
+
await nextTick()
|
|
301
|
+
hook.filters.status = 'planned'
|
|
302
|
+
await nextTick()
|
|
303
|
+
|
|
304
|
+
expect(statsUrls()).toHaveLength(2)
|
|
305
|
+
expect(statsUrls()[1]).toContain('search=glu')
|
|
306
|
+
})
|
|
307
|
+
|
|
197
308
|
it('loadMore appends the next page', async () => {
|
|
198
309
|
const hook = useExperimentSelector({ limit: 1 })
|
|
199
310
|
|