@morscherlab/mint-sdk 1.0.0-alpha.2
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 +326 -0
- package/dist/__stories__/experiment-helpers.d.ts +25 -0
- package/dist/__tests__/components/AppLayout.test.d.ts +1 -0
- package/dist/__tests__/components/AppSidebar.test.d.ts +1 -0
- package/dist/__tests__/components/AppTopBar.test.d.ts +1 -0
- package/dist/__tests__/components/BaseInput.test.d.ts +1 -0
- package/dist/__tests__/components/BasePill.test.d.ts +1 -0
- package/dist/__tests__/components/Calendar.test.d.ts +1 -0
- package/dist/__tests__/components/CollapsibleCard.test.d.ts +1 -0
- package/dist/__tests__/components/DataFrame.test.d.ts +1 -0
- package/dist/__tests__/components/DropdownButton.test.d.ts +1 -0
- package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +1 -0
- package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
- package/dist/__tests__/composables/useAuth.test.d.ts +1 -0
- package/dist/__tests__/composables/useAutoGroup.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentData.test.d.ts +13 -0
- package/dist/__tests__/composables/useExperimentSave.test.d.ts +1 -0
- package/dist/__tests__/composables/useForm.test.d.ts +1 -0
- package/dist/__tests__/composables/useFormBuilder.test.d.ts +1 -0
- package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginApi.test.d.ts +13 -0
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +14 -0
- package/dist/__tests__/utils/color.test.d.ts +1 -0
- package/dist/auth-BYmxZdJl.js +297 -0
- package/dist/auth-BYmxZdJl.js.map +1 -0
- package/dist/components/AlertBox.vue.d.ts +34 -0
- package/dist/components/AppAvatarMenu.vue.d.ts +58 -0
- package/dist/components/AppContainer.vue.d.ts +28 -0
- package/dist/components/AppLayout.vue.d.ts +31 -0
- package/dist/components/AppPageSelector.vue.d.ts +43 -0
- package/dist/components/AppPillNav.vue.d.ts +11 -0
- package/dist/components/AppPluginSwitcher.vue.d.ts +38 -0
- package/dist/components/AppSidebar.vue.d.ts +47 -0
- package/dist/components/AppTopBar.vue.d.ts +111 -0
- package/dist/components/AuditTrail.vue.d.ts +38 -0
- package/dist/components/AutoGroupModal.vue.d.ts +124 -0
- package/dist/components/Avatar.vue.d.ts +14 -0
- package/dist/components/BaseButton.vue.d.ts +37 -0
- package/dist/components/BaseCheckbox.vue.d.ts +17 -0
- package/dist/components/BaseInput.vue.d.ts +34 -0
- package/dist/components/BaseModal.vue.d.ts +46 -0
- package/dist/components/BasePill.vue.d.ts +57 -0
- package/dist/components/BaseRadioGroup.vue.d.ts +21 -0
- package/dist/components/BaseSelect.vue.d.ts +20 -0
- package/dist/components/BaseSlider.vue.d.ts +22 -0
- package/dist/components/BaseTabs.vue.d.ts +14 -0
- package/dist/components/BaseTextarea.vue.d.ts +30 -0
- package/dist/components/BaseToggle.vue.d.ts +19 -0
- package/dist/components/BatchProgressList.vue.d.ts +43 -0
- package/dist/components/Breadcrumb.vue.d.ts +33 -0
- package/dist/components/Calendar.vue.d.ts +107 -0
- package/dist/components/ChartContainer.vue.d.ts +31 -0
- package/dist/components/ChemicalFormula.vue.d.ts +8 -0
- package/dist/components/CollapsibleCard.vue.d.ts +41 -0
- package/dist/components/ColorSlider.vue.d.ts +34 -0
- package/dist/components/ConcentrationInput.vue.d.ts +25 -0
- package/dist/components/ConfirmDialog.vue.d.ts +42 -0
- package/dist/components/DataFrame.vue.d.ts +107 -0
- package/dist/components/DatePicker.vue.d.ts +25 -0
- package/dist/components/DateTimePicker.vue.d.ts +30 -0
- package/dist/components/Divider.vue.d.ts +14 -0
- package/dist/components/DoseCalculator.vue.d.ts +19 -0
- package/dist/components/DropdownButton.vue.d.ts +47 -0
- package/dist/components/EmptyState.vue.d.ts +36 -0
- package/dist/components/ExperimentCodeBadge.vue.d.ts +14 -0
- package/dist/components/ExperimentDataViewer.vue.d.ts +29 -0
- package/dist/components/ExperimentPopover.vue.d.ts +32 -0
- package/dist/components/ExperimentSelectorModal.vue.d.ts +28 -0
- package/dist/components/ExperimentTimeline.vue.d.ts +44 -0
- package/dist/components/FileUploader.vue.d.ts +40 -0
- package/dist/components/FitPanel.vue.d.ts +46 -0
- package/dist/components/FormActions.vue.d.ts +33 -0
- package/dist/components/FormBuilder.vue.d.ts +287 -0
- package/dist/components/FormField.vue.d.ts +28 -0
- package/dist/components/FormFieldRenderer.vue.d.ts +31 -0
- package/dist/components/FormSection.vue.d.ts +43 -0
- package/dist/components/FormulaInput.vue.d.ts +25 -0
- package/dist/components/GroupAssigner.vue.d.ts +25 -0
- package/dist/components/GroupingModal.vue.d.ts +12 -0
- package/dist/components/IconButton.vue.d.ts +34 -0
- package/dist/components/LoadingSpinner.vue.d.ts +12 -0
- package/dist/components/MoleculeInput.vue.d.ts +27 -0
- package/dist/components/MultiSelect.vue.d.ts +19 -0
- package/dist/components/NumberInput.vue.d.ts +22 -0
- package/dist/components/PlateMapEditor.vue.d.ts +50 -0
- package/dist/components/ProgressBar.vue.d.ts +23 -0
- package/dist/components/ProtocolStepEditor.vue.d.ts +24 -0
- package/dist/components/RackEditor.vue.d.ts +40 -0
- package/dist/components/ReagentEditor.vue.d.ts +30 -0
- package/dist/components/ReagentList.vue.d.ts +32 -0
- package/dist/components/ResourceCard.vue.d.ts +50 -0
- package/dist/components/SampleHierarchyTree.vue.d.ts +26 -0
- package/dist/components/SampleLegend.vue.d.ts +32 -0
- package/dist/components/SampleSelector.vue.d.ts +29 -0
- package/dist/components/ScheduleCalendar.vue.d.ts +110 -0
- package/dist/components/ScientificNumber.vue.d.ts +14 -0
- package/dist/components/SegmentedControl.vue.d.ts +20 -0
- package/dist/components/SequenceInput.vue.d.ts +54 -0
- package/dist/components/SettingsButton.vue.d.ts +30 -0
- package/dist/components/SettingsModal.vue.d.ts +36 -0
- package/dist/components/Skeleton.vue.d.ts +11 -0
- package/dist/components/StatusIndicator.vue.d.ts +13 -0
- package/dist/components/StepWizard.vue.d.ts +65 -0
- package/dist/components/TagsInput.vue.d.ts +39 -0
- package/dist/components/ThemeToggle.vue.d.ts +7 -0
- package/dist/components/TimePicker.vue.d.ts +29 -0
- package/dist/components/TimeRangeInput.vue.d.ts +27 -0
- package/dist/components/ToastNotification.vue.d.ts +2 -0
- package/dist/components/Tooltip.vue.d.ts +35 -0
- package/dist/components/UnitInput.vue.d.ts +39 -0
- package/dist/components/WellEditPopup.vue.d.ts +25 -0
- package/dist/components/WellPlate.vue.d.ts +73 -0
- package/dist/components/index.d.ts +87 -0
- package/dist/components/index.js +3 -0
- package/dist/components-CKf-UpGi.js +15089 -0
- package/dist/components-CKf-UpGi.js.map +1 -0
- package/dist/composables/experiment-utils.d.ts +8 -0
- package/dist/composables/formBuilderRegistry.d.ts +13 -0
- package/dist/composables/index.d.ts +28 -0
- package/dist/composables/index.js +3 -0
- package/dist/composables/useApi.d.ts +20 -0
- package/dist/composables/useAppExperiment.d.ts +37 -0
- package/dist/composables/useAsync.d.ts +128 -0
- package/dist/composables/useAuth.d.ts +47 -0
- package/dist/composables/useAutoGroup.d.ts +106 -0
- package/dist/composables/useChemicalFormula.d.ts +21 -0
- package/dist/composables/useConcentrationUnits.d.ts +29 -0
- package/dist/composables/useDoseCalculator.d.ts +58 -0
- package/dist/composables/useExperimentData.d.ts +18 -0
- package/dist/composables/useExperimentSave.d.ts +36 -0
- package/dist/composables/useExperimentSelector.d.ts +30 -0
- package/dist/composables/useForm.d.ts +92 -0
- package/dist/composables/useFormBuilder.d.ts +24 -0
- package/dist/composables/usePasskey.d.ts +10 -0
- package/dist/composables/usePlatformContext.d.ts +131 -0
- package/dist/composables/usePluginApi.d.ts +29 -0
- package/dist/composables/usePluginConfig.d.ts +13 -0
- package/dist/composables/useProtocolTemplates.d.ts +44 -0
- package/dist/composables/useRackEditor.d.ts +31 -0
- package/dist/composables/useReagentSeries.d.ts +23 -0
- package/dist/composables/useScheduleDrag.d.ts +78 -0
- package/dist/composables/useSequenceUtils.d.ts +14 -0
- package/dist/composables/useTheme.d.ts +8 -0
- package/dist/composables/useTimeUtils.d.ts +29 -0
- package/dist/composables/useToast.d.ts +22 -0
- package/dist/composables/useWellPlateEditor.d.ts +33 -0
- package/dist/composables-D0QfFzq1.js +805 -0
- package/dist/composables-D0QfFzq1.js.map +1 -0
- package/dist/histoire.setup.d.ts +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/install.d.ts +16 -0
- package/dist/install.js +23 -0
- package/dist/install.js.map +1 -0
- package/dist/stores/auth.d.ts +146 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/index.js +2 -0
- package/dist/stores/settings.d.ts +75 -0
- package/dist/styles.css +29728 -0
- package/dist/tailwind.preset.d.ts +58 -0
- package/dist/tailwind.preset.js +66 -0
- package/dist/tailwind.preset.js.map +1 -0
- package/dist/types/auth.d.ts +42 -0
- package/dist/types/auto-group.d.ts +34 -0
- package/dist/types/components.d.ts +528 -0
- package/dist/types/form-builder.d.ts +167 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +0 -0
- package/dist/types/platform.d.ts +75 -0
- package/dist/useScheduleDrag-DAJueTbK.js +7181 -0
- package/dist/useScheduleDrag-DAJueTbK.js.map +1 -0
- package/dist/utils/color.d.ts +24 -0
- package/package.json +114 -0
- package/src/__stories__/experiment-helpers.ts +83 -0
- package/src/__tests__/components/AppLayout.test.ts +163 -0
- package/src/__tests__/components/AppSidebar.test.ts +292 -0
- package/src/__tests__/components/AppTopBar.test.ts +683 -0
- package/src/__tests__/components/BaseInput.test.ts +99 -0
- package/src/__tests__/components/BasePill.test.ts +291 -0
- package/src/__tests__/components/Calendar.test.ts +566 -0
- package/src/__tests__/components/CollapsibleCard.test.ts +524 -0
- package/src/__tests__/components/DataFrame.test.ts +767 -0
- package/src/__tests__/components/DropdownButton.test.ts +471 -0
- package/src/__tests__/composables/formBuilderRegistry.test.ts +187 -0
- package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
- package/src/__tests__/composables/useAuth.test.ts +188 -0
- package/src/__tests__/composables/useAutoGroup.test.ts +860 -0
- package/src/__tests__/composables/useExperimentData.test.ts +127 -0
- package/src/__tests__/composables/useExperimentSave.test.ts +347 -0
- package/src/__tests__/composables/useForm.test.ts +205 -0
- package/src/__tests__/composables/useFormBuilder.test.ts +917 -0
- package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
- package/src/__tests__/composables/usePluginApi.test.ts +81 -0
- package/src/__tests__/composables/usePluginConfig.test.ts +176 -0
- package/src/__tests__/utils/color.test.ts +96 -0
- package/src/components/AlertBox.story.vue +204 -0
- package/src/components/AlertBox.vue +88 -0
- package/src/components/AppAvatarMenu.story.vue +155 -0
- package/src/components/AppAvatarMenu.vue +184 -0
- package/src/components/AppContainer.story.vue +104 -0
- package/src/components/AppContainer.vue +34 -0
- package/src/components/AppLayout.story.vue +292 -0
- package/src/components/AppLayout.vue +75 -0
- package/src/components/AppPageSelector.vue +159 -0
- package/src/components/AppPillNav.vue +66 -0
- package/src/components/AppPluginSwitcher.vue +241 -0
- package/src/components/AppSidebar.story.vue +309 -0
- package/src/components/AppSidebar.vue +119 -0
- package/src/components/AppTopBar.story.vue +304 -0
- package/src/components/AppTopBar.vue +661 -0
- package/src/components/AuditTrail.story.vue +163 -0
- package/src/components/AuditTrail.vue +151 -0
- package/src/components/AutoGroupModal.story.vue +273 -0
- package/src/components/AutoGroupModal.vue +566 -0
- package/src/components/Avatar.story.vue +115 -0
- package/src/components/Avatar.vue +79 -0
- package/src/components/BaseButton.story.vue +96 -0
- package/src/components/BaseButton.vue +73 -0
- package/src/components/BaseCheckbox.story.vue +73 -0
- package/src/components/BaseCheckbox.vue +69 -0
- package/src/components/BaseInput.story.vue +98 -0
- package/src/components/BaseInput.vue +74 -0
- package/src/components/BaseModal.story.vue +237 -0
- package/src/components/BaseModal.vue +182 -0
- package/src/components/BasePill.story.vue +142 -0
- package/src/components/BasePill.vue +89 -0
- package/src/components/BaseRadioGroup.story.vue +145 -0
- package/src/components/BaseRadioGroup.vue +124 -0
- package/src/components/BaseSelect.story.vue +120 -0
- package/src/components/BaseSelect.vue +71 -0
- package/src/components/BaseSlider.story.vue +122 -0
- package/src/components/BaseSlider.vue +126 -0
- package/src/components/BaseTabs.story.vue +127 -0
- package/src/components/BaseTabs.vue +59 -0
- package/src/components/BaseTextarea.story.vue +91 -0
- package/src/components/BaseTextarea.vue +62 -0
- package/src/components/BaseToggle.story.vue +81 -0
- package/src/components/BaseToggle.vue +76 -0
- package/src/components/BatchProgressList.story.vue +92 -0
- package/src/components/BatchProgressList.vue +184 -0
- package/src/components/Breadcrumb.story.vue +106 -0
- package/src/components/Breadcrumb.vue +75 -0
- package/src/components/Calendar.story.vue +106 -0
- package/src/components/Calendar.vue +363 -0
- package/src/components/ChartContainer.story.vue +113 -0
- package/src/components/ChartContainer.vue +64 -0
- package/src/components/ChemicalFormula.story.vue +102 -0
- package/src/components/ChemicalFormula.vue +39 -0
- package/src/components/CollapsibleCard.story.vue +135 -0
- package/src/components/CollapsibleCard.vue +167 -0
- package/src/components/ColorSlider.story.vue +120 -0
- package/src/components/ColorSlider.vue +164 -0
- package/src/components/ConcentrationInput.story.vue +77 -0
- package/src/components/ConcentrationInput.vue +185 -0
- package/src/components/ConfirmDialog.story.vue +248 -0
- package/src/components/ConfirmDialog.vue +93 -0
- package/src/components/DataFrame.story.vue +148 -0
- package/src/components/DataFrame.vue +419 -0
- package/src/components/DatePicker.story.vue +119 -0
- package/src/components/DatePicker.vue +330 -0
- package/src/components/DateTimePicker.story.vue +112 -0
- package/src/components/DateTimePicker.vue +392 -0
- package/src/components/Divider.story.vue +80 -0
- package/src/components/Divider.vue +49 -0
- package/src/components/DoseCalculator.story.vue +68 -0
- package/src/components/DoseCalculator.vue +476 -0
- package/src/components/DropdownButton.story.vue +102 -0
- package/src/components/DropdownButton.vue +181 -0
- package/src/components/EmptyState.story.vue +135 -0
- package/src/components/EmptyState.vue +69 -0
- package/src/components/ExperimentCodeBadge.story.vue +77 -0
- package/src/components/ExperimentCodeBadge.vue +64 -0
- package/src/components/ExperimentDataViewer.story.vue +174 -0
- package/src/components/ExperimentDataViewer.vue +288 -0
- package/src/components/ExperimentPopover.story.vue +384 -0
- package/src/components/ExperimentPopover.vue +241 -0
- package/src/components/ExperimentSelectorModal.story.vue +391 -0
- package/src/components/ExperimentSelectorModal.vue +387 -0
- package/src/components/ExperimentTimeline.story.vue +161 -0
- package/src/components/ExperimentTimeline.vue +382 -0
- package/src/components/FileUploader.story.vue +107 -0
- package/src/components/FileUploader.vue +386 -0
- package/src/components/FitPanel.story.vue +125 -0
- package/src/components/FitPanel.vue +120 -0
- package/src/components/FormActions.vue +92 -0
- package/src/components/FormBuilder.vue +214 -0
- package/src/components/FormField.story.vue +132 -0
- package/src/components/FormField.vue +59 -0
- package/src/components/FormFieldRenderer.vue +58 -0
- package/src/components/FormSection.vue +90 -0
- package/src/components/FormulaInput.story.vue +96 -0
- package/src/components/FormulaInput.vue +125 -0
- package/src/components/GroupAssigner.story.vue +83 -0
- package/src/components/GroupAssigner.vue +284 -0
- package/src/components/GroupingModal.story.vue +52 -0
- package/src/components/GroupingModal.vue +422 -0
- package/src/components/IconButton.story.vue +135 -0
- package/src/components/IconButton.vue +73 -0
- package/src/components/LoadingSpinner.story.vue +70 -0
- package/src/components/LoadingSpinner.vue +50 -0
- package/src/components/MoleculeInput.story.vue +66 -0
- package/src/components/MoleculeInput.vue +426 -0
- package/src/components/MultiSelect.story.vue +132 -0
- package/src/components/MultiSelect.vue +118 -0
- package/src/components/NumberInput.story.vue +122 -0
- package/src/components/NumberInput.vue +160 -0
- package/src/components/PlateMapEditor.story.vue +92 -0
- package/src/components/PlateMapEditor.vue +513 -0
- package/src/components/ProgressBar.story.vue +148 -0
- package/src/components/ProgressBar.vue +114 -0
- package/src/components/ProtocolStepEditor.story.vue +69 -0
- package/src/components/ProtocolStepEditor.vue +522 -0
- package/src/components/RackEditor.story.vue +100 -0
- package/src/components/RackEditor.vue +371 -0
- package/src/components/ReagentEditor.story.vue +153 -0
- package/src/components/ReagentEditor.vue +418 -0
- package/src/components/ReagentList.story.vue +137 -0
- package/src/components/ReagentList.vue +463 -0
- package/src/components/ResourceCard.story.vue +150 -0
- package/src/components/ResourceCard.vue +161 -0
- package/src/components/SampleHierarchyTree.story.vue +161 -0
- package/src/components/SampleHierarchyTree.vue +256 -0
- package/src/components/SampleLegend.story.vue +91 -0
- package/src/components/SampleLegend.vue +119 -0
- package/src/components/SampleSelector.story.vue +111 -0
- package/src/components/SampleSelector.vue +1033 -0
- package/src/components/ScheduleCalendar.story.vue +195 -0
- package/src/components/ScheduleCalendar.vue +569 -0
- package/src/components/ScientificNumber.story.vue +127 -0
- package/src/components/ScientificNumber.vue +197 -0
- package/src/components/SegmentedControl.story.vue +132 -0
- package/src/components/SegmentedControl.vue +79 -0
- package/src/components/SequenceInput.story.vue +119 -0
- package/src/components/SequenceInput.vue +209 -0
- package/src/components/SettingsButton.story.vue +58 -0
- package/src/components/SettingsButton.vue +76 -0
- package/src/components/SettingsModal.story.vue +145 -0
- package/src/components/SettingsModal.vue +146 -0
- package/src/components/Skeleton.story.vue +141 -0
- package/src/components/Skeleton.vue +74 -0
- package/src/components/StatusIndicator.story.vue +99 -0
- package/src/components/StatusIndicator.vue +40 -0
- package/src/components/StepWizard.story.vue +155 -0
- package/src/components/StepWizard.vue +223 -0
- package/src/components/TagsInput.story.vue +155 -0
- package/src/components/TagsInput.vue +265 -0
- package/src/components/ThemeToggle.story.vue +36 -0
- package/src/components/ThemeToggle.vue +54 -0
- package/src/components/TimePicker.story.vue +96 -0
- package/src/components/TimePicker.vue +273 -0
- package/src/components/TimeRangeInput.story.vue +104 -0
- package/src/components/TimeRangeInput.vue +122 -0
- package/src/components/ToastNotification.story.vue +157 -0
- package/src/components/ToastNotification.vue +62 -0
- package/src/components/Tooltip.story.vue +138 -0
- package/src/components/Tooltip.vue +119 -0
- package/src/components/UnitInput.story.vue +194 -0
- package/src/components/UnitInput.vue +213 -0
- package/src/components/WellEditPopup.vue +234 -0
- package/src/components/WellPlate.story.vue +282 -0
- package/src/components/WellPlate.vue +830 -0
- package/src/components/index.ts +118 -0
- package/src/composables/experiment-utils.ts +57 -0
- package/src/composables/formBuilderRegistry.ts +79 -0
- package/src/composables/index.ts +140 -0
- package/src/composables/useApi.ts +167 -0
- package/src/composables/useAppExperiment.ts +159 -0
- package/src/composables/useAsync.ts +323 -0
- package/src/composables/useAuth.ts +445 -0
- package/src/composables/useAutoGroup.ts +641 -0
- package/src/composables/useChemicalFormula.ts +275 -0
- package/src/composables/useConcentrationUnits.ts +246 -0
- package/src/composables/useDoseCalculator.ts +370 -0
- package/src/composables/useExperimentData.ts +86 -0
- package/src/composables/useExperimentSave.ts +192 -0
- package/src/composables/useExperimentSelector.ts +292 -0
- package/src/composables/useForm.ts +416 -0
- package/src/composables/useFormBuilder.ts +383 -0
- package/src/composables/usePasskey.ts +216 -0
- package/src/composables/usePlatformContext.ts +299 -0
- package/src/composables/usePluginApi.ts +39 -0
- package/src/composables/usePluginConfig.ts +93 -0
- package/src/composables/useProtocolTemplates.ts +518 -0
- package/src/composables/useRackEditor.ts +222 -0
- package/src/composables/useReagentSeries.ts +91 -0
- package/src/composables/useScheduleDrag.ts +245 -0
- package/src/composables/useSequenceUtils.ts +105 -0
- package/src/composables/useTheme.ts +58 -0
- package/src/composables/useTimeUtils.ts +131 -0
- package/src/composables/useToast.ts +40 -0
- package/src/composables/useWellPlateEditor.ts +421 -0
- package/src/histoire.setup.ts +17 -0
- package/src/index.ts +367 -0
- package/src/install.ts +32 -0
- package/src/stores/auth.ts +152 -0
- package/src/stores/index.ts +2 -0
- package/src/stores/settings.ts +218 -0
- package/src/styles/components/alert-box.css +150 -0
- package/src/styles/components/app-avatar-menu.css +155 -0
- package/src/styles/components/app-container.css +33 -0
- package/src/styles/components/app-layout.css +98 -0
- package/src/styles/components/app-page-selector.css +191 -0
- package/src/styles/components/app-pill-nav.css +57 -0
- package/src/styles/components/app-plugin-switcher.css +209 -0
- package/src/styles/components/app-sidebar.css +145 -0
- package/src/styles/components/app-top-bar.css +492 -0
- package/src/styles/components/audit-trail.css +143 -0
- package/src/styles/components/auto-group-modal.css +644 -0
- package/src/styles/components/avatar.css +73 -0
- package/src/styles/components/batch-progress-list.css +196 -0
- package/src/styles/components/breadcrumb.css +64 -0
- package/src/styles/components/button.css +188 -0
- package/src/styles/components/calendar.css +192 -0
- package/src/styles/components/chart-container.css +69 -0
- package/src/styles/components/checkbox.css +123 -0
- package/src/styles/components/chemical-formula.css +46 -0
- package/src/styles/components/collapsible-card.css +253 -0
- package/src/styles/components/color-slider.css +110 -0
- package/src/styles/components/concentration-input.css +156 -0
- package/src/styles/components/confirm-dialog.css +183 -0
- package/src/styles/components/dataframe.css +382 -0
- package/src/styles/components/date-picker.css +243 -0
- package/src/styles/components/datetime-picker.css +229 -0
- package/src/styles/components/divider.css +63 -0
- package/src/styles/components/dose-calculator.css +301 -0
- package/src/styles/components/dropdown-button.css +280 -0
- package/src/styles/components/empty-state.css +151 -0
- package/src/styles/components/experiment-code-badge.css +33 -0
- package/src/styles/components/experiment-data-viewer.css +138 -0
- package/src/styles/components/experiment-popover.css +562 -0
- package/src/styles/components/experiment-selector-modal.css +285 -0
- package/src/styles/components/experiment-timeline.css +529 -0
- package/src/styles/components/file-uploader.css +310 -0
- package/src/styles/components/fit-panel.css +67 -0
- package/src/styles/components/form-builder.css +69 -0
- package/src/styles/components/form-field.css +48 -0
- package/src/styles/components/formula-input.css +103 -0
- package/src/styles/components/group-assigner.css +200 -0
- package/src/styles/components/grouping-modal.css +323 -0
- package/src/styles/components/icon-button.css +192 -0
- package/src/styles/components/input.css +66 -0
- package/src/styles/components/loading-spinner.css +67 -0
- package/src/styles/components/modal.css +350 -0
- package/src/styles/components/molecule-input.css +186 -0
- package/src/styles/components/multi-select.css +131 -0
- package/src/styles/components/number-input.css +199 -0
- package/src/styles/components/pill.css +188 -0
- package/src/styles/components/plate-map-editor.css +464 -0
- package/src/styles/components/progress-bar.css +133 -0
- package/src/styles/components/protocol-step-editor.css +449 -0
- package/src/styles/components/rack-editor.css +265 -0
- package/src/styles/components/radio-group.css +240 -0
- package/src/styles/components/reagent-editor.css +510 -0
- package/src/styles/components/reagent-list.css +407 -0
- package/src/styles/components/resource-card.css +360 -0
- package/src/styles/components/sample-hierarchy-tree.css +314 -0
- package/src/styles/components/sample-legend.css +201 -0
- package/src/styles/components/sample-selector.css +751 -0
- package/src/styles/components/schedule-calendar.css +478 -0
- package/src/styles/components/scientific-number.css +63 -0
- package/src/styles/components/segmented-control.css +197 -0
- package/src/styles/components/select.css +77 -0
- package/src/styles/components/sequence-input.css +184 -0
- package/src/styles/components/settings-button.css +94 -0
- package/src/styles/components/settings-modal.css +95 -0
- package/src/styles/components/skeleton.css +49 -0
- package/src/styles/components/slider.css +74 -0
- package/src/styles/components/status-indicator.css +66 -0
- package/src/styles/components/step-wizard.css +192 -0
- package/src/styles/components/tabs.css +95 -0
- package/src/styles/components/tags-input.css +195 -0
- package/src/styles/components/textarea.css +82 -0
- package/src/styles/components/theme-toggle.css +69 -0
- package/src/styles/components/time-picker.css +171 -0
- package/src/styles/components/time-range-input.css +42 -0
- package/src/styles/components/toast.css +91 -0
- package/src/styles/components/toggle.css +146 -0
- package/src/styles/components/tooltip.css +91 -0
- package/src/styles/components/unit-input.css +123 -0
- package/src/styles/components/well-edit-popup.css +252 -0
- package/src/styles/components/well-plate.css +307 -0
- package/src/styles/index.css +87 -0
- package/src/styles/variables.css +1117 -0
- package/src/tailwind.preset.ts +61 -0
- package/src/types/auth.ts +55 -0
- package/src/types/auto-group.ts +40 -0
- package/src/types/components.ts +710 -0
- package/src/types/form-builder.ts +197 -0
- package/src/types/index.ts +207 -0
- package/src/types/platform.ts +116 -0
- package/src/utils/color.ts +96 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Base components
|
|
2
|
+
export { default as BaseButton } from './BaseButton.vue'
|
|
3
|
+
export { default as BaseInput } from './BaseInput.vue'
|
|
4
|
+
export { default as BaseTextarea } from './BaseTextarea.vue'
|
|
5
|
+
export { default as BaseSelect } from './BaseSelect.vue'
|
|
6
|
+
export { default as BaseCheckbox } from './BaseCheckbox.vue'
|
|
7
|
+
export { default as BaseToggle } from './BaseToggle.vue'
|
|
8
|
+
export { default as BaseRadioGroup } from './BaseRadioGroup.vue'
|
|
9
|
+
export { default as BaseSlider } from './BaseSlider.vue'
|
|
10
|
+
export { default as ColorSlider } from './ColorSlider.vue'
|
|
11
|
+
export { default as BaseTabs } from './BaseTabs.vue'
|
|
12
|
+
export { default as BaseModal } from './BaseModal.vue'
|
|
13
|
+
export { default as SegmentedControl } from './SegmentedControl.vue'
|
|
14
|
+
export { default as MultiSelect } from './MultiSelect.vue'
|
|
15
|
+
export { default as BasePill } from './BasePill.vue'
|
|
16
|
+
export { default as DropdownButton } from './DropdownButton.vue'
|
|
17
|
+
export { default as Calendar } from './Calendar.vue'
|
|
18
|
+
export { default as DataFrame } from './DataFrame.vue'
|
|
19
|
+
|
|
20
|
+
// Form components
|
|
21
|
+
export { default as FormField } from './FormField.vue'
|
|
22
|
+
export { default as DatePicker } from './DatePicker.vue'
|
|
23
|
+
export { default as TimePicker } from './TimePicker.vue'
|
|
24
|
+
export { default as TagsInput } from './TagsInput.vue'
|
|
25
|
+
export { default as NumberInput } from './NumberInput.vue'
|
|
26
|
+
export { default as FileUploader } from './FileUploader.vue'
|
|
27
|
+
|
|
28
|
+
// Feedback components
|
|
29
|
+
export { default as AlertBox } from './AlertBox.vue'
|
|
30
|
+
export { default as ToastNotification } from './ToastNotification.vue'
|
|
31
|
+
export { default as AppToastContainer } from './ToastNotification.vue'
|
|
32
|
+
|
|
33
|
+
// Action components
|
|
34
|
+
export { default as IconButton } from './IconButton.vue'
|
|
35
|
+
export { default as ThemeToggle } from './ThemeToggle.vue'
|
|
36
|
+
export { default as SettingsButton } from './SettingsButton.vue'
|
|
37
|
+
|
|
38
|
+
// Layout components
|
|
39
|
+
export { default as CollapsibleCard } from './CollapsibleCard.vue'
|
|
40
|
+
export { default as AppTopBar } from './AppTopBar.vue'
|
|
41
|
+
export { default as AppPageSelector } from './AppPageSelector.vue'
|
|
42
|
+
export { default as AppPillNav } from './AppPillNav.vue'
|
|
43
|
+
export { default as AppAvatarMenu } from './AppAvatarMenu.vue'
|
|
44
|
+
export { default as AppPluginSwitcher } from './AppPluginSwitcher.vue'
|
|
45
|
+
export { default as AppSidebar } from './AppSidebar.vue'
|
|
46
|
+
export { default as AppLayout } from './AppLayout.vue'
|
|
47
|
+
export { default as AppContainer } from './AppContainer.vue'
|
|
48
|
+
|
|
49
|
+
// Utility components
|
|
50
|
+
export { default as Skeleton } from './Skeleton.vue'
|
|
51
|
+
export { default as LoadingSpinner } from './LoadingSpinner.vue'
|
|
52
|
+
export { default as Divider } from './Divider.vue'
|
|
53
|
+
export { default as StatusIndicator } from './StatusIndicator.vue'
|
|
54
|
+
export { default as ProgressBar } from './ProgressBar.vue'
|
|
55
|
+
export { default as Avatar } from './Avatar.vue'
|
|
56
|
+
export { default as EmptyState } from './EmptyState.vue'
|
|
57
|
+
export { default as Breadcrumb } from './Breadcrumb.vue'
|
|
58
|
+
export { default as Tooltip } from './Tooltip.vue'
|
|
59
|
+
export { default as ConfirmDialog } from './ConfirmDialog.vue'
|
|
60
|
+
export { default as ChartContainer } from './ChartContainer.vue'
|
|
61
|
+
export { default as SettingsModal } from './SettingsModal.vue'
|
|
62
|
+
|
|
63
|
+
// Biological experiment components
|
|
64
|
+
export { default as WellPlate } from './WellPlate.vue'
|
|
65
|
+
export { default as RackEditor } from './RackEditor.vue'
|
|
66
|
+
export { default as SampleLegend } from './SampleLegend.vue'
|
|
67
|
+
export { default as PlateMapEditor } from './PlateMapEditor.vue'
|
|
68
|
+
export { default as ExperimentTimeline } from './ExperimentTimeline.vue'
|
|
69
|
+
|
|
70
|
+
// Sample management components
|
|
71
|
+
export { default as SampleSelector } from './SampleSelector.vue'
|
|
72
|
+
export { default as GroupingModal } from './GroupingModal.vue'
|
|
73
|
+
export { default as AutoGroupModal } from './AutoGroupModal.vue'
|
|
74
|
+
export { default as GroupAssigner } from './GroupAssigner.vue'
|
|
75
|
+
|
|
76
|
+
// Lab/Experiment components
|
|
77
|
+
export { default as MoleculeInput } from './MoleculeInput.vue'
|
|
78
|
+
export { default as ConcentrationInput } from './ConcentrationInput.vue'
|
|
79
|
+
export { default as DoseCalculator } from './DoseCalculator.vue'
|
|
80
|
+
export { default as ReagentEditor, type ReagentDefinition } from './ReagentEditor.vue'
|
|
81
|
+
export { default as ReagentList } from './ReagentList.vue'
|
|
82
|
+
export { default as SampleHierarchyTree } from './SampleHierarchyTree.vue'
|
|
83
|
+
export { default as ProtocolStepEditor } from './ProtocolStepEditor.vue'
|
|
84
|
+
|
|
85
|
+
// Scientific display components
|
|
86
|
+
export { default as ScientificNumber } from './ScientificNumber.vue'
|
|
87
|
+
export { default as ChemicalFormula } from './ChemicalFormula.vue'
|
|
88
|
+
|
|
89
|
+
// Scientific input components
|
|
90
|
+
export { default as FormulaInput } from './FormulaInput.vue'
|
|
91
|
+
export { default as SequenceInput } from './SequenceInput.vue'
|
|
92
|
+
export { default as UnitInput } from './UnitInput.vue'
|
|
93
|
+
|
|
94
|
+
// Workflow components
|
|
95
|
+
export { default as StepWizard } from './StepWizard.vue'
|
|
96
|
+
export { default as AuditTrail } from './AuditTrail.vue'
|
|
97
|
+
export { default as BatchProgressList } from './BatchProgressList.vue'
|
|
98
|
+
|
|
99
|
+
// Form builder components
|
|
100
|
+
export { default as FormBuilder } from './FormBuilder.vue'
|
|
101
|
+
export { default as FormSection } from './FormSection.vue'
|
|
102
|
+
export { default as FormActions } from './FormActions.vue'
|
|
103
|
+
export { default as FormFieldRenderer } from './FormFieldRenderer.vue'
|
|
104
|
+
|
|
105
|
+
// Experiment data display components
|
|
106
|
+
export { default as ExperimentDataViewer } from './ExperimentDataViewer.vue'
|
|
107
|
+
export { default as ExperimentCodeBadge } from './ExperimentCodeBadge.vue'
|
|
108
|
+
|
|
109
|
+
// Scheduling / booking components
|
|
110
|
+
export { default as DateTimePicker } from './DateTimePicker.vue'
|
|
111
|
+
export { default as TimeRangeInput } from './TimeRangeInput.vue'
|
|
112
|
+
export { default as ScheduleCalendar } from './ScheduleCalendar.vue'
|
|
113
|
+
export { default as ResourceCard } from './ResourceCard.vue'
|
|
114
|
+
|
|
115
|
+
// Experiment / analysis components
|
|
116
|
+
export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue'
|
|
117
|
+
export { default as ExperimentPopover } from './ExperimentPopover.vue'
|
|
118
|
+
export { default as FitPanel } from './FitPanel.vue'
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { DatePreset, ExperimentStatus, SelectOption, PillVariant } from '../types'
|
|
2
|
+
|
|
3
|
+
export function formatExperimentDate(dateStr: string): string {
|
|
4
|
+
try {
|
|
5
|
+
return new Date(dateStr).toLocaleDateString(undefined, {
|
|
6
|
+
year: 'numeric',
|
|
7
|
+
month: 'short',
|
|
8
|
+
day: 'numeric',
|
|
9
|
+
})
|
|
10
|
+
} catch {
|
|
11
|
+
return dateStr
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function datePresetToISO(preset: DatePreset): string {
|
|
16
|
+
const now = new Date()
|
|
17
|
+
const days = preset === 'last_7_days' ? 7 : preset === 'last_30_days' ? 30 : 90
|
|
18
|
+
const d = new Date(now.getTime() - days * 86_400_000)
|
|
19
|
+
return d.toISOString()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const EXPERIMENT_STATUS_OPTIONS: SelectOption<string>[] = [
|
|
23
|
+
{ value: '', label: 'All statuses' },
|
|
24
|
+
{ value: 'planned', label: 'Planned' },
|
|
25
|
+
{ value: 'ongoing', label: 'Ongoing' },
|
|
26
|
+
{ value: 'completed', label: 'Completed' },
|
|
27
|
+
{ value: 'cancelled', label: 'Cancelled' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
export const EXPERIMENT_STATUS_VARIANT_MAP: Record<ExperimentStatus, PillVariant> = {
|
|
31
|
+
planned: 'default',
|
|
32
|
+
ongoing: 'primary',
|
|
33
|
+
completed: 'success',
|
|
34
|
+
cancelled: 'error',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const EXPERIMENT_STATUS_LABELS: Record<ExperimentStatus, string> = {
|
|
38
|
+
planned: 'Planned',
|
|
39
|
+
ongoing: 'Ongoing',
|
|
40
|
+
completed: 'Completed',
|
|
41
|
+
cancelled: 'Cancelled',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const DATE_PRESET_OPTIONS: SelectOption<string>[] = [
|
|
45
|
+
{ value: '', label: 'Any time' },
|
|
46
|
+
{ value: 'last_7_days', label: 'Last 7 days' },
|
|
47
|
+
{ value: 'last_30_days', label: 'Last 30 days' },
|
|
48
|
+
{ value: 'last_90_days', label: 'Last 90 days' },
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
export const SORT_OPTIONS: SelectOption<string>[] = [
|
|
52
|
+
{ value: 'created_at:desc', label: 'Newest first' },
|
|
53
|
+
{ value: 'created_at:asc', label: 'Oldest first' },
|
|
54
|
+
{ value: 'updated_at:desc', label: 'Recently updated' },
|
|
55
|
+
{ value: 'name:asc', label: 'Name A\u2013Z' },
|
|
56
|
+
{ value: 'name:desc', label: 'Name Z\u2013A' },
|
|
57
|
+
]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Component } from 'vue'
|
|
2
|
+
import type { FormFieldType } from '../types/form-builder'
|
|
3
|
+
|
|
4
|
+
import BaseInput from '../components/BaseInput.vue'
|
|
5
|
+
import BaseTextarea from '../components/BaseTextarea.vue'
|
|
6
|
+
import BaseSelect from '../components/BaseSelect.vue'
|
|
7
|
+
import MultiSelect from '../components/MultiSelect.vue'
|
|
8
|
+
import BaseCheckbox from '../components/BaseCheckbox.vue'
|
|
9
|
+
import BaseToggle from '../components/BaseToggle.vue'
|
|
10
|
+
import BaseRadioGroup from '../components/BaseRadioGroup.vue'
|
|
11
|
+
import BaseSlider from '../components/BaseSlider.vue'
|
|
12
|
+
import TagsInput from '../components/TagsInput.vue'
|
|
13
|
+
import NumberInput from '../components/NumberInput.vue'
|
|
14
|
+
import DatePicker from '../components/DatePicker.vue'
|
|
15
|
+
import TimePicker from '../components/TimePicker.vue'
|
|
16
|
+
import DateTimePicker from '../components/DateTimePicker.vue'
|
|
17
|
+
import FileUploader from '../components/FileUploader.vue'
|
|
18
|
+
import FormulaInput from '../components/FormulaInput.vue'
|
|
19
|
+
import SequenceInput from '../components/SequenceInput.vue'
|
|
20
|
+
import MoleculeInput from '../components/MoleculeInput.vue'
|
|
21
|
+
import ConcentrationInput from '../components/ConcentrationInput.vue'
|
|
22
|
+
import UnitInput from '../components/UnitInput.vue'
|
|
23
|
+
|
|
24
|
+
export interface RegistryEntry {
|
|
25
|
+
component: Component
|
|
26
|
+
/** Default props applied to the component. */
|
|
27
|
+
defaults: Record<string, unknown>
|
|
28
|
+
/** Whether the component uses v-model (false for event-only components like FileUploader). */
|
|
29
|
+
vModel: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const registry: Record<FormFieldType, RegistryEntry> = {
|
|
33
|
+
text: { component: BaseInput, defaults: { type: 'text' }, vModel: true },
|
|
34
|
+
email: { component: BaseInput, defaults: { type: 'email' }, vModel: true },
|
|
35
|
+
password: { component: BaseInput, defaults: { type: 'password' }, vModel: true },
|
|
36
|
+
tel: { component: BaseInput, defaults: { type: 'tel' }, vModel: true },
|
|
37
|
+
url: { component: BaseInput, defaults: { type: 'url' }, vModel: true },
|
|
38
|
+
search: { component: BaseInput, defaults: { type: 'search' }, vModel: true },
|
|
39
|
+
number: { component: NumberInput, defaults: {}, vModel: true },
|
|
40
|
+
textarea: { component: BaseTextarea, defaults: {}, vModel: true },
|
|
41
|
+
select: { component: BaseSelect, defaults: {}, vModel: true },
|
|
42
|
+
multiselect: { component: MultiSelect, defaults: {}, vModel: true },
|
|
43
|
+
checkbox: { component: BaseCheckbox, defaults: {}, vModel: true },
|
|
44
|
+
toggle: { component: BaseToggle, defaults: {}, vModel: true },
|
|
45
|
+
radio: { component: BaseRadioGroup, defaults: {}, vModel: true },
|
|
46
|
+
slider: { component: BaseSlider, defaults: {}, vModel: true },
|
|
47
|
+
tags: { component: TagsInput, defaults: {}, vModel: true },
|
|
48
|
+
date: { component: DatePicker, defaults: {}, vModel: true },
|
|
49
|
+
time: { component: TimePicker, defaults: {}, vModel: true },
|
|
50
|
+
datetime: { component: DateTimePicker, defaults: {}, vModel: true },
|
|
51
|
+
file: { component: FileUploader, defaults: {}, vModel: false },
|
|
52
|
+
formula: { component: FormulaInput, defaults: {}, vModel: true },
|
|
53
|
+
sequence: { component: SequenceInput, defaults: {}, vModel: true },
|
|
54
|
+
molecule: { component: MoleculeInput, defaults: {}, vModel: true },
|
|
55
|
+
concentration: { component: ConcentrationInput, defaults: {}, vModel: true },
|
|
56
|
+
unit: { component: UnitInput, defaults: {}, vModel: true },
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Return the registry entry for a given field type. Throws if the type is unregistered. */
|
|
60
|
+
export function getFieldRegistryEntry(type: FormFieldType): RegistryEntry {
|
|
61
|
+
return registry[type]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Get the default empty value for a given field type. */
|
|
65
|
+
export function getTypeDefault(type: FormFieldType): unknown {
|
|
66
|
+
switch (type) {
|
|
67
|
+
case 'checkbox':
|
|
68
|
+
case 'toggle':
|
|
69
|
+
return false
|
|
70
|
+
case 'number':
|
|
71
|
+
case 'slider':
|
|
72
|
+
return undefined
|
|
73
|
+
case 'multiselect':
|
|
74
|
+
case 'tags':
|
|
75
|
+
return []
|
|
76
|
+
default:
|
|
77
|
+
return ''
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export { useApi, type ApiClientOptions } from './useApi'
|
|
2
|
+
export { useAuth } from './useAuth'
|
|
3
|
+
export { usePasskey } from './usePasskey'
|
|
4
|
+
export { useTheme } from './useTheme'
|
|
5
|
+
export { useToast } from './useToast'
|
|
6
|
+
export { usePlatformContext } from './usePlatformContext'
|
|
7
|
+
export {
|
|
8
|
+
useForm,
|
|
9
|
+
type ValidationRule,
|
|
10
|
+
type FieldRules,
|
|
11
|
+
type FieldState,
|
|
12
|
+
type UseFormReturn,
|
|
13
|
+
} from './useForm'
|
|
14
|
+
export {
|
|
15
|
+
useAsync,
|
|
16
|
+
useAsyncBatch,
|
|
17
|
+
type AsyncError,
|
|
18
|
+
type AsyncState,
|
|
19
|
+
type UseAsyncReturn,
|
|
20
|
+
type UseAsyncOptions,
|
|
21
|
+
} from './useAsync'
|
|
22
|
+
export {
|
|
23
|
+
useWellPlateEditor,
|
|
24
|
+
type UseWellPlateEditorOptions,
|
|
25
|
+
type UseWellPlateEditorReturn,
|
|
26
|
+
} from './useWellPlateEditor'
|
|
27
|
+
export {
|
|
28
|
+
useConcentrationUnits,
|
|
29
|
+
type ConcentrationValue,
|
|
30
|
+
type ConcentrationUnit,
|
|
31
|
+
type MolarityUnit,
|
|
32
|
+
type MassVolumeUnit,
|
|
33
|
+
type PercentageUnit,
|
|
34
|
+
type UnitCategory,
|
|
35
|
+
type UseConcentrationUnitsReturn,
|
|
36
|
+
} from './useConcentrationUnits'
|
|
37
|
+
export {
|
|
38
|
+
useDoseCalculator,
|
|
39
|
+
type VolumeUnit,
|
|
40
|
+
type VolumeValue,
|
|
41
|
+
type DilutionParams,
|
|
42
|
+
type DilutionResult,
|
|
43
|
+
type SerialDilutionParams,
|
|
44
|
+
type SerialDilutionStep,
|
|
45
|
+
type SerialDilutionResult,
|
|
46
|
+
type WellConcentration,
|
|
47
|
+
type UseDoseCalculatorReturn,
|
|
48
|
+
} from './useDoseCalculator'
|
|
49
|
+
export {
|
|
50
|
+
useProtocolTemplates,
|
|
51
|
+
type ParameterDefinition,
|
|
52
|
+
type StepTemplate,
|
|
53
|
+
type ValidationResult,
|
|
54
|
+
type UseProtocolTemplatesReturn,
|
|
55
|
+
} from './useProtocolTemplates'
|
|
56
|
+
export {
|
|
57
|
+
useRackEditor,
|
|
58
|
+
type UseRackEditorOptions,
|
|
59
|
+
type UseRackEditorReturn,
|
|
60
|
+
} from './useRackEditor'
|
|
61
|
+
export {
|
|
62
|
+
useChemicalFormula,
|
|
63
|
+
ATOMIC_WEIGHTS,
|
|
64
|
+
type ParsedElement,
|
|
65
|
+
type FormulaParseResult,
|
|
66
|
+
type FormulaPart,
|
|
67
|
+
type FormulaPartType,
|
|
68
|
+
} from './useChemicalFormula'
|
|
69
|
+
export {
|
|
70
|
+
useSequenceUtils,
|
|
71
|
+
type SequenceType,
|
|
72
|
+
type SequenceStats,
|
|
73
|
+
} from './useSequenceUtils'
|
|
74
|
+
export {
|
|
75
|
+
useTimeUtils,
|
|
76
|
+
parseTime,
|
|
77
|
+
formatTime,
|
|
78
|
+
generateTimeSlots,
|
|
79
|
+
rangesOverlap,
|
|
80
|
+
durationMinutes,
|
|
81
|
+
formatDuration,
|
|
82
|
+
isTimeInRange,
|
|
83
|
+
findAvailableSlots,
|
|
84
|
+
snapToSlot,
|
|
85
|
+
addMinutes,
|
|
86
|
+
compareTime,
|
|
87
|
+
} from './useTimeUtils'
|
|
88
|
+
export { useScheduleDrag } from './useScheduleDrag'
|
|
89
|
+
export { useFormBuilder, evaluateCondition } from './useFormBuilder'
|
|
90
|
+
export { useAutoGroup, DEFAULT_COLORS, extractSamplesFromDesignData } from './useAutoGroup'
|
|
91
|
+
export {
|
|
92
|
+
useReagentSeries,
|
|
93
|
+
generateDilutionSeries,
|
|
94
|
+
DEFAULT_PRESETS,
|
|
95
|
+
DEFAULT_UNITS,
|
|
96
|
+
type LevelEntry,
|
|
97
|
+
type DilutionPreset,
|
|
98
|
+
type UseReagentSeriesReturn,
|
|
99
|
+
} from './useReagentSeries'
|
|
100
|
+
export { usePluginConfig, type UsePluginConfigReturn } from './usePluginConfig'
|
|
101
|
+
export {
|
|
102
|
+
useExperimentSelector,
|
|
103
|
+
type UseExperimentSelectorOptions,
|
|
104
|
+
type UseExperimentSelectorReturn,
|
|
105
|
+
} from './useExperimentSelector'
|
|
106
|
+
export {
|
|
107
|
+
formatExperimentDate,
|
|
108
|
+
datePresetToISO,
|
|
109
|
+
EXPERIMENT_STATUS_OPTIONS,
|
|
110
|
+
EXPERIMENT_STATUS_VARIANT_MAP,
|
|
111
|
+
EXPERIMENT_STATUS_LABELS,
|
|
112
|
+
DATE_PRESET_OPTIONS,
|
|
113
|
+
SORT_OPTIONS,
|
|
114
|
+
} from './experiment-utils'
|
|
115
|
+
export {
|
|
116
|
+
useExperimentData,
|
|
117
|
+
type UseExperimentDataOptions,
|
|
118
|
+
type UseExperimentDataReturn,
|
|
119
|
+
} from './useExperimentData'
|
|
120
|
+
export {
|
|
121
|
+
getFieldRegistryEntry,
|
|
122
|
+
getTypeDefault,
|
|
123
|
+
type RegistryEntry,
|
|
124
|
+
} from './formBuilderRegistry'
|
|
125
|
+
export {
|
|
126
|
+
useAppExperiment,
|
|
127
|
+
APP_EXPERIMENT_KEY,
|
|
128
|
+
type UseAppExperimentOptions,
|
|
129
|
+
type UseAppExperimentReturn,
|
|
130
|
+
type AppExperimentState,
|
|
131
|
+
} from './useAppExperiment'
|
|
132
|
+
export {
|
|
133
|
+
useExperimentSave,
|
|
134
|
+
type UseExperimentSaveOptions,
|
|
135
|
+
type UseExperimentSaveReturn,
|
|
136
|
+
} from './useExperimentSave'
|
|
137
|
+
export {
|
|
138
|
+
usePluginApi,
|
|
139
|
+
type UsePluginApiOptions,
|
|
140
|
+
} from './usePluginApi'
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
|
|
2
|
+
import { useSettingsStore } from '../stores/settings'
|
|
3
|
+
import { useAuthStore } from '../stores/auth'
|
|
4
|
+
|
|
5
|
+
let apiClientInstance: AxiosInstance | null = null
|
|
6
|
+
let interceptorAttached = false
|
|
7
|
+
|
|
8
|
+
function getApiClient(): AxiosInstance {
|
|
9
|
+
if (!apiClientInstance) {
|
|
10
|
+
apiClientInstance = axios.create({
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
return apiClientInstance
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ApiClientOptions {
|
|
20
|
+
baseUrl?: string
|
|
21
|
+
timeout?: number
|
|
22
|
+
withAuth?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface UseApiReturn {
|
|
26
|
+
client: AxiosInstance
|
|
27
|
+
get: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>
|
|
28
|
+
post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>
|
|
29
|
+
put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>
|
|
30
|
+
patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>
|
|
31
|
+
delete: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>
|
|
32
|
+
upload: <T>(url: string, file: File, fieldName?: string, additionalData?: Record<string, unknown>) => Promise<T>
|
|
33
|
+
download: (url: string, filename?: string) => Promise<string>
|
|
34
|
+
buildUrl: (path: string) => string
|
|
35
|
+
buildWsUrl: (path: string) => string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Axios-based API client that injects the plugin base URL and JWT auth header on every request. */
|
|
39
|
+
export function useApi(options: ApiClientOptions = {}): UseApiReturn {
|
|
40
|
+
const settingsStore = useSettingsStore()
|
|
41
|
+
const authStore = useAuthStore()
|
|
42
|
+
const apiClient = getApiClient()
|
|
43
|
+
|
|
44
|
+
// Ensure auth store is initialized (reads token from localStorage)
|
|
45
|
+
if (!authStore.isInitialized) {
|
|
46
|
+
authStore.initialize()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Attach auth interceptor only once (reads token dynamically, not from closure)
|
|
50
|
+
if (!interceptorAttached) {
|
|
51
|
+
apiClient.interceptors.request.use((config) => {
|
|
52
|
+
if (authStore.token && config.headers && !config.headers.Authorization) {
|
|
53
|
+
config.headers.Authorization = `Bearer ${authStore.token}`
|
|
54
|
+
}
|
|
55
|
+
return config
|
|
56
|
+
})
|
|
57
|
+
interceptorAttached = true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Build per-request config that applies this caller's options
|
|
61
|
+
function requestConfig(config?: AxiosRequestConfig): AxiosRequestConfig {
|
|
62
|
+
const base: AxiosRequestConfig = {
|
|
63
|
+
baseURL: options.baseUrl ?? settingsStore.getApiBaseUrl(),
|
|
64
|
+
timeout: options.timeout ?? settingsStore.requestTimeout,
|
|
65
|
+
...config,
|
|
66
|
+
}
|
|
67
|
+
// Strip auth header if explicitly disabled
|
|
68
|
+
if (options.withAuth === false) {
|
|
69
|
+
base.headers = { ...base.headers, Authorization: undefined }
|
|
70
|
+
}
|
|
71
|
+
return base
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Generic request methods
|
|
75
|
+
async function get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
76
|
+
const response = await apiClient.get<T>(url, requestConfig(config))
|
|
77
|
+
return response.data
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
|
|
81
|
+
const response = await apiClient.post<T>(url, data, requestConfig(config))
|
|
82
|
+
return response.data
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
|
|
86
|
+
const response = await apiClient.put<T>(url, data, requestConfig(config))
|
|
87
|
+
return response.data
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function patch<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
|
|
91
|
+
const response = await apiClient.patch<T>(url, data, requestConfig(config))
|
|
92
|
+
return response.data
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function del<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
96
|
+
const response = await apiClient.delete<T>(url, requestConfig(config))
|
|
97
|
+
return response.data
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// File upload helper
|
|
101
|
+
async function upload<T>(url: string, file: File, fieldName = 'file', additionalData?: Record<string, unknown>): Promise<T> {
|
|
102
|
+
const formData = new FormData()
|
|
103
|
+
formData.append(fieldName, file)
|
|
104
|
+
|
|
105
|
+
if (additionalData) {
|
|
106
|
+
Object.entries(additionalData).forEach(([key, value]) => {
|
|
107
|
+
if (value !== undefined && value !== null) {
|
|
108
|
+
formData.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const response = await apiClient.post<T>(url, formData, requestConfig({
|
|
114
|
+
// Let Axios set Content-Type with the correct multipart boundary
|
|
115
|
+
headers: { 'Content-Type': undefined },
|
|
116
|
+
}))
|
|
117
|
+
return response.data
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Download helper - returns blob URL
|
|
121
|
+
async function download(url: string, filename?: string): Promise<string> {
|
|
122
|
+
const response = await apiClient.get(url, requestConfig({ responseType: 'blob' }))
|
|
123
|
+
const blob = new Blob([response.data])
|
|
124
|
+
const blobUrl = URL.createObjectURL(blob)
|
|
125
|
+
|
|
126
|
+
// Optionally trigger download
|
|
127
|
+
if (filename) {
|
|
128
|
+
const link = document.createElement('a')
|
|
129
|
+
link.href = blobUrl
|
|
130
|
+
link.download = filename
|
|
131
|
+
document.body.appendChild(link)
|
|
132
|
+
link.click()
|
|
133
|
+
document.body.removeChild(link)
|
|
134
|
+
// Revoke after a short delay to allow download to start;
|
|
135
|
+
// return empty string since the URL will be invalidated
|
|
136
|
+
setTimeout(() => URL.revokeObjectURL(blobUrl), 100)
|
|
137
|
+
return ''
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Caller is responsible for revoking when no filename is provided
|
|
141
|
+
return blobUrl
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Build full URL for external use (e.g., <a href="...">)
|
|
145
|
+
function buildUrl(path: string): string {
|
|
146
|
+
const baseUrl = options.baseUrl ?? settingsStore.getApiBaseUrl()
|
|
147
|
+
return `${baseUrl}${path}`
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// WebSocket URL builder
|
|
151
|
+
function buildWsUrl(path: string): string {
|
|
152
|
+
return `${settingsStore.getWsBaseUrl()}${path}`
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
client: apiClient,
|
|
157
|
+
get,
|
|
158
|
+
post,
|
|
159
|
+
put,
|
|
160
|
+
patch,
|
|
161
|
+
delete: del,
|
|
162
|
+
upload,
|
|
163
|
+
download,
|
|
164
|
+
buildUrl,
|
|
165
|
+
buildWsUrl,
|
|
166
|
+
}
|
|
167
|
+
}
|