@morscherlab/mint-sdk 1.0.0 → 1.0.1
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/dist/BaseModal-B9UA8Y_I.js +165 -0
- package/dist/BaseModal-B9UA8Y_I.js.map +1 -0
- package/dist/BaseSelect-DksaKYq_.js +176 -0
- package/dist/BaseSelect-DksaKYq_.js.map +1 -0
- package/dist/ExperimentPopover-CCYB1oWp.js +361 -0
- package/dist/ExperimentPopover-CCYB1oWp.js.map +1 -0
- package/dist/ExperimentPopover-D0bg_fqM.js +3 -0
- package/dist/ExperimentSelectorModal-B_kPbXcg.js +4 -0
- package/dist/ExperimentSelectorModal-wm7yUdAr.js +720 -0
- package/dist/ExperimentSelectorModal-wm7yUdAr.js.map +1 -0
- package/dist/SettingsModal-L7Ejny45.js +5 -0
- package/dist/SettingsModal-LEKI6Ebl.js +521 -0
- package/dist/SettingsModal-LEKI6Ebl.js.map +1 -0
- package/dist/{auth-BulIv_km.js → auth-D9q2GIcv.js} +3 -80
- package/dist/auth-D9q2GIcv.js.map +1 -0
- package/dist/components/DataFrame.vue.d.ts +3 -0
- package/dist/components/ExperimentDataViewer.vue.d.ts +2 -0
- package/dist/components/PluginWorkspaceView.vue.d.ts +2 -2
- package/dist/components/index.js +7 -2
- package/dist/{components-DtX3LDLq.js → components-CdjRzHI2.js} +533 -2025
- package/dist/components-CdjRzHI2.js.map +1 -0
- package/dist/composables/index.js +9 -3
- package/dist/composables/usePluginClient.d.ts +2 -1
- package/dist/{composables-wNt7VtkF.js → composables-DJgqPrlR.js} +7 -12
- package/dist/{composables-wNt7VtkF.js.map → composables-DJgqPrlR.js.map} +1 -1
- package/dist/experiment-utils-hGXMHlAc.js +109 -0
- package/dist/experiment-utils-hGXMHlAc.js.map +1 -0
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/install.js +7 -2
- package/dist/install.js.map +1 -1
- package/dist/permissions.js +81 -0
- package/dist/permissions.js.map +1 -0
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +3233 -3185
- package/dist/templates/index.js +3 -1
- package/dist/templates-Do43ZIMb.js +5065 -0
- package/dist/templates-Do43ZIMb.js.map +1 -0
- package/dist/{templates-DSbHJC4v.js → useControlSchema-0n8Bcftq.js} +10 -5335
- package/dist/useControlSchema-0n8Bcftq.js.map +1 -0
- package/dist/useDropdownState-Ben4DnjJ.js +47 -0
- package/dist/useDropdownState-Ben4DnjJ.js.map +1 -0
- package/dist/useEventListener-CfVkP9Xz.js +57 -0
- package/dist/useEventListener-CfVkP9Xz.js.map +1 -0
- package/dist/useExperimentSelector-BpZklTbV.js +469 -0
- package/dist/useExperimentSelector-BpZklTbV.js.map +1 -0
- package/dist/useFormBuilder-COfYWDuC.js +729 -0
- package/dist/useFormBuilder-COfYWDuC.js.map +1 -0
- package/dist/{useProtocolTemplates-DwBhEPPU.js → useProtocolTemplates-TUQO_F3n.js} +8 -1298
- package/dist/useProtocolTemplates-TUQO_F3n.js.map +1 -0
- package/dist/utils/pluginIcon.d.ts +29 -2
- package/package.json +5 -1
- package/src/__tests__/components/DataFrame.test.ts +37 -0
- package/src/__tests__/components/PluginIcon.test.ts +77 -0
- package/src/__tests__/composables/usePluginClient.test.ts +11 -10
- package/src/components/AppTopBar.vue +7 -6
- package/src/components/DataFrame.vue +27 -2
- package/src/components/ExperimentDataViewer.vue +5 -1
- package/src/components/PluginIcon.story.vue +31 -1
- package/src/components/PluginIcon.vue +94 -4
- package/src/composables/usePluginClient.ts +3 -12
- package/src/styles/components/dataframe.css +26 -0
- package/src/styles/components/plugin-icon.css +5 -0
- package/src/utils/pluginIcon.ts +159 -2
- package/dist/auth-BulIv_km.js.map +0 -1
- package/dist/components-DtX3LDLq.js.map +0 -1
- package/dist/templates-DSbHJC4v.js.map +0 -1
- package/dist/useProtocolTemplates-DwBhEPPU.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProtocolTemplates-TUQO_F3n.js","names":[],"sources":["../src/composables/useSortedItems.ts","../src/composables/useTextSearch.ts","../src/composables/useToast.ts","../src/composables/useTheme.ts","../src/composables/useAppExperiment.ts","../src/composables/useDoseCalculator.ts","../src/composables/useWellPlateEditor.ts","../src/composables/autoGroup/tokenize.ts","../src/composables/autoGroup/classKey.ts","../src/composables/autoGroup/vocab.json","../src/composables/autoGroup/classify.ts","../src/composables/autoGroup/columns.ts","../src/composables/autoGroup/cooccurrence.ts","../src/composables/autoGroup/colors.ts","../src/composables/autoGroup/compose.ts","../src/composables/autoGroup/fingerprint.ts","../src/composables/autoGroup/template.ts","../src/composables/autoGroup/replicatePreGroup.ts","../src/composables/experimentDesignData.ts","../src/composables/autoGroup/csv-shim.ts","../src/composables/useAutoGroup.ts","../src/utils/color.ts","../src/composables/useSampleGroups.ts","../src/composables/useExpansionSet.ts","../src/composables/platformContextHelpers.ts","../src/composables/useExperimentData.ts","../src/composables/useExperimentSamples.ts","../src/composables/useScheduleDrag.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/protocolTemplateCatalog.ts","../src/composables/useProtocolTemplates.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 {\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","const DELIMITER_CANDIDATES = ['_', '-', '.'] as const\nexport type Delimiter = (typeof DELIMITER_CANDIDATES)[number]\n\n/** Pick the delimiter whose split produces the most consistent field count across `lines`. */\nexport function pickPrimaryDelimiter(lines: string[]): Delimiter {\n if (lines.length === 0) return '_'\n\n let best: Delimiter = '_'\n let bestScore = -1\n\n for (const candidate of DELIMITER_CANDIDATES) {\n const counts = lines.map(l => l.split(candidate).length)\n const frequency = new Map<number, number>()\n for (const c of counts) frequency.set(c, (frequency.get(c) ?? 0) + 1)\n\n // Mode and its frequency\n let mode = 1\n let modeFreq = 0\n for (const [c, f] of frequency) {\n if (f > modeFreq || (f === modeFreq && c > mode)) {\n mode = c\n modeFreq = f\n }\n }\n\n // A delimiter that produces field count 1 didn't split anything — score 0.\n const score = mode > 1 ? modeFreq / lines.length : 0\n if (score > bestScore) {\n best = candidate\n bestScore = score\n }\n }\n\n return best\n}\n\n/** Split a single sample name on `delimiter`. Empty input returns `['']` so callers\n * always receive at least one token. */\nexport function splitMulti(name: string, delimiter: Delimiter): string[] {\n return name.split(delimiter)\n}\n","import type { SampleClass } from '../../types/auto-group'\n\nexport function classKey(c: Pick<SampleClass, 'kind'> & { subKind?: string }): string {\n return c.subKind ? `${c.kind}:${c.subKind}` : c.kind\n}\n","{\n \"$schema\": \"./vocab.schema.json\",\n \"_doc\": {\n \"purpose\": \"Sample-name classification vocabulary for the auto-group pipeline. Edit this file to teach the classifier new sample types or matrices without changing TypeScript. All matching is case-insensitive unless a pattern's regex flags say otherwise.\",\n \"patterns\": \"Regex source strings (no surrounding slashes). Compiled with the `i` flag at load time.\",\n \"standardAllow\": \"Tokens that should be classified as Standard even when they don't match `patterns.standard`. Case-sensitive — use the exact spelling that appears in your filenames.\",\n \"matrixVocab\": \"Lowercase token → canonical display name. Tokens are normalised to lowercase before lookup, so adding 'tissues' handles 'Tissues' / 'TISSUES' / 'tissues' uniformly. Multiple aliases map to one canonical (e.g. cell + cells → Cells).\",\n \"ionizationModes\": \"Lowercase polarity tokens (pos / positive / neg / negative). Suffixed to the subKind so POS and NEG acquisitions get independent schemas.\",\n \"tissueParentTokens\": \"Tokens that flag the immediately-following token as the organ subKind (so `tissues / kidney` becomes Biological/Tissues, tagging both positions).\",\n \"replicateStripPatterns\": \"Regex sources stripped from each sample name during the replicate pre-grouping pass. Samples whose stripped (base) names match are treated as replicates of one another and grouped together before tokenisation. Default set covers: trailing run-order numbers, _T<n>, _B<n>, and _Rep<n> markers.\"\n },\n\n \"patterns\": {\n \"blank\": \"^(blank|blk|solv?blank|matrix.?blank)$\",\n \"iqc\": \"^iqc$\",\n \"eqc\": \"^eqc$\",\n \"standard\": \"^(standard|std\\\\d*|cal(?:ibrator)?\\\\d*|.+standard)$\",\n \"spikeIn\": \"spike.?in\",\n \"stock\": \"^stock$\"\n },\n\n \"standardAllow\": [\n \"ExtractionS\",\n \"IS\",\n \"internal.standard\",\n \"PQC\",\n \"pooledQC\"\n ],\n\n \"matrixVocab\": {\n \"plasma\": \"Plasma\",\n \"serum\": \"Serum\",\n \"tissue\": \"Tissue\",\n \"tissues\": \"Tissues\",\n \"kidney\": \"Kidney\",\n \"liver\": \"Liver\",\n \"tumor\": \"Tumor\",\n \"urine\": \"Urine\",\n \"brain\": \"Brain\",\n \"muscle\": \"Muscle\",\n \"adipose\": \"Adipose\",\n \"csf\": \"CSF\",\n \"feces\": \"Feces\",\n \"faeces\": \"Faeces\",\n \"cells\": \"Cells\",\n \"cell\": \"Cells\",\n \"media\": \"Media\",\n \"medium\": \"Medium\",\n \"extract\": \"Extract\"\n },\n\n \"ionizationModes\": {\n \"pos\": \"POS\",\n \"positive\": \"POS\",\n \"neg\": \"NEG\",\n \"negative\": \"NEG\"\n },\n\n \"tissueParentTokens\": [\"tissue\", \"tissues\"],\n\n \"replicateStripPatterns\": [\n \"[_-]\\\\d{2,4}[A-Za-z]?$\",\n \"[_-]T\\\\d+(?=[_-]|$)\",\n \"[_-]B\\\\d+(?=[_-]|$)\",\n \"[_-](?:rep(?:licate)?)\\\\d+(?=[_-]|$)\"\n ]\n}\n","import type { SampleClass, SampleClassKind, ClassDisposition } from '../../types/auto-group'\nimport { classKey } from './classKey'\nimport vocabData from './vocab.json'\n\nexport interface ClassVocab {\n blankPattern: RegExp\n iqcPattern: RegExp\n eqcPattern: RegExp\n standardPattern: RegExp\n standardAllow: Set<string>\n spikeInPattern: RegExp\n stockPattern: RegExp\n /**\n * Matrix lookup: lowercase token → canonical display name. Matching is\n * case-insensitive, and several aliases can collapse to one display name\n * (cell → Cells, medium → Medium).\n */\n matrixVocab: Map<string, string>\n /** Lowercase polarity tokens → POS / NEG. */\n ionizationModes: Map<string, 'POS' | 'NEG'>\n /** Lowercase tokens that flag the next token as the organ subKind. */\n tissueParentTokens: Set<string>\n}\n\ntype VocabFile = typeof vocabData\ntype IonMode = 'POS' | 'NEG'\n\nfunction compileVocab(data: VocabFile): ClassVocab {\n return {\n blankPattern: new RegExp(data.patterns.blank, 'i'),\n iqcPattern: new RegExp(data.patterns.iqc, 'i'),\n eqcPattern: new RegExp(data.patterns.eqc, 'i'),\n standardPattern: new RegExp(data.patterns.standard, 'i'),\n spikeInPattern: new RegExp(data.patterns.spikeIn, 'i'),\n stockPattern: new RegExp(data.patterns.stock, 'i'),\n standardAllow: new Set(data.standardAllow),\n matrixVocab: new Map(Object.entries(data.matrixVocab)),\n ionizationModes: new Map(\n Object.entries(data.ionizationModes).map(([k, v]) => [k, v as IonMode]),\n ),\n tissueParentTokens: new Set(data.tissueParentTokens),\n }\n}\n\nexport const classVocab: ClassVocab = compileVocab(vocabData)\n\nfunction matrixCanonical(token: string, vocab: ClassVocab): string | undefined {\n return vocab.matrixVocab.get(token.toLowerCase())\n}\n\nfunction isTissueParentToken(token: string, vocab: ClassVocab): boolean {\n return vocab.tissueParentTokens.has(token.toLowerCase())\n}\n\nexport interface DetectClassOptions {\n vocab?: Partial<ClassVocab>\n /** Per-sample explicit `sample_type` hint (e.g. from experiment design data). */\n sampleTypeHints?: (string | undefined)[]\n}\n\nconst DEFAULT_DISPOSITION: Record<SampleClassKind, ClassDisposition> = {\n biological: 'group',\n iqc: 'overlay',\n eqc: 'overlay',\n standard: 'overlay',\n 'spike-in': 'overlay',\n stock: 'overlay',\n blank: 'overlay',\n unknown: 'group',\n}\n\nfunction classifyTokens(\n tokens: string[],\n vocab: ClassVocab,\n): { kind: SampleClassKind; subKind?: string; tagPositions: number[] } {\n // First-match-wins ordering: Blank → IQC → EQC → Standard → SpikeIn → Stock → Biological → Unknown.\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.blankPattern.test(tokens[i])) return { kind: 'blank', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.iqcPattern.test(tokens[i])) return { kind: 'iqc', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.eqcPattern.test(tokens[i])) return { kind: 'eqc', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.standardPattern.test(tokens[i]) || vocab.standardAllow.has(tokens[i])) {\n return { kind: 'standard', tagPositions: [i] }\n }\n }\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.spikeInPattern.test(tokens[i])) return { kind: 'spike-in', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n if (vocab.stockPattern.test(tokens[i])) return { kind: 'stock', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n const canonical = matrixCanonical(tokens[i], vocab)\n if (canonical) {\n const isTissueParent = isTissueParentToken(tokens[i], vocab)\n const tagPositions = [i]\n if (isTissueParent) {\n // \"Tissues\"/\"Tissue\" is the parent group; tag the next token (organ name) as well.\n if (i + 1 < tokens.length) tagPositions.push(i + 1)\n return { kind: 'biological', subKind: 'Tissues', tagPositions }\n }\n // Non-parent matrix token: tag any immediately preceding \"Tissues\"/\"Tissue\" parent.\n if (i > 0 && isTissueParentToken(tokens[i - 1], vocab)) {\n tagPositions.unshift(i - 1)\n return { kind: 'biological', subKind: 'Tissues', tagPositions }\n }\n return { kind: 'biological', subKind: canonical, tagPositions }\n }\n }\n return { kind: 'unknown', tagPositions: [] }\n}\n\n/**\n * LC-MS batches run positive- and negative-ion-mode acquisitions separately,\n * and the two produce different feature tables that should never be grouped\n * together. When a POS / NEG / positive / negative token is present we suffix\n * it to the class label so the schema builder treats each mode as its own class.\n */\nfunction ionizationModeFor(\n tokens: string[],\n vocab: ClassVocab,\n): { mode: IonMode; position: number } | undefined {\n for (let i = 0; i < tokens.length; i++) {\n const mode = vocab.ionizationModes.get(tokens[i].toLowerCase())\n if (mode) return { mode, position: i }\n }\n return undefined\n}\n\nfunction labelFor(kind: SampleClassKind, subKind?: string): string {\n const base: Record<SampleClassKind, string> = {\n biological: 'Biological',\n iqc: 'IQC',\n eqc: 'EQC',\n standard: 'Standard',\n 'spike-in': 'SpikeIn',\n stock: 'Stock',\n blank: 'Blank',\n unknown: 'Unknown',\n }\n return subKind ? `${base[kind]} / ${subKind}` : base[kind]\n}\n\n/** Classify each tokenized sample into a SampleClass. */\nexport function detectClass(\n tokenizedSamples: string[][],\n options: DetectClassOptions,\n): SampleClass[] {\n const vocab = { ...classVocab, ...(options.vocab ?? {}) }\n const hints = options.sampleTypeHints ?? []\n const buckets = new Map<string, SampleClass>()\n\n for (let i = 0; i < tokenizedSamples.length; i++) {\n const hint = hints[i]?.toLowerCase()\n let kind: SampleClassKind\n let subKind: string | undefined\n let tagPositions: number[]\n\n if (hint === 'qc') {\n kind = 'iqc'\n tagPositions = []\n } else if (hint === 'blank') {\n kind = 'blank'\n tagPositions = []\n } else {\n const r = classifyTokens(tokenizedSamples[i], vocab)\n kind = r.kind\n subKind = r.subKind\n tagPositions = r.tagPositions\n }\n\n // Split classes by ionization mode (POS / NEG) so the two acquisitions get\n // independent schemas even when they share a matrix and sample-type vocab.\n const mode = ionizationModeFor(tokenizedSamples[i], vocab)\n if (mode) {\n subKind = subKind ? `${subKind} / ${mode.mode}` : mode.mode\n if (!tagPositions.includes(mode.position)) tagPositions.push(mode.position)\n }\n\n const key = classKey({ kind, subKind })\n const bucket = buckets.get(key)\n if (bucket) {\n bucket.members.push(i)\n for (const p of tagPositions) {\n if (!bucket.classTagPositions.includes(p)) bucket.classTagPositions.push(p)\n }\n } else {\n buckets.set(key, {\n kind,\n subKind,\n label: labelFor(kind, subKind),\n members: [i],\n classTagPositions: [...tagPositions],\n disposition: DEFAULT_DISPOSITION[kind],\n })\n }\n }\n\n return [...buckets.values()]\n}\n","import type {\n ColumnInfo,\n ColumnRole,\n ClassSchema,\n NumericParse,\n SampleClassKind,\n} from '../../types/auto-group'\n\nconst NUMERIC_VALUE_UNIT = /^(\\d+(?:dot\\d+)?)([A-Za-z%/μ]+)$/\nconst RATIO = /^(\\d+)to(\\d+)$/\nconst RUN_ORDER_PATTERN = /^\\d{2,4}[A-Z]?$/\n// Explicit replicate-token vocabulary: rep1 / Rep2 / REP3 / replicate1 / R1.\n// These tokens almost always identify a within-group replicate dimension that\n// users do NOT want in the default group key — e.g. ctrl/rep1, ctrl/rep2\n// should land in one Ctrl group with two replicates, not two singleton groups.\nconst REPLICATE_TOKEN_PATTERN = /^(?:rep(?:licate)?|r)\\d+$/i\n\n// Real-world LC-MS batches often have 30+ distinct conditions (subject IDs,\n// calibration levels, treatment combinations) in a single class. The earlier\n// cutoff of 20 routed everything above it to `ignore`, leaving such columns\n// out of the default groupBy — meaning a single giant group with no useful\n// split. 50 covers the common cases without making singleton-heavy columns\n// (sample IDs, timestamps) into factors.\nconst DEFAULT_FACTOR_CARDINALITY_MAX = 50\n// Numerics with only a handful of distinct levels (e.g. `5min` / `10min`,\n// `1nM` / `5nM` / `25nM`) read as factor levels by default. Users opt into\n// numeric binning explicitly via the column popover when they want it.\nconst LOW_CARDINALITY_NUMERIC_AS_FACTOR_MAX = 5\n\nexport function parseNumeric(token: string): NumericParse | null {\n const ratio = RATIO.exec(token)\n if (ratio) {\n const num = Number(ratio[1])\n const den = Number(ratio[2])\n if (den === 0) return null\n return { value: num / den, unit: 'ratio', raw: token }\n }\n const m = NUMERIC_VALUE_UNIT.exec(token)\n if (!m) return null\n const valueStr = m[1].replace(/dot/g, '.')\n const value = Number(valueStr)\n if (Number.isNaN(value)) return null\n return { value, unit: m[2], raw: token }\n}\n\nexport interface InferRoleInput {\n values: string[]\n position: number\n totalPositions: number\n classSize: number\n}\n\nexport function inferRole(input: InferRoleInput): ColumnRole {\n const { values, position, totalPositions, classSize } = input\n const unique = new Set(values)\n const cardinality = unique.size\n\n if (cardinality === 1) return 'constant'\n\n // run-order: trailing position, all values match \\d{2,4}[A-Z]? and cardinality is high.\n if (position === totalPositions - 1) {\n const allRunLike = values.every(v => RUN_ORDER_PATTERN.test(v))\n if (allRunLike && cardinality >= classSize * 0.5) return 'run-order'\n }\n\n // numeric: every value parses as value+unit (or ratio).\n const allNumeric = values.every(v => parseNumeric(v) !== null)\n if (allNumeric) {\n // A column like 5min / 10min reads as a factor in practice — users want to\n // group on the timepoint, not bin it. Numeric binning UI is opt-in via the\n // column popover for columns the user explicitly wants binned.\n if (cardinality <= LOW_CARDINALITY_NUMERIC_AS_FACTOR_MAX) return 'factor'\n return 'numeric'\n }\n\n // replicate by explicit name (rep1, Rep2, replicate3, R1) — regardless of\n // cardinality. The cardinality-based ID_PATTERN check that used to live\n // here (allId && cardinality >= classSize * 0.5) was removed: with the\n // replicate pre-grouping pass running upstream, real replicates have\n // already been collapsed by name, so a column like C1/C2/M1/M2 reaching\n // role inference is almost certainly a distinct-condition factor, not a\n // replicate. Users who want a residual replicate column can still mark\n // it via the Workspace popover.\n const allReplicateNamed = values.every(v => REPLICATE_TOKEN_PATTERN.test(v))\n if (allReplicateNamed) return 'replicate'\n\n if (cardinality <= DEFAULT_FACTOR_CARDINALITY_MAX) return 'factor'\n\n return 'ignore'\n}\n\n/**\n * Auto-detect a friendlier column name from the column's values + role.\n * Returns null when nothing matches, so callers can fall back to \"Token N\".\n *\n * Heuristics are content-derived and deterministic. They cover the common\n * LC-MS / proteomics naming conventions; users can override anything via\n * the column popover (rename input).\n */\nfunction inferColumnName(\n values: string[],\n uniqueValues: string[],\n role: ColumnRole,\n): string | null {\n if (uniqueValues.length === 0) return null\n\n // Numeric+unit columns name themselves by the dominant unit category.\n // We tally all values so a mixed-unit column (`1uL`, `1nM`) picks the\n // majority rather than the first sample's unit.\n const allNumeric = (role === 'numeric' || role === 'factor') && values.every(v => parseNumeric(v) !== null)\n if (allNumeric) {\n const categoryFor = (u: string): string | null => {\n const ul = u.toLowerCase()\n if (['min', 'sec', 's', 'hr', 'h', 'd', 'day', 'days', 'wk', 'week', 'hour', 'hours'].includes(ul)) return 'Timepoint'\n if (['nm', 'um', 'mm', 'm', 'molar', 'mol'].includes(ul)) return 'Concentration'\n if (['mg', 'g', 'kg', 'ng', 'ug', 'pg'].includes(ul)) return 'Mass'\n if (['ml', 'l', 'ul', 'nl', 'pl'].includes(ul)) return 'Volume'\n if (ul === '%') return 'Percentage'\n if (['c', 'k', 'celsius', 'kelvin'].includes(ul)) return 'Temperature'\n return null\n }\n const tally = new Map<string, number>()\n for (const v of values) {\n const p = parseNumeric(v)\n const cat = p ? categoryFor(p.unit) : null\n if (cat) tally.set(cat, (tally.get(cat) ?? 0) + 1)\n }\n let best: { cat: string; count: number } | null = null\n for (const [cat, count] of tally) {\n if (!best || count > best.count) best = { cat, count }\n }\n if (best && best.count >= values.length / 2) return best.cat\n }\n\n // Date-like all-digits tokens (YYMMDD or YYYYMMDD).\n if (values.every(v => /^\\d{6}$/.test(v) || /^\\d{8}$/.test(v))) return 'Date'\n\n // Run-order column already has the right semantic role.\n if (role === 'run-order') return 'Run Order'\n\n // Polarity tokens (POS/NEG/positive/negative).\n if (values.every(v => /^(pos|neg|positive|negative)$/i.test(v))) return 'Polarity'\n\n // Common biological matrices — kept in sync with classify.ts matrixVocab.\n if (values.every(v => /^(plasma|serum|tissue|tissues|kidney|liver|tumor|urine|brain|muscle|adipose|csf|feces|faeces|cells?|media|medium|extract)$/i.test(v))) {\n return 'Matrix'\n }\n\n // Experiment / study identifiers (exp268, study42, expt7).\n if (values.every(v => /^(exp|expt|study)\\d+$/i.test(v))) return 'Experiment'\n\n // Operator / Username (2-3 uppercase letters per value, low cardinality).\n // Constant or small-set 2-3-letter all-caps columns are almost always\n // operator initials (LCK, JD, AB). Larger 2-4-letter columns could be\n // project codes — disambiguation happens after the loop via the\n // `Username → Project` post-pass.\n if (uniqueValues.length <= 4 && values.every(v => /^[A-Z]{2,3}$/.test(v))) return 'Username'\n\n return null\n}\n\nexport function buildClassSchema(\n tokenizedMembers: string[][],\n classKind: SampleClassKind,\n subKind: string | undefined,\n classTagPositions: number[],\n): ClassSchema {\n const totalPositions = tokenizedMembers[0]?.length ?? 0\n const classSize = tokenizedMembers.length\n\n const columns: ColumnInfo[] = []\n const tagSet = new Set(classTagPositions)\n\n for (let pos = 0; pos < totalPositions; pos++) {\n const values = tokenizedMembers.map(t => t[pos] ?? '')\n const uniqueValues = [...new Set(values)]\n\n let role: ColumnRole\n if (tagSet.has(pos) && uniqueValues.length === 1) {\n // Only constant tag positions become class-tag; multi-valued positions (e.g. organ\n // type within a Tissues class) fall through to normal role inference so they can be\n // used as factor columns for grouping.\n role = 'class-tag'\n } else {\n role = inferRole({ values, position: pos, totalPositions, classSize })\n }\n\n const numeric =\n role === 'numeric'\n ? {\n byValue: Object.fromEntries(\n uniqueValues\n .map(v => [v, parseNumeric(v)] as const)\n .filter((e): e is readonly [string, NumericParse] => e[1] !== null),\n ),\n }\n : undefined\n\n const inferredName = inferColumnName(values, uniqueValues, role)\n columns.push({\n index: pos,\n name: inferredName ?? `Token ${pos + 1}`,\n sourceIndices: [pos],\n uniqueValues,\n cardinality: uniqueValues.length,\n role,\n numeric,\n // Legacy field\n type: pos === 0 ? 'prefix' : 'suffix',\n })\n }\n\n // Disambiguate Username when there are multiple constant 2-4 letter columns:\n // first hit stays \"Username\", subsequent ones become \"Project\".\n let usernameAssigned = false\n for (const c of columns) {\n if (c.name === 'Username') {\n if (usernameAssigned) c.name = 'Project'\n else usernameAssigned = true\n }\n }\n\n const groupBy = columns.filter(c => c.role === 'factor').map(c => c.index)\n\n return { classKind, subKind, columns, groupBy }\n}\n","import type { ClassSchema, MergeSuggestion } from '../../types/auto-group'\n\nconst THRESHOLD = 0.95\nconst MIN_CLASS_SIZE = 4\n\nfunction functionalDependency(rows: string[][], srcIdx: number, dstIdx: number): number {\n const map = new Map<string, Set<string>>()\n for (const row of rows) {\n const a = row[srcIdx] ?? ''\n const b = row[dstIdx] ?? ''\n const set = map.get(a)\n if (set) set.add(b)\n else map.set(a, new Set([b]))\n }\n if (map.size === 0) return 0\n let functional = 0\n for (const set of map.values()) if (set.size === 1) functional++\n return functional / map.size\n}\n\nexport function findMerges(schema: ClassSchema, rows: string[][]): MergeSuggestion[] {\n if (rows.length < MIN_CLASS_SIZE) return []\n\n const out: MergeSuggestion[] = []\n for (let i = 0; i < schema.columns.length - 1; i++) {\n const a = schema.columns[i]\n const b = schema.columns[i + 1]\n if (a.role !== 'factor' && b.role !== 'factor') continue\n\n const forward = functionalDependency(rows, a.index, b.index)\n const backward = functionalDependency(rows, b.index, a.index)\n if (forward < THRESHOLD || backward < THRESHOLD) continue\n\n const merged = new Set(rows.map(r => `${r[a.index] ?? ''}_${r[b.index] ?? ''}`))\n if (merged.size < 2) continue\n\n out.push({\n classKind: schema.classKind,\n subKind: schema.subKind,\n columnIndices: [a.index, b.index],\n proposedName: `Column ${a.index + 1}–${b.index + 1}`,\n confidence: Math.min(forward, backward),\n })\n }\n return out\n}\n","export const DEFAULT_COLORS = [\n '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',\n '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',\n]\n\nexport const QC_OVERLAY_COLOR = '#6B7280'\n","import type {\n AutoGroupResult,\n ClassSchema,\n ColumnInfo,\n MetadataRow,\n NumericBinning,\n SampleClass,\n} from '../../types/auto-group'\nimport type { SampleGroup } from '../../types/components'\nimport { DEFAULT_COLORS, QC_OVERLAY_COLOR } from './colors'\nimport { classKey } from './classKey'\n\nexport interface ComposeInput {\n tokenizedSamples: string[][]\n sampleNames: string[]\n schemas: Record<string, ClassSchema>\n classes: SampleClass[]\n}\n\n/** Apply the operation pipeline to a single raw token value:\n * numeric-parse → alias → exclude → bin\n * Returns null if the row is excluded.\n */\nfunction applyOps(col: ColumnInfo, raw: string): string | null {\n let value = raw\n\n // alias (operates on raw source value)\n if (col.ops?.alias && raw in col.ops.alias) {\n value = col.ops.alias[raw]\n }\n\n // exclude (post-alias)\n if (col.ops?.exclude?.includes(raw) || col.ops?.exclude?.includes(value)) {\n return null\n }\n\n // bin (only when role === 'numeric' and binning.mode === 'binned')\n if (col.role === 'numeric' && col.binning?.mode === 'binned') {\n const parsed = col.numeric?.byValue[raw]\n if (parsed && col.binning.edges) {\n const bin = pickBin(parsed.value, col.binning)\n if (bin !== null) value = bin\n }\n }\n\n return value\n}\n\nfunction pickBin(value: number, b: NumericBinning): string | null {\n if (!b.edges || b.edges.length === 0) return null\n for (let i = 0; i < b.edges.length; i++) {\n if (value < b.edges[i]) {\n return b.labels?.[i] ?? `< ${b.edges[i]}`\n }\n }\n const last = b.edges[b.edges.length - 1]\n return b.labels?.[b.edges.length] ?? `> ${last}`\n}\n\nexport function composeGroups(input: ComposeInput): AutoGroupResult {\n const experimentalGroups: SampleGroup[] = []\n const qcGroups: SampleGroup[] = []\n const excludedSamples: string[] = []\n const metadata: MetadataRow[] = []\n let colorIdx = 0\n\n for (const cls of input.classes) {\n const schema = input.schemas[classKey(cls)]\n if (!schema) continue\n\n if (cls.disposition === 'exclude') {\n for (const m of cls.members) excludedSamples.push(input.sampleNames[m])\n continue\n }\n\n // Per-class group map. group key built from enabled (groupBy) columns,\n // joined with ' / ' for hierarchical display.\n const groupMap = new Map<string, { name: string; samples: string[] }>()\n const colByIdx = new Map(schema.columns.map(c => [c.index, c]))\n\n for (const m of cls.members) {\n const tokens = input.tokenizedSamples[m]\n const rowName = input.sampleNames[m]\n let excluded = false\n const fieldValues: Record<string, string> = {}\n\n for (const col of schema.columns) {\n const sourceValues = col.sourceIndices.map(idx => tokens[idx] ?? '')\n const raw = sourceValues.join('_') // merged columns join their source tokens\n const display = applyOps(col, raw)\n if (display === null) {\n excluded = true\n break\n }\n fieldValues[col.displayName ?? col.name] = display\n }\n\n if (excluded) {\n excludedSamples.push(rowName)\n continue\n }\n\n const keyParts: string[] =\n cls.disposition === 'group'\n ? schema.groupBy.map(idx => {\n const col = colByIdx.get(idx)!\n return fieldValues[col.displayName ?? col.name]\n })\n : [cls.label]\n\n // Prepend the class label to the factor-key parts so group names carry\n // class context (e.g. \"Biological / Tissues / POS / 5min\" instead of a\n // bare \"5min\" that collides with another class's \"5min\").\n //\n // Only fires for disposition === 'group' classes with actual factor\n // keyParts: overlay/exclude classes already use cls.label AS their\n // single key part, so prefixing again would produce \"IQC / IQC\". The\n // Unknown class also opts out — its label (\"Unknown\") adds no signal.\n const useClassPrefix =\n cls.disposition === 'group' && cls.kind !== 'unknown' && keyParts.length > 0\n const groupKey = useClassPrefix\n ? `${cls.label} / ${keyParts.join(' / ')}`\n : keyParts.length > 0\n ? keyParts.join(' / ')\n : cls.label\n\n const bucket = groupMap.get(groupKey)\n if (bucket) {\n bucket.samples.push(rowName)\n } else {\n groupMap.set(groupKey, { name: groupKey, samples: [rowName] })\n }\n\n metadata.push({ sampleName: rowName, fields: fieldValues, group: groupKey })\n }\n\n for (const { name, samples } of groupMap.values()) {\n const color =\n cls.disposition === 'overlay'\n ? QC_OVERLAY_COLOR\n : DEFAULT_COLORS[colorIdx++ % DEFAULT_COLORS.length]\n const g: SampleGroup = { name, color, samples }\n if (cls.disposition === 'overlay') qcGroups.push(g)\n else experimentalGroups.push(g)\n }\n }\n\n return {\n groups: [...experimentalGroups, ...qcGroups],\n experimentalGroups,\n qcGroups,\n metadata,\n excludedSamples,\n schemas: Object.values(input.schemas),\n }\n}\n","import type { ClassSchema, SchemaFingerprint } from '../../types/auto-group'\n\nexport function serializeFingerprint(schemas: ClassSchema[]): SchemaFingerprint {\n return {\n version: 1,\n classes: schemas.map(s => ({\n kind: s.classKind,\n subKind: s.subKind,\n columns: s.columns.map(c => ({\n name: c.displayName ?? c.name,\n role: c.role ?? 'factor',\n sourceIndices: c.sourceIndices,\n binning: c.binning,\n ops: c.ops,\n })),\n groupBy: s.groupBy,\n })),\n }\n}\n\nexport function restoreFingerprint(\n fp: SchemaFingerprint,\n current: ClassSchema[],\n): ClassSchema[] {\n return fp.classes.map(snap => {\n const target = current.find(c => c.classKind === snap.kind && c.subKind === snap.subKind)\n if (!target) {\n throw new Error(\n `Fingerprint class not present in current input: ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}`,\n )\n }\n if (target.columns.length !== snap.columns.length) {\n throw new Error(\n `Saved schema expects ${snap.columns.length} columns, current data has ${target.columns.length} for class ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}. column count mismatch`,\n )\n }\n return {\n ...target,\n groupBy: snap.groupBy,\n columns: target.columns.map((col, i) => ({\n ...col,\n displayName: snap.columns[i].name,\n role: snap.columns[i].role,\n binning: snap.columns[i].binning,\n ops: snap.columns[i].ops,\n })),\n }\n })\n}\n","import type { ClassSchema, ColumnInfo, SampleClass } from '../../types/auto-group'\nimport { classKey } from './classKey'\n\nexport interface TemplateOptions {\n mode: 'blank' | 'prefilled'\n format: 'csv' | 'tsv'\n /** For prefilled mode. Indexed parallel to `samples`. */\n tokenizedSamples?: string[][]\n /** Used to compute the filename; omitted → falls back to `sample_metadata_<date>`. */\n experimentCode?: string\n /** Override the blank-mode suggested headers. Defaults to ['group','class','replicate','notes']. */\n suggestedColumns?: string[]\n}\n\nconst DEFAULT_BLANK_HEADERS = ['group', 'class', 'replicate', 'notes']\n\nfunction rfc4180Quote(cell: string): string {\n if (/[\",\\n]/.test(cell)) {\n return `\"${cell.replace(/\"/g, '\"\"')}\"`\n }\n return cell\n}\n\nfunction joinRow(cells: string[], sep: string): string {\n return sep === ','\n ? cells.map(rfc4180Quote).join(',')\n : cells.join('\\t')\n}\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nexport function composeTemplate(\n samples: string[],\n schemas: ClassSchema[] | null,\n classes: SampleClass[] | null,\n options: TemplateOptions,\n): { content: string; filename: string } {\n const sep = options.format === 'tsv' ? '\\t' : ','\n const ext = options.format === 'tsv' ? 'tsv' : 'csv'\n\n const stem = options.experimentCode ? `${options.experimentCode}_metadata` : 'sample_metadata'\n const filename = `${stem}_${today()}.${ext}`\n\n if (options.mode === 'blank' || !schemas || !classes) {\n const headers = ['sample_name', ...(options.suggestedColumns ?? DEFAULT_BLANK_HEADERS)]\n const rows = samples.map(s => {\n const r = [s, ...Array(headers.length - 1).fill('')]\n return joinRow(r, sep)\n })\n return { content: [joinRow(headers, sep), ...rows].join('\\n'), filename }\n }\n\n // Prefilled mode: union of all class columns, wide layout.\n const tokenized = options.tokenizedSamples ?? []\n const allColumns: { schemaKey: string; colName: string }[] = []\n\n // Hoist: build lookup maps before the per-sample loop.\n const sampleToClass = new Map<number, SampleClass>()\n for (const cls of classes) for (const m of cls.members) sampleToClass.set(m, cls)\n\n const schemaByKey = new Map<string, ClassSchema>()\n for (const s of schemas) {\n const k = s.subKind ? `${s.classKind}:${s.subKind}` : s.classKind\n schemaByKey.set(k, s)\n }\n\n const colByNameByKey = new Map<string, Map<string, ColumnInfo>>()\n const groupBySetByKey = new Map<string, Set<number>>()\n for (const s of schemas) {\n const k = s.subKind ? `${s.classKind}:${s.subKind}` : s.classKind\n const m = new Map<string, ColumnInfo>()\n for (const c of s.columns) m.set(c.displayName ?? c.name, c)\n colByNameByKey.set(k, m)\n groupBySetByKey.set(k, new Set(s.groupBy))\n // Collect allColumns with dedup via Set\n const seenColNames = new Set<string>()\n for (const c of s.columns) {\n const name = c.displayName ?? c.name\n if (!seenColNames.has(name)) {\n seenColNames.add(name)\n if (!allColumns.some(x => x.colName === name)) {\n allColumns.push({ schemaKey: k, colName: name })\n }\n }\n }\n }\n\n const headers = ['sample_name', 'class', ...allColumns.map(c => c.colName), 'group', 'notes']\n\n const rows: string[] = []\n for (let i = 0; i < samples.length; i++) {\n const cls = sampleToClass.get(i)\n const classLabel = cls?.label ?? ''\n const tokens = tokenized[i] ?? []\n const cells: string[] = [samples[i], classLabel]\n\n if (cls) {\n const k = classKey(cls)\n const groupBySet = groupBySetByKey.get(k)\n const colByName: Map<string, ColumnInfo> | undefined = colByNameByKey.get(k)\n const keyParts: string[] = []\n for (const col of allColumns) {\n if (col.schemaKey === k && colByName) {\n const schemaCol = colByName.get(col.colName)\n const raw =\n schemaCol?.sourceIndices.map(idx => tokens[idx] ?? '').join('_') ?? ''\n cells.push(raw)\n if (schemaCol && groupBySet?.has(schemaCol.index)) keyParts.push(raw)\n } else {\n cells.push('')\n }\n }\n cells.push(keyParts.join(' / '))\n } else {\n for (const _ of allColumns) cells.push('')\n cells.push('')\n }\n\n cells.push('') // notes\n rows.push(joinRow(cells, sep))\n }\n\n return { content: [joinRow(headers, sep), ...rows].join('\\n'), filename }\n}\n","/**\n * Replicate pre-grouping.\n *\n * Strip the replicate / injection-number markers from each sample's name, then\n * collapse samples that share a base name. Those samples ARE replicates of one\n * another by definition; the remaining unique base names are what the rest of\n * the pipeline (tokenize → classify → schema → compose) should operate on.\n *\n * This pre-pass replaces the older \"treat every sample as independent, then\n * infer replicate columns\" approach. Identifying replicate-equivalence by name\n * before tokenisation removes a class of fragile cardinality heuristics.\n */\n\nimport vocabData from './vocab.json'\n\nconst STRIP_PATTERNS: RegExp[] = (vocabData.replicateStripPatterns as string[]).map(\n src => new RegExp(src, 'gi'),\n)\n\n/**\n * Iteratively strip every replicate / injection-number marker from `name`.\n * Each pattern is applied repeatedly until it stops matching, so a sample like\n * `study_T1_Rep2_004` collapses to `study` in one call.\n */\nexport function stripReplicateTokens(name: string): string {\n let base = name\n for (const re of STRIP_PATTERNS) {\n let prev\n do {\n prev = base\n base = base.replace(re, '')\n re.lastIndex = 0\n } while (base !== prev)\n }\n return base\n}\n\nexport interface ReplicatePreGrouping {\n /** Unique base names in first-seen order. Length === `originalSamples.length` only if every sample has a distinct base. */\n baseNames: string[]\n /**\n * `membersByBase[i]` = original-sample indices that collapsed onto `baseNames[i]`.\n * Length of each entry is the replicate count for that base.\n */\n membersByBase: number[][]\n /** Original sample names indexed by their position in `samples`. Retained so the compose layer can expand groups back to originals. */\n originalSamples: string[]\n}\n\nexport function preGroupReplicates(samples: string[]): ReplicatePreGrouping {\n const map = new Map<string, number[]>()\n const baseOrder: string[] = []\n for (let i = 0; i < samples.length; i++) {\n const base = stripReplicateTokens(samples[i])\n const bucket = map.get(base)\n if (bucket) {\n bucket.push(i)\n } else {\n map.set(base, [i])\n baseOrder.push(base)\n }\n }\n return {\n baseNames: baseOrder,\n membersByBase: baseOrder.map(b => map.get(b)!),\n originalSamples: samples,\n }\n}\n\n/**\n * Expand groups produced over base names back to groups of original sample\n * names. Each entry in `group.samples` is treated as a base name and replaced\n * by the list of original samples that collapsed onto it.\n */\nexport function expandGroupsWithReplicates<G extends { samples: string[] }>(\n groups: G[],\n preGrouping: ReplicatePreGrouping,\n): G[] {\n const baseToMembers = new Map<string, number[]>()\n for (let i = 0; i < preGrouping.baseNames.length; i++) {\n baseToMembers.set(preGrouping.baseNames[i], preGrouping.membersByBase[i])\n }\n return groups.map(g => ({\n ...g,\n samples: g.samples.flatMap(baseName => {\n const indices = baseToMembers.get(baseName)\n return indices ? indices.map(i => preGrouping.originalSamples[i]) : [baseName]\n }),\n }))\n}\n","import type { SelectOption } from '../types'\n\nexport interface ExperimentDesignDataResponse {\n experiment_id?: number\n plugin_id?: string\n data?: Record<string, unknown>\n schema_version?: string\n updated_at?: string | null\n}\n\nexport interface ExtractExperimentSamplesOptions {\n includeControls?: boolean\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction isPlatformDesignDataResponse(value: Record<string, unknown>): boolean {\n return (\n 'data' in value\n && (\n 'experiment_id' in value\n || 'plugin_id' in value\n || 'schema_version' in value\n || 'updated_at' in value\n )\n )\n}\n\n/** Return the plugin-defined design_data payload from common platform and plugin response shapes. */\nexport function unwrapExperimentDesignData(\n rawData: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (!rawData) return null\n\n if (isRecord(rawData.data) && isPlatformDesignDataResponse(rawData)) {\n return rawData.data\n }\n\n if (isRecord(rawData.design_data)) {\n return rawData.design_data\n }\n\n if (isRecord(rawData.designData)) {\n return rawData.designData\n }\n\n return rawData\n}\n\nfunction shouldIncludeSample(record: Record<string, unknown>, options: ExtractExperimentSamplesOptions): boolean {\n if (options.includeControls) return true\n const rawType = record.sample_type ?? record.sampleType ?? record.type ?? record.well_type ?? record.wellType\n const type = typeof rawType === 'string' ? rawType.toLowerCase() : ''\n return !['blank', 'qc'].includes(type)\n}\n\nfunction readSampleValue(record: Record<string, unknown>): string | null {\n const candidates = [\n record.sample_name,\n record.sampleName,\n record.sample_id,\n record.sampleId,\n record.name,\n record.id,\n record.label,\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim()) {\n return candidate\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n return String(candidate)\n }\n }\n\n return null\n}\n\nfunction readSampleLabel(record: Record<string, unknown>, fallback: string): string {\n const label = record.name ?? record.label ?? record.sample_name ?? record.sampleName\n return typeof label === 'string' && label.trim() ? label : fallback\n}\n\nfunction readSampleDescription(record: Record<string, unknown>): string | undefined {\n const parts = [\n record.group,\n record.batch,\n record.batch_id,\n record.batchId,\n record.plate_id,\n record.plateId,\n record.well_id,\n record.wellId,\n ].filter((value): value is string | number =>\n (typeof value === 'string' && value.trim().length > 0)\n || typeof value === 'number',\n )\n\n return parts.length > 0 ? parts.map(String).join(' / ') : undefined\n}\n\nfunction addSampleRecord(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed)\n options.push({ value: trimmed, label: trimmed })\n }\n return\n }\n\n if (!isRecord(value) || !shouldIncludeSample(value, extractOptions)) return\n\n const sampleValue = readSampleValue(value)\n if (!sampleValue || seen.has(sampleValue)) return\n\n seen.add(sampleValue)\n options.push({\n value: sampleValue,\n label: readSampleLabel(value, sampleValue),\n description: readSampleDescription(value),\n })\n}\n\nfunction addSampleArray(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (!Array.isArray(value)) return\n for (const sample of value) {\n addSampleRecord(options, seen, sample, extractOptions)\n }\n}\n\n/** Extract selectable sample options from raw or wrapped experiment design_data. */\nexport function extractSampleOptionsFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): SelectOption<string>[] {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return []\n\n const sampleOptions: SelectOption<string>[] = []\n const seen = new Set<string>()\n\n addSampleArray(sampleOptions, seen, designData.samples, options)\n\n if (isRecord(designData.templates)) {\n for (const template of Object.values(designData.templates)) {\n if (!isRecord(template)) continue\n const templateData = isRecord(template.data) ? template.data : template\n addSampleArray(sampleOptions, seen, templateData.samples, options)\n }\n }\n\n if (Array.isArray(designData.plates)) {\n for (const plate of designData.plates) {\n if (!isRecord(plate)) continue\n addSampleArray(sampleOptions, seen, plate.samples, options)\n }\n }\n\n return sampleOptions\n}\n\n/** Extract SampleSelector-compatible string values from raw or wrapped experiment design_data. */\nexport function extractSampleNamesFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): string[] {\n return extractSampleOptionsFromDesignData(rawData, options).map(sample => sample.value)\n}\n","import type { ParsedCsvData } from '../../types/auto-group'\n\nfunction parseCSVLine(line: string, delimiter: string = ','): string[] {\n const result: string[] = []\n let current = ''\n let inQuotes = false\n for (let i = 0; i < line.length; i++) {\n const char = line[i]\n if (char === '\"') {\n if (inQuotes && line[i + 1] === '\"') {\n current += '\"'\n i++\n } else {\n inQuotes = !inQuotes\n }\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 return result\n}\n\nexport function parseCSV(text: string): ParsedCsvData {\n const lines = text.trim().split('\\n')\n if (lines.length < 2) throw new Error('CSV must have at least a header and one data row')\n const firstLine = lines[0]\n const csvDelimiter = firstLine.includes('\\t') ? '\\t' : ','\n const headers = parseCSVLine(firstLine, csvDelimiter)\n const rows: Record<string, string>[] = []\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((h, idx) => { row[h] = values[idx] })\n rows.push(row)\n }\n const sampleKeywords = ['sample', 'name', 'id', 'sample_name', 'samplename', 'file name', 'filename', 'file_name']\n const sampleColumn = headers.find(h => sampleKeywords.includes(h.toLowerCase())) ?? headers[0]\n return { columns: headers, rows, sampleColumn, delimiter: csvDelimiter }\n}\n","import { computed, ref } from 'vue'\nimport type {\n AutoGroupResult,\n ClassDisposition,\n ClassSchema,\n ColumnInfo,\n ColumnRole,\n InputMode,\n MergeSuggestion,\n NumericBinning,\n OutlierAction,\n OutlierInfo,\n ParsedCsvData,\n SampleClass,\n SchemaFingerprint,\n ValueOps,\n} from '../types/auto-group'\nimport {\n buildClassSchema,\n classKey,\n composeGroups,\n composeTemplate,\n detectClass,\n expandGroupsWithReplicates,\n findMerges,\n pickPrimaryDelimiter,\n preGroupReplicates,\n restoreFingerprint,\n serializeFingerprint,\n splitMulti,\n type ReplicatePreGrouping,\n type TemplateOptions,\n} from './autoGroup'\nimport { unwrapExperimentDesignData } from './experimentDesignData'\n\nexport { DEFAULT_COLORS } from './autoGroup'\n\nlet deprecationWarned = false\nlet outlierDeprecationWarned = false\nfunction warnDeprecated(api: string) {\n if (deprecationWarned) return\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return\n console.warn(\n `[useAutoGroup] ${api} is deprecated; use the new class-first API (setClassDisposition / toggleGroupBy / setValueOps).`,\n )\n deprecationWarned = true\n}\n\n// Re-export `parseCSV` for callers that imported it from this file.\nexport { parseCSV } from './autoGroup/csv-shim'\n\nexport function useAutoGroup() {\n const inputMode = ref<InputMode>('paste')\n const rawText = ref('')\n const csvData = ref<ParsedCsvData | null>(null)\n const sampleTypeHints = ref<(string | undefined)[]>([])\n\n const classes = ref<SampleClass[]>([])\n const schemas = ref<Record<string, ClassSchema>>({})\n const activeClassKey = ref<string>('')\n\n const samples = computed(() => {\n if (csvData.value) {\n return csvData.value.rows.map(r => r[csvData.value!.sampleColumn] ?? '')\n }\n return rawText.value.split('\\n').map(l => l.trim()).filter(l => l.length > 0)\n })\n\n const tokenized = ref<string[][]>([])\n const delimiter = ref<'_' | '-' | '.'>('_')\n // Replicate pre-grouping: strip injection-number / T<n> / B<n> / Rep<n> markers,\n // collapse samples with the same base name into one \"row\" for tokenisation,\n // then expand the resulting groups back to the original samples in `result`.\n // null when the paste path hasn't run (CSV path keeps the old behaviour for now).\n const preGrouping = ref<ReplicatePreGrouping | null>(null)\n\n function parseInput() {\n if ((inputMode.value === 'csv' || inputMode.value === 'experiment') && csvData.value) {\n parseInputFromCsv()\n return\n }\n parseInputFromPaste()\n }\n\n function parseInputFromCsv() {\n // CSV input already exposes structured columns, so replicate pre-grouping\n // isn't needed (and would interfere with header-aware role inference).\n preGrouping.value = null\n const csv = csvData.value!\n const nonSampleCols = csv.columns.filter(c => c !== csv.sampleColumn && c !== 'sample_type')\n if (nonSampleCols.length === 0) {\n // No metadata columns — degenerate, single Unknown class\n tokenized.value = csv.rows.map(() => [])\n classes.value = [{\n kind: 'unknown',\n label: 'Unknown',\n members: csv.rows.map((_, i) => i),\n classTagPositions: [],\n disposition: 'group',\n }]\n schemas.value = { unknown: { classKind: 'unknown', columns: [], groupBy: [] } }\n activeClassKey.value = 'unknown'\n return\n }\n const tokens = csv.rows.map(r => nonSampleCols.map(col => r[col] ?? ''))\n tokenized.value = tokens\n // Class detection: use explicit sample_type hint from csv.rows[i].sample_type\n const hints = csv.rows.map(r => {\n const t = String(r['sample_type'] ?? '').toLowerCase()\n if (t === 'qc') return 'qc'\n if (t === 'blank') return 'blank'\n return undefined\n })\n const detected = detectClass(tokens, { sampleTypeHints: hints })\n classes.value = detected\n // Build schema per class with CSV header names\n const newSchemas: Record<string, ClassSchema> = {}\n for (const cls of detected) {\n const memberTokens = cls.members.map(i => tokens[i])\n const schema = buildClassSchema(memberTokens, cls.kind, cls.subKind, cls.classTagPositions)\n // Override default Token N names with actual CSV header names\n schema.columns = schema.columns.map((c, i) => ({\n ...c,\n name: nonSampleCols[i] ?? c.name,\n originalName: nonSampleCols[i],\n }))\n newSchemas[classKey(cls)] = schema\n }\n schemas.value = newSchemas\n if (detected.length > 0) activeClassKey.value = classKey(detected[0])\n }\n\n function parseInputFromPaste() {\n const lines = samples.value\n if (lines.length === 0) {\n classes.value = []\n schemas.value = {}\n preGrouping.value = null\n return\n }\n // Replicate pre-pass: strip run-order / T<n> / B<n> / Rep<n> markers, then\n // collapse samples whose stripped names match into one base entry. The\n // tokenize → classify → schema pipeline runs on the *base* names; the\n // `result` computed expands each resulting group back to the original\n // samples via `expandGroupsWithReplicates`.\n const pre = preGroupReplicates(lines)\n preGrouping.value = pre\n\n const d = pickPrimaryDelimiter(pre.baseNames)\n delimiter.value = d\n tokenized.value = pre.baseNames.map(l => splitMulti(l, d))\n // sampleTypeHints align to original samples, so pick the first sample's\n // hint per base group as the representative hint.\n const hints = pre.membersByBase.map(members => sampleTypeHints.value[members[0]])\n const detected = detectClass(tokenized.value, { sampleTypeHints: hints })\n classes.value = detected\n const newSchemas: Record<string, ClassSchema> = {}\n for (const cls of detected) {\n const memberTokens = cls.members.map(i => tokenized.value[i])\n newSchemas[classKey(cls)] = buildClassSchema(\n memberTokens,\n cls.kind,\n cls.subKind,\n cls.classTagPositions,\n )\n }\n schemas.value = newSchemas\n if (detected.length > 0) {\n activeClassKey.value = classKey(detected[0])\n }\n }\n\n const activeSchema = computed<ClassSchema | null>(() => schemas.value[activeClassKey.value] ?? null)\n\n const suggestions = computed<MergeSuggestion[]>(() => {\n const schema = activeSchema.value\n if (!schema) return []\n const activeClass = classes.value.find(\n c => classKey(c) === activeClassKey.value,\n )\n if (!activeClass) return []\n const memberTokens = activeClass.members.map(i => tokenized.value[i])\n return findMerges(schema, memberTokens)\n })\n\n const result = computed<AutoGroupResult>(() => {\n const pre = preGrouping.value\n const composed = composeGroups({\n tokenizedSamples: tokenized.value,\n // After the pre-pass, sampleNames passed to compose are the *base* names\n // (one per replicate group); fall back to the original samples when\n // pre-grouping hasn't run (e.g. the CSV path or empty input).\n sampleNames: pre ? pre.baseNames : samples.value,\n schemas: schemas.value,\n classes: classes.value,\n })\n if (!pre) return composed\n // Expand each group's `samples` from base names back to the original\n // sample names so the Preview panel shows real filenames, not stripped\n // bases, and so `metadata` reflects each input row exactly once.\n return {\n ...composed,\n groups: expandGroupsWithReplicates(composed.groups, pre),\n experimentalGroups: composed.experimentalGroups\n ? expandGroupsWithReplicates(composed.experimentalGroups, pre)\n : undefined,\n qcGroups: composed.qcGroups\n ? expandGroupsWithReplicates(composed.qcGroups, pre)\n : undefined,\n }\n })\n\n const fingerprint = computed<SchemaFingerprint>(() =>\n serializeFingerprint(result.value.schemas ?? []),\n )\n\n const groups = computed(() => result.value.groups)\n const qcGroups = computed(() => result.value.qcGroups ?? [])\n const metadata = computed(() => result.value.metadata)\n const excludedSamples = computed(() => result.value.excludedSamples)\n\n // ----- Mutators -----\n\n function setClassDisposition(key: string, disposition: ClassDisposition) {\n const target = classes.value.find(c => classKey(c) === key)\n if (!target || target.disposition === disposition) return\n classes.value = classes.value.map(c =>\n classKey(c) === key ? { ...c, disposition } : c,\n )\n }\n\n function setClassDispositions(\n predicate: (c: SampleClass) => boolean,\n disposition: ClassDisposition,\n ) {\n let changed = false\n const next = classes.value.map(c => {\n if (predicate(c) && c.disposition !== disposition) {\n changed = true\n return { ...c, disposition }\n }\n return c\n })\n if (changed) classes.value = next\n }\n\n function toggleGroupBy(key: string, idx: number) {\n const schema = schemas.value[key]\n if (!schema) return\n const set = new Set(schema.groupBy)\n if (set.has(idx)) set.delete(idx)\n else set.add(idx)\n schemas.value = {\n ...schemas.value,\n [key]: { ...schema, groupBy: [...set].sort((a, b) => a - b) },\n }\n }\n\n function updateColumn(key: string, idx: number, patch: Partial<ColumnInfo>) {\n const schema = schemas.value[key]\n if (!schema) return\n const col = schema.columns.find(c => c.index === idx)\n if (!col) return\n let changed = false\n for (const k of Object.keys(patch) as (keyof ColumnInfo)[]) {\n if ((col as unknown as Record<string, unknown>)[k as string] !== (patch as unknown as Record<string, unknown>)[k as string]) {\n changed = true\n break\n }\n }\n if (!changed) return\n schemas.value = {\n ...schemas.value,\n [key]: {\n ...schema,\n columns: schema.columns.map(c => (c.index === idx ? { ...c, ...patch } : c)),\n },\n }\n }\n\n function setRole(key: string, idx: number, role: ColumnRole) {\n updateColumn(key, idx, { role })\n }\n\n function setColumnName(key: string, idx: number, name: string) {\n updateColumn(key, idx, { displayName: name })\n }\n\n function setValueOps(key: string, idx: number, ops: ValueOps) {\n updateColumn(key, idx, { ops })\n }\n\n function setBinning(key: string, idx: number, binning: NumericBinning) {\n updateColumn(key, idx, { binning })\n }\n\n function mergeColumns(key: string, indices: number[]) {\n const schema = schemas.value[key]\n if (!schema || indices.length < 2) return\n const sorted = [...indices].sort((a, b) => a - b)\n const start = sorted[0]\n const merged: ColumnInfo = {\n index: start,\n name: `Column ${sorted.map(i => i + 1).join('–')}`,\n sourceIndices: sorted.flatMap(i => schema.columns.find(c => c.index === i)?.sourceIndices ?? [i]),\n uniqueValues: [],\n cardinality: 0,\n role: 'factor',\n }\n const dropped = new Set(sorted)\n schemas.value = {\n ...schemas.value,\n [key]: {\n ...schema,\n columns: [merged, ...schema.columns.filter(c => !dropped.has(c.index))]\n .sort((a, b) => a.index - b.index),\n groupBy: schema.groupBy.filter(i => !dropped.has(i) || i === start),\n },\n }\n }\n\n function loadFingerprint(fp: SchemaFingerprint) {\n const restored = restoreFingerprint(fp, Object.values(schemas.value))\n const next: Record<string, ClassSchema> = {}\n for (const s of restored) next[classKey({ kind: s.classKind, subKind: s.subKind })] = s\n schemas.value = next\n }\n\n // ----- Template download -----\n\n const canDownloadTemplate = computed(() => samples.value.length > 0)\n\n function downloadTemplate(mode: 'blank' | 'prefilled' = 'prefilled', format: 'csv' | 'tsv' = 'csv') {\n const { content, filename } = composeTemplate(\n samples.value,\n mode === 'prefilled' ? Object.values(schemas.value) : null,\n mode === 'prefilled' ? classes.value : null,\n { mode, format, tokenizedSamples: tokenized.value },\n )\n const blob = new Blob([content], { type: format === 'tsv' ? 'text/tab-separated-values' : 'text/csv' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }\n\n /** Test seam — exposes the template content/filename without triggering a browser download. */\n function composeTemplateForTest(opts: Pick<TemplateOptions, 'mode' | 'format'>) {\n return composeTemplate(\n samples.value,\n opts.mode === 'prefilled' ? Object.values(schemas.value) : null,\n opts.mode === 'prefilled' ? classes.value : null,\n { ...opts, tokenizedSamples: tokenized.value },\n )\n }\n\n // ----- Legacy public refs and shims -----\n\n const outliers = ref<OutlierInfo[]>([])\n const hasOutliers = computed(() => outliers.value.length > 0)\n const conformingSamples = computed(() => samples.value)\n const dominantFieldCount = computed(() => tokenized.value[0]?.length ?? 0)\n const minFieldCount = computed(() => {\n if (tokenized.value.length === 0) return 0\n return Math.min(...tokenized.value.map(t => t.length))\n })\n const fields = computed(() => activeSchema.value?.columns ?? [])\n const fieldNames = computed<Record<number, string>>(() => {\n const out: Record<number, string> = {}\n for (const c of fields.value) out[c.index] = c.displayName ?? c.name\n return out\n })\n const enabledFields = computed<Set<number>>(() =>\n activeSchema.value ? new Set(activeSchema.value.groupBy) : new Set(),\n )\n const effectiveColumns = fields\n const allSingletons = computed(\n () => groups.value.length > 1 && groups.value.every(g => g.samples.length === 1),\n )\n\n function setOutlierAction(_: number, __: OutlierAction) {\n if (!outlierDeprecationWarned) {\n if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {\n console.warn(\n `[useAutoGroup] setOutlierAction is deprecated AND inactive in the class-first redesign. ` +\n `Use setClassDisposition('iqc' | 'eqc' | …, 'group' | 'overlay' | 'exclude') instead.`,\n )\n outlierDeprecationWarned = true\n }\n }\n }\n\n function setAllOutlierActions(__: OutlierAction) {\n if (!outlierDeprecationWarned) {\n if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {\n console.warn(\n `[useAutoGroup] setAllOutlierActions is deprecated AND inactive in the class-first redesign. ` +\n `Use setClassDisposition('iqc' | 'eqc' | …, 'group' | 'overlay' | 'exclude') instead.`,\n )\n outlierDeprecationWarned = true\n }\n }\n }\n\n function toggleField(index: number) {\n warnDeprecated('toggleField')\n if (activeClassKey.value) toggleGroupBy(activeClassKey.value, index)\n }\n\n function renameField(index: number, name: string) {\n warnDeprecated('renameField')\n if (activeClassKey.value) setColumnName(activeClassKey.value, index, name)\n }\n\n function loadExperimentData(rawData: Record<string, unknown>): boolean {\n const parsed = extractSamplesFromDesignData(rawData)\n if (!parsed) return false\n inputMode.value = 'experiment'\n csvData.value = parsed\n sampleTypeHints.value = parsed.sampleTypeHints\n parseInput()\n return true\n }\n\n function reset() {\n rawText.value = ''\n csvData.value = null\n classes.value = []\n schemas.value = {}\n activeClassKey.value = ''\n tokenized.value = []\n outliers.value = []\n sampleTypeHints.value = []\n }\n\n return {\n // State\n inputMode, rawText, csvData, sampleTypeHints,\n classes, schemas, activeClassKey,\n delimiter, dominantFieldCount, minFieldCount,\n // Computed\n samples, tokenized, activeSchema, suggestions,\n groups, qcGroups, metadata, excludedSamples, result, fingerprint,\n fields, fieldNames, enabledFields, effectiveColumns,\n hasOutliers, outliers, conformingSamples, allSingletons,\n canDownloadTemplate,\n // Mutators\n setClassDisposition, setClassDispositions, toggleGroupBy, setRole, setColumnName, setValueOps, setBinning,\n mergeColumns, loadFingerprint,\n // Actions\n parseInput, downloadTemplate, composeTemplateForTest, loadExperimentData, reset,\n // Deprecated shims\n setOutlierAction, setAllOutlierActions, toggleField, renameField,\n }\n}\n\nexport function extractSamplesFromDesignData(\n rawData: Record<string, unknown>,\n): (ParsedCsvData & { sampleTypeHints: (string | undefined)[] }) | null {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return null\n const samples = designData.samples\n if (!Array.isArray(samples) || samples.length === 0) return null\n const allConditionKeys: string[] = []\n const keySet = new Set<string>()\n const sampleTypeHints: (string | undefined)[] = []\n for (const sample of samples) {\n const rawType = (sample as Record<string, unknown>).sample_type\n sampleTypeHints.push(typeof rawType === 'string' ? rawType.toLowerCase() : undefined)\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 if (allConditionKeys.length === 0) return null\n const columns = ['sample_name', ...allConditionKeys, 'sample_type']\n const rows = (samples as Record<string, unknown>[]).map(s => {\n const conditions = (s.conditions as Record<string, string>) ?? {}\n const row: Record<string, string> = {\n sample_name: String(s.sample_name ?? ''),\n sample_type: String(s.sample_type ?? 'sample'),\n }\n for (const key of allConditionKeys) row[key] = conditions[key] ?? ''\n return row\n })\n return { columns, rows, sampleColumn: 'sample_name', delimiter: ',', sampleTypeHints }\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 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 { shallowRef, computed, type Ref, type ComputedRef } from 'vue'\nimport { useApi, type UseApiReturn } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n} from './experimentDesignData'\nimport type { TreeNode, SummaryData, SelectOption } from '../types'\n\nexport interface UseExperimentDataOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseExperimentDataReturn {\n /** Raw experiment data response from `/experiments/{id}/data`, or null. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload unwrapped from platform response shapes, or null. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** Sample values extracted from design_data for SampleSelector-style components. */\n sampleNames: ComputedRef<string[]>\n /** Sample options extracted from design_data for select/dropdown components. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\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<Record<string, unknown> | null>\n /** Refetch the most recently fetched experiment id. */\n refresh: () => Promise<void>\n /** Clear local experiment data and current fetch target. */\n clear: () => 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 data = shallowRef<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 let api: UseApiReturn | null = null\n\n function getApi(): UseApiReturn {\n api ??= useApi({ baseUrl: options.apiBaseUrl })\n return api\n }\n\n const designData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(data.value),\n )\n\n const sampleNames = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value),\n )\n\n const treeData = computed<TreeNode[]>(() => {\n if (!designData.value) return []\n const tree = designData.value.tree_data ?? designData.value.treeData\n return Array.isArray(tree) ? tree as TreeNode[] : []\n })\n\n const tableData = computed<Record<string, unknown>[]>(() => {\n if (!designData.value) return []\n const table = designData.value.table_data ?? designData.value.tableData\n return Array.isArray(table) ? table as Record<string, unknown>[] : []\n })\n\n const summaryData = computed<SummaryData | null>(() => {\n if (!designData.value) return null\n const summary = designData.value.summary_data ?? designData.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<Record<string, unknown> | null> {\n lastExperimentId = experimentId\n try {\n data.value = await request.run(\n () => getApi().get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { success: 'load', errorMessage: 'Failed to fetch experiment data' },\n )\n return data.value\n } catch {\n data.value = null\n return null\n }\n }\n\n async function refresh(): Promise<void> {\n if (lastExperimentId !== null) {\n await fetchData(lastExperimentId)\n }\n }\n\n function clear(): void {\n data.value = null\n lastExperimentId = null\n request.clearError()\n }\n\n return {\n data,\n designData,\n sampleNames,\n sampleOptions,\n treeData,\n tableData,\n summaryData,\n isLoading,\n error,\n lastLoadedAt,\n fetch: fetchData,\n refresh,\n clear,\n }\n}\n","import {\n computed,\n inject,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport type { SelectOption } from '../types'\nimport { APP_EXPERIMENT_KEY } from './useAppExperiment'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n type ExtractExperimentSamplesOptions,\n} from './experimentDesignData'\nimport { parseExperimentId } from './platformContextHelpers'\nimport { useExperimentData } from './useExperimentData'\n\nexport type ExperimentIdSource = MaybeRefOrGetter<number | string | null | undefined>\nexport type ExperimentDesignDataSource = MaybeRefOrGetter<Record<string, unknown> | null | undefined>\n\nexport interface UseExperimentSamplesOptions extends ExtractExperimentSamplesOptions {\n /** Experiment id to load from `/experiments/{id}/data`; defaults to provided AppExperiment context. */\n experimentId?: ExperimentIdSource\n /** Pre-fetched design_data or full platform design-data response. */\n designData?: ExperimentDesignDataSource\n /** API base URL override for platform calls. */\n apiBaseUrl?: string\n /** Auto-load when an experiment id becomes available. Defaults to true. */\n immediate?: boolean\n /** Enable or disable automatic loading while keeping derived samples reactive. Defaults to true. */\n enabled?: MaybeRefOrGetter<boolean>\n /** Use `useAppExperiment` provided state when `experimentId` is not set. Defaults to true. */\n syncAppExperiment?: boolean\n}\n\nexport interface UseExperimentSamplesReturn {\n /** Experiment id currently used for automatic sample loading. */\n experimentId: ComputedRef<number | undefined>\n /** Raw `/experiments/{id}/data` response when loaded through the platform API. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload from props or platform response. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** SampleSelector-compatible string values extracted from design_data. */\n samples: ComputedRef<string[]>\n /** Select/dropdown-friendly sample options extracted from design_data. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n isLoading: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n /** Fetch samples for a specific experiment id, defaulting to the resolved id. */\n fetch: (experimentId?: number | string | null) => Promise<Record<string, unknown> | null>\n /** Refetch the current experiment id. */\n refresh: () => Promise<void>\n /** Clear fetched platform data. */\n clear: () => void\n}\n\n/** Loads experiment design_data and derives samples for SampleSelector-style UIs. */\nexport function useExperimentSamples(\n options: UseExperimentSamplesOptions = {},\n): UseExperimentSamplesReturn {\n const appExperiment = options.syncAppExperiment === false\n ? undefined\n : inject(APP_EXPERIMENT_KEY, undefined)\n const experimentData = useExperimentData({ apiBaseUrl: options.apiBaseUrl })\n\n const experimentId = computed<number | undefined>(() => {\n const explicitId = parseExperimentId(toValue(options.experimentId))\n return explicitId ?? parseExperimentId(appExperiment?.experimentId.value)\n })\n\n const explicitDesignData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(toValue(options.designData) ?? null),\n )\n\n const designData = computed<Record<string, unknown> | null>(() =>\n explicitDesignData.value ?? experimentData.designData.value,\n )\n\n const extractOptions = computed<ExtractExperimentSamplesOptions>(() => ({\n includeControls: options.includeControls,\n }))\n\n const samples = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value, extractOptions.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value, extractOptions.value),\n )\n\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n async function fetchSamples(\n id: number | string | null | undefined = experimentId.value,\n ): Promise<Record<string, unknown> | null> {\n const parsedId = parseExperimentId(id)\n if (parsedId === undefined) {\n experimentData.clear()\n return null\n }\n return experimentData.fetch(parsedId)\n }\n\n watch(\n () => ({\n designData: explicitDesignData.value,\n enabled: enabled.value,\n experimentId: experimentId.value,\n }),\n ({ designData: currentDesignData, enabled: isEnabled, experimentId: currentExperimentId }) => {\n if (options.immediate === false || !isEnabled) return\n if (currentDesignData) {\n experimentData.clear()\n return\n }\n if (currentExperimentId === undefined) {\n experimentData.clear()\n return\n }\n void experimentData.fetch(currentExperimentId)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n data: experimentData.data,\n designData,\n samples,\n sampleOptions,\n isLoading: experimentData.isLoading,\n error: experimentData.error,\n lastLoadedAt: experimentData.lastLoadedAt,\n fetch: fetchSamples,\n refresh: experimentData.refresh,\n clear: experimentData.clear,\n }\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 { 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 './controlSchemaTypes'\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 './controlSchemaTypes'\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 './controlSchemaTypes'\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 const rack = createDefaultRack('Rack 1', 0)\n racks.value = [rack]\n activeRackId.value = rack.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 type { ProtocolStepType } 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\nexport const BUILT_IN_PROTOCOL_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","import { ref, computed, type Ref, type ComputedRef } from 'vue'\nimport type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'\nimport {\n BUILT_IN_PROTOCOL_TEMPLATES,\n type ParameterDefinition,\n type StepTemplate,\n} from './protocolTemplateCatalog'\n\nexport type { ParameterDefinition, StepTemplate } from './protocolTemplateCatalog'\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// Storage key for custom templates\nconst STORAGE_KEY = 'mint-custom-protocol-templates'\n\nfunction isStepTemplate(value: unknown): value is StepTemplate {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Partial<StepTemplate>\n return (\n typeof candidate.id === 'string'\n && typeof candidate.type === 'string'\n && typeof candidate.name === 'string'\n && Array.isArray(candidate.parameters)\n )\n}\n\nfunction loadCustomTemplates(): StepTemplate[] {\n try {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) {\n const parsed = JSON.parse(stored)\n return Array.isArray(parsed) ? parsed.filter(isStepTemplate) : []\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_PROTOCOL_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_PROTOCOL_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_PROTOCOL_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_PROTOCOL_TEMPLATES,\n customTemplates,\n allTemplates,\n getTemplateByType,\n getTemplateById,\n saveCustomTemplate,\n deleteCustomTemplate,\n validateStep,\n createStepFromTemplate,\n formatParameterValue,\n }\n}\n"],"mappings":"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ACE,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;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,SAAS;IACT,SAAS;KACP;MAAE,OAAO;MAAO,OAAO;MAAO;KAC9B;MAAE,OAAO;MAAQ,OAAO;MAAQ;KAChC;MAAE,OAAO;MAAO,OAAO;MAAO;KAC9B;MAAE,OAAO;MAAQ,OAAO;MAAQ;KAChC;MAAE,OAAO;MAAS,OAAO;MAAS;KAClC;MAAE,OAAO;MAAS,OAAO;MAAS;KACnC;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,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,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACN;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACX;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;KACP;MAAE,OAAO;MAAgB,OAAO;MAAgB;KAChD;MAAE,OAAO;MAAc,OAAO;MAAc;KAC5C;MAAE,OAAO;MAAkB,OAAO;MAAkB;KACpD;MAAE,OAAO;MAAqB,OAAO;MAAqB;KAC1D;MAAE,OAAO;MAAS,OAAO;MAAS;KACnC;IACF;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACd;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;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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"}
|