@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
@@ -20,6 +20,7 @@ import {
20
20
  createReagentListTemplate,
21
21
  createSampleSheetTemplate,
22
22
  createSamplePrepTemplate,
23
+ createTargetedMetabolomicsCollection,
23
24
  createDefaultBioTemplate,
24
25
  createTemplateCollection,
25
26
  createTimeCourseTemplate,
@@ -209,6 +210,7 @@ describe('bio data templates', () => {
209
210
  'wellplate-screen',
210
211
  'qpcr-expression',
211
212
  'lcms-batch',
213
+ 'targeted-metabolomics',
212
214
  'elisa-assay',
213
215
  'flow-cytometry-assay',
214
216
  'western-blot-assay',
@@ -224,6 +226,8 @@ describe('bio data templates', () => {
224
226
  expect(getBioTemplatePresetInfo('metabolomics')?.name).toBe('lcms-batch')
225
227
  expect(getBioTemplatePresetInfo('metabolism')?.name).toBe('lcms-batch')
226
228
  expect(getBioTemplatePresetInfo('metabolite profiling')?.name).toBe('lcms-batch')
229
+ expect(getBioTemplatePresetInfo('targeted metabolomics')?.name).toBe('targeted-metabolomics')
230
+ expect(searchBioTemplatePresets('internal standards')[0].name).toBe('targeted-metabolomics')
227
231
  expect(getBioTemplatePresetInfo('immunoassay')?.templates).toEqual([
228
232
  'plate-map',
229
233
  'sample-sheet',
@@ -275,6 +279,7 @@ describe('bio data templates', () => {
275
279
  const plateSchema = getBioTemplateControlSchema('wellplate')
276
280
  const presetSchema = getBioTemplateControlSchema('wellplate-screen')
277
281
  const defaults = getBioTemplateControlDefaults('lcms-batch')
282
+ const targetedDefaults = getBioTemplateControlDefaults('targeted-metabolomics')
278
283
  const elisaDefaults = getBioTemplateControlDefaults('elisa-assay')
279
284
  const flowDefaults = getBioTemplateControlDefaults('flow-cytometry-assay')
280
285
  const westernDefaults = getBioTemplateControlDefaults('western-blot-assay')
@@ -284,6 +289,9 @@ describe('bio data templates', () => {
284
289
  expect(presetSchema?.replicates.default).toBe(3)
285
290
  expect(defaults.instrument).toBe('LC-MS')
286
291
  expect(defaults.featureNames).toEqual(['Glucose', 'Lactate'])
292
+ expect(targetedDefaults.metaboliteNames).toEqual(['Glucose', 'Lactate', 'Pyruvate'])
293
+ expect(targetedDefaults.internalStandards).toEqual(['Stable isotope internal standard mix'])
294
+ expect(targetedDefaults.method).toBe('Targeted metabolomics')
287
295
  expect(elisaDefaults.analyte).toBe('Analyte')
288
296
  expect(elisaDefaults.standardConcentrations).toEqual(['1000', '100', '10', '1'])
289
297
  expect(flowDefaults.markers).toEqual(['CD3', 'CD4', 'CD8'])
@@ -299,6 +307,7 @@ describe('bio data templates', () => {
299
307
  const elisaBindings = getBioTemplateComponentBindings('elisa-assay')
300
308
  const flowBindings = getBioTemplateComponentBindings('flow-cytometry-assay')
301
309
  const lcmsBindings = getBioTemplateComponentBindings('lcms-batch')
310
+ const targetedBindings = getBioTemplateComponentBindings('targeted-metabolomics')
302
311
  const westernBindings = getBioTemplateComponentBindings('western-blot-assay')
303
312
  const wellplateImports = toBioTemplateComponentImports('wellplate-screen')
304
313
 
@@ -311,6 +320,9 @@ describe('bio data templates', () => {
311
320
  expect(elisaBindings.map(binding => binding.component)).toContain('DataFrame')
312
321
  expect(lcmsBindings.map(binding => binding.component)).toContain('ScheduleCalendar')
313
322
  expect(lcmsBindings.map(binding => binding.component)).toContain('ExperimentTimeline')
323
+ expect(targetedBindings.map(binding => binding.component)).toContain('ReagentList')
324
+ expect(targetedBindings.map(binding => binding.component)).toContain('DataFrame')
325
+ expect(targetedBindings.map(binding => binding.component)).toContain('ScheduleCalendar')
314
326
  expect(flowBindings.map(binding => binding.template_id)).toEqual([
315
327
  'sample-sheet',
316
328
  'sample-sheet',
@@ -541,6 +553,13 @@ describe('bio data templates', () => {
541
553
  features: ['Glucose'],
542
554
  instrument: 'LC-MS',
543
555
  })
556
+ const targeted = createTargetedMetabolomicsCollection({
557
+ samples: ['S001', 'S002'],
558
+ metabolites: ['Glucose', 'Lactate'],
559
+ internalStandards: ['13C Glucose'],
560
+ standardConcentrations: [0.1, 1, 10],
561
+ instrument: 'Orbitrap',
562
+ })
544
563
  const flow = createFlowCytometryAssayCollection({
545
564
  samples: ['Control', 'Treatment'],
546
565
  markers: ['CD3', 'CD4'],
@@ -555,6 +574,7 @@ describe('bio data templates', () => {
555
574
  const wellplateTemplates = extractTemplateCollection(wellplate)
556
575
  const qpcrTemplates = extractTemplateCollection(qpcr)
557
576
  const lcmsTemplates = extractTemplateCollection(lcms)
577
+ const targetedTemplates = extractTemplateCollection(targeted)
558
578
  const flowTemplates = extractTemplateCollection(flow)
559
579
  const westernTemplates = extractTemplateCollection(western)
560
580
  const wellplateComponentProps = toBioTemplateComponentProps(wellplate)
@@ -572,6 +592,28 @@ describe('bio data templates', () => {
572
592
  expect(toInstrumentRunRows(lcmsTemplates['instrument-run'] as InstrumentRunTemplate)[2].sampleId).toBe('s001')
573
593
  expect(toTemplateDataFrame(lcmsTemplates['assay-matrix']).columns.map(column => column.key)).toContain('glucose')
574
594
  expect(toAssayMatrixSampleOptions(lcmsTemplates['assay-matrix'] as AssayMatrixTemplate).map(option => option.label)).toEqual(['S001', 'S002'])
595
+ expect(Object.keys(targetedTemplates)).toEqual([
596
+ 'sample-sheet',
597
+ 'sample-prep',
598
+ 'reagent-list',
599
+ 'instrument-run',
600
+ 'calibration-curve',
601
+ 'assay-matrix',
602
+ ])
603
+ expect(targeted.metadata?.preset).toBe('targeted-metabolomics')
604
+ expect(toReagentDataFrame(targetedTemplates['reagent-list'] as ReagentListTemplate).data[0].kind).toBe('compound')
605
+ expect(toTemplateDataFrame(targetedTemplates['calibration-curve']).data[0].role).toBe('blank')
606
+ expect(toInstrumentRunRows(targetedTemplates['instrument-run'] as InstrumentRunTemplate).map(row => row.kind)).toEqual([
607
+ 'blank',
608
+ 'standard',
609
+ 'standard',
610
+ 'standard',
611
+ 'qc',
612
+ 'qc',
613
+ 'sample',
614
+ 'sample',
615
+ ])
616
+ expect(toTemplateDataFrame(targetedTemplates['assay-matrix']).columns.map(column => column.key)).toContain('lactate')
575
617
  expect(Object.keys(flowTemplates)).toEqual(['sample-sheet', 'flow-cytometry-panel', 'assay-matrix'])
576
618
  expect(flow.metadata?.preset).toBe('flow-cytometry-assay')
577
619
  expect(flowTemplates['flow-cytometry-panel'].data).toMatchObject({
@@ -596,6 +638,7 @@ describe('bio data templates', () => {
596
638
  expect(Object.keys(extractTemplateCollection(aliasCollection))).toEqual(['plate-map', 'sample-sheet', 'dose-response'])
597
639
  expect(createBioTemplatePresetCollection('facs').metadata?.preset).toBe('flow-cytometry-assay')
598
640
  expect(createBioTemplatePresetCollection('immunoblot').metadata?.preset).toBe('western-blot-assay')
641
+ expect(createBioTemplatePresetCollection('targeted metabolomics').metadata?.preset).toBe('targeted-metabolomics')
599
642
  expect(() => createBioTemplatePresetCollection('unknown-preset')).toThrow("Unknown template preset 'unknown-preset'.")
600
643
  })
601
644
 
@@ -682,6 +725,49 @@ describe('bio data templates', () => {
682
725
  expect(run.data.items.map(item => item.kind)).toEqual(['blank', 'sample', 'sample'])
683
726
  expect(toTemplateDataFrame(lcmsTemplates['assay-matrix']).columns.map(column => column.key)).toContain('pyruvate')
684
727
 
728
+ const targetedOptions = bioTemplatePresetControlValuesToOptions('targeted-metabolomics', {
729
+ sampleNames: 'QC Pool, Patient A',
730
+ metaboliteNames: 'Glucose, Citrate',
731
+ internalStandards: '13C Glucose',
732
+ standardConcentrations: '0.5, 5, 50',
733
+ concentrationUnit: 'nM',
734
+ responseUnit: 'area ratio',
735
+ instrument: 'Triple quadrupole',
736
+ method: 'MRM panel',
737
+ outputVolume: '25',
738
+ includeQc: false,
739
+ })
740
+ const targetedTemplates = extractTemplateCollection(
741
+ createBioTemplatePresetCollectionFromControls('targeted-metabolomics', {
742
+ sampleNames: 'QC Pool, Patient A',
743
+ metaboliteNames: 'Glucose, Citrate',
744
+ internalStandards: '13C Glucose',
745
+ standardConcentrations: '0.5, 5, 50',
746
+ concentrationUnit: 'nM',
747
+ responseUnit: 'area ratio',
748
+ instrument: 'Triple quadrupole',
749
+ method: 'MRM panel',
750
+ outputVolume: '25',
751
+ includeQc: false,
752
+ }),
753
+ )
754
+ const targetedRun = targetedTemplates['instrument-run'] as InstrumentRunTemplate
755
+
756
+ expect(targetedOptions.metabolites).toEqual(['Glucose', 'Citrate'])
757
+ expect(targetedOptions.standardConcentrations).toEqual([0.5, 5, 50])
758
+ expect(targetedOptions.outputVolume).toBe(25)
759
+ expect(targetedRun.data.instrument).toBe('Triple quadrupole')
760
+ expect(targetedRun.data.methods[0].name).toBe('MRM panel')
761
+ expect(targetedRun.data.items.map(item => item.kind)).toEqual([
762
+ 'blank',
763
+ 'standard',
764
+ 'standard',
765
+ 'standard',
766
+ 'sample',
767
+ 'sample',
768
+ ])
769
+ expect(toTemplateDataFrame(targetedTemplates['assay-matrix']).columns.map(column => column.key)).toContain('citrate')
770
+
685
771
  const flowOptions = bioTemplatePresetControlValuesToOptions('flow-cytometry-assay', {
686
772
  sampleNames: 'Control, Treatment',
687
773
  markers: 'CD3, CD19',
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ estimateSequenceFinishDate,
4
+ estimateSequenceRemainingSeconds,
5
+ formatSequenceRemaining,
6
+ sequenceProgressPercent,
7
+ } from '../../instrument'
8
+ import type { SequenceProgress } from '../../types'
9
+
10
+ describe('instrument sequence helpers', () => {
11
+ const progress: SequenceProgress = {
12
+ current_sample: 3,
13
+ total_samples: 6,
14
+ elapsed_seconds: 180,
15
+ sample_durations: [50, 70, 60],
16
+ }
17
+
18
+ it('calculates percent and remaining time from sample durations', () => {
19
+ expect(sequenceProgressPercent(progress)).toBe(50)
20
+ expect(estimateSequenceRemainingSeconds(progress)).toBe(180)
21
+ expect(formatSequenceRemaining(progress)).toBe('~3m left')
22
+ })
23
+
24
+ it('falls back to elapsed average when sample durations are unavailable', () => {
25
+ expect(estimateSequenceRemainingSeconds({
26
+ current_sample: 2,
27
+ total_samples: 5,
28
+ elapsed_seconds: 120,
29
+ })).toBe(180)
30
+ })
31
+
32
+ it('uses explicit finish time or builds one from remaining seconds', () => {
33
+ const now = new Date('2026-05-15T12:00:00.000Z')
34
+
35
+ expect(estimateSequenceFinishDate(progress, now)?.toISOString()).toBe('2026-05-15T12:03:00.000Z')
36
+ expect(estimateSequenceFinishDate({
37
+ current_sample: 1,
38
+ total_samples: 2,
39
+ estimated_finish_time: '2026-05-15T13:00:00.000Z',
40
+ })?.toISOString()).toBe('2026-05-15T13:00:00.000Z')
41
+ })
42
+
43
+ it('clamps completed or over-complete sequences for display', () => {
44
+ expect(sequenceProgressPercent({ current_sample: 12, total_samples: 10 })).toBe(100)
45
+ expect(formatSequenceRemaining({ current_sample: 10, total_samples: 10 })).toBeNull()
46
+ })
47
+ })
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ basenameFromWindowsPath,
4
+ extractLcmsCommonPrefix,
5
+ extractLcmsSampleName,
6
+ inferLcmsPlateTypeFromWellIds,
7
+ lcmsWellIdFromPosition,
8
+ reconstructLcmsPlateCellsFromSequenceItems,
9
+ } from '../../lcms'
10
+
11
+ describe('lcms utilities', () => {
12
+ it('extracts common prefixes and sample names from Xcalibur file names', () => {
13
+ const prefix = extractLcmsCommonPrefix([
14
+ 'Batch_01_NEG_S1_001',
15
+ 'Batch_01_NEG_S2_002',
16
+ 'Batch_01_NEG_QC_003',
17
+ ])
18
+
19
+ expect(prefix).toBe('Batch_01')
20
+ expect(extractLcmsSampleName('Batch_01_NEG_S1_001', prefix)).toBe('S1')
21
+ })
22
+
23
+ it('infers plate type from well geometry', () => {
24
+ expect(lcmsWellIdFromPosition('R:A1')).toBe('A1')
25
+ expect(inferLcmsPlateTypeFromWellIds(['A1', 'F9'])).toBe('54vial')
26
+ expect(inferLcmsPlateTypeFromWellIds(['A1', 'H12'])).toBe('96well')
27
+ })
28
+
29
+ it('reconstructs plate cells from sequence items while skipping controls', () => {
30
+ const result = reconstructLcmsPlateCellsFromSequenceItems([
31
+ {
32
+ sample_type: 'Unknown',
33
+ file_name: 'Batch_NEG_S1_001',
34
+ sample_id: 'R:A1',
35
+ path: '',
36
+ instrument_method: 'C:\\Methods\\neg.meth',
37
+ position: 'R:A1',
38
+ injection_volume: 5,
39
+ },
40
+ {
41
+ sample_type: 'Unknown',
42
+ file_name: 'Batch_NEG_S2_002',
43
+ sample_id: 'R:H12',
44
+ path: '',
45
+ instrument_method: 'C:\\Methods\\neg.meth',
46
+ position: 'R:H12',
47
+ injection_volume: 5,
48
+ },
49
+ {
50
+ sample_type: 'Blank',
51
+ file_name: 'Batch_NEG_Blank_003',
52
+ sample_id: 'R:F9',
53
+ path: '',
54
+ instrument_method: 'C:\\Methods\\neg.meth',
55
+ position: 'R:F9',
56
+ injection_volume: 5,
57
+ },
58
+ ])
59
+
60
+ expect(result).toEqual({
61
+ plateType: '96well',
62
+ cells: [
63
+ { row: 'A', column: 1, sample_name: 'S1' },
64
+ { row: 'H', column: 12, sample_name: 'S2' },
65
+ ],
66
+ })
67
+ })
68
+
69
+ it('extracts basenames from Windows and POSIX paths', () => {
70
+ expect(basenameFromWindowsPath('C:\\Methods\\neg.meth')).toBe('neg.meth')
71
+ expect(basenameFromWindowsPath('/methods/pos.meth')).toBe('pos.meth')
72
+ })
73
+ })
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ canAccessAdmin,
4
+ canAccessByPolicy,
5
+ canAccessPlugin,
6
+ getAccessAudience,
7
+ hasAllPermissions,
8
+ hasAnyPermission,
9
+ isAdminUser,
10
+ } from '../../permissions'
11
+
12
+ describe('permission helpers', () => {
13
+ const member = {
14
+ role: 'member',
15
+ role_obj: {
16
+ slug: 'member',
17
+ permissions: ['experiments.view', 'plugins.configure'],
18
+ plugin_access: ['dose'],
19
+ },
20
+ }
21
+
22
+ it('treats the admin role as full access', () => {
23
+ const admin = { role: 'admin' }
24
+
25
+ expect(isAdminUser(admin)).toBe(true)
26
+ expect(getAccessAudience(admin)).toBe('admin')
27
+ expect(hasAllPermissions(admin, ['platform.configure'])).toBe(true)
28
+ expect(canAccessAdmin(admin)).toBe(true)
29
+ })
30
+
31
+ it('checks role permissions and plugin access for non-admin users', () => {
32
+ expect(isAdminUser(member)).toBe(false)
33
+ expect(getAccessAudience(member)).toBe('user')
34
+ expect(hasAllPermissions(member, ['experiments.view'])).toBe(true)
35
+ expect(hasAllPermissions(member, ['platform.configure'])).toBe(false)
36
+ expect(hasAnyPermission(member, ['platform.configure', 'plugins.configure'])).toBe(true)
37
+ expect(canAccessAdmin(member)).toBe(true)
38
+ expect(canAccessPlugin(member, 'dose')).toBe(true)
39
+ expect(canAccessPlugin(member, 'reports')).toBe(false)
40
+ })
41
+
42
+ it('evaluates access policies consistently', () => {
43
+ expect(canAccessByPolicy(member, { visibleFor: 'user' })).toBe(true)
44
+ expect(canAccessByPolicy(member, { visibleFor: 'admin' })).toBe(false)
45
+ expect(canAccessByPolicy(member, { permissions: ['experiments.view'] })).toBe(true)
46
+ expect(canAccessByPolicy(member, { anyPermissions: ['platform.configure', 'plugins.configure'] })).toBe(true)
47
+ expect(canAccessByPolicy(member, { requiresAdmin: true })).toBe(false)
48
+ expect(canAccessByPolicy(member, { plugin: 'reports' })).toBe(false)
49
+ })
50
+ })
@@ -0,0 +1,120 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ createLcmsControlWellEditData,
4
+ getLcmsDefaultControlWellId,
5
+ lcmsPlateCellsToRacks,
6
+ rackToLcmsPlateCells,
7
+ } from '../../utils/rack'
8
+ import type { Rack } from '../../types'
9
+
10
+ describe('rack LCMS adapters', () => {
11
+ it('converts LCMS plate cells into rack wells grouped by slot', () => {
12
+ const racks = lcmsPlateCellsToRacks([
13
+ {
14
+ row: 'A',
15
+ column: 1,
16
+ sample_name: 'S1',
17
+ sample_type: 'sample',
18
+ injection_volume: 7,
19
+ slot: 'G',
20
+ },
21
+ {
22
+ row: 'H',
23
+ column: 10,
24
+ sample_name: 'IQC',
25
+ sample_type: 'iqc',
26
+ injection_count: 2,
27
+ slot: 'R',
28
+ },
29
+ ])
30
+
31
+ expect(racks.map(rack => rack.slot)).toEqual(['R', 'G'])
32
+ expect(racks[0]).toMatchObject({
33
+ id: 'rack-R',
34
+ format: 96,
35
+ wells: {
36
+ H10: {
37
+ sampleType: 'iqc',
38
+ metadata: {
39
+ label: 'IQC',
40
+ injectionVolume: 5,
41
+ injectionCount: 2,
42
+ },
43
+ },
44
+ },
45
+ })
46
+ expect(racks[1].wells.A1?.metadata).toMatchObject({
47
+ label: 'S1',
48
+ injectionVolume: 7,
49
+ })
50
+ })
51
+
52
+ it('flattens rack wells back to LCMS plate cells with slot metadata', () => {
53
+ const rack: Rack = {
54
+ id: 'rack-R',
55
+ name: 'Rack R',
56
+ format: 54,
57
+ slot: 'R',
58
+ injectionVolume: 5,
59
+ wells: {
60
+ A1: {
61
+ id: 'A1',
62
+ state: 'filled',
63
+ sampleType: 'sample',
64
+ metadata: {
65
+ label: 'S1',
66
+ injectionVolume: 7,
67
+ injectionCount: 3,
68
+ customMethod: 'C:\\Methods\\custom.meth',
69
+ },
70
+ },
71
+ F7: {
72
+ id: 'F7',
73
+ state: 'filled',
74
+ sampleType: 'iqc',
75
+ metadata: {
76
+ label: 'IQC',
77
+ },
78
+ },
79
+ },
80
+ }
81
+
82
+ expect(rackToLcmsPlateCells(rack)).toEqual([
83
+ {
84
+ row: 'A',
85
+ column: 1,
86
+ sample_name: 'S1',
87
+ sample_type: 'sample',
88
+ injection_volume: 7,
89
+ injection_count: 3,
90
+ custom_method: 'C:\\Methods\\custom.meth',
91
+ slot: 'R',
92
+ },
93
+ {
94
+ row: 'F',
95
+ column: 7,
96
+ sample_name: 'IQC',
97
+ sample_type: 'iqc',
98
+ injection_volume: 5,
99
+ injection_count: 1,
100
+ custom_method: null,
101
+ slot: 'R',
102
+ },
103
+ ])
104
+ })
105
+
106
+ it('exposes LCMS default control well edit data', () => {
107
+ expect(getLcmsDefaultControlWellId('54vial', 'iqc')).toBe('F7')
108
+ expect(createLcmsControlWellEditData('qc', {
109
+ plateType: '96well',
110
+ injectionVolume: 8,
111
+ })).toEqual({
112
+ wellId: 'H11',
113
+ label: 'QC',
114
+ sampleType: 'qc',
115
+ injectionVolume: 8,
116
+ injectionCount: 1,
117
+ customMethod: '',
118
+ })
119
+ })
120
+ })
@@ -451,6 +451,7 @@ function currentItemIdFromLocation(pages: Array<Pick<PageSelectorItem, 'id' | 't
451
451
  :control-options="settingsConfig?.controlOptions"
452
452
  :values="settingsConfig?.values"
453
453
  :enhancements="settingsConfig?.enhancements"
454
+ :user-type="settingsConfig?.userType"
454
455
  @update:values="emit('settings-values-change', $event)"
455
456
  >
456
457
  <template v-for="tab in normalizedSettingsTabs" :key="tab.id" #[`tab-${tab.id}`]>
@@ -21,6 +21,11 @@ const emit = defineEmits<{
21
21
  const activeTab = computed(() => props.modelValue)
22
22
  const normalizedTabs = computed<TabItem[]>(() => props.tabs.map(normalizeItemInput))
23
23
 
24
+ function isSvgIcon(icon: TabItem['icon']): icon is string | string[] {
25
+ if (!icon) return false
26
+ return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')
27
+ }
28
+
24
29
  function selectTab(tabId: string) {
25
30
  const tab = normalizedTabs.value.find(t => t.id === tabId)
26
31
  if (tab && !tab.disabled) {
@@ -46,7 +51,23 @@ function selectTab(tabId: string) {
46
51
  @click="selectTab(tab.id)"
47
52
  >
48
53
  <span class="mint-tab__content">
49
- <span v-if="tab.icon" class="mint-tab__icon">{{ tab.icon }}</span>
54
+ <svg
55
+ v-if="isSvgIcon(tab.icon)"
56
+ class="mint-tab__icon mint-tab__icon--svg"
57
+ viewBox="0 0 24 24"
58
+ fill="none"
59
+ stroke="currentColor"
60
+ stroke-width="2"
61
+ stroke-linecap="round"
62
+ stroke-linejoin="round"
63
+ aria-hidden="true"
64
+ >
65
+ <template v-if="Array.isArray(tab.icon)">
66
+ <path v-for="(d, index) in tab.icon" :key="index" :d="d" />
67
+ </template>
68
+ <path v-else :d="tab.icon" />
69
+ </svg>
70
+ <span v-else-if="tab.icon" class="mint-tab__icon">{{ tab.icon }}</span>
50
71
  {{ tab.label }}
51
72
  <span v-if="tab.badge !== undefined" class="mint-tab__badge">
52
73
  {{ tab.badge }}