@morscherlab/mint-sdk 1.2.0-beta.1 → 1.2.0-beta.11
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 +35 -5
- package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-oL0fg_A0.js} +6 -4
- package/dist/ExperimentPopover-oL0fg_A0.js.map +1 -0
- package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-BeEOomw_.js} +5 -5
- package/dist/ExperimentSelectorModal-BeEOomw_.js.map +1 -0
- package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-Dphh3RrI.js} +5 -8
- package/dist/SettingsModal-Dphh3RrI.js.map +1 -0
- package/dist/{EmptyState-p90quq8Z.js → Skeleton-DxtwJ5gt.js} +111 -93
- package/dist/Skeleton-DxtwJ5gt.js.map +1 -0
- package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
- package/dist/__tests__/components/PluginWorkspaceView.internal.test.d.ts +1 -0
- package/dist/__tests__/components/SecretInput.test.d.ts +1 -0
- package/dist/__tests__/components/WellEditPopupInternal.test.d.ts +1 -0
- package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +15 -0
- package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
- package/dist/components/ActionMenu.vue.d.ts +1 -1
- package/dist/components/AppAvatarMenu.vue.d.ts +4 -0
- package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/AuditTrail.vue.d.ts +13 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BatchProgressList.vue.d.ts +17 -0
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
- package/dist/components/DataFrame.vue.d.ts +14 -2
- package/dist/components/DatePicker.vue.d.ts +1 -1
- package/dist/components/DateTimePicker.vue.d.ts +2 -0
- package/dist/components/DropdownButton.vue.d.ts +2 -0
- package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
- package/dist/components/ExperimentPopover.vue.d.ts +1 -0
- package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/JobsStatusTray.vue.d.ts +9 -2
- package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
- package/dist/components/PluginWorkspaceView.props.d.ts +29 -1
- package/dist/components/PluginWorkspaceView.vue.d.ts +5 -5
- package/dist/components/ProgressBar.vue.d.ts +1 -1
- package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
- package/dist/components/ReagentList.vue.d.ts +29 -1
- package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
- package/dist/components/SampleLegend.vue.d.ts +1 -1
- package/dist/components/SampleSelector.drag.d.ts +13 -0
- package/dist/components/SampleSelector.tree.d.ts +2 -0
- package/dist/components/SampleSelector.vue.d.ts +35 -2
- package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
- package/dist/components/SecretInput.vue.d.ts +28 -0
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -1
- package/dist/components/TimePicker.vue.d.ts +1 -0
- package/dist/components/WellPlate.geometry.d.ts +15 -0
- package/dist/components/WellPlate.interaction.d.ts +13 -0
- package/dist/components/WellPlate.vue.d.ts +29 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.js +8 -8
- package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
- package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
- package/dist/components/internal/WellEditPopupInternal.vue.d.ts +3 -1
- package/dist/components/internal/WorkspaceControlsInternal.vue.d.ts +23 -0
- package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +70 -0
- package/dist/components/internal/WorkspaceSidebarInternal.vue.d.ts +43 -0
- package/dist/{components-DkHddRMl.js → components-CgAUzF8F.js} +2497 -2235
- package/dist/components-CgAUzF8F.js.map +1 -0
- package/dist/composables/controlSchemaTypes.d.ts +34 -0
- package/dist/composables/flattenWorkspaceBindings.d.ts +61 -0
- package/dist/composables/index.d.ts +9 -2
- package/dist/composables/index.js +10 -10
- package/dist/composables/pluginWorkspaceModel.d.ts +164 -0
- package/dist/composables/useAsync.d.ts +5 -1
- package/dist/composables/useBioTemplateWorkspace.d.ts +4 -20
- package/dist/composables/useCommandHistory.d.ts +5 -1
- package/dist/composables/useDropdownState.d.ts +18 -2
- package/dist/composables/useEventStream.d.ts +9 -0
- package/dist/composables/useFocusTrap.d.ts +21 -0
- package/dist/composables/useGeneratedAnalysis.d.ts +3 -1
- package/dist/composables/useJobsStatusTray.d.ts +25 -1
- package/dist/composables/useListReorder.d.ts +90 -0
- package/dist/composables/useMenuKeyboard.d.ts +29 -0
- package/dist/composables/useOptimisticMutation.d.ts +5 -1
- package/dist/composables/usePluginClient.d.ts +2 -0
- package/dist/composables/usePluginConfig.d.ts +27 -0
- package/dist/composables/usePluginWorkspace.d.ts +51 -0
- package/dist/composables/useRequestSyncState.d.ts +42 -2
- package/dist/composables/useResourceCrud.d.ts +5 -1
- package/dist/composables/useRovingFocus.d.ts +24 -0
- package/dist/composables/useScheduleDrag.d.ts +1 -0
- package/dist/composables/useWellPainting.d.ts +5 -1
- package/dist/composables/useWellPlateAdapter.d.ts +5 -1
- package/dist/composables/useWellPlateValidation.d.ts +5 -1
- package/dist/composables/workspaceRecipes.d.ts +188 -0
- package/dist/{composables-C_i90sGS.js → composables-B_pia3hO.js} +209 -82
- package/dist/composables-B_pia3hO.js.map +1 -0
- package/dist/{useApi-J6zFkHmn.js → errors-_W0-LbA6.js} +103 -3
- package/dist/errors-_W0-LbA6.js.map +1 -0
- package/dist/{experiment-Cq145oEW.js → experiment-Cwl9AYxw.js} +3 -8
- package/dist/experiment-Cwl9AYxw.js.map +1 -0
- package/dist/{experiment-utils-CLnzPPq5.js → experiment-utils-DV3DrvE_.js} +70 -51
- package/dist/experiment-utils-DV3DrvE_.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -15
- package/dist/install.js +2 -7
- package/dist/install.js.map +1 -1
- package/dist/permissions.d.ts +42 -1
- package/dist/permissions.js +20 -10
- package/dist/permissions.js.map +1 -1
- package/dist/stores/auth.d.ts +6 -0
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js +3 -3
- package/dist/stores/settings.d.ts +31 -1
- package/dist/styles.css +11247 -29501
- package/dist/templates/builderReadUtils.d.ts +1 -1
- package/dist/templates/index.js +2 -4
- package/dist/{templates-DsP51i-S.js → templates-Qq113pyZ.js} +303 -106
- package/dist/templates-Qq113pyZ.js.map +1 -0
- package/dist/types/auth.d.ts +1 -0
- package/dist/types/form-builder.d.ts +1 -1
- package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-aMZlb4Sc.js} +462 -1130
- package/dist/useControlSchema-aMZlb4Sc.js.map +1 -0
- package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-DitCtrTT.js} +22 -6
- package/dist/useDropdownState-DitCtrTT.js.map +1 -0
- package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-I8HC8hUu.js} +4 -4
- package/dist/{useExperimentSelector-CV4iNfMS.js.map → useExperimentSelector-I8HC8hUu.js.map} +1 -1
- package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-TCxNnqeb.js} +2 -2
- package/dist/{useFormBuilder-BLxG3BOX.js.map → useFormBuilder-TCxNnqeb.js.map} +1 -1
- package/dist/{useProtocolTemplates-CS_SQl6U.js → useProtocolTemplates-BmX_iVBR.js} +766 -212
- package/dist/useProtocolTemplates-BmX_iVBR.js.map +1 -0
- package/dist/utils/color.d.ts +13 -0
- package/dist/utils/errors.d.ts +9 -0
- package/dist/utils/pluginSecrets.d.ts +53 -0
- package/dist/utils/records.d.ts +4 -0
- package/package.json +1 -1
- package/src/__tests__/components/ActionMenu.test.ts +94 -0
- package/src/__tests__/components/AppAvatarMenu.test.ts +123 -0
- package/src/__tests__/components/BaseTabs.test.ts +67 -0
- package/src/__tests__/components/DataFrame.test.ts +183 -11
- package/src/__tests__/components/DataStates.test.ts +176 -0
- package/src/__tests__/components/DatePicker.test.ts +76 -0
- package/src/__tests__/components/DateTimePicker.test.ts +36 -0
- package/src/__tests__/components/DropdownButton.test.ts +134 -0
- package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
- package/src/__tests__/components/GroupAssigner.test.ts +53 -0
- package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
- package/src/__tests__/components/PluginWorkspaceView.internal.test.ts +230 -0
- package/src/__tests__/components/RackEditor.test.ts +35 -0
- package/src/__tests__/components/ReagentList.test.ts +64 -2
- package/src/__tests__/components/RetiredStyles.test.ts +31 -0
- package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
- package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
- package/src/__tests__/components/SecretInput.test.ts +87 -0
- package/src/__tests__/components/SegmentedControl.test.ts +88 -0
- package/src/__tests__/components/TimePicker.test.ts +61 -0
- package/src/__tests__/components/WellEditPopupInternal.test.ts +108 -0
- package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
- package/src/__tests__/composables/useAuth.test.ts +2 -0
- package/src/__tests__/composables/useDropdownState.test.ts +58 -1
- package/src/__tests__/composables/useListReorder.test.ts +145 -0
- package/src/__tests__/composables/usePluginClient.test.ts +140 -0
- package/src/__tests__/composables/usePluginConfig.test.ts +497 -0
- package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +39 -7
- package/src/__tests__/stores/settings.test.ts +71 -1
- package/src/__tests__/styles/cssTokens.test.ts +131 -0
- package/src/__tests__/utils/permissions.test.ts +68 -0
- package/src/components/ActionMenu.vue +45 -88
- package/src/components/AlertBox.vue +0 -4
- package/src/components/AppAvatarMenu.vue +26 -7
- package/src/components/AppLayout.vue +0 -4
- package/src/components/AppPluginSwitcher.story.vue +87 -0
- package/src/components/AppPluginSwitcher.vue +2 -5
- package/src/components/AppSidebar.vue +0 -4
- package/src/components/AppToastContainer.vue +6 -8
- package/src/components/AppTopBar.vue +0 -4
- package/src/components/ArtifactSaveDialog.vue +0 -4
- package/src/components/ArtifactSelectorModal.vue +0 -4
- package/src/components/AuditTrail.story.vue +18 -0
- package/src/components/AuditTrail.vue +27 -7
- package/src/components/AutoGroupModal.vue +0 -4
- package/src/components/Avatar.vue +0 -4
- package/src/components/BaseButton.vue +0 -4
- package/src/components/BaseCheckbox.vue +0 -4
- package/src/components/BaseInput.vue +0 -4
- package/src/components/BaseModal.vue +8 -60
- package/src/components/BasePill.vue +0 -4
- package/src/components/BaseRadioGroup.vue +0 -4
- package/src/components/BaseSelect.vue +0 -4
- package/src/components/BaseSlider.vue +0 -4
- package/src/components/BaseTabs.vue +26 -5
- package/src/components/BaseTextarea.vue +0 -4
- package/src/components/BaseToggle.vue +0 -4
- package/src/components/BatchProgressList.story.vue +18 -0
- package/src/components/BatchProgressList.vue +32 -4
- package/src/components/BioTemplateExperimentWorkspaceView.vue +10 -21
- package/src/components/BioTemplatePackWorkspaceView.vue +11 -15
- package/src/components/BioTemplatePresetWorkspaceView.vue +8 -13
- package/src/components/Breadcrumb.vue +0 -4
- package/src/components/Calendar.vue +0 -4
- package/src/components/ChartContainer.story.vue +1 -1
- package/src/components/ChartContainer.vue +0 -4
- package/src/components/ChemicalFormula.vue +0 -4
- package/src/components/CollapsibleCard.vue +0 -4
- package/src/components/ColorSlider.vue +0 -4
- package/src/components/ComponentBindingRenderer.vue +1 -3
- package/src/components/ConcentrationInput.vue +0 -4
- package/src/components/ConfirmDialog.vue +0 -4
- package/src/components/ControlWorkspaceView.vue +11 -22
- package/src/components/DataFrame.story.vue +14 -0
- package/src/components/DataFrame.vue +97 -23
- package/src/components/DatePicker.vue +73 -27
- package/src/components/DateTimePicker.vue +45 -17
- package/src/components/Divider.vue +0 -4
- package/src/components/DoseCalculator.vue +0 -4
- package/src/components/DoseDesignWorkspaceView.vue +6 -25
- package/src/components/DropdownButton.vue +24 -6
- package/src/components/EmptyState.vue +0 -4
- package/src/components/ExperimentCodeBadge.vue +0 -4
- package/src/components/ExperimentDataViewer.story.vue +3 -0
- package/src/components/ExperimentDataViewer.vue +33 -13
- package/src/components/ExperimentPopover.vue +2 -5
- package/src/components/ExperimentSelectorModal.vue +0 -4
- package/src/components/ExperimentTimeline.story.vue +18 -0
- package/src/components/ExperimentTimeline.vue +81 -75
- package/src/components/FileUploader.vue +0 -4
- package/src/components/FitPanel.vue +0 -4
- package/src/components/FormActions.story.vue +96 -0
- package/src/components/FormActions.vue +0 -4
- package/src/components/FormBuilder.vue +0 -4
- package/src/components/FormField.vue +0 -4
- package/src/components/FormulaInput.vue +0 -4
- package/src/components/GeneratedPathInput.story.vue +68 -0
- package/src/components/GeneratedPlotlyResult.story.vue +96 -0
- package/src/components/GeneratedPlotlyResult.vue +3 -3
- package/src/components/GeneratedPluginView.story.vue +145 -0
- package/src/components/GeneratedPluginView.vue +10 -10
- package/src/components/GeneratedResultRenderer.story.vue +117 -0
- package/src/components/GeneratedResultRenderer.vue +4 -4
- package/src/components/GroupAssigner.vue +67 -5
- package/src/components/IconButton.vue +0 -4
- package/src/components/InstrumentAlertLog.vue +0 -4
- package/src/components/InstrumentStateBadge.vue +0 -4
- package/src/components/InstrumentStatusCard.vue +0 -4
- package/src/components/JobsStatusTray.vue +16 -5
- package/src/components/LcmsSequenceTable.vue +81 -50
- package/src/components/LoadingSpinner.vue +0 -4
- package/src/components/MobileSupportGate.vue +0 -4
- package/src/components/MoleculeInput.vue +0 -4
- package/src/components/MultiSelect.vue +0 -4
- package/src/components/NumberInput.vue +0 -4
- package/src/components/PlateMapEditor.vue +3 -14
- package/src/components/PluginIcon.vue +0 -4
- package/src/components/PluginWorkspaceView.props.ts +38 -0
- package/src/components/PluginWorkspaceView.vue +53 -224
- package/src/components/ProgressBar.vue +0 -4
- package/src/components/ProtocolStepEditor.vue +2 -4
- package/src/components/RackEditor.vue +51 -70
- package/src/components/ReagentEditor.vue +0 -4
- package/src/components/ReagentList.story.vue +18 -0
- package/src/components/ReagentList.vue +127 -82
- package/src/components/ResourceCard.vue +0 -4
- package/src/components/RuntimeUpdateNotice.story.vue +49 -0
- package/src/components/RuntimeUpdateNotice.vue +4 -4
- package/src/components/SampleHierarchyTree.story.vue +18 -0
- package/src/components/SampleHierarchyTree.vue +32 -9
- package/src/components/SampleLegend.vue +2 -8
- package/src/components/SampleSelector.drag.ts +51 -0
- package/src/components/SampleSelector.story.vue +6 -0
- package/src/components/SampleSelector.tree.ts +2 -0
- package/src/components/SampleSelector.vue +49 -10
- package/src/components/SampleSelectorGroupNode.vue +19 -0
- package/src/components/ScheduleCalendar.story.vue +6 -0
- package/src/components/ScheduleCalendar.vue +82 -7
- package/src/components/ScientificNumber.vue +0 -4
- package/src/components/SecretInput.story.vue +79 -0
- package/src/components/SecretInput.vue +150 -0
- package/src/components/SectionCard.vue +0 -4
- package/src/components/SegmentedControl.vue +48 -5
- package/src/components/SequenceInput.vue +0 -4
- package/src/components/SequenceProgressBar.story.vue +110 -0
- package/src/components/SequenceProgressBar.vue +0 -4
- package/src/components/SettingsModal.vue +0 -4
- package/src/components/Skeleton.vue +0 -4
- package/src/components/SmartGroupFieldRecipe.vue +8 -6
- package/src/components/SmartGroupManual.vue +0 -4
- package/src/components/StatusIndicator.vue +0 -4
- package/src/components/StepWizard.vue +0 -4
- package/src/components/TagsInput.vue +4 -6
- package/src/components/ThemeToggle.vue +0 -4
- package/src/components/TimePicker.vue +36 -7
- package/src/components/TimeRangeInput.vue +0 -4
- package/src/components/Tooltip.story.vue +3 -3
- package/src/components/Tooltip.vue +0 -4
- package/src/components/UnitInput.vue +0 -4
- package/src/components/WellPlate.geometry.ts +60 -1
- package/src/components/WellPlate.interaction.ts +44 -0
- package/src/components/WellPlate.story.vue +8 -0
- package/src/components/WellPlate.vue +53 -7
- package/src/components/index.ts +9 -0
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
- package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
- package/src/components/internal/DataStateInternal.vue +74 -0
- package/src/components/internal/FormSectionRenderer.vue +0 -4
- package/src/components/internal/WellEditPopupInternal.vue +20 -5
- package/src/components/internal/WorkspaceControlsInternal.vue +20 -0
- package/src/components/internal/WorkspaceShellInternal.vue +125 -0
- package/src/components/internal/WorkspaceSidebarInternal.vue +82 -0
- package/src/composables/controlSchemaTypes.ts +34 -0
- package/src/composables/experimentDesignData.ts +1 -3
- package/src/composables/flattenWorkspaceBindings.ts +104 -0
- package/src/composables/formBuilderRegistry.ts +5 -0
- package/src/composables/index.ts +43 -0
- package/src/composables/pluginWorkspaceModel.ts +182 -0
- package/src/composables/useAsync.ts +5 -1
- package/src/composables/useAuth.ts +3 -0
- package/src/composables/useBioTemplatePackWorkspace.ts +15 -9
- package/src/composables/useBioTemplatePresetWorkspace.ts +14 -15
- package/src/composables/useBioTemplateWorkspace.ts +18 -43
- package/src/composables/useCommandHistory.ts +5 -1
- package/src/composables/useDropdownState.ts +35 -5
- package/src/composables/useEventStream.ts +14 -2
- package/src/composables/useFileImport.ts +2 -7
- package/src/composables/useFocusTrap.ts +91 -0
- package/src/composables/useGeneratedAnalysis.ts +22 -10
- package/src/composables/useJobsStatusTray.ts +184 -17
- package/src/composables/useListReorder.story.vue +143 -0
- package/src/composables/useListReorder.ts +242 -0
- package/src/composables/useMenuKeyboard.ts +90 -0
- package/src/composables/useOptimisticMutation.ts +6 -16
- package/src/composables/usePluginClient.ts +47 -4
- package/src/composables/usePluginConfig.ts +252 -0
- package/src/composables/usePluginWorkspace.ts +208 -0
- package/src/composables/useRackEditor.ts +2 -11
- package/src/composables/useRequestSyncState.ts +98 -28
- package/src/composables/useResourceCrud.ts +6 -16
- package/src/composables/useRovingFocus.ts +66 -0
- package/src/composables/useScheduleDrag.ts +37 -0
- package/src/composables/useWellPainting.ts +10 -30
- package/src/composables/useWellPlateAdapter.ts +5 -1
- package/src/composables/useWellPlateEditor.ts +1 -11
- package/src/composables/useWellPlateValidation.ts +5 -1
- package/src/composables/workspaceRecipes.ts +267 -0
- package/src/index.ts +16 -0
- package/src/permissions.ts +48 -9
- package/src/stores/auth.ts +1 -0
- package/src/stores/experiment.ts +2 -7
- package/src/stores/index.ts +9 -1
- package/src/stores/settings.ts +93 -1
- package/src/styles/components/audit-trail.css +5 -5
- package/src/styles/components/batch-progress-list.css +7 -0
- package/src/styles/components/color-slider.css +2 -2
- package/src/styles/components/data-state.css +30 -0
- package/src/styles/components/dataframe.css +29 -35
- package/src/styles/components/experiment-data-viewer.css +4 -4
- package/src/styles/components/experiment-timeline.css +3 -30
- package/src/styles/components/form-builder.css +5 -5
- package/src/styles/components/lcms-sequence-table.css +16 -1
- package/src/styles/components/multi-select.css +1 -1
- package/src/styles/components/reagent-list.css +38 -31
- package/src/styles/components/sample-hierarchy-tree.css +5 -19
- package/src/styles/components/sample-selector.css +9 -2
- package/src/styles/components/schedule-calendar.css +8 -0
- package/src/styles/components/scientific-number.css +1 -1
- package/src/styles/components/secret-input.css +60 -0
- package/src/styles/components/well-plate.css +8 -0
- package/src/styles/index.css +9 -0
- package/src/styles/variables.css +29 -0
- package/src/templates/builderPresetControls.ts +1 -1
- package/src/templates/builderReadUtils.ts +1 -3
- package/src/templates/componentPlateHelpers.ts +3 -1
- package/src/templates/componentTargetResolvers.ts +1 -3
- package/src/templates/controlSchemaTargets.ts +1 -3
- package/src/templates/doseResponseAdapters.ts +2 -13
- package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
- package/src/templates/plateMapBuilder.ts +2 -2
- package/src/templates/qpcrPlateBuilder.ts +1 -1
- package/src/templates/templateValidators.ts +1 -1
- package/src/templates/timeCourseBuilder.ts +2 -2
- package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
- package/src/types/auth.ts +1 -0
- package/src/types/form-builder.ts +1 -0
- package/src/utils/color.ts +51 -0
- package/src/utils/errors.ts +29 -0
- package/src/utils/formModelSync.ts +1 -3
- package/src/utils/pluginIcon.ts +1 -3
- package/src/utils/pluginSecrets.ts +102 -0
- package/src/utils/records.ts +9 -0
- package/dist/EmptyState-p90quq8Z.js.map +0 -1
- package/dist/ExperimentPopover-tLwJ7XF4.js.map +0 -1
- package/dist/ExperimentSelectorModal-DyPAUCLw.js.map +0 -1
- package/dist/SettingsModal-BgKY93zh.js.map +0 -1
- package/dist/components-DkHddRMl.js.map +0 -1
- package/dist/composables/autoGroupConstants.d.ts +0 -1
- package/dist/composables/autoGroupGrouping.d.ts +0 -3
- package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
- package/dist/composables-C_i90sGS.js.map +0 -1
- package/dist/experiment-Cq145oEW.js.map +0 -1
- package/dist/experiment-utils-CLnzPPq5.js.map +0 -1
- package/dist/templates/builderDefaults.d.ts +0 -1
- package/dist/templates/plateGeometry.d.ts +0 -4
- package/dist/templates-DsP51i-S.js.map +0 -1
- package/dist/useApi-J6zFkHmn.js.map +0 -1
- package/dist/useControlSchema-BDx2Olha.js.map +0 -1
- package/dist/useDropdownState-DSb3BC3N.js.map +0 -1
- package/dist/useProtocolTemplates-CS_SQl6U.js.map +0 -1
- package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
- package/src/composables/autoGroupConstants.ts +0 -4
- package/src/composables/autoGroupGrouping.ts +0 -148
- package/src/composables/useAutoGroupInputSources.ts +0 -147
- package/src/templates/builderDefaults.ts +0 -11
- package/src/templates/plateGeometry.ts +0 -62
- /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → components/DataStates.test.d.ts} +0 -0
|
@@ -53,6 +53,7 @@ const selectedTemplateId = ref<string | null>(null)
|
|
|
53
53
|
const {
|
|
54
54
|
isOpen: templateDropdownOpen,
|
|
55
55
|
rootRef: templateDropdownRef,
|
|
56
|
+
triggerRef: templateTriggerRef,
|
|
56
57
|
close: closeTemplateDropdown,
|
|
57
58
|
toggle: toggleTemplateDropdown,
|
|
58
59
|
} = useDropdownState()
|
|
@@ -204,6 +205,7 @@ watch(
|
|
|
204
205
|
<label class="mint-protocol-editor__template-label">Template</label>
|
|
205
206
|
<div ref="templateDropdownRef" class="mint-protocol-editor__template-dropdown">
|
|
206
207
|
<button
|
|
208
|
+
ref="templateTriggerRef"
|
|
207
209
|
type="button"
|
|
208
210
|
class="mint-protocol-editor__template-btn"
|
|
209
211
|
@click="toggleTemplateDropdown"
|
|
@@ -376,7 +378,3 @@ watch(
|
|
|
376
378
|
</div>
|
|
377
379
|
</div>
|
|
378
380
|
</template>
|
|
379
|
-
|
|
380
|
-
<style>
|
|
381
|
-
@import '../styles/components/protocol-step-editor.css';
|
|
382
|
-
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Multi-rack editor for managing collections of well-plate racks with add/remove/reorder controls and per-well editing. */
|
|
3
|
-
import {
|
|
3
|
+
import { computed, watch, type ComponentPublicInstance } from 'vue'
|
|
4
|
+
import { SLOT_COLORS, SLOT_ORDER } from '../utils/color'
|
|
4
5
|
import type { Rack, SlotPosition, WellPlateFormat, WellPlateSize, WellEditData, Well, WellEditField, WellSampleDropData, RackSampleDropMapper } from '../types'
|
|
6
|
+
import { useListReorder } from '../composables/useListReorder'
|
|
5
7
|
import { useRackEditor } from '../composables/useRackEditor'
|
|
6
8
|
import WellPlate from './WellPlate.vue'
|
|
7
9
|
|
|
@@ -104,23 +106,48 @@ watch(
|
|
|
104
106
|
},
|
|
105
107
|
)
|
|
106
108
|
|
|
107
|
-
const
|
|
108
|
-
R: '#ef4444',
|
|
109
|
-
G: '#22c55e',
|
|
110
|
-
B: '#3b82f6',
|
|
111
|
-
Y: '#eab308',
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const SLOT_OPTIONS: SlotPosition[] = ['R', 'G', 'B', 'Y']
|
|
109
|
+
const SLOT_OPTIONS: readonly SlotPosition[] = SLOT_ORDER
|
|
115
110
|
|
|
116
111
|
const FORMAT_OPTIONS: { value: WellPlateFormat; label: string }[] = [
|
|
117
112
|
{ value: 54, label: '54' },
|
|
118
113
|
{ value: 96, label: '96' },
|
|
119
114
|
]
|
|
120
115
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
const
|
|
116
|
+
// Rack tab reordering: HTML5 drag for pointers, Alt+Arrow for the keyboard,
|
|
117
|
+
// both owned by the shared reorder composable.
|
|
118
|
+
const tabRefs = new Map<string, HTMLElement>()
|
|
119
|
+
|
|
120
|
+
const {
|
|
121
|
+
draggingId: draggingRackId,
|
|
122
|
+
dragOverId: dragOverRackId,
|
|
123
|
+
announcement: reorderAnnouncement,
|
|
124
|
+
announcerStyle,
|
|
125
|
+
onDragStart: onRackDragStart,
|
|
126
|
+
onDragOver: onRackDragOver,
|
|
127
|
+
onDragLeave: onRackDragLeave,
|
|
128
|
+
onDrop: onRackDrop,
|
|
129
|
+
onDragEnd: onRackDragEnd,
|
|
130
|
+
onKeydown: onRackReorderKeydown,
|
|
131
|
+
} = useListReorder<Rack>({
|
|
132
|
+
items: () => editor.racks.value,
|
|
133
|
+
getId: (rack) => rack.id,
|
|
134
|
+
getLabel: (rack) => rack.name,
|
|
135
|
+
disabled: () => !props.allowReorder || props.readonly,
|
|
136
|
+
getElement: (id) => tabRefs.get(id),
|
|
137
|
+
itemNoun: 'Rack',
|
|
138
|
+
onReorder: ({ fromIndex, toIndex }) => {
|
|
139
|
+
editor.reorderRacks(fromIndex, toIndex)
|
|
140
|
+
emit('rack-reorder', editor.racks.value.map(r => r.id))
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
function setTabRef(id: string, el: Element | ComponentPublicInstance | null) {
|
|
145
|
+
if (el instanceof HTMLElement) {
|
|
146
|
+
tabRefs.set(id, el)
|
|
147
|
+
} else {
|
|
148
|
+
tabRefs.delete(id)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
124
151
|
|
|
125
152
|
function handleAddRack() {
|
|
126
153
|
const rack = editor.addRack()
|
|
@@ -136,54 +163,6 @@ function handleTabClick(rackId: string) {
|
|
|
136
163
|
editor.setActiveRack(rackId)
|
|
137
164
|
}
|
|
138
165
|
|
|
139
|
-
// Rack drag handlers
|
|
140
|
-
function handleRackDragStart(event: DragEvent, rackId: string) {
|
|
141
|
-
if (!props.allowReorder) return
|
|
142
|
-
draggingRackId.value = rackId
|
|
143
|
-
if (event.dataTransfer) {
|
|
144
|
-
event.dataTransfer.effectAllowed = 'move'
|
|
145
|
-
event.dataTransfer.setData('text/plain', rackId)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function handleRackDragOver(event: DragEvent, rackId: string) {
|
|
150
|
-
event.preventDefault()
|
|
151
|
-
if (draggingRackId.value && draggingRackId.value !== rackId) {
|
|
152
|
-
dragOverRackId.value = rackId
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function handleRackDragLeave() {
|
|
157
|
-
dragOverRackId.value = null
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function handleRackDrop(event: DragEvent, targetRackId: string) {
|
|
161
|
-
event.preventDefault()
|
|
162
|
-
if (!draggingRackId.value || draggingRackId.value === targetRackId) {
|
|
163
|
-
clearDragState()
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const fromIndex = editor.racks.value.findIndex(r => r.id === draggingRackId.value)
|
|
168
|
-
const toIndex = editor.racks.value.findIndex(r => r.id === targetRackId)
|
|
169
|
-
|
|
170
|
-
if (fromIndex !== -1 && toIndex !== -1) {
|
|
171
|
-
editor.reorderRacks(fromIndex, toIndex)
|
|
172
|
-
emit('rack-reorder', editor.racks.value.map(r => r.id))
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
clearDragState()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function handleRackDragEnd() {
|
|
179
|
-
clearDragState()
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function clearDragState() {
|
|
183
|
-
draggingRackId.value = null
|
|
184
|
-
dragOverRackId.value = null
|
|
185
|
-
}
|
|
186
|
-
|
|
187
166
|
// Toolbar actions
|
|
188
167
|
function handleFormatChange(format: WellPlateFormat) {
|
|
189
168
|
if (!editor.activeRack.value) return
|
|
@@ -281,9 +260,11 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
|
|
|
281
260
|
<div class="mint-rack-editor__tabs">
|
|
282
261
|
<div class="mint-rack-editor__tabs-inner">
|
|
283
262
|
<button
|
|
284
|
-
v-for="rack in editor.racks.value"
|
|
263
|
+
v-for="(rack, rackIndex) in editor.racks.value"
|
|
285
264
|
:key="rack.id"
|
|
265
|
+
:ref="(el) => setTabRef(rack.id, el)"
|
|
286
266
|
:draggable="allowReorder && !readonly"
|
|
267
|
+
:title="allowReorder && !readonly ? `${rack.name} — press Alt with the arrow keys to reorder` : undefined"
|
|
287
268
|
:class="[
|
|
288
269
|
'mint-rack-editor__tab',
|
|
289
270
|
{
|
|
@@ -293,11 +274,12 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
|
|
|
293
274
|
},
|
|
294
275
|
]"
|
|
295
276
|
@click="handleTabClick(rack.id)"
|
|
296
|
-
@
|
|
297
|
-
@
|
|
298
|
-
@
|
|
299
|
-
@
|
|
300
|
-
@
|
|
277
|
+
@keydown="onRackReorderKeydown($event, rack, rackIndex)"
|
|
278
|
+
@dragstart="onRackDragStart($event, rack, rackIndex)"
|
|
279
|
+
@dragover="onRackDragOver($event, rack, rackIndex)"
|
|
280
|
+
@dragleave="onRackDragLeave"
|
|
281
|
+
@drop="onRackDrop($event, rack, rackIndex)"
|
|
282
|
+
@dragend="onRackDragEnd"
|
|
301
283
|
>
|
|
302
284
|
<span
|
|
303
285
|
class="mint-rack-editor__slot-dot"
|
|
@@ -434,9 +416,8 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
|
|
|
434
416
|
</template>
|
|
435
417
|
</WellPlate>
|
|
436
418
|
</div>
|
|
419
|
+
|
|
420
|
+
<!-- Reorder announcements for screen readers -->
|
|
421
|
+
<div role="status" aria-live="polite" :style="announcerStyle">{{ reorderAnnouncement }}</div>
|
|
437
422
|
</div>
|
|
438
423
|
</template>
|
|
439
|
-
|
|
440
|
-
<style>
|
|
441
|
-
@import '../styles/components/rack-editor.css';
|
|
442
|
-
</style>
|
|
@@ -76,6 +76,8 @@ const mockReagents: Reagent[] = [
|
|
|
76
76
|
|
|
77
77
|
function initState() {
|
|
78
78
|
return {
|
|
79
|
+
loading: false,
|
|
80
|
+
error: '',
|
|
79
81
|
modelValue: mockReagents,
|
|
80
82
|
readonly: false,
|
|
81
83
|
showStockLevel: true,
|
|
@@ -92,6 +94,8 @@ function initState() {
|
|
|
92
94
|
<template #default="{ state }">
|
|
93
95
|
<div style="padding: 2rem;">
|
|
94
96
|
<ReagentList
|
|
97
|
+
:loading="state.loading"
|
|
98
|
+
:error="state.error || null"
|
|
95
99
|
v-model="state.modelValue"
|
|
96
100
|
:readonly="state.readonly"
|
|
97
101
|
:show-stock-level="state.showStockLevel"
|
|
@@ -102,6 +106,8 @@ function initState() {
|
|
|
102
106
|
</div>
|
|
103
107
|
</template>
|
|
104
108
|
<template #controls="{ state }">
|
|
109
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
110
|
+
<HstText v-model="state.error" title="Error Message" />
|
|
105
111
|
<HstCheckbox v-model="state.readonly" title="Readonly" />
|
|
106
112
|
<HstCheckbox v-model="state.showStockLevel" title="Show Stock Level" />
|
|
107
113
|
<HstSlider v-model="state.lowStockThreshold" title="Low Stock Threshold (%)" :min="0" :max="50" />
|
|
@@ -133,5 +139,17 @@ function initState() {
|
|
|
133
139
|
<ReagentList :model-value="[]" />
|
|
134
140
|
</div>
|
|
135
141
|
</Variant>
|
|
142
|
+
|
|
143
|
+
<Variant title="Loading">
|
|
144
|
+
<div style="padding: 2rem;">
|
|
145
|
+
<ReagentList :model-value="[]" loading />
|
|
146
|
+
</div>
|
|
147
|
+
</Variant>
|
|
148
|
+
|
|
149
|
+
<Variant title="Error">
|
|
150
|
+
<div style="padding: 2rem;">
|
|
151
|
+
<ReagentList :model-value="[]" error="Could not load reagents." />
|
|
152
|
+
</div>
|
|
153
|
+
</Variant>
|
|
136
154
|
</Story>
|
|
137
155
|
</template>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Sortable, searchable table of experiment reagents showing lot number, expiry, storage conditions, and stock level with low-stock warnings. */
|
|
3
|
-
import { ref, computed } from 'vue'
|
|
3
|
+
import { ref, computed, type ComponentPublicInstance } from 'vue'
|
|
4
4
|
import type { ReagentColumn, Reagent } from '../types'
|
|
5
|
+
import { useListReorder } from '../composables/useListReorder'
|
|
5
6
|
import { useSortedItems } from '../composables/useSortedItems'
|
|
6
7
|
import { useTextSearch } from '../composables/useTextSearch'
|
|
7
8
|
import {
|
|
@@ -14,6 +15,13 @@ import {
|
|
|
14
15
|
isReagentExpired as isExpired,
|
|
15
16
|
isReagentExpiringSoon as isExpiringSoon,
|
|
16
17
|
} from './ReagentList.presentation'
|
|
18
|
+
import DataStateInternal from './internal/DataStateInternal.vue'
|
|
19
|
+
|
|
20
|
+
/** Beaker glyph kept from the pre-1.2 hand-rolled empty state. */
|
|
21
|
+
const EMPTY_ICON_PATH
|
|
22
|
+
= 'M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0'
|
|
23
|
+
+ ' 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26'
|
|
24
|
+
+ ' 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z'
|
|
17
25
|
|
|
18
26
|
interface Props {
|
|
19
27
|
modelValue?: Reagent[]
|
|
@@ -23,6 +31,13 @@ interface Props {
|
|
|
23
31
|
columns?: ReagentColumn[]
|
|
24
32
|
sortable?: boolean
|
|
25
33
|
searchable?: boolean
|
|
34
|
+
/** Replace the table with a loading placeholder. */
|
|
35
|
+
loading?: boolean
|
|
36
|
+
/**
|
|
37
|
+
* Error message. When set, the table is replaced by an error state.
|
|
38
|
+
* `null`/`undefined` renders normally.
|
|
39
|
+
*/
|
|
40
|
+
error?: string | null
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -33,6 +48,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
33
48
|
columns: () => ['name', 'lot', 'expiry', 'storage', 'stock'],
|
|
34
49
|
sortable: true,
|
|
35
50
|
searchable: true,
|
|
51
|
+
loading: false,
|
|
52
|
+
error: null,
|
|
36
53
|
})
|
|
37
54
|
|
|
38
55
|
const emit = defineEmits<{
|
|
@@ -47,8 +64,7 @@ const emit = defineEmits<{
|
|
|
47
64
|
const searchQuery = ref('')
|
|
48
65
|
const sortColumn = ref<ReagentColumn | null>(null)
|
|
49
66
|
const sortDirection = ref<'asc' | 'desc'>('asc')
|
|
50
|
-
const
|
|
51
|
-
const dragOverId = ref<string | null>(null)
|
|
67
|
+
const dragHandleRefs = new Map<string, HTMLElement>()
|
|
52
68
|
|
|
53
69
|
const reagentSearch = useTextSearch({
|
|
54
70
|
items: () => props.modelValue || [],
|
|
@@ -78,14 +94,63 @@ const sortedReagents = useSortedItems<Reagent, ReagentColumn>({
|
|
|
78
94
|
})
|
|
79
95
|
const filteredReagents = sortedReagents.sortedItems
|
|
80
96
|
|
|
97
|
+
// Drag-and-drop plus the Alt+Arrow keyboard alternative live in the shared
|
|
98
|
+
// reorder composable, which also announces every move politely.
|
|
99
|
+
const {
|
|
100
|
+
draggingId,
|
|
101
|
+
dragOverId,
|
|
102
|
+
announcement: reorderAnnouncement,
|
|
103
|
+
announcerStyle,
|
|
104
|
+
onDragStart,
|
|
105
|
+
onDragOver,
|
|
106
|
+
onDragLeave,
|
|
107
|
+
onDrop,
|
|
108
|
+
onDragEnd,
|
|
109
|
+
onKeydown: onReorderKeydown,
|
|
110
|
+
} = useListReorder<Reagent>({
|
|
111
|
+
items: () => props.modelValue || [],
|
|
112
|
+
getId: (reagent) => reagent.id,
|
|
113
|
+
getLabel: (reagent) => reagent.name,
|
|
114
|
+
disabled: () => props.readonly || !props.sortable,
|
|
115
|
+
getElement: (id) => dragHandleRefs.get(id),
|
|
116
|
+
itemNoun: 'Reagent',
|
|
117
|
+
onReorder: ({ fromIndex, toIndex, items }) => {
|
|
118
|
+
emit('reorder', items[toIndex].id, fromIndex, toIndex)
|
|
119
|
+
emit('update:modelValue', items)
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
function setDragHandleRef(id: string, el: Element | ComponentPublicInstance | null) {
|
|
124
|
+
if (el instanceof HTMLElement) {
|
|
125
|
+
dragHandleRefs.set(id, el)
|
|
126
|
+
} else {
|
|
127
|
+
dragHandleRefs.delete(id)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
81
131
|
function getRowClass(reagent: Reagent): string[] {
|
|
82
132
|
return getReagentRowClasses(reagent, {
|
|
83
133
|
lowStockThreshold: props.lowStockThreshold,
|
|
84
|
-
draggedId:
|
|
134
|
+
draggedId: draggingId.value,
|
|
85
135
|
dragOverId: dragOverId.value,
|
|
86
136
|
})
|
|
87
137
|
}
|
|
88
138
|
|
|
139
|
+
/** `aria-sort` for a column header, omitted while sorting is off. */
|
|
140
|
+
function columnAriaSort(column: ReagentColumn): 'ascending' | 'descending' | 'none' | undefined {
|
|
141
|
+
if (!props.sortable) return undefined
|
|
142
|
+
if (sortColumn.value !== column) return 'none'
|
|
143
|
+
return sortDirection.value === 'asc' ? 'ascending' : 'descending'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Native buttons activate on Enter/Space; the default is prevented so a header
|
|
147
|
+
// sorts exactly once per key press in every engine.
|
|
148
|
+
function handleSortKeydown(event: KeyboardEvent, column: ReagentColumn) {
|
|
149
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
150
|
+
event.preventDefault()
|
|
151
|
+
handleSort(column)
|
|
152
|
+
}
|
|
153
|
+
|
|
89
154
|
// Actions
|
|
90
155
|
function handleSort(column: ReagentColumn) {
|
|
91
156
|
if (!props.sortable) return
|
|
@@ -111,54 +176,7 @@ function handleAdd() {
|
|
|
111
176
|
emit('add')
|
|
112
177
|
}
|
|
113
178
|
|
|
114
|
-
// Drag and drop
|
|
115
|
-
function handleDragStart(event: DragEvent, reagent: Reagent) {
|
|
116
|
-
if (props.readonly || !props.sortable) return
|
|
117
|
-
draggedId.value = reagent.id
|
|
118
|
-
if (event.dataTransfer) {
|
|
119
|
-
event.dataTransfer.effectAllowed = 'move'
|
|
120
|
-
event.dataTransfer.setData('text/plain', reagent.id)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function handleDragOver(event: DragEvent, reagent: Reagent) {
|
|
125
|
-
if (props.readonly || !props.sortable || !draggedId.value) return
|
|
126
|
-
event.preventDefault()
|
|
127
|
-
dragOverId.value = reagent.id
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function handleDragLeave() {
|
|
131
|
-
dragOverId.value = null
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function handleDrop(event: DragEvent, targetReagent: Reagent) {
|
|
135
|
-
if (props.readonly || !props.sortable || !draggedId.value) return
|
|
136
|
-
event.preventDefault()
|
|
137
|
-
|
|
138
|
-
const reagents = [...(props.modelValue || [])]
|
|
139
|
-
const fromIndex = reagents.findIndex((r) => r.id === draggedId.value)
|
|
140
|
-
const toIndex = reagents.findIndex((r) => r.id === targetReagent.id)
|
|
141
|
-
|
|
142
|
-
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
|
|
143
|
-
draggedId.value = null
|
|
144
|
-
dragOverId.value = null
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
179
|
|
|
148
|
-
const [removed] = reagents.splice(fromIndex, 1)
|
|
149
|
-
reagents.splice(toIndex, 0, removed)
|
|
150
|
-
|
|
151
|
-
emit('reorder', draggedId.value, fromIndex, toIndex)
|
|
152
|
-
emit('update:modelValue', reagents)
|
|
153
|
-
|
|
154
|
-
draggedId.value = null
|
|
155
|
-
dragOverId.value = null
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function handleDragEnd() {
|
|
159
|
-
draggedId.value = null
|
|
160
|
-
dragOverId.value = null
|
|
161
|
-
}
|
|
162
180
|
</script>
|
|
163
181
|
|
|
164
182
|
<template>
|
|
@@ -193,7 +211,10 @@ function handleDragEnd() {
|
|
|
193
211
|
</div>
|
|
194
212
|
|
|
195
213
|
<!-- Table -->
|
|
196
|
-
<table
|
|
214
|
+
<table
|
|
215
|
+
v-if="!loading && !error && filteredReagents.length > 0"
|
|
216
|
+
class="mint-reagent-list__table"
|
|
217
|
+
>
|
|
197
218
|
<thead>
|
|
198
219
|
<tr>
|
|
199
220
|
<th v-if="sortable && !readonly" style="width: 24px" />
|
|
@@ -201,8 +222,15 @@ function handleDragEnd() {
|
|
|
201
222
|
v-for="col in columns"
|
|
202
223
|
:key="col"
|
|
203
224
|
:class="[sortable ? 'mint-reagent-list__col--sortable' : '']"
|
|
204
|
-
|
|
225
|
+
:aria-sort="columnAriaSort(col)"
|
|
205
226
|
>
|
|
227
|
+
<component
|
|
228
|
+
:is="sortable ? 'button' : 'span'"
|
|
229
|
+
:type="sortable ? 'button' : undefined"
|
|
230
|
+
class="mint-reagent-list__sort-btn"
|
|
231
|
+
@click="handleSort(col)"
|
|
232
|
+
@keydown="sortable ? handleSortKeydown($event, col) : undefined"
|
|
233
|
+
>
|
|
206
234
|
{{ columnLabels[col] }}
|
|
207
235
|
<svg
|
|
208
236
|
v-if="sortable"
|
|
@@ -229,27 +257,36 @@ function handleDragEnd() {
|
|
|
229
257
|
d="M5 15l7-7 7 7"
|
|
230
258
|
/>
|
|
231
259
|
</svg>
|
|
260
|
+
</component>
|
|
232
261
|
</th>
|
|
233
262
|
<th v-if="!readonly" style="width: 80px" />
|
|
234
263
|
</tr>
|
|
235
264
|
</thead>
|
|
236
265
|
<tbody>
|
|
237
266
|
<tr
|
|
238
|
-
v-for="reagent in filteredReagents"
|
|
267
|
+
v-for="(reagent, index) in filteredReagents"
|
|
239
268
|
:key="reagent.id"
|
|
240
269
|
:class="getRowClass(reagent)"
|
|
241
270
|
:draggable="sortable && !readonly"
|
|
242
|
-
@dragstart="
|
|
243
|
-
@dragover="
|
|
244
|
-
@dragleave="
|
|
245
|
-
@drop="
|
|
246
|
-
@dragend="
|
|
271
|
+
@dragstart="onDragStart($event, reagent, index)"
|
|
272
|
+
@dragover="onDragOver($event, reagent, index)"
|
|
273
|
+
@dragleave="onDragLeave"
|
|
274
|
+
@drop="onDrop($event, reagent, index)"
|
|
275
|
+
@dragend="onDragEnd"
|
|
247
276
|
>
|
|
248
|
-
<!-- Drag handle -->
|
|
277
|
+
<!-- Drag handle: also the keyboard reorder target (Alt+Arrow keys). -->
|
|
249
278
|
<td v-if="sortable && !readonly">
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
|
|
279
|
+
<button
|
|
280
|
+
:ref="(el) => setDragHandleRef(reagent.id, el)"
|
|
281
|
+
type="button"
|
|
282
|
+
class="mint-reagent-list__drag-handle-btn"
|
|
283
|
+
:aria-label="`Reorder ${reagent.name}. Press Alt with the arrow keys to move it.`"
|
|
284
|
+
@keydown="onReorderKeydown($event, reagent, index)"
|
|
285
|
+
>
|
|
286
|
+
<svg class="mint-reagent-list__drag-handle" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
287
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
|
|
288
|
+
</svg>
|
|
289
|
+
</button>
|
|
253
290
|
</td>
|
|
254
291
|
|
|
255
292
|
<!-- Name -->
|
|
@@ -367,26 +404,34 @@ function handleDragEnd() {
|
|
|
367
404
|
</tbody>
|
|
368
405
|
</table>
|
|
369
406
|
|
|
407
|
+
<!-- Error state -->
|
|
408
|
+
<div v-else-if="error" class="mint-reagent-list__state">
|
|
409
|
+
<slot name="error" :error="error">
|
|
410
|
+
<DataStateInternal state="error" :title="error" />
|
|
411
|
+
</slot>
|
|
412
|
+
</div>
|
|
413
|
+
|
|
414
|
+
<!-- Loading state -->
|
|
415
|
+
<div v-else-if="loading" class="mint-reagent-list__state">
|
|
416
|
+
<slot name="loading">
|
|
417
|
+
<DataStateInternal state="loading" loading-label="Loading reagents" />
|
|
418
|
+
</slot>
|
|
419
|
+
</div>
|
|
420
|
+
|
|
370
421
|
<!-- Empty state -->
|
|
371
|
-
<div v-else class="mint-reagent-
|
|
372
|
-
<
|
|
373
|
-
<
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
class="mint-reagent-list__empty-btn"
|
|
382
|
-
@click="handleAdd"
|
|
383
|
-
>
|
|
384
|
-
Add Reagent
|
|
385
|
-
</button>
|
|
422
|
+
<div v-else class="mint-reagent-list__state">
|
|
423
|
+
<slot name="empty">
|
|
424
|
+
<DataStateInternal
|
|
425
|
+
state="empty"
|
|
426
|
+
:title="searchQuery ? 'No reagents found' : 'No reagents added yet'"
|
|
427
|
+
:icon-path="EMPTY_ICON_PATH"
|
|
428
|
+
:action-label="!readonly && !searchQuery ? 'Add Reagent' : undefined"
|
|
429
|
+
@action="handleAdd"
|
|
430
|
+
/>
|
|
431
|
+
</slot>
|
|
386
432
|
</div>
|
|
433
|
+
|
|
434
|
+
<!-- Reorder announcements for screen readers -->
|
|
435
|
+
<div role="status" aria-live="polite" :style="announcerStyle">{{ reorderAnnouncement }}</div>
|
|
387
436
|
</div>
|
|
388
437
|
</template>
|
|
389
|
-
|
|
390
|
-
<style>
|
|
391
|
-
@import '../styles/components/reagent-list.css';
|
|
392
|
-
</style>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import RuntimeUpdateNotice from './RuntimeUpdateNotice.vue'
|
|
3
|
+
|
|
4
|
+
function handleReload() {
|
|
5
|
+
console.log('reload requested')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function initState() {
|
|
9
|
+
return {
|
|
10
|
+
visible: true,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Story title="Feedback/RuntimeUpdateNotice">
|
|
17
|
+
<Variant title="Playground" :init-state="initState">
|
|
18
|
+
<template #default="{ state }">
|
|
19
|
+
<!-- The notice is `position: fixed`, so it anchors to the preview
|
|
20
|
+
viewport rather than this wrapper. -->
|
|
21
|
+
<div style="padding: 2rem; min-height: 14rem; background: var(--bg-primary);">
|
|
22
|
+
<p style="margin: 0; font-size: 0.8125rem; color: var(--text-secondary);">
|
|
23
|
+
Shown after the platform detects a new frontend build.
|
|
24
|
+
</p>
|
|
25
|
+
<RuntimeUpdateNotice :visible="state.visible" @reload="handleReload" />
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<template #controls="{ state }">
|
|
30
|
+
<HstCheckbox v-model="state.visible" title="Visible" />
|
|
31
|
+
</template>
|
|
32
|
+
</Variant>
|
|
33
|
+
|
|
34
|
+
<Variant title="Visible">
|
|
35
|
+
<div style="padding: 2rem; min-height: 14rem; background: var(--bg-primary);">
|
|
36
|
+
<RuntimeUpdateNotice :visible="true" @reload="handleReload" />
|
|
37
|
+
</div>
|
|
38
|
+
</Variant>
|
|
39
|
+
|
|
40
|
+
<Variant title="Hidden">
|
|
41
|
+
<div style="padding: 2rem; min-height: 8rem; background: var(--bg-primary);">
|
|
42
|
+
<p style="margin: 0; font-size: 0.8125rem; color: var(--text-secondary);">
|
|
43
|
+
Nothing renders while <code>visible</code> is false.
|
|
44
|
+
</p>
|
|
45
|
+
<RuntimeUpdateNotice :visible="false" @reload="handleReload" />
|
|
46
|
+
</div>
|
|
47
|
+
</Variant>
|
|
48
|
+
</Story>
|
|
49
|
+
</template>
|
|
@@ -30,9 +30,9 @@ const emit = defineEmits<{
|
|
|
30
30
|
align-items: center;
|
|
31
31
|
gap: 10px;
|
|
32
32
|
padding: 10px 12px;
|
|
33
|
-
color: var(--
|
|
34
|
-
background: var(--
|
|
35
|
-
border: 1px solid var(--
|
|
33
|
+
color: var(--text-primary);
|
|
34
|
+
background: var(--bg-card);
|
|
35
|
+
border: 1px solid var(--border-color);
|
|
36
36
|
border-radius: 10px;
|
|
37
37
|
box-shadow: 0 10px 28px rgb(15 23 42 / 16%);
|
|
38
38
|
font-size: 13px;
|
|
@@ -42,7 +42,7 @@ const emit = defineEmits<{
|
|
|
42
42
|
.mint-runtime-update button {
|
|
43
43
|
padding: 5px 9px;
|
|
44
44
|
color: #fff;
|
|
45
|
-
background: var(--
|
|
45
|
+
background: var(--color-primary);
|
|
46
46
|
border: 0;
|
|
47
47
|
border-radius: 6px;
|
|
48
48
|
font: inherit;
|
|
@@ -84,6 +84,8 @@ const mockNodes: TreeNode[] = [
|
|
|
84
84
|
|
|
85
85
|
function initState() {
|
|
86
86
|
return {
|
|
87
|
+
loading: false,
|
|
88
|
+
error: '',
|
|
87
89
|
nodes: mockNodes,
|
|
88
90
|
expandAll: false,
|
|
89
91
|
showIcons: true,
|
|
@@ -99,6 +101,8 @@ function initState() {
|
|
|
99
101
|
<template #default="{ state }">
|
|
100
102
|
<div style="padding: 2rem; max-width: 500px;">
|
|
101
103
|
<SampleHierarchyTree
|
|
104
|
+
:loading="state.loading"
|
|
105
|
+
:error="state.error || null"
|
|
102
106
|
:nodes="state.nodes"
|
|
103
107
|
:expand-all="state.expandAll"
|
|
104
108
|
:show-icons="state.showIcons"
|
|
@@ -108,6 +112,8 @@ function initState() {
|
|
|
108
112
|
</div>
|
|
109
113
|
</template>
|
|
110
114
|
<template #controls="{ state }">
|
|
115
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
116
|
+
<HstText v-model="state.error" title="Error Message" />
|
|
111
117
|
<HstCheckbox v-model="state.expandAll" title="Expand All" />
|
|
112
118
|
<HstCheckbox v-model="state.showIcons" title="Show Icons" />
|
|
113
119
|
<HstCheckbox v-model="state.showCounts" title="Show Counts" />
|
|
@@ -157,5 +163,17 @@ function initState() {
|
|
|
157
163
|
<SampleHierarchyTree :nodes="[]" />
|
|
158
164
|
</div>
|
|
159
165
|
</Variant>
|
|
166
|
+
|
|
167
|
+
<Variant title="Loading">
|
|
168
|
+
<div style="padding: 2rem; max-width: 600px;">
|
|
169
|
+
<SampleHierarchyTree :nodes="[]" loading />
|
|
170
|
+
</div>
|
|
171
|
+
</Variant>
|
|
172
|
+
|
|
173
|
+
<Variant title="Error">
|
|
174
|
+
<div style="padding: 2rem; max-width: 600px;">
|
|
175
|
+
<SampleHierarchyTree :nodes="[]" error="Could not load the sample hierarchy." />
|
|
176
|
+
</div>
|
|
177
|
+
</Variant>
|
|
160
178
|
</Story>
|
|
161
179
|
</template>
|