@morscherlab/mint-sdk 1.0.0-rc.1 → 1.0.0-rc.4

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 (300) hide show
  1. package/README.md +9 -1
  2. package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +1 -0
  3. package/dist/__tests__/components/ProgressBar.test.d.ts +1 -0
  4. package/dist/__tests__/components/RackEditor.test.d.ts +1 -0
  5. package/dist/__tests__/components/SequenceProgressBar.test.d.ts +1 -0
  6. package/dist/__tests__/composables/useExperimentSamples.test.d.ts +1 -0
  7. package/dist/__tests__/utils/instrument.test.d.ts +1 -0
  8. package/dist/__tests__/utils/lcms.test.d.ts +1 -0
  9. package/dist/__tests__/utils/permissions.test.d.ts +1 -0
  10. package/dist/__tests__/utils/rack.test.d.ts +1 -0
  11. package/dist/{auth-CBG3bWEc.js → auth-B7g4J4ZF.js} +99 -5
  12. package/dist/auth-B7g4J4ZF.js.map +1 -0
  13. package/dist/components/AppSidebar.vue.d.ts +3 -3
  14. package/dist/components/AutoGroupModal.vue.d.ts +1 -1
  15. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  16. package/dist/components/BaseToggle.vue.d.ts +2 -2
  17. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
  18. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  19. package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +1 -1
  20. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  21. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +2 -2
  22. package/dist/components/FormulaInput.vue.d.ts +1 -1
  23. package/dist/components/InstrumentAlertLog.vue.d.ts +22 -0
  24. package/dist/components/InstrumentStateBadge.vue.d.ts +11 -0
  25. package/dist/components/InstrumentStatusCard.vue.d.ts +13 -0
  26. package/dist/components/LcmsSequenceTable.vue.d.ts +26 -0
  27. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -3
  28. package/dist/components/ProgressBar.vue.d.ts +1 -0
  29. package/dist/components/RackEditor.vue.d.ts +41 -3
  30. package/dist/components/ReagentList.vue.d.ts +1 -1
  31. package/dist/components/SampleSelector.vue.d.ts +5 -2
  32. package/dist/components/SegmentedControl.vue.d.ts +2 -0
  33. package/dist/components/SequenceInput.vue.d.ts +1 -1
  34. package/dist/components/SequenceProgressBar.vue.d.ts +15 -0
  35. package/dist/components/SettingsModal.vue.d.ts +3 -1
  36. package/dist/components/TagsInput.vue.d.ts +1 -1
  37. package/dist/components/WellPlate.vue.d.ts +42 -3
  38. package/dist/components/index.d.ts +5 -0
  39. package/dist/components/index.js +3 -3
  40. package/dist/{components-5KSfsVqf.js → components-DafPc4rM.js} +2091 -1051
  41. package/dist/components-DafPc4rM.js.map +1 -0
  42. package/dist/composables/controlComponentBindings.d.ts +7 -0
  43. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  44. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  45. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  46. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  47. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  48. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  49. package/dist/composables/experimentDesignData.d.ts +17 -0
  50. package/dist/composables/index.d.ts +2 -0
  51. package/dist/composables/index.js +4 -4
  52. package/dist/composables/useControlSchema.d.ts +15 -30
  53. package/dist/composables/useControlWorkspace.d.ts +5 -0
  54. package/dist/composables/useExperimentData.d.ts +11 -3
  55. package/dist/composables/useExperimentSamples.d.ts +42 -0
  56. package/dist/composables/usePlatformContext.d.ts +54 -0
  57. package/dist/{composables-D4Myb30a.js → composables-BMkPQhVK.js} +5 -3
  58. package/dist/composables-BMkPQhVK.js.map +1 -0
  59. package/dist/index.d.ts +4 -0
  60. package/dist/index.js +168 -6
  61. package/dist/index.js.map +1 -0
  62. package/dist/install.js +2 -2
  63. package/dist/instrument.d.ts +7 -0
  64. package/dist/lcms.d.ts +27 -0
  65. package/dist/permissions.d.ts +46 -0
  66. package/dist/stores/auth.d.ts +74 -2
  67. package/dist/stores/index.js +1 -1
  68. package/dist/styles.css +3316 -1216
  69. package/dist/templates/adapters.d.ts +14 -47
  70. package/dist/templates/assayLookups.d.ts +3 -0
  71. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  72. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  73. package/dist/templates/assayNormalizers.d.ts +4 -0
  74. package/dist/templates/builderDefaults.d.ts +1 -0
  75. package/dist/templates/builderIdUtils.d.ts +4 -0
  76. package/dist/templates/builderPresetControls.d.ts +10 -0
  77. package/dist/templates/builderReadUtils.d.ts +8 -0
  78. package/dist/templates/builders.d.ts +26 -63
  79. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  80. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  81. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  82. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  83. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  84. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  85. package/dist/templates/componentGenericProps.d.ts +8 -0
  86. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  87. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  88. package/dist/templates/componentPropsFactory.d.ts +3 -0
  89. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  90. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  91. package/dist/templates/componentTemplateProps.d.ts +3 -0
  92. package/dist/templates/controlSchemaClone.d.ts +4 -0
  93. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  94. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  95. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  96. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  97. package/dist/templates/controlSchemas.d.ts +4 -4
  98. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  99. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  100. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  101. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  102. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  103. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  104. package/dist/templates/flowNormalizers.d.ts +8 -0
  105. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  106. package/dist/templates/index.d.ts +2 -2
  107. package/dist/templates/index.js +2 -2
  108. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  109. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  110. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  111. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  112. package/dist/templates/plateGeometry.d.ts +4 -0
  113. package/dist/templates/plateMapAdapters.d.ts +3 -0
  114. package/dist/templates/plateMapBuilder.d.ts +2 -0
  115. package/dist/templates/presetControlSchemas.d.ts +534 -0
  116. package/dist/templates/presets.d.ts +12 -0
  117. package/dist/templates/protocolAdapters.d.ts +5 -0
  118. package/dist/templates/protocolNormalizers.d.ts +6 -0
  119. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  120. package/dist/templates/qpcrAdapters.d.ts +5 -0
  121. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  122. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  123. package/dist/templates/reagentAdapters.d.ts +5 -0
  124. package/dist/templates/reagentListBuilder.d.ts +2 -0
  125. package/dist/templates/runNormalizers.d.ts +10 -0
  126. package/dist/templates/sampleNormalizers.d.ts +4 -0
  127. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  128. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  129. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  130. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  131. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  132. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  133. package/dist/templates/templateControlSchemas.d.ts +400 -0
  134. package/dist/templates/templateEnvelopes.d.ts +9 -0
  135. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  136. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  137. package/dist/templates/templateValidators.d.ts +13 -0
  138. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  139. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  140. package/dist/templates/types.d.ts +16 -1
  141. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  142. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  143. package/dist/{templates-BSlxwV2c.js → templates-bUAWMn5L.js} +3610 -3154
  144. package/dist/templates-bUAWMn5L.js.map +1 -0
  145. package/dist/types/auth.d.ts +2 -0
  146. package/dist/types/components.d.ts +32 -3
  147. package/dist/types/form-builder.d.ts +2 -1
  148. package/dist/types/index.d.ts +4 -1
  149. package/dist/types/instrument.d.ts +56 -0
  150. package/dist/types/platform.d.ts +3 -0
  151. package/dist/{useExperimentData-BbbdI5xT.js → useProtocolTemplates-QZtHFFH2.js} +534 -359
  152. package/dist/useProtocolTemplates-QZtHFFH2.js.map +1 -0
  153. package/dist/utils/rack.d.ts +47 -0
  154. package/package.json +1 -1
  155. package/src/__tests__/components/AppTopBar.test.ts +15 -0
  156. package/src/__tests__/components/BaseTabs.test.ts +15 -0
  157. package/src/__tests__/components/LcmsSequenceTable.test.ts +57 -0
  158. package/src/__tests__/components/ProgressBar.test.ts +18 -0
  159. package/src/__tests__/components/RackEditor.test.ts +125 -0
  160. package/src/__tests__/components/SampleSelector.test.ts +25 -0
  161. package/src/__tests__/components/SegmentedControl.test.ts +45 -0
  162. package/src/__tests__/components/SequenceProgressBar.test.ts +39 -0
  163. package/src/__tests__/components/SettingsModal.test.ts +83 -2
  164. package/src/__tests__/composables/useControlSchema.test.ts +4 -0
  165. package/src/__tests__/composables/useExperimentData.test.ts +23 -0
  166. package/src/__tests__/composables/useExperimentSamples.test.ts +91 -0
  167. package/src/__tests__/templates/templates.test.ts +86 -0
  168. package/src/__tests__/utils/instrument.test.ts +47 -0
  169. package/src/__tests__/utils/lcms.test.ts +73 -0
  170. package/src/__tests__/utils/permissions.test.ts +50 -0
  171. package/src/__tests__/utils/rack.test.ts +120 -0
  172. package/src/components/AppTopBar.vue +1 -0
  173. package/src/components/BaseTabs.vue +22 -1
  174. package/src/components/InstrumentAlertLog.vue +191 -0
  175. package/src/components/InstrumentStateBadge.vue +50 -0
  176. package/src/components/InstrumentStatusCard.vue +188 -0
  177. package/src/components/LcmsSequenceTable.vue +191 -0
  178. package/src/components/ProgressBar.vue +3 -0
  179. package/src/components/RackEditor.vue +73 -2
  180. package/src/components/SampleSelector.vue +28 -9
  181. package/src/components/SegmentedControl.story.vue +17 -0
  182. package/src/components/SegmentedControl.vue +14 -3
  183. package/src/components/SequenceProgressBar.vue +71 -0
  184. package/src/components/SettingsModal.vue +42 -2
  185. package/src/components/WellPlate.vue +142 -21
  186. package/src/components/index.ts +5 -0
  187. package/src/components/internal/WellEditPopupInternal.vue +1 -0
  188. package/src/composables/controlComponentBindings.ts +80 -0
  189. package/src/composables/controlSchemaAdapters.ts +196 -0
  190. package/src/composables/controlSchemaFormFields.ts +61 -0
  191. package/src/composables/controlSchemaLayout.ts +59 -0
  192. package/src/composables/controlSchemaNormalize.ts +101 -0
  193. package/src/composables/controlSchemaUtils.ts +36 -0
  194. package/src/composables/controlWorkspaceOptions.ts +21 -0
  195. package/src/composables/experimentDesignData.ts +182 -0
  196. package/src/composables/index.ts +14 -0
  197. package/src/composables/useAuth.ts +4 -0
  198. package/src/composables/useAutoGroup.ts +5 -1
  199. package/src/composables/useControlSchema.ts +62 -618
  200. package/src/composables/useControlWorkspace.ts +207 -0
  201. package/src/composables/useExperimentData.ts +57 -16
  202. package/src/composables/useExperimentSamples.ts +142 -0
  203. package/src/index.ts +27 -0
  204. package/src/instrument.ts +90 -0
  205. package/src/lcms.ts +108 -0
  206. package/src/permissions.ts +143 -0
  207. package/src/stores/auth.ts +31 -3
  208. package/src/styles/components/instrument-monitor.css +478 -0
  209. package/src/styles/components/lcms-sequence-table.css +189 -0
  210. package/src/styles/components/sequence-progress-bar.css +63 -0
  211. package/src/styles/components/tabs.css +9 -0
  212. package/src/styles/components/well-edit-popup.css +7 -1
  213. package/src/styles/components/well-plate.css +5 -0
  214. package/src/styles/index.css +3 -0
  215. package/src/templates/adapters.ts +89 -930
  216. package/src/templates/assayLookups.ts +33 -0
  217. package/src/templates/assayMatrixAdapters.ts +78 -0
  218. package/src/templates/assayMatrixBuilder.ts +59 -0
  219. package/src/templates/assayNormalizers.ts +34 -0
  220. package/src/templates/builderDefaults.ts +11 -0
  221. package/src/templates/builderIdUtils.ts +20 -0
  222. package/src/templates/builderPresetControls.ts +165 -0
  223. package/src/templates/builderReadUtils.ts +57 -0
  224. package/src/templates/builders.ts +122 -2149
  225. package/src/templates/calibrationCurveAdapters.ts +59 -0
  226. package/src/templates/calibrationCurveBuilder.ts +99 -0
  227. package/src/templates/calibrationNormalizers.ts +60 -0
  228. package/src/templates/componentBindingCatalog.ts +90 -0
  229. package/src/templates/componentBindingHelpers.ts +93 -0
  230. package/src/templates/componentBindings.ts +12 -461
  231. package/src/templates/componentDoseResponseProps.ts +42 -0
  232. package/src/templates/componentGenericProps.ts +77 -0
  233. package/src/templates/componentPlateHelpers.ts +29 -0
  234. package/src/templates/componentPlateMapProps.ts +32 -0
  235. package/src/templates/componentPropsFactory.ts +21 -0
  236. package/src/templates/componentQpcrPlateProps.ts +28 -0
  237. package/src/templates/componentTargetResolvers.ts +69 -0
  238. package/src/templates/componentTemplateProps.ts +78 -0
  239. package/src/templates/controlSchemaClone.ts +32 -0
  240. package/src/templates/controlSchemaConstants.ts +11 -0
  241. package/src/templates/controlSchemaMerge.ts +40 -0
  242. package/src/templates/controlSchemaTargets.ts +87 -0
  243. package/src/templates/controlSchemaTypes.ts +20 -0
  244. package/src/templates/controlSchemas.ts +22 -636
  245. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  246. package/src/templates/doseResponseAdapters.ts +45 -0
  247. package/src/templates/doseResponseBuilder.ts +44 -0
  248. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  249. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  250. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  251. package/src/templates/flowNormalizers.ts +58 -0
  252. package/src/templates/flowPanelAdapters.ts +58 -0
  253. package/src/templates/index.ts +2 -0
  254. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  255. package/src/templates/instrumentRunAdapters.ts +163 -0
  256. package/src/templates/instrumentRunBuilder.ts +97 -0
  257. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  258. package/src/templates/plateGeometry.ts +62 -0
  259. package/src/templates/plateMapAdapters.ts +36 -0
  260. package/src/templates/plateMapBuilder.ts +43 -0
  261. package/src/templates/presetControlSchemas.ts +258 -0
  262. package/src/templates/presets.ts +23 -0
  263. package/src/templates/protocolAdapters.ts +69 -0
  264. package/src/templates/protocolNormalizers.ts +37 -0
  265. package/src/templates/protocolStepsBuilder.ts +36 -0
  266. package/src/templates/qpcrAdapters.ts +104 -0
  267. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  268. package/src/templates/qpcrPlateBuilder.ts +96 -0
  269. package/src/templates/reagentAdapters.ts +77 -0
  270. package/src/templates/reagentListBuilder.ts +30 -0
  271. package/src/templates/runNormalizers.ts +63 -0
  272. package/src/templates/sampleNormalizers.ts +58 -0
  273. package/src/templates/samplePrepAdapters.ts +63 -0
  274. package/src/templates/samplePrepBuilder.ts +51 -0
  275. package/src/templates/sampleSheetAdapters.ts +75 -0
  276. package/src/templates/sampleSheetBuilder.ts +23 -0
  277. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  278. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  279. package/src/templates/templateControlSchemas.ts +320 -0
  280. package/src/templates/templateEnvelopes.ts +137 -0
  281. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  282. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  283. package/src/templates/templateValidators.ts +414 -0
  284. package/src/templates/timeCourseAdapters.ts +73 -0
  285. package/src/templates/timeCourseBuilder.ts +64 -0
  286. package/src/templates/types.ts +17 -0
  287. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  288. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  289. package/src/types/auth.ts +3 -0
  290. package/src/types/components.ts +45 -3
  291. package/src/types/form-builder.ts +2 -1
  292. package/src/types/index.ts +35 -0
  293. package/src/types/instrument.ts +61 -0
  294. package/src/types/platform.ts +4 -0
  295. package/src/utils/rack.ts +209 -0
  296. package/dist/auth-CBG3bWEc.js.map +0 -1
  297. package/dist/components-5KSfsVqf.js.map +0 -1
  298. package/dist/composables-D4Myb30a.js.map +0 -1
  299. package/dist/templates-BSlxwV2c.js.map +0 -1
  300. package/dist/useExperimentData-BbbdI5xT.js.map +0 -1
