@morscherlab/mint-sdk 1.0.0-rc.2 → 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 (178) hide show
  1. package/dist/components/AppSidebar.vue.d.ts +3 -3
  2. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  3. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
  4. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -3
  5. package/dist/components/index.js +2 -2
  6. package/dist/{components-BhK-dW99.js → components-DafPc4rM.js} +3 -3
  7. package/dist/{components-BhK-dW99.js.map → components-DafPc4rM.js.map} +1 -1
  8. package/dist/composables/controlComponentBindings.d.ts +7 -0
  9. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  10. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  11. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  12. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  13. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  14. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  15. package/dist/composables/index.js +3 -3
  16. package/dist/composables/useControlSchema.d.ts +4 -30
  17. package/dist/composables/useControlWorkspace.d.ts +5 -0
  18. package/dist/{composables-Bg7CFuNz.js → composables-BMkPQhVK.js} +2 -2
  19. package/dist/{composables-Bg7CFuNz.js.map → composables-BMkPQhVK.js.map} +1 -1
  20. package/dist/index.js +4 -4
  21. package/dist/install.js +2 -2
  22. package/dist/templates/adapters.d.ts +14 -47
  23. package/dist/templates/assayLookups.d.ts +3 -0
  24. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  25. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  26. package/dist/templates/assayNormalizers.d.ts +4 -0
  27. package/dist/templates/builderDefaults.d.ts +1 -0
  28. package/dist/templates/builderIdUtils.d.ts +4 -0
  29. package/dist/templates/builderPresetControls.d.ts +10 -0
  30. package/dist/templates/builderReadUtils.d.ts +8 -0
  31. package/dist/templates/builders.d.ts +26 -67
  32. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  33. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  34. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  35. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  36. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  37. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  38. package/dist/templates/componentGenericProps.d.ts +8 -0
  39. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  40. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  41. package/dist/templates/componentPropsFactory.d.ts +3 -0
  42. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  43. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  44. package/dist/templates/componentTemplateProps.d.ts +3 -0
  45. package/dist/templates/controlSchemaClone.d.ts +4 -0
  46. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  47. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  48. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  49. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  50. package/dist/templates/controlSchemas.d.ts +4 -4
  51. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  52. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  53. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  54. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  55. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  56. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  57. package/dist/templates/flowNormalizers.d.ts +8 -0
  58. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  59. package/dist/templates/index.js +1 -1
  60. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  61. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  62. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  63. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  64. package/dist/templates/plateGeometry.d.ts +4 -0
  65. package/dist/templates/plateMapAdapters.d.ts +3 -0
  66. package/dist/templates/plateMapBuilder.d.ts +2 -0
  67. package/dist/templates/presetControlSchemas.d.ts +534 -0
  68. package/dist/templates/protocolAdapters.d.ts +5 -0
  69. package/dist/templates/protocolNormalizers.d.ts +6 -0
  70. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  71. package/dist/templates/qpcrAdapters.d.ts +5 -0
  72. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  73. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  74. package/dist/templates/reagentAdapters.d.ts +5 -0
  75. package/dist/templates/reagentListBuilder.d.ts +2 -0
  76. package/dist/templates/runNormalizers.d.ts +10 -0
  77. package/dist/templates/sampleNormalizers.d.ts +4 -0
  78. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  79. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  80. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  81. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  82. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  83. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  84. package/dist/templates/templateControlSchemas.d.ts +400 -0
  85. package/dist/templates/templateEnvelopes.d.ts +9 -0
  86. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  87. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  88. package/dist/templates/templateValidators.d.ts +13 -0
  89. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  90. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  91. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  92. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  93. package/dist/{templates-BorLR_7p.js → templates-bUAWMn5L.js} +3574 -3428
  94. package/dist/templates-bUAWMn5L.js.map +1 -0
  95. package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-QZtHFFH2.js} +2 -2
  96. package/dist/{useProtocolTemplates-n6AJqSqv.js.map → useProtocolTemplates-QZtHFFH2.js.map} +1 -1
  97. package/package.json +1 -1
  98. package/src/composables/controlComponentBindings.ts +80 -0
  99. package/src/composables/controlSchemaAdapters.ts +196 -0
  100. package/src/composables/controlSchemaFormFields.ts +61 -0
  101. package/src/composables/controlSchemaLayout.ts +59 -0
  102. package/src/composables/controlSchemaNormalize.ts +101 -0
  103. package/src/composables/controlSchemaUtils.ts +36 -0
  104. package/src/composables/controlWorkspaceOptions.ts +21 -0
  105. package/src/composables/useControlSchema.ts +51 -628
  106. package/src/composables/useControlWorkspace.ts +207 -0
  107. package/src/templates/adapters.ts +89 -930
  108. package/src/templates/assayLookups.ts +33 -0
  109. package/src/templates/assayMatrixAdapters.ts +78 -0
  110. package/src/templates/assayMatrixBuilder.ts +59 -0
  111. package/src/templates/assayNormalizers.ts +34 -0
  112. package/src/templates/builderDefaults.ts +11 -0
  113. package/src/templates/builderIdUtils.ts +20 -0
  114. package/src/templates/builderPresetControls.ts +165 -0
  115. package/src/templates/builderReadUtils.ts +57 -0
  116. package/src/templates/builders.ts +122 -2350
  117. package/src/templates/calibrationCurveAdapters.ts +59 -0
  118. package/src/templates/calibrationCurveBuilder.ts +99 -0
  119. package/src/templates/calibrationNormalizers.ts +60 -0
  120. package/src/templates/componentBindingCatalog.ts +90 -0
  121. package/src/templates/componentBindingHelpers.ts +93 -0
  122. package/src/templates/componentBindings.ts +12 -461
  123. package/src/templates/componentDoseResponseProps.ts +42 -0
  124. package/src/templates/componentGenericProps.ts +77 -0
  125. package/src/templates/componentPlateHelpers.ts +29 -0
  126. package/src/templates/componentPlateMapProps.ts +32 -0
  127. package/src/templates/componentPropsFactory.ts +21 -0
  128. package/src/templates/componentQpcrPlateProps.ts +28 -0
  129. package/src/templates/componentTargetResolvers.ts +69 -0
  130. package/src/templates/componentTemplateProps.ts +78 -0
  131. package/src/templates/controlSchemaClone.ts +32 -0
  132. package/src/templates/controlSchemaConstants.ts +11 -0
  133. package/src/templates/controlSchemaMerge.ts +40 -0
  134. package/src/templates/controlSchemaTargets.ts +87 -0
  135. package/src/templates/controlSchemaTypes.ts +20 -0
  136. package/src/templates/controlSchemas.ts +22 -704
  137. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  138. package/src/templates/doseResponseAdapters.ts +45 -0
  139. package/src/templates/doseResponseBuilder.ts +44 -0
  140. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  141. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  142. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  143. package/src/templates/flowNormalizers.ts +58 -0
  144. package/src/templates/flowPanelAdapters.ts +58 -0
  145. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  146. package/src/templates/instrumentRunAdapters.ts +163 -0
  147. package/src/templates/instrumentRunBuilder.ts +97 -0
  148. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  149. package/src/templates/plateGeometry.ts +62 -0
  150. package/src/templates/plateMapAdapters.ts +36 -0
  151. package/src/templates/plateMapBuilder.ts +43 -0
  152. package/src/templates/presetControlSchemas.ts +258 -0
  153. package/src/templates/protocolAdapters.ts +69 -0
  154. package/src/templates/protocolNormalizers.ts +37 -0
  155. package/src/templates/protocolStepsBuilder.ts +36 -0
  156. package/src/templates/qpcrAdapters.ts +104 -0
  157. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  158. package/src/templates/qpcrPlateBuilder.ts +96 -0
  159. package/src/templates/reagentAdapters.ts +77 -0
  160. package/src/templates/reagentListBuilder.ts +30 -0
  161. package/src/templates/runNormalizers.ts +63 -0
  162. package/src/templates/sampleNormalizers.ts +58 -0
  163. package/src/templates/samplePrepAdapters.ts +63 -0
  164. package/src/templates/samplePrepBuilder.ts +51 -0
  165. package/src/templates/sampleSheetAdapters.ts +75 -0
  166. package/src/templates/sampleSheetBuilder.ts +23 -0
  167. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  168. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  169. package/src/templates/templateControlSchemas.ts +320 -0
  170. package/src/templates/templateEnvelopes.ts +137 -0
  171. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  172. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  173. package/src/templates/templateValidators.ts +414 -0
  174. package/src/templates/timeCourseAdapters.ts +73 -0
  175. package/src/templates/timeCourseBuilder.ts +64 -0
  176. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  177. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  178. package/dist/templates-BorLR_7p.js.map +0 -1
