@morscherlab/mint-sdk 1.0.63 → 1.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +101 -2
  2. package/dist/EmptyState-D1c4RdC7.js +638 -0
  3. package/dist/EmptyState-D1c4RdC7.js.map +1 -0
  4. package/dist/{ExperimentPopover-BbPkIFsI.js → ExperimentPopover-BFw3QX8L.js} +10 -9
  5. package/dist/{ExperimentPopover-BbPkIFsI.js.map → ExperimentPopover-BFw3QX8L.js.map} +1 -1
  6. package/dist/{ExperimentSelectorModal-DZeSd-yr.js → ExperimentSelectorModal-B7w6k3Y8.js} +12 -216
  7. package/dist/ExperimentSelectorModal-B7w6k3Y8.js.map +1 -0
  8. package/dist/{SettingsModal-CJgLadsN.js → SettingsModal-DPDwCbXK.js} +12 -9
  9. package/dist/{SettingsModal-CJgLadsN.js.map → SettingsModal-DPDwCbXK.js.map} +1 -1
  10. package/dist/__tests__/components/GeneratedPlotlyResult.test.d.ts +1 -0
  11. package/dist/__tests__/components/GeneratedPluginView.test.d.ts +1 -0
  12. package/dist/__tests__/components/GeneratedResultRenderer.test.d.ts +1 -0
  13. package/dist/__tests__/components/InstrumentAlertLog.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useGeneratedAnalysis.test.d.ts +1 -0
  15. package/dist/__tests__/generatedUi.test.d.ts +1 -0
  16. package/dist/{analysisArtifactTypes-Cu40dzSG.js → analysisArtifactTypes-ejqR8MX3.js} +1 -1
  17. package/dist/analysisArtifactTypes-ejqR8MX3.js.map +1 -0
  18. package/dist/{auth-DZAwEeis.js → auth-B87xM--s.js} +1 -1
  19. package/dist/{auth-DZAwEeis.js.map → auth-B87xM--s.js.map} +1 -1
  20. package/dist/chunk-BoAXSpZd.js +33 -0
  21. package/dist/components/AppSidebar.vue.d.ts +1 -1
  22. package/dist/components/AutoGroupModal.vue.d.ts +2 -2
  23. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  24. package/dist/components/CollapsibleCard.vue.d.ts +1 -1
  25. package/dist/components/ComponentBindingRenderer.vue.d.ts +1 -1
  26. package/dist/components/ConfirmDialog.vue.d.ts +1 -1
  27. package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
  28. package/dist/components/ExperimentTimeline.vue.d.ts +1 -1
  29. package/dist/components/FileUploader.vue.d.ts +4 -2
  30. package/dist/components/FitPanel.vue.d.ts +1 -1
  31. package/dist/components/FormActions.vue.d.ts +1 -1
  32. package/dist/components/FormBuilder.vue.d.ts +1 -1
  33. package/dist/components/GeneratedPathInput.vue.d.ts +12 -0
  34. package/dist/components/GeneratedPlotlyResult.vue.d.ts +11 -0
  35. package/dist/components/GeneratedPluginView.vue.d.ts +10 -0
  36. package/dist/components/GeneratedResultRenderer.vue.d.ts +6 -0
  37. package/dist/components/JobsStatusTray.vue.d.ts +5 -1
  38. package/dist/components/LcmsSequenceTable.vue.d.ts +1 -1
  39. package/dist/components/SampleLegend.vue.d.ts +1 -1
  40. package/dist/components/SampleSelector.vue.d.ts +2 -2
  41. package/dist/components/SettingsModal.vue.d.ts +1 -1
  42. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
  43. package/dist/components/index.d.ts +4 -0
  44. package/dist/components/index.js +8 -9
  45. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +2 -2
  46. package/dist/{components-DdzHh3a_.js → components-UfkPN1bK.js} +2255 -2303
  47. package/dist/components-UfkPN1bK.js.map +1 -0
  48. package/dist/composables/index.d.ts +2 -3
  49. package/dist/composables/index.js +10 -11
  50. package/dist/composables/platformContextHelpers.d.ts +0 -2
  51. package/dist/composables/useAnalysisArtifacts.d.ts +1 -3
  52. package/dist/composables/useGeneratedAnalysis.d.ts +62 -0
  53. package/dist/composables/useJobsStatusTray.d.ts +48 -4
  54. package/dist/composables/usePlatformContext.d.ts +3 -0
  55. package/dist/composables/usePluginClient.d.ts +6 -3
  56. package/dist/{composables-BUUphBqg.js → composables-B512bWJP.js} +155 -74
  57. package/dist/composables-B512bWJP.js.map +1 -0
  58. package/dist/experiment-utils-CxkruZ3G.js +392 -0
  59. package/dist/experiment-utils-CxkruZ3G.js.map +1 -0
  60. package/dist/generated/schema.d.ts +7 -0
  61. package/dist/generated-ui/main.d.ts +0 -0
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +15 -18
  64. package/dist/index.js.map +1 -1
  65. package/dist/install.js +7 -8
  66. package/dist/install.js.map +1 -1
  67. package/dist/plotly.min-BR53hja4.js +180634 -0
  68. package/dist/plotly.min-BR53hja4.js.map +1 -0
  69. package/dist/stores/auth.d.ts +2 -2
  70. package/dist/stores/index.js +1 -1
  71. package/dist/styles.css +10543 -10404
  72. package/dist/templates/index.js +4 -3
  73. package/dist/templates/packs.d.ts +0 -1
  74. package/dist/{templates-CNbPQNID.js → templates-Cttbjbyc.js} +2 -4
  75. package/dist/templates-Cttbjbyc.js.map +1 -0
  76. package/dist/types/analysisArtifactTypes.d.ts +0 -8
  77. package/dist/types/form-builder.d.ts +1 -1
  78. package/dist/types/generated-ui.d.ts +170 -0
  79. package/dist/types/index.d.ts +2 -1
  80. package/dist/types/index.js +1 -1
  81. package/dist/types/instrument.d.ts +1 -0
  82. package/dist/types/jobs.d.ts +7 -1
  83. package/dist/types/platform.d.ts +2 -0
  84. package/dist/{useControlSchema-BZNdalmL.js → useControlSchema-Dallso-L.js} +1852 -171
  85. package/dist/useControlSchema-Dallso-L.js.map +1 -0
  86. package/dist/{useDropdownState-Bb-c_PeE.js → useDropdownState-gVaMXtwW.js} +2 -2
  87. package/dist/{useDropdownState-Bb-c_PeE.js.map → useDropdownState-gVaMXtwW.js.map} +1 -1
  88. package/dist/{useExperimentSelector-DRbj6vse.js → useExperimentSelector-BMjzNcf2.js} +4 -255
  89. package/dist/useExperimentSelector-BMjzNcf2.js.map +1 -0
  90. package/dist/{useFormBuilder-DKekvXRs.js → useFormBuilder-BXaaDI41.js} +2 -2
  91. package/dist/{useFormBuilder-DKekvXRs.js.map → useFormBuilder-BXaaDI41.js.map} +1 -1
  92. package/dist/{useAnalysisArtifacts-C3l0a0vu.js → useProtocolTemplates-BP7_4RGQ.js} +307 -475
  93. package/dist/useProtocolTemplates-BP7_4RGQ.js.map +1 -0
  94. package/package.json +7 -3
  95. package/src/__tests__/components/GeneratedPathInput.test.ts +132 -0
  96. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +117 -0
  97. package/src/__tests__/components/GeneratedPluginView.test.ts +230 -0
  98. package/src/__tests__/components/GeneratedResultRenderer.test.ts +93 -0
  99. package/src/__tests__/components/InstrumentAlertLog.test.ts +59 -0
  100. package/src/__tests__/composables/formBuilderRegistry.test.ts +5 -1
  101. package/src/__tests__/composables/useAnalysisArtifacts.test.ts +1 -74
  102. package/src/__tests__/composables/useApi.test.ts +8 -0
  103. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +1740 -0
  104. package/src/__tests__/composables/useJobsStatusTray.test.ts +179 -1
  105. package/src/__tests__/composables/usePlatformContext.test.ts +28 -0
  106. package/src/__tests__/composables/usePluginClient.test.ts +366 -20
  107. package/src/__tests__/composables/usePluginConfig.test.ts +323 -7
  108. package/src/__tests__/docs/extractDocsTemplates.test.ts +0 -1
  109. package/src/__tests__/generatedUi.test.ts +119 -0
  110. package/src/__tests__/templates/templates.test.ts +1 -1
  111. package/src/components/FileUploader.vue +49 -11
  112. package/src/components/GeneratedPathInput.vue +218 -0
  113. package/src/components/GeneratedPlotlyResult.vue +87 -0
  114. package/src/components/GeneratedPluginView.vue +279 -0
  115. package/src/components/GeneratedResultRenderer.vue +137 -0
  116. package/src/components/InstrumentAlertLog.vue +2 -2
  117. package/src/components/JobsStatusTray.vue +14 -8
  118. package/src/components/index.ts +4 -0
  119. package/src/composables/formBuilderRegistry.ts +2 -0
  120. package/src/composables/index.ts +18 -5
  121. package/src/composables/platformContextHelpers.ts +3 -10
  122. package/src/composables/useAnalysisArtifacts.ts +0 -48
  123. package/src/composables/useApi.ts +1 -0
  124. package/src/composables/useGeneratedAnalysis.ts +1252 -0
  125. package/src/composables/useJobsStatusTray.ts +234 -45
  126. package/src/composables/usePluginClient.ts +152 -25
  127. package/src/composables/usePluginConfig.ts +156 -20
  128. package/src/generated/schema.ts +130 -0
  129. package/src/generated-ui/main.ts +21 -0
  130. package/src/index.ts +3 -0
  131. package/src/jobs.ts +5 -0
  132. package/src/plotly-dist.d.ts +3 -0
  133. package/src/templates/packs.ts +0 -3
  134. package/src/types/analysisArtifactTypes.ts +0 -9
  135. package/src/types/form-builder.ts +1 -0
  136. package/src/types/generated-ui.ts +176 -0
  137. package/src/types/index.ts +2 -1
  138. package/src/types/instrument.ts +1 -0
  139. package/src/types/jobs.ts +10 -1
  140. package/src/types/platform.ts +2 -0
  141. package/dist/BaseButton-Dgqrze41.js +0 -74
  142. package/dist/BaseButton-Dgqrze41.js.map +0 -1
  143. package/dist/BaseModal-B9UA8Y_I.js +0 -165
  144. package/dist/BaseModal-B9UA8Y_I.js.map +0 -1
  145. package/dist/BaseSelect-ekgr9fDo.js +0 -179
  146. package/dist/BaseSelect-ekgr9fDo.js.map +0 -1
  147. package/dist/ExperimentPopover-Ryusjrhv.js +0 -4
  148. package/dist/ExperimentSelectorModal-Cg4-LXBD.js +0 -5
  149. package/dist/ExperimentSelectorModal-DZeSd-yr.js.map +0 -1
  150. package/dist/SettingsModal-Bl_9w2Y3.js +0 -5
  151. package/dist/analysisArtifactTypes-Cu40dzSG.js.map +0 -1
  152. package/dist/components-DdzHh3a_.js.map +0 -1
  153. package/dist/composables/analysisArtifactTarget.d.ts +0 -5
  154. package/dist/composables-BUUphBqg.js.map +0 -1
  155. package/dist/experiment-utils-Bfa7CwPU.js +0 -108
  156. package/dist/experiment-utils-Bfa7CwPU.js.map +0 -1
  157. package/dist/templates-CNbPQNID.js.map +0 -1
  158. package/dist/useAnalysisArtifacts-C3l0a0vu.js.map +0 -1
  159. package/dist/useControlSchema-BZNdalmL.js.map +0 -1
  160. package/dist/useEventListener-CfVkP9Xz.js +0 -57
  161. package/dist/useEventListener-CfVkP9Xz.js.map +0 -1
  162. package/dist/useExperimentSelector-DRbj6vse.js.map +0 -1
  163. package/src/__tests__/composables/analysisArtifactTarget.test.ts +0 -77
  164. package/src/composables/analysisArtifactTarget.ts +0 -53
  165. /package/dist/__tests__/{composables/analysisArtifactTarget.test.d.ts → components/GeneratedPathInput.test.d.ts} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/rack.ts"],"sourcesContent":["import type { Rack, SlotPosition, Well, WellEditData, WellPlateFormat } from '../types'\n\nexport type LcmsPlateType = '96well' | '54vial'\nexport type LcmsControlSampleType = 'blank' | 'qc' | 'iqc'\n\nexport interface LcmsPlateCell {\n row: string\n column: number\n sample_name: string\n sample_type?: string | null\n injection_volume?: number | null\n injection_count?: number | null\n custom_method?: string | null\n slot?: SlotPosition | null\n}\n\nexport interface LcmsPlateCellsToRackOptions {\n rackId?: string\n rackName?: string\n format?: WellPlateFormat\n plateType?: LcmsPlateType\n slot?: SlotPosition\n injectionVolume?: number\n}\n\nexport interface LcmsPlateCellsToRacksOptions extends Omit<LcmsPlateCellsToRackOptions, 'rackId' | 'rackName' | 'slot'> {\n defaultSlot?: SlotPosition\n rackId?: (slot: SlotPosition, index: number) => string\n rackName?: (slot: SlotPosition, index: number) => string\n}\n\nexport const LCMS_DEFAULT_CONTROL_POSITIONS: Record<LcmsPlateType, Record<LcmsControlSampleType, { row: string; column: number }>> = {\n '96well': {\n blank: { row: 'H', column: 12 },\n qc: { row: 'H', column: 11 },\n iqc: { row: 'H', column: 10 },\n },\n '54vial': {\n blank: { row: 'F', column: 9 },\n qc: { row: 'F', column: 8 },\n iqc: { row: 'F', column: 7 },\n },\n}\n\nconst SLOT_ORDER: SlotPosition[] = ['R', 'G', 'B', 'Y']\n\nexport function lcmsPlateTypeToRackFormat(plateType: LcmsPlateType): WellPlateFormat {\n return plateType === '96well' ? 96 : 54\n}\n\nexport function rackFormatToLcmsPlateType(format: WellPlateFormat): LcmsPlateType {\n if (format === 96) return '96well'\n if (format === 54) return '54vial'\n throw new Error(`LCMS plate cells support only 54-vial racks and 96-well plates; received format ${format}.`)\n}\n\nexport function lcmsWellId(row: string, column: number): string {\n return `${row.toUpperCase()}${column}`\n}\n\nexport function parseLcmsWellId(wellId: string): { row: string; column: number } {\n const match = /^([A-Za-z]+)(\\d+)$/.exec(wellId.trim())\n if (!match) {\n throw new Error(`Invalid well id \"${wellId}\". Expected a row letter followed by a column number, e.g. A1.`)\n }\n\n return {\n row: match[1].toUpperCase(),\n column: Number(match[2]),\n }\n}\n\nexport function lcmsPlateCellsToRack(cells: LcmsPlateCell[], options: LcmsPlateCellsToRackOptions = {}): Rack {\n const format = options.format ?? (options.plateType ? lcmsPlateTypeToRackFormat(options.plateType) : inferRackFormat(cells))\n const slot = options.slot ?? cells.find(cell => cell.slot)?.slot ?? 'R'\n const injectionVolume = options.injectionVolume ?? inferInjectionVolume(cells) ?? 5\n\n return {\n id: options.rackId ?? `rack-${slot}`,\n name: options.rackName ?? `Rack ${slot}`,\n format,\n slot,\n injectionVolume,\n wells: Object.fromEntries(\n cells\n .filter(cell => cell.sample_name.trim())\n .map((cell) => {\n const wellId = lcmsWellId(cell.row, cell.column)\n const well: Partial<Well> = {\n id: wellId,\n row: rowIndex(cell.row),\n col: cell.column - 1,\n state: 'filled',\n sampleType: cell.sample_type ?? 'sample',\n metadata: {\n label: cell.sample_name.trim(),\n injectionVolume: cell.injection_volume ?? injectionVolume,\n injectionCount: cell.injection_count ?? 1,\n customMethod: cell.custom_method ?? null,\n },\n }\n return [wellId, well]\n }),\n ),\n }\n}\n\nexport function lcmsPlateCellsToRacks(cells: LcmsPlateCell[], options: LcmsPlateCellsToRacksOptions = {}): Rack[] {\n const bySlot = new Map<SlotPosition, LcmsPlateCell[]>()\n const defaultSlot = options.defaultSlot ?? 'R'\n\n for (const cell of cells) {\n const slot = cell.slot ?? defaultSlot\n const slotCells = bySlot.get(slot) ?? []\n slotCells.push(cell)\n bySlot.set(slot, slotCells)\n }\n\n return Array.from(bySlot.entries())\n .sort(([a], [b]) => SLOT_ORDER.indexOf(a) - SLOT_ORDER.indexOf(b))\n .map(([slot, slotCells], index) => lcmsPlateCellsToRack(slotCells, {\n ...options,\n slot,\n rackId: options.rackId?.(slot, index) ?? `rack-${slot}`,\n rackName: options.rackName?.(slot, index) ?? `Rack ${slot}`,\n }))\n}\n\nexport function rackToLcmsPlateCells(rack: Rack): LcmsPlateCell[] {\n return Object.entries(rack.wells)\n .map(([wellId, well]) => wellToLcmsPlateCell(rack, wellId, well))\n .filter((cell): cell is LcmsPlateCell => cell !== null)\n .sort(comparePlateCells)\n}\n\nexport function racksToLcmsPlateCells(racks: Rack[]): LcmsPlateCell[] {\n return racks.flatMap(rackToLcmsPlateCells)\n}\n\nexport function getLcmsDefaultControlWellId(plateType: LcmsPlateType, sampleType: LcmsControlSampleType): string {\n const position = LCMS_DEFAULT_CONTROL_POSITIONS[plateType][sampleType]\n return lcmsWellId(position.row, position.column)\n}\n\nexport function createLcmsControlWellEditData(\n sampleType: LcmsControlSampleType,\n options: {\n wellId?: string\n plateType?: LcmsPlateType\n injectionVolume?: number\n } = {},\n): WellEditData {\n const plateType = options.plateType ?? '54vial'\n return {\n wellId: options.wellId ?? getLcmsDefaultControlWellId(plateType, sampleType),\n label: sampleType === 'blank' ? 'Blank' : sampleType.toUpperCase(),\n sampleType,\n injectionVolume: options.injectionVolume ?? 5,\n injectionCount: 1,\n customMethod: '',\n }\n}\n\nfunction wellToLcmsPlateCell(rack: Rack, wellId: string, well: Partial<Well>): LcmsPlateCell | null {\n const metadata = well.metadata ?? {}\n const label = getString(metadata.label)\n if (!label) return null\n\n const parsed = parseLcmsWellId(well.id ?? wellId)\n return {\n row: parsed.row,\n column: parsed.column,\n sample_name: label,\n sample_type: well.sampleType ?? null,\n injection_volume: getNumber(metadata.injectionVolume) ?? rack.injectionVolume,\n injection_count: getNumber(metadata.injectionCount) ?? 1,\n custom_method: getNullableString(metadata.customMethod),\n slot: rack.slot,\n }\n}\n\nfunction inferRackFormat(cells: LcmsPlateCell[]): WellPlateFormat {\n return cells.some(cell => rowIndex(cell.row) > 5 || cell.column > 9) ? 96 : 54\n}\n\nfunction inferInjectionVolume(cells: LcmsPlateCell[]): number | undefined {\n return cells.find(cell => typeof cell.injection_volume === 'number')?.injection_volume ?? undefined\n}\n\nfunction rowIndex(row: string): number {\n return row.toUpperCase().charCodeAt(0) - 65\n}\n\nfunction getString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getNullableString(value: unknown): string | null {\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n\nfunction getNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction comparePlateCells(a: LcmsPlateCell, b: LcmsPlateCell): number {\n const rowDiff = rowIndex(a.row) - rowIndex(b.row)\n return rowDiff === 0 ? a.column - b.column : rowDiff\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/utils/rack.ts"],"sourcesContent":["import type { Rack, SlotPosition, Well, WellEditData, WellPlateFormat } from '../types'\n\nexport type LcmsPlateType = '96well' | '54vial'\nexport type LcmsControlSampleType = 'blank' | 'qc' | 'iqc'\n\nexport interface LcmsPlateCell {\n row: string\n column: number\n sample_name: string\n sample_type?: string | null\n injection_volume?: number | null\n injection_count?: number | null\n custom_method?: string | null\n slot?: SlotPosition | null\n}\n\nexport interface LcmsPlateCellsToRackOptions {\n rackId?: string\n rackName?: string\n format?: WellPlateFormat\n plateType?: LcmsPlateType\n slot?: SlotPosition\n injectionVolume?: number\n}\n\nexport interface LcmsPlateCellsToRacksOptions extends Omit<LcmsPlateCellsToRackOptions, 'rackId' | 'rackName' | 'slot'> {\n defaultSlot?: SlotPosition\n rackId?: (slot: SlotPosition, index: number) => string\n rackName?: (slot: SlotPosition, index: number) => string\n}\n\nexport const LCMS_DEFAULT_CONTROL_POSITIONS: Record<LcmsPlateType, Record<LcmsControlSampleType, { row: string; column: number }>> = {\n '96well': {\n blank: { row: 'H', column: 12 },\n qc: { row: 'H', column: 11 },\n iqc: { row: 'H', column: 10 },\n },\n '54vial': {\n blank: { row: 'F', column: 9 },\n qc: { row: 'F', column: 8 },\n iqc: { row: 'F', column: 7 },\n },\n}\n\nconst SLOT_ORDER: SlotPosition[] = ['R', 'G', 'B', 'Y']\n\nexport function lcmsPlateTypeToRackFormat(plateType: LcmsPlateType): WellPlateFormat {\n return plateType === '96well' ? 96 : 54\n}\n\nexport function rackFormatToLcmsPlateType(format: WellPlateFormat): LcmsPlateType {\n if (format === 96) return '96well'\n if (format === 54) return '54vial'\n throw new Error(`LCMS plate cells support only 54-vial racks and 96-well plates; received format ${format}.`)\n}\n\nexport function lcmsWellId(row: string, column: number): string {\n return `${row.toUpperCase()}${column}`\n}\n\nexport function parseLcmsWellId(wellId: string): { row: string; column: number } {\n const match = /^([A-Za-z]+)(\\d+)$/.exec(wellId.trim())\n if (!match) {\n throw new Error(`Invalid well id \"${wellId}\". Expected a row letter followed by a column number, e.g. A1.`)\n }\n\n return {\n row: match[1].toUpperCase(),\n column: Number(match[2]),\n }\n}\n\nexport function lcmsPlateCellsToRack(cells: LcmsPlateCell[], options: LcmsPlateCellsToRackOptions = {}): Rack {\n const format = options.format ?? (options.plateType ? lcmsPlateTypeToRackFormat(options.plateType) : inferRackFormat(cells))\n const slot = options.slot ?? cells.find(cell => cell.slot)?.slot ?? 'R'\n const injectionVolume = options.injectionVolume ?? inferInjectionVolume(cells) ?? 5\n\n return {\n id: options.rackId ?? `rack-${slot}`,\n name: options.rackName ?? `Rack ${slot}`,\n format,\n slot,\n injectionVolume,\n wells: Object.fromEntries(\n cells\n .filter(cell => cell.sample_name.trim())\n .map((cell) => {\n const wellId = lcmsWellId(cell.row, cell.column)\n const well: Partial<Well> = {\n id: wellId,\n row: rowIndex(cell.row),\n col: cell.column - 1,\n state: 'filled',\n sampleType: cell.sample_type ?? 'sample',\n metadata: {\n label: cell.sample_name.trim(),\n injectionVolume: cell.injection_volume ?? injectionVolume,\n injectionCount: cell.injection_count ?? 1,\n customMethod: cell.custom_method ?? null,\n },\n }\n return [wellId, well]\n }),\n ),\n }\n}\n\nexport function lcmsPlateCellsToRacks(cells: LcmsPlateCell[], options: LcmsPlateCellsToRacksOptions = {}): Rack[] {\n const bySlot = new Map<SlotPosition, LcmsPlateCell[]>()\n const defaultSlot = options.defaultSlot ?? 'R'\n\n for (const cell of cells) {\n const slot = cell.slot ?? defaultSlot\n const slotCells = bySlot.get(slot) ?? []\n slotCells.push(cell)\n bySlot.set(slot, slotCells)\n }\n\n return Array.from(bySlot.entries())\n .sort(([a], [b]) => SLOT_ORDER.indexOf(a) - SLOT_ORDER.indexOf(b))\n .map(([slot, slotCells], index) => lcmsPlateCellsToRack(slotCells, {\n ...options,\n slot,\n rackId: options.rackId?.(slot, index) ?? `rack-${slot}`,\n rackName: options.rackName?.(slot, index) ?? `Rack ${slot}`,\n }))\n}\n\nexport function rackToLcmsPlateCells(rack: Rack): LcmsPlateCell[] {\n return Object.entries(rack.wells)\n .map(([wellId, well]) => wellToLcmsPlateCell(rack, wellId, well))\n .filter((cell): cell is LcmsPlateCell => cell !== null)\n .sort(comparePlateCells)\n}\n\nexport function racksToLcmsPlateCells(racks: Rack[]): LcmsPlateCell[] {\n return racks.flatMap(rackToLcmsPlateCells)\n}\n\nexport function getLcmsDefaultControlWellId(plateType: LcmsPlateType, sampleType: LcmsControlSampleType): string {\n const position = LCMS_DEFAULT_CONTROL_POSITIONS[plateType][sampleType]\n return lcmsWellId(position.row, position.column)\n}\n\nexport function createLcmsControlWellEditData(\n sampleType: LcmsControlSampleType,\n options: {\n wellId?: string\n plateType?: LcmsPlateType\n injectionVolume?: number\n } = {},\n): WellEditData {\n const plateType = options.plateType ?? '54vial'\n return {\n wellId: options.wellId ?? getLcmsDefaultControlWellId(plateType, sampleType),\n label: sampleType === 'blank' ? 'Blank' : sampleType.toUpperCase(),\n sampleType,\n injectionVolume: options.injectionVolume ?? 5,\n injectionCount: 1,\n customMethod: '',\n }\n}\n\nfunction wellToLcmsPlateCell(rack: Rack, wellId: string, well: Partial<Well>): LcmsPlateCell | null {\n const metadata = well.metadata ?? {}\n const label = getString(metadata.label)\n if (!label) return null\n\n const parsed = parseLcmsWellId(well.id ?? wellId)\n return {\n row: parsed.row,\n column: parsed.column,\n sample_name: label,\n sample_type: well.sampleType ?? null,\n injection_volume: getNumber(metadata.injectionVolume) ?? rack.injectionVolume,\n injection_count: getNumber(metadata.injectionCount) ?? 1,\n custom_method: getNullableString(metadata.customMethod),\n slot: rack.slot,\n }\n}\n\nfunction inferRackFormat(cells: LcmsPlateCell[]): WellPlateFormat {\n return cells.some(cell => rowIndex(cell.row) > 5 || cell.column > 9) ? 96 : 54\n}\n\nfunction inferInjectionVolume(cells: LcmsPlateCell[]): number | undefined {\n return cells.find(cell => typeof cell.injection_volume === 'number')?.injection_volume ?? undefined\n}\n\nfunction rowIndex(row: string): number {\n return row.toUpperCase().charCodeAt(0) - 65\n}\n\nfunction getString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getNullableString(value: unknown): string | null {\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n\nfunction getNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction comparePlateCells(a: LcmsPlateCell, b: LcmsPlateCell): number {\n const rowDiff = rowIndex(a.row) - rowIndex(b.row)\n return rowDiff === 0 ? a.column - b.column : rowDiff\n}\n"],"mappings":"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"}
package/dist/install.js CHANGED
@@ -1,11 +1,10 @@
1
- import { t as components_exports } from "./components-DdzHh3a_.js";
2
- import "./BaseButton-Dgqrze41.js";
3
- import "./BaseSelect-ekgr9fDo.js";
4
- import "./useControlSchema-BZNdalmL.js";
5
- import "./SettingsModal-CJgLadsN.js";
6
- import "./BaseModal-B9UA8Y_I.js";
7
- import "./ExperimentSelectorModal-DZeSd-yr.js";
8
- import "./ExperimentPopover-BbPkIFsI.js";
1
+ import "./experiment-utils-CxkruZ3G.js";
2
+ import "./EmptyState-D1c4RdC7.js";
3
+ import "./useControlSchema-Dallso-L.js";
4
+ import { t as components_exports } from "./components-UfkPN1bK.js";
5
+ import "./SettingsModal-DPDwCbXK.js";
6
+ import "./ExperimentPopover-BFw3QX8L.js";
7
+ import "./ExperimentSelectorModal-B7w6k3Y8.js";
9
8
  //#region src/install.ts
10
9
  /**
11
10
  * Vue plugin that registers all MINT SDK components globally.
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","names":[],"sources":["../src/install.ts"],"sourcesContent":["import * as components from './components'\n\ntype ComponentRegistryApp = {\n component: (name: string, component: any) => unknown\n}\n\nexport interface MINTSdkPlugin {\n install(app: ComponentRegistryApp): void\n}\n\n/**\n * Vue plugin that registers all MINT SDK components globally.\n *\n * @example\n * ```typescript\n * import { createApp } from 'vue'\n * import { MINTSdk } from '@morscherlab/mint-sdk'\n * import '@morscherlab/mint-sdk/styles'\n *\n * const app = createApp(App)\n * app.use(MINTSdk)\n * ```\n */\nexport const MINTSdk: MINTSdkPlugin = {\n install(app) {\n for (const [name, component] of Object.entries(components)) {\n // Check if it's a valid Vue component (has setup, render, or template)\n if (\n component &&\n typeof component === 'object' &&\n ('setup' in component || 'render' in component || '__name' in component)\n ) {\n app.component(name, component)\n }\n }\n },\n}\n\nexport default MINTSdk\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,UAAyB,EACpC,QAAQ,KAAK;AACX,MAAK,MAAM,CAAC,MAAM,cAAc,OAAO,QAAQ,mBAAW,CAExD,KACE,aACA,OAAO,cAAc,aACpB,WAAW,aAAa,YAAY,aAAa,YAAY,WAE9D,KAAI,UAAU,MAAM,UAAU;GAIrC"}
1
+ {"version":3,"file":"install.js","names":[],"sources":["../src/install.ts"],"sourcesContent":["import * as components from './components'\n\ntype ComponentRegistryApp = {\n component: (name: string, component: any) => unknown\n}\n\nexport interface MINTSdkPlugin {\n install(app: ComponentRegistryApp): void\n}\n\n/**\n * Vue plugin that registers all MINT SDK components globally.\n *\n * @example\n * ```typescript\n * import { createApp } from 'vue'\n * import { MINTSdk } from '@morscherlab/mint-sdk'\n * import '@morscherlab/mint-sdk/styles'\n *\n * const app = createApp(App)\n * app.use(MINTSdk)\n * ```\n */\nexport const MINTSdk: MINTSdkPlugin = {\n install(app) {\n for (const [name, component] of Object.entries(components)) {\n // Check if it's a valid Vue component (has setup, render, or template)\n if (\n component &&\n typeof component === 'object' &&\n ('setup' in component || 'render' in component || '__name' in component)\n ) {\n app.component(name, component)\n }\n }\n },\n}\n\nexport default MINTSdk\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,UAAyB,EACpC,QAAQ,KAAK;AACX,MAAK,MAAM,CAAC,MAAM,cAAc,OAAO,QAAQ,mBAAW,CAExD,KACE,aACA,OAAO,cAAc,aACpB,WAAW,aAAa,YAAY,aAAa,YAAY,WAE9D,KAAI,UAAU,MAAM,UAAU;GAIrC"}