@@ -1,845 +1,107 @@
1
+ import type { Well } from '../types'
1
2
  import type {
2
- DataFrameColumn,
3
- PlateCondition,
4
- PlateMapEditorState,
5
- ProtocolStep,
6
- ProtocolStepStatus,
7
- ProtocolStepType,
8
- ScheduleEvent,
9
- ScheduleEventStatus,
10
- SelectOption,
11
- Well,
12
- } from '../types'
13
- import {
14
- getTemplateData,
15
- validateAssayMatrixData,
16
- validateCalibrationCurveData,
17
- validateDoseResponseData,
18
- validateFlowCytometryPanelData,
19
- validateInstrumentRunData,
20
- validatePlateMapData,
21
- validateProtocolStepsData,
22
- validateQpcrPlateData,
23
- validateReagentListData,
24
- validateSamplePrepData,
25
- validateSampleSheetData,
26
- validateTimeCourseData,
27
- } from './builders'
28
- import type {
29
- AssayMatrixColumnsAdapterResult,
30
- AssayMatrixDataFrameAdapterResult,
31
- AssayMatrixRowsAdapterResult,
32
- AssayMatrixSampleOptionsAdapterResult,
33
3
  AssayMatrixTemplate,
34
- AssayMatrixTemplateData,
35
4
  BioTemplateEnvelope,
36
- CalibrationCurveColumnsAdapterResult,
37
- CalibrationCurveDataFrameAdapterResult,
38
- CalibrationCurveRowsAdapterResult,
39
5
  CalibrationCurveTemplate,
40
- CalibrationCurveTemplateData,
41
6
  DataFrameTemplate,
42
- DoseConditionsAdapterResult,
43
- DoseResponseTemplate,
44
- DoseResponseTemplateData,
45
7
  FlowCytometryPanelTemplate,
46
- FlowCytometryPanelTemplateData,
47
- FlowPanelColumnsAdapterResult,
48
- FlowPanelDataFrameAdapterResult,
49
- FlowPanelRowsAdapterResult,
50
- InstrumentRunColumnsAdapterResult,
51
- InstrumentRunDataFrameAdapterResult,
52
- InstrumentRunRowsAdapterResult,
53
- InstrumentRunScheduleEventsAdapterResult,
54
- InstrumentRunStepsAdapterResult,
55
8
  InstrumentRunTemplate,
56
- InstrumentRunTemplateData,
57
- InstrumentRunItem,
58
- InstrumentRunItemKind,
59
- InstrumentRunStatus,
60
- PlateMapEditorAdapterResult,
61
- PlateMapTemplate,
62
- PlateMapTemplateData,
63
- ProtocolColumnsAdapterResult,
64
- ProtocolDataFrameAdapterResult,
65
- ProtocolRowsAdapterResult,
66
- ProtocolStepsAdapterResult,
67
9
  ProtocolStepsTemplate,
68
- ProtocolStepsTemplateData,
69
- QpcrColumnsAdapterResult,
70
- QpcrDataFrameAdapterResult,
71
10
  QpcrPlateTemplate,
72
- QpcrPlateTemplateData,
73
- QpcrRowsAdapterResult,
74
- QpcrWellMapAdapterResult,
75
- ReagentColumnsAdapterResult,
76
- ReagentDataFrameAdapterResult,
77
- ReagentListItemsAdapterResult,
78
11
  ReagentListTemplate,
79
- ReagentListTemplateData,
80
- ReagentRowsAdapterResult,
81
- SampleColumnsAdapterResult,
82
- SampleDataFrameAdapterResult,
83
- SampleOptionsAdapterResult,
84
- SamplePrepColumnsAdapterResult,
85
- SamplePrepDataFrameAdapterResult,
86
- SamplePrepRowsAdapterResult,
87
12
  SamplePrepTemplate,
88
- SamplePrepTemplateData,
89
- SampleRowsAdapterResult,
90
13
  SampleSheetTemplate,
91
- SampleSheetTemplateData,
92
- TimeCourseColumnsAdapterResult,
93
- TimeCourseDataFrameAdapterResult,
94
- TimeCourseRowsAdapterResult,
95
- TimeCourseStepsAdapterResult,
96
14
  TimeCourseTemplate,
97
- TimeCourseTemplateData,
98
15
  TemplateDataFrameAdapterResult,
99
- WellMapAdapterResult,
100
16
  } from './types'