@@ -4,603 +4,39 @@ import {
4
4
  controlsToSidebarPanels,
5
5
  getControlDefaults,
6
6
  useControlSchema,
7
- type ControlDefinition,
8
7
  type ControlSchemaOptions,
9
8
  type UseControlSchemaReturn,
10
9
  } from '../composables/useControlSchema'
11
10
  import {
12
- extractTemplateCollection,
13
- } from './builders'
11
+ cloneControlSchema,
12
+ cloneSchemaMap,
13
+ } from './controlSchemaClone'
14
14
  import {
15
- getBioTemplateInfo,
16
- } from './catalog'
15
+ mergeTemplateControlSchemas,
16
+ } from './controlSchemaMerge'
17
17
  import {
18
- getBioTemplatePresetInfo,
19
- } from './presets'
18
+ describeControlTarget,
19
+ resolveControlSchemaTarget,
20
+ } from './controlSchemaTargets'
20
21
  import {
21
- getBioTemplatePackInfo,
22
- } from './packs'
22
+ presetControlSchemas,
23
+ } from './presetControlSchemas'
24
+ import {
25
+ templateControlSchemas,
26
+ } from './templateControlSchemas'
23
27
  import type {
24
- BioTemplateEnvelope,
25
- TemplateCollectionEnvelope,
26
28
  TemplateId,
27
- TemplatePackId,
28
29
  TemplatePresetId,
29
30
  } from './types'
