@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
package/src/types/components.ts
CHANGED
|
@@ -34,7 +34,11 @@ export interface TabItem {
|
|
|
34
34
|
badge?: string | number
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export type TabItemInput = TabItem | string
|
|
38
|
+
|
|
37
39
|
// Select types
|
|
40
|
+
export type OptionPrimitive = string | number
|
|
41
|
+
|
|
38
42
|
export interface SelectOption<T = string> {
|
|
39
43
|
value: T
|
|
40
44
|
label: string
|
|
@@ -42,6 +46,8 @@ export interface SelectOption<T = string> {
|
|
|
42
46
|
description?: string
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
export type SelectOptionInput<T extends OptionPrimitive = OptionPrimitive> = SelectOption<T> | T
|
|
50
|
+
|
|
45
51
|
// Radio types
|
|
46
52
|
export interface RadioOption {
|
|
47
53
|
value: string | number
|
|
@@ -50,6 +56,8 @@ export interface RadioOption {
|
|
|
50
56
|
description?: string
|
|
51
57
|
}
|
|
52
58
|
|
|
59
|
+
export type RadioOptionInput = RadioOption | OptionPrimitive
|
|
60
|
+
|
|
53
61
|
// Form field types
|
|
54
62
|
export interface FormFieldProps {
|
|
55
63
|
label?: string
|
|
@@ -92,6 +100,8 @@ export interface TopBarPage {
|
|
|
92
100
|
disabled?: boolean
|
|
93
101
|
}
|
|
94
102
|
|
|
103
|
+
export type TopBarPageInput = TopBarPage | string
|
|
104
|
+
|
|
95
105
|
// TopBar tab types (displayed in middle of topbar)
|
|
96
106
|
export interface TopBarTab {
|
|
97
107
|
id: string
|
|
@@ -112,23 +122,47 @@ export interface TopBarTabOption {
|
|
|
112
122
|
disabled?: boolean
|
|
113
123
|
}
|
|
114
124
|
|
|
125
|
+
export type TopBarTabOptionInput = TopBarTabOption | string
|
|
126
|
+
|
|
127
|
+
export type TopBarTabInput = (Omit<TopBarTab, 'children'> & {
|
|
128
|
+
children?: TopBarTabOptionInput[]
|
|
129
|
+
}) | string
|
|
130
|
+
|
|
115
131
|
// TopBar settings config (pass-through for built-in SettingsModal)
|
|
116
132
|
export interface TopBarSettingsConfig {
|
|
117
133
|
title?: string
|
|
118
|
-
tabs?:
|
|
134
|
+
tabs?: SettingsTabInput[]
|
|
119
135
|
showAppearance?: boolean
|
|
120
136
|
size?: 'md' | 'lg' | 'xl'
|
|
137
|
+
layout?: SettingsModalLayout
|
|
138
|
+
/** Schema-driven config — when set, fields auto-render via SDK form components. */
|
|
139
|
+
schema?: SettingsModalSchema
|
|
140
|
+
/** Model returned by defineControlModel(), or a raw nested ControlModel for one-step settings generation. */
|
|
141
|
+
model?:
|
|
142
|
+
| import('../composables/useControlSchema').ControlModel
|
|
143
|
+
| import('../composables/useControlSchema').ControlModelBinding
|
|
144
|
+
/** Compact controls model — converted to `schema` when `schema` is not set. */
|
|
145
|
+
controls?: import('../composables/useControlSchema').ControlSchema
|
|
146
|
+
/** Conversion options for `controls`, such as section labels and columns. */
|
|
147
|
+
controlOptions?: import('../composables/useControlSchema').ControlSchemaOptions
|
|
148
|
+
/** Initial values when using `schema`, `model`, or `controls`. AppTopBar emits `settings-values-change` on change. */
|
|
149
|
+
values?: Record<string, unknown>
|
|
150
|
+
/** Dynamic enhancements (validators, dynamic options, callbacks). Forwarded to SettingsModal. */
|
|
151
|
+
enhancements?: import('./form-builder').FormEnhancements
|
|
121
152
|
}
|
|
122
153
|
|
|
123
154
|
// TopBar pill-nav items (centered top-level navigation)
|
|
124
155
|
export interface PillNavItem {
|
|
125
156
|
id: string
|
|
126
157
|
label: string
|
|
158
|
+
icon?: string | string[]
|
|
127
159
|
to?: string
|
|
128
160
|
href?: string
|
|
129
161
|
disabled?: boolean
|
|
130
162
|
}
|
|
131
163
|
|
|
164
|
+
export type PillNavItemInput = PillNavItem | string
|
|
165
|
+
|
|
132
166
|
// TopBar page selector items (left-side "go to page" dropdown)
|
|
133
167
|
export interface PageSelectorItem {
|
|
134
168
|
id: string
|
|
@@ -140,6 +174,8 @@ export interface PageSelectorItem {
|
|
|
140
174
|
disabled?: boolean
|
|
141
175
|
}
|
|
142
176
|
|
|
177
|
+
export type PageSelectorItemInput = PageSelectorItem | string
|
|
178
|
+
|
|
143
179
|
// TopBar plugin switcher info
|
|
144
180
|
export interface PluginSwitcherPlugin {
|
|
145
181
|
id: string
|
|
@@ -378,6 +414,8 @@ export interface SegmentedOption {
|
|
|
378
414
|
disabled?: boolean
|
|
379
415
|
}
|
|
380
416
|
|
|
417
|
+
export type SegmentedOptionInput = SegmentedOption | OptionPrimitive
|
|
418
|
+
|
|
381
419
|
export type SegmentedControlVariant = 'simple' | 'card'
|
|
382
420
|
export type SegmentedControlSize = 'sm' | 'md' | 'lg'
|
|
383
421
|
|
|
@@ -388,6 +426,8 @@ export interface MultiSelectOption {
|
|
|
388
426
|
disabled?: boolean
|
|
389
427
|
}
|
|
390
428
|
|
|
429
|
+
export type MultiSelectOptionInput = MultiSelectOption | OptionPrimitive
|
|
430
|
+
|
|
391
431
|
export type MultiSelectSize = 'sm' | 'md' | 'lg'
|
|
392
432
|
|
|
393
433
|
// Pill types
|
|
@@ -507,6 +547,8 @@ export interface BreadcrumbItem {
|
|
|
507
547
|
href?: string
|
|
508
548
|
}
|
|
509
549
|
|
|
550
|
+
export type BreadcrumbItemInput = BreadcrumbItem | string
|
|
551
|
+
|
|
510
552
|
// Tooltip types
|
|
511
553
|
export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right'
|
|
512
554
|
|
|
@@ -517,7 +559,44 @@ export type ConfirmVariant = 'danger' | 'warning' | 'info'
|
|
|
517
559
|
export interface SettingsTab {
|
|
518
560
|
id: string
|
|
519
561
|
label: string
|
|
562
|
+
/**
|
|
563
|
+
* Inline SVG markup rendered with `v-html` in the vertical layout's rail.
|
|
564
|
+
* Must be trusted, plugin-author-controlled markup — never user-supplied data.
|
|
565
|
+
*/
|
|
566
|
+
icon?: string
|
|
567
|
+
/** Optional one-line hint shown under the label (vertical layout) and as a section subtitle in the right pane. */
|
|
568
|
+
description?: string
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export type SettingsTabInput = SettingsTab | string
|
|
572
|
+
|
|
573
|
+
export type SettingsModalLayout = 'horizontal' | 'vertical'
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Declarative settings group — becomes both a tab and a generated form section.
|
|
577
|
+
* Plugin authors describe their parameters once and the modal auto-renders
|
|
578
|
+
* SDK form components (BaseInput / BaseSelect / NumberInput / Toggle / …)
|
|
579
|
+
* via the same registry that powers FormBuilder.
|
|
580
|
+
*/
|
|
581
|
+
export interface SettingsGroup {
|
|
582
|
+
id: string
|
|
583
|
+
label: string
|
|
584
|
+
description?: string
|
|
585
|
+
/**
|
|
586
|
+
* Inline SVG markup rendered with `v-html` in the vertical layout's rail.
|
|
587
|
+
* Must be trusted, plugin-author-controlled markup — never user-supplied data.
|
|
588
|
+
*/
|
|
520
589
|
icon?: string
|
|
590
|
+
/** SDK form-builder field schemas. */
|
|
591
|
+
fields: import('./form-builder').FormFieldSchema[]
|
|
592
|
+
/** Grid columns for the rendered fields (1-3). Defaults to 1. */
|
|
593
|
+
columns?: 1 | 2 | 3
|
|
594
|
+
/** Hide the entire group (rail item + content) when this evaluates false against the form data. */
|
|
595
|
+
condition?: import('./form-builder').FieldCondition
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export interface SettingsModalSchema {
|
|
599
|
+
groups: SettingsGroup[]
|
|
521
600
|
}
|
|
522
601
|
|
|
523
602
|
// ScientificNumber types
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FieldRules } from '../composables/useForm'
|
|
2
|
+
import type { OptionPrimitive, SelectOption } from './components'
|
|
2
3
|
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
4
5
|
// Field types
|
|
@@ -88,6 +89,8 @@ export interface FormFieldSchema {
|
|
|
88
89
|
props?: Record<string, unknown>
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
export type FormOptionInput = SelectOption<unknown> | OptionPrimitive
|
|
93
|
+
|
|
91
94
|
// ---------------------------------------------------------------------------
|
|
92
95
|
// Section schema
|
|
93
96
|
// ---------------------------------------------------------------------------
|
|
@@ -147,7 +150,7 @@ export interface FieldEnhancement<T extends Record<string, unknown> = Record<str
|
|
|
147
150
|
/** Dynamic visibility (overrides schema condition if both present). */
|
|
148
151
|
visible?: (data: T) => boolean
|
|
149
152
|
/** Dynamic options for select/multiselect/radio fields. */
|
|
150
|
-
options?: (data: T) =>
|
|
153
|
+
options?: (data: T) => FormOptionInput[]
|
|
151
154
|
/** Dynamic extra props merged into the component. */
|
|
152
155
|
props?: (data: T) => Record<string, unknown>
|
|
153
156
|
}
|
|
@@ -181,7 +184,7 @@ export interface UseFormBuilderReturn<T extends Record<string, unknown>> {
|
|
|
181
184
|
/** Resolve final component props for a field. */
|
|
182
185
|
getResolvedFieldProps: (field: FormFieldSchema) => Record<string, unknown>
|
|
183
186
|
/** Get options for a select/radio/multiselect field. */
|
|
184
|
-
getFieldOptions: (name: string) =>
|
|
187
|
+
getFieldOptions: (name: string) => FormOptionInput[] | undefined
|
|
185
188
|
|
|
186
189
|
// Wizard-specific
|
|
187
190
|
currentStep: import('vue').Ref<number>
|
|
@@ -194,4 +197,6 @@ export interface UseFormBuilderReturn<T extends Record<string, unknown>> {
|
|
|
194
197
|
validate: () => boolean
|
|
195
198
|
reset: (values?: Partial<T>) => void
|
|
196
199
|
submit: () => Promise<void>
|
|
200
|
+
/** Replace the active schema and rebuild field state for still-mounted forms. */
|
|
201
|
+
updateSchema: (schema: FormSchema, values?: Partial<T>) => void
|
|
197
202
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -9,18 +9,27 @@ export type {
|
|
|
9
9
|
AlertType,
|
|
10
10
|
Toast,
|
|
11
11
|
TabItem,
|
|
12
|
+
TabItemInput,
|
|
13
|
+
OptionPrimitive,
|
|
12
14
|
SelectOption,
|
|
15
|
+
SelectOptionInput,
|
|
13
16
|
RadioOption,
|
|
17
|
+
RadioOptionInput,
|
|
14
18
|
FormFieldProps,
|
|
15
19
|
SidebarToolSection,
|
|
16
20
|
CollapsibleState,
|
|
17
21
|
TopBarVariant,
|
|
18
22
|
TopBarPage,
|
|
23
|
+
TopBarPageInput,
|
|
19
24
|
TopBarTab,
|
|
25
|
+
TopBarTabInput,
|
|
20
26
|
TopBarTabOption,
|
|
27
|
+
TopBarTabOptionInput,
|
|
21
28
|
TopBarSettingsConfig,
|
|
22
29
|
PillNavItem,
|
|
30
|
+
PillNavItemInput,
|
|
23
31
|
PageSelectorItem,
|
|
32
|
+
PageSelectorItemInput,
|
|
24
33
|
PluginSwitcherPlugin,
|
|
25
34
|
PluginSwitcherInfo,
|
|
26
35
|
AccountMenuItem,
|
|
@@ -58,10 +67,12 @@ export type {
|
|
|
58
67
|
FileUploaderMode,
|
|
59
68
|
// SegmentedControl types
|
|
60
69
|
SegmentedOption,
|
|
70
|
+
SegmentedOptionInput,
|
|
61
71
|
SegmentedControlVariant,
|
|
62
72
|
SegmentedControlSize,
|
|
63
73
|
// MultiSelect types
|
|
64
74
|
MultiSelectOption,
|
|
75
|
+
MultiSelectOptionInput,
|
|
65
76
|
MultiSelectSize,
|
|
66
77
|
// Pill types
|
|
67
78
|
PillVariant,
|
|
@@ -93,12 +104,17 @@ export type {
|
|
|
93
104
|
EmptyStateSize,
|
|
94
105
|
// Breadcrumb types
|
|
95
106
|
BreadcrumbItem,
|
|
107
|
+
BreadcrumbItemInput,
|
|
96
108
|
// Tooltip types
|
|
97
109
|
TooltipPosition,
|
|
98
110
|
// ConfirmDialog types
|
|
99
111
|
ConfirmVariant,
|
|
100
112
|
// SettingsModal types
|
|
101
113
|
SettingsTab,
|
|
114
|
+
SettingsTabInput,
|
|
115
|
+
SettingsModalLayout,
|
|
116
|
+
SettingsGroup,
|
|
117
|
+
SettingsModalSchema,
|
|
102
118
|
// ScientificNumber types
|
|
103
119
|
NumberNotation,
|
|
104
120
|
// UnitInput types
|
|
@@ -160,6 +176,7 @@ export type {
|
|
|
160
176
|
FieldCondition,
|
|
161
177
|
FieldValidation,
|
|
162
178
|
FormFieldSchema,
|
|
179
|
+
FormOptionInput,
|
|
163
180
|
FormSectionSchema,
|
|
164
181
|
FormStepSchema,
|
|
165
182
|
FormSchema,
|
package/src/types/platform.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface PluginInfo {
|
|
|
5
5
|
version: string
|
|
6
6
|
description?: string
|
|
7
7
|
icon?: string
|
|
8
|
+
color?: string
|
|
8
9
|
route_prefix: string
|
|
9
10
|
api_prefix: string
|
|
10
11
|
nav_items?: PluginNavItem[]
|
|
@@ -13,10 +14,14 @@ export interface PluginInfo {
|
|
|
13
14
|
|
|
14
15
|
// Plugin navigation item
|
|
15
16
|
export interface PluginNavItem {
|
|
16
|
-
id
|
|
17
|
+
id?: string
|
|
17
18
|
label: string
|
|
18
19
|
path: string
|
|
19
20
|
icon?: string
|
|
21
|
+
description?: string
|
|
22
|
+
requiresAuth?: boolean
|
|
23
|
+
requiresAdmin?: boolean
|
|
24
|
+
requiresFeature?: string
|
|
20
25
|
children?: PluginNavItem[]
|
|
21
26
|
}
|
|
22
27
|
|
|
@@ -81,7 +86,9 @@ export interface PlatformContext {
|
|
|
81
86
|
|
|
82
87
|
// Features enabled in platform
|
|
83
88
|
features?: {
|
|
89
|
+
admin?: boolean
|
|
84
90
|
experiments?: boolean
|
|
91
|
+
samples?: boolean
|
|
85
92
|
passkey?: boolean
|
|
86
93
|
multiUser?: boolean
|
|
87
94
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { FormSchema } from '../types/form-builder'
|
|
2
|
+
|
|
3
|
+
export function recordValuesEqualForKeys(
|
|
4
|
+
left: Record<string, unknown>,
|
|
5
|
+
right: Record<string, unknown>,
|
|
6
|
+
keys: readonly string[],
|
|
7
|
+
): boolean {
|
|
8
|
+
for (const key of keys) {
|
|
9
|
+
if (!valuesEqual(left[key], right[key])) return false
|
|
10
|
+
}
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function pickRecordKeys(
|
|
15
|
+
source: Record<string, unknown>,
|
|
16
|
+
keys: readonly string[],
|
|
17
|
+
): Record<string, unknown> {
|
|
18
|
+
return Object.fromEntries(keys.map(key => [key, source[key]]))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function pickExistingRecordKeys(
|
|
22
|
+
source: Record<string, unknown>,
|
|
23
|
+
keys: readonly string[],
|
|
24
|
+
): Record<string, unknown> {
|
|
25
|
+
return Object.fromEntries(
|
|
26
|
+
keys
|
|
27
|
+
.filter(key => Object.prototype.hasOwnProperty.call(source, key))
|
|
28
|
+
.map(key => [key, source[key]]),
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formSchemaFieldNames(schema: FormSchema): string[] {
|
|
33
|
+
const sections = schema.steps
|
|
34
|
+
? schema.steps.flatMap(step => step.sections)
|
|
35
|
+
: schema.sections
|
|
36
|
+
return sections.flatMap(section => section.fields.map(field => field.name))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function valuesEqual(left: unknown, right: unknown): boolean {
|
|
40
|
+
if (Object.is(left, right)) return true
|
|
41
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
42
|
+
return left.length === right.length && left.every((item, index) => valuesEqual(item, right[index]))
|
|
43
|
+
}
|
|
44
|
+
if (isRecord(left) && isRecord(right)) {
|
|
45
|
+
return recordValuesEqualForKeys(left, right, [...new Set([...Object.keys(left), ...Object.keys(right)])])
|
|
46
|
+
}
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
51
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
52
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type ItemWithLabel = {
|
|
2
|
+
label: string
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type ItemWithId = ItemWithLabel & {
|
|
6
|
+
id: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function normalizeItemInput<TItem extends ItemWithId>(
|
|
10
|
+
item: TItem | string,
|
|
11
|
+
): TItem {
|
|
12
|
+
if (typeof item === 'object') return item
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
id: item,
|
|
16
|
+
label: item,
|
|
17
|
+
} as TItem
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function normalizeLabelItemInput<TItem extends ItemWithLabel>(
|
|
21
|
+
item: TItem | string,
|
|
22
|
+
): TItem {
|
|
23
|
+
if (typeof item === 'object') return item
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
label: item,
|
|
27
|
+
} as TItem
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type OptionLike<TValue extends string | number> = {
|
|
2
|
+
value: TValue
|
|
3
|
+
label: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function normalizeOptionInput<
|
|
7
|
+
TValue extends string | number,
|
|
8
|
+
TOption extends OptionLike<TValue>,
|
|
9
|
+
>(option: TOption | TValue): TOption {
|
|
10
|
+
if (typeof option === 'object') return option
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
value: option,
|
|
14
|
+
label: String(option),
|
|
15
|
+
} as TOption
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function findOptionByDomValue<
|
|
19
|
+
TValue extends string | number,
|
|
20
|
+
TOption extends OptionLike<TValue>,
|
|
21
|
+
>(options: TOption[], value: string): TOption | undefined {
|
|
22
|
+
return options.find(option => String(option.value) === value)
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type PluginIconFormat = 'path' | 'data-url' | 'https-url' | 'fallback'
|
|
2
|
+
|
|
3
|
+
export interface DetectedPluginIcon {
|
|
4
|
+
format: PluginIconFormat
|
|
5
|
+
value: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// MINT canonical plugin placeholder — page-with-corner-fold glyph.
|
|
9
|
+
export const PLUGIN_ICON_FALLBACK_PATH = 'M14 7v4a1 1 0 0 0 1 1h4M5 3h9l5 5v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z'
|
|
10
|
+
|
|
11
|
+
const PATH_REGEX = /^[Mm][\s,\d\-.]/
|
|
12
|
+
const RASTER_DATA_URL_REGEX = /^data:image\/(png|jpeg|jpg|gif|webp);/
|
|
13
|
+
|
|
14
|
+
export function normalizePluginIconSource(icon?: string): string {
|
|
15
|
+
return (icon ?? '').replace(/^[\s]+/, '')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function detectPluginIcon(icon?: string): DetectedPluginIcon {
|
|
19
|
+
const raw = normalizePluginIconSource(icon)
|
|
20
|
+
if (!raw) return { format: 'fallback', value: PLUGIN_ICON_FALLBACK_PATH }
|
|
21
|
+
if (PATH_REGEX.test(raw)) return { format: 'path', value: raw }
|
|
22
|
+
if (RASTER_DATA_URL_REGEX.test(raw)) return { format: 'data-url', value: raw }
|
|
23
|
+
if (raw.startsWith('https://')) return { format: 'https-url', value: raw }
|
|
24
|
+
return { format: 'fallback', value: PLUGIN_ICON_FALLBACK_PATH }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isPluginIconFormat(icon?: string): boolean {
|
|
28
|
+
const raw = normalizePluginIconSource(icon)
|
|
29
|
+
return !!raw && detectPluginIcon(raw).format !== 'fallback'
|
|
30
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth-DsI0rQ7_.js","names":[],"sources":["../src/stores/settings.ts","../src/stores/auth.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport { ref, watch } from 'vue'\nimport type { ThemeMode, ColorPalette, TableDensity } from '../types'\n\ndeclare global {\n interface ImportMetaEnv {\n readonly VITE_API_PREFIX?: string\n }\n\n interface ImportMeta {\n readonly env: ImportMetaEnv\n }\n}\n\nexport interface SettingsState {\n serverHost: string\n serverPort: number\n requestTimeout: number\n wsAutoReconnect: boolean\n wsReconnectInterval: number\n theme: ThemeMode\n colorPalette: ColorPalette\n tableDensity: TableDensity\n}\n\nconst STORAGE_KEY = 'mint-settings'\n\nfunction getDefaultServerHost(): string {\n if (typeof window !== 'undefined' && window.location.hostname !== 'localhost') {\n return window.location.hostname\n }\n return 'localhost'\n}\n\nfunction getDefaultServerPort(): number {\n if (typeof window !== 'undefined') {\n if (window.location.port) {\n return parseInt(window.location.port, 10)\n }\n // Standard ports: 443 for HTTPS, 80 for HTTP (browser omits from location.port)\n return window.location.protocol === 'https:' ? 443 : 80\n }\n return 8000\n}\n\nconst defaultSettings: SettingsState = {\n serverHost: getDefaultServerHost(),\n serverPort: getDefaultServerPort(),\n requestTimeout: 120000,\n wsAutoReconnect: true,\n wsReconnectInterval: 5000,\n theme: 'system',\n colorPalette: 'default',\n tableDensity: 'normal',\n}\n\nexport const colorPalettes: Record<ColorPalette, { name: string; hues: [number, number] }> = {\n default: { name: 'Default (Cyan-Pink)', hues: [180, 320] },\n colorblind: { name: 'Colorblind-friendly', hues: [45, 260] },\n viridis: { name: 'Viridis', hues: [280, 80] },\n pastel: { name: 'Pastel', hues: [200, 340] },\n}\n\nfunction loadSettings(): SettingsState {\n try {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) {\n const parsed = JSON.parse(stored)\n return { ...defaultSettings, ...parsed }\n }\n } catch (e) {\n console.warn('Failed to load settings from localStorage:', e)\n }\n return { ...defaultSettings }\n}\n\nfunction saveSettings(settings: SettingsState): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))\n } catch (e) {\n console.warn('Failed to save settings to localStorage:', e)\n }\n}\n\nexport const useSettingsStore = defineStore('mint-settings', () => {\n // State\n const serverHost = ref(defaultSettings.serverHost)\n const serverPort = ref(defaultSettings.serverPort)\n const requestTimeout = ref(defaultSettings.requestTimeout)\n const wsAutoReconnect = ref(defaultSettings.wsAutoReconnect)\n const wsReconnectInterval = ref(defaultSettings.wsReconnectInterval)\n const theme = ref<ThemeMode>(defaultSettings.theme)\n const colorPalette = ref<ColorPalette>(defaultSettings.colorPalette)\n const tableDensity = ref<TableDensity>(defaultSettings.tableDensity)\n\n // API prefix - can be configured via env variable VITE_API_PREFIX\n const apiPrefix: string = (import.meta.env?.VITE_API_PREFIX as string | undefined) ?? '/api'\n\n function _isSameOrigin(): { same: boolean; currentHost: string; currentPort: string } {\n const currentHost = typeof window !== 'undefined' ? window.location.hostname : 'localhost'\n const currentPort = typeof window !== 'undefined' ? window.location.port : '8000'\n const effectivePort = currentPort || (window.location.protocol === 'https:' ? '443' : '80')\n const same =\n (serverHost.value === currentHost && String(serverPort.value) === effectivePort) ||\n (serverHost.value === 'localhost' && currentHost !== 'localhost')\n return { same, currentHost, currentPort }\n }\n\n function getApiBaseUrl(): string {\n const { same } = _isSameOrigin()\n if (same) return apiPrefix\n return `http://${serverHost.value}:${serverPort.value}${apiPrefix}`\n }\n\n function getWsBaseUrl(): string {\n const { same, currentHost, currentPort } = _isSameOrigin()\n const protocol = typeof window !== 'undefined' && window.location.protocol === 'https:' ? 'wss:' : 'ws:'\n if (same) return `${protocol}//${currentHost}${currentPort ? ':' + currentPort : ''}${apiPrefix}`\n return `ws://${serverHost.value}:${serverPort.value}${apiPrefix}`\n }\n\n let _initialized = false\n\n function initialize() {\n if (_initialized) return\n _initialized = true\n\n const loaded = loadSettings()\n serverHost.value = loaded.serverHost\n serverPort.value = loaded.serverPort\n requestTimeout.value = loaded.requestTimeout\n wsAutoReconnect.value = loaded.wsAutoReconnect\n wsReconnectInterval.value = loaded.wsReconnectInterval\n theme.value = loaded.theme\n colorPalette.value = loaded.colorPalette\n tableDensity.value = loaded.tableDensity\n\n applyTheme()\n }\n\n function applyTheme() {\n const dark = theme.value === 'system'\n ? window.matchMedia('(prefers-color-scheme: dark)').matches\n : theme.value === 'dark'\n document.documentElement.classList.toggle('dark', dark)\n }\n\n watch(theme, () => {\n applyTheme()\n persistSettings()\n })\n\n if (typeof window !== 'undefined') {\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {\n if (theme.value === 'system') {\n applyTheme()\n }\n })\n }\n\n function persistSettings() {\n saveSettings({\n serverHost: serverHost.value,\n serverPort: serverPort.value,\n requestTimeout: requestTimeout.value,\n wsAutoReconnect: wsAutoReconnect.value,\n wsReconnectInterval: wsReconnectInterval.value,\n theme: theme.value,\n colorPalette: colorPalette.value,\n tableDensity: tableDensity.value,\n })\n }\n\n watch([serverHost, serverPort, requestTimeout, wsAutoReconnect, wsReconnectInterval, colorPalette, tableDensity], () => {\n persistSettings()\n })\n\n function resetToDefaults() {\n serverHost.value = defaultSettings.serverHost\n serverPort.value = defaultSettings.serverPort\n requestTimeout.value = defaultSettings.requestTimeout\n wsAutoReconnect.value = defaultSettings.wsAutoReconnect\n wsReconnectInterval.value = defaultSettings.wsReconnectInterval\n theme.value = defaultSettings.theme\n colorPalette.value = defaultSettings.colorPalette\n tableDensity.value = defaultSettings.tableDensity\n }\n\n function getPaletteHues(): [number, number] {\n return colorPalettes[colorPalette.value].hues\n }\n\n function isDark(): boolean {\n if (theme.value === 'system') {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n }\n return theme.value === 'dark'\n }\n\n return {\n serverHost,\n serverPort,\n requestTimeout,\n wsAutoReconnect,\n wsReconnectInterval,\n theme,\n colorPalette,\n tableDensity,\n initialize,\n applyTheme,\n persistSettings,\n resetToDefaults,\n getPaletteHues,\n isDark,\n getApiBaseUrl,\n getWsBaseUrl,\n }\n})\n","import { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { AuthConfig, UserInfo } from '../types'\n\nconst AUTH_TOKEN_KEY = 'mint-auth-token'\nconst AUTH_EXPIRES_KEY = 'mint-auth-expires'\n\nconst hasLocalStorage = typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function'\n\nexport const useAuthStore = defineStore('mint-auth', () => {\n // State\n const token = ref<string | null>(null)\n const tokenExpires = ref<Date | null>(null)\n const username = ref<string | null>(null)\n const userInfo = ref<UserInfo | null>(null)\n const authConfig = ref<AuthConfig>({\n authRequired: true,\n passkeyEnabled: false,\n passkeyRegistered: false,\n registrationEnabled: false,\n databaseMode: 'none',\n })\n const isInitialized = ref(false)\n const isLoading = ref(false)\n const error = ref<string | null>(null)\n\n // Computed\n const isAuthenticated = computed(() => {\n if (!authConfig.value.authRequired) {\n return true\n }\n if (!token.value) {\n return false\n }\n if (tokenExpires.value && tokenExpires.value < new Date()) {\n return false\n }\n return true\n })\n\n const needsAuth = computed(() => {\n return authConfig.value.authRequired && !isAuthenticated.value\n })\n\n const isAdmin = computed(() => {\n return userInfo.value?.role === 'admin'\n })\n\n const canRegister = computed(() => {\n return authConfig.value.registrationEnabled\n })\n\n // Actions\n function initialize() {\n if (hasLocalStorage) {\n const storedToken = localStorage.getItem(AUTH_TOKEN_KEY)\n const storedExpires = localStorage.getItem(AUTH_EXPIRES_KEY)\n\n if (storedToken) {\n token.value = storedToken\n\n if (storedExpires) {\n const expires = new Date(storedExpires)\n if (expires > new Date()) {\n tokenExpires.value = expires\n } else {\n clearToken()\n }\n }\n }\n }\n\n isInitialized.value = true\n }\n\n function setToken(accessToken: string, expiresIn: number) {\n token.value = accessToken\n const expires = new Date(Date.now() + expiresIn * 1000)\n tokenExpires.value = expires\n\n if (hasLocalStorage) {\n localStorage.setItem(AUTH_TOKEN_KEY, accessToken)\n localStorage.setItem(AUTH_EXPIRES_KEY, expires.toISOString())\n }\n }\n\n function clearToken() {\n token.value = null\n tokenExpires.value = null\n username.value = null\n userInfo.value = null\n\n if (hasLocalStorage) {\n localStorage.removeItem(AUTH_TOKEN_KEY)\n localStorage.removeItem(AUTH_EXPIRES_KEY)\n }\n }\n\n function setUserInfo(info: UserInfo) {\n userInfo.value = info\n username.value = info.username\n }\n\n function setAuthConfig(config: AuthConfig) {\n authConfig.value = config\n }\n\n function setUsername(name: string) {\n username.value = name\n }\n\n function setError(message: string | null) {\n error.value = message\n }\n\n function setLoading(loading: boolean) {\n isLoading.value = loading\n }\n\n function logout() {\n clearToken()\n }\n\n return {\n // State\n token,\n tokenExpires,\n username,\n userInfo,\n authConfig,\n isInitialized,\n isLoading,\n error,\n\n // Computed\n isAuthenticated,\n needsAuth,\n isAdmin,\n canRegister,\n\n // Actions\n initialize,\n setToken,\n clearToken,\n setAuthConfig,\n setUsername,\n setUserInfo,\n setError,\n setLoading,\n logout,\n }\n})\n"],"mappings":"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"}
|