101
-
102
- const CONDITION_COLORS = [
103
- '#3B82F6',
104
- '#10B981',
105
- '#EF4444',
106
- '#F59E0B',
107
- '#8B5CF6',
108
- '#F97316',
109
- '#06B6D4',
110
- '#14B8A6',
111
- '#6B7280',
112
- ]
113
-
114
- export function toPlateMapEditorState(
115
- template: PlateMapTemplate | PlateMapTemplateData
116
- ): PlateMapEditorAdapterResult {
117
- const data = getTemplateData(template, 'plate-map')
118
- validatePlateMapData(data)
119
- const activePlateId = data.activePlateId ?? data.plates[0].id
120
- return {
121
- plates: data.plates,
122
- activePlateId,
123
- samples: data.samples,
124
- selectedWells: data.selectedWells ?? [],
125
- activeSampleId: data.activeSampleId,
126
- } satisfies PlateMapEditorState
127
- }
128
-
129
- export function toWellPlateWells(
130
- template: PlateMapTemplate | PlateMapTemplateData,
131
- plateId?: string
132
- ): WellMapAdapterResult {
133
- const state = toPlateMapEditorState(template)
134
- const plate = state.plates.find(candidate => candidate.id === (plateId ?? state.activePlateId))
135
- ?? state.plates[0]
136
- return plate.wells
137
- }
138
-
139
- export function toSampleRows(
140
- template: SampleSheetTemplate | SampleSheetTemplateData
141
- ): SampleRowsAdapterResult {
142
- const data = getTemplateData(template, 'sample-sheet')
143
- validateSampleSheetData(data)
144
- return data.samples.map(sample => ({
145
- sampleId: sample.sampleId,
146
- name: sample.name,
147
- group: sample.group,
148
- batch: sample.batch,
149
- replicate: sample.replicate,
150
- plateId: sample.plateId,
151
- wellId: sample.wellId,
152
- ...(sample.metadata ?? {}),
153
- }))
154
- }
155
-
156
- export function toSampleColumns(
157
- template: SampleSheetTemplate | SampleSheetTemplateData
158
- ): SampleColumnsAdapterResult {
159
- const data = getTemplateData(template, 'sample-sheet')
160
- validateSampleSheetData(data)
161
- return data.columns.map((column): DataFrameColumn<Record<string, unknown>> => ({
162
- key: sampleColumnKey(column.id),
163
- label: column.label,
164
- sortable: true,
165
- align: column.type === 'number' || column.type === 'integer' ? 'right' : 'left',
166
- }))
167
- }
168
-
169
- export function toSampleDataFrame(
170
- template: SampleSheetTemplate | SampleSheetTemplateData
171
- ): SampleDataFrameAdapterResult {
172
- return {
173
- data: toSampleRows(template),
174
- columns: toSampleColumns(template),
175
- rowKey: 'sampleId',
176
- }
177
- }
178
-
179
- export function toSampleOptions(
180
- template: SampleSheetTemplate | SampleSheetTemplateData
181
- ): SampleOptionsAdapterResult {
182
- const data = getTemplateData(template, 'sample-sheet')
183
- validateSampleSheetData(data)
184
- return data.samples.map((sample): SelectOption<string> => ({
185
- value: sample.sampleId,
186
- label: sample.name ?? sample.sampleId,
187
- description: [sample.group, sample.batch].filter(Boolean).join(' / ') || undefined,
188
- }))
189
- }
190
-
191
- export function toSamplePrepRows(
192
- template: SamplePrepTemplate | SamplePrepTemplateData
193
- ): SamplePrepRowsAdapterResult {
194
- const data = getTemplateData(template, 'sample-prep')
195
- validateSamplePrepData(data)
196
- return [...data.steps]
197
- .sort((a, b) => a.order - b.order)
198
- .map(step => ({
199
- id: step.id,
200
- order: step.order,
201
- type: step.type,
202
- name: step.name,
203
- sourceSampleId: step.sourceSampleId,
204
- sourceWellId: step.sourceWellId,
205
- destinationSampleId: step.destinationSampleId,
206
- destinationWellId: step.destinationWellId,
207
- reagentId: step.reagentId,
208
- inputVolume: step.inputVolume,
209
- outputVolume: step.outputVolume,
210
- volumeUnit: step.volumeUnit,
211
- durationMin: step.durationMin,
212
- status: step.status,
213
- protocolName: data.protocolName,
214
- ...(step.metadata ?? {}),
215
- }))
216
- }
217
-
218
- export function toSamplePrepColumns(): SamplePrepColumnsAdapterResult {
219
- return [
220
- { key: 'order', label: 'Order', sortable: true, align: 'right' },
221
- { key: 'type', label: 'Type', sortable: true },
222
- { key: 'name', label: 'Step', sortable: true },
223
- { key: 'sourceSampleId', label: 'Source', sortable: true },
224
- { key: 'sourceWellId', label: 'Source well', sortable: true },
225
- { key: 'destinationSampleId', label: 'Destination', sortable: true },
226
- { key: 'destinationWellId', label: 'Destination well', sortable: true },
227
- { key: 'reagentId', label: 'Reagent', sortable: true },
228
- { key: 'inputVolume', label: 'Input', sortable: true, align: 'right' },
229
- { key: 'outputVolume', label: 'Output', sortable: true, align: 'right' },
230
- { key: 'volumeUnit', label: 'Unit', sortable: true },
231
- { key: 'status', label: 'Status', sortable: true },
232
- ]
233
- }
234
-
235
- export function toSamplePrepDataFrame(
236
- template: SamplePrepTemplate | SamplePrepTemplateData
237
- ): SamplePrepDataFrameAdapterResult {
238
- return {
239
- data: toSamplePrepRows(template),
240
- columns: toSamplePrepColumns(),
241
- rowKey: 'id',
242
- }
243
- }
244
-
245
- export function toDoseConditions(
246
- template: DoseResponseTemplate | DoseResponseTemplateData
247
- ): DoseConditionsAdapterResult {
248
- const data = getTemplateData(template, 'dose-response')
249
- validateDoseResponseData(data)
250
- return data.compounds.map((compound, index): PlateCondition => ({
251
- label: compound.name,
252
- color: String(compound.metadata?.color ?? CONDITION_COLORS[index % CONDITION_COLORS.length]),
253
- concentrations: compound.concentrations,
254
- unit: data.unit,
255
- }))
256
- }
257
-
258
- export function toDoseLayoutState(
259
- template: DoseResponseTemplate | DoseResponseTemplateData
260
- ): PlateMapEditorState | undefined {
261
- const data = getTemplateData(template, 'dose-response')
262
- validateDoseResponseData(data)
263
- return data.layout ? toPlateMapEditorState(data.layout) : undefined
264
- }
265
-
266
- export function toCalibrationCurveRows(
267
- template: CalibrationCurveTemplate | CalibrationCurveTemplateData
268
- ): CalibrationCurveRowsAdapterResult {
269
- const data = getTemplateData(template, 'calibration-curve')
270
- validateCalibrationCurveData(data)
271
- return [...data.points]
272
- .sort((a, b) => a.order - b.order)
273
- .map(point => ({
274
- id: point.id,
275
- order: point.order,
276
- role: point.role,
277
- level: point.level,
278
- concentration: point.concentration,
279
- unit: point.unit,
280
- expectedResponse: point.expectedResponse,
281
- response: point.response,
282
- replicate: point.replicate,
283
- include: point.include,
284
- status: point.status,
285
- analyte: data.analyte,
286
- model: data.model,
287
- ...(point.metadata ?? {}),
288
- }))
289
- }
290
-
291
- export function toCalibrationCurveColumns(): CalibrationCurveColumnsAdapterResult {
292
- return [
293
- { key: 'order', label: 'Order', sortable: true, align: 'right' },
294
- { key: 'role', label: 'Role', sortable: true },
295
- { key: 'level', label: 'Level', sortable: true },
296
- { key: 'concentration', label: 'Concentration', sortable: true, align: 'right' },
297
- { key: 'unit', label: 'Unit', sortable: true },
298
- { key: 'expectedResponse', label: 'Expected', sortable: true, align: 'right' },
299
- { key: 'response', label: 'Response', sortable: true, align: 'right' },
300
- { key: 'replicate', label: 'Replicate', sortable: true, align: 'right' },
301
- { key: 'include', label: 'Include', sortable: true },
302
- { key: 'status', label: 'Status', sortable: true },
303
- ]
304
- }
305
-
306
- export function toCalibrationCurveDataFrame(
307
- template: CalibrationCurveTemplate | CalibrationCurveTemplateData
308
- ): CalibrationCurveDataFrameAdapterResult {
309
- return {
310
- data: toCalibrationCurveRows(template),
311
- columns: toCalibrationCurveColumns(),
312
- rowKey: 'id',
313
- }
314
- }
315
-
316
- export function toTimeCourseRows(
317
- template: TimeCourseTemplate | TimeCourseTemplateData
318
- ): TimeCourseRowsAdapterResult {
319
- const data = getTemplateData(template, 'time-course')
320
- validateTimeCourseData(data)
321
- const timepoints = new Map(data.timepoints.map(timepoint => [timepoint.id, timepoint]))
322
- const conditions = new Map(data.conditions.map(condition => [condition.id, condition]))
323
-
324
- return data.samples.map(sample => {
325
- const timepoint = timepoints.get(sample.timepointId)
326
- const condition = conditions.get(sample.conditionId)
327
- return {
328
- sampleId: sample.sampleId,
329
- condition: condition?.name ?? sample.conditionId,
330
- timepoint: timepoint?.label ?? sample.timepointId,
331
- value: timepoint?.value,
332
- unit: timepoint?.unit,
333
- replicate: sample.replicate,
334
- ...(sample.metadata ?? {}),
335
- }
336
- })
337
- }
338
-
339
- export function toTimeCourseColumns(): TimeCourseColumnsAdapterResult {
340
- return [
341
- { key: 'sampleId', label: 'Sample ID', sortable: true },
342
- { key: 'condition', label: 'Condition', sortable: true },
343
- { key: 'timepoint', label: 'Time Point', sortable: true },
344
- { key: 'value', label: 'Value', sortable: true, align: 'right' },
345
- { key: 'unit', label: 'Unit', sortable: true },
346
- { key: 'replicate', label: 'Replicate', sortable: true, align: 'right' },
347
- ]
348
- }
349
-
350
- export function toTimeCourseDataFrame(
351
- template: TimeCourseTemplate | TimeCourseTemplateData
352
- ): TimeCourseDataFrameAdapterResult {
353
- return {
354
- data: toTimeCourseRows(template),
355
- columns: toTimeCourseColumns(),
356
- rowKey: 'sampleId',
357
- }
358
- }
359
-
360
- export function toTimeCourseSteps(
361
- template: TimeCourseTemplate | TimeCourseTemplateData
362
- ): TimeCourseStepsAdapterResult {
363
- const data = getTemplateData(template, 'time-course')
364
- validateTimeCourseData(data)
365
- return data.timepoints.map((timepoint, index) => ({
366
- id: timepoint.id,
367
- type: 'measurement',
368
- name: timepoint.label,
369
- description: `${data.conditions.length} condition${data.conditions.length === 1 ? '' : 's'}`,
370
- status: 'pending',
371
- order: index,
372
- parameters: {
373
- value: timepoint.value,
374
- unit: timepoint.unit,
375
- },
376
- }))
377
- }
378
-
379
- export function toProtocolSteps(
380
- template: ProtocolStepsTemplate | ProtocolStepsTemplateData
381
- ): ProtocolStepsAdapterResult {
382
- const data = getTemplateData(template, 'protocol-steps')
383
- validateProtocolStepsData(data)
384
- return [...data.steps]
385
- .sort((a, b) => a.order - b.order)
386
- .map(step => ({
387
- id: step.id,
388
- type: step.type,
389
- name: step.name,
390
- description: step.description,
391
- duration: step.duration,
392
- status: step.status,
393
- parameters: step.parameters,
394
- order: step.order,
395
- }))
396
- }
397
-
398
- export function toProtocolRows(
399
- template: ProtocolStepsTemplate | ProtocolStepsTemplateData
400
- ): ProtocolRowsAdapterResult {
401
- const data = getTemplateData(template, 'protocol-steps')
402
- validateProtocolStepsData(data)
403
- return [...data.steps]
404
- .sort((a, b) => a.order - b.order)
405
- .map(step => ({
406
- id: step.id,
407
- order: step.order,
408
- type: step.type,
409
- name: step.name,
410
- description: step.description,
411
- duration: step.duration,
412
- status: step.status,
413
- ...(step.metadata ?? {}),
414
- }))
415
- }
416
-
417
- export function toProtocolColumns(): ProtocolColumnsAdapterResult {
418
- return [
419
- { key: 'order', label: 'Order', sortable: true, align: 'right' },
420
- { key: 'name', label: 'Name', sortable: true },
421
- { key: 'type', label: 'Type', sortable: true },
422
- { key: 'duration', label: 'Duration', sortable: true, align: 'right' },
423
- { key: 'status', label: 'Status', sortable: true },
424
- { key: 'description', label: 'Description', sortable: true },
425
- ]
426
- }
427
-
428
- export function toProtocolDataFrame(
429
- template: ProtocolStepsTemplate | ProtocolStepsTemplateData
430
- ): ProtocolDataFrameAdapterResult {
431
- return {
432
- data: toProtocolRows(template),
433
- columns: toProtocolColumns(),
434
- rowKey: 'id',
435
- }
436
- }
437
-
438
- export function toAssayMatrixRows(
439
- template: AssayMatrixTemplate | AssayMatrixTemplateData
440
- ): AssayMatrixRowsAdapterResult {
441
- const data = getTemplateData(template, 'assay-matrix')
442
- validateAssayMatrixData(data)
443
- const measurements = new Map(
444
- data.measurements.map(measurement => [
445
- `${measurement.sampleId}:${measurement.featureId}`,
446
- measurement.value ?? null,
447
- ])
448
- )
449
-
450
- return data.samples.map(sample => {
451
- const row: Record<string, unknown> = {
452
- sampleId: sample.sampleId,
453
- name: sample.name,
454
- group: sample.group,
455
- ...(sample.metadata ?? {}),
456
- }
457
- for (const feature of data.features) {
458
- row[feature.id] = measurements.get(`${sample.sampleId}:${feature.id}`) ?? null
459
- }
460
- return row
461
- })
462
- }
463
-
464
- export function toAssayMatrixColumns(
465
- template: AssayMatrixTemplate | AssayMatrixTemplateData
466
- ): AssayMatrixColumnsAdapterResult {
467
- const data = getTemplateData(template, 'assay-matrix')
468
- validateAssayMatrixData(data)
469
- return [
470
- { key: 'sampleId', label: 'Sample ID', sortable: true },
471
- { key: 'name', label: 'Name', sortable: true },
472
- { key: 'group', label: 'Group', sortable: true },
473
- ...data.features.map(feature => ({
474
- key: feature.id,
475
- label: feature.unit ? `${feature.name} (${feature.unit})` : feature.name,
476
- sortable: true,
477
- align: 'right' as const,
478
- })),
479
- ]
480
- }
481
-
482
- export function toAssayMatrixDataFrame(
483
- template: AssayMatrixTemplate | AssayMatrixTemplateData
484
- ): AssayMatrixDataFrameAdapterResult {
485
- return {
486
- data: toAssayMatrixRows(template),
487
- columns: toAssayMatrixColumns(template),
488
- rowKey: 'sampleId',
489
- }
490
- }
491
-
492
- /** Convert an assay-matrix template into SampleSelector options derived from assay samples. */
493
- export function toAssayMatrixSampleOptions(
494
- template: AssayMatrixTemplate | AssayMatrixTemplateData
495
- ): AssayMatrixSampleOptionsAdapterResult {
496
- const data = getTemplateData(template, 'assay-matrix')
497
- validateAssayMatrixData(data)
498
- return data.samples.map((sample): SelectOption<string> => ({
499
- value: sample.sampleId,
500
- label: sample.name ?? sample.sampleId,
501
- description: sample.group,
502
- }))
503
- }
504
-
505
- export function toReagentListItems(
506
- template: ReagentListTemplate | ReagentListTemplateData
507
- ): ReagentListItemsAdapterResult {
508
- const data = getTemplateData(template, 'reagent-list')
509
- validateReagentListData(data)
510
- return data.reagents.map(reagent => ({
511
- id: reagent.id,
512
- name: reagent.name,
513
- catalogNumber: reagent.catalogNumber,
514
- lotNumber: reagent.lotNumber,
515
- expiryDate: reagent.expiryDate,
516
- storageCondition: reagent.storageCondition,
517
- location: reagent.location,
518
- stockLevel: reagent.stockLevel,
519
- stockUnit: reagent.stockUnit,
520
- supplier: reagent.supplier,
521
- url: reagent.url,
522
- }))
523
- }
524
-
525
- export function toReagentRows(
526
- template: ReagentListTemplate | ReagentListTemplateData
527
- ): ReagentRowsAdapterResult {
528
- const data = getTemplateData(template, 'reagent-list')
529
- validateReagentListData(data)
530
- return data.reagents.map(reagent => ({
531
- id: reagent.id,
532
- name: reagent.name,
533
- kind: reagent.kind,
534
- catalogNumber: reagent.catalogNumber,
535
- lotNumber: reagent.lotNumber,
536
- expiryDate: reagent.expiryDate,
537
- storageCondition: reagent.storageCondition,
538
- location: reagent.location,
539
- stockLevel: reagent.stockLevel,
540
- stockUnit: reagent.stockUnit,
541
- supplier: reagent.supplier,
542
- concentration: reagent.concentration,
543
- ...(reagent.metadata ?? {}),
544
- }))
545
- }
546
-
547
- export function toReagentColumns(): ReagentColumnsAdapterResult {
548
- return [
549
- { key: 'name', label: 'Name', sortable: true },
550
- { key: 'kind', label: 'Kind', sortable: true },
551
- { key: 'catalogNumber', label: 'Catalog', sortable: true },
552
- { key: 'lotNumber', label: 'Lot', sortable: true },
553
- { key: 'expiryDate', label: 'Expiry', sortable: true },
554
- { key: 'storageCondition', label: 'Storage', sortable: true },
555
- { key: 'location', label: 'Location', sortable: true },
556
- { key: 'stockLevel', label: 'Stock', sortable: true, align: 'right' },
557
- { key: 'stockUnit', label: 'Unit', sortable: true },
558
- { key: 'supplier', label: 'Supplier', sortable: true },
559
- ]
560
- }
561
-
562
- export function toReagentDataFrame(
563
- template: ReagentListTemplate | ReagentListTemplateData
564
- ): ReagentDataFrameAdapterResult {
565
- return {
566
- data: toReagentRows(template),
567
- columns: toReagentColumns(),
568
- rowKey: 'id',
569
- }
570
- }
571
-
572
- export function toFlowPanelRows(
573
- template: FlowCytometryPanelTemplate | FlowCytometryPanelTemplateData
574
- ): FlowPanelRowsAdapterResult {
575
- const data = getTemplateData(template, 'flow-cytometry-panel')
576
- validateFlowCytometryPanelData(data)
577
- return data.markers.map(marker => {
578
- const markerControls = data.controls
579
- .filter(control => control.markerId === marker.id)
580
- .map(control => control.name)
581
- .join(', ')
582
- return {
583
- id: marker.id,
584
- marker: marker.marker,
585
- fluorophore: marker.fluorophore,
586
- detector: marker.detector,
587
- clone: marker.clone,
588
- reagentId: marker.reagentId,
589
- purpose: marker.purpose,
590
- compensationRequired: marker.compensationRequired,
591
- controls: markerControls,
592
- instrument: data.instrument,
593
- ...(marker.metadata ?? {}),
594
- }
595
- })
596
- }
597
-
598
- export function toFlowPanelColumns(): FlowPanelColumnsAdapterResult {
599
- return [
600
- { key: 'marker', label: 'Marker', sortable: true },
601
- { key: 'fluorophore', label: 'Fluorophore', sortable: true },
602
- { key: 'detector', label: 'Detector', sortable: true },
603
- { key: 'clone', label: 'Clone', sortable: true },
604
- { key: 'purpose', label: 'Purpose', sortable: true },
605
- { key: 'compensationRequired', label: 'Compensation', sortable: true },
606
- { key: 'controls', label: 'Controls' },
607
- { key: 'instrument', label: 'Instrument', sortable: true },
608
- ]
609
- }
610
-
611
- export function toFlowPanelDataFrame(
612
- template: FlowCytometryPanelTemplate | FlowCytometryPanelTemplateData
613
- ): FlowPanelDataFrameAdapterResult {
614
- return {
615
- data: toFlowPanelRows(template),
616
- columns: toFlowPanelColumns(),
617
- rowKey: 'id',
618
- }
619
- }
620
-
621
- export function toInstrumentRunRows(
622
- template: InstrumentRunTemplate | InstrumentRunTemplateData
623
- ): InstrumentRunRowsAdapterResult {
624
- const data = getTemplateData(template, 'instrument-run')
625
- validateInstrumentRunData(data)
626
- const methods = new Map(data.methods.map(method => [method.id, method]))
627
- return [...data.items]
628
- .sort((a, b) => a.order - b.order)
629
- .map(item => {
630
- const method = methods.get(item.methodId)
631
- return {
632
- id: item.id,
633
- order: item.order,
634
- kind: item.kind,
635
- sampleId: item.sampleId,
636
- name: item.name ?? item.sampleId ?? item.kind,
637
- method: method?.name ?? item.methodId,
638
- vial: item.vial,
639
- plateId: item.plateId,
640
- wellId: item.wellId,
641
- injectionVolume: item.injectionVolume,
642
- expectedDurationMin: item.expectedDurationMin,
643
- status: item.status,
644
- instrument: data.instrument ?? method?.instrument,
645
- ...(item.metadata ?? {}),
646
- }
647
- })
648
- }
649
-
650
- export function toInstrumentRunColumns(): InstrumentRunColumnsAdapterResult {
651
- return [
652
- { key: 'order', label: 'Order', sortable: true, align: 'right' },
653
- { key: 'kind', label: 'Kind', sortable: true },
654
- { key: 'sampleId', label: 'Sample ID', sortable: true },
655
- { key: 'name', label: 'Name', sortable: true },
656
- { key: 'method', label: 'Method', sortable: true },
657
- { key: 'vial', label: 'Vial', sortable: true },
658
- { key: 'wellId', label: 'Well', sortable: true },
659
- { key: 'injectionVolume', label: 'Injection', sortable: true, align: 'right' },
660
- { key: 'expectedDurationMin', label: 'Duration', sortable: true, align: 'right' },
661
- { key: 'status', label: 'Status', sortable: true },
662
- { key: 'instrument', label: 'Instrument', sortable: true },
663
- ]
664
- }
665
-
666
- export function toInstrumentRunDataFrame(
667
- template: InstrumentRunTemplate | InstrumentRunTemplateData
668
- ): InstrumentRunDataFrameAdapterResult {
669
- return {
670
- data: toInstrumentRunRows(template),
671
- columns: toInstrumentRunColumns(),
672
- rowKey: 'id',
673
- }
674
- }
675
-
676
- /** Convert an instrument-run template into ExperimentTimeline protocol steps for acquisition queue previews. */
677
- export function toInstrumentRunSteps(
678
- template: InstrumentRunTemplate | InstrumentRunTemplateData
679
- ): InstrumentRunStepsAdapterResult {
680
- const data = getTemplateData(template, 'instrument-run')
681
- validateInstrumentRunData(data)
682
- const methods = new Map(data.methods.map(method => [method.id, method]))
683
- return [...data.items]
684
- .sort((a, b) => a.order - b.order)
685
- .map((item): ProtocolStep => {
686
- const method = methods.get(item.methodId)
687
- const name = item.name ?? item.sampleId ?? item.kind
688
- return {
689
- id: item.id,
690
- type: instrumentRunStepType(item.kind),
691
- name,
692
- description: [
693
- item.kind,
694
- method?.name,
695
- item.vial ? `Vial ${item.vial}` : undefined,
696
- item.wellId ? `Well ${item.wellId}` : undefined,
697
- ]
698
- .filter(Boolean)
699
- .join(' / '),
700
- duration: item.expectedDurationMin,
701
- status: instrumentRunStepStatus(item.status),
702
- parameters: {
703
- kind: item.kind,
704
- sampleId: item.sampleId,
705
- methodId: item.methodId,
706
- method: method?.name,
707
- vial: item.vial,
708
- plateId: item.plateId,
709
- wellId: item.wellId,
710
- injectionVolume: item.injectionVolume,
711
- instrument: data.instrument ?? method?.instrument,
712
- },
713
- order: item.order,
714
- }
715
- })
716
- }
717
-
718
- /** Convert an instrument-run template into readonly ScheduleCalendar events ordered by run queue timing. */
719
- export function toInstrumentRunScheduleEvents(
720
- template: InstrumentRunTemplate | InstrumentRunTemplateData
721
- ): InstrumentRunScheduleEventsAdapterResult {
722
- const data = getTemplateData(template, 'instrument-run')
723
- validateInstrumentRunData(data)
724
- const methods = new Map(data.methods.map(method => [method.id, method]))
725
- let cursor = dateFromMetadata(data.metadata, ['scheduledStart', 'runStart', 'start', 'startedAt'])
726
- ?? new Date('2024-01-01T08:00:00.000Z')
727
-
728
- return [...data.items]
729
- .sort((a, b) => a.order - b.order)
730
- .map((item): ScheduleEvent => {
731
- const method = methods.get(item.methodId)
732
- const start = dateFromMetadata(item.metadata, ['scheduledStart', 'start', 'startedAt']) ?? cursor
733
- const end = dateFromMetadata(item.metadata, ['scheduledEnd', 'end', 'completedAt'])
734
- ?? addMinutes(start, Math.max(item.expectedDurationMin ?? 10, 1))
735
- cursor = end
736
-
737
- return {
738
- id: item.id,
739
- title: item.name ?? item.sampleId ?? item.kind,
740
- start: start.toISOString(),
741
- end: end.toISOString(),
742
- color: instrumentRunScheduleColor(item.kind),
743
- status: instrumentRunScheduleStatus(item.status),
744
- draggable: false,
745
- resizable: false,
746
- metadata: {
747
- kind: item.kind,
748
- sampleId: item.sampleId,
749
- methodId: item.methodId,
750
- method: method?.name,
751
- vial: item.vial,
752
- plateId: item.plateId,
753
- wellId: item.wellId,
754
- injectionVolume: item.injectionVolume,
755
- instrument: data.instrument ?? method?.instrument,
756
- },
757
- }
758
- })
759
- }
760
-
761
- export function toQpcrRows(
762
- template: QpcrPlateTemplate | QpcrPlateTemplateData
763
- ): QpcrRowsAdapterResult {
764
- const data = getTemplateData(template, 'qpcr-plate')
765
- validateQpcrPlateData(data)
766
- const samples = new Map(data.samples.map(sample => [sample.sampleId, sample]))
767
- const targets = new Map(data.targets.map(target => [target.id, target]))
768
-
769
- return data.reactions.map(reaction => {
770
- const sample = reaction.sampleId ? samples.get(reaction.sampleId) : undefined
771
- const target = targets.get(reaction.targetId)
772
- return {
773
- id: reaction.id,
774
- wellId: reaction.wellId,
775
- sampleId: reaction.sampleId,
776
- sample: sample?.name ?? reaction.sampleId ?? reaction.controlKind,
777
- group: sample?.group,
778
- targetId: reaction.targetId,
779
- target: target?.name ?? reaction.targetId,
780
- replicate: reaction.replicate,
781
- controlKind: reaction.controlKind,
782
- cq: reaction.cq ?? null,
783
- quantity: reaction.quantity ?? null,
784
- flags: reaction.flags.join(', '),
785
- instrument: data.instrument,
786
- chemistry: data.chemistry,
787
- ...(reaction.metadata ?? {}),
788
- }
789
- })
790
- }
791
-
792
- export function toQpcrColumns(): QpcrColumnsAdapterResult {
793
- return [
794
- { key: 'wellId', label: 'Well', sortable: true },
795
- { key: 'sample', label: 'Sample', sortable: true },
796
- { key: 'group', label: 'Group', sortable: true },
797
- { key: 'target', label: 'Target', sortable: true },
798
- { key: 'replicate', label: 'Replicate', sortable: true, align: 'right' },
799
- { key: 'controlKind', label: 'Control', sortable: true },
800
- { key: 'cq', label: 'Cq', sortable: true, align: 'right' },
801
- { key: 'quantity', label: 'Quantity', sortable: true, align: 'right' },
802
- { key: 'flags', label: 'Flags' },
803
- ]
804
- }
805
-
806
- export function toQpcrDataFrame(
807
- template: QpcrPlateTemplate | QpcrPlateTemplateData
808
- ): QpcrDataFrameAdapterResult {
809
- return {
810
- data: toQpcrRows(template),
811
- columns: toQpcrColumns(),
812
- rowKey: 'id',
813
- }
814
- }
815
-
816
- export function toQpcrWellPlateWells(
817
- template: QpcrPlateTemplate | QpcrPlateTemplateData
818
- ): QpcrWellMapAdapterResult {
819
- const data = getTemplateData(template, 'qpcr-plate')
820
- validateQpcrPlateData(data)
821
- return Object.fromEntries(data.reactions.map(reaction => {
822
- const [row, col] = wellPositionFromId(reaction.wellId)
823
- return [
824
- reaction.wellId,
825
- {
826
- id: reaction.wellId,
827
- row,
828
- col,
829
- state: 'filled' as const,
830
- sampleType: reaction.sampleId ?? reaction.controlKind,
831
- value: reaction.cq ?? undefined,
832
- metadata: {
833
- reactionId: reaction.id,
834
- sampleId: reaction.sampleId,
835
- targetId: reaction.targetId,
836
- replicate: reaction.replicate,
837
- controlKind: reaction.controlKind,
838
- },
839
- } satisfies Well,
840
- ]
841
- }))
842
- }
17
+ import { toAssayMatrixDataFrame } from './assayMatrixAdapters'
18
+ import { toCalibrationCurveDataFrame } from './calibrationCurveAdapters'
19
+ import { toFlowPanelDataFrame } from './flowPanelAdapters'
20
+ import { toInstrumentRunDataFrame } from './instrumentRunAdapters'
21
+ import { toProtocolDataFrame } from './protocolAdapters'
22
+ import { toQpcrDataFrame } from './qpcrAdapters'
23
+ import { toReagentDataFrame } from './reagentAdapters'
24
+ import { toSamplePrepDataFrame } from './samplePrepAdapters'
25
+ import { toSampleDataFrame } from './sampleSheetAdapters'
26
+ import { toTimeCourseDataFrame } from './timeCourseAdapters'
27
+
28
+ export {
29
+ toAssayMatrixColumns,
30
+ toAssayMatrixDataFrame,
31
+ toAssayMatrixRows,
32
+ toAssayMatrixSampleOptions,
33
+ } from './assayMatrixAdapters'
34
+
35
+ export {
36
+ toCalibrationCurveColumns,
37
+ toCalibrationCurveDataFrame,
38
+ toCalibrationCurveRows,
39
+ } from './calibrationCurveAdapters'
40
+
41
+ export {
42
+ toDoseConditions,
43
+ toDoseLayoutState,
44
+ } from './doseResponseAdapters'
45
+
46
+ export {
47
+ toFlowPanelColumns,
48
+ toFlowPanelDataFrame,
49
+ toFlowPanelRows,
50
+ } from './flowPanelAdapters'
51
+
52
+ export {
53
+ toInstrumentRunColumns,
54
+ toInstrumentRunDataFrame,
55
+ toInstrumentRunRows,
56
+ toInstrumentRunScheduleEvents,
57
+ toInstrumentRunSteps,
58
+ } from './instrumentRunAdapters'
59
+
60
+ export {
61
+ toPlateMapEditorState,
62
+ toWellPlateWells,
63
+ } from './plateMapAdapters'
64
+
65
+ export {
66
+ toProtocolColumns,
67
+ toProtocolDataFrame,
68
+ toProtocolRows,
69
+ toProtocolSteps,
70
+ } from './protocolAdapters'
71
+
72
+ export {
73
+ toQpcrColumns,
74
+ toQpcrDataFrame,
75
+ toQpcrRows,
76
+ toQpcrWellPlateWells,
77
+ } from './qpcrAdapters'
78
+
79
+ export {
80
+ toReagentColumns,
81
+ toReagentDataFrame,
82
+ toReagentListItems,
83
+ toReagentRows,
84
+ } from './reagentAdapters'
85
+
86
+ export {
87
+ toSamplePrepColumns,
88
+ toSamplePrepDataFrame,
89
+ toSamplePrepRows,
90
+ } from './samplePrepAdapters'
91
+
92
+ export {
93
+ toSampleColumns,
94
+ toSampleDataFrame,
95
+ toSampleOptions,
96
+ toSampleRows,
97
+ } from './sampleSheetAdapters'
98
+
99
+ export {
100
+ toTimeCourseColumns,
101
+ toTimeCourseDataFrame,
102
+ toTimeCourseRows,
103
+ toTimeCourseSteps,
104
+ } from './timeCourseAdapters'
843
105
 
