@morscherlab/mint-sdk 1.0.0-beta.7 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +1 -0
- package/dist/__tests__/components/ProgressBar.test.d.ts +1 -0
- package/dist/__tests__/components/RackEditor.test.d.ts +1 -0
- package/dist/__tests__/components/SequenceProgressBar.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentSamples.test.d.ts +1 -0
- package/dist/__tests__/composables/useProtocolTemplates.test.d.ts +1 -0
- package/dist/__tests__/stores/settings.test.d.ts +1 -0
- package/dist/__tests__/utils/instrument.test.d.ts +1 -0
- package/dist/__tests__/utils/lcms.test.d.ts +1 -0
- package/dist/__tests__/utils/permissions.test.d.ts +1 -0
- package/dist/__tests__/utils/rack.test.d.ts +1 -0
- package/dist/{auth-QQj2kkze.js → auth-B7g4J4ZF.js} +148 -24
- package/dist/auth-B7g4J4ZF.js.map +1 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BaseCheckbox.vue.d.ts +1 -1
- package/dist/components/BaseToggle.vue.d.ts +2 -2
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +1 -1
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
- package/dist/components/FormulaInput.vue.d.ts +1 -1
- package/dist/components/InstrumentAlertLog.vue.d.ts +22 -0
- package/dist/components/InstrumentStateBadge.vue.d.ts +11 -0
- package/dist/components/InstrumentStatusCard.vue.d.ts +13 -0
- package/dist/components/LcmsSequenceTable.vue.d.ts +26 -0
- package/dist/components/ProgressBar.vue.d.ts +1 -0
- package/dist/components/RackEditor.vue.d.ts +41 -3
- package/dist/components/ReagentList.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +5 -2
- package/dist/components/SegmentedControl.vue.d.ts +2 -0
- package/dist/components/SequenceInput.vue.d.ts +1 -1
- package/dist/components/SequenceProgressBar.vue.d.ts +15 -0
- package/dist/components/SettingsModal.vue.d.ts +8 -1
- package/dist/components/TagsInput.vue.d.ts +1 -1
- package/dist/components/WellPlate.vue.d.ts +42 -3
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +3 -3
- package/dist/{components-DihbSJjU.js → components-BhK-dW99.js} +2135 -1075
- package/dist/components-BhK-dW99.js.map +1 -0
- package/dist/composables/experimentDesignData.d.ts +17 -0
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.js +4 -4
- package/dist/composables/useControlSchema.d.ts +11 -0
- package/dist/composables/useExperimentData.d.ts +11 -3
- package/dist/composables/useExperimentSamples.d.ts +42 -0
- package/dist/composables/usePlatformContext.d.ts +54 -0
- package/dist/{composables-BcgZ6diz.js → composables-Bg7CFuNz.js} +5 -3
- package/dist/composables-Bg7CFuNz.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +168 -6
- package/dist/index.js.map +1 -0
- package/dist/install.js +2 -2
- package/dist/instrument.d.ts +7 -0
- package/dist/lcms.d.ts +27 -0
- package/dist/permissions.d.ts +46 -0
- package/dist/stores/auth.d.ts +74 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +3186 -1070
- package/dist/templates/builders.d.ts +7 -3
- package/dist/templates/index.d.ts +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/templates/presets.d.ts +12 -0
- package/dist/templates/types.d.ts +16 -1
- package/dist/{templates-Cyt0Suwf.js → templates-BorLR_7p.js} +324 -10
- package/dist/templates-BorLR_7p.js.map +1 -0
- package/dist/types/auth.d.ts +2 -0
- package/dist/types/components.d.ts +32 -3
- package/dist/types/form-builder.d.ts +2 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/instrument.d.ts +56 -0
- package/dist/types/platform.d.ts +3 -0
- package/dist/{useExperimentData-CM6Y0u5L.js → useProtocolTemplates-n6AJqSqv.js} +627 -380
- package/dist/useProtocolTemplates-n6AJqSqv.js.map +1 -0
- package/dist/utils/rack.d.ts +47 -0
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +15 -0
- package/src/__tests__/components/BaseTabs.test.ts +15 -0
- package/src/__tests__/components/GroupAssigner.test.ts +18 -0
- package/src/__tests__/components/LcmsSequenceTable.test.ts +57 -0
- package/src/__tests__/components/ProgressBar.test.ts +18 -0
- package/src/__tests__/components/RackEditor.test.ts +125 -0
- package/src/__tests__/components/SampleSelector.test.ts +25 -0
- package/src/__tests__/components/SegmentedControl.test.ts +45 -0
- package/src/__tests__/components/SequenceProgressBar.test.ts +39 -0
- package/src/__tests__/components/SettingsModal.test.ts +83 -2
- package/src/__tests__/composables/useApi.test.ts +45 -0
- package/src/__tests__/composables/useAuth.test.ts +20 -0
- package/src/__tests__/composables/useControlSchema.test.ts +4 -0
- package/src/__tests__/composables/useExperimentData.test.ts +23 -0
- package/src/__tests__/composables/useExperimentSamples.test.ts +91 -0
- package/src/__tests__/composables/useProtocolTemplates.test.ts +64 -0
- package/src/__tests__/stores/settings.test.ts +78 -0
- package/src/__tests__/templates/templates.test.ts +86 -0
- package/src/__tests__/utils/instrument.test.ts +47 -0
- package/src/__tests__/utils/lcms.test.ts +73 -0
- package/src/__tests__/utils/permissions.test.ts +50 -0
- package/src/__tests__/utils/rack.test.ts +120 -0
- package/src/components/AppAvatarMenu.vue +6 -3
- package/src/components/AppTopBar.vue +16 -10
- package/src/components/AuditTrail.vue +1 -1
- package/src/components/BaseTabs.vue +22 -1
- package/src/components/Calendar.vue +6 -2
- package/src/components/ConcentrationInput.vue +3 -2
- package/src/components/GroupAssigner.vue +8 -3
- package/src/components/InstrumentAlertLog.vue +191 -0
- package/src/components/InstrumentStateBadge.vue +50 -0
- package/src/components/InstrumentStatusCard.vue +188 -0
- package/src/components/LcmsSequenceTable.vue +191 -0
- package/src/components/NumberInput.vue +5 -3
- package/src/components/ProgressBar.vue +3 -0
- package/src/components/RackEditor.vue +73 -2
- package/src/components/SampleHierarchyTree.vue +3 -2
- package/src/components/SampleSelector.vue +28 -9
- package/src/components/SegmentedControl.story.vue +17 -0
- package/src/components/SegmentedControl.vue +14 -3
- package/src/components/SequenceProgressBar.vue +71 -0
- package/src/components/SettingsModal.vue +49 -2
- package/src/components/UnitInput.vue +6 -2
- package/src/components/WellPlate.vue +145 -24
- package/src/components/index.ts +5 -0
- package/src/components/internal/WellEditPopupInternal.vue +1 -0
- package/src/composables/experimentDesignData.ts +182 -0
- package/src/composables/index.ts +14 -0
- package/src/composables/useApi.ts +113 -16
- package/src/composables/useAuth.ts +4 -0
- package/src/composables/useAutoGroup.ts +18 -9
- package/src/composables/useControlSchema.ts +21 -0
- package/src/composables/useExperimentData.ts +57 -16
- package/src/composables/useExperimentSamples.ts +142 -0
- package/src/composables/useProtocolTemplates.ts +13 -1
- package/src/composables/useRackEditor.ts +3 -2
- package/src/index.ts +27 -0
- package/src/instrument.ts +90 -0
- package/src/lcms.ts +108 -0
- package/src/permissions.ts +143 -0
- package/src/stores/auth.ts +79 -26
- package/src/stores/settings.ts +10 -0
- package/src/styles/components/instrument-monitor.css +478 -0
- package/src/styles/components/lcms-sequence-table.css +189 -0
- package/src/styles/components/sequence-progress-bar.css +63 -0
- package/src/styles/components/settings-modal.css +9 -0
- package/src/styles/components/tabs.css +9 -0
- package/src/styles/components/well-edit-popup.css +7 -1
- package/src/styles/components/well-plate.css +5 -0
- package/src/styles/index.css +3 -0
- package/src/templates/builders.ts +201 -0
- package/src/templates/controlSchemas.ts +68 -0
- package/src/templates/index.ts +2 -0
- package/src/templates/presets.ts +23 -0
- package/src/templates/types.ts +17 -0
- package/src/types/auth.ts +3 -0
- package/src/types/components.ts +45 -3
- package/src/types/form-builder.ts +2 -1
- package/src/types/index.ts +35 -0
- package/src/types/instrument.ts +61 -0
- package/src/types/platform.ts +4 -0
- package/src/utils/rack.ts +209 -0
- package/dist/auth-QQj2kkze.js.map +0 -1
- package/dist/components-DihbSJjU.js.map +0 -1
- package/dist/composables-BcgZ6diz.js.map +0 -1
- package/dist/templates-Cyt0Suwf.js.map +0 -1
- package/dist/useExperimentData-CM6Y0u5L.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useExperimentData-CM6Y0u5L.js","names":[],"sources":["../src/composables/useSortedItems.ts","../src/composables/useTextSearch.ts","../src/composables/useToast.ts","../src/composables/useTheme.ts","../src/composables/useForm.ts","../src/composables/useFormBuilder.ts","../src/composables/experiment-utils.ts","../src/composables/useApi.ts","../src/composables/useDebouncedWatch.ts","../src/composables/useRequestSyncState.ts","../src/composables/useExperimentSelector.ts","../src/composables/usePlatformContext.ts","../src/composables/useAppExperiment.ts","../src/composables/useDoseCalculator.ts","../src/composables/useWellPlateEditor.ts","../src/composables/useAutoGroup.ts","../src/utils/color.ts","../src/composables/useSampleGroups.ts","../src/composables/useExpansionSet.ts","../src/composables/useScheduleDrag.ts","../src/composables/platformContextHelpers.ts","../src/composables/useExperimentSave.ts","../src/composables/useTemplateCollection.ts","../src/composables/useBioTemplateControls.ts","../src/composables/useBioTemplateComponents.ts","../src/composables/useBioTemplateWorkspace.ts","../src/composables/useBioTemplatePackWorkspace.ts","../src/composables/useBioTemplatePresetWorkspace.ts","../src/composables/useRackEditor.ts","../src/composables/useGroupAssignment.ts","../src/composables/useReagentSeries.ts","../src/composables/useProtocolTemplates.ts","../src/composables/useExperimentData.ts"],"sourcesContent":["import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type SortedItemsSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type SortOrder = 'asc' | 'desc'\n\nexport interface SortDescriptor<TKey extends string = string> {\n key: TKey\n direction?: SortOrder | null\n}\n\nexport interface CompareSortValuesOptions {\n caseSensitive?: boolean\n}\n\nexport interface SortComparatorContext<TItem, TKey extends string = string> {\n key: TKey\n direction: SortOrder\n a: TItem\n b: TItem\n}\n\nexport type SortComparator<TItem, TKey extends string = string> = (\n aValue: unknown,\n bValue: unknown,\n context: SortComparatorContext<TItem, TKey>,\n) => number\n\nexport interface UseSortedItemsOptions<TItem, TKey extends string = string> {\n items: SortedItemsSource<readonly TItem[]>\n sort: SortedItemsSource<SortDescriptor<TKey> | null | undefined>\n enabled?: SortedItemsSource<boolean | null | undefined>\n caseSensitive?: SortedItemsSource<boolean | null | undefined>\n getValue: (item: TItem, key: TKey) => unknown\n compare?: SortComparator<TItem, TKey>\n}\n\nexport interface UseSortedItemsReturn<TItem, TKey extends string = string> {\n sort: ComputedRef<SortDescriptor<TKey> | null | undefined>\n sortedItems: ComputedRef<TItem[]>\n}\n\n/** Shared sorting for SDK tables and lists with stable empty-value handling. */\nexport function useSortedItems<TItem, TKey extends string = string>(\n options: UseSortedItemsOptions<TItem, TKey>,\n): UseSortedItemsReturn<TItem, TKey> {\n const sort = computed(() => toValue(options.sort))\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n const sortedItems = computed(() => {\n const items = [...toValue(options.items)]\n const activeSort = sort.value\n\n if (!enabled.value || !activeSort?.key || !activeSort.direction) return items\n\n const direction = activeSort.direction\n const caseSensitive = toValue(options.caseSensitive) ?? true\n\n return items.sort((a, b) => {\n const aValue = options.getValue(a, activeSort.key)\n const bValue = options.getValue(b, activeSort.key)\n\n if (options.compare) {\n return options.compare(aValue, bValue, {\n key: activeSort.key,\n direction,\n a,\n b,\n })\n }\n\n return compareSortValues(aValue, bValue, direction, { caseSensitive })\n })\n })\n\n return {\n sort,\n sortedItems,\n }\n}\n\nexport function compareSortValues(\n aValue: unknown,\n bValue: unknown,\n direction: SortOrder = 'asc',\n options: CompareSortValuesOptions = {},\n): number {\n const aEmpty = aValue === null || aValue === undefined\n const bEmpty = bValue === null || bValue === undefined\n\n if (aEmpty && bEmpty) return 0\n if (aEmpty) return 1\n if (bEmpty) return -1\n\n const aComparable = toComparableSortValue(aValue, options)\n const bComparable = toComparableSortValue(bValue, options)\n\n let comparison = 0\n if (typeof aComparable === 'number' && typeof bComparable === 'number') {\n comparison = aComparable - bComparable\n } else {\n comparison = String(aComparable).localeCompare(String(bComparable))\n }\n\n return direction === 'asc' ? comparison : -comparison\n}\n\nfunction toComparableSortValue(value: unknown, options: CompareSortValuesOptions): unknown {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'string' && options.caseSensitive === false) {\n return value.toLowerCase()\n }\n return value\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type TextSearchSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type TextSearchCandidate = unknown | readonly unknown[]\n\nexport interface UseTextSearchOptions<TItem> {\n items: TextSearchSource<readonly TItem[]>\n query: TextSearchSource<string | null | undefined>\n enabled?: TextSearchSource<boolean | null | undefined>\n getText: (item: TItem) => TextSearchCandidate\n}\n\nexport interface UseTextSearchReturn<TItem> {\n query: ComputedRef<string>\n filteredItems: ComputedRef<TItem[]>\n matches: (item: TItem, query?: string | null | undefined) => boolean\n}\n\n/** Shared text-search filtering for tables, lists, selectors, and chip inputs. */\nexport function useTextSearch<TItem>(options: UseTextSearchOptions<TItem>): UseTextSearchReturn<TItem> {\n const query = computed(() => normalizeSearchQuery(toValue(options.query)))\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n function matches(item: TItem, overrideQuery?: string | null | undefined): boolean {\n const activeQuery = overrideQuery === undefined ? query.value : normalizeSearchQuery(overrideQuery)\n if (!activeQuery) return true\n return candidateMatchesSearch(options.getText(item), activeQuery)\n }\n\n const filteredItems = computed(() => {\n const items = [...toValue(options.items)]\n if (!enabled.value || !query.value) return items\n return items.filter(item => matches(item))\n })\n\n return {\n query,\n filteredItems,\n matches,\n }\n}\n\nexport function normalizeSearchQuery(value: string | null | undefined): string {\n return (value ?? '').trim().toLowerCase()\n}\n\nexport function candidateMatchesSearch(candidate: TextSearchCandidate, query: string): boolean {\n const normalizedQuery = normalizeSearchQuery(query)\n if (!normalizedQuery) return true\n const values = Array.isArray(candidate) ? candidate : [candidate]\n return values.some((value) => {\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(normalizedQuery)\n })\n}\n","import { ref } from 'vue'\nimport type { Toast } from '../types'\n\nconst toasts = ref<Toast[]>([])\nlet nextId = 0\n\n/** Reactive global toast queue with success/error/warning/info variants and auto-dismiss timers. */\nexport function useToast() {\n function show(message: string, type: Toast['type'] = 'success', duration = 3500) {\n const id = nextId++\n toasts.value.push({ id, message, type, duration })\n setTimeout(() => dismiss(id), duration)\n }\n\n function success(message: string, duration = 3500) {\n show(message, 'success', duration)\n }\n\n function error(message: string, duration = 5000) {\n show(message, 'error', duration)\n }\n\n function warning(message: string, duration = 4000) {\n show(message, 'warning', duration)\n }\n\n function info(message: string, duration = 3500) {\n show(message, 'info', duration)\n }\n\n function dismiss(id: number) {\n toasts.value = toasts.value.filter(t => t.id !== id)\n }\n\n function clear() {\n toasts.value = []\n }\n\n return { toasts, show, success, error, warning, info, dismiss, clear }\n}\n","import { computed, type Ref } from 'vue'\nimport { useSettingsStore } from '../stores/settings'\n\nexport interface UseThemeReturn {\n isDark: Ref<boolean>\n toggleTheme: () => void\n setTheme: (theme: 'light' | 'dark') => void\n}\n\n/** Reads and toggles the active theme (light/dark/system) with reactivity to OS preference changes. */\nexport function useTheme(): UseThemeReturn {\n const settings = useSettingsStore()\n\n // Load persisted theme from localStorage (idempotent — safe to call multiple times)\n settings.initialize()\n\n const isDark = computed(() => settings.isDark())\n\n function toggleTheme() {\n settings.theme = isDark.value ? 'light' : 'dark'\n }\n\n function setTheme(theme: 'light' | 'dark') {\n settings.theme = theme\n }\n\n return {\n isDark,\n toggleTheme,\n setTheme,\n }\n}\n","import { ref, reactive, computed, toRaw, watch, type Ref } from 'vue'\n\n/**\n * Validation rule function type.\n * Returns error message string if invalid, undefined/null if valid.\n */\nexport type ValidationRule<T = unknown> = (value: T, formData: Record<string, unknown>) => string | undefined | null\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldRules<T = unknown> {\n required?: boolean | string\n minLength?: number | { value: number; message: string }\n maxLength?: number | { value: number; message: string }\n min?: number | { value: number; message: string }\n max?: number | { value: number; message: string }\n pattern?: RegExp | { value: RegExp; message: string }\n email?: boolean | string\n custom?: ValidationRule<T> | ValidationRule<T>[]\n}\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldState {\n value: unknown\n error: string | null\n touched: boolean\n dirty: boolean\n}\n\n/**\n * Form state and methods.\n */\nexport interface UseFormReturn<T extends Record<string, unknown>> {\n // Form data (reactive)\n data: T\n\n // Field errors\n errors: Record<string, string | null>\n\n // Field touched state\n touched: Record<string, boolean>\n\n // Field dirty state (value changed from initial)\n dirty: Record<string, boolean>\n\n // Overall form state\n isValid: Ref<boolean>\n isDirty: Ref<boolean>\n isSubmitting: Ref<boolean>\n\n // Methods\n setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void\n setFieldError: (field: string, error: string | null) => void\n setFieldTouched: (field: string, touched?: boolean) => void\n validateField: (field: string) => boolean\n validate: () => boolean\n reset: (values?: Partial<T>) => void\n /** Replace the full form state and treat the provided values as the new clean baseline. */\n replaceState: (values: T) => void\n handleSubmit: (onSubmit: (data: T) => Promise<void> | void) => (e?: Event) => Promise<void>\n getFieldProps: <K extends keyof T>(field: K) => {\n modelValue: T[K]\n 'onUpdate:modelValue': (value: T[K]) => void\n onBlur: () => void\n error: string | null\n }\n}\n\n// Built-in validators\nconst validators = {\n required: (value: unknown, message = 'This field is required'): string | null => {\n if (value === null || value === undefined || value === '') {\n return message\n }\n if (Array.isArray(value) && value.length === 0) {\n return message\n }\n return null\n },\n\n minLength: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length < min) {\n return message || `Must be at least ${min} characters`\n }\n return null\n },\n\n maxLength: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length > max) {\n return message || `Must be at most ${max} characters`\n }\n return null\n },\n\n min: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value < min) {\n return message || `Must be at least ${min}`\n }\n return null\n },\n\n max: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value > max) {\n return message || `Must be at most ${max}`\n }\n return null\n },\n\n pattern: (value: unknown, pattern: RegExp, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (!pattern.test(value)) {\n return message || 'Invalid format'\n }\n return null\n },\n\n email: (value: unknown, message = 'Invalid email address'): string | null => {\n if (typeof value !== 'string' || !value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(value)) {\n return message\n }\n return null\n },\n}\n\n/**\n * Form state management composable with validation.\n *\n * @param initialValues - Initial form values\n * @param rules - Validation rules for each field\n *\n * @example\n * ```typescript\n * const { data, errors, isValid, handleSubmit, getFieldProps } = useForm(\n * { email: '', password: '' },\n * {\n * email: { required: true, email: true },\n * password: { required: true, minLength: 8 },\n * }\n * )\n *\n * // In template\n * <BaseInput v-bind=\"getFieldProps('email')\" label=\"Email\" />\n * <BaseInput v-bind=\"getFieldProps('password')\" type=\"password\" label=\"Password\" />\n * <BaseButton @click=\"handleSubmit(onSubmit)\" :disabled=\"!isValid\">Submit</BaseButton>\n * ```\n */\n/** Reactive form state with field-level validation, dirty tracking, and submit handling. */\nexport function useForm<T extends Record<string, unknown>>(\n initialValues: T,\n rules: Partial<Record<keyof T, FieldRules>> = {}\n): UseFormReturn<T> {\n const cloneableInitialValues = deepToRaw(initialValues) as T\n\n // Deep copy initial values so nested objects are not shared\n let _initialValues = structuredClone(cloneableInitialValues)\n\n // Reactive form data\n const data = reactive(structuredClone(cloneableInitialValues)) as T\n\n // Field state - use simple Record types for better TS compatibility\n const errors = reactive<Record<string, string | null>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = null\n return acc\n }, {} as Record<string, string | null>)\n )\n\n const touched = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const dirty = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const isSubmitting = ref(false)\n\n // Watch data changes to track dirty state\n watch(\n () => ({ ...data }),\n (newData) => {\n for (const key of Object.keys(newData)) {\n dirty[key] = newData[key as keyof T] !== _initialValues[key as keyof T]\n }\n },\n { deep: true }\n )\n\n // Validate a single field\n function validateField(field: string): boolean {\n const value = data[field as keyof T]\n const fieldRules = rules[field as keyof T]\n\n if (!fieldRules) {\n errors[field] = null\n return true\n }\n\n // Check required\n if (fieldRules.required) {\n const message = typeof fieldRules.required === 'string' ? fieldRules.required : undefined\n const error = validators.required(value, message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Skip other validations if empty and not required\n if (value === null || value === undefined || value === '') {\n errors[field] = null\n return true\n }\n\n // Check minLength\n if (fieldRules.minLength !== undefined) {\n const config = typeof fieldRules.minLength === 'number'\n ? { value: fieldRules.minLength, message: undefined }\n : fieldRules.minLength\n const error = validators.minLength(value, config.value, config.message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check maxLength\n if (fieldRules.maxLength !== undefined) {\n const config = typeof fieldRules.maxLength === 'number'\n ? { value: fieldRules.maxLength, message: undefined }\n : fieldRules.maxLength\n const error = validators.maxLength(value, config.value, config.message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check min\n if (fieldRules.min !== undefined) {\n const config = typeof fieldRules.min === 'number'\n ? { value: fieldRules.min, message: undefined }\n : fieldRules.min\n const error = validators.min(value, config.value, config.message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check max\n if (fieldRules.max !== undefined) {\n const config = typeof fieldRules.max === 'number'\n ? { value: fieldRules.max, message: undefined }\n : fieldRules.max\n const error = validators.max(value, config.value, config.message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check pattern\n if (fieldRules.pattern !== undefined) {\n const config = fieldRules.pattern instanceof RegExp\n ? { value: fieldRules.pattern, message: undefined }\n : fieldRules.pattern\n const error = validators.pattern(value, config.value, config.message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check email\n if (fieldRules.email) {\n const message = typeof fieldRules.email === 'string' ? fieldRules.email : undefined\n const error = validators.email(value, message)\n if (error) {\n errors[field] = error\n return false\n }\n }\n\n // Check custom validators\n if (fieldRules.custom) {\n const customRules = Array.isArray(fieldRules.custom) ? fieldRules.custom : [fieldRules.custom]\n for (const rule of customRules) {\n const error = rule(value, data as Record<string, unknown>)\n if (error) {\n errors[field] = error\n return false\n }\n }\n }\n\n errors[field] = null\n return true\n }\n\n // Validate all fields\n function validate(): boolean {\n let isAllValid = true\n for (const field of Object.keys(data)) {\n if (!validateField(field)) {\n isAllValid = false\n }\n }\n return isAllValid\n }\n\n // Computed overall validity\n const isValid = computed(() => {\n return Object.values(errors).every(error => error === null)\n })\n\n // Computed overall dirty state\n const isDirty = computed(() => {\n return Object.values(dirty).some(d => d)\n })\n\n // Set field value\n function setFieldValue<K extends keyof T>(field: K, value: T[K]): void {\n ;(data as Record<string, unknown>)[field as string] = value\n if (touched[field as string]) {\n validateField(field as string)\n }\n }\n\n // Set field error\n function setFieldError(field: string, error: string | null): void {\n errors[field] = error\n }\n\n // Set field touched\n function setFieldTouched(field: string, isTouched = true): void {\n touched[field] = isTouched\n if (isTouched) {\n validateField(field)\n }\n }\n\n // Reset form\n function reset(values?: Partial<T>): void {\n const resetValues = values ? { ..._initialValues, ...values } : _initialValues\n for (const key of Object.keys(data)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(resetValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n function replaceState(values: T): void {\n const nextValues = structuredClone(deepToRaw(values)) as T\n _initialValues = structuredClone(nextValues)\n\n for (const key of Object.keys(data)) {\n if (key in nextValues) continue\n delete (data as Record<string, unknown>)[key]\n delete errors[key]\n delete touched[key]\n delete dirty[key]\n }\n\n for (const key of Object.keys(nextValues)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(nextValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n // Handle submit\n function handleSubmit(onSubmit: (data: T) => Promise<void> | void) {\n return async (e?: Event): Promise<void> => {\n e?.preventDefault()\n\n // Mark all fields as touched\n for (const field of Object.keys(data)) {\n touched[field] = true\n }\n\n if (!validate()) {\n return\n }\n\n isSubmitting.value = true\n try {\n await onSubmit(data)\n } finally {\n isSubmitting.value = false\n }\n }\n }\n\n // Get props for a field (for v-bind)\n function getFieldProps<K extends keyof T>(field: K) {\n const fieldStr = field as string\n return {\n modelValue: data[field],\n 'onUpdate:modelValue': (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(fieldStr),\n error: touched[fieldStr] ? errors[fieldStr] : null,\n }\n }\n\n return {\n data,\n errors,\n touched,\n dirty,\n isValid,\n isDirty,\n isSubmitting,\n setFieldValue,\n setFieldError,\n setFieldTouched,\n validateField,\n validate,\n reset,\n replaceState,\n handleSubmit,\n getFieldProps,\n }\n}\n\nfunction deepToRaw(value: unknown): unknown {\n const raw = toRaw(value)\n\n if (Array.isArray(raw)) {\n return raw.map(item => deepToRaw(item))\n }\n\n if (isPlainRecord(raw)) {\n return Object.fromEntries(\n Object.entries(raw).map(([key, item]) => [key, deepToRaw(item)])\n )\n }\n\n return raw\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]'\n}\n","import { reactive, ref, computed, shallowRef, watch } from 'vue'\nimport { useForm, type FieldRules, type UseFormReturn } from './useForm'\nimport { getFieldRegistryEntry, getTypeDefault } from './formBuilderRegistry'\nimport type {\n FormSchema,\n FormFieldSchema,\n FormSectionSchema,\n FieldCondition,\n FieldValidation,\n FormOptionInput,\n FormEnhancements,\n UseFormBuilderReturn,\n} from '../types/form-builder'\n\n// ---------------------------------------------------------------------------\n// Condition evaluator\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate a JSON-serializable field condition against the current form data.\n *\n * Supports logical operators (`and`, `or`, `not`) and comparison operators\n * (`eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `notIn`, `truthy`, `falsy`,\n * `contains`). Returns `true` if the condition passes.\n */\nexport function evaluateCondition(\n condition: FieldCondition,\n data: Record<string, unknown>,\n): boolean {\n if ('and' in condition) {\n return condition.and.every((c) => evaluateCondition(c, data))\n }\n if ('or' in condition) {\n return condition.or.some((c) => evaluateCondition(c, data))\n }\n if ('not' in condition) {\n return !evaluateCondition(condition.not, data)\n }\n\n const value = data[condition.field]\n\n if ('eq' in condition) return value === condition.eq\n if ('neq' in condition) return value !== condition.neq\n if ('gt' in condition) return typeof value === 'number' && value > condition.gt\n if ('lt' in condition) return typeof value === 'number' && value < condition.lt\n if ('gte' in condition) return typeof value === 'number' && value >= condition.gte\n if ('lte' in condition) return typeof value === 'number' && value <= condition.lte\n if ('in' in condition) return condition.in.includes(value)\n if ('notIn' in condition) return !condition.notIn.includes(value)\n if ('truthy' in condition) return !!value\n if ('falsy' in condition) return !value\n if ('contains' in condition) {\n if (typeof value === 'string') return value.includes(condition.contains)\n if (Array.isArray(value)) return value.includes(condition.contains)\n return false\n }\n\n return true\n}\n\n// ---------------------------------------------------------------------------\n// Schema helpers\n// ---------------------------------------------------------------------------\n\n/** Return all sections across steps (wizard) or directly from a flat schema. */\nfunction collectSections(schema: FormSchema): FormSectionSchema[] {\n return schema.steps ? schema.steps.flatMap((step) => step.sections) : schema.sections\n}\n\n/** Return all field schemas in schema order, flattening sections and steps. */\nfunction flattenFields(schema: FormSchema): FormFieldSchema[] {\n return collectSections(schema).flatMap((section) => section.fields)\n}\n\n/** Convert a JSON-safe `FieldValidation` descriptor to a runtime `FieldRules` object. */\nfunction convertValidation(v: FieldValidation): FieldRules {\n const rules: FieldRules = {}\n\n if (v.required !== undefined) rules.required = v.required\n if (v.minLength !== undefined) rules.minLength = v.minLength\n if (v.maxLength !== undefined) rules.maxLength = v.maxLength\n if (v.min !== undefined) rules.min = v.min\n if (v.max !== undefined) rules.max = v.max\n if (v.email !== undefined) rules.email = v.email\n\n if (v.pattern !== undefined) {\n rules.pattern =\n typeof v.pattern === 'string'\n ? new RegExp(v.pattern)\n : { value: new RegExp(v.pattern.value), message: v.pattern.message }\n }\n\n return rules\n}\n\nfunction buildInitialValues<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n initialData?: Partial<T>,\n): Record<string, unknown> {\n const initialValues = {} as Record<string, unknown>\n\n for (const field of fields) {\n const key = field.name\n if (initialData && hasOwnKey(initialData, key)) {\n initialValues[key] = (initialData as Record<string, unknown>)[key]\n } else if (field.defaultValue !== undefined) {\n initialValues[key] = field.defaultValue\n } else {\n initialValues[key] = getTypeDefault(field.type)\n }\n }\n\n return initialValues\n}\n\nfunction buildRules<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n enhancements?: FormEnhancements<T>,\n): Partial<Record<string, FieldRules>> {\n const rules: Partial<Record<string, FieldRules>> = {}\n\n for (const field of fields) {\n const base: FieldRules = field.validation ? convertValidation(field.validation) : {}\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n\n const customValidators: Array<(\n value: unknown,\n formData: Record<string, unknown>,\n ) => string | undefined | null> = []\n\n if (enhancement?.validate) {\n const fn = enhancement.validate\n customValidators.push((value, formData) => fn(value, formData as T))\n }\n\n if (customValidators.length > 0) {\n base.custom = customValidators\n }\n\n if (Object.keys(base).length > 0) {\n rules[field.name] = base\n }\n }\n\n return rules\n}\n\nfunction replaceArray<T>(target: T[], values: readonly T[]): void {\n target.splice(0, target.length, ...values)\n}\n\nfunction replaceRecord<TValue>(\n target: Partial<Record<string, TValue>>,\n source: Partial<Record<string, TValue>>,\n): void {\n for (const key of Object.keys(target)) {\n delete target[key]\n }\n Object.assign(target, source)\n}\n\nfunction hasOwnKey(source: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(source, key)\n}\n\n// ---------------------------------------------------------------------------\n// useFormBuilder\n// ---------------------------------------------------------------------------\n\n/**\n * Drive a `FormSchema` as reactive form state.\n *\n * Builds initial values from schema defaults and `initialData`, derives\n * validation rules from `FieldValidation` descriptors and enhancement\n * validators, evaluates `FieldCondition` expressions for field/section\n * visibility, and wires wizard step navigation when `schema.steps` is set.\n *\n * @param schema - Declarative form or wizard schema.\n * @param initialData - Values that override schema defaults.\n * @param enhancements - TypeScript-only callbacks (dynamic options, validators,\n * submit handler, transform, field-change watcher).\n */\n/** Drives a declarative FormSchema as reactive state with conditional fields, wizard steps, and validation. */\nexport function useFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(\n schema: FormSchema,\n initialData?: Partial<T>,\n enhancements?: FormEnhancements<T>,\n): UseFormBuilderReturn<T> {\n const currentSchema = shallowRef(schema)\n const fields = reactive<FormFieldSchema[]>(flattenFields(schema))\n const sections = reactive<FormSectionSchema[]>(collectSections(schema))\n const rules = reactive<Partial<Record<string, FieldRules>>>(buildRules(fields, enhancements))\n\n // -- Create form -----------------------------------------------------------\n const form = useForm(\n buildInitialValues<T>(fields, initialData) as T,\n rules as Partial<Record<keyof T, FieldRules>>,\n )\n\n // -- Visibility ------------------------------------------------------------\n function isFieldVisible(name: string): boolean {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.visible) {\n return enhancement.visible(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.condition) {\n return evaluateCondition(field.condition, form.data as Record<string, unknown>)\n }\n\n return true\n }\n\n function isSectionVisible(id: string): boolean {\n const section = sections.find((s) => s.id === id)\n if (section?.condition) {\n return evaluateCondition(section.condition, form.data as Record<string, unknown>)\n }\n return true\n }\n\n // -- Resolved field props --------------------------------------------------\n function getResolvedFieldProps(field: FormFieldSchema): Record<string, unknown> {\n const entry = getFieldRegistryEntry(field.type)\n const formProps = form.getFieldProps(field.name as keyof T)\n\n const merged: Record<string, unknown> = {\n ...entry.defaults,\n ...(field.props ?? {}),\n }\n\n // Dynamic enhancement props\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n if (enhancement?.props) {\n Object.assign(merged, enhancement.props(form.data as T))\n }\n\n // Dynamic options\n const options = getFieldOptions(field.name)\n if (options) {\n merged.options = options\n }\n\n // Form field bindings\n if (entry.vModel) {\n merged.modelValue = formProps.modelValue\n merged['onUpdate:modelValue'] = formProps['onUpdate:modelValue']\n }\n merged.onBlur = formProps.onBlur\n\n // Error as boolean for components that use boolean error prop\n const errorMsg = formProps.error\n if (errorMsg) {\n merged.error = true\n }\n\n // Schema-level props\n if (field.placeholder) merged.placeholder = field.placeholder\n if (field.size) merged.size = field.size\n if (field.disabled) merged.disabled = true\n if (field.readonly) merged.readonly = true\n\n // Radio group needs a name prop\n if (field.type === 'radio' && !merged.name) {\n merged.name = field.name\n }\n\n return merged\n }\n\n function getFieldOptions(name: string): FormOptionInput[] | undefined {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.options) {\n return enhancement.options(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.props?.options) {\n return field.props.options as FormOptionInput[]\n }\n\n return undefined\n }\n\n // -- Wizard state ----------------------------------------------------------\n const currentStep = ref(0)\n\n const isCurrentStepValid = computed(() => {\n if (!currentSchema.value.steps) return form.isValid.value\n\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return true\n\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n if (!form.validateField(field.name)) return false\n }\n }\n return true\n })\n\n function goNext(): boolean {\n if (!currentSchema.value.steps) return false\n\n // Touch and validate all visible fields in current step\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return false\n\n let valid = true\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) valid = false\n }\n }\n\n if (!valid) return false\n\n if (currentStep.value < currentSchema.value.steps.length - 1) {\n currentStep.value++\n }\n return true\n }\n\n function goBack(): void {\n if (currentStep.value > 0) {\n currentStep.value--\n }\n }\n\n function goToStep(index: number): void {\n if (!currentSchema.value.steps) return\n if (index >= 0 && index < currentSchema.value.steps.length) {\n currentStep.value = index\n }\n }\n\n // -- Validate (skip hidden fields) -----------------------------------------\n function validate(): boolean {\n let allValid = true\n for (const field of fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) {\n allValid = false\n }\n }\n return allValid\n }\n\n // -- Submit ----------------------------------------------------------------\n async function submit(): Promise<void> {\n if (!validate()) return\n\n // Build submission data excluding hidden fields\n let submitData = {} as Record<string, unknown>\n for (const field of fields) {\n if (isFieldVisible(field.name)) {\n submitData[field.name] = (form.data as Record<string, unknown>)[field.name]\n }\n }\n\n if (enhancements?.transform) {\n submitData = enhancements.transform(submitData as T) as Record<string, unknown>\n }\n\n if (enhancements?.onSubmit) {\n form.isSubmitting.value = true\n try {\n await enhancements.onSubmit(submitData as T)\n } finally {\n form.isSubmitting.value = false\n }\n }\n }\n\n // -- Reset -----------------------------------------------------------------\n function reset(values?: Partial<T>): void {\n form.reset(values)\n currentStep.value = 0\n }\n\n function updateSchema(nextSchema: FormSchema, nextData?: Partial<T>): void {\n currentSchema.value = nextSchema\n\n const nextFields = flattenFields(nextSchema)\n replaceArray(fields, nextFields)\n replaceArray(sections, collectSections(nextSchema))\n replaceRecord(rules, buildRules(nextFields, enhancements))\n form.replaceState(buildInitialValues<T>(nextFields, nextData) as T)\n currentStep.value = 0\n }\n\n // -- onFieldChange wiring --------------------------------------------------\n if (enhancements?.onFieldChange) {\n const callback = enhancements.onFieldChange\n watch(\n () => ({ ...(form.data as Record<string, unknown>) }),\n (newData, oldData) => {\n if (!oldData) return\n for (const key of Object.keys(newData)) {\n if (newData[key] !== oldData[key]) {\n callback(key as keyof T, newData[key], newData as T)\n }\n }\n },\n { deep: true },\n )\n }\n\n return {\n form: form as UseFormReturn<T>,\n rules: rules as Partial<Record<keyof T, FieldRules>>,\n isFieldVisible,\n isSectionVisible,\n fields,\n getResolvedFieldProps,\n getFieldOptions,\n currentStep,\n isCurrentStepValid,\n goNext,\n goBack,\n goToStep,\n validate,\n reset,\n submit,\n updateSchema,\n }\n}\n","import type { DatePreset, ExperimentStatus, SelectOption, PillVariant } from '../types'\n\ninterface ExperimentCodeSource {\n id?: number | null\n experiment_code?: string | null\n}\n\nexport function formatExperimentDate(dateStr: string): string {\n try {\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n } catch {\n return dateStr\n }\n}\n\nexport function datePresetToISO(preset: DatePreset): string {\n const now = new Date()\n const days = preset === 'last_7_days' ? 7 : preset === 'last_30_days' ? 30 : 90\n const d = new Date(now.getTime() - days * 86_400_000)\n return d.toISOString()\n}\n\nexport const EXPERIMENT_STATUS_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'All statuses' },\n { value: 'planned', label: 'Planned' },\n { value: 'ongoing', label: 'Ongoing' },\n { value: 'completed', label: 'Completed' },\n { value: 'cancelled', label: 'Cancelled' },\n]\n\nexport const EXPERIMENT_STATUS_VARIANT_MAP: Record<ExperimentStatus, PillVariant> = {\n planned: 'default',\n ongoing: 'primary',\n completed: 'success',\n cancelled: 'error',\n}\n\nexport const EXPERIMENT_STATUS_LABELS: Record<ExperimentStatus, string> = {\n planned: 'Planned',\n ongoing: 'Ongoing',\n completed: 'Completed',\n cancelled: 'Cancelled',\n}\n\nexport function formatExperimentStatus(status?: ExperimentStatus | string | null): string {\n if (!status) return ''\n if (status in EXPERIMENT_STATUS_LABELS) {\n return EXPERIMENT_STATUS_LABELS[status as ExperimentStatus]\n }\n const label = String(status).replace(/[-_]+/g, ' ').trim()\n return label ? label.replace(/^\\w/, c => c.toUpperCase()) : ''\n}\n\nexport function getExperimentStatusVariant(status?: ExperimentStatus | string | null): PillVariant {\n if (status && status in EXPERIMENT_STATUS_VARIANT_MAP) {\n return EXPERIMENT_STATUS_VARIANT_MAP[status as ExperimentStatus]\n }\n return 'default'\n}\n\nexport function resolveExperimentCode(experiment: ExperimentCodeSource): string | undefined {\n if (experiment.experiment_code) return experiment.experiment_code\n return experiment.id != null ? `EXP-${experiment.id}` : undefined\n}\n\nexport const DATE_PRESET_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'Any time' },\n { value: 'last_7_days', label: 'Last 7 days' },\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_90_days', label: 'Last 90 days' },\n]\n\nexport const SORT_OPTIONS: SelectOption<string>[] = [\n { value: 'created_at:desc', label: 'Newest first' },\n { value: 'created_at:asc', label: 'Oldest first' },\n { value: 'updated_at:desc', label: 'Recently updated' },\n { value: 'name:asc', label: 'Name A\\u2013Z' },\n { value: 'name:desc', label: 'Name Z\\u2013A' },\n]\n","import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'\nimport { useSettingsStore } from '../stores/settings'\nimport { useAuthStore } from '../stores/auth'\n\nlet apiClientInstance: AxiosInstance | null = null\nlet interceptorAttached = false\n\nfunction joinUrlPath(baseUrl: string, path: string): string {\n if (!path) return baseUrl\n const normalizedBase = baseUrl.replace(/\\/+$/, '')\n const normalizedPath = path.replace(/^\\/+/, '/')\n return `${normalizedBase}${normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`}`\n}\n\nfunction getApiClient(): AxiosInstance {\n if (!apiClientInstance) {\n apiClientInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n }\n return apiClientInstance\n}\n\nexport interface ApiClientOptions {\n baseUrl?: string\n timeout?: number\n withAuth?: boolean\n}\n\nexport interface UseApiReturn {\n client: AxiosInstance\n get: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n delete: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n upload: <T>(url: string, file: File, fieldName?: string, additionalData?: Record<string, unknown>) => Promise<T>\n download: (url: string, filename?: string) => Promise<string>\n buildUrl: (path: string) => string\n buildWsUrl: (path: string) => string\n}\n\n/** Axios-based API client that injects the plugin base URL and JWT auth header on every request. */\nexport function useApi(options: ApiClientOptions = {}): UseApiReturn {\n const settingsStore = useSettingsStore()\n const authStore = useAuthStore()\n const apiClient = getApiClient()\n\n // Ensure auth store is initialized (reads token from localStorage)\n if (!authStore.isInitialized) {\n authStore.initialize()\n }\n\n // Attach auth interceptor only once (reads token dynamically, not from closure)\n if (!interceptorAttached) {\n apiClient.interceptors.request.use((config) => {\n if (authStore.token && config.headers && !config.headers.Authorization) {\n config.headers.Authorization = `Bearer ${authStore.token}`\n }\n return config\n })\n interceptorAttached = true\n }\n\n // Build per-request config that applies this caller's options\n function requestConfig(config?: AxiosRequestConfig): AxiosRequestConfig {\n const base: AxiosRequestConfig = {\n baseURL: options.baseUrl ?? settingsStore.getApiBaseUrl(),\n timeout: options.timeout ?? settingsStore.requestTimeout,\n ...config,\n }\n // Strip auth header if explicitly disabled\n if (options.withAuth === false) {\n base.headers = { ...base.headers, Authorization: undefined }\n }\n return base\n }\n\n // Generic request methods\n async function get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.get<T>(url, requestConfig(config))\n return response.data\n }\n\n async function post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.post<T>(url, data, requestConfig(config))\n return response.data\n }\n\n async function put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.put<T>(url, data, requestConfig(config))\n return response.data\n }\n\n async function patch<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.patch<T>(url, data, requestConfig(config))\n return response.data\n }\n\n async function del<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.delete<T>(url, requestConfig(config))\n return response.data\n }\n\n // File upload helper\n async function upload<T>(url: string, file: File, fieldName = 'file', additionalData?: Record<string, unknown>): Promise<T> {\n const formData = new FormData()\n formData.append(fieldName, file)\n\n if (additionalData) {\n Object.entries(additionalData).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))\n }\n })\n }\n\n const response = await apiClient.post<T>(url, formData, requestConfig({\n // Let Axios set Content-Type with the correct multipart boundary\n headers: { 'Content-Type': undefined },\n }))\n return response.data\n }\n\n // Download helper - returns blob URL\n async function download(url: string, filename?: string): Promise<string> {\n const response = await apiClient.get(url, requestConfig({ responseType: 'blob' }))\n const blob = new Blob([response.data])\n const blobUrl = URL.createObjectURL(blob)\n\n // Optionally trigger download\n if (filename) {\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n // Revoke after a short delay to allow download to start;\n // return empty string since the URL will be invalidated\n setTimeout(() => URL.revokeObjectURL(blobUrl), 100)\n return ''\n }\n\n // Caller is responsible for revoking when no filename is provided\n return blobUrl\n }\n\n // Build full URL for external use (e.g., <a href=\"...\">)\n function buildUrl(path: string): string {\n const baseUrl = options.baseUrl ?? settingsStore.getApiBaseUrl()\n return joinUrlPath(baseUrl, path)\n }\n\n // WebSocket URL builder\n function buildWsUrl(path: string): string {\n return joinUrlPath(settingsStore.getWsBaseUrl(), path)\n }\n\n return {\n client: apiClient,\n get,\n post,\n put,\n patch,\n delete: del,\n upload,\n download,\n buildUrl,\n buildWsUrl,\n }\n}\n","import {\n onScopeDispose,\n ref,\n watch,\n type Ref,\n type WatchOptions,\n type WatchSource,\n type WatchStopHandle,\n} from 'vue'\n\nexport type DebouncedWatchCleanup = () => void\nexport type DebouncedWatchSource<T> = WatchSource<T> | WatchSource<unknown>[] | (() => T)\nexport type DebouncedWatchCallback<T> = (\n value: T,\n oldValue: T | undefined,\n onCleanup: (cleanup: DebouncedWatchCleanup) => void,\n) => void | Promise<void>\n\nexport interface UseDebouncedWatchOptions extends WatchOptions {\n /** Debounce interval in milliseconds. */\n delay?: number\n}\n\nexport interface UseDebouncedWatchReturn {\n /** Whether a callback is currently scheduled. */\n isPending: Ref<boolean>\n /** Cancel the pending callback without stopping the watcher. */\n cancel: () => void\n /** Run the pending callback immediately, if one is scheduled. */\n flush: () => void\n /** Stop the watcher and clear pending callbacks. */\n stop: WatchStopHandle\n}\n\n/** Watch a Vue source with debounced callback execution and explicit cancel/flush controls. */\nexport function useDebouncedWatch<T>(\n source: DebouncedWatchSource<T>,\n callback: DebouncedWatchCallback<T>,\n options: UseDebouncedWatchOptions = {},\n): UseDebouncedWatchReturn {\n const { delay = 300, ...watchOptions } = options\n const isPending = ref(false)\n\n let timer: ReturnType<typeof setTimeout> | null = null\n let hasLatestValue = false\n let latestValue: T\n let latestOldValue: T | undefined\n let callbackCleanup: DebouncedWatchCleanup | null = null\n let stopped = false\n\n function clearTimer(): void {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n isPending.value = false\n }\n\n function runCallbackCleanup(): void {\n if (!callbackCleanup) return\n callbackCleanup()\n callbackCleanup = null\n }\n\n function cancel(): void {\n clearTimer()\n hasLatestValue = false\n latestOldValue = undefined\n }\n\n function flush(): void {\n if (!hasLatestValue) return\n const value = latestValue\n const oldValue = latestOldValue\n cancel()\n runCallbackCleanup()\n void callback(value, oldValue, (cleanup) => {\n callbackCleanup = cleanup\n })\n }\n\n function schedule(value: T, oldValue: T | undefined): void {\n cancel()\n hasLatestValue = true\n latestValue = value\n latestOldValue = oldValue\n isPending.value = true\n timer = setTimeout(flush, delay)\n }\n\n const stopWatch = watch(\n source as WatchSource<unknown> | WatchSource<unknown>[],\n (value, oldValue, onCleanup) => {\n schedule(value as T, oldValue as T | undefined)\n onCleanup(() => {\n cancel()\n runCallbackCleanup()\n })\n },\n watchOptions,\n )\n\n function stop(): void {\n if (stopped) return\n stopped = true\n stopWatch()\n cancel()\n runCallbackCleanup()\n }\n\n onScopeDispose(stop)\n\n return {\n isPending,\n cancel,\n flush,\n stop,\n }\n}\n","import { ref, type Ref } from 'vue'\n\nexport type RequestSyncSuccessKind = 'load' | 'save' | 'run'\n\nexport interface RequestSyncRunOptions {\n success?: RequestSyncSuccessKind\n errorMessage?: string\n}\n\nexport interface UseRequestSyncStateReturn {\n /** Whether a request is in progress. */\n loading: Ref<boolean>\n /** Message from the last failed request, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load operation, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save operation, or null. */\n lastSavedAt: Ref<Date | null>\n /** Timestamp of the last successful run operation, or null. */\n lastRunAt: Ref<Date | null>\n /** Clear the current error without changing loading or timestamps. */\n clearError: () => void\n /** Convert thrown values into a developer-facing error message. */\n readErrorMessage: (value: unknown, fallback?: string) => string\n /** Store and return a normalized error message. */\n setError: (value: unknown, fallback?: string) => string\n /** Mark the resource as successfully loaded. */\n markLoaded: (date?: Date) => void\n /** Mark the resource as successfully saved. */\n markSaved: (date?: Date) => void\n /** Mark the operation as successfully run. */\n markRun: (date?: Date) => void\n /** Run a request with shared loading/error handling and optional sync marking. */\n run: <T>(operation: () => Promise<T>, options?: RequestSyncRunOptions) => Promise<T>\n}\n\n/** Shared loading/error/timestamp state for generated plugin request helpers. */\nexport function useRequestSyncState(\n defaultErrorMessage = 'Request failed.',\n): UseRequestSyncStateReturn {\n const loading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedAt = ref<Date | null>(null)\n const lastSavedAt = ref<Date | null>(null)\n const lastRunAt = ref<Date | null>(null)\n\n function clearError(): void {\n error.value = null\n }\n\n function readErrorMessage(value: unknown, fallback = defaultErrorMessage): string {\n if (value instanceof Error && value.message) {\n return value.message\n }\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message\n ) {\n return (value as { message: string }).message\n }\n return fallback\n }\n\n function setError(value: unknown, fallback?: string): string {\n const message = readErrorMessage(value, fallback)\n error.value = message\n return message\n }\n\n function markLoaded(date = new Date()): void {\n lastLoadedAt.value = date\n }\n\n function markSaved(date = new Date()): void {\n lastSavedAt.value = date\n }\n\n function markRun(date = new Date()): void {\n lastRunAt.value = date\n }\n\n async function run<T>(\n operation: () => Promise<T>,\n options: RequestSyncRunOptions = {},\n ): Promise<T> {\n loading.value = true\n clearError()\n try {\n const response = await operation()\n if (options.success === 'load') {\n markLoaded()\n } else if (options.success === 'save') {\n markSaved()\n } else if (options.success === 'run') {\n markRun()\n }\n return response\n } catch (err) {\n setError(err, options.errorMessage)\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n lastLoadedAt,\n lastSavedAt,\n lastRunAt,\n clearError,\n readErrorMessage,\n setError,\n markLoaded,\n markSaved,\n markRun,\n run,\n }\n}\n","import { ref, reactive, computed, watch, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { useDebouncedWatch } from './useDebouncedWatch'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { datePresetToISO } from './experiment-utils'\nimport type {\n ExperimentSummary,\n ExperimentListResponse,\n ExperimentFilters,\n ExperimentTypeOption,\n ExperimentSortField,\n PlatformContext,\n SelectOption,\n} from '../types'\n\nfunction getPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\nfunction getPlatformApiUrl(): string | undefined {\n return getPlatformContext()?.platformApiUrl\n}\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n /** Current page of fetched experiment rows. */\n experiments: Ref<ExperimentSummary[]>\n /** Total matching experiment count reported by the platform. */\n total: Ref<number>\n /** Currently selected experiment, or null. */\n selectedExperiment: Ref<ExperimentSummary | null>\n /** Mutable filters used for the next fetch. */\n filters: ExperimentFilters\n /** Whether experiment rows are currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Current zero-based page index. */\n page: Ref<number>\n /** Whether another page can be loaded. */\n hasMore: ComputedRef<boolean>\n // Sort\n /** Combined sort key in the form `<field>:<asc|desc>`. */\n sortKey: Ref<string>\n // Filter options\n /** Available experiment type options for filter UI. */\n experimentTypes: Ref<ExperimentTypeOption[]>\n /** Available project options for filter UI. */\n projects: Ref<SelectOption<string>[]>\n // Grouped view\n /** Fetched experiments grouped by project name. */\n groupedByProject: ComputedRef<[string, ExperimentSummary[]][]>\n // Methods\n /** Fetch the current page with the current filters. */\n fetch: () => Promise<void>\n /** Fetch and append the next page when available. */\n loadMore: () => Promise<void>\n /** Clear fetched rows and refetch page zero. */\n reset: () => void\n /** Select an experiment. */\n select: (experiment: ExperimentSummary) => void\n /** Clear selection and filters. */\n clear: () => void\n /** Fetch experiment type and project filter options. */\n fetchFilterOptions: () => Promise<void>\n}\n\n/** Fetches a paginated, filtered experiment list from the platform API for picker and selector UIs. */\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const { limit = 100, immediate = false, experimentType, apiBaseUrl } = options\n const platformBase = apiBaseUrl ?? getPlatformApiUrl()\n const api = useApi()\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const request = useRequestSyncState('Failed to fetch experiments')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const page = ref(0)\n\n // Sort: combined key like \"created_at:desc\"\n const sortKey = ref<string>('created_at:desc')\n\n // Filter option data (fetched once, cached)\n const experimentTypes = ref<ExperimentTypeOption[]>([])\n const projects = ref<SelectOption<string>[]>([])\n let filterOptionsFetched = false\n\n const hasMore = computed(() => experiments.value.length < total.value)\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n experimentType: undefined,\n datePreset: undefined,\n })\n\n function parseSortKey(): { sortBy: ExperimentSortField; sortOrder: 'asc' | 'desc' } {\n const [field, order] = sortKey.value.split(':')\n return {\n sortBy: (field || 'created_at') as ExperimentSortField,\n sortOrder: (order || 'desc') as 'asc' | 'desc',\n }\n }\n\n async function fetchExperiments(): Promise<void> {\n try {\n await request.run(async () => {\n const params = new URLSearchParams()\n // Priority: explicit option > platform context (single type) > filter dropdown > no filter\n const allowedTypes = getPlatformContext()?.allowedExperimentTypes\n const effectiveType = experimentType\n ?? (allowedTypes?.length === 1 ? allowedTypes[0] : undefined)\n ?? filters.experimentType\n ?? undefined\n if (effectiveType) params.set('experiment_type', effectiveType)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n\n // Sort params\n const { sortBy, sortOrder } = parseSortKey()\n params.set('sort_by', sortBy)\n params.set('sort_order', sortOrder)\n\n // Date preset → created_after\n if (filters.datePreset) {\n params.set('created_after', datePresetToISO(filters.datePreset))\n }\n\n params.set('limit', String(limit))\n params.set('skip', String(page.value * limit))\n\n const query = params.toString()\n const base = platformBase ?? ''\n const url = `${base}/experiments${query ? `?${query}` : ''}`\n const data = await api.get<ExperimentListResponse>(url)\n\n // Client-side filter for multiple allowed types (backend only supports single type)\n let filtered = data.experiments\n if (!effectiveType && allowedTypes && allowedTypes.length > 1) {\n const typeSet = new Set(allowedTypes)\n filtered = filtered.filter(e => typeSet.has(e.experiment_type))\n }\n\n if (page.value === 0) {\n experiments.value = filtered\n } else {\n experiments.value = [...experiments.value, ...filtered]\n }\n // When client-side filtering is active (multiple allowedTypes), we can't\n // use data.total since it counts all types. Check if server has more pages.\n if (!effectiveType && allowedTypes && allowedTypes.length > 1) {\n if (data.experiments.length < limit) {\n // Server returned less than a full page — no more data\n total.value = experiments.value.length\n } else {\n // Might be more pages on the server\n total.value = experiments.value.length + 1\n }\n } else {\n total.value = data.total\n }\n }, { success: 'load', errorMessage: 'Failed to fetch experiments' })\n } catch {\n if (page.value === 0) {\n experiments.value = []\n total.value = 0\n }\n }\n }\n\n async function fetchFilterOptions(): Promise<void> {\n if (filterOptionsFetched) return\n filterOptionsFetched = true\n\n const base = platformBase ?? ''\n const [typesRes, projectsRes] = await Promise.allSettled([\n api.get<Array<{ value: string; label: string; color?: string }>>(`${base}/experiments/experiment-types`),\n api.get<{ projects: Array<{ id: number; name: string }>; total: number }>(`${base}/projects`),\n ])\n\n if (typesRes.status === 'fulfilled' && Array.isArray(typesRes.value)) {\n experimentTypes.value = typesRes.value.map(t => ({\n value: t.value,\n label: t.label,\n color: t.color,\n }))\n }\n\n if (projectsRes.status === 'fulfilled' && projectsRes.value?.projects && Array.isArray(projectsRes.value.projects)) {\n projects.value = projectsRes.value.projects.map(p => ({\n value: p.name,\n label: p.name,\n }))\n }\n }\n\n async function loadMore(): Promise<void> {\n if (!hasMore.value || isLoading.value) return\n page.value++\n await fetchExperiments()\n }\n\n function reset(): void {\n page.value = 0\n experiments.value = []\n total.value = 0\n fetchExperiments()\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n filters.experimentType = undefined\n filters.datePreset = undefined\n sortKey.value = 'created_at:desc'\n page.value = 0\n request.clearError()\n }\n\n // Group experiments by project (client-side)\n const groupedByProject = computed<[string, ExperimentSummary[]][]>(() => {\n const groups = new Map<string, ExperimentSummary[]>()\n for (const exp of experiments.value) {\n const key = exp.project_name ?? exp.project ?? 'No project'\n const list = groups.get(key)\n if (list) {\n list.push(exp)\n } else {\n groups.set(key, [exp])\n }\n }\n // Sort alphabetically, \"No project\" last\n return [...groups.entries()].sort(([a], [b]) => {\n if (a === 'No project') return 1\n if (b === 'No project') return -1\n return a.localeCompare(b)\n })\n })\n\n const searchWatch = useDebouncedWatch(\n () => filters.search,\n () => {\n page.value = 0\n fetchExperiments()\n },\n { delay: 300 },\n )\n\n // Immediate watch on discrete filters and sort (cancel any pending search debounce)\n watch(\n () => [filters.status, filters.project, filters.experimentType, filters.datePreset, sortKey.value],\n () => {\n searchWatch.cancel()\n page.value = 0\n fetchExperiments()\n },\n )\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n lastLoadedAt,\n page,\n hasMore,\n sortKey,\n experimentTypes,\n projects,\n groupedByProject,\n fetch: fetchExperiments,\n loadMore,\n reset,\n select,\n clear,\n fetchFilterOptions,\n }\n}\n","import { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { PlatformContext, PlatformContextOptions, PlatformEvent } from '../types'\n\nconst DEFAULT_CONTEXT: PlatformContext = {\n isIntegrated: false,\n theme: 'system',\n}\n\nconst platformContext = ref<PlatformContext>({ ...DEFAULT_CONTEXT })\n\n// Track allowed origins for postMessage security.\n// Inferred origins come from platform injection and URL params.\n// Consumer origins and allowAnyOrigin are tracked per composable instance.\nlet inferredOrigins: Set<string> = new Set()\nlet allowedOrigins: Set<string> = new Set()\nlet allowAnyOrigin = false\nlet initialized = false\nlet listenerCount = 0\nlet nextConsumerId = 0\nlet currentHandler: ((event: MessageEvent) => void) | null = null\nconst consumerOrigins: Map<number, Set<string>> = new Map()\nconst allowAnyOriginConsumers: Set<number> = new Set()\n\n/**\n * Derive origin from URL (protocol + host)\n */\nfunction getOriginFromUrl(url: string): string | null {\n try {\n const parsed = new URL(url)\n return parsed.origin\n } catch {\n return null\n }\n}\n\nfunction normalizeAllowedOrigins(origins: string[] | undefined): Set<string> {\n const normalized = new Set<string>()\n if (!origins) {\n return normalized\n }\n\n for (const origin of origins) {\n normalized.add(getOriginFromUrl(origin) || origin)\n }\n return normalized\n}\n\nfunction recomputeOriginPolicy(): void {\n allowedOrigins = new Set(inferredOrigins)\n for (const origins of consumerOrigins.values()) {\n for (const origin of origins) {\n allowedOrigins.add(origin)\n }\n }\n allowAnyOrigin = allowAnyOriginConsumers.size > 0\n}\n\nfunction resetPlatformContextState(): void {\n inferredOrigins = new Set()\n allowedOrigins = new Set()\n allowAnyOrigin = false\n initialized = false\n listenerCount = 0\n currentHandler = null\n consumerOrigins.clear()\n allowAnyOriginConsumers.clear()\n platformContext.value = { ...DEFAULT_CONTEXT }\n}\n\n/**\n * Check if an origin is allowed for postMessage communication\n */\nfunction isOriginAllowed(origin: string): boolean {\n // Development mode: allow any origin (must be explicitly enabled)\n if (allowAnyOrigin) {\n console.warn('[MINT SDK] postMessage origin validation disabled - only use in development')\n return true\n }\n\n // Same origin is always allowed\n if (origin === window.location.origin) {\n return true\n }\n\n // Check against allowed origins list\n return allowedOrigins.has(origin)\n}\n\n/**\n * Platform context composable for plugin integration with MINT Platform.\n *\n * Provides secure communication with the parent platform via postMessage.\n *\n * @param options - Configuration options\n * @param options.allowedOrigins - List of allowed origins for postMessage\n * @param options.allowAnyOrigin - Allow any origin (UNSAFE, development only)\n *\n * @example\n * ```typescript\n * // Basic usage - derives origin from platform injection\n * const { isIntegrated, user, theme } = usePlatformContext()\n *\n * // With explicit allowed origins\n * const { isIntegrated } = usePlatformContext({\n * allowedOrigins: ['https://mint.example.com']\n * })\n *\n * // Development mode (UNSAFE)\n * const { isIntegrated } = usePlatformContext({\n * allowAnyOrigin: import.meta.env.DEV\n * })\n * ```\n */\n/** Connects a plugin to the MINT platform via postMessage, exposing user, theme, and experiment context. */\nexport function usePlatformContext(options: PlatformContextOptions = {}) {\n const consumerId = ++nextConsumerId\n const instanceOrigins = normalizeAllowedOrigins(options.allowedOrigins)\n const instanceAllowAnyOrigin = options.allowAnyOrigin === true\n\n function detectPlatform(): void {\n const detectedOrigins = new Set<string>()\n\n // Check if running under MINT Platform by looking for platform-injected global\n const platformData = (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n\n if (platformData) {\n platformContext.value = {\n ...platformData,\n isIntegrated: true,\n }\n\n // Derive platform origin from injected data\n if (platformData.platformOrigin) {\n detectedOrigins.add(platformData.platformOrigin)\n } else if (platformData.platformApiUrl) {\n const origin = getOriginFromUrl(platformData.platformApiUrl)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n } else {\n // Check for platform indicator in URL or localStorage\n const urlParams = new URLSearchParams(window.location.search)\n const hasPluginParam = urlParams.has('mint-plugin')\n\n // Try to get platform origin from URL parameter\n const platformOrigin = urlParams.get('mint-origin')\n if (platformOrigin) {\n const origin = getOriginFromUrl(platformOrigin)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n\n platformContext.value = {\n isIntegrated: hasPluginParam,\n theme: (() => {\n try {\n const s = localStorage.getItem('mint-settings')\n if (s) return (JSON.parse(s).theme as 'light' | 'dark' | 'system') || 'system'\n } catch { /* ignore */ }\n return 'system'\n })(),\n platformOrigin: platformOrigin || undefined,\n }\n }\n\n inferredOrigins = detectedOrigins\n }\n\n function handlePlatformMessage(event: MessageEvent): void {\n // Only accept messages from parent window (platform)\n if (event.source !== window.parent) return\n\n // Validate origin for security\n if (!isOriginAllowed(event.origin)) {\n console.warn(`[MINT SDK] Rejected postMessage from untrusted origin: ${event.origin}`)\n return\n }\n\n try {\n const platformEvent = event.data as PlatformEvent\n if (!platformEvent.type?.startsWith('mint:')) return\n\n switch (platformEvent.type) {\n case 'mint:theme-changed':\n platformContext.value.theme = platformEvent.payload as 'light' | 'dark' | 'system'\n break\n case 'mint:user-changed':\n platformContext.value.user = platformEvent.payload as PlatformContext['user']\n break\n }\n } catch {\n // Ignore invalid messages\n }\n }\n\n /**\n * Send a message to the parent platform.\n * Uses validated target origin for security.\n */\n function sendToPlatform(event: PlatformEvent): void {\n if (!platformContext.value.isIntegrated || window.parent === window) {\n return\n }\n\n // Determine target origin\n let targetOrigin: string\n\n if (platformContext.value.platformOrigin) {\n // Use explicitly configured platform origin\n targetOrigin = platformContext.value.platformOrigin\n } else if (allowedOrigins.size > 0) {\n // Use first allowed origin (typically the platform)\n targetOrigin = allowedOrigins.values().next().value as string\n } else if (allowAnyOrigin) {\n // Development mode fallback\n targetOrigin = '*'\n console.warn('[MINT SDK] Using wildcard origin for postMessage - only use in development')\n } else {\n // Safety: if no origin is configured, log warning and don't send\n console.warn('[MINT SDK] Cannot send postMessage: no platform origin configured')\n return\n }\n\n window.parent.postMessage(event, targetOrigin)\n }\n\n /**\n * Request navigation to a path in the platform.\n */\n function navigate(path: string): void {\n sendToPlatform({\n type: 'mint:navigate',\n payload: path,\n })\n }\n\n /**\n * Show a notification in the platform.\n */\n function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n sendToPlatform({\n type: 'mint:notification',\n payload: { message, type },\n })\n }\n\n onMounted(() => {\n consumerOrigins.set(consumerId, instanceOrigins)\n if (instanceAllowAnyOrigin) {\n allowAnyOriginConsumers.add(consumerId)\n }\n\n if (!initialized) {\n detectPlatform()\n currentHandler = handlePlatformMessage\n window.addEventListener('message', handlePlatformMessage)\n initialized = true\n }\n\n listenerCount++\n recomputeOriginPolicy()\n })\n\n onUnmounted(() => {\n consumerOrigins.delete(consumerId)\n allowAnyOriginConsumers.delete(consumerId)\n\n listenerCount = Math.max(0, listenerCount - 1)\n if (listenerCount === 0) {\n if (currentHandler) {\n window.removeEventListener('message', currentHandler)\n }\n resetPlatformContextState()\n return\n }\n\n recomputeOriginPolicy()\n })\n\n const isIntegrated = computed(() => platformContext.value.isIntegrated)\n const plugin = computed(() => platformContext.value.plugin)\n const user = computed(() => platformContext.value.user)\n const theme = computed(() => platformContext.value.theme)\n const features = computed(() => platformContext.value.features)\n\n return {\n context: platformContext,\n isIntegrated,\n plugin,\n user,\n theme,\n features,\n navigate,\n notify,\n sendToPlatform,\n }\n}\n","import {\n ref,\n computed,\n readonly,\n provide,\n toValue,\n watch,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\nimport { resolveExperimentCode } from './experiment-utils'\n\nexport type AppExperimentRecord = Pick<ExperimentSummary, 'id' | 'name' | 'status' | 'experiment_code'>\n\nexport type AppExperimentSource =\n | AppExperimentRecord\n | null\n | undefined\n | Ref<AppExperimentRecord | null | undefined>\n | ComputedRef<AppExperimentRecord | null | undefined>\n | (() => AppExperimentRecord | null | undefined)\n\nexport interface UseAppExperimentOptions {\n /** Current experiment source to mirror into the app shell. Accepts a value, ref, computed, or getter. */\n experiment?: AppExperimentSource\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n}\n\nexport interface AppExperimentPopoverBinding {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: ExperimentStatus\n showSave: boolean\n showDetach: boolean\n saveDisabled: boolean\n saveDisabledMessage?: string\n saveLoading: boolean\n saveSuccessMessage?: string\n}\n\nexport interface AppExperimentSelectorModalBinding {\n modelValue: boolean\n currentExperimentId: number | null\n}\n\nexport interface UseAppExperimentReturn {\n set: (experiment: AppExperimentRecord) => void\n clear: () => void\n experimentName: Readonly<Ref<string | undefined>>\n experimentCode: Readonly<Ref<string | undefined>>\n experimentStatus: Readonly<Ref<ExperimentStatus | undefined>>\n experimentId: Readonly<Ref<number | null>>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n closeModal: () => void\n handleSelect: (experiment: ExperimentSummary) => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport interface AppExperimentState {\n experimentName: Ref<string | undefined>\n experimentCode: Ref<string | undefined>\n experimentStatus: Ref<ExperimentStatus | undefined>\n experimentId: Ref<number | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n handleSelect: (experiment: ExperimentSummary) => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\n/** Manages the current experiment selection, save flow, and detach action for a plugin's AppTopBar app shell. */\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const experimentName = ref<string | undefined>()\n const experimentCode = ref<string | undefined>()\n const experimentStatus = ref<ExperimentStatus | undefined>()\n const experimentId = ref<number | null>(null)\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n const popover = computed<AppExperimentPopoverBinding>(() => ({\n experimentName: experimentName.value,\n experimentCode: experimentCode.value,\n experimentStatus: experimentStatus.value,\n showSave: showSave.value,\n showDetach: showDetach.value,\n saveDisabled: saveDisabled.value,\n saveDisabledMessage: saveDisabledMessage.value,\n saveLoading: saveLoading.value,\n saveSuccessMessage: saveSuccessMessage.value,\n }))\n const selectorModal = computed<AppExperimentSelectorModalBinding>(() => ({\n modelValue: showModal.value,\n currentExperimentId: experimentId.value,\n }))\n\n function set(experiment: AppExperimentRecord) {\n experimentId.value = experiment.id\n experimentName.value = experiment.name\n experimentCode.value = resolveExperimentCode(experiment)\n experimentStatus.value = experiment.status\n }\n\n function clear() {\n experimentId.value = null\n experimentName.value = undefined\n experimentCode.value = undefined\n experimentStatus.value = undefined\n }\n\n if (options.experiment !== undefined) {\n watch(\n () => toValue(options.experiment),\n (experiment) => {\n if (experiment) {\n set(experiment)\n } else {\n clear()\n }\n },\n { immediate: true },\n )\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n function handleSelect(experiment: ExperimentSummary) {\n set(experiment)\n showModal.value = false\n options.onSelect?.(experiment)\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSelect,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n set,\n clear,\n experimentName: readonly(experimentName),\n experimentCode: readonly(experimentCode),\n experimentStatus: readonly(experimentStatus),\n experimentId: readonly(experimentId),\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSelect,\n handleSave,\n handleDetach,\n }\n}\n","import {\n useConcentrationUnits,\n type ConcentrationValue,\n type MolarityUnit,\n type MassVolumeUnit,\n} from './useConcentrationUnits'\n\n// Volume units\nexport type VolumeUnit = 'µL' | 'mL' | 'L'\n\nexport interface VolumeValue {\n value: number\n unit: VolumeUnit\n}\n\n// Dilution calculation types\nexport interface DilutionParams {\n stockConcentration: ConcentrationValue\n finalConcentration: ConcentrationValue\n finalVolume: VolumeValue\n}\n\nexport interface DilutionResult {\n stockVolume: VolumeValue\n diluentVolume: VolumeValue\n dilutionFactor: number\n valid: boolean\n error?: string\n}\n\n// Serial dilution types\nexport interface SerialDilutionParams {\n startingConcentration: ConcentrationValue\n dilutionFactor: number\n numberOfDilutions: number\n volumePerWell: VolumeValue\n}\n\nexport interface SerialDilutionStep {\n stepNumber: number\n concentration: ConcentrationValue\n transferVolume: VolumeValue\n diluentVolume: VolumeValue\n}\n\nexport interface SerialDilutionResult {\n steps: SerialDilutionStep[]\n totalStockVolume: VolumeValue\n valid: boolean\n error?: string\n}\n\n// Conversion types\nexport interface ConversionResult {\n result: ConcentrationValue\n valid: boolean\n error?: string\n}\n\n// Well concentration for plate integration\nexport interface WellConcentration {\n wellId: string\n concentration: ConcentrationValue\n volume?: VolumeValue\n}\n\nexport interface UseDoseCalculatorReturn {\n volumeUnits: VolumeUnit[]\n calculateDilution: (params: DilutionParams) => DilutionResult\n calculateSerialDilution: (params: SerialDilutionParams) => SerialDilutionResult\n convertMassToMolar: (\n mass: number,\n massUnit: MassVolumeUnit,\n mw: number\n ) => ConcentrationValue\n convertMolarToMass: (\n molar: number,\n molarUnit: MolarityUnit,\n mw: number\n ) => ConcentrationValue\n convertVolume: (value: number, from: VolumeUnit, to: VolumeUnit) => number\n formatVolume: (volume: VolumeValue, precision?: number) => string\n generateWellConcentrations: (\n result: SerialDilutionResult,\n wellIds: string[]\n ) => WellConcentration[]\n}\n\nconst VOLUME_UNITS: VolumeUnit[] = ['µL', 'mL', 'L']\n\nconst VOLUME_FACTORS: Record<VolumeUnit, number> = {\n 'µL': 1e-6,\n 'mL': 1e-3,\n 'L': 1,\n}\n\n/** Calculates single dilutions, serial dilution series, and plate-filling volumes for dose-response experiments. */\nexport function useDoseCalculator(): UseDoseCalculatorReturn {\n const { convert } = useConcentrationUnits()\n\n function convertVolume(value: number, from: VolumeUnit, to: VolumeUnit): number {\n if (from === to) return value\n const baseValue = value * VOLUME_FACTORS[from]\n return baseValue / VOLUME_FACTORS[to]\n }\n\n function formatVolume(volume: VolumeValue, precision: number = 3): string {\n const { value, unit } = volume\n if (value === 0) return `0 ${unit}`\n\n let formattedValue: string\n if (Math.abs(value) >= 1000) {\n formattedValue = value.toExponential(precision - 1)\n } else if (Math.abs(value) < 0.001) {\n formattedValue = value.toExponential(precision - 1)\n } else {\n formattedValue = value.toPrecision(precision)\n }\n\n // Remove trailing zeros\n formattedValue = formattedValue.replace(/\\.?0+$/, '')\n formattedValue = formattedValue.replace(/\\.?0+e/, 'e')\n\n return `${formattedValue} ${unit}`\n }\n\n function calculateDilution(params: DilutionParams): DilutionResult {\n const { stockConcentration, finalConcentration, finalVolume } = params\n\n // Validate inputs\n if (stockConcentration.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Stock concentration must be positive',\n }\n }\n\n if (finalConcentration.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Final concentration must be positive',\n }\n }\n\n if (finalVolume.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Final volume must be positive',\n }\n }\n\n // Convert concentrations to same unit\n const convertedFinal = convert(\n finalConcentration.value,\n finalConcentration.unit,\n stockConcentration.unit\n )\n\n if (convertedFinal === null) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Cannot convert between concentration units. Provide molecular weight for mass↔molarity conversion.',\n }\n }\n\n // Check that stock is more concentrated than final\n if (convertedFinal >= stockConcentration.value) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Stock concentration must be higher than final concentration',\n }\n }\n\n // Calculate using C1V1 = C2V2\n const dilutionFactor = stockConcentration.value / convertedFinal\n const finalVolumeInL = convertVolume(finalVolume.value, finalVolume.unit, 'L')\n const stockVolumeInL = finalVolumeInL / dilutionFactor\n const diluentVolumeInL = finalVolumeInL - stockVolumeInL\n\n // Convert to appropriate unit (µL for small volumes, mL for larger)\n let outputUnit: VolumeUnit = 'µL'\n if (stockVolumeInL >= 0.001) outputUnit = 'mL'\n if (stockVolumeInL >= 1) outputUnit = 'L'\n\n return {\n stockVolume: {\n value: convertVolume(stockVolumeInL, 'L', outputUnit),\n unit: outputUnit,\n },\n diluentVolume: {\n value: convertVolume(diluentVolumeInL, 'L', outputUnit),\n unit: outputUnit,\n },\n dilutionFactor,\n valid: true,\n }\n }\n\n function calculateSerialDilution(params: SerialDilutionParams): SerialDilutionResult {\n const { startingConcentration, dilutionFactor, numberOfDilutions, volumePerWell } = params\n\n // Validate inputs\n if (startingConcentration.value <= 0) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Starting concentration must be positive',\n }\n }\n\n if (dilutionFactor <= 1) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Dilution factor must be greater than 1',\n }\n }\n\n if (numberOfDilutions < 1) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Number of dilutions must be at least 1',\n }\n }\n\n if (volumePerWell.value <= 0) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Volume per well must be positive',\n }\n }\n\n const steps: SerialDilutionStep[] = []\n let currentConcentration = startingConcentration.value\n const transferVolume = volumePerWell.value / (dilutionFactor - 1)\n const diluentVolume = volumePerWell.value - transferVolume\n\n for (let i = 0; i < numberOfDilutions; i++) {\n steps.push({\n stepNumber: i + 1,\n concentration: {\n value: currentConcentration,\n unit: startingConcentration.unit,\n },\n transferVolume: {\n value: i === 0 ? volumePerWell.value : transferVolume,\n unit: volumePerWell.unit,\n },\n diluentVolume: {\n value: i === 0 ? 0 : diluentVolume,\n unit: volumePerWell.unit,\n },\n })\n currentConcentration /= dilutionFactor\n }\n\n // Total stock needed for first well\n const totalStockVolume: VolumeValue = {\n value: volumePerWell.value + (transferVolume * (numberOfDilutions - 1)),\n unit: volumePerWell.unit,\n }\n\n return {\n steps,\n totalStockVolume,\n valid: true,\n }\n }\n\n function convertMassToMolar(\n mass: number,\n massUnit: MassVolumeUnit,\n mw: number\n ): ConcentrationValue {\n // Convert mass to g/mL, then to M using MW\n const converted = convert(mass, massUnit, 'µM', mw)\n if (converted !== null) {\n return { value: converted, unit: 'µM' }\n }\n // Fallback to manual calculation\n // mass (g/mL) / MW (g/mol) = mol/L = M\n const massInGML = mass * getMassVolumeFactor(massUnit)\n const molarConc = massInGML / mw\n return { value: molarConc * 1e6, unit: 'µM' }\n }\n\n function convertMolarToMass(\n molar: number,\n molarUnit: MolarityUnit,\n mw: number\n ): ConcentrationValue {\n // Convert M to mass using MW\n const converted = convert(molar, molarUnit, 'µg/mL', mw)\n if (converted !== null) {\n return { value: converted, unit: 'µg/mL' }\n }\n // Fallback to manual calculation\n // mol/L * MW (g/mol) = g/L = mg/mL\n const molarInM = molar * getMolarityFactor(molarUnit)\n const massConc = molarInM * mw * 1e6 // µg/mL\n return { value: massConc, unit: 'µg/mL' }\n }\n\n function getMassVolumeFactor(unit: MassVolumeUnit): number {\n const factors: Record<MassVolumeUnit, number> = {\n 'pg/mL': 1e-12,\n 'ng/mL': 1e-9,\n 'µg/mL': 1e-6,\n 'mg/mL': 1e-3,\n 'g/mL': 1,\n }\n return factors[unit]\n }\n\n function getMolarityFactor(unit: MolarityUnit): number {\n const factors: Record<MolarityUnit, number> = {\n 'pM': 1e-12,\n 'nM': 1e-9,\n 'µM': 1e-6,\n 'mM': 1e-3,\n 'M': 1,\n }\n return factors[unit]\n }\n\n function generateWellConcentrations(\n result: SerialDilutionResult,\n wellIds: string[]\n ): WellConcentration[] {\n if (!result.valid || result.steps.length === 0) return []\n\n return result.steps.slice(0, wellIds.length).map((step, index) => ({\n wellId: wellIds[index],\n concentration: step.concentration,\n volume: step.transferVolume,\n }))\n }\n\n return {\n volumeUnits: VOLUME_UNITS,\n calculateDilution,\n calculateSerialDilution,\n convertMassToMolar,\n convertMolarToMass,\n convertVolume,\n formatVolume,\n generateWellConcentrations,\n }\n}\n","import { ref, computed, toRaw, type ComputedRef } from 'vue'\nimport type {\n PlateMapEditorState,\n PlateMap,\n SampleType,\n WellPlateFormat,\n} from '../types'\n\nconst DEFAULT_PALETTE = [\n '#3B82F6', // blue\n '#10B981', // green\n '#EF4444', // red\n '#F59E0B', // amber\n '#8B5CF6', // purple\n '#F97316', // orange\n '#06B6D4', // cyan\n '#14B8A6', // teal\n '#6B7280', // gray\n]\n\nconst MAX_HISTORY = 50\n\ninterface HistoryEntry {\n plates: PlateMap[]\n samples: SampleType[]\n}\n\nexport interface UseWellPlateEditorOptions {\n maxHistory?: number\n defaultFormat?: WellPlateFormat\n}\n\nexport interface UseWellPlateEditorReturn {\n state: ComputedRef<PlateMapEditorState>\n plates: ComputedRef<PlateMap[]>\n activePlate: ComputedRef<PlateMap | undefined>\n samples: ComputedRef<SampleType[]>\n selectedWells: ComputedRef<string[]>\n activeSampleId: ComputedRef<string | undefined>\n canUndo: ComputedRef<boolean>\n canRedo: ComputedRef<boolean>\n setActivePlate: (plateId: string) => void\n setActiveSample: (sampleId: string | undefined) => void\n setSelectedWells: (wellIds: string[]) => void\n addPlate: (name?: string, format?: WellPlateFormat) => PlateMap\n removePlate: (plateId: string) => void\n addSample: (name: string, color?: string) => SampleType\n removeSample: (sampleId: string) => void\n assignSample: (wellIds: string[], sampleId: string | undefined) => void\n clearWells: (wellIds: string[]) => void\n undo: () => void\n redo: () => void\n exportData: (format: 'json' | 'csv') => string\n importData: (data: string, format: 'json' | 'csv') => boolean\n loadState: (state: Partial<PlateMapEditorState>) => void\n reset: () => void\n}\n\nfunction createEmptyPlate(\n name: string,\n format: WellPlateFormat,\n id?: string\n): PlateMap {\n return {\n id: id || `plate-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n name,\n format,\n wells: {},\n }\n}\n\nfunction generateSampleId(): string {\n return `sample-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\nfunction cloneValue<T>(value: T): T {\n return structuredClone(toRaw(value))\n}\n\n/** Manages multi-plate well-plate state with sample assignment, selection, and undo/redo history. */\nexport function useWellPlateEditor(\n initialState?: Partial<PlateMapEditorState>,\n options: UseWellPlateEditorOptions = {}\n): UseWellPlateEditorReturn {\n const { maxHistory = MAX_HISTORY, defaultFormat = 96 } = options\n\n const defaultPlate = createEmptyPlate('Plate 1', defaultFormat)\n\n const internalState = ref<PlateMapEditorState>({\n plates: initialState?.plates || [defaultPlate],\n activePlateId: initialState?.activePlateId || defaultPlate.id,\n samples: initialState?.samples || [],\n selectedWells: initialState?.selectedWells || [],\n activeSampleId: initialState?.activeSampleId,\n })\n\n const history = ref<HistoryEntry[]>([])\n const historyIndex = ref(-1)\n\n const state = computed(() => internalState.value)\n const plates = computed(() => internalState.value.plates)\n const activePlate = computed(() =>\n internalState.value.plates.find(p => p.id === internalState.value.activePlateId)\n )\n const samples = computed(() => internalState.value.samples)\n const selectedWells = computed(() => internalState.value.selectedWells)\n const activeSampleId = computed(() => internalState.value.activeSampleId)\n\n const canUndo = computed(() => historyIndex.value >= 0)\n const canRedo = computed(() => historyIndex.value < history.value.length - 1)\n\n function saveToHistory() {\n const entry: HistoryEntry = {\n plates: cloneValue(internalState.value.plates),\n samples: cloneValue(internalState.value.samples),\n }\n\n if (historyIndex.value < history.value.length - 1) {\n history.value = history.value.slice(0, historyIndex.value + 1)\n }\n\n history.value.push(entry)\n\n if (history.value.length > maxHistory) {\n history.value.shift()\n } else {\n historyIndex.value++\n }\n }\n\n function setActivePlate(plateId: string) {\n if (internalState.value.plates.some(p => p.id === plateId)) {\n internalState.value.activePlateId = plateId\n internalState.value.selectedWells = []\n }\n }\n\n function setActiveSample(sampleId: string | undefined) {\n internalState.value.activeSampleId = sampleId\n }\n\n function setSelectedWells(wellIds: string[]) {\n internalState.value.selectedWells = wellIds\n }\n\n function addPlate(name?: string, format?: WellPlateFormat): PlateMap {\n saveToHistory()\n const plateNumber = internalState.value.plates.length + 1\n const plate = createEmptyPlate(\n name || `Plate ${plateNumber}`,\n format || defaultFormat\n )\n internalState.value.plates.push(plate)\n internalState.value.activePlateId = plate.id\n internalState.value.selectedWells = []\n return plate\n }\n\n function removePlate(plateId: string) {\n if (internalState.value.plates.length <= 1) return\n\n saveToHistory()\n const index = internalState.value.plates.findIndex(p => p.id === plateId)\n if (index === -1) return\n\n internalState.value.plates.splice(index, 1)\n if (internalState.value.activePlateId === plateId) {\n internalState.value.activePlateId = internalState.value.plates[0].id\n internalState.value.selectedWells = []\n }\n }\n\n function addSample(name: string, color?: string): SampleType {\n saveToHistory()\n const sample: SampleType = {\n id: generateSampleId(),\n name,\n color: color || DEFAULT_PALETTE[internalState.value.samples.length % DEFAULT_PALETTE.length],\n count: 0,\n }\n internalState.value.samples.push(sample)\n return sample\n }\n\n function removeSample(sampleId: string) {\n saveToHistory()\n const index = internalState.value.samples.findIndex(s => s.id === sampleId)\n if (index === -1) return\n\n internalState.value.samples.splice(index, 1)\n\n for (const plate of internalState.value.plates) {\n for (const well of Object.values(plate.wells)) {\n if (well.sampleType === sampleId) {\n delete well.sampleType\n well.state = 'empty'\n }\n }\n }\n\n if (internalState.value.activeSampleId === sampleId) {\n internalState.value.activeSampleId = undefined\n }\n\n updateSampleCounts()\n }\n\n function assignSample(wellIds: string[], sampleId: string | undefined) {\n if (wellIds.length === 0) return\n\n saveToHistory()\n const plate = activePlate.value\n if (!plate) return\n\n for (const wellId of wellIds) {\n const well = plate.wells[wellId] || {\n id: wellId,\n row: wellId.charCodeAt(0) - 65,\n col: parseInt(wellId.slice(1)) - 1,\n state: 'empty',\n }\n\n if (sampleId) {\n well.sampleType = sampleId\n well.state = 'filled'\n } else {\n delete well.sampleType\n well.state = 'empty'\n }\n\n plate.wells[wellId] = well\n }\n updateSampleCounts()\n }\n\n function clearWells(wellIds: string[]) {\n assignSample(wellIds, undefined)\n }\n\n function updateSampleCounts() {\n const counts: Record<string, number> = {}\n\n for (const plate of internalState.value.plates) {\n for (const well of Object.values(plate.wells)) {\n if (well.sampleType) {\n counts[well.sampleType] = (counts[well.sampleType] || 0) + 1\n }\n }\n }\n\n for (const sample of internalState.value.samples) {\n sample.count = counts[sample.id] || 0\n }\n }\n\n function undo() {\n if (!canUndo.value) return\n\n const entry = history.value[historyIndex.value]\n historyIndex.value--\n\n internalState.value.plates = cloneValue(entry.plates)\n internalState.value.samples = cloneValue(entry.samples)\n\n const activePlateExists = internalState.value.plates.some(p => p.id === internalState.value.activePlateId)\n if (!activePlateExists) {\n internalState.value.activePlateId = internalState.value.plates[0]?.id || ''\n }\n internalState.value.selectedWells = []\n }\n\n function redo() {\n if (!canRedo.value) return\n\n historyIndex.value++\n const entry = history.value[historyIndex.value]\n\n internalState.value.plates = cloneValue(entry.plates)\n internalState.value.samples = cloneValue(entry.samples)\n internalState.value.selectedWells = []\n }\n\n function exportData(format: 'json' | 'csv'): string {\n if (format === 'json') {\n return JSON.stringify({\n plates: internalState.value.plates,\n samples: internalState.value.samples,\n }, null, 2)\n }\n\n const sampleMap = new Map(internalState.value.samples.map(s => [s.id, s.name]))\n const rows = ['Plate,Well,Sample Type,Sample Name']\n\n for (const plate of internalState.value.plates) {\n for (const [wellId, well] of Object.entries(plate.wells)) {\n if (well.sampleType) {\n const sampleName = sampleMap.get(well.sampleType) || ''\n rows.push(`\"${plate.name}\",\"${wellId}\",\"${well.sampleType}\",\"${sampleName}\"`)\n }\n }\n }\n\n return rows.join('\\n')\n }\n\n function importData(data: string, format: 'json' | 'csv'): boolean {\n try {\n saveToHistory()\n\n if (format === 'json') {\n const parsed = JSON.parse(data)\n if (parsed.plates && Array.isArray(parsed.plates)) {\n internalState.value.plates = parsed.plates\n internalState.value.activePlateId = parsed.plates[0]?.id || ''\n }\n if (parsed.samples && Array.isArray(parsed.samples)) {\n internalState.value.samples = parsed.samples\n }\n internalState.value.selectedWells = []\n updateSampleCounts()\n return true\n }\n\n const lines = data.trim().split('\\n')\n if (lines.length < 2) return false\n\n const plateMap = new Map<string, PlateMap>()\n const sampleMap = new Map<string, SampleType>()\n\n for (let i = 1; i < lines.length; i++) {\n const parts = lines[i].match(/(?:[^\",]+|\"[^\"]*\")+/g)\n if (!parts || parts.length < 4) continue\n\n const plateName = parts[0].replace(/^\"|\"$/g, '')\n const wellId = parts[1].replace(/^\"|\"$/g, '')\n const sampleId = parts[2].replace(/^\"|\"$/g, '')\n const sampleName = parts[3].replace(/^\"|\"$/g, '')\n\n if (!plateMap.has(plateName)) {\n plateMap.set(plateName, createEmptyPlate(plateName, defaultFormat))\n }\n\n if (sampleId && !sampleMap.has(sampleId)) {\n sampleMap.set(sampleId, {\n id: sampleId,\n name: sampleName || sampleId,\n color: DEFAULT_PALETTE[sampleMap.size % DEFAULT_PALETTE.length],\n count: 0,\n })\n }\n\n const plate = plateMap.get(plateName)!\n plate.wells[wellId] = {\n id: wellId,\n row: wellId.charCodeAt(0) - 65,\n col: parseInt(wellId.slice(1)) - 1,\n state: sampleId ? 'filled' : 'empty',\n sampleType: sampleId || undefined,\n }\n }\n\n internalState.value.plates = Array.from(plateMap.values())\n internalState.value.samples = Array.from(sampleMap.values())\n internalState.value.activePlateId = internalState.value.plates[0]?.id || ''\n internalState.value.selectedWells = []\n updateSampleCounts()\n return true\n } catch {\n return false\n }\n }\n\n function loadState(state: Partial<PlateMapEditorState>) {\n saveToHistory()\n if (state.plates && state.plates.length > 0) {\n internalState.value.plates = cloneValue(state.plates)\n internalState.value.activePlateId = state.activePlateId ?? state.plates[0].id\n }\n if (state.samples) {\n internalState.value.samples = cloneValue(state.samples)\n }\n internalState.value.selectedWells = state.selectedWells ?? []\n internalState.value.activeSampleId = state.activeSampleId\n updateSampleCounts()\n }\n\n function reset() {\n const plate = createEmptyPlate('Plate 1', defaultFormat)\n internalState.value = {\n plates: [plate],\n activePlateId: plate.id,\n samples: [],\n selectedWells: [],\n activeSampleId: undefined,\n }\n history.value = []\n historyIndex.value = -1\n }\n\n return {\n state,\n plates,\n activePlate,\n samples,\n selectedWells,\n activeSampleId,\n canUndo,\n canRedo,\n setActivePlate,\n setActiveSample,\n setSelectedWells,\n addPlate,\n removePlate,\n addSample,\n removeSample,\n assignSample,\n clearWells,\n undo,\n redo,\n exportData,\n importData,\n loadState,\n reset,\n }\n}\n","import { ref, computed } from 'vue'\nimport type {\n InputMode,\n OutlierAction,\n OutlierInfo,\n ColumnInfo,\n MetadataRow,\n AutoGroupResult,\n ParsedCsvData,\n} from '../types/auto-group'\nimport type { SampleGroup } from '../types/components'\n\nexport const DEFAULT_COLORS = [\n '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',\n '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',\n]\n\nconst DELIMITER_CANDIDATES = ['_', '-', '.'] as const\n\n// --- Pure functions (exported for testing) ---\n\nexport function analyzeDelimiter(lines: string[]): {\n delimiter: string\n dominantFieldCount: number\n minFieldCount: number\n consistency: number\n} {\n if (lines.length === 0) {\n return { delimiter: '_', dominantFieldCount: 1, minFieldCount: 1, consistency: 0 }\n }\n\n let bestDelimiter = '_'\n let bestConsistency = -1\n let bestFieldCount = 1\n\n for (const candidate of DELIMITER_CANDIDATES) {\n const fieldCounts = lines.map(line => line.split(candidate).length)\n const countFrequency = new Map<number, number>()\n\n for (const count of fieldCounts) {\n countFrequency.set(count, (countFrequency.get(count) ?? 0) + 1)\n }\n\n // Find mode (most frequent field count)\n let modeCount = 1\n let modeFrequency = 0\n for (const [count, freq] of countFrequency) {\n if (freq > modeFrequency || (freq === modeFrequency && count > modeCount)) {\n modeCount = count\n modeFrequency = freq\n }\n }\n\n const rawConsistency = modeFrequency / lines.length\n // A delimiter that produces field count 1 didn't actually split anything\n const consistency = modeCount > 1 ? rawConsistency : 0\n\n if (\n consistency > bestConsistency ||\n (consistency === bestConsistency &&\n DELIMITER_CANDIDATES.indexOf(candidate) < DELIMITER_CANDIDATES.indexOf(bestDelimiter as typeof candidate))\n ) {\n bestDelimiter = candidate\n bestConsistency = consistency\n bestFieldCount = modeCount\n }\n }\n\n const bestFieldCounts = lines.map(line => line.split(bestDelimiter).length)\n const multiFieldCounts = bestFieldCounts.filter(c => c >= 2)\n const minFieldCount = multiFieldCounts.length > 0 ? Math.min(...multiFieldCounts) : 1\n\n return {\n delimiter: bestDelimiter,\n dominantFieldCount: bestFieldCount,\n minFieldCount,\n consistency: bestConsistency,\n }\n}\n\nexport function detectOutliers(\n lines: string[],\n delimiter: string,\n minFieldCount: number,\n): OutlierInfo[] {\n const outliers: OutlierInfo[] = []\n\n for (let i = 0; i < lines.length; i++) {\n const fieldCount = lines[i].split(delimiter).length\n if (fieldCount < minFieldCount) {\n outliers.push({\n sample: lines[i],\n index: i,\n fieldCount,\n action: 'include',\n })\n }\n }\n\n return outliers\n}\n\nconst QC_KEYWORDS = new Set([\n 'eqc', 'iqc', 'qc', 'blank', 'std', 'standard', 'test',\n])\n\nexport function classifyOutlierAction(\n sample: string,\n delimiter: string,\n): OutlierAction {\n const segments = sample.split(delimiter)\n return segments.some(seg => QC_KEYWORDS.has(seg.toLowerCase()))\n ? 'qc'\n : 'include'\n}\n\n// A column is useful for grouping when it has more than one distinct value\n// AND it does not produce a unique value per row (which would create N\n// singleton groups instead of meaningful aggregation).\nexport function isUsefulField(field: ColumnInfo, rowCount: number): boolean {\n return field.cardinality > 1 && !(rowCount > 1 && field.cardinality === rowCount)\n}\n\nexport function extractColumns(\n samples: string[],\n delimiter: string,\n minFieldCount: number,\n): ColumnInfo[] {\n if (samples.length === 0) return []\n\n const suffixCount = minFieldCount - 1\n const rows = samples.map(s => {\n const parts = s.split(delimiter)\n const splitAt = parts.length - suffixCount\n return [\n parts.slice(0, splitAt).join(delimiter),\n ...parts.slice(splitAt),\n ]\n })\n\n const columnCount = minFieldCount\n const columns: ColumnInfo[] = []\n for (let col = 0; col < columnCount; col++) {\n const values = rows.map(row => row[col])\n const unique = [...new Set(values)]\n columns.push({\n index: col,\n name: col === 0 ? 'Condition' : `Field ${col + 1}`,\n uniqueValues: unique,\n cardinality: unique.length,\n type: col === 0 ? 'prefix' : 'suffix',\n })\n }\n\n return columns\n}\n\nexport function parseCSVLine(line: string, delimiter: string = ','): string[] {\n const result: string[] = []\n let current = ''\n let inQuotes = false\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]\n if (char === '\"') {\n inQuotes = !inQuotes\n } else if (char === delimiter && !inQuotes) {\n result.push(current.trim())\n current = ''\n } else {\n current += char\n }\n }\n result.push(current.trim())\n\n return result\n}\n\nexport function parseCSV(text: string): ParsedCsvData {\n const lines = text.trim().split('\\n')\n if (lines.length < 2) {\n throw new Error('CSV must have at least a header and one data row')\n }\n\n // Auto-detect delimiter: tab takes precedence if present in header\n const firstLine = lines[0]\n const csvDelimiter = firstLine.includes('\\t') ? '\\t' : ','\n\n const headers = parseCSVLine(firstLine, csvDelimiter)\n const rows: Record<string, string>[] = []\n\n for (let i = 1; i < lines.length; i++) {\n const values = parseCSVLine(lines[i], csvDelimiter)\n if (values.length !== headers.length) continue\n const row: Record<string, string> = {}\n headers.forEach((header, idx) => {\n row[header] = values[idx]\n })\n rows.push(row)\n }\n\n // Auto-detect sample column\n const sampleKeywords = ['sample', 'name', 'id', 'sample_name', 'samplename', 'file name', 'filename', 'file_name']\n const sampleColumn =\n headers.find(h => sampleKeywords.includes(h.toLowerCase())) ?? headers[0]\n\n return { columns: headers, rows, sampleColumn, delimiter: csvDelimiter }\n}\n\nexport function computeGroups(\n allSamples: string[],\n columns: ColumnInfo[],\n enabledFields: Set<number>,\n outlierActions: Map<number, OutlierAction>,\n delimiter: string,\n minFieldCount: number,\n): { groups: SampleGroup[]; metadata: MetadataRow[]; excludedSamples: string[] } {\n const excludedSamples: string[] = []\n const qcSamples: string[] = []\n const conformingSamples: string[] = []\n\n for (let i = 0; i < allSamples.length; i++) {\n const action = outlierActions.get(i)\n if (action === 'exclude') {\n excludedSamples.push(allSamples[i])\n } else if (action === 'qc') {\n qcSamples.push(allSamples[i])\n } else {\n conformingSamples.push(allSamples[i])\n }\n }\n\n // Build group map\n const groupMap = new Map<string, string[]>()\n const metadata: MetadataRow[] = []\n const enabledIndices = [...enabledFields].sort((a, b) => a - b)\n\n const suffixCount = minFieldCount - 1\n\n for (const sample of conformingSamples) {\n const parts = sample.split(delimiter)\n const splitAt = Math.max(1, parts.length - suffixCount)\n const row = [\n parts.slice(0, splitAt).join(delimiter),\n ...parts.slice(splitAt),\n ]\n\n // Build group key from enabled columns\n const keyParts: string[] = []\n for (const idx of enabledIndices) {\n if (idx < row.length && idx < columns.length) {\n keyParts.push(row[idx])\n }\n }\n const groupKey = keyParts.join(' / ')\n\n if (!groupMap.has(groupKey)) {\n groupMap.set(groupKey, [])\n }\n groupMap.get(groupKey)!.push(sample)\n\n // Build metadata row with ALL columns\n const fields: Record<string, string> = {}\n for (const col of columns) {\n if (col.index < row.length) {\n fields[col.name] = row[col.index]\n }\n }\n metadata.push({ sampleName: sample, fields, group: groupKey })\n }\n\n // Convert to SampleGroup[]\n const groups: SampleGroup[] = []\n let colorIdx = 0\n for (const [name, samples] of groupMap) {\n groups.push({\n name,\n color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],\n samples,\n })\n colorIdx++\n }\n\n // QC group\n if (qcSamples.length > 0) {\n groups.push({\n name: 'QC',\n color: '#6B7280',\n samples: qcSamples,\n })\n for (const sample of qcSamples) {\n metadata.push({ sampleName: sample, fields: {}, group: 'QC' })\n }\n }\n\n return { groups, metadata, excludedSamples }\n}\n\n/**\n * Extract sample metadata from raw design_data into ParsedCsvData format.\n *\n * Looks for a `samples` array in the design data. For each sample, merges\n * the `conditions` dict (the metadata table) with the `sample_name` to\n * produce a flat tabular row. QC and blank samples are filtered out by\n * their explicit `sample_type` field.\n *\n * Returns null if no samples with conditions are found.\n */\nexport function extractSamplesFromDesignData(\n rawData: Record<string, unknown>,\n): ParsedCsvData | null {\n const samples = rawData.samples\n if (!Array.isArray(samples) || samples.length === 0) return null\n\n // Single pass: filter QC/blank and collect all condition keys\n const allConditionKeys: string[] = []\n const keySet = new Set<string>()\n const filteredSamples: Record<string, unknown>[] = []\n\n for (const sample of samples) {\n const sampleType = String((sample as Record<string, unknown>).sample_type ?? 'sample').toLowerCase()\n if (sampleType === 'qc' || sampleType === 'blank') continue\n\n filteredSamples.push(sample as Record<string, unknown>)\n const conditions = (sample as Record<string, unknown>).conditions as Record<string, string> | undefined\n if (conditions && typeof conditions === 'object') {\n for (const key of Object.keys(conditions)) {\n if (!keySet.has(key)) {\n keySet.add(key)\n allConditionKeys.push(key)\n }\n }\n }\n }\n\n if (filteredSamples.length === 0 || allConditionKeys.length === 0) return null\n\n const columns = ['sample_name', ...allConditionKeys]\n const rows: Record<string, string>[] = filteredSamples.map((sample) => {\n const conditions = (sample.conditions as Record<string, string>) ?? {}\n const row: Record<string, string> = {\n sample_name: String(sample.sample_name ?? ''),\n }\n for (const key of allConditionKeys) {\n row[key] = conditions[key] ?? ''\n }\n return row\n })\n\n return { columns, rows, sampleColumn: 'sample_name', delimiter: ',' }\n}\n\nexport function computeGroupsFromCsv(\n csvData: ParsedCsvData,\n columns: ColumnInfo[],\n enabledFields: Set<number>,\n): { groups: SampleGroup[]; metadata: MetadataRow[]; excludedSamples: string[] } {\n const groupMap = new Map<string, string[]>()\n const metadata: MetadataRow[] = []\n const enabledCols = columns\n .filter(c => enabledFields.has(c.index))\n .sort((a, b) => a.index - b.index)\n\n for (const row of csvData.rows) {\n const sampleName = row[csvData.sampleColumn]\n\n // Build group key from enabled CSV column values\n // Use originalName for CSV row lookup (survives user renames), display name for group key\n const keyParts = enabledCols.map(col => row[col.originalName ?? col.name])\n const groupKey = keyParts.join(' / ')\n\n if (!groupMap.has(groupKey)) {\n groupMap.set(groupKey, [])\n }\n groupMap.get(groupKey)!.push(sampleName)\n\n // Build metadata row with ALL columns — use display name as key, original for lookup\n const fields: Record<string, string> = {}\n for (const col of columns) {\n fields[col.name] = row[col.originalName ?? col.name]\n }\n metadata.push({ sampleName, fields, group: groupKey })\n }\n\n // Convert to SampleGroup[]\n const groups: SampleGroup[] = []\n let colorIdx = 0\n for (const [name, samples] of groupMap) {\n groups.push({\n name,\n color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],\n samples,\n })\n colorIdx++\n }\n\n return { groups, metadata, excludedSamples: [] }\n}\n\n// --- Reactive composable ---\n\n/** Parses sample names or CSV data to propose group assignments with outlier detection and preview. */\nexport function useAutoGroup() {\n const inputMode = ref<InputMode>('paste')\n const rawText = ref('')\n const csvData = ref<ParsedCsvData | null>(null)\n const delimiter = ref('_')\n const dominantFieldCount = ref(1)\n const minFieldCount = ref(1)\n const outliers = ref<OutlierInfo[]>([])\n const fields = ref<ColumnInfo[]>([])\n const fieldNames = ref<Record<number, string>>({})\n const enabledFields = ref(new Set<number>())\n\n const isTabularMode = computed(() =>\n (inputMode.value === 'csv' || inputMode.value === 'experiment') && csvData.value !== null,\n )\n\n const samples = computed(() => {\n if (isTabularMode.value && csvData.value) {\n return csvData.value.rows.map(r => r[csvData.value!.sampleColumn])\n }\n return rawText.value\n .split('\\n')\n .map(l => l.trim())\n .filter(l => l.length > 0)\n })\n\n const hasOutliers = computed(() => outliers.value.length > 0)\n\n const conformingSamples = computed(() => {\n const outlierIndices = new Set(outliers.value.map(o => o.index))\n return samples.value.filter((_, i) => !outlierIndices.has(i))\n })\n\n const outlierActions = computed(() => {\n const map = new Map<number, OutlierAction>()\n for (const o of outliers.value) {\n map.set(o.index, o.action)\n }\n return map\n })\n\n const effectiveColumns = computed(() => {\n return fields.value.map(col => ({\n ...col,\n name: fieldNames.value[col.index] ?? col.name,\n }))\n })\n\n const _computedResult = computed((): AutoGroupResult => {\n if (effectiveColumns.value.length === 0 || enabledFields.value.size === 0) {\n return { groups: [], metadata: [], excludedSamples: [] }\n }\n\n if (isTabularMode.value && csvData.value) {\n return computeGroupsFromCsv(\n csvData.value,\n effectiveColumns.value,\n enabledFields.value,\n )\n }\n\n return computeGroups(\n samples.value,\n effectiveColumns.value,\n enabledFields.value,\n outlierActions.value,\n delimiter.value,\n minFieldCount.value,\n )\n })\n\n const groups = computed(() => _computedResult.value.groups)\n const metadata = computed(() => _computedResult.value.metadata)\n const excludedSamples = computed(() => _computedResult.value.excludedSamples)\n\n const allSingletons = computed(() =>\n groups.value.length > 1 && groups.value.every(g => g.samples.length === 1),\n )\n\n const result = _computedResult\n\n function parseInput() {\n if (isTabularMode.value) {\n parseCsvInput()\n } else {\n parsePasteInput()\n }\n }\n\n function parsePasteInput() {\n const lines = samples.value\n if (lines.length === 0) return\n\n const analysis = analyzeDelimiter(lines)\n delimiter.value = analysis.delimiter\n dominantFieldCount.value = analysis.dominantFieldCount\n\n // Use dominantFieldCount as outlier threshold so QC/test samples with\n // fewer fields than the majority are correctly flagged\n outliers.value = detectOutliers(lines, analysis.delimiter, analysis.dominantFieldCount)\n\n // Apply smart default actions: auto-classify QC/test samples\n for (const outlier of outliers.value) {\n outlier.action = classifyOutlierAction(outlier.sample, analysis.delimiter)\n }\n\n const conforming = lines.filter(\n (_, i) => !outliers.value.some(o => o.index === i)\n )\n\n // Recompute minFieldCount from conforming samples only\n const conformingFieldCounts = conforming.map(s => s.split(analysis.delimiter).length)\n minFieldCount.value = conformingFieldCounts.length > 0\n ? Math.min(...conformingFieldCounts)\n : analysis.dominantFieldCount\n\n fields.value = extractColumns(conforming, analysis.delimiter, minFieldCount.value)\n\n fieldNames.value = {}\n const rowCount = conforming.length\n enabledFields.value = new Set(\n fields.value.filter(f => isUsefulField(f, rowCount)).map(f => f.index),\n )\n }\n\n function parseCsvInput() {\n if (!csvData.value) return\n\n const csv = csvData.value\n const nonSampleCols = csv.columns.filter(c => c !== csv.sampleColumn)\n\n fields.value = nonSampleCols.map((col, i) => {\n const values = csv.rows.map(r => r[col])\n const unique = [...new Set(values)]\n return {\n index: i,\n name: col,\n originalName: col,\n uniqueValues: unique,\n cardinality: unique.length,\n }\n })\n\n // For CSV, no outliers\n outliers.value = []\n delimiter.value = csv.delimiter\n dominantFieldCount.value = csv.columns.length\n\n fieldNames.value = Object.fromEntries(fields.value.map(f => [f.index, f.name]))\n const rowCount = csv.rows.length\n enabledFields.value = new Set(\n fields.value.filter(f => isUsefulField(f, rowCount)).map(f => f.index),\n )\n }\n\n function setOutlierAction(index: number, action: OutlierAction) {\n const outlier = outliers.value.find(o => o.index === index)\n if (outlier) {\n outlier.action = action\n // Trigger reactivity\n outliers.value = [...outliers.value]\n }\n }\n\n function setAllOutlierActions(action: OutlierAction) {\n for (const outlier of outliers.value) {\n outlier.action = action\n }\n outliers.value = [...outliers.value]\n }\n\n function toggleField(index: number) {\n const newSet = new Set(enabledFields.value)\n if (newSet.has(index)) {\n newSet.delete(index)\n } else {\n newSet.add(index)\n }\n enabledFields.value = newSet\n }\n\n function renameField(index: number, name: string) {\n fieldNames.value = { ...fieldNames.value, [index]: name }\n }\n\n function loadExperimentData(rawData: Record<string, unknown>): boolean {\n const parsed = extractSamplesFromDesignData(rawData)\n if (!parsed) return false\n\n inputMode.value = 'experiment'\n csvData.value = parsed\n parseCsvInput()\n return true\n }\n\n function reset() {\n rawText.value = ''\n csvData.value = null\n delimiter.value = '_'\n dominantFieldCount.value = 1\n minFieldCount.value = 1\n outliers.value = []\n fields.value = []\n fieldNames.value = {}\n enabledFields.value = new Set()\n }\n\n return {\n // State\n inputMode,\n rawText,\n csvData,\n delimiter,\n dominantFieldCount,\n minFieldCount,\n outliers,\n fields,\n fieldNames,\n enabledFields,\n // Computed\n samples,\n hasOutliers,\n conformingSamples,\n groups,\n metadata,\n excludedSamples,\n allSingletons,\n result,\n effectiveColumns,\n // Actions\n parseInput,\n loadExperimentData,\n setOutlierAction,\n setAllOutlierActions,\n toggleField,\n renameField,\n reset,\n }\n}\n","/**\n * Color utilities for deriving same-hue-family shades.\n *\n * Used by SampleSelector and other group/legend UIs where a parent color\n * needs to seed a gradient of related shades for its children.\n */\n\nexport interface Hsl {\n h: number // 0–360\n s: number // 0–100\n l: number // 0–100\n}\n\nconst HEX_RE = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n))\n}\n\nexport function hexToHsl(hex: string): Hsl {\n const match = HEX_RE.exec(hex.trim())\n if (!match) return { h: 0, s: 0, l: 50 }\n\n let raw = match[1]\n if (raw.length === 3) raw = raw.split('').map(c => c + c).join('')\n\n const r = parseInt(raw.slice(0, 2), 16) / 255\n const g = parseInt(raw.slice(2, 4), 16) / 255\n const b = parseInt(raw.slice(4, 6), 16) / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const delta = max - min\n\n let h = 0\n if (delta !== 0) {\n if (max === r) h = ((g - b) / delta) % 6\n else if (max === g) h = (b - r) / delta + 2\n else h = (r - g) / delta + 4\n }\n h = (h * 60 + 360) % 360\n\n const l = (max + min) / 2\n const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1))\n\n return { h, s: s * 100, l: l * 100 }\n}\n\nexport function hslToHex(h: number, s: number, l: number): string {\n const sNorm = clamp(s, 0, 100) / 100\n const lNorm = clamp(l, 0, 100) / 100\n const hNorm = ((h % 360) + 360) % 360\n\n const c = (1 - Math.abs(2 * lNorm - 1)) * sNorm\n const x = c * (1 - Math.abs(((hNorm / 60) % 2) - 1))\n const m = lNorm - c / 2\n\n let r = 0, g = 0, b = 0\n if (hNorm < 60) [r, g, b] = [c, x, 0]\n else if (hNorm < 120) [r, g, b] = [x, c, 0]\n else if (hNorm < 180) [r, g, b] = [0, c, x]\n else if (hNorm < 240) [r, g, b] = [0, x, c]\n else if (hNorm < 300) [r, g, b] = [x, 0, c]\n else [r, g, b] = [c, 0, x]\n\n const toHex = (n: number) => Math.round((n + m) * 255).toString(16).padStart(2, '0')\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`\n}\n\n/**\n * Derive a same-hue-family shade of `parentHex` for child at `index` of `total`.\n *\n * Lightness is distributed evenly within [35, 75] so all children remain\n * readable on light/dark backgrounds. Hue and saturation are inherited from\n * the parent. With `total <= 1`, returns the parent unchanged.\n *\n * Children are ordered light → dark by index, so index 0 is the brightest\n * sibling and index `total - 1` is the darkest.\n */\nexport function deriveShade(parentHex: string, index: number, total: number): string {\n if (total <= 1) return parentHex\n const { h, s, l } = hexToHsl(parentHex)\n\n const L_MIN = 35\n const L_MAX = 75\n const spread = Math.min(L_MAX - L_MIN, 40)\n const center = clamp(l, L_MIN + spread / 2, L_MAX - spread / 2)\n\n const top = center + spread / 2\n const bot = center - spread / 2\n const t = total === 1 ? 0.5 : index / (total - 1)\n const childL = top - t * (top - bot)\n\n const childS = clamp(s, 35, 100)\n return hslToHex(h, childS, childL)\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { SampleGroup } from '../types'\nimport { deriveShade } from '../utils/color'\n\nexport type SampleGroupSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface DisplaySampleSubGroup extends SampleGroup {\n displayColor: string\n displayBg: string\n displayBorder: string\n}\n\nexport interface SampleMajorGroup {\n name: string\n color: string\n subGroups: DisplaySampleSubGroup[]\n allSamples: string[]\n}\n\nexport interface UseSampleGroupsOptions {\n groups: SampleGroupSource<readonly SampleGroup[]>\n samples?: SampleGroupSource<readonly string[]>\n separator?: SampleGroupSource<string | null | undefined>\n fallbackColor?: SampleGroupSource<string | null | undefined>\n}\n\nexport interface UseSampleGroupsReturn {\n groups: ComputedRef<SampleGroup[]>\n separator: ComputedRef<string>\n hierarchicalGroups: ComputedRef<SampleMajorGroup[]>\n showHierarchy: ComputedRef<boolean>\n groupedSamples: ComputedRef<Set<string>>\n ungroupedSamples: ComputedRef<string[]>\n findGroup: (groupName: string) => SampleGroup | undefined\n getGroupColor: (groupName: string) => string\n}\n\n/** Shared sample-group hierarchy, color, and ungrouped-sample derivation for lab selectors. */\nexport function useSampleGroups(options: UseSampleGroupsOptions): UseSampleGroupsReturn {\n const groups = computed(() => [...toValue(options.groups)])\n const samples = computed(() => [...(toValue(options.samples) ?? [])])\n const fallbackColor = computed(() => toValue(options.fallbackColor) || '#3B82F6')\n const separator = computed(() => {\n const explicit = toValue(options.separator)\n if (explicit) return explicit\n return groups.value.some(group => group.name.includes('/')) ? '/' : '_'\n })\n\n const hierarchicalGroups = computed<SampleMajorGroup[]>(() => {\n if (groups.value.length === 0) return []\n const groupedByMajor = new Map<string, SampleGroup[]>()\n\n for (const group of groups.value) {\n const majorName = getMajorGroupName(group.name, separator.value)\n const existing = groupedByMajor.get(majorName)\n if (existing) {\n existing.push(group)\n } else {\n groupedByMajor.set(majorName, [group])\n }\n }\n\n return [...groupedByMajor.entries()].map(([majorName, subGroups]) => {\n const color = subGroups[0]?.color || fallbackColor.value\n const displaySubs = subGroups.map((subGroup, index) => {\n const displayColor = deriveShade(color, index, subGroups.length)\n return {\n ...subGroup,\n displayColor,\n displayBg: displayColor + '20',\n displayBorder: displayColor + '40',\n }\n })\n\n return {\n name: majorName,\n color,\n subGroups: displaySubs,\n allSamples: subGroups.flatMap(group => group.samples),\n }\n })\n })\n\n const showHierarchy = computed(() =>\n hierarchicalGroups.value.some(major =>\n major.subGroups.length > 1 ||\n (major.subGroups.length === 1 && major.name !== major.subGroups[0].name)\n )\n )\n\n const groupedSamples = computed(() =>\n new Set(groups.value.flatMap(group => group.samples))\n )\n\n const ungroupedSamples = computed(() =>\n samples.value.filter(sample => !groupedSamples.value.has(sample))\n )\n\n function findGroup(groupName: string): SampleGroup | undefined {\n return groups.value.find(group => group.name === groupName)\n }\n\n function getGroupColor(groupName: string): string {\n return findGroup(groupName)?.color || fallbackColor.value\n }\n\n return {\n groups,\n separator,\n hierarchicalGroups,\n showHierarchy,\n groupedSamples,\n ungroupedSamples,\n findGroup,\n getGroupColor,\n }\n}\n\nfunction getMajorGroupName(groupName: string, separator: string): string {\n const parts = groupName.split(separator)\n return parts.length > 1 ? parts[0] : groupName\n}\n","import { computed, ref, toValue, watch, type ComputedRef, type Ref } from 'vue'\n\nexport type ExpansionSetSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface UseExpansionSetOptions {\n defaultIds?: ExpansionSetSource<readonly string[] | null | undefined>\n allIds?: ExpansionSetSource<readonly string[] | null | undefined>\n expandAll?: ExpansionSetSource<boolean | null | undefined>\n}\n\nexport interface UseExpansionSetReturn {\n expandedIds: Ref<Set<string>>\n expandedList: ComputedRef<string[]>\n isExpanded: (id: string) => boolean\n expand: (id: string) => void\n collapse: (id: string) => void\n toggle: (id: string) => boolean\n expandMany: (ids: readonly string[]) => void\n setExpanded: (ids: readonly string[]) => void\n collapseAll: () => void\n reset: () => void\n}\n\n/** Shared expansion state for trees, grouped selectors, and disclosure lists. */\nexport function useExpansionSet(options: UseExpansionSetOptions = {}): UseExpansionSetReturn {\n const expandedIds = ref(new Set(normalizeIds(toValue(options.defaultIds))))\n const expandedList = computed(() => [...expandedIds.value])\n\n if (options.expandAll !== undefined) {\n watch(\n () => toValue(options.expandAll),\n (shouldExpandAll) => {\n if (shouldExpandAll === undefined || shouldExpandAll === null) return\n if (shouldExpandAll) {\n setExpanded(normalizeIds(toValue(options.allIds)))\n } else {\n reset()\n }\n },\n { immediate: true },\n )\n }\n\n if (options.allIds !== undefined) {\n watch(\n () => normalizeIds(toValue(options.allIds)),\n (ids) => {\n if (toValue(options.expandAll)) {\n setExpanded(ids)\n }\n },\n )\n }\n\n function isExpanded(id: string): boolean {\n return expandedIds.value.has(id)\n }\n\n function expand(id: string) {\n if (expandedIds.value.has(id)) return\n expandedIds.value = new Set([...expandedIds.value, id])\n }\n\n function collapse(id: string) {\n if (!expandedIds.value.has(id)) return\n const next = new Set(expandedIds.value)\n next.delete(id)\n expandedIds.value = next\n }\n\n function toggle(id: string): boolean {\n if (expandedIds.value.has(id)) {\n collapse(id)\n return false\n }\n expand(id)\n return true\n }\n\n function expandMany(ids: readonly string[]) {\n expandedIds.value = new Set([...expandedIds.value, ...normalizeIds(ids)])\n }\n\n function setExpanded(ids: readonly string[]) {\n expandedIds.value = new Set(normalizeIds(ids))\n }\n\n function collapseAll() {\n expandedIds.value = new Set()\n }\n\n function reset() {\n setExpanded(normalizeIds(toValue(options.defaultIds)))\n }\n\n return {\n expandedIds,\n expandedList,\n isExpanded,\n expand,\n collapse,\n toggle,\n expandMany,\n setExpanded,\n collapseAll,\n reset,\n }\n}\n\nfunction normalizeIds(ids: readonly string[] | null | undefined): string[] {\n if (!ids) return []\n return [...new Set(ids.filter(Boolean))]\n}\n","import { ref, computed, onUnmounted, type Ref } from 'vue'\nimport type { ScheduleEvent } from '../types/components'\n\nexport type DragType = 'create' | 'resize-top' | 'resize-bottom' | 'move'\n\nexport interface DragState {\n type: DragType\n event?: ScheduleEvent\n startDate: Date\n startY: number\n currentY: number\n dayIndex: number\n currentDayIndex: number\n}\n\nexport interface GhostEvent {\n start: Date\n end: Date\n dayIndex: number\n style: Record<string, string>\n}\n\nexport interface UseScheduleDragOptions {\n slotDuration: Ref<number>\n dayStartHour: Ref<number>\n dayEndHour: Ref<number>\n readonly: Ref<boolean>\n slotHeight: Ref<number>\n blockedSlots?: Ref<{ start: string; end: string; label?: string }[]>\n onCreateComplete?: (start: Date, end: Date) => void\n onMoveComplete?: (event: ScheduleEvent, newStart: Date, newEnd: Date) => void\n onResizeComplete?: (event: ScheduleEvent, newStart: Date, newEnd: Date) => void\n}\n\n/** Handles pointer-driven create, move, and resize drag interactions for the ScheduleCalendar grid. */\nexport function useScheduleDrag(options: UseScheduleDragOptions) {\n const isDragging = ref(false)\n const dragState = ref<DragState | null>(null)\n\n const ghost = computed<GhostEvent | null>(() => {\n if (!dragState.value) return null\n const state = dragState.value\n const slotH = options.slotHeight.value\n const slotMin = options.slotDuration.value\n const dayStart = options.dayStartHour.value * 60\n\n if (state.type === 'create') {\n const deltaY = state.currentY - state.startY\n const startOffset = state.startY\n const endOffset = startOffset + deltaY\n\n const topPx = Math.min(startOffset, endOffset)\n const bottomPx = Math.max(startOffset, endOffset)\n\n const startMinutes = dayStart + Math.round((topPx / slotH) * slotMin)\n const endMinutes = dayStart + Math.round((bottomPx / slotH) * slotMin)\n\n const snappedStart = snapMinutes(startMinutes, slotMin)\n const snappedEnd = Math.max(snapMinutes(endMinutes, slotMin), snappedStart + slotMin)\n\n const snappedTopPx = ((snappedStart - dayStart) / slotMin) * slotH\n const snappedHeightPx = ((snappedEnd - snappedStart) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, snappedStart),\n end: minutesToDate(state.startDate, snappedEnd),\n dayIndex: state.dayIndex,\n style: {\n top: `${snappedTopPx}px`,\n height: `${snappedHeightPx}px`,\n },\n }\n }\n\n if (state.type === 'move' && state.event) {\n const deltaY = state.currentY - state.startY\n const eventStart = dateToMinutes(new Date(state.event.start))\n const eventEnd = dateToMinutes(new Date(state.event.end))\n const duration = eventEnd - eventStart\n const pixelDelta = Math.round((deltaY / slotH) * slotMin)\n const newStart = snapMinutes(eventStart + pixelDelta, slotMin)\n const newEnd = newStart + duration\n\n const clamped = clampRange(newStart, newEnd, dayStart, options.dayEndHour.value * 60)\n const topPx = ((clamped.start - dayStart) / slotMin) * slotH\n const heightPx = ((clamped.end - clamped.start) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, clamped.start),\n end: minutesToDate(state.startDate, clamped.end),\n dayIndex: state.currentDayIndex,\n style: {\n top: `${topPx}px`,\n height: `${heightPx}px`,\n },\n }\n }\n\n if ((state.type === 'resize-top' || state.type === 'resize-bottom') && state.event) {\n const eventStart = dateToMinutes(new Date(state.event.start))\n const eventEnd = dateToMinutes(new Date(state.event.end))\n const deltaY = state.currentY - state.startY\n const pixelDelta = Math.round((deltaY / slotH) * slotMin)\n\n let newStart = eventStart\n let newEnd = eventEnd\n\n if (state.type === 'resize-top') {\n newStart = snapMinutes(eventStart + pixelDelta, slotMin)\n newStart = Math.min(newStart, newEnd - slotMin)\n } else {\n newEnd = snapMinutes(eventEnd + pixelDelta, slotMin)\n newEnd = Math.max(newEnd, newStart + slotMin)\n }\n\n const clamped = clampRange(newStart, newEnd, dayStart, options.dayEndHour.value * 60)\n const topPx = ((clamped.start - dayStart) / slotMin) * slotH\n const heightPx = ((clamped.end - clamped.start) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, clamped.start),\n end: minutesToDate(state.startDate, clamped.end),\n dayIndex: state.dayIndex,\n style: {\n top: `${topPx}px`,\n height: `${heightPx}px`,\n },\n }\n }\n\n return null\n })\n\n function startCreate(date: Date, y: number, dayIndex: number) {\n if (options.readonly.value) return\n isDragging.value = true\n dragState.value = {\n type: 'create',\n startDate: date,\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function startMove(event: ScheduleEvent, y: number, dayIndex: number) {\n if (options.readonly.value || event.draggable === false) return\n isDragging.value = true\n dragState.value = {\n type: 'move',\n event,\n startDate: new Date(event.start),\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function startResize(event: ScheduleEvent, edge: 'top' | 'bottom', y: number, dayIndex: number) {\n if (options.readonly.value || event.resizable === false) return\n isDragging.value = true\n dragState.value = {\n type: edge === 'top' ? 'resize-top' : 'resize-bottom',\n event,\n startDate: new Date(event.start),\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!dragState.value) return\n dragState.value = { ...dragState.value, currentY: e.clientY }\n }\n\n function onPointerUp() {\n if (!dragState.value || !ghost.value) {\n cleanup()\n return\n }\n\n const g = ghost.value\n const state = dragState.value\n\n if (state.type === 'create' && options.onCreateComplete) {\n options.onCreateComplete(g.start, g.end)\n } else if (state.type === 'move' && state.event && options.onMoveComplete) {\n options.onMoveComplete(state.event, g.start, g.end)\n } else if ((state.type === 'resize-top' || state.type === 'resize-bottom') && state.event && options.onResizeComplete) {\n options.onResizeComplete(state.event, g.start, g.end)\n }\n\n cleanup()\n }\n\n function addListeners() {\n document.addEventListener('pointermove', onPointerMove)\n document.addEventListener('pointerup', onPointerUp)\n }\n\n function cleanup() {\n isDragging.value = false\n dragState.value = null\n document.removeEventListener('pointermove', onPointerMove)\n document.removeEventListener('pointerup', onPointerUp)\n }\n\n onUnmounted(cleanup)\n\n return {\n isDragging,\n dragState,\n ghost,\n startCreate,\n startMove,\n startResize,\n }\n}\n\nfunction snapMinutes(minutes: number, step: number): number {\n return Math.round(minutes / step) * step\n}\n\nfunction dateToMinutes(date: Date): number {\n return date.getHours() * 60 + date.getMinutes()\n}\n\nfunction minutesToDate(baseDate: Date, minutes: number): Date {\n const d = new Date(baseDate)\n d.setHours(Math.floor(minutes / 60), minutes % 60, 0, 0)\n return d\n}\n\nfunction clampRange(start: number, end: number, min: number, max: number) {\n const s = Math.max(start, min)\n const e = Math.min(end, max)\n return { start: s, end: Math.max(e, s) }\n}\n","import type { PlatformContext } from '../types'\n\nexport type ExperimentAwarePlatformContext = PlatformContext & {\n currentExperiment?: unknown\n currentExperimentId?: unknown\n experiment?: unknown\n experimentId?: unknown\n}\n\nexport function getInjectedPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\nexport function getInjectedExperimentContext(): ExperimentAwarePlatformContext | undefined {\n return getInjectedPlatformContext() as ExperimentAwarePlatformContext | undefined\n}\n\nexport function currentExperimentFromContext<TExperiment>(\n context: ExperimentAwarePlatformContext | undefined = getInjectedExperimentContext(),\n): TExperiment | undefined {\n const candidate = context?.currentExperiment ?? context?.experiment\n return candidate && typeof candidate === 'object'\n ? candidate as TExperiment\n : undefined\n}\n\nexport function currentExperimentIdFromContext(\n context: ExperimentAwarePlatformContext | undefined = getInjectedExperimentContext(),\n): number | undefined {\n return parseExperimentId(\n context?.currentExperimentId ??\n context?.experimentId ??\n context?.currentExperiment ??\n context?.experiment,\n )\n}\n\nexport function currentExperimentIdFromUrl(): number | undefined {\n if (typeof window === 'undefined') return undefined\n const params = new URLSearchParams(window.location.search)\n return parseExperimentId(params.get('experimentId') ?? params.get('experiment_id'))\n ?? experimentIdFromPath(window.location.pathname)\n ?? experimentIdFromPath(window.location.hash.replace(/^#\\/?/, '/'))\n}\n\nexport function resolveCurrentExperimentId(\n context: ExperimentAwarePlatformContext | undefined = getInjectedExperimentContext(),\n): number | undefined {\n return currentExperimentIdFromContext(context) ?? currentExperimentIdFromUrl()\n}\n\nexport function parseExperimentId(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n if (value && typeof value === 'object' && 'id' in value) {\n return parseExperimentId((value as { id?: unknown }).id)\n }\n return undefined\n}\n\nfunction experimentIdFromPath(path: string): number | undefined {\n const segments = path.split('/').filter(Boolean)\n for (let index = 0; index < segments.length - 1; index += 1) {\n const segment = segments[index]?.toLowerCase()\n if (segment === 'experiment' || segment === 'experiments') {\n return parseExperimentId(decodeURIComponent(segments[index + 1] ?? ''))\n }\n }\n return undefined\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\nimport { useApi } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { createBioTemplatePresetCollection } from '../templates'\nimport type {\n CreateLcmsBatchCollectionOptions,\n CreateQpcrExpressionCollectionOptions,\n CreateWellPlateScreenCollectionOptions,\n TemplatePresetId,\n} from '../templates'\nimport {\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\n\ntype TemplatePresetCollectionOptions =\n | CreateWellPlateScreenCollectionOptions\n | CreateQpcrExpressionCollectionOptions\n | CreateLcmsBatchCollectionOptions\n\nexport interface UseExperimentSaveOptions {\n /** Default plugin_id for all save/load calls. */\n pluginId?: string\n /** Default schema version for design saves (defaults to \"1.0\"). */\n schemaVersion?: string\n /** Override API base URL. */\n apiBaseUrl?: string\n}\n\nexport interface UseExperimentSaveReturn {\n /** Current experiment id from platform injection, URL query, or URL path. */\n currentExperimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasCurrentExperiment: ComputedRef<boolean>\n /** Whether a save operation is in progress. */\n isSaving: Ref<boolean>\n /** Whether a load or delete operation is in progress. */\n isLoading: Ref<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save, or null. */\n lastSavedAt: Ref<Date | null>\n /** Save design data for an experiment. */\n saveDesign: (experimentId: number, data: Record<string, unknown>) => Promise<boolean>\n /** Save design data for the current experiment. */\n saveCurrentDesign: (data: Record<string, unknown>) => Promise<boolean>\n /** Create and save a built-in biology template preset as experiment design data. */\n saveTemplatePreset: (\n experimentId: number,\n name: TemplatePresetId | string,\n options?: TemplatePresetCollectionOptions,\n ) => Promise<boolean>\n /** Create and save a built-in biology template preset for the current experiment. */\n saveCurrentTemplatePreset: (\n name: TemplatePresetId | string,\n options?: TemplatePresetCollectionOptions,\n ) => Promise<boolean>\n /** Save analysis result for an experiment. */\n saveAnalysis: (experimentId: number, result: Record<string, unknown>) => Promise<boolean>\n /** Save analysis result for the current experiment. */\n saveCurrentAnalysis: (result: Record<string, unknown>) => Promise<boolean>\n /** Save design and/or analysis in one call. */\n save: (experimentId: number, opts: {\n design?: Record<string, unknown>\n analysis?: Record<string, unknown>\n }) => Promise<boolean>\n /** Load design data for an experiment. */\n loadDesign: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Load design data for the current experiment. */\n loadCurrentDesign: () => Promise<Record<string, unknown> | null>\n /** Load analysis result for an experiment. */\n loadAnalysis: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Load analysis result for the current experiment. */\n loadCurrentAnalysis: () => Promise<Record<string, unknown> | null>\n /** Delete design data for an experiment. */\n deleteDesign: (experimentId: number) => Promise<boolean>\n /** Delete design data for the current experiment. */\n deleteCurrentDesign: () => Promise<boolean>\n /** Delete analysis result for an experiment. */\n deleteAnalysis: (experimentId: number) => Promise<boolean>\n /** Delete analysis result for the current experiment. */\n deleteCurrentAnalysis: () => Promise<boolean>\n /** Require and return the current experiment id, or throw when missing. */\n requireCurrentExperimentId: () => number\n}\n\n/** Persists experiment design, analysis, and built-in template preset data through the platform API. */\nexport function useExperimentSave(\n options: UseExperimentSaveOptions = {},\n): UseExperimentSaveReturn {\n const injectedContext = getInjectedPlatformContext()\n const api = useApi({ baseUrl: options.apiBaseUrl ?? injectedContext?.platformApiUrl })\n const pluginId = options.pluginId ?? injectedContext?.plugin?.id\n const schemaVersion = options.schemaVersion ?? '1.0'\n const currentExperimentId = computed<number | undefined>(() => {\n return resolveCurrentExperimentId(injectedContext)\n })\n const hasCurrentExperiment = computed(() => currentExperimentId.value !== undefined)\n\n const request = useRequestSyncState('Experiment request failed.')\n const isSaving = ref(false)\n const isLoading = ref(false)\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const lastSavedAt = request.lastSavedAt\n\n function requireCurrentExperimentId(): number {\n const id = currentExperimentId.value\n if (id === undefined) {\n throw new Error('[MINT SDK] No current experiment is selected.')\n }\n return id\n }\n\n function currentExperimentIdOrError(action: string): number | undefined {\n const id = currentExperimentId.value\n if (id === undefined) {\n request.setError(`No current experiment is selected for ${action}`)\n return undefined\n }\n return id\n }\n\n async function saveDesign(\n experimentId: number,\n data: Record<string, unknown>,\n ): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for saveDesign')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n await api.put(`/experiments/${experimentId}/data`, {\n plugin_id: pluginId,\n data,\n schema_version: schemaVersion,\n })\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function saveCurrentDesign(data: Record<string, unknown>): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveDesign')\n return experimentId === undefined ? false : saveDesign(experimentId, data)\n }\n\n async function saveTemplatePreset(\n experimentId: number,\n name: TemplatePresetId | string,\n presetOptions: TemplatePresetCollectionOptions = {},\n ): Promise<boolean> {\n const collection = createBioTemplatePresetCollection(name, presetOptions)\n return saveDesign(experimentId, collection as unknown as Record<string, unknown>)\n }\n\n async function saveCurrentTemplatePreset(\n name: TemplatePresetId | string,\n presetOptions: TemplatePresetCollectionOptions = {},\n ): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveTemplatePreset')\n return experimentId === undefined ? false : saveTemplatePreset(experimentId, name, presetOptions)\n }\n\n async function saveAnalysis(\n experimentId: number,\n result: Record<string, unknown>,\n ): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for saveAnalysis')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n await api.put(`/experiments/${experimentId}/results/${pluginId}`, {\n result,\n })\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function saveCurrentAnalysis(result: Record<string, unknown>): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveAnalysis')\n return experimentId === undefined ? false : saveAnalysis(experimentId, result)\n }\n\n async function save(\n experimentId: number,\n opts: { design?: Record<string, unknown>; analysis?: Record<string, unknown> },\n ): Promise<boolean> {\n if ((opts.design || opts.analysis) && !pluginId) {\n request.setError('pluginId is required for save')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n if (opts.design) {\n await api.put(`/experiments/${experimentId}/data`, {\n plugin_id: pluginId,\n data: opts.design,\n schema_version: schemaVersion,\n })\n }\n if (opts.analysis) {\n await api.put(`/experiments/${experimentId}/results/${pluginId}`, {\n result: opts.analysis,\n })\n }\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function loadDesign(\n experimentId: number,\n ): Promise<Record<string, unknown> | null> {\n isLoading.value = true\n try {\n return await request.run(\n () => api.get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { success: 'load' },\n )\n } catch {\n return null\n } finally {\n isLoading.value = false\n }\n }\n\n async function loadCurrentDesign(): Promise<Record<string, unknown> | null> {\n const experimentId = currentExperimentIdOrError('loadDesign')\n return experimentId === undefined ? null : loadDesign(experimentId)\n }\n\n async function loadAnalysis(\n experimentId: number,\n ): Promise<Record<string, unknown> | null> {\n if (!pluginId) {\n request.setError('pluginId is required for loadAnalysis')\n return null\n }\n isLoading.value = true\n try {\n return await request.run(\n () => api.get<Record<string, unknown>>(\n `/experiments/${experimentId}/results/${pluginId}`,\n ),\n { success: 'load' },\n )\n } catch {\n return null\n } finally {\n isLoading.value = false\n }\n }\n\n async function loadCurrentAnalysis(): Promise<Record<string, unknown> | null> {\n const experimentId = currentExperimentIdOrError('loadAnalysis')\n return experimentId === undefined ? null : loadAnalysis(experimentId)\n }\n\n async function deleteDesign(experimentId: number): Promise<boolean> {\n isLoading.value = true\n try {\n await request.run(() => api.delete(`/experiments/${experimentId}/data`))\n return true\n } catch {\n return false\n } finally {\n isLoading.value = false\n }\n }\n\n async function deleteCurrentDesign(): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('deleteDesign')\n return experimentId === undefined ? false : deleteDesign(experimentId)\n }\n\n async function deleteAnalysis(experimentId: number): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for deleteAnalysis')\n return false\n }\n isLoading.value = true\n try {\n await request.run(() => api.delete(`/experiments/${experimentId}/results/${pluginId}`))\n return true\n } catch {\n return false\n } finally {\n isLoading.value = false\n }\n }\n\n async function deleteCurrentAnalysis(): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('deleteAnalysis')\n return experimentId === undefined ? false : deleteAnalysis(experimentId)\n }\n\n return {\n currentExperimentId,\n hasCurrentExperiment,\n isSaving,\n isLoading,\n error,\n lastLoadedAt,\n lastSavedAt,\n saveDesign,\n saveCurrentDesign,\n saveTemplatePreset,\n saveCurrentTemplatePreset,\n saveAnalysis,\n saveCurrentAnalysis,\n save,\n loadDesign,\n loadCurrentDesign,\n loadAnalysis,\n loadCurrentAnalysis,\n deleteDesign,\n deleteCurrentDesign,\n deleteAnalysis,\n deleteCurrentAnalysis,\n requireCurrentExperimentId,\n }\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\nimport { useExperimentSave, type UseExperimentSaveOptions } from './useExperimentSave'\nimport {\n createTemplateCollection,\n ensureTemplateFromCollection,\n extractTemplateCollection,\n type BioTemplateEnvelope,\n type TemplateCollection,\n type TemplateCollectionEnvelope,\n} from '../templates'\n\nexport type TemplateCollectionInput =\n | TemplateCollectionEnvelope\n | BioTemplateEnvelope<unknown>\n | Array<BioTemplateEnvelope<unknown>>\n\nexport interface UseTemplateCollectionOptions extends UseExperimentSaveOptions {\n /** Initial template collection or factory; defaults to an empty collection. */\n initial?: TemplateCollectionInput | (() => TemplateCollectionInput)\n}\n\nexport interface UseTemplateCollectionReturn {\n /** Current experiment id from platform injection, URL query, or URL path. */\n currentExperimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasCurrentExperiment: ComputedRef<boolean>\n /** Full template collection envelope ready to save into design_data. */\n templateCollection: Ref<TemplateCollectionEnvelope>\n /** Template map keyed by template_id. */\n templates: ComputedRef<TemplateCollection>\n /** Collection-level metadata, or an empty object. */\n metadata: ComputedRef<Record<string, unknown>>\n /** Template ids currently present in the collection. */\n templateIds: ComputedRef<string[]>\n /** Whether the collection contains at least one template. */\n hasTemplates: ComputedRef<boolean>\n /** Whether a load or delete operation is in progress. */\n isLoading: Ref<boolean>\n /** Whether a save operation is in progress. */\n isSaving: Ref<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save, or null. */\n lastSavedAt: Ref<Date | null>\n /** Replace local state from a template envelope, collection envelope, or raw design_data. */\n apply: (value: unknown, metadata?: Record<string, unknown>) => TemplateCollectionEnvelope\n /** Reset local state to the configured initial collection. */\n reset: () => TemplateCollectionEnvelope\n /** Add or replace one template in the local collection. */\n setTemplate: (template: BioTemplateEnvelope<unknown>) => TemplateCollectionEnvelope\n /** Remove one template from the local collection. */\n removeTemplate: (templateId: string) => boolean\n /** Read one template from the local collection, returning null when missing. */\n getTemplate: <TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>>(\n templateId: string,\n ) => TTemplate | null\n /** Read one template from the local collection, throwing when missing or mismatched. */\n requireTemplate: <TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>>(\n templateId: string,\n ) => TTemplate\n /** Load template design_data for an experiment and apply it locally. */\n load: (experimentId: number) => Promise<TemplateCollectionEnvelope | null>\n /** Load template design_data for the current experiment and apply it locally. */\n loadCurrent: () => Promise<TemplateCollectionEnvelope | null>\n /** Save the local template collection as experiment design_data. */\n save: (experimentId: number) => Promise<boolean>\n /** Save the local template collection as current experiment design_data. */\n saveCurrent: () => Promise<boolean>\n /** Require and return the current experiment id, or throw when missing. */\n requireCurrentExperimentId: () => number\n}\n\n/** Manages a biology template collection in the current experiment's design_data. */\nexport function useTemplateCollection(\n options: UseTemplateCollectionOptions = {},\n): UseTemplateCollectionReturn {\n const experimentSave = useExperimentSave(options)\n const templateCollection = ref<TemplateCollectionEnvelope>(createInitialCollection(options))\n const templates = computed(() => extractTemplateCollection(templateCollection.value))\n const metadata = computed(() => templateCollection.value.metadata ?? {})\n const templateIds = computed(() => Object.keys(templates.value))\n const hasTemplates = computed(() => templateIds.value.length > 0)\n\n function apply(value: unknown, metadata?: Record<string, unknown>): TemplateCollectionEnvelope {\n templateCollection.value = normalizeTemplateCollection(value, metadata)\n return templateCollection.value\n }\n\n function reset(): TemplateCollectionEnvelope {\n templateCollection.value = createInitialCollection(options)\n return templateCollection.value\n }\n\n function setTemplate(template: BioTemplateEnvelope<unknown>): TemplateCollectionEnvelope {\n const nextTemplates = {\n ...templates.value,\n [template.template_id]: template,\n }\n templateCollection.value = createTemplateCollectionEnvelope(\n Object.values(nextTemplates),\n templateCollection.value.metadata,\n )\n return templateCollection.value\n }\n\n function removeTemplate(templateId: string): boolean {\n if (!templates.value[templateId]) return false\n const nextTemplates = { ...templates.value }\n delete nextTemplates[templateId]\n templateCollection.value = createTemplateCollectionEnvelope(\n Object.values(nextTemplates),\n templateCollection.value.metadata,\n )\n return true\n }\n\n function getTemplate<\n TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>,\n >(templateId: string): TTemplate | null {\n return (templates.value[templateId] as TTemplate | undefined) ?? null\n }\n\n function requireTemplate<\n TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>,\n >(templateId: string): TTemplate {\n return ensureTemplateFromCollection<TTemplate>(templateCollection.value, templateId)\n }\n\n async function load(experimentId: number): Promise<TemplateCollectionEnvelope | null> {\n const data = await experimentSave.loadDesign(experimentId)\n return data === null ? null : apply(data)\n }\n\n async function loadCurrent(): Promise<TemplateCollectionEnvelope | null> {\n const data = await experimentSave.loadCurrentDesign()\n return data === null ? null : apply(data)\n }\n\n async function save(experimentId: number): Promise<boolean> {\n return experimentSave.saveDesign(\n experimentId,\n templateCollection.value as unknown as Record<string, unknown>,\n )\n }\n\n async function saveCurrent(): Promise<boolean> {\n return experimentSave.saveCurrentDesign(\n templateCollection.value as unknown as Record<string, unknown>,\n )\n }\n\n return {\n currentExperimentId: experimentSave.currentExperimentId,\n hasCurrentExperiment: experimentSave.hasCurrentExperiment,\n templateCollection,\n templates,\n metadata,\n templateIds,\n hasTemplates,\n isLoading: experimentSave.isLoading,\n isSaving: experimentSave.isSaving,\n error: experimentSave.error,\n lastLoadedAt: experimentSave.lastLoadedAt,\n lastSavedAt: experimentSave.lastSavedAt,\n apply,\n reset,\n setTemplate,\n removeTemplate,\n getTemplate,\n requireTemplate,\n load,\n loadCurrent,\n save,\n saveCurrent,\n requireCurrentExperimentId: experimentSave.requireCurrentExperimentId,\n }\n}\n\nfunction createInitialCollection(options: UseTemplateCollectionOptions): TemplateCollectionEnvelope {\n const initial = typeof options.initial === 'function' ? options.initial() : options.initial\n if (initial === undefined) return { templates: {} }\n return normalizeTemplateCollection(initial)\n}\n\nfunction normalizeTemplateCollection(\n value: unknown,\n metadata?: Record<string, unknown>,\n): TemplateCollectionEnvelope {\n if (Array.isArray(value)) {\n return createTemplateCollectionEnvelope(value, metadata)\n }\n\n return createTemplateCollectionEnvelope(\n Object.values(extractTemplateCollection(value)),\n readCollectionMetadata(value) ?? metadata,\n )\n}\n\nfunction createTemplateCollectionEnvelope(\n templates: Array<BioTemplateEnvelope<unknown>>,\n metadata?: Record<string, unknown>,\n): TemplateCollectionEnvelope {\n return metadata === undefined\n ? createTemplateCollection(templates)\n : createTemplateCollection(templates, metadata)\n}\n\nfunction readCollectionMetadata(value: unknown): Record<string, unknown> | undefined {\n if (\n typeof value !== 'object'\n || value === null\n || Array.isArray(value)\n || !('metadata' in value)\n ) {\n return undefined\n }\n\n const metadata = (value as { metadata?: unknown }).metadata\n if (\n typeof metadata === 'object'\n && metadata !== null\n && !Array.isArray(metadata)\n ) {\n return metadata as Record<string, unknown>\n }\n return undefined\n}\n","import {\n createBioTemplateControlToolkit,\n getBioTemplateControlSchema,\n requireBioTemplateControlSchema,\n type BioTemplateControlSchema,\n type BioTemplateControlTarget,\n} from '../templates/controlSchemas'\nimport type {\n ControlSchemaOptions,\n ControlWorkspaceOptions,\n UseControlSchemaReturn,\n} from './useControlSchema'\n\nexport {\n getBioTemplateControlSchema,\n requireBioTemplateControlSchema,\n}\n\nexport type {\n BioTemplateControlSchema,\n BioTemplateControlTarget,\n}\n\n/** Build FormBuilder schema, AppSidebar panels, and defaults for a built-in biology template or preset. */\nexport function useBioTemplateControls(\n target: BioTemplateControlTarget,\n options: ControlWorkspaceOptions = {},\n): UseControlSchemaReturn<BioTemplateControlSchema> {\n const { initialValues, topBarSettings: _topBarSettings, ...schemaOptions } = options\n const controls = createBioTemplateControlToolkit(target, schemaOptions as ControlSchemaOptions)\n\n if (initialValues === undefined) return controls\n\n return {\n ...controls,\n initialValues: {\n ...controls.initialValues,\n ...initialValues,\n },\n }\n}\n","import {\n getBioTemplateComponentBindings,\n getBioTemplateComponentProps as getTemplateComponentProps,\n toBioTemplateComponentImports,\n toBioTemplateComponentBindings,\n toBioTemplateComponentBindingsById,\n toBioTemplateComponentProps,\n toBioTemplateComponentPropsByComponent as toTemplateComponentPropsByComponent,\n toBioTemplateComponentPropsById,\n toBioTemplateComponentSnippets,\n toBioTemplateComponentUsage,\n type BioTemplateComponentBinding,\n type BioTemplateComponentBindingsById,\n type BioTemplateComponentImport,\n type BioTemplateComponentPropsByComponent,\n type BioTemplateComponentPropsBinding,\n type BioTemplateComponentPropsById,\n type BioTemplateComponentPropsLookupOptions,\n type BioTemplateResolvedComponentBinding,\n type BioTemplateComponentSnippet,\n type BioTemplateComponentTarget,\n type BioTemplateComponentUsage,\n} from '../templates/componentBindings'\nimport type {\n BioTemplateEnvelope,\n TemplateCollectionEnvelope,\n} from '../templates/types'\n\nexport {\n getBioTemplateComponentBindings,\n toBioTemplateComponentBindings,\n toBioTemplateComponentBindingsById,\n toBioTemplateComponentImports,\n toBioTemplateComponentProps,\n toBioTemplateComponentPropsById,\n toBioTemplateComponentSnippets,\n toBioTemplateComponentUsage,\n}\n\nexport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentPropsLookupOptions,\n BioTemplateResolvedComponentBinding,\n BioTemplateComponentSnippet,\n BioTemplateComponentTarget,\n BioTemplateComponentUsage,\n}\n\nexport interface UseBioTemplateComponentsReturn {\n bindings: BioTemplateComponentBinding[]\n imports: BioTemplateComponentImport[]\n componentBindings: BioTemplateResolvedComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n snippets: BioTemplateComponentSnippet[]\n usage: BioTemplateComponentUsage | null\n getComponentProps: (\n component: string,\n options?: BioTemplateComponentPropsLookupOptions,\n ) => Record<string, unknown> | undefined\n}\n\n/** Return component props grouped by SDK component name for direct WellPlate/DoseCalculator binding. */\nexport function toBioTemplateComponentPropsByComponent(\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,\n): BioTemplateComponentPropsByComponent {\n return toTemplateComponentPropsByComponent(target)\n}\n\n/** Return the first props object for an SDK component, optionally restricted by template id or binding id. */\nexport function getBioTemplateComponentProps(\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,\n component: string,\n options: BioTemplateComponentPropsLookupOptions = {},\n): Record<string, unknown> | undefined {\n return getTemplateComponentProps(target, component, options)\n}\n\n/** Map built-in biology templates to SDK components such as WellPlate, DataFrame, DoseCalculator, and PlateMapEditor. */\nexport function useBioTemplateComponents(\n target: BioTemplateComponentTarget\n): UseBioTemplateComponentsReturn {\n return {\n bindings: getBioTemplateComponentBindings(target),\n imports: toBioTemplateComponentImports(target),\n componentBindings: typeof target === 'string' ? [] : toBioTemplateComponentBindings(target),\n componentBindingsById: typeof target === 'string' ? {} : toBioTemplateComponentBindingsById(target),\n componentProps: typeof target === 'string' ? [] : toBioTemplateComponentProps(target),\n componentPropsById: typeof target === 'string' ? {} : toBioTemplateComponentPropsById(target),\n componentPropsByComponent: typeof target === 'string' ? {} : toBioTemplateComponentPropsByComponent(target),\n snippets: typeof target === 'string' ? [] : toBioTemplateComponentSnippets(target),\n usage: typeof target === 'string' ? null : toBioTemplateComponentUsage(target),\n getComponentProps: (component, options) =>\n typeof target === 'string'\n ? undefined\n : getBioTemplateComponentProps(target, component, options),\n }\n}\n","import type {\n BioTemplateEnvelope,\n TemplateCollectionEnvelope,\n} from '../templates'\nimport type {\n ControlWorkspaceFormBinding,\n ControlWorkspaceOptions,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlSchemaReturn,\n UseControlWorkspaceReturn,\n} from './useControlSchema'\nimport {\n useControlWorkspace,\n} from './useControlSchema'\nimport {\n useBioTemplateControls,\n type BioTemplateControlSchema,\n type BioTemplateControlTarget,\n} from './useBioTemplateControls'\nimport {\n useBioTemplateComponents,\n type BioTemplateComponentBinding,\n type BioTemplateComponentBindingsById,\n type BioTemplateComponentImport,\n type BioTemplateComponentPropsByComponent,\n type BioTemplateComponentPropsBinding,\n type BioTemplateComponentPropsById,\n type BioTemplateComponentSnippet,\n type BioTemplateComponentUsage,\n type UseBioTemplateComponentsReturn,\n} from './useBioTemplateComponents'\n\nexport type BioTemplateWorkspaceTarget = BioTemplateControlTarget\n\nexport interface BioTemplateRendererBinding {\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope\n}\n\nexport interface BioTemplateWorkspaceBindings {\n renderer: BioTemplateRendererBinding | null\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: UseControlWorkspaceReturn<BioTemplateControlSchema>['bindings']['topBar']\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n pillNav: ControlWorkspacePillNavBinding\n componentBindings: BioTemplateComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n componentSnippets: BioTemplateComponentSnippet[]\n componentUsage: BioTemplateComponentUsage | null\n getComponentProps: UseBioTemplateComponentsReturn['getComponentProps']\n}\n\nexport interface UseBioTemplateWorkspaceReturn {\n target: BioTemplateWorkspaceTarget\n controls: UseControlSchemaReturn<BioTemplateControlSchema>\n workspace: UseControlWorkspaceReturn<BioTemplateControlSchema>\n controlSchema: BioTemplateControlSchema\n components: UseBioTemplateComponentsReturn\n values: UseControlWorkspaceReturn<BioTemplateControlSchema>['values']\n activeView: UseControlWorkspaceReturn<BioTemplateControlSchema>['activeView']\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: UseControlWorkspaceReturn<BioTemplateControlSchema>['topBar']\n pillNav: ControlWorkspacePillNavBinding\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n bindings: BioTemplateWorkspaceBindings\n renderer: BioTemplateRendererBinding | null\n componentBindings: BioTemplateComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentImports: BioTemplateComponentImport[]\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n componentSnippets: BioTemplateComponentSnippet[]\n componentUsage: BioTemplateComponentUsage | null\n getComponentProps: UseBioTemplateComponentsReturn['getComponentProps']\n}\n\n/** One-stop wiring for BioTemplateRenderer, FormBuilder, AppSidebar, and template-aware SDK components. */\nexport function useBioTemplateWorkspace(\n target: BioTemplateWorkspaceTarget,\n options: ControlWorkspaceOptions = {}\n): UseBioTemplateWorkspaceReturn {\n const controls = useBioTemplateControls(target, options)\n const workspace = useControlWorkspace(controls.controls, options)\n const components = useBioTemplateComponents(target)\n const renderer = isTemplateObjectTarget(target) ? { target } : null\n const bindings: BioTemplateWorkspaceBindings = {\n renderer,\n form: workspace.bindings.form,\n sidebar: workspace.bindings.sidebar,\n topBar: workspace.bindings.topBar,\n topBarSettings: workspace.bindings.topBarSettings,\n pillNav: workspace.bindings.pillNav,\n componentBindings: components.bindings,\n componentBindingsById: components.componentBindingsById,\n componentProps: components.componentProps,\n componentPropsById: components.componentPropsById,\n componentPropsByComponent: components.componentPropsByComponent,\n componentSnippets: components.snippets,\n componentUsage: components.usage,\n getComponentProps: components.getComponentProps,\n }\n\n return {\n target,\n controls,\n workspace,\n controlSchema: controls.controls,\n components,\n values: workspace.values,\n activeView: workspace.activeView,\n form: workspace.form,\n sidebar: workspace.sidebar,\n topBar: workspace.topBar,\n pillNav: workspace.pillNav,\n topBarSettings: workspace.topBarSettings,\n bindings,\n renderer,\n componentBindings: components.bindings,\n componentBindingsById: components.componentBindingsById,\n componentImports: components.imports,\n componentProps: components.componentProps,\n componentPropsById: components.componentPropsById,\n componentPropsByComponent: components.componentPropsByComponent,\n componentSnippets: components.snippets,\n componentUsage: components.usage,\n getComponentProps: components.getComponentProps,\n }\n}\n\nfunction isTemplateObjectTarget(\n target: BioTemplateWorkspaceTarget\n): target is BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope {\n return typeof target !== 'string'\n}\n","import {\n computed,\n effectScope,\n getCurrentScope,\n onScopeDispose,\n shallowRef,\n watch,\n type ComputedRef,\n type EffectScope,\n type Ref,\n} from 'vue'\nimport {\n createBioTemplatePackCollection,\n getBioTemplatePackInfo,\n type BioTemplatePackEntry,\n type TemplateCollectionEnvelope,\n type TemplatePackId,\n} from '../templates'\nimport {\n useTemplateCollection,\n type UseTemplateCollectionOptions,\n type UseTemplateCollectionReturn,\n} from './useTemplateCollection'\nimport {\n useBioTemplateWorkspace,\n type BioTemplateRendererBinding,\n type BioTemplateWorkspaceBindings,\n type UseBioTemplateWorkspaceReturn,\n} from './useBioTemplateWorkspace'\nimport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentSnippet,\n BioTemplateComponentUsage,\n} from './useBioTemplateComponents'\n\nexport type UseBioTemplatePackWorkspaceOptions = UseTemplateCollectionOptions\n\nexport interface UseBioTemplatePackWorkspaceReturn {\n packId: TemplatePackId\n pack: BioTemplatePackEntry\n collection: Ref<TemplateCollectionEnvelope>\n templates: UseTemplateCollectionReturn['templates']\n templateIds: UseTemplateCollectionReturn['templateIds']\n currentExperimentId: UseTemplateCollectionReturn['currentExperimentId']\n hasCurrentExperiment: UseTemplateCollectionReturn['hasCurrentExperiment']\n loading: UseTemplateCollectionReturn['isLoading']\n saving: UseTemplateCollectionReturn['isSaving']\n error: UseTemplateCollectionReturn['error']\n lastLoadedAt: UseTemplateCollectionReturn['lastLoadedAt']\n lastSavedAt: UseTemplateCollectionReturn['lastSavedAt']\n renderer: ComputedRef<BioTemplateRendererBinding>\n workspace: ComputedRef<UseBioTemplateWorkspaceReturn>\n form: ComputedRef<UseBioTemplateWorkspaceReturn['form']>\n sidebar: ComputedRef<UseBioTemplateWorkspaceReturn['sidebar']>\n topBar: ComputedRef<UseBioTemplateWorkspaceReturn['topBar']['value']>\n pillNav: ComputedRef<UseBioTemplateWorkspaceReturn['pillNav']>\n topBarSettings: ComputedRef<UseBioTemplateWorkspaceReturn['topBarSettings']>\n bindings: ComputedRef<BioTemplateWorkspaceBindings>\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentImports: ComputedRef<BioTemplateComponentImport[]>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n applyCollection: (value: unknown, metadata?: Record<string, unknown>) => TemplateCollectionEnvelope\n resetToDefaultCollection: () => TemplateCollectionEnvelope\n save: UseTemplateCollectionReturn['save']\n saveCurrent: UseTemplateCollectionReturn['saveCurrent']\n load: UseTemplateCollectionReturn['load']\n loadCurrent: UseTemplateCollectionReturn['loadCurrent']\n requireCurrentExperimentId: UseTemplateCollectionReturn['requireCurrentExperimentId']\n}\n\n/** Create a complete workspace for a curated biology template pack from a single pack id. */\nexport function useBioTemplatePackWorkspace(\n packId: TemplatePackId | string,\n options: UseBioTemplatePackWorkspaceOptions = {},\n): UseBioTemplatePackWorkspaceReturn {\n const pack = getBioTemplatePackInfo(packId)\n if (!pack) {\n throw new Error(`Unknown template pack '${packId}'.`)\n }\n const resolvedPack = pack\n\n const templateCollection = useTemplateCollection({\n ...options,\n initial: createDefaultCollection,\n })\n const collection = templateCollection.templateCollection\n let workspaceScope: EffectScope | undefined\n\n function createWorkspace(value: TemplateCollectionEnvelope): UseBioTemplateWorkspaceReturn {\n workspaceScope?.stop()\n workspaceScope = effectScope()\n return workspaceScope.run(() => useBioTemplateWorkspace(value))!\n }\n\n const workspaceRef = shallowRef<UseBioTemplateWorkspaceReturn>(createWorkspace(collection.value))\n const workspace = computed(() => workspaceRef.value)\n const renderer = computed<BioTemplateRendererBinding>(() => ({ target: collection.value }))\n const form = computed(() => workspace.value.form)\n const sidebar = computed(() => workspace.value.sidebar)\n const topBar = computed(() => workspace.value.topBar.value)\n const pillNav = computed(() => workspace.value.pillNav)\n const topBarSettings = computed(() => workspace.value.topBarSettings)\n const bindings = computed(() => workspace.value.bindings)\n const componentBindings = computed(() => workspace.value.componentBindings)\n const componentBindingsById = computed(() => workspace.value.componentBindingsById)\n const componentImports = computed(() => workspace.value.componentImports)\n const componentProps = computed(() => workspace.value.componentProps)\n const componentPropsById = computed(() => workspace.value.componentPropsById)\n const componentPropsByComponent = computed(() => workspace.value.componentPropsByComponent)\n const componentSnippets = computed(() => workspace.value.componentSnippets)\n const componentUsage = computed(() => workspace.value.componentUsage)\n\n watch(collection, value => {\n workspaceRef.value = createWorkspace(value)\n })\n\n if (getCurrentScope()) {\n onScopeDispose(() => workspaceScope?.stop())\n }\n\n function createDefaultCollection(): TemplateCollectionEnvelope {\n return createBioTemplatePackCollection(resolvedPack.name)\n }\n\n function applyCollection(\n value: unknown,\n metadata?: Record<string, unknown>,\n ): TemplateCollectionEnvelope {\n return templateCollection.apply(value, metadata)\n }\n\n function resetToDefaultCollection(): TemplateCollectionEnvelope {\n return templateCollection.apply(createDefaultCollection())\n }\n\n return {\n packId: resolvedPack.name,\n pack: resolvedPack,\n collection,\n templates: templateCollection.templates,\n templateIds: templateCollection.templateIds,\n currentExperimentId: templateCollection.currentExperimentId,\n hasCurrentExperiment: templateCollection.hasCurrentExperiment,\n loading: templateCollection.isLoading,\n saving: templateCollection.isSaving,\n error: templateCollection.error,\n lastLoadedAt: templateCollection.lastLoadedAt,\n lastSavedAt: templateCollection.lastSavedAt,\n renderer,\n workspace,\n form,\n sidebar,\n topBar,\n pillNav,\n topBarSettings,\n bindings,\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps: (component, options) => workspace.value.getComponentProps(component, options),\n applyCollection,\n resetToDefaultCollection,\n save: templateCollection.save,\n saveCurrent: templateCollection.saveCurrent,\n load: templateCollection.load,\n loadCurrent: templateCollection.loadCurrent,\n requireCurrentExperimentId: templateCollection.requireCurrentExperimentId,\n }\n}\n","import {\n computed,\n reactive,\n ref,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\nimport type { PillNavItem } from '../types'\nimport {\n createBioTemplatePresetCollectionFromControls,\n getBioTemplatePresetInfo,\n type BioTemplateControlValues,\n type BioTemplatePresetEntry,\n type TemplateCollectionEnvelope,\n type TemplatePresetId,\n} from '../templates'\nimport type {\n ControlWorkspaceOptions,\n ControlWorkspaceFormBinding,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlSchemaReturn,\n} from './useControlSchema'\nimport {\n useTemplateCollection,\n type UseTemplateCollectionOptions,\n type UseTemplateCollectionReturn,\n} from './useTemplateCollection'\nimport {\n useBioTemplateWorkspace,\n type BioTemplateRendererBinding,\n type UseBioTemplateWorkspaceReturn,\n} from './useBioTemplateWorkspace'\nimport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentSnippet,\n BioTemplateComponentUsage,\n} from './useBioTemplateComponents'\nimport type {\n BioTemplateControlSchema,\n} from './useBioTemplateControls'\n\nexport interface UseBioTemplatePresetWorkspaceOptions extends UseTemplateCollectionOptions {\n /** Optional schema-rendering options for the generated FormBuilder/AppSidebar controls. */\n controlOptions?: ControlWorkspaceOptions\n /** Initial control values for the generated preset. Merged over controlOptions.initialValues. */\n initialValues?: BioTemplateControlValues\n}\n\nexport interface UseBioTemplatePresetWorkspaceReturn {\n presetId: TemplatePresetId\n presetInfo: ComputedRef<BioTemplatePresetEntry | undefined>\n presetLabel: ComputedRef<string>\n collection: Ref<TemplateCollectionEnvelope>\n templates: UseTemplateCollectionReturn['templates']\n templateIds: UseTemplateCollectionReturn['templateIds']\n currentExperimentId: UseTemplateCollectionReturn['currentExperimentId']\n hasCurrentExperiment: UseTemplateCollectionReturn['hasCurrentExperiment']\n saving: UseTemplateCollectionReturn['isSaving']\n error: UseTemplateCollectionReturn['error']\n lastSavedAt: UseTemplateCollectionReturn['lastSavedAt']\n controls: UseControlSchemaReturn<BioTemplateControlSchema>\n controlSchema: BioTemplateControlSchema\n controlValues: Ref<BioTemplateControlValues>\n controlViewIds: ComputedRef<string[]>\n controlViewItems: ComputedRef<PillNavItem[]>\n activeControlView: Ref<string>\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: ComputedRef<ControlWorkspaceTopBarBinding>\n pillNav: ControlWorkspacePillNavBinding\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n bindings: BioTemplatePresetWorkspaceBindings\n renderer: ComputedRef<BioTemplateRendererBinding>\n workspace: ComputedRef<UseBioTemplateWorkspaceReturn>\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentImports: ComputedRef<BioTemplateComponentImport[]>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n setActiveControlView: (viewId: string) => void\n setControlValues: (values: BioTemplateControlValues) => TemplateCollectionEnvelope\n updateControlValues: (values: Partial<BioTemplateControlValues>) => TemplateCollectionEnvelope\n applyCollection: (value: TemplateCollectionEnvelope) => TemplateCollectionEnvelope\n resetToDefaultCollection: () => TemplateCollectionEnvelope\n save: UseTemplateCollectionReturn['save']\n saveCurrent: UseTemplateCollectionReturn['saveCurrent']\n}\n\nexport interface BioTemplatePresetWorkspaceBindings {\n renderer: ComputedRef<BioTemplateRendererBinding>\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: ComputedRef<ControlWorkspaceTopBarBinding>\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n pillNav: ControlWorkspacePillNavBinding\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n}\n\n/** Create a complete editable WellPlate/DoseCalculator workspace for dose design from a built-in biology template preset with current-experiment save wiring. */\nexport function useBioTemplatePresetWorkspace(\n presetId: TemplatePresetId,\n options: UseBioTemplatePresetWorkspaceOptions = {},\n): UseBioTemplatePresetWorkspaceReturn {\n const { controlOptions, initialValues, ...collectionOptions } = options\n const resolvedControlOptions = mergeInitialValues(controlOptions, initialValues)\n const presetWorkspace = useBioTemplateWorkspace(presetId, resolvedControlOptions)\n const presetInfo = computed(() => getBioTemplatePresetInfo(presetId))\n const presetLabel = computed(() => presetInfo.value?.label ?? humanizePresetId(presetId))\n const controls = presetWorkspace.controls\n const controlValues = ref<BioTemplateControlValues>({ ...controls.initialValues })\n const controlViewIds = computed(() => controls.viewIds)\n const controlViewItems = computed(() => controls.viewItems)\n const activeControlView = ref(controls.defaultView)\n const templateCollection = useTemplateCollection({\n ...collectionOptions,\n initial: createDefaultCollection,\n })\n const collection = templateCollection.templateCollection\n const workspace = computed(() => useBioTemplateWorkspace(collection.value, resolvedControlOptions))\n const renderer = computed<BioTemplateRendererBinding>(() => ({ target: collection.value }))\n const componentBindings = computed(() => workspace.value.componentBindings)\n const componentBindingsById = computed(() => workspace.value.componentBindingsById)\n const componentImports = computed(() => workspace.value.componentImports)\n const componentProps = computed(() => workspace.value.componentProps)\n const componentPropsById = computed(() => workspace.value.componentPropsById)\n const componentPropsByComponent = computed(() => workspace.value.componentPropsByComponent)\n const componentSnippets = computed(() => workspace.value.componentSnippets)\n const componentUsage = computed(() => workspace.value.componentUsage)\n const form = reactive({\n ...controls.form,\n modelValue: controlValues.value,\n 'onUpdate:modelValue': setControlValues,\n }) as ControlWorkspaceFormBinding\n const sidebar = reactive({\n ...controls.sidebar,\n activeView: activeControlView.value,\n modelValue: controlValues.value,\n 'onUpdate:modelValue': setControlValues,\n values: controlValues.value,\n 'onUpdate:values': setControlValues,\n }) as ControlWorkspaceSidebarBinding\n const pillNav = reactive({\n items: controls.viewItems,\n currentItemId: activeControlView.value,\n onSelect: (item: { id: string }) => setActiveControlView(item.id),\n }) as ControlWorkspacePillNavBinding\n const topBarSettings = reactive({\n showSettings: true,\n settingsConfig: {\n ...controls.topBarSettingsConfig,\n values: controlValues.value,\n },\n onSettingsValuesChange: setControlValues,\n }) as ControlWorkspaceTopBarSettingsBinding\n const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({\n pillNav: pillNav.items,\n currentPillId: pillNav.currentItemId,\n onPillSelect: pillNav.onSelect,\n ...topBarSettings,\n }))\n\n function getComponentProps(\n component: string,\n options?: Parameters<UseBioTemplateWorkspaceReturn['getComponentProps']>[1],\n ) {\n return workspace.value.getComponentProps(component, options)\n }\n\n const bindings: BioTemplatePresetWorkspaceBindings = {\n renderer,\n form,\n sidebar,\n topBar: topBarProps,\n topBarSettings,\n pillNav,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps,\n }\n\n function createDefaultCollection(): TemplateCollectionEnvelope {\n return createBioTemplatePresetCollectionFromControls(presetId, controls.initialValues)\n }\n\n watch(\n controlValues,\n (values) => {\n syncControlValueBindings(values)\n templateCollection.apply(createBioTemplatePresetCollectionFromControls(presetId, values))\n },\n { deep: true },\n )\n\n watch(activeControlView, (viewId) => {\n sidebar.activeView = viewId\n pillNav.currentItemId = viewId\n }, { flush: 'sync' })\n watch(() => sidebar.activeView, setActiveControlView, { flush: 'sync' })\n watch(() => pillNav.currentItemId, setActiveControlView, { flush: 'sync' })\n\n function applyCollection(value: TemplateCollectionEnvelope): TemplateCollectionEnvelope {\n return templateCollection.apply(value)\n }\n\n function setActiveControlView(viewId: string): void {\n if (!controlViewIds.value.includes(viewId)) return\n activeControlView.value = viewId\n }\n\n function setControlValues(values: BioTemplateControlValues): TemplateCollectionEnvelope {\n const nextValues = { ...values }\n controlValues.value = nextValues\n syncControlValueBindings(nextValues)\n return templateCollection.apply(createBioTemplatePresetCollectionFromControls(presetId, nextValues))\n }\n\n function updateControlValues(values: Partial<BioTemplateControlValues>): TemplateCollectionEnvelope {\n return setControlValues({\n ...controlValues.value,\n ...values,\n })\n }\n\n function resetToDefaultCollection(): TemplateCollectionEnvelope {\n return setControlValues({ ...controls.initialValues })\n }\n\n function syncControlValueBindings(values: BioTemplateControlValues): void {\n form.modelValue = values\n sidebar.modelValue = values\n sidebar.values = values\n topBarSettings.settingsConfig = {\n ...topBarSettings.settingsConfig,\n values,\n }\n }\n\n return {\n presetId,\n presetInfo,\n presetLabel,\n collection,\n templates: templateCollection.templates,\n templateIds: templateCollection.templateIds,\n currentExperimentId: templateCollection.currentExperimentId,\n hasCurrentExperiment: templateCollection.hasCurrentExperiment,\n saving: templateCollection.isSaving,\n error: templateCollection.error,\n lastSavedAt: templateCollection.lastSavedAt,\n controls,\n controlSchema: controls.controls,\n controlValues,\n controlViewIds,\n controlViewItems,\n activeControlView,\n form,\n sidebar,\n topBar: topBarProps,\n pillNav,\n topBarSettings,\n bindings,\n renderer,\n workspace,\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps,\n setActiveControlView,\n setControlValues,\n updateControlValues,\n applyCollection,\n resetToDefaultCollection,\n save: templateCollection.save,\n saveCurrent: templateCollection.saveCurrent,\n }\n}\n\nfunction humanizePresetId(value: string): string {\n return value\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, match => match.toUpperCase())\n}\n\nfunction mergeInitialValues(\n controlOptions: ControlWorkspaceOptions | undefined,\n initialValues: BioTemplateControlValues | undefined,\n): ControlWorkspaceOptions | undefined {\n if (initialValues === undefined) return controlOptions\n return {\n ...(controlOptions ?? {}),\n initialValues: {\n ...(controlOptions?.initialValues ?? {}),\n ...initialValues,\n },\n }\n}\n","import { ref, computed, type Ref, type ComputedRef } from 'vue'\nimport type { Rack, SlotPosition, WellPlateFormat, Well } from '../types'\n\nexport interface UseRackEditorOptions {\n defaultFormat?: WellPlateFormat\n defaultInjectionVolume?: number\n maxRacks?: number\n minRacks?: number\n}\n\nexport interface UseRackEditorReturn {\n racks: Ref<Rack[]>\n activeRack: ComputedRef<Rack | undefined>\n activeRackId: Ref<string>\n\n addRack(name?: string): Rack\n removeRack(rackId: string): void\n reorderRacks(fromIndex: number, toIndex: number): void\n updateRack(rackId: string, data: Partial<Rack>): void\n setActiveRack(rackId: string): void\n\n setWellData(rackId: string, wellId: string, data: Partial<Well>): void\n clearWell(rackId: string, wellId: string): void\n clearAllWells(rackId: string): void\n fillSeries(rackId: string, prefix?: string): void\n\n getAllWells(): Array<{ rackId: string; wellId: string; well: Partial<Well> }>\n totalSampleCount: ComputedRef<number>\n reset(): void\n}\n\nconst SLOT_CYCLE: SlotPosition[] = ['R', 'G', 'B', 'Y']\n\nconst PLATE_CONFIGS: Record<WellPlateFormat, { rows: number; cols: number }> = {\n 6: { rows: 2, cols: 3 },\n 12: { rows: 3, cols: 4 },\n 24: { rows: 4, cols: 6 },\n 48: { rows: 6, cols: 8 },\n 54: { rows: 6, cols: 9 },\n 96: { rows: 8, cols: 12 },\n 384: { rows: 16, cols: 24 },\n}\n\nlet globalIdCounter = 0\n\nfunction generateId(): string {\n globalIdCounter++\n return `rack-${Date.now()}-${globalIdCounter}`\n}\n\n/** Manages a set of sample racks with well-level assignment, series fill, and multi-rack reordering. */\nexport function useRackEditor(\n initialRacks?: Rack[],\n options?: UseRackEditorOptions,\n): UseRackEditorReturn {\n const defaultFormat = options?.defaultFormat ?? 54\n const defaultInjVol = options?.defaultInjectionVolume ?? 5\n const maxRacks = options?.maxRacks ?? 10\n const minRacks = options?.minRacks ?? 1\n\n function createDefaultRack(name?: string, slotIndex?: number): Rack {\n const slot = SLOT_CYCLE[(slotIndex ?? 0) % SLOT_CYCLE.length]!\n return {\n id: generateId(),\n name: name ?? `Rack ${racks.value.length + 1}`,\n format: defaultFormat,\n slot,\n injectionVolume: defaultInjVol,\n wells: {},\n }\n }\n\n const racks = ref<Rack[]>(\n initialRacks && initialRacks.length > 0\n ? initialRacks.map(r => ({ ...r }))\n : [createDefaultRack('Rack 1', 0)]\n ) as Ref<Rack[]>\n\n const activeRackId = ref<string>(racks.value[0]?.id ?? '')\n\n const activeRack = computed(() =>\n racks.value.find(r => r.id === activeRackId.value) ?? racks.value[0]\n )\n\n function addRack(name?: string): Rack {\n if (racks.value.length >= maxRacks) {\n return racks.value[racks.value.length - 1]!\n }\n const rack = createDefaultRack(name, racks.value.length)\n racks.value.push(rack)\n activeRackId.value = rack.id\n return rack\n }\n\n function removeRack(rackId: string): void {\n if (racks.value.length <= minRacks) return\n const index = racks.value.findIndex(r => r.id === rackId)\n if (index === -1) return\n racks.value.splice(index, 1)\n if (activeRackId.value === rackId && racks.value[0]) {\n activeRackId.value = racks.value[0].id\n }\n }\n\n function reorderRacks(fromIndex: number, toIndex: number): void {\n if (fromIndex < 0 || fromIndex >= racks.value.length) return\n if (toIndex < 0 || toIndex >= racks.value.length) return\n if (fromIndex === toIndex) return\n const [moved] = racks.value.splice(fromIndex, 1)\n if (moved) {\n racks.value.splice(toIndex, 0, moved)\n }\n }\n\n function updateRack(rackId: string, data: Partial<Rack>): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n if (data.name !== undefined) rack.name = data.name\n if (data.format !== undefined) rack.format = data.format\n if (data.slot !== undefined) rack.slot = data.slot\n if (data.injectionVolume !== undefined) rack.injectionVolume = data.injectionVolume\n if (data.wells !== undefined) rack.wells = data.wells\n }\n\n function setActiveRack(rackId: string): void {\n if (racks.value.some(r => r.id === rackId)) {\n activeRackId.value = rackId\n }\n }\n\n function setWellData(rackId: string, wellId: string, data: Partial<Well>): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n rack.wells[wellId] = { ...rack.wells[wellId], ...data }\n }\n\n function clearWell(rackId: string, wellId: string): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n delete rack.wells[wellId]\n }\n\n function clearAllWells(rackId: string): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n rack.wells = {}\n }\n\n function fillSeries(rackId: string, prefix: string = 'S'): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n\n const config = PLATE_CONFIGS[rack.format]\n if (!config) return\n\n let counter = 1\n for (let row = 0; row < config.rows; row++) {\n for (let col = 0; col < config.cols; col++) {\n const rowLabel = String.fromCharCode(65 + row)\n const wellId = `${rowLabel}${col + 1}`\n // Only fill empty wells\n if (!rack.wells[wellId]?.sampleType) {\n const paddedNum = String(counter).padStart(3, '0')\n rack.wells[wellId] = {\n id: wellId,\n row,\n col,\n state: 'filled',\n sampleType: 'sample',\n metadata: {\n label: `${prefix}${paddedNum}`,\n injectionVolume: rack.injectionVolume,\n injectionCount: 1,\n },\n }\n }\n counter++\n }\n }\n }\n\n function getAllWells(): Array<{ rackId: string; wellId: string; well: Partial<Well> }> {\n const result: Array<{ rackId: string; wellId: string; well: Partial<Well> }> = []\n for (const rack of racks.value) {\n for (const [wellId, well] of Object.entries(rack.wells)) {\n result.push({ rackId: rack.id, wellId, well })\n }\n }\n return result\n }\n\n const totalSampleCount = computed(() => {\n let count = 0\n for (const rack of racks.value) {\n count += Object.keys(rack.wells).length\n }\n return count\n })\n\n function reset(): void {\n racks.value = [createDefaultRack('Rack 1', 0)]\n activeRackId.value = racks.value[0]!.id\n }\n\n return {\n racks,\n activeRack,\n activeRackId,\n addRack,\n removeRack,\n reorderRacks,\n updateRack,\n setActiveRack,\n setWellData,\n clearWell,\n clearAllWells,\n fillSeries,\n getAllWells,\n totalSampleCount,\n reset,\n }\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { GroupItem } from '../types'\n\nexport type GroupAssignmentZone = 'zone1' | 'zone2'\n\nexport type GroupAssignmentSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface GroupAssignmentState {\n group1: string[]\n group2: string[]\n}\n\nexport interface UseGroupAssignmentOptions {\n groups: GroupAssignmentSource<readonly GroupItem[]>\n group1: GroupAssignmentSource<readonly string[]>\n group2: GroupAssignmentSource<readonly string[]>\n label1?: GroupAssignmentSource<string | null | undefined>\n label2?: GroupAssignmentSource<string | null | undefined>\n minPerGroup?: GroupAssignmentSource<number | null | undefined>\n}\n\nexport interface UseGroupAssignmentReturn {\n unassignedGroups: ComputedRef<GroupItem[]>\n zone1Groups: ComputedRef<GroupItem[]>\n zone2Groups: ComputedRef<GroupItem[]>\n zone1Count: ComputedRef<number>\n zone2Count: ComputedRef<number>\n isValid: ComputedRef<boolean>\n validationMessage: ComputedRef<string | null>\n getZoneForGroup: (groupName: string) => GroupAssignmentZone | null\n assignToZone: (groupName: string, zone: GroupAssignmentZone) => GroupAssignmentState\n removeFromZone: (groupName: string, zone: GroupAssignmentZone) => GroupAssignmentState\n clearAll: () => GroupAssignmentState\n}\n\n/** Shared two-zone group assignment model for control/treatment style workflows. */\nexport function useGroupAssignment(options: UseGroupAssignmentOptions): UseGroupAssignmentReturn {\n const groups = computed(() => [...toValue(options.groups)])\n const group1 = computed(() => [...toValue(options.group1)])\n const group2 = computed(() => [...toValue(options.group2)])\n const label1 = computed(() => toValue(options.label1) || 'Control')\n const label2 = computed(() => toValue(options.label2) || 'Treatment')\n const minPerGroup = computed(() => normalizeMinimum(toValue(options.minPerGroup)))\n const group1Set = computed(() => new Set(group1.value))\n const group2Set = computed(() => new Set(group2.value))\n\n const unassignedGroups = computed(() =>\n groups.value.filter(group => !group1Set.value.has(group.name) && !group2Set.value.has(group.name))\n )\n\n const zone1Groups = computed(() =>\n groups.value.filter(group => group1Set.value.has(group.name))\n )\n\n const zone2Groups = computed(() =>\n groups.value.filter(group => group2Set.value.has(group.name))\n )\n\n const zone1Count = computed(() =>\n zone1Groups.value.reduce((sum, group) => sum + group.count, 0)\n )\n\n const zone2Count = computed(() =>\n zone2Groups.value.reduce((sum, group) => sum + group.count, 0)\n )\n\n const isValid = computed(() =>\n group1.value.length >= minPerGroup.value &&\n group2.value.length >= minPerGroup.value\n )\n\n const validationMessage = computed(() => {\n if (isValid.value) return null\n const missing1 = Math.max(0, minPerGroup.value - group1.value.length)\n const missing2 = Math.max(0, minPerGroup.value - group2.value.length)\n const parts: string[] = []\n if (missing1 > 0) parts.push(`${missing1} more to ${label1.value}`)\n if (missing2 > 0) parts.push(`${missing2} more to ${label2.value}`)\n return `Add ${parts.join(' and ')}`\n })\n\n function getZoneForGroup(groupName: string): GroupAssignmentZone | null {\n if (group1Set.value.has(groupName)) return 'zone1'\n if (group2Set.value.has(groupName)) return 'zone2'\n return null\n }\n\n function assignToZone(groupName: string, zone: GroupAssignmentZone): GroupAssignmentState {\n const next = removeFromBoth(groupName)\n if (zone === 'zone1') {\n return {\n group1: [...next.group1, groupName],\n group2: next.group2,\n }\n }\n return {\n group1: next.group1,\n group2: [...next.group2, groupName],\n }\n }\n\n function removeFromZone(groupName: string, zone: GroupAssignmentZone): GroupAssignmentState {\n if (zone === 'zone1') {\n return {\n group1: group1.value.filter(name => name !== groupName),\n group2: group2.value,\n }\n }\n return {\n group1: group1.value,\n group2: group2.value.filter(name => name !== groupName),\n }\n }\n\n function clearAll(): GroupAssignmentState {\n return { group1: [], group2: [] }\n }\n\n function removeFromBoth(groupName: string): GroupAssignmentState {\n return {\n group1: group1.value.filter(name => name !== groupName),\n group2: group2.value.filter(name => name !== groupName),\n }\n }\n\n return {\n unassignedGroups,\n zone1Groups,\n zone2Groups,\n zone1Count,\n zone2Count,\n isValid,\n validationMessage,\n getZoneForGroup,\n assignToZone,\n removeFromZone,\n clearAll,\n }\n}\n\nfunction normalizeMinimum(value: number | null | undefined): number {\n if (value === null || value === undefined || !Number.isFinite(value)) return 1\n return Math.max(0, Math.floor(value))\n}\n","/**\n * Composable for generating dilution series used in plate-based experiments.\n * Provides geometric series generation from presets (2x, 3x, ½ log, 10x)\n * and utility functions for series manipulation.\n */\n\nexport interface LevelEntry {\n value: number\n replicates: number\n}\n\nexport interface DilutionPreset {\n label: string\n factor: number | 'half-log'\n}\n\nexport const DEFAULT_PRESETS: DilutionPreset[] = [\n { label: '2x', factor: 2 },\n { label: '3x', factor: 3 },\n { label: '½ log', factor: 'half-log' },\n { label: '10x', factor: 10 },\n]\n\nexport const DEFAULT_UNITS = ['µM', 'nM', 'mM', 'pM']\n\nfunction resolveFactor(factor: number | 'half-log'): number {\n return factor === 'half-log' ? Math.sqrt(10) : factor\n}\n\nfunction roundToSignificant(value: number, digits: number = 4): number {\n if (value === 0) return 0\n const magnitude = Math.floor(Math.log10(Math.abs(value))) + 1\n const factor = Math.pow(10, digits - magnitude)\n return Math.round(value * factor) / factor\n}\n\nexport function generateDilutionSeries(\n startConcentration: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates: number = 1,\n): LevelEntry[] {\n if (count < 1 || startConcentration <= 0) return []\n\n const divisor = resolveFactor(factor)\n const levels: LevelEntry[] = []\n\n for (let i = 0; i < count; i++) {\n levels.push({\n value: roundToSignificant(startConcentration / Math.pow(divisor, i)),\n replicates: defaultReplicates,\n })\n }\n\n return levels\n}\n\nexport interface UseReagentSeriesReturn {\n generateSeries: (\n start: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates?: number,\n ) => LevelEntry[]\n sortLevels: (levels: LevelEntry[], order?: 'asc' | 'desc') => LevelEntry[]\n totalPositions: (levels: LevelEntry[]) => number\n}\n\n/** Generates and sorts geometric dilution series (2x, 3x, ½ log, 10x) for plate-based experiments. */\nexport function useReagentSeries(): UseReagentSeriesReturn {\n function generateSeries(\n start: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates: number = 1,\n ): LevelEntry[] {\n return generateDilutionSeries(start, count, factor, defaultReplicates)\n }\n\n function sortLevels(levels: LevelEntry[], order: 'asc' | 'desc' = 'desc'): LevelEntry[] {\n return [...levels].sort((a, b) =>\n order === 'desc' ? b.value - a.value : a.value - b.value,\n )\n }\n\n function totalPositions(levels: LevelEntry[]): number {\n return levels.reduce((sum, l) => sum + l.replicates, 0)\n }\n\n return { generateSeries, sortLevels, totalPositions }\n}\n","import { ref, computed, type Ref, type ComputedRef } from 'vue'\nimport type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'\n\n// Parameter definition for step templates\nexport interface ParameterDefinition {\n key: string\n label: string\n type: 'number' | 'text' | 'select' | 'concentration' | 'temperature' | 'duration' | 'reagent'\n unit?: string\n options?: Array<{ value: string; label: string }>\n required?: boolean\n default?: unknown\n min?: number\n max?: number\n placeholder?: string\n}\n\n// Step template definition\nexport interface StepTemplate {\n id: string\n type: ProtocolStepType\n name: string\n description?: string\n defaultDuration?: number\n parameters: ParameterDefinition[]\n isBuiltIn?: boolean\n}\n\n// Validation result\nexport interface ValidationResult {\n valid: boolean\n errors: Record<string, string>\n}\n\nexport interface UseProtocolTemplatesReturn {\n builtInTemplates: StepTemplate[]\n customTemplates: Ref<StepTemplate[]>\n allTemplates: ComputedRef<StepTemplate[]>\n getTemplateByType: (type: ProtocolStepType) => StepTemplate | undefined\n getTemplateById: (id: string) => StepTemplate | undefined\n saveCustomTemplate: (template: StepTemplate) => void\n deleteCustomTemplate: (templateId: string) => void\n validateStep: (step: ProtocolStep, template: StepTemplate) => ValidationResult\n createStepFromTemplate: (template: StepTemplate, overrides?: Partial<ProtocolStep>) => ProtocolStep\n formatParameterValue: (value: unknown, param: ParameterDefinition) => string\n}\n\n// Built-in templates\nconst BUILT_IN_TEMPLATES: StepTemplate[] = [\n {\n id: 'builtin-incubation',\n type: 'incubation',\n name: 'Incubation',\n description: 'Incubate samples at specified conditions',\n defaultDuration: 60,\n isBuiltIn: true,\n parameters: [\n {\n key: 'temperature',\n label: 'Temperature',\n type: 'temperature',\n unit: '°C',\n required: true,\n default: 37,\n min: -80,\n max: 100,\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'duration',\n unit: 'hours',\n required: true,\n default: 24,\n min: 0,\n },\n {\n key: 'co2',\n label: 'CO2',\n type: 'number',\n unit: '%',\n required: false,\n default: 5,\n min: 0,\n max: 100,\n },\n {\n key: 'humidity',\n label: 'Humidity',\n type: 'number',\n unit: '%',\n required: false,\n default: 95,\n min: 0,\n max: 100,\n },\n ],\n },\n {\n id: 'builtin-wash',\n type: 'wash',\n name: 'Wash',\n description: 'Wash samples with buffer',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'buffer',\n label: 'Buffer',\n type: 'select',\n required: true,\n default: 'PBS',\n options: [\n { value: 'PBS', label: 'PBS' },\n { value: 'PBST', label: 'PBST' },\n { value: 'TBS', label: 'TBS' },\n { value: 'TBST', label: 'TBST' },\n { value: 'Water', label: 'Water' },\n { value: 'Other', label: 'Other' },\n ],\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 200,\n min: 0,\n },\n {\n key: 'cycles',\n label: 'Wash Cycles',\n type: 'number',\n required: true,\n default: 3,\n min: 1,\n max: 10,\n },\n ],\n },\n {\n id: 'builtin-addition',\n type: 'addition',\n name: 'Addition',\n description: 'Add reagent or compound to samples',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'reagent',\n label: 'Reagent',\n type: 'text',\n required: true,\n placeholder: 'Enter reagent name',\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 100,\n min: 0,\n },\n {\n key: 'concentration',\n label: 'Concentration',\n type: 'concentration',\n required: false,\n },\n ],\n },\n {\n id: 'builtin-measurement',\n type: 'measurement',\n name: 'Measurement',\n description: 'Take measurements using specified instrument',\n defaultDuration: 15,\n isBuiltIn: true,\n parameters: [\n {\n key: 'instrument',\n label: 'Instrument',\n type: 'select',\n required: true,\n options: [\n { value: 'plate_reader', label: 'Plate Reader' },\n { value: 'microscope', label: 'Microscope' },\n { value: 'flow_cytometer', label: 'Flow Cytometer' },\n { value: 'spectrophotometer', label: 'Spectrophotometer' },\n { value: 'other', label: 'Other' },\n ],\n },\n {\n key: 'readout',\n label: 'Readout Type',\n type: 'text',\n required: false,\n placeholder: 'e.g., Absorbance 450nm',\n },\n {\n key: 'notes',\n label: 'Parameters',\n type: 'text',\n required: false,\n placeholder: 'Additional parameters',\n },\n ],\n },\n {\n id: 'builtin-centrifuge',\n type: 'centrifuge',\n name: 'Centrifuge',\n description: 'Centrifuge samples',\n defaultDuration: 10,\n isBuiltIn: true,\n parameters: [\n {\n key: 'speed',\n label: 'Speed',\n type: 'number',\n unit: 'RPM',\n required: true,\n default: 1000,\n min: 100,\n max: 20000,\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'number',\n unit: 'min',\n required: true,\n default: 5,\n min: 1,\n },\n {\n key: 'temperature',\n label: 'Temperature',\n type: 'temperature',\n unit: '°C',\n required: false,\n default: 4,\n min: -10,\n max: 40,\n },\n ],\n },\n {\n id: 'builtin-transfer',\n type: 'transfer',\n name: 'Transfer',\n description: 'Transfer samples between containers',\n defaultDuration: 10,\n isBuiltIn: true,\n parameters: [\n {\n key: 'source',\n label: 'Source',\n type: 'text',\n required: true,\n placeholder: 'Source container',\n },\n {\n key: 'destination',\n label: 'Destination',\n type: 'text',\n required: true,\n placeholder: 'Destination container',\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 100,\n min: 0,\n },\n ],\n },\n {\n id: 'builtin-mix',\n type: 'mix',\n name: 'Mix',\n description: 'Mix samples',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'method',\n label: 'Method',\n type: 'select',\n required: true,\n default: 'pipette',\n options: [\n { value: 'pipette', label: 'Pipette mixing' },\n { value: 'vortex', label: 'Vortex' },\n { value: 'shaker', label: 'Orbital shaker' },\n { value: 'inversion', label: 'Inversion' },\n ],\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'number',\n unit: 'sec',\n required: false,\n default: 30,\n min: 1,\n },\n {\n key: 'speed',\n label: 'Speed/Intensity',\n type: 'text',\n required: false,\n placeholder: 'e.g., 300 RPM',\n },\n ],\n },\n {\n id: 'builtin-custom',\n type: 'custom',\n name: 'Custom Step',\n description: 'Custom protocol step',\n defaultDuration: 15,\n isBuiltIn: true,\n parameters: [\n {\n key: 'description',\n label: 'Description',\n type: 'text',\n required: true,\n placeholder: 'Describe the step',\n },\n {\n key: 'notes',\n label: 'Notes',\n type: 'text',\n required: false,\n placeholder: 'Additional notes',\n },\n ],\n },\n]\n\n// Storage key for custom templates\nconst STORAGE_KEY = 'mint-custom-protocol-templates'\n\nfunction loadCustomTemplates(): StepTemplate[] {\n try {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) {\n return JSON.parse(stored)\n }\n } catch {\n // Ignore errors\n }\n return []\n}\n\nfunction saveCustomTemplatesToStorage(templates: StepTemplate[]) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(templates))\n } catch {\n // Ignore errors\n }\n}\n\n/** Provides built-in and custom protocol step templates with validation and step creation helpers. */\nexport function useProtocolTemplates(): UseProtocolTemplatesReturn {\n const customTemplates = ref<StepTemplate[]>(loadCustomTemplates())\n\n const allTemplates = computed(() => {\n return [...BUILT_IN_TEMPLATES, ...customTemplates.value]\n })\n\n function getTemplateByType(type: ProtocolStepType): StepTemplate | undefined {\n // First check custom templates, then built-in\n return (\n customTemplates.value.find((t) => t.type === type) ||\n BUILT_IN_TEMPLATES.find((t) => t.type === type)\n )\n }\n\n function getTemplateById(id: string): StepTemplate | undefined {\n return (\n customTemplates.value.find((t) => t.id === id) ||\n BUILT_IN_TEMPLATES.find((t) => t.id === id)\n )\n }\n\n function saveCustomTemplate(template: StepTemplate) {\n const newTemplate = {\n ...template,\n isBuiltIn: false,\n id: template.id || `custom-${Date.now()}`,\n }\n\n const index = customTemplates.value.findIndex((t) => t.id === newTemplate.id)\n if (index >= 0) {\n customTemplates.value[index] = newTemplate\n } else {\n customTemplates.value.push(newTemplate)\n }\n\n saveCustomTemplatesToStorage(customTemplates.value)\n }\n\n function deleteCustomTemplate(templateId: string) {\n const index = customTemplates.value.findIndex((t) => t.id === templateId)\n if (index >= 0) {\n customTemplates.value.splice(index, 1)\n saveCustomTemplatesToStorage(customTemplates.value)\n }\n }\n\n function validateStep(step: ProtocolStep, template: StepTemplate): ValidationResult {\n const errors: Record<string, string> = {}\n\n if (!step.name || step.name.trim() === '') {\n errors.name = 'Step name is required'\n }\n\n for (const param of template.parameters) {\n if (param.required) {\n const value = step.parameters?.[param.key]\n if (value === undefined || value === null || value === '') {\n errors[param.key] = `${param.label} is required`\n }\n }\n\n if (param.type === 'number' || param.type === 'temperature' || param.type === 'duration') {\n const value = step.parameters?.[param.key]\n if (value !== undefined && value !== null && value !== '') {\n const numValue = Number(value)\n if (isNaN(numValue)) {\n errors[param.key] = `${param.label} must be a number`\n } else {\n if (param.min !== undefined && numValue < param.min) {\n errors[param.key] = `${param.label} must be at least ${param.min}`\n }\n if (param.max !== undefined && numValue > param.max) {\n errors[param.key] = `${param.label} must be at most ${param.max}`\n }\n }\n }\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors,\n }\n }\n\n function createStepFromTemplate(\n template: StepTemplate,\n overrides?: Partial<ProtocolStep>\n ): ProtocolStep {\n // Build default parameters from template\n const parameters: Record<string, unknown> = {}\n for (const param of template.parameters) {\n if (param.default !== undefined) {\n parameters[param.key] = param.default\n }\n }\n\n return {\n id: `step-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n type: template.type,\n name: template.name,\n description: template.description,\n duration: template.defaultDuration,\n status: 'pending' as ProtocolStepStatus,\n parameters,\n order: 0,\n ...overrides,\n }\n }\n\n function formatParameterValue(value: unknown, param: ParameterDefinition): string {\n if (value === undefined || value === null || value === '') {\n return '-'\n }\n\n if (param.type === 'select' && param.options) {\n const option = param.options.find((o) => o.value === value)\n if (option) return option.label\n }\n\n if (param.type === 'concentration' && typeof value === 'object') {\n const conc = value as { value: number; unit: string }\n return `${conc.value} ${conc.unit}`\n }\n\n const strValue = String(value)\n if (param.unit) {\n return `${strValue} ${param.unit}`\n }\n\n return strValue\n }\n\n return {\n builtInTemplates: BUILT_IN_TEMPLATES,\n customTemplates,\n allTemplates,\n getTemplateByType,\n getTemplateById,\n saveCustomTemplate,\n deleteCustomTemplate,\n validateStep,\n createStepFromTemplate,\n formatParameterValue,\n }\n}\n","import { ref, computed, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport type { TreeNode, SummaryData } from '../types'\n\nexport interface UseExperimentDataOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseExperimentDataReturn {\n /** Raw experiment data payload from `/experiments/{id}/data`, or null. */\n data: Ref<Record<string, unknown> | null>\n /** Hierarchy tree rows normalised from `tree_data` or `treeData`. */\n treeData: ComputedRef<TreeNode[]>\n /** Table rows normalised from `table_data` or `tableData`. */\n tableData: ComputedRef<Record<string, unknown>[]>\n /** Summary payload normalised from `summary_data` or `summaryData`, or null. */\n summaryData: ComputedRef<SummaryData | null>\n /** Whether experiment data is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment data fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Fetch experiment data for an experiment id. */\n fetch: (experimentId: number) => Promise<void>\n /** Refetch the most recently fetched experiment id. */\n refresh: () => Promise<void>\n}\n\n/** Fetches and normalises experiment output data (tree, table, summary) from the platform API. */\nexport function useExperimentData(\n options: UseExperimentDataOptions = {},\n): UseExperimentDataReturn {\n const api = useApi({ baseUrl: options.apiBaseUrl })\n\n const data = ref<Record<string, unknown> | null>(null)\n const request = useRequestSyncState('Failed to fetch experiment data')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n let lastExperimentId: number | null = null\n\n const treeData = computed<TreeNode[]>(() => {\n if (!data.value) return []\n const tree = data.value.tree_data ?? data.value.treeData\n return Array.isArray(tree) ? tree as TreeNode[] : []\n })\n\n const tableData = computed<Record<string, unknown>[]>(() => {\n if (!data.value) return []\n const table = data.value.table_data ?? data.value.tableData\n return Array.isArray(table) ? table as Record<string, unknown>[] : []\n })\n\n const summaryData = computed<SummaryData | null>(() => {\n if (!data.value) return null\n const summary = data.value.summary_data ?? data.value.summaryData\n if (summary && typeof summary === 'object' && 'metadata' in (summary as Record<string, unknown>)) {\n return summary as SummaryData\n }\n return null\n })\n\n async function fetchData(experimentId: number): Promise<void> {\n lastExperimentId = experimentId\n try {\n data.value = await request.run(\n () => api.get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { success: 'load', errorMessage: 'Failed to fetch experiment data' },\n )\n } catch {\n data.value = null\n }\n }\n\n async function refresh(): Promise<void> {\n if (lastExperimentId !== null) {\n await fetchData(lastExperimentId)\n }\n }\n\n return {\n data,\n treeData,\n tableData,\n summaryData,\n isLoading,\n error,\n lastLoadedAt,\n fetch: fetchData,\n refresh,\n }\n}\n"],"mappings":"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;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY;GACV;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACL,KAAK;IACN;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACN;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACL,KAAK;IACN;GACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY;GACV;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACN;GACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY;GACV;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,SAAS;IACT,SAAS;KACP;MAAE,OAAO;MAAW,OAAO;MAAkB;KAC7C;MAAE,OAAO;MAAU,OAAO;MAAU;KACpC;MAAE,OAAO;MAAU,OAAO;MAAkB;KAC5C;MAAE,OAAO;MAAa,OAAO;MAAa;KAC3C;IACF;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACN;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CACD;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY,CACV;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,UAAU;GACV,aAAa;GACd,EACD;GACE,KAAK;GACL,O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"}
|