@morscherlab/mint-sdk 1.0.0-rc.1 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +1 -0
- package/dist/__tests__/components/ProgressBar.test.d.ts +1 -0
- package/dist/__tests__/components/RackEditor.test.d.ts +1 -0
- package/dist/__tests__/components/SequenceProgressBar.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentSamples.test.d.ts +1 -0
- package/dist/__tests__/utils/instrument.test.d.ts +1 -0
- package/dist/__tests__/utils/lcms.test.d.ts +1 -0
- package/dist/__tests__/utils/permissions.test.d.ts +1 -0
- package/dist/__tests__/utils/rack.test.d.ts +1 -0
- package/dist/{auth-CBG3bWEc.js → auth-B7g4J4ZF.js} +99 -5
- package/dist/auth-B7g4J4ZF.js.map +1 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BaseCheckbox.vue.d.ts +1 -1
- package/dist/components/BaseToggle.vue.d.ts +2 -2
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +1 -1
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
- package/dist/components/FormulaInput.vue.d.ts +1 -1
- package/dist/components/InstrumentAlertLog.vue.d.ts +22 -0
- package/dist/components/InstrumentStateBadge.vue.d.ts +11 -0
- package/dist/components/InstrumentStatusCard.vue.d.ts +13 -0
- package/dist/components/LcmsSequenceTable.vue.d.ts +26 -0
- package/dist/components/ProgressBar.vue.d.ts +1 -0
- package/dist/components/RackEditor.vue.d.ts +41 -3
- package/dist/components/ReagentList.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +5 -2
- package/dist/components/SegmentedControl.vue.d.ts +2 -0
- package/dist/components/SequenceInput.vue.d.ts +1 -1
- package/dist/components/SequenceProgressBar.vue.d.ts +15 -0
- package/dist/components/SettingsModal.vue.d.ts +3 -1
- package/dist/components/TagsInput.vue.d.ts +1 -1
- package/dist/components/WellPlate.vue.d.ts +42 -3
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +3 -3
- package/dist/{components-5KSfsVqf.js → components-BhK-dW99.js} +2091 -1051
- package/dist/components-BhK-dW99.js.map +1 -0
- package/dist/composables/experimentDesignData.d.ts +17 -0
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.js +4 -4
- package/dist/composables/useControlSchema.d.ts +11 -0
- package/dist/composables/useExperimentData.d.ts +11 -3
- package/dist/composables/useExperimentSamples.d.ts +42 -0
- package/dist/composables/usePlatformContext.d.ts +54 -0
- package/dist/{composables-D4Myb30a.js → composables-Bg7CFuNz.js} +5 -3
- package/dist/composables-Bg7CFuNz.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +168 -6
- package/dist/index.js.map +1 -0
- package/dist/install.js +2 -2
- package/dist/instrument.d.ts +7 -0
- package/dist/lcms.d.ts +27 -0
- package/dist/permissions.d.ts +46 -0
- package/dist/stores/auth.d.ts +74 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +3316 -1216
- package/dist/templates/builders.d.ts +7 -3
- package/dist/templates/index.d.ts +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/templates/presets.d.ts +12 -0
- package/dist/templates/types.d.ts +16 -1
- package/dist/{templates-BSlxwV2c.js → templates-BorLR_7p.js} +313 -3
- package/dist/templates-BorLR_7p.js.map +1 -0
- package/dist/types/auth.d.ts +2 -0
- package/dist/types/components.d.ts +32 -3
- package/dist/types/form-builder.d.ts +2 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/instrument.d.ts +56 -0
- package/dist/types/platform.d.ts +3 -0
- package/dist/{useExperimentData-BbbdI5xT.js → useProtocolTemplates-n6AJqSqv.js} +534 -359
- package/dist/useProtocolTemplates-n6AJqSqv.js.map +1 -0
- package/dist/utils/rack.d.ts +47 -0
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +15 -0
- package/src/__tests__/components/BaseTabs.test.ts +15 -0
- package/src/__tests__/components/LcmsSequenceTable.test.ts +57 -0
- package/src/__tests__/components/ProgressBar.test.ts +18 -0
- package/src/__tests__/components/RackEditor.test.ts +125 -0
- package/src/__tests__/components/SampleSelector.test.ts +25 -0
- package/src/__tests__/components/SegmentedControl.test.ts +45 -0
- package/src/__tests__/components/SequenceProgressBar.test.ts +39 -0
- package/src/__tests__/components/SettingsModal.test.ts +83 -2
- package/src/__tests__/composables/useControlSchema.test.ts +4 -0
- package/src/__tests__/composables/useExperimentData.test.ts +23 -0
- package/src/__tests__/composables/useExperimentSamples.test.ts +91 -0
- package/src/__tests__/templates/templates.test.ts +86 -0
- package/src/__tests__/utils/instrument.test.ts +47 -0
- package/src/__tests__/utils/lcms.test.ts +73 -0
- package/src/__tests__/utils/permissions.test.ts +50 -0
- package/src/__tests__/utils/rack.test.ts +120 -0
- package/src/components/AppTopBar.vue +1 -0
- package/src/components/BaseTabs.vue +22 -1
- package/src/components/InstrumentAlertLog.vue +191 -0
- package/src/components/InstrumentStateBadge.vue +50 -0
- package/src/components/InstrumentStatusCard.vue +188 -0
- package/src/components/LcmsSequenceTable.vue +191 -0
- package/src/components/ProgressBar.vue +3 -0
- package/src/components/RackEditor.vue +73 -2
- package/src/components/SampleSelector.vue +28 -9
- package/src/components/SegmentedControl.story.vue +17 -0
- package/src/components/SegmentedControl.vue +14 -3
- package/src/components/SequenceProgressBar.vue +71 -0
- package/src/components/SettingsModal.vue +42 -2
- package/src/components/WellPlate.vue +142 -21
- package/src/components/index.ts +5 -0
- package/src/components/internal/WellEditPopupInternal.vue +1 -0
- package/src/composables/experimentDesignData.ts +182 -0
- package/src/composables/index.ts +14 -0
- package/src/composables/useAuth.ts +4 -0
- package/src/composables/useAutoGroup.ts +5 -1
- package/src/composables/useControlSchema.ts +21 -0
- package/src/composables/useExperimentData.ts +57 -16
- package/src/composables/useExperimentSamples.ts +142 -0
- package/src/index.ts +27 -0
- package/src/instrument.ts +90 -0
- package/src/lcms.ts +108 -0
- package/src/permissions.ts +143 -0
- package/src/stores/auth.ts +31 -3
- package/src/styles/components/instrument-monitor.css +478 -0
- package/src/styles/components/lcms-sequence-table.css +189 -0
- package/src/styles/components/sequence-progress-bar.css +63 -0
- package/src/styles/components/tabs.css +9 -0
- package/src/styles/components/well-edit-popup.css +7 -1
- package/src/styles/components/well-plate.css +5 -0
- package/src/styles/index.css +3 -0
- package/src/templates/builders.ts +201 -0
- package/src/templates/controlSchemas.ts +68 -0
- package/src/templates/index.ts +2 -0
- package/src/templates/presets.ts +23 -0
- package/src/templates/types.ts +17 -0
- package/src/types/auth.ts +3 -0
- package/src/types/components.ts +45 -3
- package/src/types/form-builder.ts +2 -1
- package/src/types/index.ts +35 -0
- package/src/types/instrument.ts +61 -0
- package/src/types/platform.ts +4 -0
- package/src/utils/rack.ts +209 -0
- package/dist/auth-CBG3bWEc.js.map +0 -1
- package/dist/components-5KSfsVqf.js.map +0 -1
- package/dist/composables-D4Myb30a.js.map +0 -1
- package/dist/templates-BSlxwV2c.js.map +0 -1
- package/dist/useExperimentData-BbbdI5xT.js.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
.mint-sequence-progress {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 0.25rem;
|
|
5
|
+
min-width: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.mint-sequence-progress__header {
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
gap: 0.75rem;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.mint-sequence-progress__label {
|
|
17
|
+
min-width: 0;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
color: var(--text-muted, #64748b);
|
|
20
|
+
font-family: var(--font-mono, 'Fira Code', monospace);
|
|
21
|
+
font-size: 0.75rem;
|
|
22
|
+
text-overflow: ellipsis;
|
|
23
|
+
white-space: nowrap;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.mint-sequence-progress__percent {
|
|
27
|
+
flex: 0 0 auto;
|
|
28
|
+
color: var(--mint-info, #3b82f6);
|
|
29
|
+
font-family: var(--font-mono, 'Fira Code', monospace);
|
|
30
|
+
font-size: 0.6875rem;
|
|
31
|
+
font-weight: 700;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mint-sequence-progress__footer {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: space-between;
|
|
38
|
+
gap: 0.75rem;
|
|
39
|
+
min-width: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.mint-sequence-progress__remaining {
|
|
43
|
+
min-width: 0;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
color: var(--text-muted, #64748b);
|
|
46
|
+
font-family: var(--font-mono, 'Fira Code', monospace);
|
|
47
|
+
font-size: 0.6875rem;
|
|
48
|
+
text-overflow: ellipsis;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.mint-sequence-progress__eta {
|
|
53
|
+
flex: 0 0 auto;
|
|
54
|
+
border: 1px solid color-mix(in srgb, var(--mint-info, #3b82f6) 24%, transparent);
|
|
55
|
+
border-radius: 999px;
|
|
56
|
+
background: color-mix(in srgb, var(--mint-info, #3b82f6) 10%, transparent);
|
|
57
|
+
color: var(--mint-info, #3b82f6);
|
|
58
|
+
font-family: var(--font-mono, 'Fira Code', monospace);
|
|
59
|
+
font-size: 0.6875rem;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
padding: 0.125rem 0.5rem;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
}
|
|
@@ -9,10 +9,13 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.mint-tabs--pills {
|
|
12
|
+
width: fit-content;
|
|
13
|
+
max-width: 100%;
|
|
12
14
|
gap: 0.5rem;
|
|
13
15
|
padding: 0.25rem;
|
|
14
16
|
background-color: var(--bg-tertiary);
|
|
15
17
|
border-radius: var(--radius-md);
|
|
18
|
+
overflow-x: auto;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
.mint-tab {
|
|
@@ -84,6 +87,12 @@
|
|
|
84
87
|
color: currentColor;
|
|
85
88
|
}
|
|
86
89
|
|
|
90
|
+
.mint-tab__icon--svg {
|
|
91
|
+
width: 1rem;
|
|
92
|
+
height: 1rem;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
.mint-tab__badge {
|
|
88
97
|
margin-left: 0.25rem;
|
|
89
98
|
padding: 0.125rem 0.375rem;
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
/* Sample type buttons */
|
|
121
121
|
.mint-well-edit-popup__type-grid {
|
|
122
122
|
display: grid;
|
|
123
|
-
grid-template-columns: repeat(
|
|
123
|
+
grid-template-columns: repeat(4, 1fr);
|
|
124
124
|
gap: 0.25rem;
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -154,6 +154,12 @@
|
|
|
154
154
|
color: #8b5cf6;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
.mint-well-edit-popup__type-btn--iqc {
|
|
158
|
+
background-color: rgba(236, 72, 153, 0.15);
|
|
159
|
+
border-color: rgba(236, 72, 153, 0.4);
|
|
160
|
+
color: #ec4899;
|
|
161
|
+
}
|
|
162
|
+
|
|
157
163
|
/* Injection count buttons */
|
|
158
164
|
.mint-well-edit-popup__count-grid {
|
|
159
165
|
display: grid;
|
|
@@ -183,6 +183,11 @@
|
|
|
183
183
|
border: 1px solid rgba(139, 92, 246, 0.4);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
.mint-well-plate__well--iqc {
|
|
187
|
+
background-color: rgba(236, 72, 153, 0.15);
|
|
188
|
+
border: 1px solid rgba(236, 72, 153, 0.4);
|
|
189
|
+
}
|
|
190
|
+
|
|
186
191
|
/* Condition header - drug label row */
|
|
187
192
|
.mint-well-plate__condition-label {
|
|
188
193
|
font-weight: 600;
|
package/src/styles/index.css
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
@import './components/file-uploader.css';
|
|
21
21
|
@import './components/form-field.css';
|
|
22
22
|
@import './components/icon-button.css';
|
|
23
|
+
@import './components/instrument-monitor.css';
|
|
23
24
|
@import './components/input.css';
|
|
24
25
|
@import './components/modal.css';
|
|
25
26
|
@import './components/number-input.css';
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
@import './components/sample-hierarchy-tree.css';
|
|
47
48
|
@import './components/protocol-step-editor.css';
|
|
48
49
|
@import './components/segmented-control.css';
|
|
50
|
+
@import './components/sequence-progress-bar.css';
|
|
49
51
|
@import './components/multi-select.css';
|
|
50
52
|
@import './components/pill.css';
|
|
51
53
|
@import './components/dropdown-button.css';
|
|
@@ -54,6 +56,7 @@
|
|
|
54
56
|
@import './components/well-edit-popup.css';
|
|
55
57
|
@import './components/rack-editor.css';
|
|
56
58
|
@import './components/loading-spinner.css';
|
|
59
|
+
@import './components/lcms-sequence-table.css';
|
|
57
60
|
@import './components/divider.css';
|
|
58
61
|
@import './components/status-indicator.css';
|
|
59
62
|
@import './components/progress-bar.css';
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
CreateBioTemplatePackCollectionOptions,
|
|
15
15
|
CreateElisaAssayCollectionOptions,
|
|
16
16
|
CreateLcmsBatchCollectionOptions,
|
|
17
|
+
CreateTargetedMetabolomicsCollectionOptions,
|
|
17
18
|
CreateAssayMatrixTemplateOptions,
|
|
18
19
|
CreateCalibrationCurveTemplateOptions,
|
|
19
20
|
CreateDoseResponseTemplateOptions,
|
|
@@ -38,6 +39,7 @@ import type {
|
|
|
38
39
|
FlowPanelMarker,
|
|
39
40
|
InstrumentMethod,
|
|
40
41
|
InstrumentRunItem,
|
|
42
|
+
InstrumentRunItemInput,
|
|
41
43
|
InstrumentRunTemplate,
|
|
42
44
|
InstrumentRunTemplateData,
|
|
43
45
|
PlateMapTemplate,
|
|
@@ -858,6 +860,67 @@ export function createLcmsBatchCollection(
|
|
|
858
860
|
)
|
|
859
861
|
}
|
|
860
862
|
|
|
863
|
+
export function createTargetedMetabolomicsCollection(
|
|
864
|
+
options: CreateTargetedMetabolomicsCollectionOptions = {}
|
|
865
|
+
): TemplateCollectionEnvelope {
|
|
866
|
+
const sampleRecords = presetSampleRecords(options.samples ?? ['S001', 'S002'])
|
|
867
|
+
const responseUnit = options.responseUnit ?? 'peak area ratio'
|
|
868
|
+
const concentrationUnit = options.concentrationUnit ?? 'uM'
|
|
869
|
+
const metaboliteFeatures = normalizeMetaboliteFeatures(
|
|
870
|
+
options.metabolites ?? ['Glucose', 'Lactate', 'Pyruvate'],
|
|
871
|
+
responseUnit,
|
|
872
|
+
)
|
|
873
|
+
const sampleSheet = createSampleSheetTemplate({ samples: sampleRecords })
|
|
874
|
+
const samplePrep = createSamplePrepTemplate({
|
|
875
|
+
samples: sampleRecords.map(sample => sample.sampleId),
|
|
876
|
+
prepType: options.prepType ?? 'extraction',
|
|
877
|
+
protocolName: 'Metabolomics sample preparation',
|
|
878
|
+
outputVolume: options.outputVolume ?? 50,
|
|
879
|
+
metadata: { assay: 'targeted-metabolomics' },
|
|
880
|
+
})
|
|
881
|
+
const reagents = createReagentListTemplate({
|
|
882
|
+
reagents: normalizeInternalStandardReagents(
|
|
883
|
+
options.internalStandards ?? ['Stable isotope internal standard mix'],
|
|
884
|
+
),
|
|
885
|
+
metadata: { assay: 'targeted-metabolomics' },
|
|
886
|
+
})
|
|
887
|
+
const calibrationCurve = createCalibrationCurveTemplate({
|
|
888
|
+
concentrations: options.standardConcentrations ?? [0.1, 1, 10, 100],
|
|
889
|
+
analyte: options.calibrationAnalyte ?? firstFeatureName(metaboliteFeatures, 'Metabolite panel'),
|
|
890
|
+
unit: concentrationUnit,
|
|
891
|
+
responseUnit,
|
|
892
|
+
model: 'linear-weighted-1-x',
|
|
893
|
+
includeQc: options.includeQc,
|
|
894
|
+
metadata: { assay: 'targeted-metabolomics' },
|
|
895
|
+
})
|
|
896
|
+
const instrumentRun = createInstrumentRunTemplate({
|
|
897
|
+
items: targetedMetabolomicsRunItems(
|
|
898
|
+
sampleRecords,
|
|
899
|
+
calibrationCurve.data.points,
|
|
900
|
+
options.includeQc !== false,
|
|
901
|
+
),
|
|
902
|
+
method: options.method ?? 'Targeted metabolomics',
|
|
903
|
+
instrument: options.instrument ?? 'LC-MS',
|
|
904
|
+
includeBlanks: false,
|
|
905
|
+
includeQc: false,
|
|
906
|
+
metadata: { assay: 'targeted-metabolomics' },
|
|
907
|
+
})
|
|
908
|
+
const assayMatrix = createAssayMatrixTemplate({
|
|
909
|
+
samples: sampleRecords.map(sample => ({
|
|
910
|
+
sampleId: sample.sampleId,
|
|
911
|
+
name: sample.name,
|
|
912
|
+
group: sample.group,
|
|
913
|
+
metadata: sample.metadata ?? {},
|
|
914
|
+
})),
|
|
915
|
+
features: metaboliteFeatures,
|
|
916
|
+
metadata: { assay: 'targeted-metabolomics', responseUnit },
|
|
917
|
+
})
|
|
918
|
+
return createTemplateCollection(
|
|
919
|
+
[sampleSheet, samplePrep, reagents, instrumentRun, calibrationCurve, assayMatrix],
|
|
920
|
+
{ preset: 'targeted-metabolomics', ...(options.metadata ?? {}) }
|
|
921
|
+
)
|
|
922
|
+
}
|
|
923
|
+
|
|
861
924
|
export function createElisaAssayCollection(
|
|
862
925
|
options: CreateElisaAssayCollectionOptions = {}
|
|
863
926
|
): TemplateCollectionEnvelope {
|
|
@@ -1009,6 +1072,10 @@ export function createBioTemplatePresetCollection(
|
|
|
1009
1072
|
name: 'lcms-batch',
|
|
1010
1073
|
options?: CreateLcmsBatchCollectionOptions
|
|
1011
1074
|
): TemplateCollectionEnvelope
|
|
1075
|
+
export function createBioTemplatePresetCollection(
|
|
1076
|
+
name: 'targeted-metabolomics',
|
|
1077
|
+
options?: CreateTargetedMetabolomicsCollectionOptions
|
|
1078
|
+
): TemplateCollectionEnvelope
|
|
1012
1079
|
export function createBioTemplatePresetCollection(
|
|
1013
1080
|
name: 'elisa-assay',
|
|
1014
1081
|
options?: CreateElisaAssayCollectionOptions
|
|
@@ -1027,6 +1094,7 @@ export function createBioTemplatePresetCollection(
|
|
|
1027
1094
|
| CreateWellPlateScreenCollectionOptions
|
|
1028
1095
|
| CreateQpcrExpressionCollectionOptions
|
|
1029
1096
|
| CreateLcmsBatchCollectionOptions
|
|
1097
|
+
| CreateTargetedMetabolomicsCollectionOptions
|
|
1030
1098
|
| CreateElisaAssayCollectionOptions
|
|
1031
1099
|
| CreateFlowCytometryAssayCollectionOptions
|
|
1032
1100
|
| CreateWesternBlotAssayCollectionOptions
|
|
@@ -1037,6 +1105,7 @@ export function createBioTemplatePresetCollection(
|
|
|
1037
1105
|
| CreateWellPlateScreenCollectionOptions
|
|
1038
1106
|
| CreateQpcrExpressionCollectionOptions
|
|
1039
1107
|
| CreateLcmsBatchCollectionOptions
|
|
1108
|
+
| CreateTargetedMetabolomicsCollectionOptions
|
|
1040
1109
|
| CreateElisaAssayCollectionOptions
|
|
1041
1110
|
| CreateFlowCytometryAssayCollectionOptions
|
|
1042
1111
|
| CreateWesternBlotAssayCollectionOptions = {}
|
|
@@ -1054,6 +1123,9 @@ export function createBioTemplatePresetCollection(
|
|
|
1054
1123
|
if (preset.name === 'lcms-batch') {
|
|
1055
1124
|
return createLcmsBatchCollection(options as CreateLcmsBatchCollectionOptions)
|
|
1056
1125
|
}
|
|
1126
|
+
if (preset.name === 'targeted-metabolomics') {
|
|
1127
|
+
return createTargetedMetabolomicsCollection(options as CreateTargetedMetabolomicsCollectionOptions)
|
|
1128
|
+
}
|
|
1057
1129
|
if (preset.name === 'elisa-assay') {
|
|
1058
1130
|
return createElisaAssayCollection(options as CreateElisaAssayCollectionOptions)
|
|
1059
1131
|
}
|
|
@@ -1080,6 +1152,10 @@ export function bioTemplatePresetControlValuesToOptions(
|
|
|
1080
1152
|
name: 'lcms-batch',
|
|
1081
1153
|
values: BioTemplateControlValues
|
|
1082
1154
|
): CreateLcmsBatchCollectionOptions
|
|
1155
|
+
export function bioTemplatePresetControlValuesToOptions(
|
|
1156
|
+
name: 'targeted-metabolomics',
|
|
1157
|
+
values: BioTemplateControlValues
|
|
1158
|
+
): CreateTargetedMetabolomicsCollectionOptions
|
|
1083
1159
|
export function bioTemplatePresetControlValuesToOptions(
|
|
1084
1160
|
name: 'elisa-assay',
|
|
1085
1161
|
values: BioTemplateControlValues
|
|
@@ -1099,6 +1175,7 @@ export function bioTemplatePresetControlValuesToOptions(
|
|
|
1099
1175
|
| CreateWellPlateScreenCollectionOptions
|
|
1100
1176
|
| CreateQpcrExpressionCollectionOptions
|
|
1101
1177
|
| CreateLcmsBatchCollectionOptions
|
|
1178
|
+
| CreateTargetedMetabolomicsCollectionOptions
|
|
1102
1179
|
| CreateElisaAssayCollectionOptions
|
|
1103
1180
|
| CreateFlowCytometryAssayCollectionOptions
|
|
1104
1181
|
| CreateWesternBlotAssayCollectionOptions
|
|
@@ -1109,6 +1186,7 @@ export function bioTemplatePresetControlValuesToOptions(
|
|
|
1109
1186
|
| CreateWellPlateScreenCollectionOptions
|
|
1110
1187
|
| CreateQpcrExpressionCollectionOptions
|
|
1111
1188
|
| CreateLcmsBatchCollectionOptions
|
|
1189
|
+
| CreateTargetedMetabolomicsCollectionOptions
|
|
1112
1190
|
| CreateElisaAssayCollectionOptions
|
|
1113
1191
|
| CreateFlowCytometryAssayCollectionOptions
|
|
1114
1192
|
| CreateWesternBlotAssayCollectionOptions {
|
|
@@ -1149,6 +1227,26 @@ export function bioTemplatePresetControlValuesToOptions(
|
|
|
1149
1227
|
}
|
|
1150
1228
|
}
|
|
1151
1229
|
|
|
1230
|
+
if (preset.name === 'targeted-metabolomics') {
|
|
1231
|
+
return {
|
|
1232
|
+
samples: readStringList(values.sampleNames, ['S001', 'S002']),
|
|
1233
|
+
metabolites: readStringList(values.metaboliteNames, ['Glucose', 'Lactate', 'Pyruvate']),
|
|
1234
|
+
internalStandards: readStringList(
|
|
1235
|
+
values.internalStandards,
|
|
1236
|
+
['Stable isotope internal standard mix'],
|
|
1237
|
+
),
|
|
1238
|
+
standardConcentrations: readNumberList(values.standardConcentrations, [0.1, 1, 10, 100]),
|
|
1239
|
+
concentrationUnit: readString(values.concentrationUnit, 'uM'),
|
|
1240
|
+
responseUnit: readString(values.responseUnit, 'peak area ratio'),
|
|
1241
|
+
calibrationAnalyte: readOptionalString(values.calibrationAnalyte),
|
|
1242
|
+
instrument: readString(values.instrument, 'LC-MS'),
|
|
1243
|
+
method: readString(values.method, 'Targeted metabolomics'),
|
|
1244
|
+
prepType: readString(values.prepType, 'extraction') as CreateSamplePrepTemplateOptions['prepType'],
|
|
1245
|
+
outputVolume: readNumber(values.outputVolume, 50),
|
|
1246
|
+
includeQc: readBoolean(values.includeQc, true),
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1152
1250
|
if (preset.name === 'elisa-assay') {
|
|
1153
1251
|
return {
|
|
1154
1252
|
samples: readStringList(values.sampleNames, ['Control', 'Treatment']),
|
|
@@ -1194,6 +1292,10 @@ export function createBioTemplatePresetCollectionFromControls(
|
|
|
1194
1292
|
name: 'lcms-batch',
|
|
1195
1293
|
values: BioTemplateControlValues
|
|
1196
1294
|
): TemplateCollectionEnvelope
|
|
1295
|
+
export function createBioTemplatePresetCollectionFromControls(
|
|
1296
|
+
name: 'targeted-metabolomics',
|
|
1297
|
+
values: BioTemplateControlValues
|
|
1298
|
+
): TemplateCollectionEnvelope
|
|
1197
1299
|
export function createBioTemplatePresetCollectionFromControls(
|
|
1198
1300
|
name: 'elisa-assay',
|
|
1199
1301
|
values: BioTemplateControlValues
|
|
@@ -1863,6 +1965,96 @@ function normalizeReagent(reagent: ReagentTemplateInput): ReagentRecord {
|
|
|
1863
1965
|
}
|
|
1864
1966
|
}
|
|
1865
1967
|
|
|
1968
|
+
function normalizeMetaboliteFeatures(
|
|
1969
|
+
metabolites: Array<string | AssayFeature>,
|
|
1970
|
+
responseUnit: string,
|
|
1971
|
+
): AssayFeature[] {
|
|
1972
|
+
return metabolites.map((metabolite, index) => {
|
|
1973
|
+
if (typeof metabolite === 'string') {
|
|
1974
|
+
return {
|
|
1975
|
+
id: idFromName(metabolite, `metabolite-${index + 1}`),
|
|
1976
|
+
name: metabolite,
|
|
1977
|
+
type: 'metabolite',
|
|
1978
|
+
unit: responseUnit,
|
|
1979
|
+
metadata: { quantitation: 'targeted' },
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
const feature = normalizeAssayFeature(metabolite)
|
|
1984
|
+
return {
|
|
1985
|
+
...feature,
|
|
1986
|
+
type: feature.type ?? 'metabolite',
|
|
1987
|
+
unit: feature.unit ?? responseUnit,
|
|
1988
|
+
metadata: {
|
|
1989
|
+
quantitation: 'targeted',
|
|
1990
|
+
...feature.metadata,
|
|
1991
|
+
},
|
|
1992
|
+
}
|
|
1993
|
+
})
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
function normalizeInternalStandardReagents(
|
|
1997
|
+
internalStandards: Array<string | ReagentTemplateInput>,
|
|
1998
|
+
): ReagentTemplateInput[] {
|
|
1999
|
+
return internalStandards.map((standard, index) => {
|
|
2000
|
+
if (typeof standard === 'string') {
|
|
2001
|
+
return {
|
|
2002
|
+
id: idFromName(standard, `internal-standard-${index + 1}`),
|
|
2003
|
+
name: standard,
|
|
2004
|
+
kind: 'compound',
|
|
2005
|
+
metadata: { role: 'internal-standard' },
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
const reagent = normalizeReagent(standard)
|
|
2010
|
+
return {
|
|
2011
|
+
...reagent,
|
|
2012
|
+
kind: standard.kind ?? 'compound',
|
|
2013
|
+
metadata: {
|
|
2014
|
+
role: 'internal-standard',
|
|
2015
|
+
...reagent.metadata,
|
|
2016
|
+
},
|
|
2017
|
+
}
|
|
2018
|
+
})
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
function targetedMetabolomicsRunItems(
|
|
2022
|
+
samples: SampleRecord[],
|
|
2023
|
+
calibrationPoints: CalibrationPoint[],
|
|
2024
|
+
includeQc: boolean,
|
|
2025
|
+
): InstrumentRunItemInput[] {
|
|
2026
|
+
const calibrationItems = calibrationPoints
|
|
2027
|
+
.filter(point => point.role !== 'qc' || includeQc)
|
|
2028
|
+
.filter(point => point.role === 'blank' || point.role === 'standard' || point.role === 'qc')
|
|
2029
|
+
.map((point): InstrumentRunItemInput => ({
|
|
2030
|
+
id: `${point.id}-run`,
|
|
2031
|
+
kind: calibrationRunItemKind(point.role),
|
|
2032
|
+
name: point.level,
|
|
2033
|
+
metadata: {
|
|
2034
|
+
concentration: point.concentration,
|
|
2035
|
+
unit: point.unit,
|
|
2036
|
+
role: point.role,
|
|
2037
|
+
},
|
|
2038
|
+
}))
|
|
2039
|
+
|
|
2040
|
+
const sampleItems = samples.map((sample): InstrumentRunItemInput => ({
|
|
2041
|
+
sampleId: sample.sampleId,
|
|
2042
|
+
name: sample.name ?? sample.sampleId,
|
|
2043
|
+
kind: 'sample',
|
|
2044
|
+
}))
|
|
2045
|
+
|
|
2046
|
+
return [...calibrationItems, ...sampleItems]
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
function calibrationRunItemKind(role: CalibrationPoint['role']): 'blank' | 'standard' | 'qc' {
|
|
2050
|
+
if (role === 'blank' || role === 'standard' || role === 'qc') return role
|
|
2051
|
+
return 'standard'
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
function firstFeatureName(features: AssayFeature[], fallback: string): string {
|
|
2055
|
+
return features.find(feature => feature.name)?.name ?? fallback
|
|
2056
|
+
}
|
|
2057
|
+
|
|
1866
2058
|
function normalizeDateString(value: Date | string | null | undefined): string | undefined {
|
|
1867
2059
|
if (value === undefined || value === null) return undefined
|
|
1868
2060
|
return value instanceof Date ? value.toISOString() : value
|
|
@@ -2114,6 +2306,15 @@ function readInteger(value: unknown, fallback: number): number {
|
|
|
2114
2306
|
return Number.isFinite(parsed) ? Math.max(1, Math.round(parsed)) : fallback
|
|
2115
2307
|
}
|
|
2116
2308
|
|
|
2309
|
+
function readNumber(value: unknown, fallback: number): number {
|
|
2310
|
+
const parsed = typeof value === 'number'
|
|
2311
|
+
? value
|
|
2312
|
+
: typeof value === 'string'
|
|
2313
|
+
? Number(value)
|
|
2314
|
+
: Number.NaN
|
|
2315
|
+
return Number.isFinite(parsed) ? parsed : fallback
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2117
2318
|
function readBoolean(value: unknown, fallback: boolean): boolean {
|
|
2118
2319
|
return typeof value === 'boolean' ? value : fallback
|
|
2119
2320
|
}
|
|
@@ -412,6 +412,74 @@ const presetControlSchemas = {
|
|
|
412
412
|
...templateControlSchemas['instrument-run'],
|
|
413
413
|
...templateControlSchemas['assay-matrix'],
|
|
414
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
|
+
},
|
|
415
483
|
'elisa-assay': {
|
|
416
484
|
sampleNames: {
|
|
417
485
|
type: 'tags',
|
package/src/templates/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export {
|
|
|
20
20
|
createReagentListTemplate,
|
|
21
21
|
createSampleSheetTemplate,
|
|
22
22
|
createSamplePrepTemplate,
|
|
23
|
+
createTargetedMetabolomicsCollection,
|
|
23
24
|
createTemplateCollection,
|
|
24
25
|
createDefaultBioTemplate,
|
|
25
26
|
createTimeCourseTemplate,
|
|
@@ -186,6 +187,7 @@ export type {
|
|
|
186
187
|
CreateFlowCytometryPanelTemplateOptions,
|
|
187
188
|
CreateInstrumentRunTemplateOptions,
|
|
188
189
|
CreateLcmsBatchCollectionOptions,
|
|
190
|
+
CreateTargetedMetabolomicsCollectionOptions,
|
|
189
191
|
CreatePlateMapTemplateOptions,
|
|
190
192
|
CreateProtocolStepsTemplateOptions,
|
|
191
193
|
CreateQpcrExpressionCollectionOptions,
|
package/src/templates/presets.ts
CHANGED
|
@@ -74,6 +74,29 @@ export const bioTemplatePresets = [
|
|
|
74
74
|
frontend_adapters: ['toTemplateDataFrame', 'toInstrumentRunDataFrame', 'toInstrumentRunSteps', 'toInstrumentRunScheduleEvents', 'toAssayMatrixDataFrame', 'toAssayMatrixSampleOptions'],
|
|
75
75
|
components: ['DataFrame', 'ExperimentTimeline', 'ScheduleCalendar', 'ChartContainer', 'SampleSelector'],
|
|
76
76
|
},
|
|
77
|
+
{
|
|
78
|
+
name: 'targeted-metabolomics',
|
|
79
|
+
label: 'Targeted metabolomics',
|
|
80
|
+
category: 'bio-template-preset',
|
|
81
|
+
purpose: 'Sample metadata, extraction prep, internal standards, LC/GC-MS sequence, calibration curve, and metabolite readout matrix for quantitative metabolomics.',
|
|
82
|
+
templates: ['sample-sheet', 'sample-prep', 'reagent-list', 'instrument-run', 'calibration-curve', 'assay-matrix'],
|
|
83
|
+
aliases: [
|
|
84
|
+
'targeted metabolomics',
|
|
85
|
+
'quantitative metabolomics',
|
|
86
|
+
'lc-ms metabolomics',
|
|
87
|
+
'gc-ms metabolomics',
|
|
88
|
+
'targeted lcms',
|
|
89
|
+
'metabolite quantitation',
|
|
90
|
+
'mass spec quantitation',
|
|
91
|
+
'internal standards',
|
|
92
|
+
'peak area ratio',
|
|
93
|
+
],
|
|
94
|
+
python_import: 'from mint_sdk.templates import create_targeted_metabolomics_collection, save_template_collection',
|
|
95
|
+
python_example: 'create_targeted_metabolomics_collection(samples=["S001", "S002"], metabolites=["Glucose", "Lactate"], internal_standards=["13C Glucose"], instrument="LC-MS")',
|
|
96
|
+
frontend_import: "import { createTargetedMetabolomicsCollection, toInstrumentRunDataFrame, toCalibrationCurveDataFrame, toAssayMatrixDataFrame, toTemplateDataFrame } from '@morscherlab/mint-sdk/templates'",
|
|
97
|
+
frontend_adapters: ['toTemplateDataFrame', 'toSamplePrepDataFrame', 'toReagentDataFrame', 'toInstrumentRunDataFrame', 'toInstrumentRunSteps', 'toInstrumentRunScheduleEvents', 'toCalibrationCurveDataFrame', 'toAssayMatrixDataFrame', 'toAssayMatrixSampleOptions'],
|
|
98
|
+
components: ['DataFrame', 'ReagentList', 'ExperimentTimeline', 'ScheduleCalendar', 'FitPanel', 'ChartContainer', 'SampleSelector'],
|
|
99
|
+
},
|
|
77
100
|
{
|
|
78
101
|
name: 'elisa-assay',
|
|
79
102
|
label: 'ELISA assay',
|
package/src/templates/types.ts
CHANGED
|
@@ -31,6 +31,7 @@ export type TemplatePresetId =
|
|
|
31
31
|
| 'wellplate-screen'
|
|
32
32
|
| 'qpcr-expression'
|
|
33
33
|
| 'lcms-batch'
|
|
34
|
+
| 'targeted-metabolomics'
|
|
34
35
|
| 'elisa-assay'
|
|
35
36
|
| 'flow-cytometry-assay'
|
|
36
37
|
| 'western-blot-assay'
|
|
@@ -596,6 +597,22 @@ export interface CreateLcmsBatchCollectionOptions {
|
|
|
596
597
|
metadata?: Record<string, unknown>
|
|
597
598
|
}
|
|
598
599
|
|
|
600
|
+
export interface CreateTargetedMetabolomicsCollectionOptions {
|
|
601
|
+
samples?: Array<string | SampleRecord>
|
|
602
|
+
metabolites?: Array<string | AssayFeature>
|
|
603
|
+
internalStandards?: Array<string | ReagentTemplateInput>
|
|
604
|
+
standardConcentrations?: number[]
|
|
605
|
+
concentrationUnit?: string
|
|
606
|
+
responseUnit?: string
|
|
607
|
+
calibrationAnalyte?: string
|
|
608
|
+
instrument?: string
|
|
609
|
+
method?: string | InstrumentMethodInput
|
|
610
|
+
prepType?: SamplePrepStepType
|
|
611
|
+
outputVolume?: number
|
|
612
|
+
includeQc?: boolean
|
|
613
|
+
metadata?: Record<string, unknown>
|
|
614
|
+
}
|
|
615
|
+
|
|
599
616
|
export interface CreateElisaAssayCollectionOptions {
|
|
600
617
|
samples?: Array<string | SampleRecord>
|
|
601
618
|
analyte?: string
|
package/src/types/auth.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { RoleInfo } from '../permissions'
|
|
2
|
+
|
|
1
3
|
// Authentication configuration
|
|
2
4
|
export interface AuthConfig {
|
|
3
5
|
authRequired: boolean
|
|
@@ -14,6 +16,7 @@ export interface UserInfo {
|
|
|
14
16
|
shortname: string | null
|
|
15
17
|
email: string | null
|
|
16
18
|
role: string
|
|
19
|
+
roleObj?: RoleInfo | null
|
|
17
20
|
isActive: boolean
|
|
18
21
|
}
|
|
19
22
|
|