844
106
  export function toTemplateDataFrame(
845
107
  template: DataFrameTemplate | BioTemplateEnvelope<unknown>
@@ -873,106 +135,3 @@ export function toTemplateDataFrame(
873
135
  export function toWellMapArray(wells: Record<string, Well>): Well[] {
874
136
  return Object.values(wells)
875
137
  }
876
-
877
- function wellPositionFromId(wellId: string): [number, number] {
878
- const match = /^([A-Z]+)([1-9][0-9]*)$/.exec(wellId.toUpperCase())
879
- if (!match) {
880
- throw new Error(`Invalid well id '${wellId}'.`)
881
- }
882
- const row = [...match[1]].reduce((value, char) => value * 26 + char.charCodeAt(0) - 64, 0) - 1
883
- const col = Number(match[2]) - 1
884
- return [row, col]
885
- }
886
-
887
- function sampleColumnKey(columnId: string): string {
888
- const aliases: Record<string, string> = {
889
- sample_id: 'sampleId',
890
- plate_id: 'plateId',
891
- well_id: 'wellId',
892
- }
893
- return aliases[columnId] ?? columnId
894
- }
895
-
896
- function instrumentRunStepType(kind: InstrumentRunItemKind): ProtocolStepType {
897
- switch (kind) {
898
- case 'wash':
899
- return 'wash'
900
- case 'blank':
901
- case 'qc':
902
- case 'standard':
903
- case 'calibration':
904
- case 'sample':
905
- return 'measurement'
906
- default:
907
- return 'custom'
908
- }
909
- }
910
-
911
- function instrumentRunStepStatus(status: InstrumentRunStatus): ProtocolStepStatus {
912
- switch (status) {
913
- case 'running':
914
- return 'in_progress'
915
- case 'completed':
916
- return 'completed'
917
- case 'failed':
918
- return 'failed'
919
- case 'skipped':
920
- return 'skipped'
921
- case 'planned':
922
- case 'queued':
923
- default:
924
- return 'pending'
925
- }
926
- }
927
-
928
- function instrumentRunScheduleStatus(status: InstrumentRunStatus): ScheduleEventStatus {
929
- switch (status) {
930
- case 'running':
931
- return 'in-progress'
932
- case 'completed':
933
- return 'confirmed'
934
- case 'failed':
935
- case 'skipped':
936
- return 'cancelled'
937
- case 'planned':
938
- case 'queued':
939
- default:
940
- return 'pending'
941
- }
942
- }
943
-
944
- function instrumentRunScheduleColor(kind: InstrumentRunItem['kind']): string {
945
- switch (kind) {
946
- case 'blank':
947
- return '#64748b'
948
- case 'qc':
949
- return '#8b5cf6'
950
- case 'standard':
951
- case 'calibration':
952
- return '#f59e0b'
953
- case 'wash':
954
- return '#06b6d4'
955
- case 'sample':
956
- return '#2563eb'
957
- default:
958
- return '#475569'
959
- }
960
- }
961
-
962
- function dateFromMetadata(
963
- metadata: Record<string, unknown> | undefined,
964
- keys: readonly string[]
965
- ): Date | undefined {
966
- if (!metadata) return undefined
967
- for (const key of keys) {
968
- const value = metadata[key]
969
- if (!(typeof value === 'string' || value instanceof Date)) continue
970
- const date = new Date(value)
971
- if (!Number.isNaN(date.getTime())) return date
972
- }
973
- return undefined
974
- }
975
-
976
- function addMinutes(date: Date, minutes: number): Date {
977
- return new Date(date.getTime() + minutes * 60_000)
978
- }