@morscherlab/mint-sdk 1.0.0-beta.1 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -6
- package/dist/__tests__/components/ActionItem.test.d.ts +1 -0
- package/dist/__tests__/components/AppAvatarMenu.test.d.ts +1 -0
- package/dist/__tests__/components/AppPageSelector.test.d.ts +1 -0
- package/dist/__tests__/components/AppPillNav.test.d.ts +1 -0
- package/dist/__tests__/components/AppPluginSwitcher.test.d.ts +1 -0
- package/dist/__tests__/components/AppToastContainer.test.d.ts +1 -0
- package/dist/__tests__/components/BaseRadioGroup.test.d.ts +1 -0
- package/dist/__tests__/components/BaseSelect.test.d.ts +1 -0
- package/dist/__tests__/components/BaseTabs.test.d.ts +1 -0
- package/dist/__tests__/components/BatchProgressList.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplateExperimentWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplatePackWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplatePresetWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/BioTemplateRenderer.test.d.ts +1 -0
- package/dist/__tests__/components/Breadcrumb.test.d.ts +1 -0
- package/dist/__tests__/components/CalendarGridPanel.test.d.ts +1 -0
- package/dist/__tests__/components/ConcentrationInput.test.d.ts +1 -0
- package/dist/__tests__/components/ControlWorkspaceView.test.d.ts +1 -0
- package/dist/__tests__/components/DatePicker.test.d.ts +1 -0
- package/dist/__tests__/components/DateTimePicker.test.d.ts +1 -0
- package/dist/__tests__/components/EmptyState.test.d.ts +1 -0
- package/dist/__tests__/components/ExperimentPopover.test.d.ts +1 -0
- package/dist/__tests__/components/FormBuilder.test.d.ts +1 -0
- package/dist/__tests__/components/FormCompatibility.test.d.ts +1 -0
- package/dist/__tests__/components/GroupAssigner.test.d.ts +1 -0
- package/dist/__tests__/components/GroupingModal.test.d.ts +1 -0
- package/dist/__tests__/components/MultiSelect.test.d.ts +1 -0
- package/dist/__tests__/components/PluginIcon.test.d.ts +1 -0
- package/dist/__tests__/components/ProtocolStepEditor.test.d.ts +1 -0
- package/dist/__tests__/components/ReagentList.test.d.ts +1 -0
- package/dist/__tests__/components/SampleHierarchyTree.test.d.ts +1 -0
- package/dist/__tests__/components/SampleSelector.test.d.ts +1 -0
- package/dist/__tests__/components/SegmentedControl.test.d.ts +1 -0
- package/dist/__tests__/components/SettingsButton.test.d.ts +1 -0
- package/dist/__tests__/components/SettingsModal.test.d.ts +1 -0
- package/dist/__tests__/components/TagsInput.test.d.ts +1 -0
- package/dist/__tests__/components/ThemeToggle.test.d.ts +1 -0
- package/dist/__tests__/components/TimePicker.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplatePackWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplatePresetWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useBioTemplateWorkspace.test.d.ts +1 -0
- package/dist/__tests__/composables/useCalendarGrid.test.d.ts +1 -0
- package/dist/__tests__/composables/useControlSchema.test.d.ts +1 -0
- package/dist/__tests__/composables/useDebouncedWatch.test.d.ts +1 -0
- package/dist/__tests__/composables/useDropdownState.test.d.ts +1 -0
- package/dist/__tests__/composables/useEventListener.test.d.ts +1 -0
- package/dist/__tests__/composables/useExpansionSet.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentData.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentSelector.test.d.ts +1 -0
- package/dist/__tests__/composables/useGroupAssignment.test.d.ts +1 -0
- package/dist/__tests__/composables/useListSelection.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginClient.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +1 -0
- package/dist/__tests__/composables/useRequestSyncState.test.d.ts +1 -0
- package/dist/__tests__/composables/useSampleGroups.test.d.ts +1 -0
- package/dist/__tests__/composables/useSelectionLimit.test.d.ts +1 -0
- package/dist/__tests__/composables/useSortedItems.test.d.ts +1 -0
- package/dist/__tests__/composables/useTemplateCollection.test.d.ts +1 -0
- package/dist/__tests__/composables/useTextSearch.test.d.ts +1 -0
- package/dist/__tests__/composables/useTheme.test.d.ts +1 -0
- package/dist/__tests__/composables/useTimeUtils.test.d.ts +1 -0
- package/dist/__tests__/docs/frontendDocsCatalog.test.d.ts +1 -0
- package/dist/__tests__/templates/templates.test.d.ts +1 -0
- package/dist/{auth-DsI0rQ7_.js → auth-QQj2kkze.js} +12 -5
- package/dist/auth-QQj2kkze.js.map +1 -0
- package/dist/components/ActionItem.vue.d.ts +32 -0
- package/dist/components/AppAvatarMenu.vue.d.ts +2 -7
- package/dist/components/AppPageSelector.vue.d.ts +3 -6
- package/dist/components/AppPillNav.vue.d.ts +2 -2
- package/dist/components/AppSidebar.vue.d.ts +56 -3
- package/dist/components/AppToastContainer.vue.d.ts +2 -0
- package/dist/components/AppTopBar.vue.d.ts +43 -10
- package/dist/components/BaseButton.vue.d.ts +2 -2
- 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 +3 -3
- package/dist/components/BaseRadioGroup.vue.d.ts +4 -4
- package/dist/components/BaseSelect.vue.d.ts +4 -4
- package/dist/components/BaseSlider.vue.d.ts +1 -1
- package/dist/components/BaseTabs.vue.d.ts +2 -2
- package/dist/components/BaseTextarea.vue.d.ts +2 -2
- package/dist/components/BaseToggle.vue.d.ts +1 -1
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +117 -0
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +92 -0
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +82 -0
- package/dist/components/BioTemplateRenderer.vue.d.ts +29 -0
- package/dist/components/Breadcrumb.vue.d.ts +2 -2
- package/dist/components/Calendar.vue.d.ts +1 -1
- package/dist/components/CalendarGridPanel.vue.d.ts +25 -0
- package/dist/components/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/ColorSlider.vue.d.ts +1 -1
- package/dist/components/ConcentrationInput.vue.d.ts +2 -2
- package/dist/components/ConfirmDialog.vue.d.ts +2 -2
- package/dist/components/ControlWorkspaceView.vue.d.ts +130 -0
- package/dist/components/DatePicker.vue.d.ts +2 -2
- package/dist/components/DateTimePicker.vue.d.ts +3 -3
- package/dist/components/DropdownButton.vue.d.ts +4 -4
- 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 +2 -2
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/FormActions.vue.d.ts +4 -4
- package/dist/components/FormBuilder.vue.d.ts +22 -8
- package/dist/components/FormFieldRenderer.vue.d.ts +7 -10
- package/dist/components/FormSection.vue.d.ts +11 -24
- package/dist/components/FormulaInput.vue.d.ts +2 -2
- package/dist/components/IconButton.vue.d.ts +1 -1
- package/dist/components/LoadingSpinner.vue.d.ts +1 -1
- 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 +2 -2
- package/dist/components/PluginIcon.vue.d.ts +11 -0
- package/dist/components/ProgressBar.vue.d.ts +2 -2
- package/dist/components/ProtocolStepEditor.vue.d.ts +3 -1
- package/dist/components/RackEditor.vue.d.ts +2 -2
- package/dist/components/ReagentEditor.vue.d.ts +1 -1
- package/dist/components/ResourceCard.vue.d.ts +1 -1
- package/dist/components/SampleLegend.vue.d.ts +2 -2
- package/dist/components/SampleSelector.vue.d.ts +1 -1
- package/dist/components/ScheduleCalendar.vue.d.ts +2 -2
- package/dist/components/ScientificNumber.vue.d.ts +1 -1
- package/dist/components/SegmentedControl.vue.d.ts +3 -3
- package/dist/components/SequenceInput.vue.d.ts +3 -3
- package/dist/components/SettingsButton.vue.d.ts +2 -2
- package/dist/components/SettingsModal.vue.d.ts +32 -4
- 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 +2 -2
- package/dist/components/UnitInput.vue.d.ts +2 -2
- package/dist/components/WellPlate.vue.d.ts +8 -8
- package/dist/components/index.d.ts +12 -1
- package/dist/components/index.js +3 -3
- package/dist/components/internal/FormFieldRendererInternal.vue.d.ts +31 -0
- package/dist/components/internal/FormSectionRenderer.vue.d.ts +43 -0
- package/dist/{components-CzbQQPCb.js → components-D_Sr0adg.js} +9629 -8647
- package/dist/components-D_Sr0adg.js.map +1 -0
- package/dist/composables/index.d.ts +21 -2
- package/dist/composables/index.js +4 -3
- package/dist/composables/platformContextHelpers.d.ts +14 -0
- package/dist/composables/useBioTemplateComponents.d.ts +20 -0
- package/dist/composables/useBioTemplateControls.d.ts +6 -0
- package/dist/composables/useBioTemplatePackWorkspace.d.ts +45 -0
- package/dist/composables/useBioTemplatePresetWorkspace.d.ts +74 -0
- package/dist/composables/useBioTemplateWorkspace.d.ts +50 -0
- package/dist/composables/useCalendarGrid.d.ts +26 -0
- package/dist/composables/useControlSchema.d.ts +321 -0
- package/dist/composables/useDebouncedWatch.d.ts +20 -0
- package/dist/composables/useDropdownState.d.ts +19 -0
- package/dist/composables/useEventListener.d.ts +13 -0
- package/dist/composables/useExpansionSet.d.ts +21 -0
- package/dist/composables/useExperimentData.d.ts +10 -0
- package/dist/composables/useExperimentSave.d.ts +31 -2
- package/dist/composables/useExperimentSelector.d.ts +20 -0
- package/dist/composables/useForm.d.ts +2 -0
- package/dist/composables/useGroupAssignment.d.ts +31 -0
- package/dist/composables/useListSelection.d.ts +35 -0
- package/dist/composables/usePlatformContext.d.ts +24 -3
- package/dist/composables/usePluginApi.d.ts +7 -14
- package/dist/composables/usePluginClient.d.ts +109 -0
- package/dist/composables/usePluginConfig.d.ts +12 -0
- package/dist/composables/useRequestSyncState.d.ts +34 -0
- package/dist/composables/useSampleGroups.d.ts +32 -0
- package/dist/composables/useSelectionLimit.d.ts +17 -0
- package/dist/composables/useSortedItems.d.ts +32 -0
- package/dist/composables/useTemplateCollection.d.ts +58 -0
- package/dist/composables/useTextSearch.d.ts +18 -0
- package/dist/composables/useTimeUtils.d.ts +8 -0
- package/dist/{composables-BXklV5ii.js → composables-C3dpXQN5.js} +228 -146
- package/dist/composables-C3dpXQN5.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +6 -5
- package/dist/install.d.ts +7 -2
- package/dist/install.js +2 -2
- package/dist/install.js.map +1 -1
- package/dist/stores/auth.d.ts +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/stores/settings.d.ts +4 -1
- package/dist/styles.css +5255 -5654
- package/dist/templates/adapters.d.ts +43 -0
- package/dist/templates/builders.d.ts +63 -0
- package/dist/templates/catalog.d.ts +188 -0
- package/dist/templates/componentBindings.d.ts +58 -0
- package/dist/templates/controlSchemas.d.ts +25 -0
- package/dist/templates/index.d.ts +15 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/lookup.d.ts +4 -0
- package/dist/templates/packs.d.ts +18 -0
- package/dist/templates/presets.d.ts +90 -0
- package/dist/templates/types.d.ts +531 -0
- package/dist/templates-50NPjaxL.js +9333 -0
- package/dist/templates-50NPjaxL.js.map +1 -0
- package/dist/types/components.d.ts +62 -1
- package/dist/types/form-builder.d.ts +6 -8
- package/dist/types/index.d.ts +2 -2
- package/dist/types/platform.d.ts +8 -1
- package/dist/useScheduleDrag-D4oWdh41.js +4371 -0
- package/dist/useScheduleDrag-D4oWdh41.js.map +1 -0
- package/dist/utils/formModelSync.d.ts +5 -0
- package/dist/utils/items.d.ts +8 -0
- package/dist/utils/options.d.ts +6 -0
- package/dist/utils/pluginIcon.d.ts +9 -0
- package/package.json +7 -2
- package/src/__tests__/components/ActionItem.test.ts +99 -0
- package/src/__tests__/components/AppAvatarMenu.test.ts +27 -0
- package/src/__tests__/components/AppPageSelector.test.ts +134 -0
- package/src/__tests__/components/AppPillNav.test.ts +78 -0
- package/src/__tests__/components/AppPluginSwitcher.test.ts +44 -0
- package/src/__tests__/components/AppSidebar.test.ts +370 -0
- package/src/__tests__/components/AppToastContainer.test.ts +48 -0
- package/src/__tests__/components/AppTopBar.test.ts +414 -13
- package/src/__tests__/components/BaseRadioGroup.test.ts +25 -0
- package/src/__tests__/components/BaseSelect.test.ts +21 -0
- package/src/__tests__/components/BaseTabs.test.ts +25 -0
- package/src/__tests__/components/BatchProgressList.test.ts +52 -0
- package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +153 -0
- package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +161 -0
- package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +281 -0
- package/src/__tests__/components/BioTemplateRenderer.test.ts +71 -0
- package/src/__tests__/components/Breadcrumb.test.ts +23 -0
- package/src/__tests__/components/CalendarGridPanel.test.ts +36 -0
- package/src/__tests__/components/ConcentrationInput.test.ts +45 -0
- package/src/__tests__/components/ControlWorkspaceView.test.ts +1031 -0
- package/src/__tests__/components/DataFrame.test.ts +11 -0
- package/src/__tests__/components/DatePicker.test.ts +45 -0
- package/src/__tests__/components/DateTimePicker.test.ts +48 -0
- package/src/__tests__/components/DropdownButton.test.ts +23 -0
- package/src/__tests__/components/EmptyState.test.ts +23 -0
- package/src/__tests__/components/ExperimentPopover.test.ts +56 -0
- package/src/__tests__/components/FormBuilder.test.ts +296 -0
- package/src/__tests__/components/FormCompatibility.test.ts +94 -0
- package/src/__tests__/components/GroupAssigner.test.ts +30 -0
- package/src/__tests__/components/GroupingModal.test.ts +73 -0
- package/src/__tests__/components/MultiSelect.test.ts +48 -0
- package/src/__tests__/components/PluginIcon.test.ts +119 -0
- package/src/__tests__/components/ProtocolStepEditor.test.ts +33 -0
- package/src/__tests__/components/ReagentList.test.ts +82 -0
- package/src/__tests__/components/SampleHierarchyTree.test.ts +53 -0
- package/src/__tests__/components/SampleSelector.test.ts +60 -0
- package/src/__tests__/components/SegmentedControl.test.ts +24 -0
- package/src/__tests__/components/SettingsButton.test.ts +44 -0
- package/src/__tests__/components/SettingsModal.test.ts +296 -0
- package/src/__tests__/components/TagsInput.test.ts +75 -0
- package/src/__tests__/components/ThemeToggle.test.ts +47 -0
- package/src/__tests__/components/TimePicker.test.ts +38 -0
- package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +122 -0
- package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +199 -0
- package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +99 -0
- package/src/__tests__/composables/useCalendarGrid.test.ts +38 -0
- package/src/__tests__/composables/useControlSchema.test.ts +919 -0
- package/src/__tests__/composables/useDebouncedWatch.test.ts +93 -0
- package/src/__tests__/composables/useDropdownState.test.ts +95 -0
- package/src/__tests__/composables/useEventListener.test.ts +116 -0
- package/src/__tests__/composables/useExpansionSet.test.ts +62 -0
- package/src/__tests__/composables/useExperimentData.test.ts +4 -0
- package/src/__tests__/composables/useExperimentSave.test.ts +203 -8
- package/src/__tests__/composables/useExperimentSelector.test.ts +164 -0
- package/src/__tests__/composables/useForm.test.ts +58 -0
- package/src/__tests__/composables/useFormBuilder.test.ts +77 -0
- package/src/__tests__/composables/useGroupAssignment.test.ts +73 -0
- package/src/__tests__/composables/useListSelection.test.ts +66 -0
- package/src/__tests__/composables/usePluginClient.test.ts +444 -0
- package/src/__tests__/composables/usePluginConfig.test.ts +5 -0
- package/src/__tests__/composables/useRequestSyncState.test.ts +92 -0
- package/src/__tests__/composables/useSampleGroups.test.ts +66 -0
- package/src/__tests__/composables/useSelectionLimit.test.ts +41 -0
- package/src/__tests__/composables/useSortedItems.test.ts +87 -0
- package/src/__tests__/composables/useTemplateCollection.test.ts +147 -0
- package/src/__tests__/composables/useTextSearch.test.ts +55 -0
- package/src/__tests__/composables/useTheme.test.ts +91 -0
- package/src/__tests__/composables/useTimeUtils.test.ts +35 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +229 -0
- package/src/__tests__/fixtures/templates/dose-response.json +81 -0
- package/src/__tests__/fixtures/templates/plate-map.json +54 -0
- package/src/__tests__/fixtures/templates/qpcr-plate.json +96 -0
- package/src/__tests__/fixtures/templates/sample-sheet.json +71 -0
- package/src/__tests__/templates/templates.test.ts +1043 -0
- package/src/components/ActionItem.vue +82 -0
- package/src/components/AppAvatarMenu.vue +15 -69
- package/src/components/AppLayout.story.vue +25 -25
- package/src/components/AppPageSelector.vue +63 -94
- package/src/components/AppPillNav.vue +44 -39
- package/src/components/AppPluginSwitcher.vue +41 -145
- package/src/components/AppSidebar.story.vue +94 -0
- package/src/components/AppSidebar.vue +187 -12
- package/src/components/{ToastNotification.story.vue → AppToastContainer.story.vue} +6 -6
- package/src/components/AppToastContainer.vue +62 -0
- package/src/components/AppTopBar.story.vue +7 -30
- package/src/components/AppTopBar.vue +283 -84
- package/src/components/BaseModal.vue +3 -5
- package/src/components/BaseRadioGroup.vue +7 -3
- package/src/components/BaseSelect.vue +11 -7
- package/src/components/BaseTabs.vue +6 -4
- package/src/components/BatchProgressList.vue +5 -8
- package/src/components/BioTemplateExperimentWorkspaceView.story.vue +123 -0
- package/src/components/BioTemplateExperimentWorkspaceView.vue +337 -0
- package/src/components/BioTemplatePackWorkspaceView.story.vue +107 -0
- package/src/components/BioTemplatePackWorkspaceView.vue +176 -0
- package/src/components/BioTemplatePresetWorkspaceView.story.vue +151 -0
- package/src/components/BioTemplatePresetWorkspaceView.vue +392 -0
- package/src/components/BioTemplateRenderer.story.vue +57 -0
- package/src/components/BioTemplateRenderer.vue +269 -0
- package/src/components/Breadcrumb.vue +14 -8
- package/src/components/CalendarGridPanel.vue +120 -0
- package/src/components/ConcentrationInput.vue +27 -64
- package/src/components/ControlWorkspaceView.story.vue +336 -0
- package/src/components/ControlWorkspaceView.vue +347 -0
- package/src/components/DataFrame.vue +34 -50
- package/src/components/DatePicker.vue +59 -192
- package/src/components/DateTimePicker.vue +50 -171
- package/src/components/DropdownButton.vue +14 -32
- package/src/components/EmptyState.vue +4 -2
- package/src/components/ExperimentPopover.vue +5 -22
- package/src/components/FormBuilder.vue +124 -27
- package/src/components/FormFieldRenderer.vue +15 -38
- package/src/components/FormSection.vue +20 -73
- package/src/components/GroupAssigner.vue +24 -56
- package/src/components/GroupingModal.story.vue +3 -3
- package/src/components/GroupingModal.vue +30 -391
- package/src/components/MultiSelect.vue +17 -12
- package/src/components/PlateMapEditor.vue +3 -8
- package/src/components/PluginIcon.story.vue +71 -0
- package/src/components/PluginIcon.vue +68 -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/SettingsButton.story.vue +1 -1
- package/src/components/SettingsButton.vue +15 -27
- package/src/components/SettingsModal.story.vue +337 -45
- package/src/components/SettingsModal.vue +344 -66
- package/src/components/TagsInput.vue +29 -14
- package/src/components/ThemeToggle.vue +9 -7
- package/src/components/TimePicker.vue +19 -41
- package/src/components/ToastNotification.vue +4 -57
- package/src/components/Tooltip.vue +7 -12
- package/src/components/WellEditPopup.vue +3 -8
- package/src/components/WellPlate.vue +4 -10
- package/src/components/index.ts +12 -1
- package/src/components/internal/FormFieldRendererInternal.vue +50 -0
- package/src/components/internal/FormSectionRenderer.vue +78 -0
- package/src/composables/index.ts +212 -0
- package/src/composables/platformContextHelpers.ts +74 -0
- package/src/composables/useBioTemplateComponents.ts +93 -0
- package/src/composables/useBioTemplateControls.ts +41 -0
- package/src/composables/useBioTemplatePackWorkspace.ts +181 -0
- package/src/composables/useBioTemplatePresetWorkspace.ts +337 -0
- package/src/composables/useBioTemplateWorkspace.ts +139 -0
- package/src/composables/useCalendarGrid.ts +140 -0
- package/src/composables/useControlSchema.ts +1274 -0
- package/src/composables/useDebouncedWatch.ts +119 -0
- package/src/composables/useDropdownState.ts +83 -0
- package/src/composables/useEventListener.ts +111 -0
- package/src/composables/useExpansionSet.ts +117 -0
- package/src/composables/useExperimentData.ts +20 -11
- package/src/composables/useExperimentSave.ts +202 -50
- package/src/composables/useExperimentSelector.ts +86 -72
- package/src/composables/useForm.ts +49 -4
- package/src/composables/useFormBuilder.ts +93 -42
- package/src/composables/useGroupAssignment.ts +148 -0
- package/src/composables/useListSelection.ts +158 -0
- package/src/composables/usePluginApi.ts +7 -14
- package/src/composables/usePluginClient.ts +425 -0
- package/src/composables/usePluginConfig.ts +34 -13
- package/src/composables/useRequestSyncState.ts +126 -0
- package/src/composables/useSampleGroups.ts +126 -0
- package/src/composables/useSelectionLimit.ts +57 -0
- package/src/composables/useSortedItems.ts +118 -0
- package/src/composables/useTemplateCollection.ts +229 -0
- package/src/composables/useTextSearch.ts +60 -0
- package/src/composables/useTheme.ts +2 -28
- package/src/composables/useTimeUtils.ts +26 -2
- package/src/composables/useWellPlateEditor.ts +13 -9
- package/src/index.ts +228 -4
- package/src/install.ts +11 -4
- package/src/stores/settings.ts +13 -9
- package/src/styles/components/app-page-selector.css +23 -0
- package/src/styles/components/app-pill-nav.css +8 -2
- package/src/styles/components/app-top-bar.css +35 -2
- package/src/styles/components/button.css +3 -7
- package/src/styles/components/concentration-input.css +3 -142
- package/src/styles/components/dropdown-button.css +4 -4
- package/src/styles/components/empty-state.css +0 -16
- package/src/styles/components/input.css +4 -5
- package/src/styles/components/number-input.css +3 -3
- package/src/styles/components/plugin-icon.css +38 -0
- package/src/styles/components/segmented-control.css +4 -7
- package/src/styles/components/settings-button.css +3 -66
- package/src/styles/components/settings-modal.css +184 -0
- package/src/styles/components/tabs.css +1 -2
- package/src/styles/components/textarea.css +4 -5
- package/src/styles/components/theme-toggle.css +3 -66
- package/src/styles/components/unit-input.css +3 -3
- package/src/styles/index.css +0 -1
- package/src/templates/adapters.ts +785 -0
- package/src/templates/builders.ts +2149 -0
- package/src/templates/catalog.ts +245 -0
- package/src/templates/componentBindings.ts +615 -0
- package/src/templates/controlSchemas.ts +718 -0
- package/src/templates/index.ts +314 -0
- package/src/templates/lookup.ts +18 -0
- package/src/templates/packs.ts +156 -0
- package/src/templates/presets.ts +146 -0
- package/src/templates/types.ts +668 -0
- package/src/types/components.ts +80 -1
- package/src/types/form-builder.ts +7 -2
- package/src/types/index.ts +17 -0
- package/src/types/platform.ts +8 -1
- package/src/utils/formModelSync.ts +52 -0
- package/src/utils/items.ts +28 -0
- package/src/utils/options.ts +23 -0
- package/src/utils/pluginIcon.ts +30 -0
- package/dist/auth-DsI0rQ7_.js.map +0 -1
- package/dist/components-CzbQQPCb.js.map +0 -1
- package/dist/composables-BXklV5ii.js.map +0 -1
- package/dist/useScheduleDrag-CxBeqYcu.js +0 -7181
- package/dist/useScheduleDrag-CxBeqYcu.js.map +0 -1
- package/src/styles/components/grouping-modal.css +0 -323
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Form for creating or editing a single protocol step (incubation, wash, addition, centrifuge, etc.) with template picker, typed parameters, and duration. */
|
|
3
|
-
import { ref, computed, watch, onMounted
|
|
3
|
+
import { ref, computed, watch, onMounted } from 'vue'
|
|
4
4
|
import type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'
|
|
5
|
+
import { useDropdownState } from '../composables/useDropdownState'
|
|
5
6
|
import {
|
|
6
7
|
useProtocolTemplates,
|
|
7
8
|
type StepTemplate,
|
|
@@ -38,7 +39,12 @@ const {
|
|
|
38
39
|
|
|
39
40
|
// State
|
|
40
41
|
const selectedTemplateId = ref<string | null>(null)
|
|
41
|
-
const
|
|
42
|
+
const {
|
|
43
|
+
isOpen: templateDropdownOpen,
|
|
44
|
+
rootRef: templateDropdownRef,
|
|
45
|
+
close: closeTemplateDropdown,
|
|
46
|
+
toggle: toggleTemplateDropdown,
|
|
47
|
+
} = useDropdownState()
|
|
42
48
|
const stepName = ref('')
|
|
43
49
|
const stepDescription = ref('')
|
|
44
50
|
const stepDuration = ref<number | undefined>()
|
|
@@ -113,7 +119,7 @@ function initFromStep(step: ProtocolStep) {
|
|
|
113
119
|
// Handle template selection
|
|
114
120
|
function selectTemplate(template: StepTemplate) {
|
|
115
121
|
selectedTemplateId.value = template.id
|
|
116
|
-
|
|
122
|
+
closeTemplateDropdown()
|
|
117
123
|
|
|
118
124
|
// Reset to template defaults if creating new
|
|
119
125
|
if (props.mode === 'create') {
|
|
@@ -185,14 +191,6 @@ function handleCancel() {
|
|
|
185
191
|
emit('cancel')
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
// Close dropdown on click outside
|
|
189
|
-
function handleClickOutside(event: MouseEvent) {
|
|
190
|
-
const target = event.target as HTMLElement
|
|
191
|
-
if (!target.closest('.mint-protocol-editor__template-dropdown')) {
|
|
192
|
-
dropdownOpen.value = false
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
194
|
// Format duration
|
|
197
195
|
function formatDuration(minutes: number | undefined): string {
|
|
198
196
|
if (minutes === undefined) return ''
|
|
@@ -202,10 +200,7 @@ function formatDuration(minutes: number | undefined): string {
|
|
|
202
200
|
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`
|
|
203
201
|
}
|
|
204
202
|
|
|
205
|
-
// Lifecycle
|
|
206
203
|
onMounted(() => {
|
|
207
|
-
document.addEventListener('click', handleClickOutside)
|
|
208
|
-
|
|
209
204
|
if (props.modelValue) {
|
|
210
205
|
initFromStep(props.modelValue)
|
|
211
206
|
} else if (availableTemplates.value.length > 0) {
|
|
@@ -213,10 +208,6 @@ onMounted(() => {
|
|
|
213
208
|
}
|
|
214
209
|
})
|
|
215
210
|
|
|
216
|
-
onUnmounted(() => {
|
|
217
|
-
document.removeEventListener('click', handleClickOutside)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
211
|
// Watch for external changes
|
|
221
212
|
watch(
|
|
222
213
|
() => props.modelValue,
|
|
@@ -250,11 +241,11 @@ watch(
|
|
|
250
241
|
<!-- Template selector -->
|
|
251
242
|
<div class="mint-protocol-editor__template-select">
|
|
252
243
|
<label class="mint-protocol-editor__template-label">Template</label>
|
|
253
|
-
<div class="mint-protocol-editor__template-dropdown">
|
|
244
|
+
<div ref="templateDropdownRef" class="mint-protocol-editor__template-dropdown">
|
|
254
245
|
<button
|
|
255
246
|
type="button"
|
|
256
247
|
class="mint-protocol-editor__template-btn"
|
|
257
|
-
@click
|
|
248
|
+
@click="toggleTemplateDropdown"
|
|
258
249
|
>
|
|
259
250
|
<svg
|
|
260
251
|
v-if="selectedTemplate"
|
|
@@ -276,7 +267,7 @@ watch(
|
|
|
276
267
|
<svg
|
|
277
268
|
:class="[
|
|
278
269
|
'mint-protocol-editor__template-arrow',
|
|
279
|
-
|
|
270
|
+
templateDropdownOpen ? 'mint-protocol-editor__template-arrow--open' : '',
|
|
280
271
|
]"
|
|
281
272
|
fill="none"
|
|
282
273
|
stroke="currentColor"
|
|
@@ -286,7 +277,7 @@ watch(
|
|
|
286
277
|
</svg>
|
|
287
278
|
</button>
|
|
288
279
|
|
|
289
|
-
<div v-if="
|
|
280
|
+
<div v-if="templateDropdownOpen" class="mint-protocol-editor__template-menu">
|
|
290
281
|
<button
|
|
291
282
|
v-for="template in availableTemplates"
|
|
292
283
|
:key="template.id"
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/** Sortable, searchable table of experiment reagents showing lot number, expiry, storage conditions, and stock level with low-stock warnings. */
|
|
3
3
|
import { ref, computed } from 'vue'
|
|
4
4
|
import type { ReagentColumn, Reagent } from '../types'
|
|
5
|
+
import { useSortedItems } from '../composables/useSortedItems'
|
|
6
|
+
import { useTextSearch } from '../composables/useTextSearch'
|
|
5
7
|
|
|
6
8
|
interface Props {
|
|
7
9
|
modelValue?: Reagent[]
|
|
@@ -50,43 +52,33 @@ const columnLabels: Record<ReagentColumn, string> = {
|
|
|
50
52
|
supplier: 'Supplier',
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
r.lotNumber?.toLowerCase().includes(query) ||
|
|
65
|
-
r.supplier?.toLowerCase().includes(query)
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Sort
|
|
70
|
-
if (sortColumn.value) {
|
|
71
|
-
const col = sortColumn.value
|
|
72
|
-
result.sort((a, b) => {
|
|
73
|
-
let aVal: string | number | null | undefined = getColumnValue(a, col) as string | number | null | undefined
|
|
74
|
-
let bVal: string | number | null | undefined = getColumnValue(b, col) as string | number | null | undefined
|
|
75
|
-
|
|
76
|
-
if (aVal === null || aVal === undefined) return 1
|
|
77
|
-
if (bVal === null || bVal === undefined) return -1
|
|
78
|
-
|
|
79
|
-
if (typeof aVal === 'string') aVal = aVal.toLowerCase()
|
|
80
|
-
if (typeof bVal === 'string') bVal = bVal.toLowerCase()
|
|
55
|
+
const reagentSearch = useTextSearch({
|
|
56
|
+
items: () => props.modelValue || [],
|
|
57
|
+
query: searchQuery,
|
|
58
|
+
enabled: () => props.searchable,
|
|
59
|
+
getText: (reagent) => [
|
|
60
|
+
reagent.name,
|
|
61
|
+
reagent.catalogNumber,
|
|
62
|
+
reagent.lotNumber,
|
|
63
|
+
reagent.supplier,
|
|
64
|
+
],
|
|
65
|
+
})
|
|
81
66
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
67
|
+
const reagentSort = computed(() => {
|
|
68
|
+
if (!sortColumn.value) return null
|
|
69
|
+
return {
|
|
70
|
+
key: sortColumn.value,
|
|
71
|
+
direction: sortDirection.value,
|
|
86
72
|
}
|
|
73
|
+
})
|
|
87
74
|
|
|
88
|
-
|
|
75
|
+
const sortedReagents = useSortedItems<Reagent, ReagentColumn>({
|
|
76
|
+
items: reagentSearch.filteredItems,
|
|
77
|
+
sort: reagentSort,
|
|
78
|
+
caseSensitive: false,
|
|
79
|
+
getValue: (reagent, column) => getColumnValue(reagent, column),
|
|
89
80
|
})
|
|
81
|
+
const filteredReagents = sortedReagents.sortedItems
|
|
90
82
|
|
|
91
83
|
function getColumnValue(reagent: Reagent, column: ReagentColumn): unknown {
|
|
92
84
|
switch (column) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Collapsible tree visualizing the biological sample hierarchy (study → experiment → plate → sample → cell line → passage → clone → treatment). */
|
|
3
|
-
import {
|
|
4
|
-
import { h, Transition } from 'vue'
|
|
3
|
+
import { h, Transition, type VNode } from 'vue'
|
|
5
4
|
import type { TreeNodeType, BadgeVariant, TreeNode } from '../types'
|
|
5
|
+
import { useExpansionSet } from '../composables/useExpansionSet'
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
8
|
nodes: TreeNode[]
|
|
@@ -28,9 +28,6 @@ const emit = defineEmits<{
|
|
|
28
28
|
'collapse': [nodeId: string]
|
|
29
29
|
}>()
|
|
30
30
|
|
|
31
|
-
// Track expanded nodes
|
|
32
|
-
const expandedIds = ref<Set<string>>(new Set(props.defaultExpandedIds))
|
|
33
|
-
|
|
34
31
|
// Default icons by type (Lucide SVG paths - arrays to support multi-path icons)
|
|
35
32
|
interface IconElement {
|
|
36
33
|
tag: 'path' | 'circle' | 'rect'
|
|
@@ -100,30 +97,22 @@ function collectAllIds(nodes: TreeNode[]): string[] {
|
|
|
100
97
|
return ids
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
() => props.
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
expandedIds.value = new Set(collectAllIds(props.nodes))
|
|
109
|
-
} else {
|
|
110
|
-
expandedIds.value = new Set(props.defaultExpandedIds)
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
{ immediate: true }
|
|
114
|
-
)
|
|
100
|
+
const expansion = useExpansionSet({
|
|
101
|
+
defaultIds: () => props.defaultExpandedIds,
|
|
102
|
+
allIds: () => collectAllIds(props.nodes),
|
|
103
|
+
expandAll: () => props.expandAll,
|
|
104
|
+
})
|
|
115
105
|
|
|
116
106
|
function isExpanded(nodeId: string): boolean {
|
|
117
|
-
return
|
|
107
|
+
return expansion.isExpanded(nodeId)
|
|
118
108
|
}
|
|
119
109
|
|
|
120
110
|
function toggleExpand(node: TreeNode) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
emit('collapse', node.id)
|
|
124
|
-
} else {
|
|
125
|
-
expandedIds.value.add(node.id)
|
|
111
|
+
const expanded = expansion.toggle(node.id)
|
|
112
|
+
if (expanded) {
|
|
126
113
|
emit('expand', node.id)
|
|
114
|
+
} else {
|
|
115
|
+
emit('collapse', node.id)
|
|
127
116
|
}
|
|
128
117
|
}
|
|
129
118
|
|
|
@@ -6,8 +6,11 @@ import BaseInput from './BaseInput.vue'
|
|
|
6
6
|
import AutoGroupModal from './AutoGroupModal.vue'
|
|
7
7
|
import type { SampleGroup } from '../types'
|
|
8
8
|
import type { AutoGroupResult } from '../types/auto-group'
|
|
9
|
-
import { deriveShade } from '../utils/color'
|
|
10
9
|
import { DEFAULT_COLORS } from '../composables/useAutoGroup'
|
|
10
|
+
import { useTextSearch } from '../composables/useTextSearch'
|
|
11
|
+
import { useListSelection } from '../composables/useListSelection'
|
|
12
|
+
import { useSampleGroups, type SampleMajorGroup } from '../composables/useSampleGroups'
|
|
13
|
+
import { useExpansionSet } from '../composables/useExpansionSet'
|
|
11
14
|
|
|
12
15
|
interface Props {
|
|
13
16
|
samples: string[]
|
|
@@ -42,8 +45,8 @@ const showSmartGroupModal = ref(false)
|
|
|
42
45
|
const newGroupName = ref('')
|
|
43
46
|
const editingColor = ref<ColorEdit | null>(null)
|
|
44
47
|
const colorPickerInput = ref<HTMLInputElement | null>(null)
|
|
45
|
-
const expandedGroups = ref<Record<string, boolean>>({})
|
|
46
48
|
const searchQuery = ref('')
|
|
49
|
+
const groupExpansion = useExpansionSet()
|
|
47
50
|
|
|
48
51
|
// Sample Drag State
|
|
49
52
|
const draggingSample = ref<string | null>(null)
|
|
@@ -63,184 +66,102 @@ const internalGroups = computed({
|
|
|
63
66
|
set: (value) => emit('update:groups', value),
|
|
64
67
|
})
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// each render re-uses the same string reference instead of re-allocating.
|
|
70
|
-
displayBg: string
|
|
71
|
-
displayBorder: string
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface MajorGroup {
|
|
75
|
-
name: string
|
|
76
|
-
color: string
|
|
77
|
-
subGroups: DisplaySubGroup[]
|
|
78
|
-
allSamples: string[]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const hierarchicalGroups = computed<MajorGroup[]>(() => {
|
|
82
|
-
const groups = internalGroups.value
|
|
83
|
-
if (groups.length === 0) return []
|
|
84
|
-
|
|
85
|
-
// Detect separator: use '/' if any group name contains it, otherwise '_'
|
|
86
|
-
const separator = groups.some(g => g.name.includes('/')) ? '/' : '_'
|
|
87
|
-
const majorGroupMap: Record<string, SampleGroup[]> = {}
|
|
88
|
-
|
|
89
|
-
for (const group of groups) {
|
|
90
|
-
const parts = group.name.split(separator)
|
|
91
|
-
// Use first part as major group, or full name if no separator
|
|
92
|
-
const majorPrefix = parts.length > 1 ? parts[0] : group.name
|
|
93
|
-
|
|
94
|
-
if (!majorGroupMap[majorPrefix]) {
|
|
95
|
-
majorGroupMap[majorPrefix] = []
|
|
96
|
-
}
|
|
97
|
-
majorGroupMap[majorPrefix].push(group)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const result: MajorGroup[] = []
|
|
101
|
-
|
|
102
|
-
// Preserve insertion order from internalGroups so manual drag-reorder sticks.
|
|
103
|
-
for (const [majorName, subGroups] of Object.entries(majorGroupMap)) {
|
|
104
|
-
const allSamples = subGroups.flatMap(g => g.samples)
|
|
105
|
-
const color = subGroups[0]?.color || '#3B82F6'
|
|
106
|
-
const displaySubs: DisplaySubGroup[] = subGroups.map((sub, i) => {
|
|
107
|
-
const displayColor = deriveShade(color, i, subGroups.length)
|
|
108
|
-
return {
|
|
109
|
-
...sub,
|
|
110
|
-
displayColor,
|
|
111
|
-
displayBg: displayColor + '20',
|
|
112
|
-
displayBorder: displayColor + '40',
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
result.push({ name: majorName, color, subGroups: displaySubs, allSamples })
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return result
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
// Check if hierarchy is meaningful (major groups have multiple sub-groups)
|
|
123
|
-
// If each major group only has 1 sub-group with same name, show flat view instead
|
|
124
|
-
const showHierarchy = computed(() => {
|
|
125
|
-
const groups = hierarchicalGroups.value
|
|
126
|
-
if (groups.length === 0) return false
|
|
127
|
-
|
|
128
|
-
// Show hierarchy if any major group has multiple sub-groups
|
|
129
|
-
// OR if major group name differs from its sub-group name
|
|
130
|
-
return groups.some(major =>
|
|
131
|
-
major.subGroups.length > 1 ||
|
|
132
|
-
(major.subGroups.length === 1 && major.name !== major.subGroups[0].name)
|
|
133
|
-
)
|
|
69
|
+
const sampleGroups = useSampleGroups({
|
|
70
|
+
samples: () => props.samples,
|
|
71
|
+
groups: internalGroups,
|
|
134
72
|
})
|
|
73
|
+
const hierarchicalGroups = sampleGroups.hierarchicalGroups
|
|
74
|
+
const showHierarchy = sampleGroups.showHierarchy
|
|
135
75
|
|
|
136
76
|
const groupingEnabled = computed(() => internalGroups.value.length > 0)
|
|
77
|
+
const ungroupedSamples = sampleGroups.ungroupedSamples
|
|
137
78
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return props.samples.filter(s => !groupedSamples.has(s))
|
|
79
|
+
const sampleSearch = useTextSearch({
|
|
80
|
+
items: () => props.samples,
|
|
81
|
+
query: searchQuery,
|
|
82
|
+
getText: sample => sample,
|
|
143
83
|
})
|
|
84
|
+
const filteredSamples = sampleSearch.filteredItems
|
|
144
85
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return props.samples.filter(s => s.toLowerCase().includes(query))
|
|
86
|
+
const sampleSelection = useListSelection({
|
|
87
|
+
selected: () => props.modelValue,
|
|
88
|
+
items: () => props.samples,
|
|
149
89
|
})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// Selection state
|
|
153
|
-
const isAllSelected = computed(() =>
|
|
154
|
-
props.samples.length > 0 && props.modelValue.length === props.samples.length
|
|
155
|
-
)
|
|
90
|
+
const isAllSelected = sampleSelection.isAllSelected
|
|
156
91
|
|
|
157
92
|
// Toggle functions
|
|
158
93
|
function toggleSelectAll() {
|
|
159
|
-
|
|
160
|
-
emit('update:modelValue', [])
|
|
161
|
-
} else {
|
|
162
|
-
emit('update:modelValue', [...props.samples])
|
|
163
|
-
}
|
|
94
|
+
emit('update:modelValue', sampleSelection.toggleAll())
|
|
164
95
|
}
|
|
165
96
|
|
|
166
97
|
function toggleSample(sample: string) {
|
|
167
|
-
|
|
168
|
-
? props.modelValue.filter(s => s !== sample)
|
|
169
|
-
: [...props.modelValue, sample]
|
|
170
|
-
emit('update:modelValue', newSelection)
|
|
98
|
+
emit('update:modelValue', sampleSelection.toggleValue(sample))
|
|
171
99
|
}
|
|
172
100
|
|
|
173
101
|
function toggleSamplesSelection(samples: string[]) {
|
|
174
|
-
|
|
175
|
-
const newSelection = allSelected
|
|
176
|
-
? props.modelValue.filter(s => !samples.includes(s))
|
|
177
|
-
: [...props.modelValue, ...samples.filter(s => !props.modelValue.includes(s))]
|
|
178
|
-
|
|
179
|
-
emit('update:modelValue', newSelection)
|
|
102
|
+
emit('update:modelValue', sampleSelection.toggleValues(samples))
|
|
180
103
|
}
|
|
181
104
|
|
|
182
105
|
function toggleGroupSamples(groupName: string) {
|
|
183
|
-
const group =
|
|
106
|
+
const group = sampleGroups.findGroup(groupName)
|
|
184
107
|
if (!group) return
|
|
185
108
|
toggleSamplesSelection(group.samples)
|
|
186
109
|
}
|
|
187
110
|
|
|
188
|
-
function toggleMajorGroupSamples(majorGroup:
|
|
111
|
+
function toggleMajorGroupSamples(majorGroup: SampleMajorGroup) {
|
|
189
112
|
toggleSamplesSelection(majorGroup.allSamples)
|
|
190
113
|
}
|
|
191
114
|
|
|
192
115
|
// Selection state checks
|
|
193
116
|
function isFullySelected(samples: string[]): boolean {
|
|
194
|
-
return
|
|
117
|
+
return sampleSelection.isFullySelected(samples)
|
|
195
118
|
}
|
|
196
119
|
|
|
197
120
|
function isPartiallySelected(samples: string[]): boolean {
|
|
198
|
-
|
|
199
|
-
const selectedCount = samples.filter(s => props.modelValue.includes(s)).length
|
|
200
|
-
return selectedCount > 0 && selectedCount < samples.length
|
|
121
|
+
return sampleSelection.isPartiallySelected(samples)
|
|
201
122
|
}
|
|
202
123
|
|
|
203
124
|
function isGroupFullySelected(groupName: string): boolean {
|
|
204
|
-
const group =
|
|
125
|
+
const group = sampleGroups.findGroup(groupName)
|
|
205
126
|
return group ? isFullySelected(group.samples) : false
|
|
206
127
|
}
|
|
207
128
|
|
|
208
129
|
function isGroupPartiallySelected(groupName: string): boolean {
|
|
209
|
-
const group =
|
|
130
|
+
const group = sampleGroups.findGroup(groupName)
|
|
210
131
|
return group ? isPartiallySelected(group.samples) : false
|
|
211
132
|
}
|
|
212
133
|
|
|
213
|
-
function isMajorGroupFullySelected(majorGroup:
|
|
134
|
+
function isMajorGroupFullySelected(majorGroup: SampleMajorGroup): boolean {
|
|
214
135
|
return isFullySelected(majorGroup.allSamples)
|
|
215
136
|
}
|
|
216
137
|
|
|
217
|
-
function isMajorGroupPartiallySelected(majorGroup:
|
|
138
|
+
function isMajorGroupPartiallySelected(majorGroup: SampleMajorGroup): boolean {
|
|
218
139
|
return isPartiallySelected(majorGroup.allSamples)
|
|
219
140
|
}
|
|
220
141
|
|
|
221
142
|
// Expand/collapse
|
|
222
143
|
function toggleGroupExpanded(groupName: string) {
|
|
223
|
-
|
|
144
|
+
groupExpansion.toggle(groupName)
|
|
224
145
|
}
|
|
225
146
|
|
|
226
147
|
function isGroupExpanded(groupName: string): boolean {
|
|
227
|
-
return
|
|
148
|
+
return groupExpansion.isExpanded(groupName)
|
|
228
149
|
}
|
|
229
150
|
|
|
230
151
|
function expandAllGroups() {
|
|
231
|
-
const expanded:
|
|
152
|
+
const expanded: string[] = []
|
|
232
153
|
for (const major of hierarchicalGroups.value) {
|
|
233
|
-
expanded
|
|
154
|
+
expanded.push(`major:${major.name}`)
|
|
234
155
|
for (const sub of major.subGroups) {
|
|
235
|
-
expanded
|
|
156
|
+
expanded.push(sub.name)
|
|
236
157
|
}
|
|
237
158
|
}
|
|
238
|
-
expanded
|
|
239
|
-
|
|
159
|
+
expanded.push('__ungrouped__')
|
|
160
|
+
groupExpansion.setExpanded(expanded)
|
|
240
161
|
}
|
|
241
162
|
|
|
242
163
|
function collapseAllGroups() {
|
|
243
|
-
|
|
164
|
+
groupExpansion.collapseAll()
|
|
244
165
|
}
|
|
245
166
|
|
|
246
167
|
// Smart group
|
|
@@ -254,7 +175,7 @@ function clearGroups() {
|
|
|
254
175
|
internalGroups.value = []
|
|
255
176
|
}
|
|
256
177
|
|
|
257
|
-
function deleteMajorGroup(majorGroup:
|
|
178
|
+
function deleteMajorGroup(majorGroup: SampleMajorGroup) {
|
|
258
179
|
internalGroups.value = internalGroups.value.filter(
|
|
259
180
|
g => !majorGroup.subGroups.some(sg => sg.name === g.name)
|
|
260
181
|
)
|
|
@@ -452,7 +373,7 @@ function openColorPicker(groupName: string, event: Event) {
|
|
|
452
373
|
colorPickerInput.value?.click()
|
|
453
374
|
}
|
|
454
375
|
|
|
455
|
-
function openMajorGroupColorPicker(majorGroup:
|
|
376
|
+
function openMajorGroupColorPicker(majorGroup: SampleMajorGroup, event: Event) {
|
|
456
377
|
event.stopPropagation()
|
|
457
378
|
editingColor.value = { kind: 'family', names: majorGroup.subGroups.map(sg => sg.name) }
|
|
458
379
|
colorPickerInput.value?.click()
|
|
@@ -473,8 +394,7 @@ function handleColorChange(event: Event) {
|
|
|
473
394
|
}
|
|
474
395
|
|
|
475
396
|
function getGroupColor(groupName: string): string {
|
|
476
|
-
|
|
477
|
-
return group?.color || '#3B82F6'
|
|
397
|
+
return sampleGroups.getGroupColor(groupName)
|
|
478
398
|
}
|
|
479
399
|
|
|
480
400
|
const colorPickerSeed = computed(() => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Renders a segmented button group for single-option selection, with simple or solid variants. */
|
|
3
|
-
import
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import type { SegmentedOption, SegmentedOptionInput, SegmentedControlVariant, SegmentedControlSize } from '../types'
|
|
5
|
+
import { normalizeOptionInput } from '../utils/options'
|
|
4
6
|
|
|
5
7
|
interface Props {
|
|
6
8
|
modelValue: string | number
|
|
7
|
-
options:
|
|
9
|
+
options: SegmentedOptionInput[]
|
|
8
10
|
variant?: SegmentedControlVariant
|
|
9
11
|
size?: SegmentedControlSize
|
|
10
12
|
fullWidth?: boolean
|
|
@@ -22,6 +24,8 @@ const emit = defineEmits<{
|
|
|
22
24
|
'update:modelValue': [value: string | number]
|
|
23
25
|
}>()
|
|
24
26
|
|
|
27
|
+
const normalizedOptions = computed<SegmentedOption[]>(() => props.options.map(normalizeOptionInput))
|
|
28
|
+
|
|
25
29
|
function handleSelect(option: SegmentedOption) {
|
|
26
30
|
if (props.disabled || option.disabled) return
|
|
27
31
|
emit('update:modelValue', option.value)
|
|
@@ -47,7 +51,7 @@ function handleKeydown(event: KeyboardEvent, option: SegmentedOption) {
|
|
|
47
51
|
role="radiogroup"
|
|
48
52
|
>
|
|
49
53
|
<button
|
|
50
|
-
v-for="option in
|
|
54
|
+
v-for="option in normalizedOptions"
|
|
51
55
|
:key="String(option.value)"
|
|
52
56
|
type="button"
|
|
53
57
|
role="radio"
|
|
@@ -5,7 +5,7 @@ const sizes: ('sm' | 'md' | 'lg')[] = ['sm', 'md', 'lg']
|
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
7
|
<template>
|
|
8
|
-
<Story title="Action/SettingsButton">
|
|
8
|
+
<Story title="Action/Deprecated/SettingsButton">
|
|
9
9
|
<Variant title="Playground">
|
|
10
10
|
<template #default="{ state }">
|
|
11
11
|
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
import {
|
|
2
|
+
/** @deprecated Use AppTopBar settingsConfig or SettingsModal instead. */
|
|
3
|
+
import { useDropdownState } from '../composables/useDropdownState'
|
|
4
|
+
import IconButton from './IconButton.vue'
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
size?: 'sm' | 'md' | 'lg'
|
|
@@ -14,41 +15,28 @@ const emit = defineEmits<{
|
|
|
14
15
|
click: [event: MouseEvent]
|
|
15
16
|
}>()
|
|
16
17
|
|
|
17
|
-
const isOpen =
|
|
18
|
-
|
|
18
|
+
const { isOpen, rootRef, toggle: toggleDropdown } = useDropdownState({
|
|
19
|
+
closeOnEscape: false,
|
|
20
|
+
})
|
|
19
21
|
|
|
20
22
|
function toggle(event: MouseEvent) {
|
|
21
|
-
|
|
23
|
+
toggleDropdown()
|
|
22
24
|
emit('click', event)
|
|
23
25
|
}
|
|
24
|
-
|
|
25
|
-
function handleClickOutside(event: MouseEvent) {
|
|
26
|
-
const target = event.target as Node
|
|
27
|
-
if (dropdownRef.value && !dropdownRef.value.contains(target)) {
|
|
28
|
-
isOpen.value = false
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
onMounted(() => {
|
|
33
|
-
document.addEventListener('click', handleClickOutside)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
onUnmounted(() => {
|
|
37
|
-
document.removeEventListener('click', handleClickOutside)
|
|
38
|
-
})
|
|
39
26
|
</script>
|
|
40
27
|
|
|
41
28
|
<template>
|
|
42
|
-
<div ref="
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
<div ref="rootRef" class="mint-settings-button">
|
|
30
|
+
<IconButton
|
|
31
|
+
class="mint-settings-button__trigger"
|
|
32
|
+
label="Settings"
|
|
33
|
+
variant="ghost"
|
|
34
|
+
:size="size"
|
|
47
35
|
@click.stop="toggle"
|
|
48
36
|
>
|
|
49
37
|
<!-- Settings/Gear icon -->
|
|
50
38
|
<svg
|
|
51
|
-
|
|
39
|
+
class="mint-settings-button__icon"
|
|
52
40
|
viewBox="0 0 24 24"
|
|
53
41
|
fill="none"
|
|
54
42
|
stroke="currentColor"
|
|
@@ -58,7 +46,7 @@ onUnmounted(() => {
|
|
|
58
46
|
>
|
|
59
47
|
<path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /><circle cx="12" cy="12" r="3" />
|
|
60
48
|
</svg>
|
|
61
|
-
</
|
|
49
|
+
</IconButton>
|
|
62
50
|
|
|
63
51
|
<!-- Dropdown panel -->
|
|
64
52
|
<div v-show="isOpen" class="mint-settings-dropdown">
|