@morscherlab/mint-sdk 1.0.0-beta.2 → 1.0.0-beta.3
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 +218 -6
- package/dist/__tests__/components/ActionItem.test.d.ts +1 -0
- package/dist/__tests__/components/AppAvatarMenu.test.d.ts +1 -0
- package/dist/__tests__/components/AppPageSelector.test.d.ts +1 -0
- package/dist/__tests__/components/AppPillNav.test.d.ts +1 -0
- package/dist/__tests__/components/AppPluginSwitcher.test.d.ts +1 -0
- package/dist/__tests__/components/AppToastContainer.test.d.ts +1 -0
- package/dist/__tests__/components/BaseRadioGroup.test.d.ts +1 -0
- package/dist/__tests__/components/BaseSelect.test.d.ts +1 -0
- package/dist/__tests__/components/BaseTabs.test.d.ts +1 -0
- package/dist/__tests__/components/BatchProgressList.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplateExperimentWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplatePackWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplatePresetWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplateRenderer.test.d.ts +1 -0
- package/dist/__tests__/components/Breadcrumb.test.d.ts +1 -0
- package/dist/__tests__/components/CalendarGridPanel.test.d.ts +1 -0
- package/dist/__tests__/components/ConcentrationInput.test.d.ts +1 -0
- package/dist/__tests__/components/ControlWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/DatePicker.test.d.ts +1 -0
- package/dist/__tests__/components/DateTimePicker.test.d.ts +1 -0
- package/dist/__tests__/components/EmptyState.test.d.ts +1 -0
- package/dist/__tests__/components/ExperimentPopover.test.d.ts +1 -0
- package/dist/__tests__/components/FormBuilder.test.d.ts +1 -0
- package/dist/__tests__/components/FormCompatibility.test.d.ts +1 -0
- package/dist/__tests__/components/GroupAssigner.test.d.ts +1 -0
- package/dist/__tests__/components/GroupingModal.test.d.ts +1 -0
- package/dist/__tests__/components/MultiSelect.test.d.ts +1 -0
- package/dist/__tests__/components/ProtocolStepEditor.test.d.ts +1 -0
- package/dist/__tests__/components/ReagentList.test.d.ts +1 -0
- package/dist/__tests__/components/SampleHierarchyTree.test.d.ts +1 -0
- package/dist/__tests__/components/SampleSelector.test.d.ts +1 -0
- package/dist/__tests__/components/SegmentedControl.test.d.ts +1 -0
- package/dist/__tests__/components/SettingsButton.test.d.ts +1 -0
- package/dist/__tests__/components/SettingsModal.test.d.ts +1 -0
- package/dist/__tests__/components/TagsInput.test.d.ts +1 -0
- package/dist/__tests__/components/ThemeToggle.test.d.ts +1 -0
- package/dist/__tests__/components/TimePicker.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplatePackWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplatePresetWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplateWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useCalendarGrid.test.d.ts +1 -0
- package/dist/__tests__/composables/useControlSchema.test.d.ts +1 -0
- package/dist/__tests__/composables/useDebouncedWatch.test.d.ts +1 -0
- package/dist/__tests__/composables/useDropdownState.test.d.ts +1 -0
- package/dist/__tests__/composables/useEventListener.test.d.ts +1 -0
- package/dist/__tests__/composables/useExpansionSet.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentData.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentSelector.test.d.ts +1 -0
- package/dist/__tests__/composables/useGroupAssignment.test.d.ts +1 -0
- package/dist/__tests__/composables/useListSelection.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginClient.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +1 -0
- package/dist/__tests__/composables/useRequestSyncState.test.d.ts +1 -0
- package/dist/__tests__/composables/useSampleGroups.test.d.ts +1 -0
- package/dist/__tests__/composables/useSelectionLimit.test.d.ts +1 -0
- package/dist/__tests__/composables/useSortedItems.test.d.ts +1 -0
- package/dist/__tests__/composables/useTemplateCollection.test.d.ts +1 -0
- package/dist/__tests__/composables/useTextSearch.test.d.ts +1 -0
- package/dist/__tests__/composables/useTheme.test.d.ts +1 -0
- package/dist/__tests__/composables/useTimeUtils.test.d.ts +1 -0
- package/dist/__tests__/docs/frontendDocsCatalog.test.d.ts +1 -0
- package/dist/__tests__/templates/templates.test.d.ts +1 -0
- package/dist/{auth-DsI0rQ7_.js → auth-QQj2kkze.js} +12 -5
- package/dist/auth-QQj2kkze.js.map +1 -0
- package/dist/components/ActionItem.vue.d.ts +32 -0
- package/dist/components/AppAvatarMenu.vue.d.ts +2 -7
- package/dist/components/AppPageSelector.vue.d.ts +3 -6
- package/dist/components/AppPillNav.vue.d.ts +2 -2
- package/dist/components/AppSidebar.vue.d.ts +56 -3
- package/dist/components/AppToastContainer.vue.d.ts +2 -0
- package/dist/components/AppTopBar.vue.d.ts +41 -10
- package/dist/components/BaseButton.vue.d.ts +1 -1
- package/dist/components/BaseCheckbox.vue.d.ts +1 -1
- package/dist/components/BaseInput.vue.d.ts +2 -2
- package/dist/components/BasePill.vue.d.ts +2 -2
- package/dist/components/BaseRadioGroup.vue.d.ts +3 -3
- package/dist/components/BaseSelect.vue.d.ts +3 -3
- package/dist/components/BaseTabs.vue.d.ts +2 -2
- package/dist/components/BaseTextarea.vue.d.ts +1 -1
- package/dist/components/BaseToggle.vue.d.ts +1 -1
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +117 -0
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +92 -0
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +82 -0
- package/dist/components/BioTemplateRenderer.vue.d.ts +29 -0
- package/dist/components/Breadcrumb.vue.d.ts +2 -2
- package/dist/components/Calendar.vue.d.ts +1 -1
- package/dist/components/CalendarGridPanel.vue.d.ts +25 -0
- package/dist/components/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/ConcentrationInput.vue.d.ts +2 -2
- package/dist/components/ConfirmDialog.vue.d.ts +2 -2
- package/dist/components/ControlWorkspaceView.vue.d.ts +130 -0
- package/dist/components/DatePicker.vue.d.ts +1 -1
- package/dist/components/DateTimePicker.vue.d.ts +3 -3
- package/dist/components/Divider.vue.d.ts +1 -1
- package/dist/components/DropdownButton.vue.d.ts +3 -3
- package/dist/components/EmptyState.vue.d.ts +1 -2
- package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
- package/dist/components/ExperimentTimeline.vue.d.ts +2 -2
- package/dist/components/FileUploader.vue.d.ts +1 -1
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/FormActions.vue.d.ts +4 -4
- package/dist/components/FormBuilder.vue.d.ts +22 -8
- package/dist/components/FormFieldRenderer.vue.d.ts +7 -10
- package/dist/components/FormSection.vue.d.ts +11 -24
- package/dist/components/FormulaInput.vue.d.ts +2 -2
- package/dist/components/MoleculeInput.vue.d.ts +2 -2
- package/dist/components/MultiSelect.vue.d.ts +3 -3
- package/dist/components/NumberInput.vue.d.ts +1 -1
- package/dist/components/ProgressBar.vue.d.ts +1 -1
- package/dist/components/ProtocolStepEditor.vue.d.ts +3 -1
- package/dist/components/RackEditor.vue.d.ts +2 -2
- package/dist/components/SampleLegend.vue.d.ts +2 -2
- package/dist/components/ScheduleCalendar.vue.d.ts +2 -2
- package/dist/components/SegmentedControl.vue.d.ts +2 -2
- package/dist/components/SequenceInput.vue.d.ts +3 -3
- package/dist/components/SettingsButton.vue.d.ts +2 -2
- package/dist/components/SettingsModal.vue.d.ts +13 -5
- package/dist/components/StatusIndicator.vue.d.ts +1 -1
- package/dist/components/TagsInput.vue.d.ts +3 -2
- package/dist/components/TimePicker.vue.d.ts +3 -3
- package/dist/components/TimeRangeInput.vue.d.ts +1 -1
- package/dist/components/UnitInput.vue.d.ts +2 -2
- package/dist/components/WellPlate.vue.d.ts +8 -8
- package/dist/components/index.d.ts +11 -1
- package/dist/components/index.js +3 -3
- package/dist/components/internal/FormFieldRendererInternal.vue.d.ts +31 -0
- package/dist/components/internal/FormSectionRenderer.vue.d.ts +43 -0
- package/dist/{components-_XqPEhP9.js → components-D_Sr0adg.js} +7290 -6518
- package/dist/components-D_Sr0adg.js.map +1 -0
- package/dist/composables/index.d.ts +21 -2
- package/dist/composables/index.js +4 -3
- package/dist/composables/platformContextHelpers.d.ts +14 -0
- package/dist/composables/useBioTemplateComponents.d.ts +20 -0
- package/dist/composables/useBioTemplateControls.d.ts +6 -0
- package/dist/composables/useBioTemplatePackWorkspace.d.ts +45 -0
- package/dist/composables/useBioTemplatePresetWorkspace.d.ts +74 -0
- package/dist/composables/useBioTemplateWorkspace.d.ts +50 -0
- package/dist/composables/useCalendarGrid.d.ts +26 -0
- package/dist/composables/useControlSchema.d.ts +321 -0
- package/dist/composables/useDebouncedWatch.d.ts +20 -0
- package/dist/composables/useDropdownState.d.ts +19 -0
- package/dist/composables/useEventListener.d.ts +13 -0
- package/dist/composables/useExpansionSet.d.ts +21 -0
- package/dist/composables/useExperimentData.d.ts +10 -0
- package/dist/composables/useExperimentSave.d.ts +31 -2
- package/dist/composables/useExperimentSelector.d.ts +20 -0
- package/dist/composables/useForm.d.ts +2 -0
- package/dist/composables/useGroupAssignment.d.ts +31 -0
- package/dist/composables/useListSelection.d.ts +35 -0
- package/dist/composables/usePlatformContext.d.ts +21 -3
- package/dist/composables/usePluginApi.d.ts +7 -14
- package/dist/composables/usePluginClient.d.ts +109 -0
- package/dist/composables/usePluginConfig.d.ts +12 -0
- package/dist/composables/useRequestSyncState.d.ts +34 -0
- package/dist/composables/useSampleGroups.d.ts +32 -0
- package/dist/composables/useSelectionLimit.d.ts +17 -0
- package/dist/composables/useSortedItems.d.ts +32 -0
- package/dist/composables/useTemplateCollection.d.ts +58 -0
- package/dist/composables/useTextSearch.d.ts +18 -0
- package/dist/composables/useTimeUtils.d.ts +8 -0
- package/dist/{composables-tiZqLu1M.js → composables-C3dpXQN5.js} +228 -146
- package/dist/composables-C3dpXQN5.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +6 -5
- package/dist/install.d.ts +7 -2
- package/dist/install.js +2 -2
- package/dist/install.js.map +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/stores/settings.d.ts +4 -1
- package/dist/styles.css +5235 -5977
- package/dist/templates/adapters.d.ts +43 -0
- package/dist/templates/builders.d.ts +63 -0
- package/dist/templates/catalog.d.ts +188 -0
- package/dist/templates/componentBindings.d.ts +58 -0
- package/dist/templates/controlSchemas.d.ts +25 -0
- package/dist/templates/index.d.ts +15 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/lookup.d.ts +4 -0
- package/dist/templates/packs.d.ts +18 -0
- package/dist/templates/presets.d.ts +90 -0
- package/dist/templates/types.d.ts +531 -0
- package/dist/templates-50NPjaxL.js +9333 -0
- package/dist/templates-50NPjaxL.js.map +1 -0
- package/dist/types/components.d.ts +26 -4
- package/dist/types/form-builder.d.ts +6 -8
- package/dist/types/index.d.ts +2 -2
- package/dist/types/platform.d.ts +7 -1
- package/dist/useScheduleDrag-D4oWdh41.js +4371 -0
- package/dist/useScheduleDrag-D4oWdh41.js.map +1 -0
- package/dist/utils/formModelSync.d.ts +5 -0
- package/dist/utils/items.d.ts +8 -0
- package/dist/utils/options.d.ts +6 -0
- package/dist/utils/pluginIcon.d.ts +9 -0
- package/package.json +7 -2
- package/src/__tests__/components/ActionItem.test.ts +99 -0
- package/src/__tests__/components/AppAvatarMenu.test.ts +27 -0
- package/src/__tests__/components/AppPageSelector.test.ts +134 -0
- package/src/__tests__/components/AppPillNav.test.ts +78 -0
- package/src/__tests__/components/AppPluginSwitcher.test.ts +44 -0
- package/src/__tests__/components/AppSidebar.test.ts +370 -0
- package/src/__tests__/components/AppToastContainer.test.ts +48 -0
- package/src/__tests__/components/AppTopBar.test.ts +383 -0
- package/src/__tests__/components/BaseRadioGroup.test.ts +25 -0
- package/src/__tests__/components/BaseSelect.test.ts +21 -0
- package/src/__tests__/components/BaseTabs.test.ts +25 -0
- package/src/__tests__/components/BatchProgressList.test.ts +52 -0
- package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +153 -0
- package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +161 -0
- package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +281 -0
- package/src/__tests__/components/BioTemplateRenderer.test.ts +71 -0
- package/src/__tests__/components/Breadcrumb.test.ts +23 -0
- package/src/__tests__/components/CalendarGridPanel.test.ts +36 -0
- package/src/__tests__/components/ConcentrationInput.test.ts +45 -0
- package/src/__tests__/components/ControlWorkspaceView.test.ts +1031 -0
- package/src/__tests__/components/DataFrame.test.ts +11 -0
- package/src/__tests__/components/DatePicker.test.ts +45 -0
- package/src/__tests__/components/DateTimePicker.test.ts +48 -0
- package/src/__tests__/components/DropdownButton.test.ts +23 -0
- package/src/__tests__/components/EmptyState.test.ts +23 -0
- package/src/__tests__/components/ExperimentPopover.test.ts +56 -0
- package/src/__tests__/components/FormBuilder.test.ts +296 -0
- package/src/__tests__/components/FormCompatibility.test.ts +94 -0
- package/src/__tests__/components/GroupAssigner.test.ts +30 -0
- package/src/__tests__/components/GroupingModal.test.ts +73 -0
- package/src/__tests__/components/MultiSelect.test.ts +48 -0
- package/src/__tests__/components/ProtocolStepEditor.test.ts +33 -0
- package/src/__tests__/components/ReagentList.test.ts +82 -0
- package/src/__tests__/components/SampleHierarchyTree.test.ts +53 -0
- package/src/__tests__/components/SampleSelector.test.ts +60 -0
- package/src/__tests__/components/SegmentedControl.test.ts +24 -0
- package/src/__tests__/components/SettingsButton.test.ts +44 -0
- package/src/__tests__/components/SettingsModal.test.ts +296 -0
- package/src/__tests__/components/TagsInput.test.ts +75 -0
- package/src/__tests__/components/ThemeToggle.test.ts +47 -0
- package/src/__tests__/components/TimePicker.test.ts +38 -0
- package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +122 -0
- package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +199 -0
- package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +99 -0
- package/src/__tests__/composables/useCalendarGrid.test.ts +38 -0
- package/src/__tests__/composables/useControlSchema.test.ts +919 -0
- package/src/__tests__/composables/useDebouncedWatch.test.ts +93 -0
- package/src/__tests__/composables/useDropdownState.test.ts +95 -0
- package/src/__tests__/composables/useEventListener.test.ts +116 -0
- package/src/__tests__/composables/useExpansionSet.test.ts +62 -0
- package/src/__tests__/composables/useExperimentData.test.ts +4 -0
- package/src/__tests__/composables/useExperimentSave.test.ts +203 -8
- package/src/__tests__/composables/useExperimentSelector.test.ts +164 -0
- package/src/__tests__/composables/useForm.test.ts +58 -0
- package/src/__tests__/composables/useFormBuilder.test.ts +77 -0
- package/src/__tests__/composables/useGroupAssignment.test.ts +73 -0
- package/src/__tests__/composables/useListSelection.test.ts +66 -0
- package/src/__tests__/composables/usePluginClient.test.ts +444 -0
- package/src/__tests__/composables/usePluginConfig.test.ts +5 -0
- package/src/__tests__/composables/useRequestSyncState.test.ts +92 -0
- package/src/__tests__/composables/useSampleGroups.test.ts +66 -0
- package/src/__tests__/composables/useSelectionLimit.test.ts +41 -0
- package/src/__tests__/composables/useSortedItems.test.ts +87 -0
- package/src/__tests__/composables/useTemplateCollection.test.ts +147 -0
- package/src/__tests__/composables/useTextSearch.test.ts +55 -0
- package/src/__tests__/composables/useTheme.test.ts +91 -0
- package/src/__tests__/composables/useTimeUtils.test.ts +35 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +229 -0
- package/src/__tests__/fixtures/templates/dose-response.json +81 -0
- package/src/__tests__/fixtures/templates/plate-map.json +54 -0
- package/src/__tests__/fixtures/templates/qpcr-plate.json +96 -0
- package/src/__tests__/fixtures/templates/sample-sheet.json +71 -0
- package/src/__tests__/templates/templates.test.ts +1043 -0
- package/src/components/ActionItem.vue +82 -0
- package/src/components/AppAvatarMenu.vue +15 -69
- package/src/components/AppLayout.story.vue +25 -25
- package/src/components/AppPageSelector.vue +63 -94
- package/src/components/AppPillNav.vue +44 -39
- package/src/components/AppPluginSwitcher.vue +41 -145
- package/src/components/AppSidebar.story.vue +94 -0
- package/src/components/AppSidebar.vue +187 -12
- package/src/components/{ToastNotification.story.vue → AppToastContainer.story.vue} +6 -6
- package/src/components/AppToastContainer.vue +62 -0
- package/src/components/AppTopBar.story.vue +7 -30
- package/src/components/AppTopBar.vue +251 -57
- package/src/components/BaseModal.vue +3 -5
- package/src/components/BaseRadioGroup.vue +7 -3
- package/src/components/BaseSelect.vue +11 -7
- package/src/components/BaseTabs.vue +6 -4
- package/src/components/BatchProgressList.vue +5 -8
- package/src/components/BioTemplateExperimentWorkspaceView.story.vue +123 -0
- package/src/components/BioTemplateExperimentWorkspaceView.vue +337 -0
- package/src/components/BioTemplatePackWorkspaceView.story.vue +107 -0
- package/src/components/BioTemplatePackWorkspaceView.vue +176 -0
- package/src/components/BioTemplatePresetWorkspaceView.story.vue +151 -0
- package/src/components/BioTemplatePresetWorkspaceView.vue +392 -0
- package/src/components/BioTemplateRenderer.story.vue +57 -0
- package/src/components/BioTemplateRenderer.vue +269 -0
- package/src/components/Breadcrumb.vue +14 -8
- package/src/components/CalendarGridPanel.vue +120 -0
- package/src/components/ConcentrationInput.vue +27 -64
- package/src/components/ControlWorkspaceView.story.vue +336 -0
- package/src/components/ControlWorkspaceView.vue +347 -0
- package/src/components/DataFrame.vue +34 -50
- package/src/components/DatePicker.vue +59 -192
- package/src/components/DateTimePicker.vue +50 -171
- package/src/components/DropdownButton.vue +14 -32
- package/src/components/EmptyState.vue +4 -2
- package/src/components/ExperimentPopover.vue +5 -22
- package/src/components/FormBuilder.vue +124 -27
- package/src/components/FormFieldRenderer.vue +15 -38
- package/src/components/FormSection.vue +20 -73
- package/src/components/GroupAssigner.vue +24 -56
- package/src/components/GroupingModal.story.vue +3 -3
- package/src/components/GroupingModal.vue +30 -391
- package/src/components/MultiSelect.vue +17 -12
- package/src/components/PlateMapEditor.vue +3 -8
- package/src/components/PluginIcon.vue +2 -22
- package/src/components/ProtocolStepEditor.vue +13 -22
- package/src/components/ReagentList.vue +25 -33
- package/src/components/SampleHierarchyTree.vue +12 -23
- package/src/components/SampleSelector.vue +42 -122
- package/src/components/SegmentedControl.vue +7 -3
- package/src/components/SettingsButton.story.vue +1 -1
- package/src/components/SettingsButton.vue +15 -27
- package/src/components/SettingsModal.story.vue +1 -1
- package/src/components/SettingsModal.vue +120 -29
- package/src/components/TagsInput.vue +29 -14
- package/src/components/ThemeToggle.vue +9 -7
- package/src/components/TimePicker.vue +19 -41
- package/src/components/ToastNotification.vue +4 -57
- package/src/components/Tooltip.vue +7 -12
- package/src/components/WellEditPopup.vue +3 -8
- package/src/components/WellPlate.vue +4 -10
- package/src/components/index.ts +11 -1
- package/src/components/internal/FormFieldRendererInternal.vue +50 -0
- package/src/components/internal/FormSectionRenderer.vue +78 -0
- package/src/composables/index.ts +212 -0
- package/src/composables/platformContextHelpers.ts +74 -0
- package/src/composables/useBioTemplateComponents.ts +93 -0
- package/src/composables/useBioTemplateControls.ts +41 -0
- package/src/composables/useBioTemplatePackWorkspace.ts +181 -0
- package/src/composables/useBioTemplatePresetWorkspace.ts +337 -0
- package/src/composables/useBioTemplateWorkspace.ts +139 -0
- package/src/composables/useCalendarGrid.ts +140 -0
- package/src/composables/useControlSchema.ts +1274 -0
- package/src/composables/useDebouncedWatch.ts +119 -0
- package/src/composables/useDropdownState.ts +83 -0
- package/src/composables/useEventListener.ts +111 -0
- package/src/composables/useExpansionSet.ts +117 -0
- package/src/composables/useExperimentData.ts +20 -11
- package/src/composables/useExperimentSave.ts +202 -50
- package/src/composables/useExperimentSelector.ts +86 -72
- package/src/composables/useForm.ts +49 -4
- package/src/composables/useFormBuilder.ts +93 -42
- package/src/composables/useGroupAssignment.ts +148 -0
- package/src/composables/useListSelection.ts +158 -0
- package/src/composables/usePluginApi.ts +7 -14
- package/src/composables/usePluginClient.ts +425 -0
- package/src/composables/usePluginConfig.ts +34 -13
- package/src/composables/useRequestSyncState.ts +126 -0
- package/src/composables/useSampleGroups.ts +126 -0
- package/src/composables/useSelectionLimit.ts +57 -0
- package/src/composables/useSortedItems.ts +118 -0
- package/src/composables/useTemplateCollection.ts +229 -0
- package/src/composables/useTextSearch.ts +60 -0
- package/src/composables/useTheme.ts +2 -28
- package/src/composables/useTimeUtils.ts +26 -2
- package/src/composables/useWellPlateEditor.ts +13 -9
- package/src/index.ts +224 -4
- package/src/install.ts +11 -4
- package/src/stores/settings.ts +13 -9
- package/src/styles/components/app-page-selector.css +23 -0
- package/src/styles/components/app-pill-nav.css +7 -0
- package/src/styles/components/app-top-bar.css +34 -0
- package/src/styles/components/concentration-input.css +3 -142
- package/src/styles/components/empty-state.css +0 -16
- package/src/styles/components/settings-button.css +3 -66
- package/src/styles/components/theme-toggle.css +3 -66
- package/src/styles/index.css +0 -1
- package/src/templates/adapters.ts +785 -0
- package/src/templates/builders.ts +2149 -0
- package/src/templates/catalog.ts +245 -0
- package/src/templates/componentBindings.ts +615 -0
- package/src/templates/controlSchemas.ts +718 -0
- package/src/templates/index.ts +314 -0
- package/src/templates/lookup.ts +18 -0
- package/src/templates/packs.ts +156 -0
- package/src/templates/presets.ts +146 -0
- package/src/templates/types.ts +668 -0
- package/src/types/components.ts +41 -4
- package/src/types/form-builder.ts +7 -2
- package/src/types/index.ts +14 -0
- package/src/types/platform.ts +7 -1
- package/src/utils/formModelSync.ts +52 -0
- package/src/utils/items.ts +28 -0
- package/src/utils/options.ts +23 -0
- package/src/utils/pluginIcon.ts +30 -0
- package/dist/auth-DsI0rQ7_.js.map +0 -1
- package/dist/components-_XqPEhP9.js.map +0 -1
- package/dist/composables-tiZqLu1M.js.map +0 -1
- package/dist/useScheduleDrag-CA9sGNJG.js +0 -7181
- package/dist/useScheduleDrag-CA9sGNJG.js.map +0 -1
- package/src/styles/components/grouping-modal.css +0 -323
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as useSettingsStore, t as useAuthStore } from "./auth-
|
|
3
|
-
import { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from "vue";
|
|
1
|
+
import { F as usePlatformContext, K as useApi, W as useRequestSyncState, b as getInjectedPlatformContext, x as resolveCurrentExperimentId, y as currentExperimentFromContext } from "./useScheduleDrag-D4oWdh41.js";
|
|
2
|
+
import { r as useSettingsStore, t as useAuthStore } from "./auth-QQj2kkze.js";
|
|
3
|
+
import { computed, getCurrentInstance, onMounted, onUnmounted, ref, shallowRef, watch } from "vue";
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
//#region src/composables/useAuth.ts
|
|
6
6
|
var TOKEN_REFRESH_MARGIN_MS = 300 * 1e3;
|
|
@@ -596,9 +596,12 @@ function usePluginConfig(pluginName) {
|
|
|
596
596
|
const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? "");
|
|
597
597
|
const config = ref({});
|
|
598
598
|
const savedConfig = ref({});
|
|
599
|
+
const request = useRequestSyncState("Plugin config request failed.");
|
|
599
600
|
const isLoading = ref(false);
|
|
600
601
|
const isSaving = ref(false);
|
|
601
|
-
const error =
|
|
602
|
+
const error = request.error;
|
|
603
|
+
const lastLoadedAt = request.lastLoadedAt;
|
|
604
|
+
const lastSavedAt = request.lastSavedAt;
|
|
602
605
|
const isDirty = computed(() => {
|
|
603
606
|
return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value);
|
|
604
607
|
});
|
|
@@ -606,14 +609,14 @@ function usePluginConfig(pluginName) {
|
|
|
606
609
|
const name = resolvedName.value;
|
|
607
610
|
if (!name) return;
|
|
608
611
|
isLoading.value = true;
|
|
609
|
-
error.value = null;
|
|
610
612
|
try {
|
|
611
|
-
const response = await api.get(`/plugins/${encodeURIComponent(name)}/config`)
|
|
613
|
+
const response = await request.run(() => api.get(`/plugins/${encodeURIComponent(name)}/config`), {
|
|
614
|
+
success: "load",
|
|
615
|
+
errorMessage: "Failed to load plugin config"
|
|
616
|
+
});
|
|
612
617
|
config.value = { ...response.config };
|
|
613
618
|
savedConfig.value = { ...response.config };
|
|
614
|
-
} catch
|
|
615
|
-
error.value = e instanceof Error ? e.message : "Failed to load plugin config";
|
|
616
|
-
} finally {
|
|
619
|
+
} catch {} finally {
|
|
617
620
|
isLoading.value = false;
|
|
618
621
|
}
|
|
619
622
|
}
|
|
@@ -621,14 +624,15 @@ function usePluginConfig(pluginName) {
|
|
|
621
624
|
const name = resolvedName.value;
|
|
622
625
|
if (!name) return false;
|
|
623
626
|
isSaving.value = true;
|
|
624
|
-
error.value = null;
|
|
625
627
|
try {
|
|
626
|
-
const response = await api.patch(`/plugins/${encodeURIComponent(name)}/config`, { config: config.value })
|
|
628
|
+
const response = await request.run(() => api.patch(`/plugins/${encodeURIComponent(name)}/config`, { config: config.value }), {
|
|
629
|
+
success: "save",
|
|
630
|
+
errorMessage: "Failed to save plugin config"
|
|
631
|
+
});
|
|
627
632
|
config.value = { ...response.config };
|
|
628
633
|
savedConfig.value = { ...response.config };
|
|
629
634
|
return true;
|
|
630
|
-
} catch
|
|
631
|
-
error.value = e instanceof Error ? e.message : "Failed to save plugin config";
|
|
635
|
+
} catch {
|
|
632
636
|
return false;
|
|
633
637
|
} finally {
|
|
634
638
|
isSaving.value = false;
|
|
@@ -636,7 +640,7 @@ function usePluginConfig(pluginName) {
|
|
|
636
640
|
}
|
|
637
641
|
function reset() {
|
|
638
642
|
config.value = { ...savedConfig.value };
|
|
639
|
-
|
|
643
|
+
request.clearError();
|
|
640
644
|
}
|
|
641
645
|
onMounted(() => {
|
|
642
646
|
load();
|
|
@@ -646,6 +650,8 @@ function usePluginConfig(pluginName) {
|
|
|
646
650
|
isLoading,
|
|
647
651
|
isSaving,
|
|
648
652
|
error,
|
|
653
|
+
lastLoadedAt,
|
|
654
|
+
lastSavedAt,
|
|
649
655
|
isDirty,
|
|
650
656
|
load,
|
|
651
657
|
save,
|
|
@@ -653,153 +659,229 @@ function usePluginConfig(pluginName) {
|
|
|
653
659
|
};
|
|
654
660
|
}
|
|
655
661
|
//#endregion
|
|
656
|
-
//#region src/composables/
|
|
657
|
-
/**
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
662
|
+
//#region src/composables/usePluginApi.ts
|
|
663
|
+
/**
|
|
664
|
+
* Legacy plugin API client resolving the plugin base URL from VITE_API_PREFIX or a fallback prefix.
|
|
665
|
+
*
|
|
666
|
+
* @deprecated Use `useGeneratedPluginClient()` from `mint sdk generate` for new
|
|
667
|
+
* plugin frontends. This helper remains as a compatibility shim for older
|
|
668
|
+
* plugins that still hand-wire API prefixes.
|
|
669
|
+
*
|
|
670
|
+
* Migration shape for generated plugins:
|
|
671
|
+
* ```ts
|
|
672
|
+
* import { useGeneratedPluginClient } from '../generated/mint-plugin'
|
|
673
|
+
*
|
|
674
|
+
* const pluginClient = useGeneratedPluginClient()
|
|
675
|
+
* ```
|
|
676
|
+
*/
|
|
677
|
+
function usePluginApi(options = {}) {
|
|
678
|
+
return useApi({ baseUrl: options.fallbackPrefix || "/api" });
|
|
679
|
+
}
|
|
680
|
+
//#endregion
|
|
681
|
+
//#region src/composables/usePluginClient.ts
|
|
682
|
+
function normalizeApiPrefix(prefix) {
|
|
683
|
+
if (!prefix) return void 0;
|
|
684
|
+
if (prefix.startsWith("/api/")) return prefix;
|
|
685
|
+
if (prefix === "/api") return prefix;
|
|
686
|
+
if (prefix.startsWith("/")) return `/api${prefix}`;
|
|
687
|
+
return `/api/${prefix}`;
|
|
688
|
+
}
|
|
689
|
+
/** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */
|
|
690
|
+
function resolvePluginBaseUrl(contract, explicitBaseUrl) {
|
|
691
|
+
if (explicitBaseUrl) return explicitBaseUrl;
|
|
692
|
+
const injected = getInjectedPlatformContext();
|
|
693
|
+
const platformPrefix = injected?.plugin?.api_prefix || normalizeApiPrefix(injected?.plugin?.route_prefix);
|
|
694
|
+
if (platformPrefix) return platformPrefix;
|
|
695
|
+
return contract.plugin.apiPrefix || "/api";
|
|
696
|
+
}
|
|
697
|
+
function encodePath(path, payload, pathParams) {
|
|
698
|
+
let nextPath = path;
|
|
699
|
+
for (const param of pathParams) {
|
|
700
|
+
const value = payload[param];
|
|
701
|
+
if (value === void 0 || value === null) throw new Error(`[MINT SDK] Missing path parameter '${param}' for plugin endpoint ${path}`);
|
|
702
|
+
nextPath = nextPath.replace(`{${param}}`, encodeURIComponent(String(value)));
|
|
703
|
+
nextPath = nextPath.replace(`:${param}`, encodeURIComponent(String(value)));
|
|
704
|
+
}
|
|
705
|
+
return nextPath;
|
|
706
|
+
}
|
|
707
|
+
function withDefaultPathParams(payload, pathParams) {
|
|
708
|
+
if (!pathParams.length) return payload;
|
|
709
|
+
const nextPayload = { ...payload };
|
|
710
|
+
for (const param of pathParams) {
|
|
711
|
+
if (nextPayload[param] !== void 0 && nextPayload[param] !== null) continue;
|
|
712
|
+
if (isExperimentPathParam(param)) {
|
|
713
|
+
const experimentId = resolveCurrentExperimentId();
|
|
714
|
+
if (experimentId !== void 0) nextPayload[param] = experimentId;
|
|
688
715
|
}
|
|
689
716
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
717
|
+
return nextPayload;
|
|
718
|
+
}
|
|
719
|
+
function isExperimentPathParam(param) {
|
|
720
|
+
return param === "experimentId" || param === "experiment_id";
|
|
721
|
+
}
|
|
722
|
+
function withoutPathParams(payload, pathParams) {
|
|
723
|
+
const copy = { ...payload };
|
|
724
|
+
for (const param of pathParams) delete copy[param];
|
|
725
|
+
return copy;
|
|
726
|
+
}
|
|
727
|
+
function queryParamsFromPayload(payload, pathParams, queryParams, endpointPath, includeUnspecifiedParams = false) {
|
|
728
|
+
if (!queryParams?.length) return includeUnspecifiedParams ? withoutPathParams(payload, pathParams) : {};
|
|
729
|
+
const query = {};
|
|
730
|
+
for (const param of queryParams) {
|
|
731
|
+
const name = typeof param === "string" ? param : param.name;
|
|
732
|
+
const fieldName = typeof param === "string" ? param : param.fieldName ?? param.name;
|
|
733
|
+
const required = typeof param !== "string" && param.required === true;
|
|
734
|
+
const value = payload[fieldName];
|
|
735
|
+
if (value === void 0 || value === null) {
|
|
736
|
+
if (required) throw new Error(`[MINT SDK] Missing query parameter '${fieldName}' for plugin endpoint ${endpointPath ?? ""}`);
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
query[name] = value;
|
|
740
|
+
}
|
|
741
|
+
return query;
|
|
742
|
+
}
|
|
743
|
+
function hasKeys(value) {
|
|
744
|
+
return Object.keys(value).length > 0;
|
|
745
|
+
}
|
|
746
|
+
function requestBodyFromPayload(payload, requestPayload, endpoint) {
|
|
747
|
+
if (!endpoint.hasBody) return void 0;
|
|
748
|
+
const body = endpoint.pathParams?.length || endpoint.queryParams?.length ? requestPayload.body : payload;
|
|
749
|
+
if (body === void 0 || body === null) throw new Error(`[MINT SDK] Missing request body for plugin endpoint ${endpoint.path}`);
|
|
750
|
+
return body;
|
|
751
|
+
}
|
|
752
|
+
function pluginEndpointRequestParts(contract, endpoint, payload, explicitBaseUrl) {
|
|
753
|
+
const payloadObject = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
754
|
+
const pathParams = endpoint.pathParams ?? [];
|
|
755
|
+
const requestPayload = withDefaultPathParams(payloadObject, pathParams);
|
|
756
|
+
const path = encodePath(endpoint.path, requestPayload, pathParams);
|
|
757
|
+
const query = queryParamsFromPayload(requestPayload, pathParams, endpoint.queryParams, endpoint.path, endpoint.method === "get");
|
|
758
|
+
return {
|
|
759
|
+
baseUrl: resolvePluginBaseUrl(contract, explicitBaseUrl),
|
|
760
|
+
path,
|
|
761
|
+
query,
|
|
762
|
+
requestPayload
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function appendQueryValue(params, key, value) {
|
|
766
|
+
if (value === void 0 || value === null) return;
|
|
767
|
+
if (Array.isArray(value)) {
|
|
768
|
+
for (const item of value) appendQueryValue(params, key, item);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
if (typeof value === "object") {
|
|
772
|
+
params.append(key, JSON.stringify(value));
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
params.append(key, String(value));
|
|
776
|
+
}
|
|
777
|
+
function queryString(query) {
|
|
778
|
+
const params = new URLSearchParams();
|
|
779
|
+
for (const [key, value] of Object.entries(query)) appendQueryValue(params, key, value);
|
|
780
|
+
const serialized = params.toString();
|
|
781
|
+
return serialized ? `?${serialized}` : "";
|
|
782
|
+
}
|
|
783
|
+
function joinBaseUrl(baseUrl, path) {
|
|
784
|
+
if (!baseUrl) return path;
|
|
785
|
+
return `${baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
786
|
+
}
|
|
787
|
+
/** Build the concrete URL for a generated plugin endpoint without making a request. */
|
|
788
|
+
function buildPluginEndpointUrl(contract, endpoint, payload, options = {}) {
|
|
789
|
+
const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
|
|
790
|
+
const pathWithQuery = `${parts.path}${queryString(parts.query)}`;
|
|
791
|
+
if (options.includeBaseUrl === false) return pathWithQuery;
|
|
792
|
+
return joinBaseUrl(parts.baseUrl, pathWithQuery);
|
|
793
|
+
}
|
|
794
|
+
/** Create a typed plugin API client from a generated MINT plugin contract. */
|
|
795
|
+
function createPluginClient(contract, options) {
|
|
796
|
+
const client = {};
|
|
797
|
+
for (const [name, endpoint] of Object.entries(options.endpoints)) client[name] = async (payload) => {
|
|
798
|
+
const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
|
|
799
|
+
const api = useApi({ baseUrl: parts.baseUrl });
|
|
800
|
+
const queryConfig = hasKeys(parts.query) ? { params: parts.query } : void 0;
|
|
801
|
+
if (endpoint.method === "get") return api.get(parts.path, queryConfig);
|
|
802
|
+
if (endpoint.method === "delete") {
|
|
803
|
+
const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
|
|
804
|
+
const config = body === void 0 ? queryConfig : {
|
|
805
|
+
...queryConfig,
|
|
806
|
+
data: body
|
|
807
|
+
};
|
|
808
|
+
return api.delete(parts.path, config);
|
|
706
809
|
}
|
|
810
|
+
const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
|
|
811
|
+
if (endpoint.method === "post") return api.post(parts.path, body, queryConfig);
|
|
812
|
+
if (endpoint.method === "put") return api.put(parts.path, body, queryConfig);
|
|
813
|
+
if (endpoint.method === "patch") return api.patch(parts.path, body, queryConfig);
|
|
814
|
+
throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`);
|
|
815
|
+
};
|
|
816
|
+
return client;
|
|
817
|
+
}
|
|
818
|
+
/** Return a generated plugin client from setup code with a stable typed identity. */
|
|
819
|
+
function usePluginClient(client) {
|
|
820
|
+
return client;
|
|
821
|
+
}
|
|
822
|
+
/** Read plugin settings exposed through the platform context. */
|
|
823
|
+
function usePluginSettings() {
|
|
824
|
+
const { plugin } = usePlatformContext();
|
|
825
|
+
return { settings: computed(() => plugin.value?.settings) };
|
|
826
|
+
}
|
|
827
|
+
/** Read and optionally load the current platform experiment for integrated plugin views. */
|
|
828
|
+
function useCurrentExperiment(options = {}) {
|
|
829
|
+
const api = useApi({ baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl });
|
|
830
|
+
const experiment = shallowRef(currentExperimentFromContext());
|
|
831
|
+
const request = useRequestSyncState("Failed to load current experiment");
|
|
832
|
+
const isLoading = request.loading;
|
|
833
|
+
const error = request.error;
|
|
834
|
+
const lastLoadedAt = request.lastLoadedAt;
|
|
835
|
+
const experimentId = computed(() => {
|
|
836
|
+
return resolveCurrentExperimentId();
|
|
837
|
+
});
|
|
838
|
+
const hasExperiment = computed(() => experimentId.value !== void 0);
|
|
839
|
+
function requireExperimentId() {
|
|
840
|
+
const id = experimentId.value;
|
|
841
|
+
if (id === void 0) throw new Error("[MINT SDK] No current experiment is selected.");
|
|
842
|
+
return id;
|
|
707
843
|
}
|
|
708
|
-
async function
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
return
|
|
844
|
+
async function fetchExperiment(id = experimentId.value) {
|
|
845
|
+
if (id === void 0) {
|
|
846
|
+
experiment.value = currentExperimentFromContext();
|
|
847
|
+
return experiment.value;
|
|
712
848
|
}
|
|
713
|
-
isSaving.value = true;
|
|
714
|
-
error.value = null;
|
|
715
849
|
try {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
schema_version: schemaVersion
|
|
850
|
+
const result = await request.run(() => api.get(`/experiments/${id}`), {
|
|
851
|
+
success: "load",
|
|
852
|
+
errorMessage: "Failed to load current experiment"
|
|
720
853
|
});
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return true;
|
|
854
|
+
experiment.value = result;
|
|
855
|
+
return result;
|
|
724
856
|
} catch (e) {
|
|
725
|
-
|
|
726
|
-
return
|
|
727
|
-
} finally {
|
|
728
|
-
isSaving.value = false;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
async function loadDesign(experimentId) {
|
|
732
|
-
try {
|
|
733
|
-
return await api.get(`/experiments/${experimentId}/data`);
|
|
734
|
-
} catch {
|
|
735
|
-
return null;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
async function loadAnalysis(experimentId) {
|
|
739
|
-
if (!pluginId) return null;
|
|
740
|
-
try {
|
|
741
|
-
return await api.get(`/experiments/${experimentId}/results/${pluginId}`);
|
|
742
|
-
} catch {
|
|
743
|
-
return null;
|
|
857
|
+
experiment.value = void 0;
|
|
858
|
+
return;
|
|
744
859
|
}
|
|
745
860
|
}
|
|
746
|
-
async function
|
|
747
|
-
|
|
748
|
-
await api.delete(`/experiments/${experimentId}/data`);
|
|
749
|
-
return true;
|
|
750
|
-
} catch {
|
|
751
|
-
return false;
|
|
752
|
-
}
|
|
861
|
+
async function refresh() {
|
|
862
|
+
return fetchExperiment();
|
|
753
863
|
}
|
|
754
|
-
|
|
755
|
-
if (
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
return
|
|
759
|
-
} catch {
|
|
760
|
-
return false;
|
|
864
|
+
watch(experimentId, (id) => {
|
|
865
|
+
if (options.immediate === false) return;
|
|
866
|
+
if (id === void 0) {
|
|
867
|
+
experiment.value = currentExperimentFromContext();
|
|
868
|
+
return;
|
|
761
869
|
}
|
|
762
|
-
|
|
870
|
+
fetchExperiment(id);
|
|
871
|
+
}, { immediate: options.immediate !== false });
|
|
763
872
|
return {
|
|
764
|
-
|
|
873
|
+
experimentId,
|
|
874
|
+
hasExperiment,
|
|
875
|
+
experiment,
|
|
876
|
+
isLoading,
|
|
765
877
|
error,
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
loadDesign,
|
|
771
|
-
loadAnalysis,
|
|
772
|
-
deleteDesign,
|
|
773
|
-
deleteAnalysis
|
|
878
|
+
lastLoadedAt,
|
|
879
|
+
requireExperimentId,
|
|
880
|
+
fetch: fetchExperiment,
|
|
881
|
+
refresh
|
|
774
882
|
};
|
|
775
883
|
}
|
|
776
884
|
//#endregion
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
* Pre-configured API client for plugins.
|
|
780
|
-
*
|
|
781
|
-
* Resolves the base URL in priority order:
|
|
782
|
-
* 1. `import.meta.env.VITE_API_PREFIX` (build-time env override)
|
|
783
|
-
* 2. `fallbackPrefix` option (plugin's route prefix)
|
|
784
|
-
* 3. `'/api'` (default)
|
|
785
|
-
*
|
|
786
|
-
* Eliminates the repeated pattern across plugins:
|
|
787
|
-
* ```ts
|
|
788
|
-
* const API_BASE = import.meta.env.VITE_API_PREFIX || '/api/my-plugin'
|
|
789
|
-
* const api = useApi({ baseUrl: API_BASE })
|
|
790
|
-
* ```
|
|
791
|
-
*
|
|
792
|
-
* @example
|
|
793
|
-
* ```ts
|
|
794
|
-
* const api = usePluginApi({ fallbackPrefix: '/api/drp' })
|
|
795
|
-
* const data = await api.get('/sessions')
|
|
796
|
-
* ```
|
|
797
|
-
*/
|
|
798
|
-
/** Pre-configured API client resolving the plugin base URL from VITE_API_PREFIX or a fallback prefix. */
|
|
799
|
-
function usePluginApi(options = {}) {
|
|
800
|
-
return useApi({ baseUrl: options.fallbackPrefix || "/api" });
|
|
801
|
-
}
|
|
802
|
-
//#endregion
|
|
803
|
-
export { useAsyncBatch as a, useAsync as i, useExperimentSave as n, usePasskey as o, usePluginConfig as r, useAuth as s, usePluginApi as t };
|
|
885
|
+
export { usePluginClient as a, usePluginConfig as c, usePasskey as d, useAuth as f, useCurrentExperiment as i, useAsync as l, createPluginClient as n, usePluginSettings as o, resolvePluginBaseUrl as r, usePluginApi as s, buildPluginEndpointUrl as t, useAsyncBatch as u };
|
|
804
886
|
|
|
805
|
-
//# sourceMappingURL=composables-
|
|
887
|
+
//# sourceMappingURL=composables-C3dpXQN5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composables-C3dpXQN5.js","names":[],"sources":["../src/composables/useAuth.ts","../src/composables/usePasskey.ts","../src/composables/useAsync.ts","../src/composables/usePluginConfig.ts","../src/composables/usePluginApi.ts","../src/composables/usePluginClient.ts"],"sourcesContent":["import axios from 'axios'\nimport { ref, onMounted, onUnmounted, watch, getCurrentInstance, type Ref } from 'vue'\nimport { useAuthStore } from '../stores/auth'\nimport { useSettingsStore } from '../stores/settings'\nimport type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, UpdateProfileRequest } from '../types'\n\ninterface UserResponse {\n id: string\n username: string\n shortname: string | null\n email: string | null\n role: string\n is_active: boolean\n}\n\ninterface RefreshResponse {\n access_token: string\n expires_in: number\n token_type: string\n}\n\n// Token refresh configuration\nconst TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1000 // Refresh 5 minutes before expiry\nconst TOKEN_REFRESH_CHECK_INTERVAL_MS = 60 * 1000 // Check every minute\n\n/**\n * Authentication composable with automatic token refresh.\n *\n * Features:\n * - Automatic token refresh before expiration\n * - Login/logout/register functionality\n * - Token verification on startup\n * - User profile management\n *\n * @example\n * ```typescript\n * const { login, logout, isAuthenticated, user } = useAuth()\n *\n * // Login\n * const success = await login('username', 'password')\n *\n * // Automatic refresh is enabled by default\n * // Tokens are refreshed 5 minutes before expiration\n * ```\n */\nexport interface UseAuthReturn {\n login: (username: string, password: string) => Promise<boolean>\n logout: () => void\n register: (username: string, password: string, email?: string) => Promise<boolean>\n verifyToken: () => Promise<boolean>\n fetchAuthConfig: () => Promise<AuthConfig>\n initializeAuth: () => Promise<void>\n getCurrentUser: () => Promise<UserInfo | null>\n getAuthHeader: () => Record<string, string>\n updateProfile: (data: { email?: string; shortname?: string; currentPassword?: string; newPassword?: string }) => Promise<{ success: boolean; error?: string }>\n refreshToken: () => Promise<boolean>\n isRefreshing: Ref<boolean>\n}\n\n// Module-level singletons to prevent duplicate refresh requests and timers\n// across multiple useAuth() instances\nlet _refreshPromise: Promise<boolean> | null = null\nlet _refreshTimerId: number | null = null\nlet _mountedConsumerCount = 0\n\n/** @internal Reset module-level state — only for use in tests. */\nexport function _resetAuthStateForTesting(): void {\n _refreshPromise = null\n if (_refreshTimerId !== null) {\n clearTimeout(_refreshTimerId)\n _refreshTimerId = null\n }\n _mountedConsumerCount = 0\n}\n\n/** Manages authentication state with login/logout/register and automatic JWT token refresh. */\nexport function useAuth(): UseAuthReturn {\n const authStore = useAuthStore()\n const settingsStore = useSettingsStore()\n\n const isRefreshing = ref(false)\n\n function getApiBaseUrl(): string {\n return settingsStore.getApiBaseUrl()\n }\n\n async function fetchAuthConfig(): Promise<AuthConfig> {\n try {\n const response = await axios.get<{\n auth_required: boolean\n passkey_enabled: boolean\n passkey_registered?: boolean\n registration_enabled?: boolean\n database_mode?: string\n }>(`${getApiBaseUrl()}/setup/config/public`)\n\n const config: AuthConfig = {\n authRequired: response.data.auth_required,\n passkeyEnabled: response.data.passkey_enabled,\n passkeyRegistered: response.data.passkey_registered ?? false,\n registrationEnabled: response.data.registration_enabled ?? false,\n databaseMode: response.data.database_mode ?? 'none',\n }\n\n authStore.setAuthConfig(config)\n return config\n } catch (error) {\n console.error('Failed to fetch auth config:', error)\n return {\n authRequired: false,\n passkeyEnabled: false,\n passkeyRegistered: false,\n registrationEnabled: false,\n databaseMode: 'none',\n }\n }\n }\n\n async function login(username: string, password: string): Promise<boolean> {\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const response = await axios.post<LoginResponse>(\n `${getApiBaseUrl()}/auth/login`,\n { username, password }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n authStore.setUsername(username)\n\n await getCurrentUser()\n\n // Start auto-refresh after successful login\n scheduleTokenRefresh()\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Login failed')\n } else {\n authStore.setError('Network error. Please try again.')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function register(username: string, password: string, email?: string): Promise<boolean> {\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n await axios.post<UserResponse>(\n `${getApiBaseUrl()}/users/register`,\n { username, password, email }\n )\n\n return await login(username, password)\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Registration failed')\n } else {\n authStore.setError('Network error. Please try again.')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function getCurrentUser(): Promise<UserInfo | null> {\n if (!authStore.token) {\n return null\n }\n\n try {\n const response = await axios.get<UserResponse>(\n `${getApiBaseUrl()}/users/me`,\n { headers: getAuthHeader() }\n )\n\n const userInfo: UserInfo = {\n id: response.data.id,\n username: response.data.username,\n shortname: response.data.shortname,\n email: response.data.email,\n role: response.data.role,\n isActive: response.data.is_active,\n }\n\n authStore.setUserInfo(userInfo)\n return userInfo\n } catch {\n return null\n }\n }\n\n async function verifyToken(): Promise<boolean> {\n if (!authStore.token) {\n return false\n }\n\n try {\n const response = await axios.get<TokenVerifyResponse>(\n `${getApiBaseUrl()}/auth/verify`,\n {\n headers: {\n Authorization: `Bearer ${authStore.token}`,\n },\n }\n )\n\n if (response.data.valid && response.data.username) {\n authStore.setUsername(response.data.username)\n return true\n }\n\n authStore.clearToken()\n return false\n } catch {\n authStore.clearToken()\n return false\n }\n }\n\n /**\n * Refresh the authentication token.\n * Called automatically before token expiration.\n * Uses promise caching to prevent concurrent refresh requests.\n */\n async function refreshToken(): Promise<boolean> {\n if (!authStore.token) return false\n if (_refreshPromise) return _refreshPromise\n\n _refreshPromise = (async () => {\n isRefreshing.value = true\n\n try {\n const response = await axios.post<RefreshResponse>(\n `${getApiBaseUrl()}/auth/refresh`,\n {},\n { headers: getAuthHeader() }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n\n // Reschedule next refresh\n scheduleTokenRefresh()\n\n return true\n } catch (error) {\n // If refresh fails, the token may have been revoked\n // Clear auth state and let user re-login\n if (axios.isAxiosError(error) && error.response?.status === 401) {\n console.warn('[Auth] Token refresh failed - session expired')\n authStore.clearToken()\n stopTokenRefresh()\n }\n return false\n } finally {\n isRefreshing.value = false\n _refreshPromise = null\n }\n })()\n\n return _refreshPromise\n }\n\n /**\n * Schedule automatic token refresh before expiration.\n */\n function scheduleTokenRefresh(): void {\n // Clear any existing timer\n stopTokenRefresh()\n\n if (!authStore.tokenExpires) {\n return\n }\n\n const expiresAt = authStore.tokenExpires.getTime()\n const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS\n const now = Date.now()\n\n if (refreshAt <= now) {\n // Token is already close to expiring or expired, refresh now\n refreshToken()\n return\n }\n\n // Schedule refresh\n const delay = refreshAt - now\n _refreshTimerId = window.setTimeout(() => {\n refreshToken()\n }, delay)\n }\n\n /**\n * Stop automatic token refresh.\n */\n function stopTokenRefresh(): void {\n if (_refreshTimerId !== null) {\n window.clearTimeout(_refreshTimerId)\n _refreshTimerId = null\n }\n }\n\n /**\n * Check if token needs refresh and refresh if necessary.\n * Called periodically as a safety net.\n */\n function checkAndRefreshIfNeeded(): void {\n if (!authStore.token || !authStore.tokenExpires) {\n return\n }\n\n const expiresAt = authStore.tokenExpires.getTime()\n const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS\n const now = Date.now()\n\n if (now >= refreshAt) {\n refreshToken()\n }\n }\n\n async function initializeAuth(): Promise<void> {\n authStore.initialize()\n await fetchAuthConfig()\n\n if (authStore.token) {\n const valid = await verifyToken()\n if (valid) {\n await getCurrentUser()\n // Start auto-refresh for existing session\n scheduleTokenRefresh()\n }\n }\n }\n\n function logout(): void {\n stopTokenRefresh()\n authStore.logout()\n }\n\n function getAuthHeader(): Record<string, string> {\n if (authStore.token) {\n return { Authorization: `Bearer ${authStore.token}` }\n }\n return {}\n }\n\n async function updateProfile(data: {\n email?: string\n shortname?: string\n currentPassword?: string\n newPassword?: string\n }): Promise<{ success: boolean; error?: string }> {\n if (!authStore.token) {\n return { success: false, error: 'Not authenticated' }\n }\n\n try {\n const requestData: UpdateProfileRequest = {}\n if (data.email !== undefined) requestData.email = data.email\n if (data.shortname !== undefined) requestData.shortname = data.shortname\n if (data.currentPassword) requestData.current_password = data.currentPassword\n if (data.newPassword) requestData.new_password = data.newPassword\n\n const response = await axios.put<UserResponse>(\n `${getApiBaseUrl()}/users/me`,\n requestData,\n { headers: getAuthHeader() }\n )\n\n const userInfo: UserInfo = {\n id: response.data.id,\n username: response.data.username,\n shortname: response.data.shortname,\n email: response.data.email,\n role: response.data.role,\n isActive: response.data.is_active,\n }\n authStore.setUserInfo(userInfo)\n\n return { success: true }\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n return { success: false, error: error.response.data.detail || 'Update failed' }\n }\n return { success: false, error: 'Network error. Please try again.' }\n }\n }\n\n // Set up periodic check as safety net (only inside component setup)\n let checkInterval: number | null = null\n\n if (getCurrentInstance()) {\n onMounted(() => {\n _mountedConsumerCount += 1\n checkInterval = window.setInterval(checkAndRefreshIfNeeded, TOKEN_REFRESH_CHECK_INTERVAL_MS)\n })\n\n onUnmounted(() => {\n if (checkInterval !== null) {\n window.clearInterval(checkInterval)\n checkInterval = null\n }\n\n _mountedConsumerCount = Math.max(0, _mountedConsumerCount - 1)\n if (_mountedConsumerCount === 0) {\n stopTokenRefresh()\n }\n })\n\n // Watch for token changes to reschedule refresh\n watch(\n () => authStore.tokenExpires,\n (newExpires) => {\n if (newExpires) {\n scheduleTokenRefresh()\n } else {\n stopTokenRefresh()\n }\n }\n )\n }\n\n return {\n // Core auth methods\n login,\n logout,\n register,\n verifyToken,\n fetchAuthConfig,\n initializeAuth,\n getCurrentUser,\n getAuthHeader,\n updateProfile,\n\n // Token refresh\n refreshToken,\n isRefreshing,\n }\n}\n","import axios from 'axios'\nimport { useAuthStore } from '../stores/auth'\nimport { useSettingsStore } from '../stores/settings'\nimport type { CredentialInfo } from '../types'\n\n// Lazy-load @simplewebauthn/browser so plugins that never call usePasskey\n// don't need the optional peer dep installed (avoids build failures).\nasync function loadWebAuthn() {\n try {\n return await import('@simplewebauthn/browser')\n } catch {\n throw new Error(\n '@simplewebauthn/browser is required for passkey support. Install it: bun add @simplewebauthn/browser',\n )\n }\n}\n\ninterface PasskeyLoginResponse {\n access_token: string\n token_type: string\n expires_in: number\n}\n\n/** Registers and authenticates passkeys using WebAuthn, lazily loading the browser dependency. */\nexport function usePasskey() {\n const authStore = useAuthStore()\n const settingsStore = useSettingsStore()\n\n function getApiBaseUrl(): string {\n return settingsStore.getApiBaseUrl()\n }\n\n async function isSupported(): Promise<boolean> {\n try {\n const { browserSupportsWebAuthn } = await loadWebAuthn()\n return browserSupportsWebAuthn()\n } catch {\n return false\n }\n }\n\n async function registerPasskey(deviceName?: string): Promise<boolean> {\n const webauthn = await loadWebAuthn()\n if (!webauthn.browserSupportsWebAuthn()) {\n authStore.setError('WebAuthn is not supported in this browser')\n return false\n }\n\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const optionsResponse = await axios.get<{ options: string }>(\n `${getApiBaseUrl()}/auth/passkey/register/options`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n withCredentials: true,\n }\n )\n\n const options = JSON.parse(optionsResponse.data.options)\n\n const credential = await webauthn.startRegistration(options)\n\n await axios.post(\n `${getApiBaseUrl()}/auth/passkey/register/verify`,\n {\n credential: JSON.stringify(credential),\n device_name: deviceName,\n },\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n withCredentials: true,\n }\n )\n\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: true,\n })\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Passkey registration failed')\n } else if (error instanceof Error) {\n if (error.name === 'NotAllowedError') {\n authStore.setError('Registration was cancelled or timed out')\n } else if (error.name === 'InvalidStateError') {\n authStore.setError('This authenticator is already registered')\n } else {\n authStore.setError(error.message)\n }\n } else {\n authStore.setError('Passkey registration failed')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function loginWithPasskey(): Promise<boolean> {\n const webauthn = await loadWebAuthn()\n if (!webauthn.browserSupportsWebAuthn()) {\n authStore.setError('WebAuthn is not supported in this browser')\n return false\n }\n\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const optionsResponse = await axios.get<{ options: string }>(\n `${getApiBaseUrl()}/auth/passkey/login/options`,\n { withCredentials: true }\n )\n\n const options = JSON.parse(optionsResponse.data.options)\n\n const credential = await webauthn.startAuthentication(options)\n\n const response = await axios.post<PasskeyLoginResponse>(\n `${getApiBaseUrl()}/auth/passkey/login/verify`,\n { credential: JSON.stringify(credential) },\n { withCredentials: true }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n if (error.response.status === 404) {\n authStore.setError('No passkeys registered. Please login with password first.')\n } else {\n authStore.setError(error.response.data.detail || 'Passkey login failed')\n }\n } else if (error instanceof Error) {\n if (error.name === 'NotAllowedError') {\n authStore.setError('Authentication was cancelled or timed out')\n } else {\n authStore.setError(error.message)\n }\n } else {\n authStore.setError('Passkey login failed')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function listCredentials(): Promise<CredentialInfo[]> {\n try {\n const response = await axios.get<{ credentials: CredentialInfo[] }>(\n `${getApiBaseUrl()}/auth/passkey/credentials`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n }\n )\n return response.data.credentials\n } catch {\n return []\n }\n }\n\n async function deleteCredential(credentialId: string): Promise<boolean> {\n try {\n await axios.delete(\n `${getApiBaseUrl()}/auth/passkey/credentials/${encodeURIComponent(credentialId)}`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n }\n )\n\n const remaining = await listCredentials()\n if (remaining.length === 0) {\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: false,\n })\n }\n\n return true\n } catch {\n return false\n }\n }\n\n async function deleteAllCredentials(): Promise<boolean> {\n try {\n await axios.delete(`${getApiBaseUrl()}/auth/passkey/credentials`, {\n headers: { Authorization: `Bearer ${authStore.token}` },\n })\n\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: false,\n })\n\n return true\n } catch {\n return false\n }\n }\n\n return {\n isSupported,\n registerPasskey,\n loginWithPasskey,\n listCredentials,\n deleteCredential,\n deleteAllCredentials,\n }\n}\n","import { ref, computed, type Ref, type ComputedRef } from 'vue'\n\n/**\n * Error type for async operations.\n */\nexport interface AsyncError {\n message: string\n code?: string\n details?: Record<string, unknown>\n originalError?: unknown\n}\n\n/**\n * State of an async operation.\n */\nexport type AsyncState = 'idle' | 'loading' | 'success' | 'error'\n\n/**\n * Return type for useAsync composable.\n */\nexport interface UseAsyncReturn<T> {\n // Data\n data: Ref<T | null>\n error: Ref<AsyncError | null>\n\n // State\n state: Ref<AsyncState>\n isIdle: ComputedRef<boolean>\n isLoading: ComputedRef<boolean>\n isSuccess: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n\n // Methods\n execute: (...args: unknown[]) => Promise<T | null>\n reset: () => void\n setData: (data: T | null) => void\n setError: (error: AsyncError | null) => void\n}\n\n/**\n * Options for useAsync.\n */\nexport interface UseAsyncOptions<T> {\n // Initial data value\n initialData?: T | null\n\n // Whether to run immediately on creation\n immediate?: boolean\n\n // Arguments for immediate execution\n immediateArgs?: unknown[]\n\n // Transform error into AsyncError\n transformError?: (error: unknown) => AsyncError\n\n // Called on success\n onSuccess?: (data: T) => void\n\n // Called on error\n onError?: (error: AsyncError) => void\n\n // Reset data on new execution\n resetOnExecute?: boolean\n}\n\n/**\n * Default error transformer.\n */\nfunction defaultTransformError(error: unknown): AsyncError {\n if (error instanceof Error) {\n return {\n message: error.message,\n originalError: error,\n }\n }\n\n if (typeof error === 'object' && error !== null) {\n const errorObj = error as Record<string, unknown>\n\n // Handle Axios-like errors\n if ('response' in errorObj && errorObj.response) {\n const response = errorObj.response as Record<string, unknown>\n const data = response.data as Record<string, unknown> | undefined\n\n return {\n message: (data?.detail as string) || (data?.message as string) || 'Request failed',\n code: String(response.status),\n details: data,\n originalError: error,\n }\n }\n\n // Handle generic error objects\n return {\n message: (errorObj.message as string) || 'Unknown error',\n code: errorObj.code as string | undefined,\n details: errorObj,\n originalError: error,\n }\n }\n\n return {\n message: String(error),\n originalError: error,\n }\n}\n\n/**\n * Composable for managing async operation state.\n *\n * Provides standardized loading, error, and success state management\n * for any async function.\n *\n * @param asyncFn - The async function to wrap\n * @param options - Configuration options\n *\n * @example\n * ```typescript\n * // Basic usage\n * const { data, isLoading, error, execute } = useAsync(\n * async (id: string) => {\n * const response = await api.get(`/users/${id}`)\n * return response.data\n * }\n * )\n *\n * // Execute the function\n * await execute('user-123')\n *\n * // In template\n * <div v-if=\"isLoading\">Loading...</div>\n * <div v-else-if=\"error\">{{ error.message }}</div>\n * <div v-else-if=\"data\">{{ data.name }}</div>\n * ```\n *\n * @example\n * ```typescript\n * // With options\n * const { data, execute } = useAsync(\n * fetchUser,\n * {\n * immediate: true,\n * immediateArgs: ['default-user'],\n * onSuccess: (user) => console.log('Fetched:', user.name),\n * onError: (error) => toast.error(error.message),\n * }\n * )\n * ```\n *\n * @example\n * ```typescript\n * // Form submission\n * const { isLoading, error, execute: submit } = useAsync(\n * async (formData: FormData) => {\n * await api.post('/submit', formData)\n * },\n * {\n * onSuccess: () => {\n * toast.success('Submitted!')\n * router.push('/success')\n * },\n * }\n * )\n *\n * const handleSubmit = () => submit(new FormData(formRef.value))\n * ```\n */\n/** Wraps an async function with reactive loading, error, and success state plus optional auto-execute. */\nexport function useAsync<T>(\n asyncFn: (...args: unknown[]) => Promise<T>,\n options: UseAsyncOptions<T> = {}\n): UseAsyncReturn<T> {\n const {\n initialData = null,\n immediate = false,\n immediateArgs = [],\n transformError = defaultTransformError,\n onSuccess,\n onError,\n resetOnExecute = false,\n } = options\n\n // State\n const data = ref<T | null>(initialData) as Ref<T | null>\n const error = ref<AsyncError | null>(null)\n const state = ref<AsyncState>('idle')\n\n // Computed state helpers\n const isIdle = computed(() => state.value === 'idle')\n const isLoading = computed(() => state.value === 'loading')\n const isSuccess = computed(() => state.value === 'success')\n const isError = computed(() => state.value === 'error')\n\n // Execute the async function\n async function execute(...args: unknown[]): Promise<T | null> {\n state.value = 'loading'\n error.value = null\n\n if (resetOnExecute) {\n data.value = null\n }\n\n try {\n const result = await asyncFn(...args)\n data.value = result\n state.value = 'success'\n onSuccess?.(result)\n return result\n } catch (e) {\n const asyncError = transformError(e)\n error.value = asyncError\n state.value = 'error'\n onError?.(asyncError)\n return null\n }\n }\n\n // Reset to initial state\n function reset(): void {\n data.value = initialData\n error.value = null\n state.value = 'idle'\n }\n\n // Manual data setter\n function setData(newData: T | null): void {\n data.value = newData\n if (newData !== null) {\n state.value = 'success'\n error.value = null\n }\n }\n\n // Manual error setter\n function setError(newError: AsyncError | null): void {\n error.value = newError\n if (newError !== null) {\n state.value = 'error'\n }\n }\n\n // Execute immediately if requested\n if (immediate) {\n execute(...immediateArgs)\n }\n\n return {\n data,\n error,\n state,\n isIdle,\n isLoading,\n isSuccess,\n isError,\n execute,\n reset,\n setData,\n setError,\n }\n}\n\n/**\n * Create a batch of async operations that can be executed in parallel.\n *\n * @example\n * ```typescript\n * const { results, isLoading, execute } = useAsyncBatch([\n * () => fetchUser(userId),\n * () => fetchPosts(userId),\n * () => fetchComments(userId),\n * ])\n *\n * await execute()\n * // results.value = [user, posts, comments]\n * ```\n */\nexport function useAsyncBatch<T extends readonly (() => Promise<unknown>)[]>(\n asyncFns: T\n): {\n results: Ref<{ [K in keyof T]: Awaited<ReturnType<T[K]>> | null }>\n errors: Ref<(AsyncError | null)[]>\n isLoading: Ref<boolean>\n execute: () => Promise<void>\n reset: () => void\n} {\n type Results = { [K in keyof T]: Awaited<ReturnType<T[K]>> | null }\n\n const results = ref<Results>(asyncFns.map(() => null) as unknown as Results) as Ref<Results>\n const errors = ref<(AsyncError | null)[]>(asyncFns.map(() => null))\n const isLoading = ref(false)\n\n async function execute(): Promise<void> {\n isLoading.value = true\n errors.value = asyncFns.map(() => null)\n\n const promises = asyncFns.map(async (fn, index) => {\n try {\n const result = await fn()\n ;(results.value as unknown[])[index] = result\n } catch (e) {\n errors.value[index] = defaultTransformError(e)\n ;(results.value as unknown[])[index] = null\n }\n })\n\n await Promise.all(promises)\n isLoading.value = false\n }\n\n function reset(): void {\n results.value = asyncFns.map(() => null) as unknown as Results\n errors.value = asyncFns.map(() => null)\n isLoading.value = false\n }\n\n return {\n results,\n errors,\n isLoading,\n execute,\n reset,\n }\n}\n","import { ref, computed, onMounted, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\nimport { useRequestSyncState } from './useRequestSyncState'\n\nexport interface UsePluginConfigReturn {\n /** Editable plugin configuration values. */\n config: Ref<Record<string, unknown>>\n /** Whether the config is currently loading. */\n isLoading: Ref<boolean>\n /** Whether the config is currently saving. */\n isSaving: Ref<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save, or null. */\n lastSavedAt: Ref<Date | null>\n /** Whether local config differs from the last loaded or saved snapshot. */\n isDirty: ComputedRef<boolean>\n /** Load plugin configuration from the platform. */\n load: () => Promise<void>\n /** Save plugin configuration to the platform. */\n save: () => Promise<boolean>\n /** Restore the last loaded or saved configuration snapshot. */\n reset: () => void\n}\n\n/** Loads, saves, and tracks dirty state for a plugin's persistent configuration via the platform API. */\nexport function usePluginConfig(pluginName?: string): UsePluginConfigReturn {\n const api = useApi()\n const { plugin } = usePlatformContext()\n\n const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? '')\n\n const config = ref<Record<string, unknown>>({})\n const savedConfig = ref<Record<string, unknown>>({})\n const request = useRequestSyncState('Plugin config request failed.')\n const isLoading = ref(false)\n const isSaving = ref(false)\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const lastSavedAt = request.lastSavedAt\n\n const isDirty = computed(() => {\n return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value)\n })\n\n async function load(): Promise<void> {\n const name = resolvedName.value\n if (!name) return\n\n isLoading.value = true\n try {\n const response = await request.run(\n () => api.get<{ plugin_name: string; config: Record<string, unknown> }>(\n `/plugins/${encodeURIComponent(name)}/config`,\n ),\n { success: 'load', errorMessage: 'Failed to load plugin config' },\n )\n config.value = { ...response.config }\n savedConfig.value = { ...response.config }\n } catch {\n // Error state is handled by request.run().\n } finally {\n isLoading.value = false\n }\n }\n\n async function save(): Promise<boolean> {\n const name = resolvedName.value\n if (!name) return false\n\n isSaving.value = true\n try {\n const response = await request.run(\n () => api.patch<{ plugin_name: string; config: Record<string, unknown> }>(\n `/plugins/${encodeURIComponent(name)}/config`,\n { config: config.value },\n ),\n { success: 'save', errorMessage: 'Failed to save plugin config' },\n )\n config.value = { ...response.config }\n savedConfig.value = { ...response.config }\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n function reset(): void {\n config.value = { ...savedConfig.value }\n request.clearError()\n }\n\n onMounted(() => {\n load()\n })\n\n return {\n config,\n isLoading,\n isSaving,\n error,\n lastLoadedAt,\n lastSavedAt,\n isDirty,\n load,\n save,\n reset,\n }\n}\n","import { useApi } from './useApi'\n\nexport interface UsePluginApiOptions {\n /**\n * Fallback API prefix when `VITE_API_PREFIX` is not set.\n * Typically your plugin's route prefix, e.g. `'/api/drp'`.\n */\n fallbackPrefix?: string\n}\n\n/**\n * Legacy plugin API client resolving the plugin base URL from VITE_API_PREFIX or a fallback prefix.\n *\n * @deprecated Use `useGeneratedPluginClient()` from `mint sdk generate` for new\n * plugin frontends. This helper remains as a compatibility shim for older\n * plugins that still hand-wire API prefixes.\n *\n * Migration shape for generated plugins:\n * ```ts\n * import { useGeneratedPluginClient } from '../generated/mint-plugin'\n *\n * const pluginClient = useGeneratedPluginClient()\n * ```\n */\nexport function usePluginApi(options: UsePluginApiOptions = {}) {\n const baseUrl =\n (import.meta.env?.VITE_API_PREFIX as string | undefined) ||\n options.fallbackPrefix ||\n '/api'\n\n return useApi({ baseUrl })\n}\n","import { computed, shallowRef, watch, type ComputedRef, type Ref } from 'vue'\nimport { useApi } from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport {\n currentExperimentFromContext,\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\n\nexport type PluginHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport interface PluginEndpointContract {\n name: string\n method: PluginHttpMethod\n path: string\n pathParams?: string[]\n queryParams?: PluginEndpointParamContract[]\n requestType?: string | null\n responseType?: string | null\n}\n\nexport interface PluginEndpointParamContract {\n name: string\n fieldName: string\n type?: string\n required?: boolean\n}\n\nexport interface PluginNavItemContract {\n path: string\n label: string\n id?: string\n icon?: string\n description?: string\n requiresAuth?: boolean\n requiresAdmin?: boolean\n requiresFeature?: string\n}\n\nexport interface PluginContract {\n schemaVersion: number\n plugin: {\n name?: string\n packageName?: string\n version?: string\n description?: string\n routesPrefix: string\n apiPrefix: string\n type: 'analysis' | 'experiment-design' | string\n analysisType?: string\n icon?: string\n color?: string\n navItems?: PluginNavItemContract[]\n capabilities?: Record<string, unknown>\n }\n endpoints: PluginEndpointContract[]\n hash: string\n}\n\nexport interface PluginEndpointDefinition {\n method: PluginHttpMethod\n path: string\n pathParams?: string[]\n queryParams?: PluginEndpointParamDefinition[]\n hasBody?: boolean\n}\n\nexport type PluginEndpointParamDefinition = string | {\n name: string\n fieldName?: string\n type?: string\n required?: boolean\n}\n\nexport interface CreatePluginClientOptions {\n endpoints: Record<string, PluginEndpointDefinition>\n baseUrl?: string\n}\n\nexport interface BuildPluginEndpointUrlOptions {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Return only the endpoint path and query string instead of base URL + path. */\n includeBaseUrl?: boolean\n}\n\nexport interface UseCurrentExperimentOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseCurrentExperimentReturn<TExperiment = unknown> {\n /** Current experiment id resolved from platform injection or URL conventions. */\n experimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasExperiment: ComputedRef<boolean>\n /** Current experiment payload, if injected or successfully fetched. */\n experiment: Ref<TExperiment | undefined>\n /** Whether the current experiment is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed current-experiment fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful current-experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Return the current experiment id or throw a clear SDK error when absent. */\n requireExperimentId: () => number\n /** Fetch a specific experiment id, defaulting to the current experiment id. */\n fetch: (experimentId?: number) => Promise<TExperiment | undefined>\n /** Refetch the currently resolved experiment id. */\n refresh: () => Promise<TExperiment | undefined>\n}\n\nexport type PluginEndpointCaller = (payload?: unknown) => Promise<unknown>\nexport type GeneratedPluginClient = Record<string, (...args: any[]) => Promise<any>>\n\nfunction normalizeApiPrefix(prefix: string | undefined): string | undefined {\n if (!prefix) return undefined\n if (prefix.startsWith('/api/')) return prefix\n if (prefix === '/api') return prefix\n if (prefix.startsWith('/')) return `/api${prefix}`\n return `/api/${prefix}`\n}\n\n/** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */\nexport function resolvePluginBaseUrl(contract: PluginContract, explicitBaseUrl?: string): string {\n const envPrefix = (import.meta.env?.VITE_API_PREFIX as string | undefined) || undefined\n if (envPrefix) return envPrefix\n if (explicitBaseUrl) return explicitBaseUrl\n\n const injected = getInjectedPlatformContext()\n const platformPrefix =\n injected?.plugin?.api_prefix ||\n normalizeApiPrefix(injected?.plugin?.route_prefix)\n if (platformPrefix) return platformPrefix\n\n return contract.plugin.apiPrefix || '/api'\n}\n\nfunction encodePath(path: string, payload: Record<string, unknown>, pathParams: string[]): string {\n let nextPath = path\n for (const param of pathParams) {\n const value = payload[param]\n if (value === undefined || value === null) {\n throw new Error(`[MINT SDK] Missing path parameter '${param}' for plugin endpoint ${path}`)\n }\n nextPath = nextPath.replace(`{${param}}`, encodeURIComponent(String(value)))\n nextPath = nextPath.replace(`:${param}`, encodeURIComponent(String(value)))\n }\n return nextPath\n}\n\nfunction withDefaultPathParams(\n payload: Record<string, unknown>,\n pathParams: string[],\n): Record<string, unknown> {\n if (!pathParams.length) return payload\n const nextPayload = { ...payload }\n for (const param of pathParams) {\n if (nextPayload[param] !== undefined && nextPayload[param] !== null) continue\n if (isExperimentPathParam(param)) {\n const experimentId = resolveCurrentExperimentId()\n if (experimentId !== undefined) {\n nextPayload[param] = experimentId\n }\n }\n }\n return nextPayload\n}\n\nfunction isExperimentPathParam(param: string): boolean {\n return param === 'experimentId' || param === 'experiment_id'\n}\n\nfunction withoutPathParams(payload: Record<string, unknown>, pathParams: string[]) {\n const copy = { ...payload }\n for (const param of pathParams) {\n delete copy[param]\n }\n return copy\n}\n\nfunction queryParamsFromPayload(\n payload: Record<string, unknown>,\n pathParams: string[],\n queryParams?: PluginEndpointParamDefinition[],\n endpointPath?: string,\n includeUnspecifiedParams = false,\n) {\n if (!queryParams?.length) {\n return includeUnspecifiedParams ? withoutPathParams(payload, pathParams) : {}\n }\n\n const query: Record<string, unknown> = {}\n for (const param of queryParams) {\n const name = typeof param === 'string' ? param : param.name\n const fieldName = typeof param === 'string' ? param : param.fieldName ?? param.name\n const required = typeof param !== 'string' && param.required === true\n const value = payload[fieldName]\n if (value === undefined || value === null) {\n if (required) {\n throw new Error(\n `[MINT SDK] Missing query parameter '${fieldName}' for plugin endpoint ${endpointPath ?? ''}`,\n )\n }\n continue\n }\n query[name] = value\n }\n return query\n}\n\nfunction hasKeys(value: Record<string, unknown>): boolean {\n return Object.keys(value).length > 0\n}\n\nfunction requestBodyFromPayload(\n payload: unknown,\n requestPayload: Record<string, unknown>,\n endpoint: PluginEndpointDefinition,\n): unknown {\n if (!endpoint.hasBody) return undefined\n const body = endpoint.pathParams?.length || endpoint.queryParams?.length\n ? requestPayload.body\n : payload\n if (body === undefined || body === null) {\n throw new Error(`[MINT SDK] Missing request body for plugin endpoint ${endpoint.path}`)\n }\n return body\n}\n\nfunction pluginEndpointRequestParts(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n explicitBaseUrl?: string,\n) {\n const payloadObject =\n payload && typeof payload === 'object' && !Array.isArray(payload)\n ? payload as Record<string, unknown>\n : {}\n const pathParams = endpoint.pathParams ?? []\n const requestPayload = withDefaultPathParams(payloadObject, pathParams)\n const path = encodePath(endpoint.path, requestPayload, pathParams)\n const query = queryParamsFromPayload(\n requestPayload,\n pathParams,\n endpoint.queryParams,\n endpoint.path,\n endpoint.method === 'get',\n )\n\n return {\n baseUrl: resolvePluginBaseUrl(contract, explicitBaseUrl),\n path,\n query,\n requestPayload,\n }\n}\n\nfunction appendQueryValue(params: URLSearchParams, key: string, value: unknown): void {\n if (value === undefined || value === null) return\n if (Array.isArray(value)) {\n for (const item of value) {\n appendQueryValue(params, key, item)\n }\n return\n }\n if (typeof value === 'object') {\n params.append(key, JSON.stringify(value))\n return\n }\n params.append(key, String(value))\n}\n\nfunction queryString(query: Record<string, unknown>): string {\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n appendQueryValue(params, key, value)\n }\n const serialized = params.toString()\n return serialized ? `?${serialized}` : ''\n}\n\nfunction joinBaseUrl(baseUrl: string, path: string): string {\n if (!baseUrl) return path\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n return `${normalizedBase}${normalizedPath}`\n}\n\n/** Build the concrete URL for a generated plugin endpoint without making a request. */\nexport function buildPluginEndpointUrl(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: BuildPluginEndpointUrlOptions = {},\n): string {\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const pathWithQuery = `${parts.path}${queryString(parts.query)}`\n if (options.includeBaseUrl === false) return pathWithQuery\n return joinBaseUrl(parts.baseUrl, pathWithQuery)\n}\n\n/** Create a typed plugin API client from a generated MINT plugin contract. */\nexport function createPluginClient<TClient extends object = GeneratedPluginClient>(\n contract: PluginContract,\n options: CreatePluginClientOptions,\n): TClient {\n const client: Record<string, PluginEndpointCaller> = {}\n\n for (const [name, endpoint] of Object.entries(options.endpoints)) {\n client[name] = async (payload?: unknown) => {\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({ baseUrl: parts.baseUrl })\n const queryConfig = hasKeys(parts.query) ? { params: parts.query } : undefined\n\n if (endpoint.method === 'get') {\n return api.get(parts.path, queryConfig)\n }\n\n if (endpoint.method === 'delete') {\n const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n const config = body === undefined\n ? queryConfig\n : { ...queryConfig, data: body }\n return api.delete(parts.path, config)\n }\n\n const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n\n if (endpoint.method === 'post') return api.post(parts.path, body, queryConfig)\n if (endpoint.method === 'put') return api.put(parts.path, body, queryConfig)\n if (endpoint.method === 'patch') return api.patch(parts.path, body, queryConfig)\n throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`)\n }\n }\n\n return client as TClient\n}\n\n/** Return a generated plugin client from setup code with a stable typed identity. */\nexport function usePluginClient<TClient>(client: TClient): TClient {\n return client\n}\n\n/** Read plugin settings exposed through the platform context. */\nexport function usePluginSettings<TSettings = Record<string, unknown>>() {\n const { plugin } = usePlatformContext()\n const settings = computed(() => plugin.value?.settings as TSettings | undefined)\n return { settings }\n}\n\n/** Read and optionally load the current platform experiment for integrated plugin views. */\nexport function useCurrentExperiment<TExperiment = unknown>(\n options: UseCurrentExperimentOptions = {},\n): UseCurrentExperimentReturn<TExperiment> {\n const api = useApi({ baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl })\n const experiment = shallowRef<TExperiment | undefined>(currentExperimentFromContext<TExperiment>())\n const request = useRequestSyncState('Failed to load current experiment')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n\n const experimentId = computed<number | undefined>(() => {\n return resolveCurrentExperimentId()\n })\n const hasExperiment = computed(() => experimentId.value !== undefined)\n\n function requireExperimentId(): number {\n const id = experimentId.value\n if (id === undefined) {\n throw new Error('[MINT SDK] No current experiment is selected.')\n }\n return id\n }\n\n async function fetchExperiment(id = experimentId.value): Promise<TExperiment | undefined> {\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return experiment.value\n }\n\n try {\n const result = await request.run(\n () => api.get<TExperiment>(`/experiments/${id}`),\n { success: 'load', errorMessage: 'Failed to load current experiment' },\n )\n experiment.value = result\n return result\n } catch (e) {\n experiment.value = undefined\n return undefined\n }\n }\n\n async function refresh(): Promise<TExperiment | undefined> {\n return fetchExperiment()\n }\n\n watch(\n experimentId,\n (id) => {\n if (options.immediate === false) return\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return\n }\n void fetchExperiment(id)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n hasExperiment,\n experiment,\n isLoading,\n error,\n lastLoadedAt,\n requireExperimentId,\n fetch: fetchExperiment,\n refresh,\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export { MINTSdk, default } from './install';
|
|
2
|
-
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox,
|
|
3
|
-
|
|
2
|
+
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormBuilder, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, AppToastContainer, IconButton, ThemeToggle, CollapsibleCard, AppTopBar, AppPageSelector, AppPillNav, AppAvatarMenu, AppPluginSwitcher, AppSidebar, AppLayout, ControlWorkspaceView, AppContainer, PluginIcon, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, ExperimentSelectorModal, ExperimentPopover, FitPanel, BioTemplateRenderer, BioTemplateExperimentWorkspaceView, BioTemplatePackWorkspaceView, BioTemplatePresetWorkspaceView, } from './components';
|
|
3
|
+
/** @deprecated Use AppToastContainer instead. */
|
|
4
|
+
export { ToastNotification } from './components';
|
|
5
|
+
/** @deprecated Use AppTopBar settingsConfig or SettingsModal instead. */
|
|
6
|
+
export { SettingsButton } from './components';
|
|
7
|
+
/** @deprecated Use AutoGroupModal instead. */
|
|
8
|
+
export { GroupingModal } from './components';
|
|
9
|
+
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type DilutionParams, type DilutionResult, type SerialDilutionParams, type SerialDilutionStep, type SerialDilutionResult, type ConversionResult, type WellConcentration, type UseDoseCalculatorReturn, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, useEventListener, type EventListenerEnabled, type EventFor, type EventListenerStop, type EventMapFor, type EventTargetGetter, type EventTargetLike, type UseEventListenerObjectOptions, type UseEventListenerOptions, usePluginConfig, type UsePluginConfigReturn, useAutoGroup, DEFAULT_COLORS, useExperimentSelector, type UseExperimentSelectorOptions, type UseExperimentSelectorReturn, formatExperimentDate, datePresetToISO, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, EXPERIMENT_STATUS_LABELS, DATE_PRESET_OPTIONS, SORT_OPTIONS, useExperimentData, type UseExperimentDataOptions, type UseExperimentDataReturn, useAppExperiment, APP_EXPERIMENT_KEY, type UseAppExperimentOptions, type UseAppExperimentReturn, useExperimentSave, type UseExperimentSaveOptions, type UseExperimentSaveReturn, useTemplateCollection, type TemplateCollectionInput, type UseTemplateCollectionOptions, type UseTemplateCollectionReturn, useRequestSyncState, type RequestSyncRunOptions, type RequestSyncSuccessKind, type UseRequestSyncStateReturn, useSelectionLimit, type SelectionLimitSource, type UseSelectionLimitOptions, type UseSelectionLimitReturn, useListSelection, type ListSelectionSource, type ListSelectionValue, type UseListSelectionOptions, type UseListSelectionReturn, type WidenListSelectionValue, useGroupAssignment, type GroupAssignmentSource, type GroupAssignmentState, type GroupAssignmentZone, type UseGroupAssignmentOptions, type UseGroupAssignmentReturn, useSampleGroups, type DisplaySampleSubGroup, type SampleGroupSource, type SampleMajorGroup, type UseSampleGroupsOptions, type UseSampleGroupsReturn, useExpansionSet, type ExpansionSetSource, type UseExpansionSetOptions, type UseExpansionSetReturn, compareSortValues, useSortedItems, type CompareSortValuesOptions, type SortComparator, type SortComparatorContext, type SortDescriptor, type SortedItemsSource, type SortOrder, type UseSortedItemsOptions, type UseSortedItemsReturn, candidateMatchesSearch, normalizeSearchQuery, useTextSearch, type TextSearchCandidate, type TextSearchSource, type UseTextSearchOptions, type UseTextSearchReturn, controlsToFormSchema, controlsToSectionFormSchema, controlsToSectionFormSchemas, controlsToSidebarPanels, controlsToSettingsSchema, controlsToTopBarSettingsConfig, controlsToTopBarTabs, controlsToViewIds, controlsToViewItems, controlValuesToComponentProps, defineControlModel, defineDoseDesignControlModel, defineDoseCalculatorControlProps, defineControls, defineWellPlateControlProps, defineWellPlateDoseControlProps, getDefaultControlView, getControlDefaults, useControlSchema, useControlWorkspace, type ControlDefinition, type ControlWorkspaceAppTopBarPillBinding, type ControlWorkspaceAppTopBarTabsBinding, type ControlWorkspaceComponentBindings, type ControlComponentPropSource, type ControlComponentPropsByIdMap, type ControlComponentPropsMap, type DoseDesignControlModelOptions, type DoseCalculatorControlPropsOptions, type ControlFormSchema, type ControlInput, type ControlModel, type ControlModelBinding, type ControlModelSectionConfig, type ControlModelViewConfig, type ControlOption, type ControlOptionValue, type ControlPrimitive, type ControlSchema, type ControlSchemaOptions, type ControlShorthand, type ControlWorkspaceOptions, type ControlFormBinding, type ControlSettingsBinding, type ControlSidebarBinding, type ControlSectionConfig, type ControlSidebarConfig, type ControlTopBarSettingsBinding, type ControlViewConfig, type ControlValues, type UseControlSchemaReturn, type ControlWorkspaceFormBinding, type ControlWorkspacePillNavBinding, type ControlWorkspaceSidebarBinding, type ControlWorkspaceTopBarBinding, type ControlWorkspaceTopBarSettingsBinding, type UseControlWorkspaceReturn, type WellPlateControlPropsOptions, type WellPlateDoseControlPropsOptions, useBioTemplateControls, getBioTemplateControlSchema, requireBioTemplateControlSchema, type BioTemplateControlSchema, type BioTemplateControlTarget, useBioTemplateComponents, getBioTemplateComponentProps, getBioTemplateComponentBindings, toBioTemplateComponentProps, toBioTemplateComponentPropsByComponent, toBioTemplateComponentPropsById, type BioTemplateComponentBinding, type BioTemplateComponentPropsByComponent, type BioTemplateComponentPropsBinding, type BioTemplateComponentPropsById, type BioTemplateComponentPropsLookupOptions, type BioTemplateComponentTarget, type UseBioTemplateComponentsReturn, useBioTemplateWorkspace, type BioTemplateRendererBinding, type BioTemplateWorkspaceBindings, type BioTemplateWorkspaceTarget, type UseBioTemplateWorkspaceReturn, useBioTemplatePresetWorkspace, type BioTemplatePresetWorkspaceBindings, type UseBioTemplatePresetWorkspaceOptions, type UseBioTemplatePresetWorkspaceReturn, useBioTemplatePackWorkspace, type UseBioTemplatePackWorkspaceOptions, type UseBioTemplatePackWorkspaceReturn, buildPluginEndpointUrl, createPluginClient, resolvePluginBaseUrl, usePluginClient, usePluginSettings, useCurrentExperiment, type BuildPluginEndpointUrlOptions, type PluginContract, type PluginEndpointContract, type PluginEndpointDefinition, type PluginHttpMethod, type PluginNavItemContract, type CreatePluginClientOptions, type UseCurrentExperimentOptions, type UseCurrentExperimentReturn, } from './composables';
|
|
10
|
+
/** @deprecated Use generated plugin clients from `mint sdk generate` instead. */
|
|
11
|
+
export { usePluginApi, type UsePluginApiOptions, } from './composables';
|
|
4
12
|
export { useAuthStore, useSettingsStore, colorPalettes, type SettingsState, } from './stores';
|
|
5
13
|
export { hexToHsl, hslToHex, deriveShade, type Hsl, } from './utils/color';
|
|
6
|
-
export
|
|
14
|
+
export * from './templates';
|
|
15
|
+
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, TabItemInput, OptionPrimitive, SelectOption, SelectOptionInput, RadioOption, RadioOptionInput, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarPageInput, TopBarTab, TopBarTabInput, TopBarTabOption, TopBarTabOptionInput, TopBarSettingsConfig, PillNavItem, PillNavItemInput, PageSelectorItem, PageSelectorItemInput, PluginSwitcherPlugin, PluginSwitcherInfo, AccountMenuItem, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, FileUploaderMode, SegmentedOption, SegmentedOptionInput, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectOptionInput, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, BreadcrumbItemInput, TooltipPosition, ConfirmVariant, SettingsTab, SettingsTabInput, SettingsModalLayout, SettingsGroup, SettingsModalSchema, FormFieldType, FieldCondition, FieldValidation, FormFieldSchema, FormOptionInput, FormSectionSchema, FormStepSchema, FormSchema, FieldEnhancement, FormEnhancements, UseFormBuilderReturn, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, ExperimentStatus, ExperimentSummary, ExperimentListResponse, ExperimentFilters, FitState, FitResultSummary, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, UserSummary, } from './types';
|