@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
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Demonstrates `useListReorder`: drag a row, or focus a handle and press Alt with the arrow keys. */
|
|
3
|
+
import { ref } from 'vue'
|
|
4
|
+
import { useListReorder } from './useListReorder'
|
|
5
|
+
|
|
6
|
+
interface Step { id: string; name: string }
|
|
7
|
+
|
|
8
|
+
const steps = ref<Step[]>([
|
|
9
|
+
{ id: 's1', name: 'Thaw samples' },
|
|
10
|
+
{ id: 's2', name: 'Quench metabolism' },
|
|
11
|
+
{ id: 's3', name: 'Extract metabolites' },
|
|
12
|
+
{ id: 's4', name: 'Dry down' },
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
const handles = new Map<string, HTMLElement>()
|
|
16
|
+
|
|
17
|
+
function setHandle(id: string, el: Element | null) {
|
|
18
|
+
if (el instanceof HTMLElement) handles.set(id, el)
|
|
19
|
+
else handles.delete(id)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
draggingId,
|
|
24
|
+
dragOverId,
|
|
25
|
+
announcement,
|
|
26
|
+
announcerStyle,
|
|
27
|
+
onDragStart,
|
|
28
|
+
onDragOver,
|
|
29
|
+
onDragLeave,
|
|
30
|
+
onDrop,
|
|
31
|
+
onDragEnd,
|
|
32
|
+
onKeydown,
|
|
33
|
+
} = useListReorder<Step>({
|
|
34
|
+
items: () => steps.value,
|
|
35
|
+
getId: (step) => step.id,
|
|
36
|
+
getLabel: (step) => step.name,
|
|
37
|
+
getElement: (id) => handles.get(id),
|
|
38
|
+
itemNoun: 'Step',
|
|
39
|
+
onReorder: ({ items }) => {
|
|
40
|
+
steps.value = items
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function initState() {
|
|
45
|
+
return { showAnnouncement: true }
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<Story title="Composables/useListReorder">
|
|
51
|
+
<Variant title="Playground" :init-state="initState">
|
|
52
|
+
<template #default="{ state }">
|
|
53
|
+
<div style="padding: 2rem; max-width: 600px;">
|
|
54
|
+
<p class="mint-story-hint">
|
|
55
|
+
Drag a row, or focus its handle and press Alt with the up/down arrow keys.
|
|
56
|
+
</p>
|
|
57
|
+
<ul class="mint-story-list">
|
|
58
|
+
<li
|
|
59
|
+
v-for="(step, index) in steps"
|
|
60
|
+
:key="step.id"
|
|
61
|
+
class="mint-story-row"
|
|
62
|
+
:class="{
|
|
63
|
+
'mint-story-row--dragging': draggingId === step.id,
|
|
64
|
+
'mint-story-row--over': dragOverId === step.id,
|
|
65
|
+
}"
|
|
66
|
+
draggable="true"
|
|
67
|
+
@dragstart="onDragStart($event, step, index)"
|
|
68
|
+
@dragover="onDragOver($event, step, index)"
|
|
69
|
+
@dragleave="onDragLeave"
|
|
70
|
+
@drop="onDrop($event, step, index)"
|
|
71
|
+
@dragend="onDragEnd"
|
|
72
|
+
>
|
|
73
|
+
<button
|
|
74
|
+
:ref="(el) => setHandle(step.id, el as Element | null)"
|
|
75
|
+
type="button"
|
|
76
|
+
class="mint-story-handle"
|
|
77
|
+
:aria-label="`Reorder ${step.name}. Press Alt with the arrow keys to move it.`"
|
|
78
|
+
@keydown="onKeydown($event, step, index)"
|
|
79
|
+
>
|
|
80
|
+
⠿
|
|
81
|
+
</button>
|
|
82
|
+
<span>{{ index + 1 }}. {{ step.name }}</span>
|
|
83
|
+
</li>
|
|
84
|
+
</ul>
|
|
85
|
+
|
|
86
|
+
<p v-if="state.showAnnouncement" class="mint-story-hint">
|
|
87
|
+
Live region: <em>{{ announcement || '—' }}</em>
|
|
88
|
+
</p>
|
|
89
|
+
<div role="status" aria-live="polite" :style="announcerStyle">{{ announcement }}</div>
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<template #controls="{ state }">
|
|
94
|
+
<HstCheckbox v-model="state.showAnnouncement" title="Show live-region text" />
|
|
95
|
+
</template>
|
|
96
|
+
</Variant>
|
|
97
|
+
</Story>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<style scoped>
|
|
101
|
+
.mint-story-list {
|
|
102
|
+
list-style: none;
|
|
103
|
+
margin: 0;
|
|
104
|
+
padding: 0;
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
gap: 0.25rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.mint-story-row {
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 0.5rem;
|
|
114
|
+
padding: 0.5rem 0.75rem;
|
|
115
|
+
border: 1px solid var(--border-color);
|
|
116
|
+
border-radius: 0.5rem;
|
|
117
|
+
background: var(--bg-primary);
|
|
118
|
+
color: var(--text-primary);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mint-story-row--dragging {
|
|
122
|
+
opacity: 0.5;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.mint-story-row--over {
|
|
126
|
+
border-color: var(--color-primary);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.mint-story-handle {
|
|
130
|
+
padding: 0;
|
|
131
|
+
border: 0;
|
|
132
|
+
background: none;
|
|
133
|
+
color: var(--text-muted);
|
|
134
|
+
cursor: grab;
|
|
135
|
+
font-size: 1rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.mint-story-hint {
|
|
139
|
+
margin: 0 0 0.75rem;
|
|
140
|
+
color: var(--text-secondary);
|
|
141
|
+
font-size: 0.8125rem;
|
|
142
|
+
}
|
|
143
|
+
</style>
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { nextTick, ref, type Ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
/** Inline style for a visually hidden `aria-live` region (no global utility class in the SDK). */
|
|
4
|
+
export const REORDER_ANNOUNCER_STYLE = Object.freeze({
|
|
5
|
+
position: 'absolute',
|
|
6
|
+
width: '1px',
|
|
7
|
+
height: '1px',
|
|
8
|
+
padding: '0',
|
|
9
|
+
margin: '-1px',
|
|
10
|
+
overflow: 'hidden',
|
|
11
|
+
clip: 'rect(0, 0, 0, 0)',
|
|
12
|
+
whiteSpace: 'nowrap',
|
|
13
|
+
border: '0',
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export interface UseReorderAnnouncerReturn {
|
|
17
|
+
/** Bind to a polite live region's text content. */
|
|
18
|
+
announcement: Ref<string>
|
|
19
|
+
/** Publishes a message to the live region. */
|
|
20
|
+
announce: (message: string) => void
|
|
21
|
+
/** Bind to the live region's `style` so it stays visually hidden. */
|
|
22
|
+
announcerStyle: typeof REORDER_ANNOUNCER_STYLE
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Screen-reader announcements for drag/keyboard move interactions. Bind
|
|
27
|
+
* `announcement` to a `role="status" aria-live="polite"` element styled with
|
|
28
|
+
* `announcerStyle`.
|
|
29
|
+
*/
|
|
30
|
+
export function useReorderAnnouncer(): UseReorderAnnouncerReturn {
|
|
31
|
+
const announcement = ref('')
|
|
32
|
+
|
|
33
|
+
function announce(message: string) {
|
|
34
|
+
// Re-announce identical consecutive messages by clearing first.
|
|
35
|
+
if (announcement.value === message) announcement.value = ''
|
|
36
|
+
void nextTick(() => {
|
|
37
|
+
announcement.value = message
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { announcement, announce, announcerStyle: REORDER_ANNOUNCER_STYLE }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ListReorderMove<T> {
|
|
45
|
+
/** Index the item moved from, within `items()`. */
|
|
46
|
+
fromIndex: number
|
|
47
|
+
/** Index the item moved to, within `items()`. */
|
|
48
|
+
toIndex: number
|
|
49
|
+
/** The reordered array (a copy — `items()` is never mutated). */
|
|
50
|
+
items: T[]
|
|
51
|
+
/** Whether the move came from the keyboard or a pointer drag. */
|
|
52
|
+
source: 'keyboard' | 'drag'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface UseListReorderOptions<T> {
|
|
56
|
+
/** The list being reordered, in its canonical (not merely rendered) order. */
|
|
57
|
+
items: () => T[]
|
|
58
|
+
/** Stable id for an item; falls back to the render index when ids repeat. */
|
|
59
|
+
getId: (item: T, index: number) => string
|
|
60
|
+
/** Applies the move. The composable never mutates the source array. */
|
|
61
|
+
onReorder: (move: ListReorderMove<T>) => void
|
|
62
|
+
/** Human-readable name used in announcements. Defaults to the item's id. */
|
|
63
|
+
getLabel?: (item: T, index: number) => string
|
|
64
|
+
/** Blocks every reorder while it returns `true` (readonly / non-sortable lists). */
|
|
65
|
+
disabled?: () => boolean
|
|
66
|
+
/** Resolves the focusable element for an id so keyboard moves keep focus on the item. */
|
|
67
|
+
getElement?: (id: string) => HTMLElement | null | undefined
|
|
68
|
+
/** Noun used in announcements, e.g. `'Reagent'`. Default `'Item'`. */
|
|
69
|
+
itemNoun?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface UseListReorderReturn<T> {
|
|
73
|
+
/** Id of the item currently being dragged, or `null`. */
|
|
74
|
+
draggingId: Ref<string | null>
|
|
75
|
+
/** Id of the item the pointer is hovering as a drop target, or `null`. */
|
|
76
|
+
dragOverId: Ref<string | null>
|
|
77
|
+
isDragging: (id: string) => boolean
|
|
78
|
+
isDragOver: (id: string) => boolean
|
|
79
|
+
announcement: Ref<string>
|
|
80
|
+
announcerStyle: typeof REORDER_ANNOUNCER_STYLE
|
|
81
|
+
announce: (message: string) => void
|
|
82
|
+
/** Bind to the draggable element's `@dragstart`. */
|
|
83
|
+
onDragStart: (event: DragEvent, item: T, index: number) => void
|
|
84
|
+
/** Bind to `@dragover` — calls `preventDefault()` so the drop is accepted. */
|
|
85
|
+
onDragOver: (event: DragEvent, item: T, index: number) => void
|
|
86
|
+
/** Bind to `@dragleave`. */
|
|
87
|
+
onDragLeave: () => void
|
|
88
|
+
/** Bind to `@drop`. */
|
|
89
|
+
onDrop: (event: DragEvent, item: T, index: number) => void
|
|
90
|
+
/** Bind to `@dragend`. */
|
|
91
|
+
onDragEnd: () => void
|
|
92
|
+
/**
|
|
93
|
+
* Bind to the item's (or its drag handle's) `@keydown`: Alt+ArrowUp / Alt+ArrowLeft
|
|
94
|
+
* moves the item one position earlier, Alt+ArrowDown / Alt+ArrowRight one later.
|
|
95
|
+
*/
|
|
96
|
+
onKeydown: (event: KeyboardEvent, item: T, index: number) => void
|
|
97
|
+
/** Moves an item between two indices of `items()` programmatically. */
|
|
98
|
+
move: (fromIndex: number, toIndex: number, source?: 'keyboard' | 'drag') => void
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Pure helper: a copy of `items` with the entry at `from` moved to `to`. */
|
|
102
|
+
export function reorderList<T>(items: T[], from: number, to: number): T[] {
|
|
103
|
+
const next = [...items]
|
|
104
|
+
const [moved] = next.splice(from, 1)
|
|
105
|
+
next.splice(to, 0, moved)
|
|
106
|
+
return next
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Keyboard-accessible list reordering shared by the SDK's drag-to-reorder lists.
|
|
111
|
+
* It owns the HTML5 drag state, the drop-index maths, and an Alt+Arrow keyboard
|
|
112
|
+
* alternative that announces every move through a polite live region — so a
|
|
113
|
+
* reorder never depends on a pointer.
|
|
114
|
+
*/
|
|
115
|
+
export function useListReorder<T>(options: UseListReorderOptions<T>): UseListReorderReturn<T> {
|
|
116
|
+
const draggingId = ref<string | null>(null)
|
|
117
|
+
const dragOverId = ref<string | null>(null)
|
|
118
|
+
const { announcement, announce, announcerStyle } = useReorderAnnouncer()
|
|
119
|
+
const noun = options.itemNoun ?? 'Item'
|
|
120
|
+
|
|
121
|
+
function isDisabled(): boolean {
|
|
122
|
+
return options.disabled?.() === true
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function idFor(item: T, index: number): string {
|
|
126
|
+
return options.getId(item, index)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Index within `items()`, resolved by id so filtered/sorted renders still map back. */
|
|
130
|
+
function indexOf(item: T, renderIndex: number): number {
|
|
131
|
+
const id = idFor(item, renderIndex)
|
|
132
|
+
const found = options.items().findIndex((candidate, index) => idFor(candidate, index) === id)
|
|
133
|
+
return found === -1 ? renderIndex : found
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function labelFor(index: number): string {
|
|
137
|
+
const item = options.items()[index]
|
|
138
|
+
if (item === undefined) return noun
|
|
139
|
+
return options.getLabel?.(item, index) ?? idFor(item, index)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function clearDragState() {
|
|
143
|
+
draggingId.value = null
|
|
144
|
+
dragOverId.value = null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function move(fromIndex: number, toIndex: number, source: 'keyboard' | 'drag' = 'keyboard') {
|
|
148
|
+
if (isDisabled()) return
|
|
149
|
+
const items = options.items()
|
|
150
|
+
if (
|
|
151
|
+
fromIndex === toIndex ||
|
|
152
|
+
fromIndex < 0 ||
|
|
153
|
+
toIndex < 0 ||
|
|
154
|
+
fromIndex >= items.length ||
|
|
155
|
+
toIndex >= items.length
|
|
156
|
+
) return
|
|
157
|
+
|
|
158
|
+
const movedId = idFor(items[fromIndex], fromIndex)
|
|
159
|
+
const label = labelFor(fromIndex)
|
|
160
|
+
options.onReorder({
|
|
161
|
+
fromIndex,
|
|
162
|
+
toIndex,
|
|
163
|
+
items: reorderList(items, fromIndex, toIndex),
|
|
164
|
+
source,
|
|
165
|
+
})
|
|
166
|
+
announce(`${label} moved to position ${toIndex + 1} of ${items.length}.`)
|
|
167
|
+
void nextTick(() => options.getElement?.(movedId)?.focus())
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function onDragStart(event: DragEvent, item: T, index: number) {
|
|
171
|
+
if (isDisabled()) return
|
|
172
|
+
const id = idFor(item, index)
|
|
173
|
+
draggingId.value = id
|
|
174
|
+
if (event.dataTransfer) {
|
|
175
|
+
event.dataTransfer.effectAllowed = 'move'
|
|
176
|
+
event.dataTransfer.setData('text/plain', id)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function onDragOver(event: DragEvent, item: T, index: number) {
|
|
181
|
+
if (isDisabled() || draggingId.value === null) return
|
|
182
|
+
event.preventDefault()
|
|
183
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'
|
|
184
|
+
const id = idFor(item, index)
|
|
185
|
+
dragOverId.value = id === draggingId.value ? null : id
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function onDragLeave() {
|
|
189
|
+
dragOverId.value = null
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function onDrop(event: DragEvent, item: T, index: number) {
|
|
193
|
+
if (isDisabled() || draggingId.value === null) {
|
|
194
|
+
clearDragState()
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
event.preventDefault()
|
|
198
|
+
|
|
199
|
+
const items = options.items()
|
|
200
|
+
const fromIndex = items.findIndex((candidate, i) => idFor(candidate, i) === draggingId.value)
|
|
201
|
+
const toIndex = indexOf(item, index)
|
|
202
|
+
clearDragState()
|
|
203
|
+
if (fromIndex === -1) return
|
|
204
|
+
move(fromIndex, toIndex, 'drag')
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function onDragEnd() {
|
|
208
|
+
clearDragState()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function onKeydown(event: KeyboardEvent, item: T, index: number) {
|
|
212
|
+
if (isDisabled() || !event.altKey) return
|
|
213
|
+
const direction =
|
|
214
|
+
event.key === 'ArrowUp' || event.key === 'ArrowLeft'
|
|
215
|
+
? -1
|
|
216
|
+
: event.key === 'ArrowDown' || event.key === 'ArrowRight'
|
|
217
|
+
? 1
|
|
218
|
+
: 0
|
|
219
|
+
if (direction === 0) return
|
|
220
|
+
|
|
221
|
+
event.preventDefault()
|
|
222
|
+
const fromIndex = indexOf(item, index)
|
|
223
|
+
move(fromIndex, fromIndex + direction, 'keyboard')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
draggingId,
|
|
228
|
+
dragOverId,
|
|
229
|
+
isDragging: (id: string) => draggingId.value === id,
|
|
230
|
+
isDragOver: (id: string) => dragOverId.value === id,
|
|
231
|
+
announcement,
|
|
232
|
+
announcerStyle,
|
|
233
|
+
announce,
|
|
234
|
+
onDragStart,
|
|
235
|
+
onDragOver,
|
|
236
|
+
onDragLeave,
|
|
237
|
+
onDrop,
|
|
238
|
+
onDragEnd,
|
|
239
|
+
onKeydown,
|
|
240
|
+
move,
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { nextTick } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface UseMenuKeyboardOptions {
|
|
4
|
+
/** Returns the currently navigable items inside the open panel, in DOM order. */
|
|
5
|
+
items: () => HTMLElement[]
|
|
6
|
+
/** True while the panel is open. */
|
|
7
|
+
isOpen: () => boolean
|
|
8
|
+
/** Opens the panel. */
|
|
9
|
+
open: () => void
|
|
10
|
+
/** Closes the panel. When `returnFocus` is true, focus should return to the trigger. */
|
|
11
|
+
close: (returnFocus?: boolean) => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface UseMenuKeyboardReturn {
|
|
15
|
+
/**
|
|
16
|
+
* Bind to the trigger's `@keydown`. ArrowDown/Enter/Space open the panel (when
|
|
17
|
+
* closed) and focus its first item; ArrowUp opens it focused on the last item.
|
|
18
|
+
*/
|
|
19
|
+
handleTriggerKeydown: (event: KeyboardEvent) => void
|
|
20
|
+
/**
|
|
21
|
+
* Bind to the open panel's `@keydown`. ArrowUp/ArrowDown cycle focus with
|
|
22
|
+
* wraparound, Home/End jump to the first/last item, Escape closes and returns
|
|
23
|
+
* focus to the trigger, and Tab closes without moving focus.
|
|
24
|
+
*/
|
|
25
|
+
handlePanelKeydown: (event: KeyboardEvent) => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Shared keyboard contract for menu- and listbox-style disclosure panels (the
|
|
30
|
+
* WAI-ARIA menu button pattern). Used by ActionMenu, AppAvatarMenu and DropdownButton,
|
|
31
|
+
* each pairing it with `useDropdownState` for the disclosure state itself.
|
|
32
|
+
*/
|
|
33
|
+
export function useMenuKeyboard(options: UseMenuKeyboardOptions): UseMenuKeyboardReturn {
|
|
34
|
+
function focusItem(position: 'first' | 'last') {
|
|
35
|
+
void nextTick(() => {
|
|
36
|
+
const items = options.items()
|
|
37
|
+
const target = position === 'first' ? items[0] : items[items.length - 1]
|
|
38
|
+
target?.focus()
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function handleTriggerKeydown(event: KeyboardEvent) {
|
|
43
|
+
if (options.isOpen()) return
|
|
44
|
+
|
|
45
|
+
if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {
|
|
46
|
+
event.preventDefault()
|
|
47
|
+
options.open()
|
|
48
|
+
focusItem('first')
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if (event.key === 'ArrowUp') {
|
|
52
|
+
event.preventDefault()
|
|
53
|
+
options.open()
|
|
54
|
+
focusItem('last')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handlePanelKeydown(event: KeyboardEvent) {
|
|
59
|
+
const items = options.items()
|
|
60
|
+
const currentIndex = items.indexOf(document.activeElement as HTMLElement)
|
|
61
|
+
|
|
62
|
+
if (event.key === 'Escape') {
|
|
63
|
+
event.preventDefault()
|
|
64
|
+
options.close(true)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if (event.key === 'Tab') {
|
|
68
|
+
options.close()
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
if (event.key === 'Home') {
|
|
72
|
+
event.preventDefault()
|
|
73
|
+
items[0]?.focus()
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
if (event.key === 'End') {
|
|
77
|
+
event.preventDefault()
|
|
78
|
+
items[items.length - 1]?.focus()
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return
|
|
82
|
+
|
|
83
|
+
event.preventDefault()
|
|
84
|
+
const direction = event.key === 'ArrowDown' ? 1 : -1
|
|
85
|
+
const nextIndex = (Math.max(currentIndex, 0) + direction + items.length) % items.length
|
|
86
|
+
items[nextIndex]?.focus()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { handleTriggerKeydown, handlePanelKeydown }
|
|
90
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computed, ref, shallowRef, type ComputedRef, type Ref, type ShallowRef } from 'vue'
|
|
2
|
+
import { readErrorMessage } from '../utils/errors'
|
|
2
3
|
|
|
3
4
|
export interface OptimisticMutationContext<TVariables, TSnapshot> {
|
|
4
5
|
variables: TVariables
|
|
@@ -32,7 +33,11 @@ export interface UseOptimisticMutationReturn<TVariables, TData, TSnapshot = unkn
|
|
|
32
33
|
reset: () => void
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Run async mutations with optional optimistic local updates and rollback.
|
|
38
|
+
*
|
|
39
|
+
* @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; use `useRequestSyncState()` instead.
|
|
40
|
+
*/
|
|
36
41
|
export function useOptimisticMutation<TVariables, TData, TSnapshot = unknown>(
|
|
37
42
|
options: UseOptimisticMutationOptions<TVariables, TData, TSnapshot>,
|
|
38
43
|
): UseOptimisticMutationReturn<TVariables, TData, TSnapshot> {
|
|
@@ -90,18 +95,3 @@ export function useOptimisticMutation<TVariables, TData, TSnapshot = unknown>(
|
|
|
90
95
|
reset,
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
|
-
|
|
94
|
-
function readErrorMessage(value: unknown): string {
|
|
95
|
-
if (value instanceof Error && value.message) return value.message
|
|
96
|
-
if (typeof value === 'string' && value.trim()) return value
|
|
97
|
-
if (
|
|
98
|
-
typeof value === 'object'
|
|
99
|
-
&& value !== null
|
|
100
|
-
&& 'message' in value
|
|
101
|
-
&& typeof (value as { message?: unknown }).message === 'string'
|
|
102
|
-
&& (value as { message: string }).message.trim()
|
|
103
|
-
) {
|
|
104
|
-
return (value as { message: string }).message
|
|
105
|
-
}
|
|
106
|
-
return 'Request failed.'
|
|
107
|
-
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { PickerAdapter, PickerNode, PickerRequest } from '../types/filePicker'
|
|
2
|
+
import type { FileDirectoryListing, ServerMount } from '../types/fileBrowserTypes'
|
|
3
|
+
import { useApi } from './useApi'
|
|
4
|
+
import { getInjectedPlatformContext } from './platformContextHelpers'
|
|
5
|
+
import { pickerFormat } from './filePicker/validation'
|
|
6
|
+
|
|
7
|
+
/** Opaque picker identity; decode before passing a selection to a mount-scoped API. */
|
|
8
|
+
export function encodePlatformPickerPath(mountId: string, path = ''): string {
|
|
9
|
+
return JSON.stringify([mountId, path])
|
|
10
|
+
}
|
|
11
|
+
export function decodePlatformPickerPath(path: string): { mountId: string; path: string } {
|
|
12
|
+
const decoded: unknown = JSON.parse(path)
|
|
13
|
+
if (
|
|
14
|
+
!Array.isArray(decoded) ||
|
|
15
|
+
decoded.length !== 2 ||
|
|
16
|
+
!decoded.every((item) => typeof item === 'string') ||
|
|
17
|
+
!decoded[0]
|
|
18
|
+
) {
|
|
19
|
+
throw new Error('Invalid platform picker path.')
|
|
20
|
+
}
|
|
21
|
+
return { mountId: decoded[0], path: decoded[1] }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Adapt the authenticated MINT mount API without exposing absolute host paths. */
|
|
25
|
+
export function usePlatformFilePickerAdapter(options: { apiBaseUrl?: string } = {}): PickerAdapter {
|
|
26
|
+
const api = useApi({
|
|
27
|
+
baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl,
|
|
28
|
+
})
|
|
29
|
+
const mountLabels = new Map<string, string>()
|
|
30
|
+
async function listRoot(request?: PickerRequest): Promise<PickerNode[]> {
|
|
31
|
+
try {
|
|
32
|
+
const { mounts } = await api.get<{ mounts: ServerMount[] }>('/filesystem/mounts', {
|
|
33
|
+
signal: request?.signal,
|
|
34
|
+
})
|
|
35
|
+
return mounts.map((mount) => {
|
|
36
|
+
mountLabels.set(mount.id, mount.label)
|
|
37
|
+
return {
|
|
38
|
+
kind: 'folder',
|
|
39
|
+
path: encodePlatformPickerPath(mount.id),
|
|
40
|
+
name: mount.label,
|
|
41
|
+
parentPath: null,
|
|
42
|
+
parentName: 'Server mounts',
|
|
43
|
+
unavailableReason: mount.available === false ? 'This mount is offline.' : undefined,
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
} catch (cause) {
|
|
47
|
+
if ((cause as { response?: { status?: number } }).response?.status === 404) return []
|
|
48
|
+
throw cause
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function listChildren(path: string, request?: PickerRequest): Promise<PickerNode[]> {
|
|
52
|
+
const location = decodePlatformPickerPath(path)
|
|
53
|
+
const query = new URLSearchParams({ mount_id: location.mountId, path: location.path })
|
|
54
|
+
const listing = await api.get<FileDirectoryListing>(`/filesystem/browse?${query}`, {
|
|
55
|
+
signal: request?.signal,
|
|
56
|
+
})
|
|
57
|
+
if (listing.truncated)
|
|
58
|
+
throw new Error(
|
|
59
|
+
'This directory exceeds the server listing limit. Choose a smaller data directory.',
|
|
60
|
+
)
|
|
61
|
+
return (listing.entries ?? []).map(
|
|
62
|
+
(entry) =>
|
|
63
|
+
({
|
|
64
|
+
kind: entry.kind === 'directory' ? 'folder' : 'file',
|
|
65
|
+
path: encodePlatformPickerPath(location.mountId, entry.path),
|
|
66
|
+
parentPath: path,
|
|
67
|
+
parentName: `${mountLabels.get(location.mountId) ?? location.mountId}${location.path ? ` / ${location.path}` : ''}`,
|
|
68
|
+
name: entry.name,
|
|
69
|
+
bytes: entry.size_bytes,
|
|
70
|
+
...(entry.kind === 'directory'
|
|
71
|
+
? { hasChildren: entry.child_count !== 0 }
|
|
72
|
+
: { format: pickerFormat(entry.name) }),
|
|
73
|
+
}) as PickerNode,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
listRoot,
|
|
78
|
+
listChildren,
|
|
79
|
+
async search(query, scope, request) {
|
|
80
|
+
const matches: PickerNode[] = []
|
|
81
|
+
const queue = [scope.path]
|
|
82
|
+
const visited = new Set<string>()
|
|
83
|
+
while (queue.length) {
|
|
84
|
+
request?.signal?.throwIfAborted()
|
|
85
|
+
const path = queue.shift()!
|
|
86
|
+
if (visited.has(path)) continue
|
|
87
|
+
visited.add(path)
|
|
88
|
+
if (visited.size > 500)
|
|
89
|
+
throw new Error(
|
|
90
|
+
'Search reached its folder limit. Search a smaller location or turn off Subfolders.',
|
|
91
|
+
)
|
|
92
|
+
const nodes = path ? await listChildren(path, request) : await listRoot(request)
|
|
93
|
+
for (const node of nodes) {
|
|
94
|
+
if (node.name.toLowerCase().includes(query.toLowerCase())) matches.push(node)
|
|
95
|
+
if (scope.recursive && node.kind === 'folder' && !node.unavailableReason)
|
|
96
|
+
queue.push(node.path)
|
|
97
|
+
}
|
|
98
|
+
if (matches.length > 10000)
|
|
99
|
+
throw new Error('Too many search results. Use a more specific search.')
|
|
100
|
+
}
|
|
101
|
+
return matches
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
}
|