@morscherlab/mint-sdk 1.0.0-beta.2 → 1.0.0-beta.4
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 +225 -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/ComponentBindingRenderer.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/DoseDesignWorkspaceView.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/GroupAssigner.test.d.ts +1 -0
- package/dist/__tests__/components/MultiSelect.test.d.ts +1 -0
- package/dist/__tests__/components/PluginWorkspaceView.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/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/experiment-utils.test.d.ts +1 -0
- package/dist/__tests__/composables/useApi.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/AppAvatarMenu.vue.d.ts +2 -7
- package/dist/components/AppContainer.vue.d.ts +1 -1
- package/dist/components/AppLayout.vue.d.ts +20 -1
- package/dist/components/AppSidebar.vue.d.ts +111 -6
- package/dist/components/AppTopBar.vue.d.ts +35 -22
- 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 +119 -0
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +93 -0
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +87 -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/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/ComponentBindingRenderer.vue.d.ts +44 -0
- 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 +147 -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/DoseDesignWorkspaceView.vue.d.ts +149 -0
- 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 +31 -17
- 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/PlateMapEditor.vue.d.ts +1 -1
- package/dist/components/PluginWorkspaceView.vue.d.ts +310 -0
- 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/SettingsModal.vue.d.ts +14 -6
- 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 +6 -6
- package/dist/components/index.d.ts +9 -8
- package/dist/components/index.js +3 -3
- package/dist/components/{SettingsButton.vue.d.ts → internal/ActionItemInternal.vue.d.ts} +11 -9
- package/dist/components/{AppPageSelector.vue.d.ts → internal/AppPageSelectorInternal.vue.d.ts} +3 -6
- package/dist/components/{AppPillNav.vue.d.ts → internal/AppPillNavInternal.vue.d.ts} +4 -2
- package/dist/components/internal/CalendarGridPanelInternal.vue.d.ts +25 -0
- package/dist/components/{FormFieldRenderer.vue.d.ts → internal/FormFieldRendererInternal.vue.d.ts} +2 -2
- package/dist/components/{FormSection.vue.d.ts → internal/FormSectionRenderer.vue.d.ts} +7 -7
- package/dist/components/{WellEditPopup.vue.d.ts → internal/WellEditPopupInternal.vue.d.ts} +1 -1
- package/dist/{components-_XqPEhP9.js → components-BkGF4B4y.js} +9760 -8471
- package/dist/components-BkGF4B4y.js.map +1 -0
- package/dist/composables/experiment-utils.d.ts +8 -0
- package/dist/composables/index.d.ts +22 -5
- package/dist/composables/index.js +4 -3
- package/dist/composables/platformContextHelpers.d.ts +14 -0
- package/dist/composables/useAppExperiment.d.ts +31 -2
- package/dist/composables/useBioTemplateComponents.d.ts +22 -0
- package/dist/composables/useBioTemplateControls.d.ts +6 -0
- package/dist/composables/useBioTemplatePackWorkspace.d.ts +46 -0
- package/dist/composables/useBioTemplatePresetWorkspace.d.ts +75 -0
- package/dist/composables/useBioTemplateWorkspace.d.ts +51 -0
- package/dist/composables/useCalendarGrid.d.ts +26 -0
- package/dist/composables/useControlSchema.d.ts +343 -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/usePluginClient.d.ts +112 -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-CHsME9H1.js} +240 -146
- package/dist/composables-CHsME9H1.js.map +1 -0
- package/dist/index.d.ts +6 -4
- 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 +4746 -5514
- 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 +71 -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-B5jmTWuk.js +9388 -0
- package/dist/templates-B5jmTWuk.js.map +1 -0
- package/dist/types/components.d.ts +26 -23
- 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-BgzpQT53.js +4414 -0
- package/dist/useScheduleDrag-BgzpQT53.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/AppLayout.test.ts +44 -0
- package/src/__tests__/components/AppPageSelector.test.ts +134 -0
- package/src/__tests__/components/AppPillNav.test.ts +125 -0
- package/src/__tests__/components/AppPluginSwitcher.test.ts +44 -0
- package/src/__tests__/components/AppSidebar.test.ts +496 -0
- package/src/__tests__/components/AppToastContainer.test.ts +37 -0
- package/src/__tests__/components/AppTopBar.test.ts +455 -9
- 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 +159 -0
- package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +175 -0
- package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +306 -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/ComponentBindingRenderer.test.ts +161 -0
- package/src/__tests__/components/ConcentrationInput.test.ts +45 -0
- package/src/__tests__/components/ControlWorkspaceView.test.ts +1102 -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/DoseDesignWorkspaceView.test.ts +185 -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/GroupAssigner.test.ts +30 -0
- package/src/__tests__/components/MultiSelect.test.ts +48 -0
- package/src/__tests__/components/PluginWorkspaceView.test.ts +548 -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/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/experiment-utils.test.ts +30 -0
- package/src/__tests__/composables/useApi.test.ts +30 -0
- package/src/__tests__/composables/useAppExperiment.test.ts +100 -1
- package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +125 -0
- package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +199 -0
- package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +104 -0
- package/src/__tests__/composables/useCalendarGrid.test.ts +38 -0
- package/src/__tests__/composables/useControlSchema.test.ts +1033 -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 +541 -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 +324 -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 +1055 -0
- package/src/components/AppAvatarMenu.vue +15 -69
- package/src/components/AppLayout.story.vue +64 -25
- package/src/components/AppLayout.vue +83 -2
- package/src/components/AppPluginSwitcher.vue +41 -145
- package/src/components/AppSidebar.story.vue +203 -1
- package/src/components/AppSidebar.vue +320 -25
- package/src/components/{ToastNotification.story.vue → AppToastContainer.story.vue} +6 -6
- package/src/components/{ToastNotification.vue → AppToastContainer.vue} +1 -1
- package/src/components/AppTopBar.story.vue +7 -33
- package/src/components/AppTopBar.vue +104 -300
- 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 +343 -0
- package/src/components/BioTemplatePackWorkspaceView.story.vue +107 -0
- package/src/components/BioTemplatePackWorkspaceView.vue +177 -0
- package/src/components/BioTemplatePresetWorkspaceView.story.vue +163 -0
- package/src/components/BioTemplatePresetWorkspaceView.vue +401 -0
- package/src/components/BioTemplateRenderer.story.vue +57 -0
- package/src/components/BioTemplateRenderer.vue +57 -0
- package/src/components/Breadcrumb.vue +14 -8
- package/src/components/ComponentBindingRenderer.story.vue +57 -0
- package/src/components/ComponentBindingRenderer.vue +308 -0
- package/src/components/ConcentrationInput.vue +27 -64
- package/src/components/ControlWorkspaceView.story.vue +347 -0
- package/src/components/ControlWorkspaceView.vue +378 -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/DoseDesignWorkspaceView.story.vue +77 -0
- package/src/components/DoseDesignWorkspaceView.vue +255 -0
- package/src/components/DropdownButton.vue +14 -32
- package/src/components/EmptyState.vue +4 -2
- package/src/components/ExperimentPopover.vue +7 -28
- package/src/components/ExperimentSelectorModal.vue +6 -5
- package/src/components/FormBuilder.story.vue +190 -0
- package/src/components/FormBuilder.vue +124 -27
- package/src/components/GroupAssigner.vue +24 -56
- package/src/components/MultiSelect.vue +17 -12
- package/src/components/PlateMapEditor.vue +3 -8
- package/src/components/PluginIcon.vue +2 -22
- package/src/components/PluginWorkspaceView.story.vue +334 -0
- package/src/components/PluginWorkspaceView.vue +708 -0
- 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/SettingsModal.story.vue +88 -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/Tooltip.vue +7 -12
- package/src/components/WellPlate.vue +6 -12
- package/src/components/index.ts +9 -8
- package/src/components/internal/ActionItemInternal.vue +82 -0
- package/src/components/internal/AppPageSelectorInternal.vue +128 -0
- package/src/components/internal/AppPillNavInternal.vue +194 -0
- package/src/components/internal/CalendarGridPanelInternal.vue +120 -0
- package/src/components/{FormFieldRenderer.vue → internal/FormFieldRendererInternal.vue} +4 -12
- package/src/components/{FormSection.vue → internal/FormSectionRenderer.vue} +6 -18
- package/src/components/{WellEditPopup.vue → internal/WellEditPopupInternal.vue} +5 -10
- package/src/composables/experiment-utils.ts +26 -0
- package/src/composables/index.ts +229 -3
- package/src/composables/platformContextHelpers.ts +74 -0
- package/src/composables/useApi.ts +9 -2
- package/src/composables/useAppExperiment.ts +85 -13
- package/src/composables/useBioTemplateComponents.ts +105 -0
- package/src/composables/useBioTemplateControls.ts +41 -0
- package/src/composables/useBioTemplatePackWorkspace.ts +185 -0
- package/src/composables/useBioTemplatePresetWorkspace.ts +326 -0
- package/src/composables/useBioTemplateWorkspace.ts +141 -0
- package/src/composables/useCalendarGrid.ts +140 -0
- package/src/composables/useControlSchema.ts +1362 -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/usePluginClient.ts +466 -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 +11 -348
- package/src/install.ts +11 -4
- package/src/stores/settings.ts +13 -9
- package/src/styles/components/app-layout.css +82 -0
- package/src/styles/components/app-page-selector.css +23 -0
- package/src/styles/components/app-pill-nav.css +77 -0
- package/src/styles/components/app-sidebar.css +119 -0
- package/src/styles/components/app-top-bar.css +0 -201
- package/src/styles/components/concentration-input.css +3 -142
- package/src/styles/components/empty-state.css +0 -16
- package/src/styles/components/theme-toggle.css +3 -66
- package/src/styles/index.css +0 -2
- 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 +653 -0
- package/src/templates/controlSchemas.ts +718 -0
- package/src/templates/index.ts +318 -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 +39 -27
- package/src/types/form-builder.ts +7 -2
- package/src/types/index.ts +13 -3
- 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/__tests__/composables/usePluginApi.test.d.ts +0 -13
- package/dist/auth-DsI0rQ7_.js.map +0 -1
- package/dist/components/GroupingModal.vue.d.ts +0 -12
- package/dist/components-_XqPEhP9.js.map +0 -1
- package/dist/composables/usePluginApi.d.ts +0 -29
- 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/__tests__/composables/usePluginApi.test.ts +0 -81
- package/src/components/AppPageSelector.vue +0 -159
- package/src/components/AppPillNav.vue +0 -66
- package/src/components/GroupingModal.story.vue +0 -52
- package/src/components/GroupingModal.vue +0 -422
- package/src/components/SettingsButton.story.vue +0 -58
- package/src/components/SettingsButton.vue +0 -76
- package/src/composables/usePluginApi.ts +0 -39
- package/src/styles/components/grouping-modal.css +0 -323
- package/src/styles/components/settings-button.css +0 -94
- /package/dist/components/{ToastNotification.vue.d.ts → AppToastContainer.vue.d.ts} +0 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
import type { WellLegendItem } from '../types'
|
|
2
|
+
import {
|
|
3
|
+
extractTemplateCollection,
|
|
4
|
+
getTemplateData,
|
|
5
|
+
} from './builders'
|
|
6
|
+
import {
|
|
7
|
+
toDoseConditions,
|
|
8
|
+
toDoseLayoutState,
|
|
9
|
+
toPlateMapEditorState,
|
|
10
|
+
toProtocolSteps,
|
|
11
|
+
toQpcrWellPlateWells,
|
|
12
|
+
toReagentListItems,
|
|
13
|
+
toSampleOptions,
|
|
14
|
+
toTemplateDataFrame,
|
|
15
|
+
toTimeCourseSteps,
|
|
16
|
+
toWellPlateWells,
|
|
17
|
+
} from './adapters'
|
|
18
|
+
import {
|
|
19
|
+
getBioTemplateInfo,
|
|
20
|
+
} from './catalog'
|
|
21
|
+
import {
|
|
22
|
+
getBioTemplatePresetInfo,
|
|
23
|
+
} from './presets'
|
|
24
|
+
import {
|
|
25
|
+
getBioTemplatePackInfo,
|
|
26
|
+
} from './packs'
|
|
27
|
+
import type {
|
|
28
|
+
BioTemplateEnvelope,
|
|
29
|
+
DataFrameTemplate,
|
|
30
|
+
DoseResponseTemplate,
|
|
31
|
+
PlateMapTemplate,
|
|
32
|
+
QpcrPlateTemplate,
|
|
33
|
+
ReagentListTemplate,
|
|
34
|
+
SampleSheetTemplate,
|
|
35
|
+
TemplateCollectionEnvelope,
|
|
36
|
+
TemplateId,
|
|
37
|
+
TemplatePackId,
|
|
38
|
+
TemplatePresetId,
|
|
39
|
+
TimeCourseTemplate,
|
|
40
|
+
ProtocolStepsTemplate,
|
|
41
|
+
} from './types'
|
|
42
|
+
|
|
43
|
+
export type BioTemplateComponentTarget =
|
|
44
|
+
| TemplateId
|
|
45
|
+
| TemplatePackId
|
|
46
|
+
| TemplatePresetId
|
|
47
|
+
| string
|
|
48
|
+
| BioTemplateEnvelope<unknown>
|
|
49
|
+
| TemplateCollectionEnvelope
|
|
50
|
+
|
|
51
|
+
export interface BioTemplateComponentBinding {
|
|
52
|
+
id: string
|
|
53
|
+
template_id: TemplateId
|
|
54
|
+
component: string
|
|
55
|
+
adapters: readonly string[]
|
|
56
|
+
props: readonly string[]
|
|
57
|
+
description: string
|
|
58
|
+
importPath: '@morscherlab/mint-sdk'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface BioTemplateComponentPropsBinding extends BioTemplateComponentBinding {
|
|
62
|
+
propsObject: Record<string, unknown>
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface BioTemplateResolvedComponentBinding extends Omit<BioTemplateComponentBinding, 'props'> {
|
|
66
|
+
/** Prop names advertised by the static template/component compatibility catalog. */
|
|
67
|
+
propNames: readonly string[]
|
|
68
|
+
/** Concrete props ready for direct `v-bind="componentBindingsById[id].props"` use. */
|
|
69
|
+
props: Record<string, unknown>
|
|
70
|
+
/** Backward-compatible alias for callers that already consume componentProps entries. */
|
|
71
|
+
propsObject: Record<string, unknown>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type BioTemplateComponentBindingsById = Record<string, BioTemplateResolvedComponentBinding>
|
|
75
|
+
export type BioTemplateComponentPropsById = Record<string, Record<string, unknown>>
|
|
76
|
+
export type BioTemplateComponentPropsByComponent = Record<string, Record<string, unknown>[]>
|
|
77
|
+
|
|
78
|
+
export interface BioTemplateComponentPropsLookupOptions {
|
|
79
|
+
templateId?: TemplateId
|
|
80
|
+
id?: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface BioTemplateComponentImport {
|
|
84
|
+
importPath: BioTemplateComponentBinding['importPath']
|
|
85
|
+
components: string[]
|
|
86
|
+
statement: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface BioTemplateComponentSnippet extends BioTemplateComponentBinding {
|
|
90
|
+
propsName: string
|
|
91
|
+
propsExpression: string
|
|
92
|
+
template: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface BioTemplateComponentSnippetOptions {
|
|
96
|
+
propsVariable?: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface BioTemplateComponentUsageOptions extends BioTemplateComponentSnippetOptions {
|
|
100
|
+
targetExpression?: string
|
|
101
|
+
targetPropName?: string
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface BioTemplateComponentUsage {
|
|
105
|
+
imports: BioTemplateComponentImport[]
|
|
106
|
+
componentProps: BioTemplateComponentPropsBinding[]
|
|
107
|
+
snippets: BioTemplateComponentSnippet[]
|
|
108
|
+
propsDeclarations: string[]
|
|
109
|
+
scriptSetup: string
|
|
110
|
+
template: string
|
|
111
|
+
sfc: string
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const templateComponentBindings = {
|
|
115
|
+
'plate-map': [
|
|
116
|
+
binding('plate-map', 'PlateMapEditor', ['toPlateMapEditorState'], ['modelValue', 'format', 'samples'], 'Edit plate layouts from plate-map template data.'),
|
|
117
|
+
binding('plate-map', 'WellPlate', ['toWellPlateWells'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render the active plate as a well grid.'),
|
|
118
|
+
],
|
|
119
|
+
'sample-sheet': [
|
|
120
|
+
binding('sample-sheet', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render sample metadata as a sortable table.'),
|
|
121
|
+
binding('sample-sheet', 'SampleSelector', ['toSampleOptions'], ['samples', 'modelValue'], 'Select samples from sample-sheet records.'),
|
|
122
|
+
],
|
|
123
|
+
'sample-prep': [
|
|
124
|
+
binding('sample-prep', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render preparation steps as a table.'),
|
|
125
|
+
],
|
|
126
|
+
'dose-response': [
|
|
127
|
+
binding('dose-response', 'DoseCalculator', ['toDoseConditions'], ['mode', 'targetWells'], 'Configure serial dilution and apply concentrations to wells.'),
|
|
128
|
+
binding('dose-response', 'WellPlate', ['toDoseLayoutState'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render the optional dose-response plate layout.'),
|
|
129
|
+
],
|
|
130
|
+
'calibration-curve': [
|
|
131
|
+
binding('calibration-curve', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render standards, QC, blanks, and response values.'),
|
|
132
|
+
],
|
|
133
|
+
'time-course': [
|
|
134
|
+
binding('time-course', 'ExperimentTimeline', ['toTimeCourseSteps'], ['modelValue', 'orientation'], 'Render time points as an ordered timeline.'),
|
|
135
|
+
binding('time-course', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render longitudinal samples as a table.'),
|
|
136
|
+
],
|
|
137
|
+
'protocol-steps': [
|
|
138
|
+
binding('protocol-steps', 'ExperimentTimeline', ['toProtocolSteps'], ['modelValue', 'orientation', 'editable'], 'Render protocol steps as an editable timeline.'),
|
|
139
|
+
binding('protocol-steps', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render protocol steps as a table.'),
|
|
140
|
+
],
|
|
141
|
+
'assay-matrix': [
|
|
142
|
+
binding('assay-matrix', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render sample-by-feature measurements.'),
|
|
143
|
+
],
|
|
144
|
+
'reagent-list': [
|
|
145
|
+
binding('reagent-list', 'ReagentList', ['toReagentListItems'], ['modelValue'], 'Render reagents with lot, storage, and stock metadata.'),
|
|
146
|
+
binding('reagent-list', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render reagents as a table.'),
|
|
147
|
+
],
|
|
148
|
+
'flow-cytometry-panel': [
|
|
149
|
+
binding('flow-cytometry-panel', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render markers, fluorophores, detectors, and controls.'),
|
|
150
|
+
],
|
|
151
|
+
'instrument-run': [
|
|
152
|
+
binding('instrument-run', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render acquisition queues, methods, QC, and run status.'),
|
|
153
|
+
],
|
|
154
|
+
'qpcr-plate': [
|
|
155
|
+
binding('qpcr-plate', 'WellPlate', ['toQpcrWellPlateWells'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render qPCR reactions on a well plate.'),
|
|
156
|
+
binding('qpcr-plate', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render qPCR reactions, targets, controls, and Cq values.'),
|
|
157
|
+
],
|
|
158
|
+
} satisfies Record<TemplateId, readonly BioTemplateComponentBinding[]>
|
|
159
|
+
|
|
160
|
+
export function listBioTemplateComponentBindings(): Record<TemplateId, BioTemplateComponentBinding[]> {
|
|
161
|
+
return cloneBindingMap(templateComponentBindings)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function getBioTemplateComponentBindings(
|
|
165
|
+
target: BioTemplateComponentTarget
|
|
166
|
+
): BioTemplateComponentBinding[] {
|
|
167
|
+
const templateIds = resolveComponentTemplateIds(target)
|
|
168
|
+
return templateIds.flatMap(templateId => cloneBindings(templateComponentBindings[templateId]))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function toBioTemplateComponentProps(
|
|
172
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope
|
|
173
|
+
): BioTemplateComponentPropsBinding[] {
|
|
174
|
+
if (isTemplateEnvelope(target)) {
|
|
175
|
+
return propsForTemplate(target)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const collection = extractTemplateCollection(target)
|
|
179
|
+
return Object.values(collection).flatMap(template => propsForTemplate(template))
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Return resolved component bindings with concrete props for direct slot rendering. */
|
|
183
|
+
export function toBioTemplateComponentBindings(
|
|
184
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
185
|
+
): BioTemplateResolvedComponentBinding[] {
|
|
186
|
+
return toBioTemplateComponentProps(target).map(toResolvedComponentBinding)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Return resolved component bindings keyed by stable template component id. */
|
|
190
|
+
export function toBioTemplateComponentBindingsById(
|
|
191
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
192
|
+
): BioTemplateComponentBindingsById {
|
|
193
|
+
return Object.fromEntries(
|
|
194
|
+
toBioTemplateComponentBindings(target).map(binding => [binding.id, binding]),
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Return component props keyed by stable binding id for direct `v-bind="componentPropsById[id]"` use. */
|
|
199
|
+
export function toBioTemplateComponentPropsById(
|
|
200
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
201
|
+
): BioTemplateComponentPropsById {
|
|
202
|
+
return Object.fromEntries(
|
|
203
|
+
toBioTemplateComponentProps(target).map(binding => [binding.id, binding.propsObject]),
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Return component props grouped by SDK component name for direct WellPlate/DoseCalculator binding. */
|
|
208
|
+
export function toBioTemplateComponentPropsByComponent(
|
|
209
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
210
|
+
): BioTemplateComponentPropsByComponent {
|
|
211
|
+
const grouped: BioTemplateComponentPropsByComponent = {}
|
|
212
|
+
for (const binding of toBioTemplateComponentProps(target)) {
|
|
213
|
+
const props = grouped[binding.component] ?? []
|
|
214
|
+
props.push(binding.propsObject)
|
|
215
|
+
grouped[binding.component] = props
|
|
216
|
+
}
|
|
217
|
+
return grouped
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Return the first props object for an SDK component, optionally restricted by template id or binding id. */
|
|
221
|
+
export function getBioTemplateComponentProps(
|
|
222
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
223
|
+
component: string,
|
|
224
|
+
options: BioTemplateComponentPropsLookupOptions = {},
|
|
225
|
+
): Record<string, unknown> | undefined {
|
|
226
|
+
return toBioTemplateComponentProps(target).find((binding) => {
|
|
227
|
+
if (binding.component !== component) return false
|
|
228
|
+
if (options.id !== undefined && binding.id !== options.id) return false
|
|
229
|
+
if (options.templateId !== undefined && binding.template_id !== options.templateId) return false
|
|
230
|
+
return true
|
|
231
|
+
})?.propsObject
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function toResolvedComponentBinding(
|
|
235
|
+
binding: BioTemplateComponentPropsBinding,
|
|
236
|
+
): BioTemplateResolvedComponentBinding {
|
|
237
|
+
const { props: propNames, propsObject, ...rest } = binding
|
|
238
|
+
return {
|
|
239
|
+
...rest,
|
|
240
|
+
propNames,
|
|
241
|
+
props: propsObject,
|
|
242
|
+
propsObject,
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function toBioTemplateComponentImports(
|
|
247
|
+
target: BioTemplateComponentTarget
|
|
248
|
+
): BioTemplateComponentImport[] {
|
|
249
|
+
const groups = new Map<BioTemplateComponentBinding['importPath'], string[]>()
|
|
250
|
+
|
|
251
|
+
for (const binding of getBioTemplateComponentBindings(target)) {
|
|
252
|
+
const components = groups.get(binding.importPath) ?? []
|
|
253
|
+
if (!components.includes(binding.component)) components.push(binding.component)
|
|
254
|
+
groups.set(binding.importPath, components)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return Array.from(groups.entries()).map(([importPath, components]) => ({
|
|
258
|
+
importPath,
|
|
259
|
+
components,
|
|
260
|
+
statement: `import { ${components.join(', ')} } from '${importPath}'`,
|
|
261
|
+
}))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function toBioTemplateComponentSnippets(
|
|
265
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
266
|
+
options: BioTemplateComponentSnippetOptions = {}
|
|
267
|
+
): BioTemplateComponentSnippet[] {
|
|
268
|
+
const propsVariable = options.propsVariable ?? 'componentProps'
|
|
269
|
+
const usedNames = new Map<string, number>()
|
|
270
|
+
|
|
271
|
+
return toBioTemplateComponentProps(target).map((binding, index) => {
|
|
272
|
+
const propsName = uniquePropsName(binding, usedNames)
|
|
273
|
+
const propsExpression = `${propsVariable}[${index}].propsObject`
|
|
274
|
+
return {
|
|
275
|
+
...cloneBinding(binding),
|
|
276
|
+
propsName,
|
|
277
|
+
propsExpression,
|
|
278
|
+
template: `<${binding.component} v-bind="${propsExpression}" />`,
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function toBioTemplateComponentUsage(
|
|
284
|
+
target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,
|
|
285
|
+
options: BioTemplateComponentUsageOptions = {}
|
|
286
|
+
): BioTemplateComponentUsage {
|
|
287
|
+
const propsVariable = options.propsVariable ?? 'componentProps'
|
|
288
|
+
const usesGeneratedTargetProp = options.targetExpression === undefined
|
|
289
|
+
const targetPropName = options.targetPropName ?? 'templateCollection'
|
|
290
|
+
const targetExpression = options.targetExpression ?? `props.${targetPropName}`
|
|
291
|
+
const componentProps = toBioTemplateComponentProps(target)
|
|
292
|
+
const snippets = toBioTemplateComponentSnippets(target, { propsVariable }).map(snippet => ({
|
|
293
|
+
...snippet,
|
|
294
|
+
propsExpression: snippet.propsName,
|
|
295
|
+
template: `<${snippet.component} v-bind="${snippet.propsName}" />`,
|
|
296
|
+
}))
|
|
297
|
+
const propsDeclarations = snippets.map(
|
|
298
|
+
(snippet, index) => `const ${snippet.propsName} = ${propsVariable}[${index}].propsObject`
|
|
299
|
+
)
|
|
300
|
+
const setupLines = [
|
|
301
|
+
...(usesGeneratedTargetProp
|
|
302
|
+
? [`const props = defineProps<{ ${targetPropName}: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope }>()`]
|
|
303
|
+
: []),
|
|
304
|
+
`const ${propsVariable} = toBioTemplateComponentProps(${targetExpression})`,
|
|
305
|
+
...propsDeclarations,
|
|
306
|
+
]
|
|
307
|
+
const imports = toBioTemplateComponentImports(target)
|
|
308
|
+
const template = snippets.map(snippet => snippet.template).join('\n')
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
imports,
|
|
312
|
+
componentProps,
|
|
313
|
+
snippets,
|
|
314
|
+
propsDeclarations,
|
|
315
|
+
scriptSetup: setupLines.join('\n'),
|
|
316
|
+
template,
|
|
317
|
+
sfc: toVueSfc(imports, setupLines, template, usesGeneratedTargetProp),
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function propsForTemplate(template: BioTemplateEnvelope<unknown>): BioTemplateComponentPropsBinding[] {
|
|
322
|
+
switch (template.template_id) {
|
|
323
|
+
case 'plate-map':
|
|
324
|
+
return plateMapProps(template as PlateMapTemplate)
|
|
325
|
+
case 'sample-sheet':
|
|
326
|
+
return [
|
|
327
|
+
dataFrameProps(template as DataFrameTemplate),
|
|
328
|
+
sampleSelectorProps(template as SampleSheetTemplate),
|
|
329
|
+
]
|
|
330
|
+
case 'sample-prep':
|
|
331
|
+
case 'calibration-curve':
|
|
332
|
+
case 'assay-matrix':
|
|
333
|
+
case 'flow-cytometry-panel':
|
|
334
|
+
case 'instrument-run':
|
|
335
|
+
return [dataFrameProps(template as DataFrameTemplate)]
|
|
336
|
+
case 'dose-response':
|
|
337
|
+
return doseResponseProps(template as DoseResponseTemplate)
|
|
338
|
+
case 'time-course':
|
|
339
|
+
return [
|
|
340
|
+
timelineProps(template as TimeCourseTemplate, toTimeCourseSteps(template as TimeCourseTemplate)),
|
|
341
|
+
dataFrameProps(template as DataFrameTemplate),
|
|
342
|
+
]
|
|
343
|
+
case 'protocol-steps':
|
|
344
|
+
return [
|
|
345
|
+
timelineProps(template as ProtocolStepsTemplate, toProtocolSteps(template as ProtocolStepsTemplate), true),
|
|
346
|
+
dataFrameProps(template as DataFrameTemplate),
|
|
347
|
+
]
|
|
348
|
+
case 'reagent-list':
|
|
349
|
+
return [
|
|
350
|
+
reagentListProps(template as ReagentListTemplate),
|
|
351
|
+
dataFrameProps(template as DataFrameTemplate),
|
|
352
|
+
]
|
|
353
|
+
case 'qpcr-plate':
|
|
354
|
+
return qpcrPlateProps(template as QpcrPlateTemplate)
|
|
355
|
+
default:
|
|
356
|
+
return []
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function plateMapProps(template: PlateMapTemplate): BioTemplateComponentPropsBinding[] {
|
|
361
|
+
const state = toPlateMapEditorState(template)
|
|
362
|
+
const plate = activePlateFromState(state)
|
|
363
|
+
return [
|
|
364
|
+
propsBinding('plate-map', 'PlateMapEditor', {
|
|
365
|
+
modelValue: state,
|
|
366
|
+
format: plate.format,
|
|
367
|
+
samples: state.samples,
|
|
368
|
+
}),
|
|
369
|
+
propsBinding('plate-map', 'WellPlate', {
|
|
370
|
+
format: plate.format,
|
|
371
|
+
wells: toWellPlateWells(template),
|
|
372
|
+
sampleColors: sampleColorsFromPlateState(state),
|
|
373
|
+
legendItems: legendItemsFromPlateState(state),
|
|
374
|
+
showLegend: true,
|
|
375
|
+
showSampleTypeIndicator: true,
|
|
376
|
+
}),
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function doseResponseProps(template: DoseResponseTemplate): BioTemplateComponentPropsBinding[] {
|
|
381
|
+
const conditions = toDoseConditions(template)
|
|
382
|
+
const layout = toDoseLayoutState(template)
|
|
383
|
+
const targetWells = layout ? Object.keys(activePlateFromState(layout).wells) : []
|
|
384
|
+
const props = [
|
|
385
|
+
propsBinding('dose-response', 'DoseCalculator', {
|
|
386
|
+
mode: 'serial',
|
|
387
|
+
targetWells,
|
|
388
|
+
disabled: conditions.length === 0,
|
|
389
|
+
}),
|
|
390
|
+
]
|
|
391
|
+
|
|
392
|
+
if (layout) {
|
|
393
|
+
const plate = activePlateFromState(layout)
|
|
394
|
+
props.push(propsBinding('dose-response', 'WellPlate', {
|
|
395
|
+
format: plate.format,
|
|
396
|
+
wells: plate.wells,
|
|
397
|
+
sampleColors: sampleColorsFromPlateState(layout),
|
|
398
|
+
legendItems: conditions.map(condition => ({
|
|
399
|
+
type: condition.label,
|
|
400
|
+
label: condition.label,
|
|
401
|
+
color: condition.color,
|
|
402
|
+
})),
|
|
403
|
+
showLegend: true,
|
|
404
|
+
showSampleTypeIndicator: true,
|
|
405
|
+
}))
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return props
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function qpcrPlateProps(template: QpcrPlateTemplate): BioTemplateComponentPropsBinding[] {
|
|
412
|
+
const data = getTemplateData(template, 'qpcr-plate')
|
|
413
|
+
const frame = dataFrameProps(template)
|
|
414
|
+
return [
|
|
415
|
+
propsBinding('qpcr-plate', 'WellPlate', {
|
|
416
|
+
format: data.format,
|
|
417
|
+
wells: toQpcrWellPlateWells(template),
|
|
418
|
+
sampleColors: Object.fromEntries(data.samples.map((sample, index) => [sample.sampleId, colorForIndex(index)])),
|
|
419
|
+
legendItems: data.samples.map((sample, index): WellLegendItem => ({
|
|
420
|
+
type: sample.sampleId,
|
|
421
|
+
label: sample.name ?? sample.sampleId,
|
|
422
|
+
color: colorForIndex(index),
|
|
423
|
+
})),
|
|
424
|
+
showLegend: true,
|
|
425
|
+
showSampleTypeIndicator: true,
|
|
426
|
+
}),
|
|
427
|
+
frame,
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function dataFrameProps(template: DataFrameTemplate): BioTemplateComponentPropsBinding {
|
|
432
|
+
const frame = toTemplateDataFrame(template)
|
|
433
|
+
return propsBinding(template.template_id as TemplateId, 'DataFrame', {
|
|
434
|
+
...frame,
|
|
435
|
+
searchable: true,
|
|
436
|
+
sortable: true,
|
|
437
|
+
size: 'sm',
|
|
438
|
+
})
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function sampleSelectorProps(template: SampleSheetTemplate): BioTemplateComponentPropsBinding {
|
|
442
|
+
const options = toSampleOptions(template)
|
|
443
|
+
return propsBinding('sample-sheet', 'SampleSelector', {
|
|
444
|
+
samples: options.map(option => option.label),
|
|
445
|
+
modelValue: [],
|
|
446
|
+
})
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function timelineProps(
|
|
450
|
+
template: TimeCourseTemplate | ProtocolStepsTemplate,
|
|
451
|
+
steps: unknown[],
|
|
452
|
+
editable = false
|
|
453
|
+
): BioTemplateComponentPropsBinding {
|
|
454
|
+
return propsBinding(template.template_id as TemplateId, 'ExperimentTimeline', {
|
|
455
|
+
modelValue: steps,
|
|
456
|
+
orientation: 'vertical',
|
|
457
|
+
editable,
|
|
458
|
+
})
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function reagentListProps(template: ReagentListTemplate): BioTemplateComponentPropsBinding {
|
|
462
|
+
return propsBinding('reagent-list', 'ReagentList', {
|
|
463
|
+
modelValue: toReagentListItems(template),
|
|
464
|
+
searchable: true,
|
|
465
|
+
sortable: true,
|
|
466
|
+
})
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function propsBinding(
|
|
470
|
+
templateId: TemplateId,
|
|
471
|
+
component: string,
|
|
472
|
+
propsObject: Record<string, unknown>
|
|
473
|
+
): BioTemplateComponentPropsBinding {
|
|
474
|
+
const matched = templateComponentBindings[templateId].find(binding => binding.component === component)
|
|
475
|
+
if (!matched) {
|
|
476
|
+
throw new Error(`No component binding registered for '${templateId}' and '${component}'.`)
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
...cloneBinding(matched),
|
|
480
|
+
propsObject,
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function resolveComponentTemplateIds(target: BioTemplateComponentTarget): TemplateId[] {
|
|
485
|
+
if (typeof target === 'string') {
|
|
486
|
+
const preset = getBioTemplatePresetInfo(target)
|
|
487
|
+
if (preset) return [...preset.templates]
|
|
488
|
+
const pack = getBioTemplatePackInfo(target)
|
|
489
|
+
if (pack) return [...pack.templates]
|
|
490
|
+
const template = getBioTemplateInfo(target)
|
|
491
|
+
return template ? [template.template_id] : []
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (isTemplateEnvelope(target)) {
|
|
495
|
+
const template = getBioTemplateInfo(target.template_id)
|
|
496
|
+
return template ? [template.template_id] : []
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const presetName = collectionPresetName(target)
|
|
500
|
+
if (presetName) {
|
|
501
|
+
const preset = getBioTemplatePresetInfo(presetName)
|
|
502
|
+
if (preset) return [...preset.templates]
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const packName = collectionPackName(target)
|
|
506
|
+
if (packName) {
|
|
507
|
+
const pack = getBioTemplatePackInfo(packName)
|
|
508
|
+
if (pack) return [...pack.templates]
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return Object.keys(extractTemplateCollection(target))
|
|
512
|
+
.map(templateId => getBioTemplateInfo(templateId)?.template_id)
|
|
513
|
+
.filter((templateId): templateId is TemplateId => templateId !== undefined)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function binding(
|
|
517
|
+
templateId: TemplateId,
|
|
518
|
+
component: string,
|
|
519
|
+
adapters: readonly string[],
|
|
520
|
+
props: readonly string[],
|
|
521
|
+
description: string
|
|
522
|
+
): BioTemplateComponentBinding {
|
|
523
|
+
return {
|
|
524
|
+
id: `${templateId}:${component}`,
|
|
525
|
+
template_id: templateId,
|
|
526
|
+
component,
|
|
527
|
+
adapters,
|
|
528
|
+
props,
|
|
529
|
+
description,
|
|
530
|
+
importPath: '@morscherlab/mint-sdk',
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function activePlateFromState(state: ReturnType<typeof toPlateMapEditorState>) {
|
|
535
|
+
return state.plates.find(plate => plate.id === state.activePlateId) ?? state.plates[0]
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function sampleColorsFromPlateState(state: ReturnType<typeof toPlateMapEditorState>): Record<string, string> {
|
|
539
|
+
return Object.fromEntries(
|
|
540
|
+
state.samples
|
|
541
|
+
.filter(sample => sample.color)
|
|
542
|
+
.map(sample => [sample.id, sample.color as string])
|
|
543
|
+
)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function legendItemsFromPlateState(state: ReturnType<typeof toPlateMapEditorState>): WellLegendItem[] {
|
|
547
|
+
return state.samples.map((sample, index) => ({
|
|
548
|
+
type: sample.id,
|
|
549
|
+
label: sample.name,
|
|
550
|
+
color: sample.color ?? colorForIndex(index),
|
|
551
|
+
}))
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function colorForIndex(index: number): string {
|
|
555
|
+
const colors = ['#3B82F6', '#10B981', '#EF4444', '#F59E0B', '#8B5CF6', '#F97316', '#06B6D4', '#14B8A6']
|
|
556
|
+
return colors[index % colors.length]
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function cloneBindingMap<TName extends string>(
|
|
560
|
+
bindings: Record<TName, readonly BioTemplateComponentBinding[]>
|
|
561
|
+
): Record<TName, BioTemplateComponentBinding[]> {
|
|
562
|
+
const result = {} as Record<TName, BioTemplateComponentBinding[]>
|
|
563
|
+
for (const name of Object.keys(bindings) as TName[]) {
|
|
564
|
+
result[name] = cloneBindings(bindings[name])
|
|
565
|
+
}
|
|
566
|
+
return result
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function cloneBindings(bindings: readonly BioTemplateComponentBinding[]): BioTemplateComponentBinding[] {
|
|
570
|
+
return bindings.map(cloneBinding)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function cloneBinding(binding: BioTemplateComponentBinding): BioTemplateComponentBinding {
|
|
574
|
+
return {
|
|
575
|
+
...binding,
|
|
576
|
+
adapters: [...binding.adapters],
|
|
577
|
+
props: [...binding.props],
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function uniquePropsName(
|
|
582
|
+
binding: BioTemplateComponentBinding,
|
|
583
|
+
usedNames: Map<string, number>
|
|
584
|
+
): string {
|
|
585
|
+
const base = toCamelIdentifier(`${binding.template_id} ${binding.component} props`)
|
|
586
|
+
const count = usedNames.get(base) ?? 0
|
|
587
|
+
usedNames.set(base, count + 1)
|
|
588
|
+
return count === 0 ? base : `${base}${count + 1}`
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function toCamelIdentifier(value: string): string {
|
|
592
|
+
const words = value
|
|
593
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
594
|
+
.split(/[^A-Za-z0-9]+/)
|
|
595
|
+
.filter(Boolean)
|
|
596
|
+
|
|
597
|
+
if (words.length === 0) return 'componentProps'
|
|
598
|
+
|
|
599
|
+
return words
|
|
600
|
+
.map((word, index) => {
|
|
601
|
+
const lower = word.toLowerCase()
|
|
602
|
+
return index === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1)
|
|
603
|
+
})
|
|
604
|
+
.join('')
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function toVueSfc(
|
|
608
|
+
imports: BioTemplateComponentImport[],
|
|
609
|
+
setupLines: string[],
|
|
610
|
+
template: string,
|
|
611
|
+
includeTargetTypeImport: boolean
|
|
612
|
+
): string {
|
|
613
|
+
const importLines = [
|
|
614
|
+
...imports.map(item => item.statement),
|
|
615
|
+
"import { toBioTemplateComponentProps } from '@morscherlab/mint-sdk/templates'",
|
|
616
|
+
...(includeTargetTypeImport
|
|
617
|
+
? ["import type { BioTemplateEnvelope, TemplateCollectionEnvelope } from '@morscherlab/mint-sdk/templates'"]
|
|
618
|
+
: []),
|
|
619
|
+
]
|
|
620
|
+
const templateLines = template
|
|
621
|
+
? template.split('\n').map(line => ` ${line}`).join('\n')
|
|
622
|
+
: ''
|
|
623
|
+
|
|
624
|
+
return [
|
|
625
|
+
'<script setup lang="ts">',
|
|
626
|
+
...importLines,
|
|
627
|
+
'',
|
|
628
|
+
...setupLines,
|
|
629
|
+
'</script>',
|
|
630
|
+
'',
|
|
631
|
+
'<template>',
|
|
632
|
+
templateLines,
|
|
633
|
+
'</template>',
|
|
634
|
+
].join('\n')
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function isTemplateEnvelope(value: unknown): value is BioTemplateEnvelope<unknown> {
|
|
638
|
+
return isRecord(value) && typeof value.template_id === 'string' && 'data' in value
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function collectionPresetName(value: unknown): string | undefined {
|
|
642
|
+
if (!isRecord(value) || !isRecord(value.metadata)) return undefined
|
|
643
|
+
return typeof value.metadata.preset === 'string' ? value.metadata.preset : undefined
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function collectionPackName(value: unknown): string | undefined {
|
|
647
|
+
if (!isRecord(value) || !isRecord(value.metadata)) return undefined
|
|
648
|
+
return typeof value.metadata.pack === 'string' ? value.metadata.pack : undefined
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
652
|
+
return typeof value === 'object' && value !== null
|
|
653
|
+
}
|