@morscherlab/mint-sdk 1.2.0-beta.2 → 1.2.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 +65 -5
- package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-CJdNlCZb.js} +24 -15
- package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
- package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-DCXmwKNS.js} +5 -5
- package/dist/ExperimentSelectorModal-DCXmwKNS.js.map +1 -0
- package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-BYR20I4c.js} +5 -8
- package/dist/SettingsModal-BYR20I4c.js.map +1 -0
- package/dist/{EmptyState-p90quq8Z.js → Skeleton-BAF3CKY7.js} +111 -93
- package/dist/Skeleton-BAF3CKY7.js.map +1 -0
- package/dist/__tests__/components/DataStates.test.d.ts +1 -0
- package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
- package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
- package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
- package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
- package/dist/__tests__/components/PlotlyChart.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__/components/iconButtonIconSizing.test.d.ts +1 -0
- package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
- package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
- package/dist/__tests__/composables/usePlatformFilePickerAdapter.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/apiErrors.d.ts +26 -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/BaseInput.vue.d.ts +1 -1
- package/dist/components/BaseSelect.vue.d.ts +1 -1
- package/dist/components/BaseTextarea.vue.d.ts +1 -1
- package/dist/components/BatchProgressList.vue.d.ts +17 -0
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +4 -4
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
- package/dist/components/ConcentrationInput.vue.d.ts +1 -1
- package/dist/components/DataFrame.vue.d.ts +14 -2
- package/dist/components/DatePicker.vue.d.ts +2 -2
- package/dist/components/DateTimePicker.vue.d.ts +3 -1
- 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/FileBrowserModal.vue.d.ts +99 -0
- package/dist/components/FilePicker.vue.d.ts +32 -0
- package/dist/components/FileUploader.vue.d.ts +5 -2
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/FormulaInput.vue.d.ts +1 -1
- package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
- package/dist/components/JobsStatusTray.vue.d.ts +9 -2
- package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
- package/dist/components/MobileSupportGate.vue.d.ts +1 -1
- package/dist/components/MoleculeInput.vue.d.ts +1 -1
- package/dist/components/NumberInput.vue.d.ts +1 -1
- package/dist/components/PlotlyChart.vue.d.ts +59 -0
- 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/ResourceCard.vue.d.ts +1 -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/SequenceInput.vue.d.ts +1 -1
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -1
- package/dist/components/StatusIndicator.vue.d.ts +1 -1
- package/dist/components/TagsInput.vue.d.ts +1 -1
- package/dist/components/TimePicker.vue.d.ts +2 -1
- package/dist/components/TimeRangeInput.vue.d.ts +1 -1
- package/dist/components/UnitInput.vue.d.ts +1 -1
- 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 +30 -1
- package/dist/components/fileBrowserPresentation.d.ts +10 -0
- package/dist/components/index.d.ts +13 -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/FileBrowserDialogInternal.vue.d.ts +34 -0
- package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
- package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
- package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
- package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -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-DIum5hkx.js} +5882 -3200
- package/dist/components-DIum5hkx.js.map +1 -0
- package/dist/composables/controlSchemaTypes.d.ts +34 -0
- package/dist/composables/filePicker/localFiles.d.ts +3 -0
- package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
- package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
- package/dist/composables/filePicker/validation.d.ts +5 -0
- package/dist/composables/flattenWorkspaceBindings.d.ts +61 -0
- package/dist/composables/index.d.ts +11 -2
- package/dist/composables/index.js +10 -10
- package/dist/composables/pluginWorkspaceModel.d.ts +164 -0
- package/dist/composables/useApi.d.ts +14 -7
- 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/useFileBrowser.d.ts +55 -0
- package/dist/composables/useFilePicker.d.ts +189 -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/usePlatformFilePickerAdapter.d.ts +11 -0
- 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-mFXsTA4g.js} +502 -86
- package/dist/composables-mFXsTA4g.js.map +1 -0
- package/dist/{useApi-J6zFkHmn.js → errors-BLuqMee5.js} +179 -16
- package/dist/errors-BLuqMee5.js.map +1 -0
- package/dist/{experiment-Cq145oEW.js → experiment-CVDRAnqp.js} +3 -8
- package/dist/experiment-CVDRAnqp.js.map +1 -0
- package/dist/{experiment-utils-CLnzPPq5.js → experiment-utils-CV2Wza3z.js} +70 -51
- package/dist/experiment-utils-CV2Wza3z.js.map +1 -0
- package/dist/index.d.ts +2 -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 +15135 -32397
- package/dist/templates/builderReadUtils.d.ts +1 -1
- package/dist/templates/index.js +2 -4
- package/dist/{templates-DsP51i-S.js → templates-CmGfmBRA.js} +303 -106
- package/dist/templates-CmGfmBRA.js.map +1 -0
- package/dist/types/auth.d.ts +1 -0
- package/dist/types/fileBrowserTypes.d.ts +77 -0
- package/dist/types/filePicker.d.ts +77 -0
- package/dist/types/form-builder.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-DldpxNOP.js} +499 -1162
- package/dist/useControlSchema-DldpxNOP.js.map +1 -0
- package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-C7hRiVQf.js} +22 -6
- package/dist/useDropdownState-C7hRiVQf.js.map +1 -0
- package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-CEcIaueJ.js} +4 -4
- package/dist/{useExperimentSelector-CV4iNfMS.js.map → useExperimentSelector-CEcIaueJ.js.map} +1 -1
- package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-z5L_dUIy.js} +2 -2
- package/dist/{useFormBuilder-BLxG3BOX.js.map → useFormBuilder-z5L_dUIy.js.map} +1 -1
- 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/dist/{useProtocolTemplates-CS_SQl6U.js → validation-uwoJGEb6.js} +811 -212
- package/dist/validation-uwoJGEb6.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/apiErrors.test.ts +81 -0
- 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/ExperimentPopover.test.ts +30 -0
- package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
- package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
- package/src/__tests__/components/FilePicker.state.test.ts +287 -0
- package/src/__tests__/components/FilePicker.test.ts +487 -0
- package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
- package/src/__tests__/components/GroupAssigner.test.ts +53 -0
- package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
- package/src/__tests__/components/PlotlyChart.test.ts +305 -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 +107 -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__/components/iconButtonIconSizing.test.ts +18 -0
- package/src/__tests__/composables/useApi.test.ts +92 -9
- package/src/__tests__/composables/useAuth.test.ts +2 -0
- package/src/__tests__/composables/useDropdownState.test.ts +58 -1
- package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
- package/src/__tests__/composables/useListReorder.test.ts +145 -0
- package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
- package/src/__tests__/composables/usePluginClient.test.ts +143 -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/apiErrors.ts +85 -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 +12 -7
- 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/FileBrowserModal.story.vue +203 -0
- package/src/components/FileBrowserModal.vue +384 -0
- package/src/components/FilePicker.story.vue +44 -0
- package/src/components/FilePicker.vue +284 -0
- package/src/components/FileUploader.vue +32 -18
- 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 +34 -69
- 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 -9
- 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/PlotlyChart.story.vue +61 -0
- package/src/components/PlotlyChart.vue +233 -0
- 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 +50 -7
- 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/fileBrowserPresentation.ts +39 -0
- package/src/components/index.ts +14 -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/FileBrowserDialogInternal.vue +75 -0
- package/src/components/internal/FileBrowserListingInternal.vue +197 -0
- package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
- package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
- package/src/components/internal/FilePickerTreeInternal.vue +238 -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/filePicker/localFiles.ts +58 -0
- package/src/composables/filePicker/usePickerNavigation.ts +220 -0
- package/src/composables/filePicker/usePickerSelection.ts +259 -0
- package/src/composables/filePicker/validation.ts +41 -0
- package/src/composables/flattenWorkspaceBindings.ts +104 -0
- package/src/composables/formBuilderRegistry.ts +5 -0
- package/src/composables/index.ts +50 -0
- package/src/composables/pluginWorkspaceModel.ts +182 -0
- package/src/composables/useApi.ts +57 -13
- 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/useFileBrowser.ts +314 -0
- package/src/composables/useFileImport.ts +2 -7
- package/src/composables/useFilePicker.ts +366 -0
- package/src/composables/useFocusTrap.ts +91 -0
- package/src/composables/useGeneratedAnalysis.ts +32 -27
- 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/usePlatformFilePickerAdapter.ts +104 -0
- package/src/composables/usePluginClient.ts +50 -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 +19 -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/file-browser-modal.css +489 -0
- package/src/styles/components/file-picker.css +502 -0
- package/src/styles/components/form-builder.css +5 -5
- package/src/styles/components/icon-button.css +9 -0
- 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 +12 -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/fileBrowserTypes.ts +85 -0
- package/src/types/filePicker.ts +72 -0
- package/src/types/form-builder.ts +1 -0
- package/src/types/index.ts +14 -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 → apiErrors.test.d.ts} +0 -0
|
@@ -37,8 +37,67 @@ export const WELL_PLATE_SIZE_CONFIGS: Record<WellPlateSize, WellPlateSizeConfig>
|
|
|
37
37
|
fill: { cellWidth: '100%', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '2px' },
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Spreadsheet-style row label for a zero-based row index: A…Z, then AA, AB, …
|
|
42
|
+
*
|
|
43
|
+
* This is the single row-label generator for the SDK — plate grids, rack
|
|
44
|
+
* grids, well-id parsing and the template builders all go through it.
|
|
45
|
+
*/
|
|
46
|
+
export function rowLabel(index: number): string {
|
|
47
|
+
let label = ''
|
|
48
|
+
let current = index
|
|
49
|
+
for (;;) {
|
|
50
|
+
label = String.fromCharCode(65 + (current % 26)) + label
|
|
51
|
+
current = Math.floor(current / 26) - 1
|
|
52
|
+
if (current < 0) return label
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Inverse of {@link rowLabel}: 'A' → 0, 'Z' → 25, 'AA' → 26. */
|
|
57
|
+
export function rowIndex(label: string): number {
|
|
58
|
+
return [...label].reduce((value, char) => value * 26 + char.charCodeAt(0) - 64, 0) - 1
|
|
59
|
+
}
|
|
60
|
+
|
|
40
61
|
export function createPlateRowLabels(config: WellPlateConfig): string[] {
|
|
41
|
-
return Array.from({ length: config.rows }, (_, index) =>
|
|
62
|
+
return Array.from({ length: config.rows }, (_, index) => rowLabel(index))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function plateConfigOrThrow(format: number): WellPlateConfig {
|
|
66
|
+
const config = PLATE_CONFIGS[format as WellPlateFormat]
|
|
67
|
+
if (!config) throw new Error(`Unsupported plate format '${format}'.`)
|
|
68
|
+
return config
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Every well id of a plate, row-major (A1, A2, … B1, …). */
|
|
72
|
+
export function wellIdsForFormat(format: number): string[] {
|
|
73
|
+
const { rows, cols } = plateConfigOrThrow(format)
|
|
74
|
+
return Array.from({ length: rows }, (_, row) =>
|
|
75
|
+
Array.from({ length: cols }, (_col, col) => `${rowLabel(row)}${col + 1}`)
|
|
76
|
+
).flat()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Throw unless `wellId` names a well that exists on a `format`-well plate. */
|
|
80
|
+
export function assertWellInFormat(wellId: string, format: number): void {
|
|
81
|
+
const { rows, cols } = plateConfigOrThrow(format)
|
|
82
|
+
const match = /^([A-Z]+)([1-9][0-9]*)$/.exec(wellId.toUpperCase())
|
|
83
|
+
if (!match) {
|
|
84
|
+
throw new Error(`Invalid well id '${wellId}'.`)
|
|
85
|
+
}
|
|
86
|
+
const row = rowIndex(match[1])
|
|
87
|
+
const col = Number(match[2]) - 1
|
|
88
|
+
if (row < 0 || col < 0 || row >= rows || col >= cols) {
|
|
89
|
+
throw new Error(`Well '${wellId}' is outside a ${format}-well plate.`)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Coerce an unknown value to a supported plate format, else `fallback`. */
|
|
94
|
+
export function readPlateFormat(value: unknown, fallback: WellPlateFormat): WellPlateFormat {
|
|
95
|
+
const parsed = typeof value === 'number'
|
|
96
|
+
? value
|
|
97
|
+
: typeof value === 'string'
|
|
98
|
+
? Number(value)
|
|
99
|
+
: Number.NaN
|
|
100
|
+
return parsed in PLATE_CONFIGS ? (parsed as WellPlateFormat) : fallback
|
|
42
101
|
}
|
|
43
102
|
|
|
44
103
|
export function createPlateColumnLabels(config: WellPlateConfig): number[] {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type WellPlateCoordinate,
|
|
12
12
|
} from './WellPlate.geometry'
|
|
13
13
|
import { parseDroppedSampleTransfer } from './WellPlate.sampleDrop'
|
|
14
|
+
import { useReorderAnnouncer } from '../composables/useListReorder'
|
|
14
15
|
|
|
15
16
|
export interface WellPlateInteractionOptions {
|
|
16
17
|
modelValue: () => string[]
|
|
@@ -64,6 +65,7 @@ export function useWellPlateInteraction(options: WellPlateInteractionOptions) {
|
|
|
64
65
|
const hoveredWell = ref<string | null>(null)
|
|
65
66
|
const editingWellId = ref<string | null>(null)
|
|
66
67
|
const editPopupPosition = ref({ x: 0, y: 0 })
|
|
68
|
+
const { announcement, announce, announcerStyle } = useReorderAnnouncer()
|
|
67
69
|
|
|
68
70
|
const selectedWellSet = computed(() => new Set(options.modelValue()))
|
|
69
71
|
|
|
@@ -215,6 +217,45 @@ export function useWellPlateInteraction(options: WellPlateInteractionOptions) {
|
|
|
215
217
|
dragTargetWell.value = null
|
|
216
218
|
}
|
|
217
219
|
|
|
220
|
+
// Keyboard alternative to the well-to-well drag. The plate is a 2D grid, not a
|
|
221
|
+
// list, so it cannot use `useListReorder`'s index maths: instead Alt+Enter (or
|
|
222
|
+
// Alt+Space) picks a filled well up, the same chord on another well drops it
|
|
223
|
+
// there, and Escape cancels. Every step is announced politely.
|
|
224
|
+
function handleWellMoveKeydown(well: Well, event: KeyboardEvent) {
|
|
225
|
+
if (options.disabled() || options.readonly() || options.selectionMode() !== 'drag') return
|
|
226
|
+
|
|
227
|
+
if (event.key === 'Escape' && dragSourceWell.value) {
|
|
228
|
+
event.preventDefault()
|
|
229
|
+
announce(`Move cancelled. ${dragSourceWell.value} stays in place.`)
|
|
230
|
+
dragSourceWell.value = null
|
|
231
|
+
dragTargetWell.value = null
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!event.altKey || (event.key !== 'Enter' && event.key !== ' ')) return
|
|
236
|
+
event.preventDefault()
|
|
237
|
+
|
|
238
|
+
const source = dragSourceWell.value
|
|
239
|
+
if (!source) {
|
|
240
|
+
if (!well.sampleType) {
|
|
241
|
+
announce(`Well ${well.id} is empty and cannot be moved.`)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
dragSourceWell.value = well.id
|
|
245
|
+
announce(`Well ${well.id} picked up. Move to another well and press Alt and Enter to drop it.`)
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (source !== well.id) {
|
|
250
|
+
options.emitWellMove(source, well.id)
|
|
251
|
+
announce(`Well ${source} moved to ${well.id}.`)
|
|
252
|
+
} else {
|
|
253
|
+
announce(`Move cancelled. ${source} stays in place.`)
|
|
254
|
+
}
|
|
255
|
+
dragSourceWell.value = null
|
|
256
|
+
dragTargetWell.value = null
|
|
257
|
+
}
|
|
258
|
+
|
|
218
259
|
function parseDroppedSample(event: DragEvent, wellId: string): WellSampleDropData | null {
|
|
219
260
|
const customParser = options.sampleDropParser()
|
|
220
261
|
if (customParser) return customParser(event, { wellId, event }) ?? null
|
|
@@ -267,6 +308,9 @@ export function useWellPlateInteraction(options: WellPlateInteractionOptions) {
|
|
|
267
308
|
handleDragLeave,
|
|
268
309
|
handleDrop,
|
|
269
310
|
handleDragEnd,
|
|
311
|
+
handleWellMoveKeydown,
|
|
270
312
|
handleKeyDown,
|
|
313
|
+
moveAnnouncement: announcement,
|
|
314
|
+
moveAnnouncerStyle: announcerStyle,
|
|
271
315
|
}
|
|
272
316
|
}
|
|
@@ -121,6 +121,8 @@ const doseWells = generateDoseWells()
|
|
|
121
121
|
|
|
122
122
|
function initState() {
|
|
123
123
|
return {
|
|
124
|
+
loading: false,
|
|
125
|
+
error: '',
|
|
124
126
|
format: 96 as WellPlateFormat,
|
|
125
127
|
selectionMode: 'multiple' as WellPlateSelectionMode,
|
|
126
128
|
size: 'md' as WellPlateSize,
|
|
@@ -141,6 +143,8 @@ function initState() {
|
|
|
141
143
|
<template #default="{ state }">
|
|
142
144
|
<div style="padding: 2rem;">
|
|
143
145
|
<WellPlate
|
|
146
|
+
:loading="state.loading"
|
|
147
|
+
:error="state.error || null"
|
|
144
148
|
v-model="selectedWells"
|
|
145
149
|
:format="state.format"
|
|
146
150
|
:wells="generateMockWells(state.format)"
|
|
@@ -161,6 +165,10 @@ function initState() {
|
|
|
161
165
|
</template>
|
|
162
166
|
|
|
163
167
|
<template #controls="{ state }">
|
|
168
|
+
|
|
169
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
170
|
+
|
|
171
|
+
<HstText v-model="state.error" title="Error Message" />
|
|
164
172
|
<HstSelect
|
|
165
173
|
v-model="state.format"
|
|
166
174
|
title="Format"
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
wellStyle,
|
|
33
33
|
} from './WellPlate.rendering'
|
|
34
34
|
import { DEFAULT_WELL_LEGEND_ITEMS } from './WellPlate.legend'
|
|
35
|
+
import DataStateInternal from './internal/DataStateInternal.vue'
|
|
35
36
|
|
|
36
37
|
interface Props {
|
|
37
38
|
modelValue?: string[]
|
|
@@ -59,6 +60,19 @@ interface Props {
|
|
|
59
60
|
rowConditions?: RowCondition[]
|
|
60
61
|
allowSampleDrop?: boolean
|
|
61
62
|
sampleDropParser?: WellSampleDropParser
|
|
63
|
+
/** Replace the plate grid with a loading placeholder. */
|
|
64
|
+
loading?: boolean
|
|
65
|
+
/**
|
|
66
|
+
* Error message. When set, the plate grid is replaced by an error state.
|
|
67
|
+
* `null`/`undefined` renders normally.
|
|
68
|
+
*/
|
|
69
|
+
error?: string | null
|
|
70
|
+
/**
|
|
71
|
+
* Opt-in empty-state headline. A blank plate is meaningful, so the empty
|
|
72
|
+
* state only replaces the grid when this message is supplied and no wells
|
|
73
|
+
* carry data.
|
|
74
|
+
*/
|
|
75
|
+
emptyMessage?: string
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -114,6 +128,12 @@ interface WellEditorSlotProps {
|
|
|
114
128
|
|
|
115
129
|
defineSlots<{
|
|
116
130
|
'well-editor'?: (props: WellEditorSlotProps) => unknown
|
|
131
|
+
/** Replaces the default loading placeholder. */
|
|
132
|
+
loading?: () => unknown
|
|
133
|
+
/** Replaces the default error placeholder. */
|
|
134
|
+
error?: (props: { error: string }) => unknown
|
|
135
|
+
/** Replaces the default empty placeholder. */
|
|
136
|
+
empty?: () => unknown
|
|
117
137
|
}>()
|
|
118
138
|
|
|
119
139
|
const plateRef = ref<HTMLElement | null>(null)
|
|
@@ -166,7 +186,10 @@ const {
|
|
|
166
186
|
handleDragLeave,
|
|
167
187
|
handleDrop,
|
|
168
188
|
handleDragEnd,
|
|
189
|
+
handleWellMoveKeydown,
|
|
169
190
|
handleKeyDown,
|
|
191
|
+
moveAnnouncement,
|
|
192
|
+
moveAnnouncerStyle,
|
|
170
193
|
} = useWellPlateInteraction({
|
|
171
194
|
modelValue: () => props.modelValue,
|
|
172
195
|
selectionMode: () => props.selectionMode,
|
|
@@ -233,6 +256,11 @@ const containerStyle = computed(() =>
|
|
|
233
256
|
}
|
|
234
257
|
)
|
|
235
258
|
|
|
259
|
+
/** Empty state is opt-in: it needs an `emptyMessage` and a plate with no well data. */
|
|
260
|
+
const showEmptyState = computed(() =>
|
|
261
|
+
Boolean(props.emptyMessage) && Object.keys(props.wells).length === 0,
|
|
262
|
+
)
|
|
263
|
+
|
|
236
264
|
const tableStyle = computed(() => ({
|
|
237
265
|
borderCollapse: 'separate' as const,
|
|
238
266
|
borderSpacing: sizeConfig.value.gap,
|
|
@@ -246,7 +274,25 @@ const tableStyle = computed(() => ({
|
|
|
246
274
|
:class="['mint-well-plate', isFillMode ? 'mint-well-plate--fill' : 'mint-well-plate--inline']"
|
|
247
275
|
:style="containerStyle"
|
|
248
276
|
>
|
|
249
|
-
<div class="mint-well-
|
|
277
|
+
<div v-if="error" class="mint-well-plate__state">
|
|
278
|
+
<slot name="error" :error="error">
|
|
279
|
+
<DataStateInternal state="error" :title="error" />
|
|
280
|
+
</slot>
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<div v-else-if="loading" class="mint-well-plate__state">
|
|
284
|
+
<slot name="loading">
|
|
285
|
+
<DataStateInternal state="loading" loading-label="Loading plate" />
|
|
286
|
+
</slot>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div v-else-if="showEmptyState" class="mint-well-plate__state">
|
|
290
|
+
<slot name="empty">
|
|
291
|
+
<DataStateInternal state="empty" :title="emptyMessage" />
|
|
292
|
+
</slot>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<div v-else class="mint-well-plate__scroll">
|
|
250
296
|
<div class="mint-well-plate__content">
|
|
251
297
|
<table
|
|
252
298
|
ref="tableRef"
|
|
@@ -390,8 +436,9 @@ const tableStyle = computed(() => ({
|
|
|
390
436
|
@dragleave="handleDragLeave"
|
|
391
437
|
@drop="handleDrop(well, $event)"
|
|
392
438
|
@dragend="handleDragEnd"
|
|
393
|
-
@keydown
|
|
394
|
-
@keydown.
|
|
439
|
+
@keydown="handleWellMoveKeydown(well, $event)"
|
|
440
|
+
@keydown.enter.exact="handleWellClick(well, $event as unknown as MouseEvent)"
|
|
441
|
+
@keydown.space.exact.prevent="handleWellClick(well, $event as unknown as MouseEvent)"
|
|
395
442
|
>
|
|
396
443
|
<!-- Well label text (from metadata.label) -->
|
|
397
444
|
<span
|
|
@@ -489,9 +536,8 @@ const tableStyle = computed(() => ({
|
|
|
489
536
|
/>
|
|
490
537
|
</slot>
|
|
491
538
|
</template>
|
|
539
|
+
|
|
540
|
+
<!-- Keyboard well-move announcements for screen readers -->
|
|
541
|
+
<div role="status" aria-live="polite" :style="moveAnnouncerStyle">{{ moveAnnouncement }}</div>
|
|
492
542
|
</div>
|
|
493
543
|
</template>
|
|
494
|
-
|
|
495
|
-
<style>
|
|
496
|
-
@import '../styles/components/well-plate.css';
|
|
497
|
-
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FileEntry } from '../types/fileBrowserTypes'
|
|
2
|
+
|
|
3
|
+
export const FILE_BROWSER_ICONS = {
|
|
4
|
+
disk: 'M4 5h16v14H4zM8 9h.01M4 12h16',
|
|
5
|
+
folder: 'M4 7h6l2 2h8v10H4z',
|
|
6
|
+
file: 'M14 3v5h5M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function formatCount(value: number): string {
|
|
10
|
+
// Thin spaces group digits without the comma/period ambiguity across locales.
|
|
11
|
+
return value.toLocaleString('en-US').replace(/,/g, ' ')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatSize(entry: FileEntry): string {
|
|
15
|
+
if (entry.kind === 'directory') {
|
|
16
|
+
return entry.child_count === null || entry.child_count === undefined
|
|
17
|
+
? '—'
|
|
18
|
+
: `${entry.child_count} item${entry.child_count === 1 ? '' : 's'}`
|
|
19
|
+
}
|
|
20
|
+
return formatBytes(entry.size_bytes ?? null)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function formatBytes(bytes: number | null): string {
|
|
24
|
+
if (bytes === null) return '—'
|
|
25
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
26
|
+
let value = bytes
|
|
27
|
+
let unit = 0
|
|
28
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
29
|
+
value /= 1024
|
|
30
|
+
unit += 1
|
|
31
|
+
}
|
|
32
|
+
const rounded = value >= 100 || unit === 0 ? Math.round(value) : Number(value.toFixed(1))
|
|
33
|
+
return `${rounded} ${units[unit]}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function entryType(entry: FileEntry): string {
|
|
37
|
+
if (entry.kind === 'directory') return 'Folder'
|
|
38
|
+
return entry.extension ? entry.extension.replace('.', '').toUpperCase() : 'File'
|
|
39
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -7,12 +7,14 @@ export { default as BaseCheckbox } from './BaseCheckbox.vue'
|
|
|
7
7
|
export { default as BaseToggle } from './BaseToggle.vue'
|
|
8
8
|
export { default as BaseRadioGroup } from './BaseRadioGroup.vue'
|
|
9
9
|
export { default as BaseSlider } from './BaseSlider.vue'
|
|
10
|
+
/** Range slider with a gradient color track and color-coded value badge for threshold visualization. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; use `BaseSlider` instead. */
|
|
10
11
|
export { default as ColorSlider } from './ColorSlider.vue'
|
|
11
12
|
export { default as BaseTabs } from './BaseTabs.vue'
|
|
12
13
|
export { default as BaseModal } from './BaseModal.vue'
|
|
13
14
|
export { default as SegmentedControl } from './SegmentedControl.vue'
|
|
14
15
|
export { default as MultiSelect } from './MultiSelect.vue'
|
|
15
16
|
export { default as BasePill } from './BasePill.vue'
|
|
17
|
+
/** Button that opens a dropdown menu for selecting one option from a list. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; use `ActionMenu` instead. */
|
|
16
18
|
export { default as DropdownButton } from './DropdownButton.vue'
|
|
17
19
|
export { default as Calendar } from './Calendar.vue'
|
|
18
20
|
export { default as DataFrame } from './DataFrame.vue'
|
|
@@ -22,6 +24,7 @@ export { default as FormField } from './FormField.vue'
|
|
|
22
24
|
export { default as DatePicker } from './DatePicker.vue'
|
|
23
25
|
export { default as TimePicker } from './TimePicker.vue'
|
|
24
26
|
export { default as TagsInput } from './TagsInput.vue'
|
|
27
|
+
export { default as SecretInput } from './SecretInput.vue'
|
|
25
28
|
export { default as NumberInput } from './NumberInput.vue'
|
|
26
29
|
export { default as FileUploader } from './FileUploader.vue'
|
|
27
30
|
|
|
@@ -96,12 +99,17 @@ export { default as SampleHierarchyTree } from './SampleHierarchyTree.vue'
|
|
|
96
99
|
export { default as ProtocolStepEditor } from './ProtocolStepEditor.vue'
|
|
97
100
|
|
|
98
101
|
// Scientific display components
|
|
102
|
+
export { default as PlotlyChart } from './PlotlyChart.vue'
|
|
99
103
|
export { default as ScientificNumber } from './ScientificNumber.vue'
|
|
104
|
+
/** Renders a chemical formula string (H₂O, C₆H₁₂O₆, Ca(OH)₂) with typographically correct subscripts and superscripts for charges. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; no platform replacement is planned. */
|
|
100
105
|
export { default as ChemicalFormula } from './ChemicalFormula.vue'
|
|
101
106
|
export { default as SequenceProgressBar } from './SequenceProgressBar.vue'
|
|
107
|
+
/** Filterable instrument alert/event list keyed by each alert's required stable event_key. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; instrument UI moves to the mld-ms plugins. */
|
|
102
108
|
export { default as InstrumentAlertLog } from './InstrumentAlertLog.vue'
|
|
103
109
|
export { default as InstrumentStateBadge } from './InstrumentStateBadge.vue'
|
|
110
|
+
/** Compact card for live instrument monitor status, sample, method, sequence progress, and ETA. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; instrument UI moves to the mld-ms plugins. */
|
|
104
111
|
export { default as InstrumentStatusCard } from './InstrumentStatusCard.vue'
|
|
112
|
+
/** Table for Xcalibur-compatible LCMS sequence rows with optional reorder/remove/duplicate controls. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; instrument UI moves to the mld-ms plugins. */
|
|
105
113
|
export { default as LcmsSequenceTable } from './LcmsSequenceTable.vue'
|
|
106
114
|
|
|
107
115
|
// Scientific input components
|
|
@@ -125,15 +133,21 @@ export { default as ExperimentCodeBadge } from './ExperimentCodeBadge.vue'
|
|
|
125
133
|
|
|
126
134
|
// Scheduling / booking components
|
|
127
135
|
export { default as DateTimePicker } from './DateTimePicker.vue'
|
|
136
|
+
/** Paired start/end time pickers that validate range order and display computed duration. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; use `TimePicker` instead. */
|
|
128
137
|
export { default as TimeRangeInput } from './TimeRangeInput.vue'
|
|
129
138
|
export { default as ScheduleCalendar } from './ScheduleCalendar.vue'
|
|
139
|
+
/** Card displaying a lab resource with availability status, specs, tags, and a book action. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; no platform replacement is planned. */
|
|
130
140
|
export { default as ResourceCard } from './ResourceCard.vue'
|
|
131
141
|
export { default as SectionCard } from './SectionCard.vue'
|
|
132
142
|
|
|
133
143
|
// Experiment / analysis components
|
|
134
144
|
export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue'
|
|
135
145
|
export { default as ArtifactSelectorModal } from './ArtifactSelectorModal.vue'
|
|
146
|
+
/** Modal picker over the read-only server mounts, recording paths rather than copying data. */
|
|
147
|
+
export { default as FileBrowserModal } from './FileBrowserModal.vue'
|
|
136
148
|
export { default as GeneratedPathInput } from './GeneratedPathInput.vue'
|
|
137
149
|
export { default as ArtifactSaveDialog } from './ArtifactSaveDialog.vue'
|
|
138
150
|
export { default as ExperimentPopover } from './ExperimentPopover.vue'
|
|
139
151
|
export { default as FitPanel } from './FitPanel.vue'
|
|
152
|
+
|
|
153
|
+
export { default as FilePicker } from './FilePicker.vue'
|
|
@@ -24,7 +24,7 @@ const emit = defineEmits<{
|
|
|
24
24
|
select: [page: PageSelectorItem]
|
|
25
25
|
}>()
|
|
26
26
|
|
|
27
|
-
const { isOpen, rootRef, close, toggle } = useDropdownState()
|
|
27
|
+
const { isOpen, rootRef, triggerRef, close, toggle } = useDropdownState()
|
|
28
28
|
const normalizedPages = computed<PageSelectorItem[]>(() => props.pages.map(normalizeItemInput))
|
|
29
29
|
|
|
30
30
|
const current = computed<PageSelectorItem | undefined>(() =>
|
|
@@ -45,6 +45,7 @@ function handleSelect(page: PageSelectorItem) {
|
|
|
45
45
|
<template>
|
|
46
46
|
<div ref="rootRef" class="mint-page-selector" :style="{ minWidth }">
|
|
47
47
|
<button
|
|
48
|
+
ref="triggerRef"
|
|
48
49
|
type="button"
|
|
49
50
|
class="mint-page-selector__trigger"
|
|
50
51
|
:class="{ 'mint-page-selector__trigger--open': isOpen }"
|
|
@@ -121,7 +122,3 @@ function handleSelect(page: PageSelectorItem) {
|
|
|
121
122
|
</div>
|
|
122
123
|
</div>
|
|
123
124
|
</template>
|
|
124
|
-
|
|
125
|
-
<style>
|
|
126
|
-
@import '../../styles/components/app-page-selector.css';
|
|
127
|
-
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Shared loading / error / empty presentation for the SDK data components.
|
|
4
|
+
*
|
|
5
|
+
* Internal: not exported from the package entrypoints. Data components render
|
|
6
|
+
* this instead of hand-rolling their own placeholder markup so that the
|
|
7
|
+
* loading, error and empty states look the same everywhere.
|
|
8
|
+
*/
|
|
9
|
+
import { computed } from 'vue'
|
|
10
|
+
import EmptyState from '../EmptyState.vue'
|
|
11
|
+
import LoadingSpinner from '../LoadingSpinner.vue'
|
|
12
|
+
|
|
13
|
+
/** Single-path warning triangle used for the error state. */
|
|
14
|
+
const ERROR_ICON_PATH
|
|
15
|
+
= 'M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'
|
|
16
|
+
+ 'M12 9v4M12 17h.01'
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Which of the three placeholder states to render. */
|
|
20
|
+
state: 'loading' | 'error' | 'empty'
|
|
21
|
+
/** Headline for the empty/error state. */
|
|
22
|
+
title?: string
|
|
23
|
+
/** Supporting copy for the empty/error state. */
|
|
24
|
+
description?: string
|
|
25
|
+
/** Custom `<path d>` for the empty state icon (the error state has its own). */
|
|
26
|
+
iconPath?: string
|
|
27
|
+
/** Placeholder scale; also drives the loading spinner size. */
|
|
28
|
+
size?: 'sm' | 'md' | 'lg'
|
|
29
|
+
/** `EmptyState` layout variant. */
|
|
30
|
+
variant?: 'illustrated' | 'inline'
|
|
31
|
+
/** Accessible label (and visible caption) for the loading state. */
|
|
32
|
+
loadingLabel?: string
|
|
33
|
+
/** Optional call-to-action rendered under the empty/error copy. */
|
|
34
|
+
actionLabel?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
38
|
+
size: 'md',
|
|
39
|
+
variant: 'illustrated',
|
|
40
|
+
loadingLabel: 'Loading',
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const emit = defineEmits<{
|
|
44
|
+
action: []
|
|
45
|
+
}>()
|
|
46
|
+
|
|
47
|
+
const spinnerSize = computed(() => (props.size === 'sm' ? 'sm' : props.size === 'lg' ? 'lg' : 'md'))
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<div
|
|
52
|
+
:class="['mint-data-state', `mint-data-state--${state}`, `mint-data-state--${size}`]"
|
|
53
|
+
:data-state="state"
|
|
54
|
+
>
|
|
55
|
+
<template v-if="state === 'loading'">
|
|
56
|
+
<LoadingSpinner :size="spinnerSize" :label="loadingLabel" />
|
|
57
|
+
<p class="mint-data-state__loading-text" aria-hidden="true">{{ loadingLabel }}</p>
|
|
58
|
+
</template>
|
|
59
|
+
<EmptyState
|
|
60
|
+
v-else
|
|
61
|
+
:title="title"
|
|
62
|
+
:description="description"
|
|
63
|
+
:icon-path="state === 'error' ? ERROR_ICON_PATH : iconPath"
|
|
64
|
+
:color="state === 'error' ? 'error' : 'muted'"
|
|
65
|
+
:size="size"
|
|
66
|
+
:variant="variant"
|
|
67
|
+
:action-label="actionLabel"
|
|
68
|
+
@action="emit('action')"
|
|
69
|
+
>
|
|
70
|
+
<slot />
|
|
71
|
+
</EmptyState>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onBeforeUnmount, onMounted, shallowRef, watch } from 'vue'
|
|
3
|
+
import type { ModalSize } from '../../types'
|
|
4
|
+
import { useFocusTrap } from '../../composables/useFocusTrap'
|
|
5
|
+
import IconButton from '../IconButton.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{ open: boolean; label: string; size: ModalSize; variant?: 'picker' }>()
|
|
8
|
+
const emit = defineEmits<{ close: [] }>()
|
|
9
|
+
const containerRef = shallowRef<HTMLElement | null>(null)
|
|
10
|
+
const active = shallowRef(false)
|
|
11
|
+
useFocusTrap({ containerRef, active })
|
|
12
|
+
|
|
13
|
+
// Activate after mounting so an initially open picker traps focus too.
|
|
14
|
+
onMounted(() => {
|
|
15
|
+
active.value = props.open
|
|
16
|
+
})
|
|
17
|
+
watch(
|
|
18
|
+
() => props.open,
|
|
19
|
+
(open) => {
|
|
20
|
+
active.value = open
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
watch(
|
|
24
|
+
active,
|
|
25
|
+
(open, _, onCleanup) => {
|
|
26
|
+
if (!open) return
|
|
27
|
+
const overflow = document.body.style.overflow
|
|
28
|
+
document.body.style.overflow = 'hidden'
|
|
29
|
+
onCleanup(() => {
|
|
30
|
+
document.body.style.overflow = overflow
|
|
31
|
+
})
|
|
32
|
+
},
|
|
33
|
+
{ flush: 'sync' },
|
|
34
|
+
)
|
|
35
|
+
onBeforeUnmount(() => {
|
|
36
|
+
active.value = false
|
|
37
|
+
})
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<Teleport to="body">
|
|
42
|
+
<div v-if="open" class="mint-file-browser-overlay">
|
|
43
|
+
<section
|
|
44
|
+
ref="containerRef"
|
|
45
|
+
class="mint-file-browser-dialog"
|
|
46
|
+
:class="[
|
|
47
|
+
`mint-file-browser-dialog--${size}`,
|
|
48
|
+
variant === 'picker' ? 'mint-picker-dialog' : '',
|
|
49
|
+
]"
|
|
50
|
+
role="dialog"
|
|
51
|
+
aria-modal="true"
|
|
52
|
+
:aria-label="label"
|
|
53
|
+
tabindex="-1"
|
|
54
|
+
@keydown.esc.stop.prevent="emit('close')"
|
|
55
|
+
>
|
|
56
|
+
<header class="mint-file-browser-dialog__header">
|
|
57
|
+
<slot name="header" />
|
|
58
|
+
<IconButton size="sm" label="Close modal" @click="emit('close')">
|
|
59
|
+
<svg
|
|
60
|
+
viewBox="0 0 24 24"
|
|
61
|
+
fill="none"
|
|
62
|
+
stroke="currentColor"
|
|
63
|
+
stroke-width="2"
|
|
64
|
+
aria-hidden="true"
|
|
65
|
+
>
|
|
66
|
+
<path d="M6 6l12 12M18 6L6 18" />
|
|
67
|
+
</svg>
|
|
68
|
+
</IconButton>
|
|
69
|
+
</header>
|
|
70
|
+
<slot />
|
|
71
|
+
<footer class="mint-file-browser-dialog__footer"><slot name="footer" /></footer>
|
|
72
|
+
</section>
|
|
73
|
+
</div>
|
|
74
|
+
</Teleport>
|
|
75
|
+
</template>
|