31
+ import type {
32
+ BioTemplateControlSchema,
33
+ BioTemplateControlTarget,
34
+ } from './controlSchemaTypes'
30
35
 
31
- export type BioTemplateControlSchema = Record<string, ControlDefinition>
32
- export type BioTemplateControlTarget =
33
- | TemplateId
34
- | TemplatePackId
35
- | TemplatePresetId
36
- | string
37
- | BioTemplateEnvelope<unknown>
38
- | TemplateCollectionEnvelope
39
-
40
- const ICONS = {
41
- plate: ['M4 4h16v16H4z', 'M8 4v16', 'M12 4v16', 'M16 4v16', 'M4 8h16', 'M4 12h16', 'M4 16h16'],
42
- samples: ['M16 21v-2a4 4 0 0 0-8 0v2', 'M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8'],
43
- dose: ['M10 2v8L4 20h16l-6-10V2', 'M8 2h8', 'M7 14h10'],
44
- table: ['M3 5h18', 'M3 12h18', 'M3 19h18', 'M8 5v14', 'M16 5v14'],
45
- run: ['M4 17l6-6 4 4 6-8', 'M4 21h16'],
46
- settings: ['M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8', 'M4 12h2', 'M18 12h2', 'M12 4v2', 'M12 18v2'],
47
- }
48
-
49
- const PLATE_FORMAT_OPTIONS = [6, 12, 24, 48, 96, 384] as const
50
- const CONCENTRATION_UNITS = ['nM', 'uM', 'mM', 'ug/mL', 'mg/mL'] as const
51
-
52
- const templateControlSchemas = {
53
- 'plate-map': {
54
- plateName: {
55
- label: 'Plate name',
56
- default: 'Plate 1',
57
- section: 'layout',
58
- sectionLabel: 'Layout',
59
- sectionSubtitle: 'Plate geometry',
60
- view: 'design',
61
- sidebar: { icon: ICONS.plate, iconColor: '#6366f1', iconBg: '#e0e7ff' },
62
- },
63
- plateFormat: {
64
- label: 'Format',
65
- default: 96,
66
- options: PLATE_FORMAT_OPTIONS,
67
- section: 'layout',
68
- view: 'design',
69
- },
70
- sampleNames: {
71
- type: 'tags',
72
- label: 'Samples',
73
- default: ['Control', 'Treatment'],
74
- section: 'samples',
75
- sectionLabel: 'Samples',
76
- sectionSubtitle: 'Groups and legend',
77
- view: 'design',
78
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
79
- },
80
- },
81
- 'sample-sheet': {
82
- sampleCount: {
83
- type: 'number',
84
- label: 'Sample count',
85
- default: 2,
86
- min: 1,
87
- max: 10000,
88
- section: 'samples',
89
- sectionLabel: 'Samples',
90
- sectionSubtitle: 'Metadata table',
91
- view: 'design',
92
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
93
- },
94
- includeGroups: {
95
- label: 'Include groups',
96
- default: true,
97
- section: 'samples',
98
- view: 'design',
99
- },
100
- includeBatch: {
101
- label: 'Include batch',
102
- default: false,
103
- section: 'columns',
104
- sectionLabel: 'Columns',
105
- view: 'design',
106
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
107
- },
108
- },
109
- 'sample-prep': {
110
- prepType: {
111
- label: 'Prep type',
112
- default: 'extraction',
113
- options: ['extraction', 'dilution', 'normalization', 'transfer', 'quench', 'custom'],
114
- section: 'protocol',
115
- sectionLabel: 'Protocol',
116
- sectionSubtitle: 'Prep workflow',
117
- view: 'design',
118
- sidebar: { icon: ICONS.run, iconColor: '#f97316', iconBg: '#ffedd5' },
119
- },
120
- volumeUnit: {
121
- label: 'Volume unit',
122
- default: 'uL',
123
- options: ['uL', 'mL'],
124
- section: 'protocol',
125
- view: 'design',
126
- },
127
- outputVolume: {
128
- type: 'number',
129
- label: 'Output volume',
130
- default: 50,
131
- min: 0,
132
- section: 'protocol',
133
- view: 'design',
134
- },
135
- },
136
- 'dose-response': {
137
- unit: {
138
- label: 'Dose unit',
139
- default: 'uM',
140
- options: CONCENTRATION_UNITS,
141
- section: 'dose',
142
- sectionLabel: 'Dose Design',
143
- sectionSubtitle: 'Concentration series',
144
- view: 'design',
145
- sidebar: { icon: ICONS.dose, iconColor: '#8b5cf6', iconBg: '#ede9fe' },
146
- },
147
- replicates: {
148
- type: 'number',
149
- label: 'Replicates',
150
- default: 3,
151
- min: 1,
152
- max: 24,
153
- section: 'dose',
154
- view: 'design',
155
- },
156
- includePlateLayout: {
157
- label: 'Create plate layout',
158
- default: true,
159
- section: 'layout',
160
- sectionLabel: 'Layout',
161
- sectionSubtitle: 'Well assignment',
162
- view: 'design',
163
- sidebar: { icon: ICONS.plate, iconColor: '#6366f1', iconBg: '#e0e7ff', defaultOpen: false },
164
- },
165
- },
166
- 'calibration-curve': {
167
- analyte: {
168
- label: 'Analyte',
169
- default: 'Analyte',
170
- section: 'standards',
171
- sectionLabel: 'Standards',
172
- sectionSubtitle: 'Curve setup',
173
- view: 'analysis',
174
- sidebar: { icon: ICONS.dose, iconColor: '#8b5cf6', iconBg: '#ede9fe' },
175
- },
176
- model: {
177
- label: 'Model',
178
- default: 'linear',
179
- options: ['linear', 'linear-weighted-1-x', 'linear-weighted-1-x2', 'quadratic', 'four-parameter-logistic'],
180
- section: 'fit',
181
- sectionLabel: 'Fit',
182
- view: 'analysis',
183
- sidebar: { icon: ICONS.settings, iconColor: '#6366f1', iconBg: '#e0e7ff' },
184
- },
185
- minRSquared: {
186
- type: 'number',
187
- label: 'Minimum R squared',
188
- default: 0.99,
189
- min: 0,
190
- max: 1,
191
- props: { step: 0.001 },
192
- section: 'fit',
193
- view: 'analysis',
194
- },
195
- },
196
- 'time-course': {
197
- timeUnit: {
198
- label: 'Time unit',
199
- default: 'hour',
200
- options: ['second', 'minute', 'hour', 'day', 'week'],
201
- section: 'schedule',
202
- sectionLabel: 'Schedule',
203
- sectionSubtitle: 'Sampling timeline',
204
- view: 'design',
205
- sidebar: { icon: ICONS.run, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
206
- },
207
- replicates: {
208
- type: 'number',
209
- label: 'Replicates',
210
- default: 3,
211
- min: 1,
212
- max: 24,
213
- section: 'samples',
214
- sectionLabel: 'Samples',
215
- view: 'design',
216
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
217
- },
218
- },
219
- 'protocol-steps': {
220
- defaultDuration: {
221
- type: 'number',
222
- label: 'Default duration',
223
- default: 30,
224
- min: 0,
225
- section: 'protocol',
226
- sectionLabel: 'Protocol',
227
- sectionSubtitle: 'Step defaults',
228
- view: 'design',
229
- sidebar: { icon: ICONS.run, iconColor: '#f97316', iconBg: '#ffedd5' },
230
- props: { suffix: 'min' },
231
- },
232
- editable: {
233
- label: 'Editable timeline',
234
- default: true,
235
- section: 'protocol',
236
- view: 'design',
237
- },
238
- },
239
- 'assay-matrix': {
240
- featureType: {
241
- label: 'Feature type',
242
- default: 'metabolite',
243
- options: ['metabolite', 'protein', 'gene', 'cell', 'compound', 'readout', 'other'],
244
- section: 'features',
245
- sectionLabel: 'Features',
246
- sectionSubtitle: 'Measurement matrix',
247
- view: 'analysis',
248
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
249
- },
250
- normalizeValues: {
251
- label: 'Normalize values',
252
- default: false,
253
- section: 'analysis',
254
- sectionLabel: 'Analysis',
255
- view: 'analysis',
256
- sidebar: { icon: ICONS.settings, iconColor: '#6366f1', iconBg: '#e0e7ff', defaultOpen: false },
257
- },
258
- },
259
- 'reagent-list': {
260
- reagentKind: {
261
- label: 'Reagent kind',
262
- default: 'reagent',
263
- options: ['compound', 'antibody', 'primer', 'enzyme', 'buffer', 'media', 'kit', 'reagent', 'other'],
264
- section: 'inventory',
265
- sectionLabel: 'Inventory',
266
- sectionSubtitle: 'Reagent metadata',
267
- view: 'design',
268
- sidebar: { icon: ICONS.table, iconColor: '#10b981', iconBg: '#d1fae5' },
269
- },
270
- trackStock: {
271
- label: 'Track stock level',
272
- default: true,
273
- section: 'inventory',
274
- view: 'design',
275
- },
276
- },
277
- 'flow-cytometry-panel': {
278
- markers: {
279
- type: 'tags',
280
- label: 'Markers',
281
- default: ['CD3', 'CD4', 'CD8'],
282
- section: 'panel',
283
- sectionLabel: 'Panel',
284
- sectionSubtitle: 'Markers and controls',
285
- view: 'design',
286
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
287
- },
288
- instrument: {
289
- label: 'Instrument',
290
- default: 'Flow cytometer',
291
- section: 'panel',
292
- sectionLabel: 'Panel',
293
- sectionSubtitle: 'Markers and controls',
294
- view: 'design',
295
- sidebar: { icon: ICONS.settings, iconColor: '#6366f1', iconBg: '#e0e7ff' },
296
- },
297
- includeDefaultControls: {
298
- label: 'Default controls',
299
- default: true,
300
- section: 'panel',
301
- view: 'design',
302
- },
303
- },
304
- 'instrument-run': {
305
- instrument: {
306
- label: 'Instrument',
307
- default: 'LC-MS',
308
- options: ['LC-MS', 'GC-MS', 'Orbitrap', 'Triple quadrupole', 'Plate reader', 'Other'],
309
- section: 'acquisition',
310
- sectionLabel: 'Acquisition',
311
- sectionSubtitle: 'Run queue',
312
- view: 'run',
313
- sidebar: { icon: ICONS.run, iconColor: '#ef4444', iconBg: '#fee2e2' },
314
- },
315
- method: {
316
- label: 'Method',
317
- default: 'Default method',
318
- section: 'acquisition',
319
- view: 'run',
320
- },
321
- includeQc: {
322
- label: 'Include QC',
323
- default: true,
324
- section: 'quality',
325
- sectionLabel: 'Quality Control',
326
- view: 'run',
327
- sidebar: { icon: ICONS.settings, iconColor: '#6366f1', iconBg: '#e0e7ff', defaultOpen: false },
328
- },
329
- },
330
- 'qpcr-plate': {
331
- chemistry: {
332
- label: 'Chemistry',
333
- default: 'sybr',
334
- options: ['sybr', 'taqman', 'probe', 'evagreen', 'other'],
335
- section: 'assay',
336
- sectionLabel: 'Assay',
337
- sectionSubtitle: 'qPCR setup',
338
- view: 'design',
339
- sidebar: { icon: ICONS.plate, iconColor: '#6366f1', iconBg: '#e0e7ff' },
340
- },
341
- replicates: {
342
- type: 'number',
343
- label: 'Replicates',
344
- default: 3,
345
- min: 1,
346
- max: 12,
347
- section: 'assay',
348
- view: 'design',
349
- },
350
- includeNoTemplateControls: {
351
- label: 'No-template controls',
352
- default: true,
353
- section: 'controls',
354
- sectionLabel: 'Controls',
355
- view: 'design',
356
- sidebar: { icon: ICONS.settings, iconColor: '#8b5cf6', iconBg: '#ede9fe', defaultOpen: false },
357
- },
358
- },
359
- } satisfies Record<TemplateId, BioTemplateControlSchema>
360
-
361
- const presetControlSchemas = {
362
- 'wellplate-screen': {
363
- ...templateControlSchemas['plate-map'],
364
- ...templateControlSchemas['dose-response'],
365
- sampleNames: {
366
- ...templateControlSchemas['plate-map'].sampleNames,
367
- default: ['Control', 'Treatment'],
368
- },
369
- },
370
- 'qpcr-expression': {
371
- sampleNames: {
372
- type: 'tags',
373
- label: 'Samples',
374
- default: ['Control', 'Treatment'],
375
- section: 'samples',
376
- sectionLabel: 'Samples',
377
- sectionSubtitle: 'Expression groups',
378
- view: 'design',
379
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
380
- },
381
- targets: {
382
- type: 'tags',
383
- label: 'Targets',
384
- default: ['ACTB', 'GAPDH'],
385
- section: 'assay',
386
- sectionLabel: 'Assay',
387
- view: 'design',
388
- sidebar: { icon: ICONS.plate, iconColor: '#6366f1', iconBg: '#e0e7ff' },
389
- },
390
- ...templateControlSchemas['qpcr-plate'],
391
- },
392
- 'lcms-batch': {
393
- sampleNames: {
394
- type: 'tags',
395
- label: 'Samples',
396
- default: ['S001', 'S002'],
397
- section: 'samples',
398
- sectionLabel: 'Samples',
399
- sectionSubtitle: 'Batch samples',
400
- view: 'run',
401
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
402
- },
403
- featureNames: {
404
- type: 'tags',
405
- label: 'Features',
406
- default: ['Glucose', 'Lactate'],
407
- section: 'features',
408
- sectionLabel: 'Features',
409
- view: 'analysis',
410
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
411
- },
412
- ...templateControlSchemas['instrument-run'],
413
- ...templateControlSchemas['assay-matrix'],
414
- },
415
- 'targeted-metabolomics': {
416
- sampleNames: {
417
- type: 'tags',
418
- label: 'Samples',
419
- default: ['S001', 'S002'],
420
- section: 'samples',
421
- sectionLabel: 'Samples',
422
- sectionSubtitle: 'Unknowns and QC pool',
423
- view: 'run',
424
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
425
- },
426
- metaboliteNames: {
427
- type: 'tags',
428
- label: 'Metabolites',
429
- default: ['Glucose', 'Lactate', 'Pyruvate'],
430
- section: 'features',
431
- sectionLabel: 'Metabolites',
432
- sectionSubtitle: 'Quantitation panel',
433
- view: 'analysis',
434
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
435
- },
436
- internalStandards: {
437
- type: 'tags',
438
- label: 'Internal standards',
439
- default: ['Stable isotope internal standard mix'],
440
- section: 'standards',
441
- sectionLabel: 'Standards',
442
- sectionSubtitle: 'Calibration and internal standards',
443
- view: 'analysis',
444
- sidebar: { icon: ICONS.dose, iconColor: '#8b5cf6', iconBg: '#ede9fe' },
445
- },
446
- standardConcentrations: {
447
- type: 'tags',
448
- label: 'Calibration levels',
449
- default: ['0.1', '1', '10', '100'],
450
- section: 'standards',
451
- view: 'analysis',
452
- },
453
- concentrationUnit: {
454
- label: 'Concentration unit',
455
- default: 'uM',
456
- options: CONCENTRATION_UNITS,
457
- section: 'standards',
458
- view: 'analysis',
459
- },
460
- responseUnit: {
461
- label: 'Response unit',
462
- default: 'peak area ratio',
463
- section: 'readout',
464
- sectionLabel: 'Readout',
465
- view: 'analysis',
466
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
467
- },
468
- instrument: {
469
- ...templateControlSchemas['instrument-run'].instrument,
470
- default: 'LC-MS',
471
- },
472
- method: {
473
- ...templateControlSchemas['instrument-run'].method,
474
- default: 'Targeted metabolomics',
475
- },
476
- prepType: {
477
- ...templateControlSchemas['sample-prep'].prepType,
478
- default: 'extraction',
479
- },
480
- outputVolume: templateControlSchemas['sample-prep'].outputVolume,
481
- includeQc: templateControlSchemas['instrument-run'].includeQc,
482
- },
483
- 'elisa-assay': {
484
- sampleNames: {
485
- type: 'tags',
486
- label: 'Samples',
487
- default: ['Control', 'Treatment'],
488
- section: 'samples',
489
- sectionLabel: 'Samples',
490
- sectionSubtitle: 'Unknowns and controls',
491
- view: 'design',
492
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
493
- },
494
- analyte: {
495
- label: 'Analyte',
496
- default: 'Analyte',
497
- section: 'standards',
498
- sectionLabel: 'Standards',
499
- sectionSubtitle: 'Calibration setup',
500
- view: 'analysis',
501
- sidebar: { icon: ICONS.dose, iconColor: '#8b5cf6', iconBg: '#ede9fe' },
502
- },
503
- standardConcentrations: {
504
- type: 'tags',
505
- label: 'Standards',
506
- default: ['1000', '100', '10', '1'],
507
- section: 'standards',
508
- view: 'analysis',
509
- },
510
- unit: {
511
- label: 'Concentration unit',
512
- default: 'pg/mL',
513
- options: ['pg/mL', 'ng/mL', 'ug/mL', 'nM', 'uM'],
514
- section: 'standards',
515
- view: 'analysis',
516
- },
517
- responseUnit: {
518
- label: 'Response unit',
519
- default: 'OD450',
520
- section: 'readout',
521
- sectionLabel: 'Readout',
522
- view: 'analysis',
523
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
524
- },
525
- plateName: {
526
- label: 'Plate name',
527
- default: 'ELISA plate',
528
- section: 'layout',
529
- sectionLabel: 'Layout',
530
- sectionSubtitle: 'Plate geometry',
531
- view: 'design',
532
- sidebar: { icon: ICONS.plate, iconColor: '#6366f1', iconBg: '#e0e7ff' },
533
- },
534
- plateFormat: {
535
- label: 'Format',
536
- default: 96,
537
- options: PLATE_FORMAT_OPTIONS,
538
- section: 'layout',
539
- view: 'design',
540
- },
541
- },
542
- 'flow-cytometry-assay': {
543
- sampleNames: {
544
- type: 'tags',
545
- label: 'Samples',
546
- default: ['Control', 'Treatment'],
547
- section: 'samples',
548
- sectionLabel: 'Samples',
549
- sectionSubtitle: 'Assay groups',
550
- view: 'design',
551
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
552
- },
553
- markers: {
554
- ...templateControlSchemas['flow-cytometry-panel'].markers,
555
- default: ['CD3', 'CD4', 'CD8'],
556
- },
557
- featureNames: {
558
- type: 'tags',
559
- label: 'Readouts',
560
- default: ['CD3+ cells', 'CD4+ cells', 'CD8+ cells'],
561
- section: 'features',
562
- sectionLabel: 'Readouts',
563
- sectionSubtitle: 'Assay matrix columns',
564
- view: 'analysis',
565
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
566
- },
567
- instrument: {
568
- ...templateControlSchemas['flow-cytometry-panel'].instrument,
569
- default: 'Flow cytometer',
570
- },
571
- includeDefaultControls: templateControlSchemas['flow-cytometry-panel'].includeDefaultControls,
572
- },
573
- 'western-blot-assay': {
574
- sampleNames: {
575
- type: 'tags',
576
- label: 'Samples',
577
- default: ['Control', 'Treatment'],
578
- section: 'samples',
579
- sectionLabel: 'Samples',
580
- sectionSubtitle: 'Blot lanes and groups',
581
- view: 'design',
582
- sidebar: { icon: ICONS.samples, iconColor: '#10b981', iconBg: '#d1fae5' },
583
- },
584
- targets: {
585
- type: 'tags',
586
- label: 'Targets',
587
- default: ['Target protein'],
588
- section: 'assay',
589
- sectionLabel: 'Assay',
590
- sectionSubtitle: 'Protein targets',
591
- view: 'design',
592
- sidebar: { icon: ICONS.table, iconColor: '#0ea5e9', iconBg: '#e0f2fe' },
593
- },
594
- loadingControl: {
595
- label: 'Loading control',
596
- default: 'ACTB',
597
- section: 'normalization',
598
- sectionLabel: 'Normalization',
599
- view: 'analysis',
600
- sidebar: { icon: ICONS.settings, iconColor: '#6366f1', iconBg: '#e0e7ff' },
601
- },
602
- },
603
- } satisfies Record<TemplatePresetId, BioTemplateControlSchema>
36
+ export type {
37
+ BioTemplateControlSchema,
38
+ BioTemplateControlTarget,
39
+ } from './controlSchemaTypes'
604
40
 
605
41
  export function listBioTemplateControlSchemas(): Record<TemplateId, BioTemplateControlSchema> {
606
42
  return cloneSchemaMap(templateControlSchemas)
@@ -622,7 +58,7 @@ export function getBioTemplateControlSchema(
622
58
  if (resolved.kind === 'preset') {
623
59
  return cloneControlSchema(presetControlSchemas[resolved.name])
624
60
  }
625
- return mergeTemplateControlSchemas(resolved.templates)
61
+ return mergeTemplateControlSchemas(resolved.templates, templateControlSchemas)
626
62
  }
627
63
 
628
64
  export function requireBioTemplateControlSchema(
@@ -666,121 +102,3 @@ export function bioTemplateControlsToSectionFormSchemas(
666
102
  export function getBioTemplateControlDefaults(target: BioTemplateControlTarget) {
667
103
  return getControlDefaults(requireBioTemplateControlSchema(target))
668
104
  }
669
-
670
- function resolveControlSchemaTarget(
671
- target: BioTemplateControlTarget
672
- ):
673
- | { kind: 'template'; name: TemplateId }
674
- | { kind: 'pack'; templates: TemplateId[] }
675
- | { kind: 'preset'; name: TemplatePresetId }
676
- | { kind: 'collection'; templates: TemplateId[] }
677
- | undefined {
678
- if (typeof target === 'string') {
679
- const preset = getBioTemplatePresetInfo(target)
680
- if (preset) return { kind: 'preset', name: preset.name }
681
- const pack = getBioTemplatePackInfo(target)
682
- if (pack) return { kind: 'pack', templates: [...pack.templates] }
683
- const template = getBioTemplateInfo(target)
684
- if (template) return { kind: 'template', name: template.template_id }
685
- return undefined
686
- }
687
-
688
- if (isTemplateEnvelope(target)) {
689
- const template = getBioTemplateInfo(target.template_id)
690
- return template ? { kind: 'template', name: template.template_id } : undefined
691
- }
692
-
693
- const presetName = collectionPresetName(target)
694
- if (presetName) {
695
- const preset = getBioTemplatePresetInfo(presetName)
696
- if (preset) return { kind: 'preset', name: preset.name }
697
- }
698
-
699
- const packName = collectionPackName(target)
700
- if (packName) {
701
- const pack = getBioTemplatePackInfo(packName)
702
- if (pack) return { kind: 'pack', templates: [...pack.templates] }
703
- }
704
-
705
- const collection = extractTemplateCollection(target)
706
- const templateIds = Object.keys(collection)
707
- .map(id => getBioTemplateInfo(id)?.template_id)
708
- .filter((id): id is TemplateId => id !== undefined)
709
- return templateIds.length > 0 ? { kind: 'collection', templates: templateIds } : undefined
710
- }
711
-
712
- function mergeTemplateControlSchemas(templateIds: TemplateId[]): BioTemplateControlSchema {
713
- const merged: BioTemplateControlSchema = {}
714
- for (const templateId of templateIds) {
715
- const schema = templateControlSchemas[templateId]
716
- const template = getBioTemplateInfo(templateId)
717
- for (const [name, definition] of Object.entries(schema)) {
718
- const key = `${camelize(templateId)}${capitalize(name)}`
719
- merged[key] = {
720
- ...cloneControlDefinition(definition),
721
- section: definition.section ?? templateId,
722
- sectionLabel: definition.sectionLabel ?? template?.label ?? templateId,
723
- }
724
- }
725
- }
726
- return merged
727
- }
728
-
729
- function cloneSchemaMap<TName extends string>(
730
- schemas: Record<TName, BioTemplateControlSchema>
731
- ): Record<TName, BioTemplateControlSchema> {
732
- const result = {} as Record<TName, BioTemplateControlSchema>
733
- for (const name of Object.keys(schemas) as TName[]) {
734
- result[name] = cloneControlSchema(schemas[name])
735
- }
736
- return result
737
- }
738
-
739
- function cloneControlSchema(schema: BioTemplateControlSchema): BioTemplateControlSchema {
740
- return Object.fromEntries(
741
- Object.entries(schema).map(([name, definition]) => [name, cloneControlDefinition(definition)])
742
- )
743
- }
744
-
745
- function cloneControlDefinition(definition: BioTemplateControlSchema[string]): BioTemplateControlSchema[string] {
746
- return {
747
- ...definition,
748
- options: definition.options ? [...definition.options] : undefined,
749
- props: definition.props ? { ...definition.props } : undefined,
750
- sidebar: typeof definition.sidebar === 'object' && definition.sidebar !== null
751
- ? { ...definition.sidebar }
752
- : definition.sidebar,
753
- }
754
- }
755
-
756
- function isTemplateEnvelope(value: unknown): value is BioTemplateEnvelope<unknown> {
757
- return isRecord(value) && typeof value.template_id === 'string' && 'data' in value
758
- }
759
-
760
- function collectionPresetName(value: unknown): string | undefined {
761
- if (!isRecord(value) || !isRecord(value.metadata)) return undefined
762
- return typeof value.metadata.preset === 'string' ? value.metadata.preset : undefined
763
- }
764
-
765
- function collectionPackName(value: unknown): string | undefined {
766
- if (!isRecord(value) || !isRecord(value.metadata)) return undefined
767
- return typeof value.metadata.pack === 'string' ? value.metadata.pack : undefined
768
- }
769
-
770
- function isRecord(value: unknown): value is Record<string, unknown> {
771
- return typeof value === 'object' && value !== null
772
- }
773
-
774
- function describeControlTarget(target: BioTemplateControlTarget): string {
775
- if (typeof target === 'string') return target
776
- if (isTemplateEnvelope(target)) return target.template_id
777
- return collectionPresetName(target) ?? collectionPackName(target) ?? 'template collection'
778
- }
779
-
780
- function camelize(value: string): string {
781
- return value.replace(/-([a-z0-9])/g, (_, char: string) => char.toUpperCase())
782
- }
783
-
784
- function capitalize(value: string): string {
785
- return value.charAt(0).toUpperCase() + value.slice(1)
786
- }