@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.
- 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/AppSidebar.vue.d.ts +3 -3
- 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/ControlWorkspaceView.vue.d.ts +3 -3
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +2 -2
- 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/PluginWorkspaceView.vue.d.ts +3 -3
- 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-DafPc4rM.js} +2091 -1051
- package/dist/components-DafPc4rM.js.map +1 -0
- package/dist/composables/controlComponentBindings.d.ts +7 -0
- package/dist/composables/controlSchemaAdapters.d.ts +20 -0
- package/dist/composables/controlSchemaFormFields.d.ts +3 -0
- package/dist/composables/controlSchemaLayout.d.ts +7 -0
- package/dist/composables/controlSchemaNormalize.d.ts +15 -0
- package/dist/composables/controlSchemaUtils.d.ts +9 -0
- package/dist/composables/controlWorkspaceOptions.d.ts +2 -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 +15 -30
- package/dist/composables/useControlWorkspace.d.ts +5 -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-BMkPQhVK.js} +5 -3
- package/dist/composables-BMkPQhVK.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/adapters.d.ts +14 -47
- package/dist/templates/assayLookups.d.ts +3 -0
- package/dist/templates/assayMatrixAdapters.d.ts +6 -0
- package/dist/templates/assayMatrixBuilder.d.ts +2 -0
- package/dist/templates/assayNormalizers.d.ts +4 -0
- package/dist/templates/builderDefaults.d.ts +1 -0
- package/dist/templates/builderIdUtils.d.ts +4 -0
- package/dist/templates/builderPresetControls.d.ts +10 -0
- package/dist/templates/builderReadUtils.d.ts +8 -0
- package/dist/templates/builders.d.ts +26 -63
- package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
- package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
- package/dist/templates/calibrationNormalizers.d.ts +5 -0
- package/dist/templates/componentBindingCatalog.d.ts +25 -0
- package/dist/templates/componentBindingHelpers.d.ts +17 -0
- package/dist/templates/componentDoseResponseProps.d.ts +3 -0
- package/dist/templates/componentGenericProps.d.ts +8 -0
- package/dist/templates/componentPlateHelpers.d.ts +5 -0
- package/dist/templates/componentPlateMapProps.d.ts +3 -0
- package/dist/templates/componentPropsFactory.d.ts +3 -0
- package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
- package/dist/templates/componentTargetResolvers.d.ts +5 -0
- package/dist/templates/componentTemplateProps.d.ts +3 -0
- package/dist/templates/controlSchemaClone.d.ts +4 -0
- package/dist/templates/controlSchemaConstants.d.ts +10 -0
- package/dist/templates/controlSchemaMerge.d.ts +3 -0
- package/dist/templates/controlSchemaTargets.d.ts +17 -0
- package/dist/templates/controlSchemaTypes.d.ts +4 -0
- package/dist/templates/controlSchemas.d.ts +4 -4
- package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
- package/dist/templates/doseResponseAdapters.d.ts +4 -0
- package/dist/templates/doseResponseBuilder.d.ts +2 -0
- package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
- package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
- package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
- package/dist/templates/flowNormalizers.d.ts +8 -0
- package/dist/templates/flowPanelAdapters.d.ts +4 -0
- package/dist/templates/index.d.ts +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
- package/dist/templates/instrumentRunAdapters.d.ts +8 -0
- package/dist/templates/instrumentRunBuilder.d.ts +2 -0
- package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
- package/dist/templates/plateGeometry.d.ts +4 -0
- package/dist/templates/plateMapAdapters.d.ts +3 -0
- package/dist/templates/plateMapBuilder.d.ts +2 -0
- package/dist/templates/presetControlSchemas.d.ts +534 -0
- package/dist/templates/presets.d.ts +12 -0
- package/dist/templates/protocolAdapters.d.ts +5 -0
- package/dist/templates/protocolNormalizers.d.ts +6 -0
- package/dist/templates/protocolStepsBuilder.d.ts +2 -0
- package/dist/templates/qpcrAdapters.d.ts +5 -0
- package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
- package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
- package/dist/templates/reagentAdapters.d.ts +5 -0
- package/dist/templates/reagentListBuilder.d.ts +2 -0
- package/dist/templates/runNormalizers.d.ts +10 -0
- package/dist/templates/sampleNormalizers.d.ts +4 -0
- package/dist/templates/samplePrepAdapters.d.ts +4 -0
- package/dist/templates/samplePrepBuilder.d.ts +2 -0
- package/dist/templates/sampleSheetAdapters.d.ts +5 -0
- package/dist/templates/sampleSheetBuilder.d.ts +2 -0
- package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
- package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
- package/dist/templates/templateControlSchemas.d.ts +400 -0
- package/dist/templates/templateEnvelopes.d.ts +9 -0
- package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
- package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
- package/dist/templates/templateValidators.d.ts +13 -0
- package/dist/templates/timeCourseAdapters.d.ts +5 -0
- package/dist/templates/timeCourseBuilder.d.ts +2 -0
- package/dist/templates/types.d.ts +16 -1
- package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
- package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
- package/dist/{templates-BSlxwV2c.js → templates-bUAWMn5L.js} +3610 -3154
- package/dist/templates-bUAWMn5L.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-QZtHFFH2.js} +534 -359
- package/dist/useProtocolTemplates-QZtHFFH2.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/controlComponentBindings.ts +80 -0
- package/src/composables/controlSchemaAdapters.ts +196 -0
- package/src/composables/controlSchemaFormFields.ts +61 -0
- package/src/composables/controlSchemaLayout.ts +59 -0
- package/src/composables/controlSchemaNormalize.ts +101 -0
- package/src/composables/controlSchemaUtils.ts +36 -0
- package/src/composables/controlWorkspaceOptions.ts +21 -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 +62 -618
- package/src/composables/useControlWorkspace.ts +207 -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/adapters.ts +89 -930
- package/src/templates/assayLookups.ts +33 -0
- package/src/templates/assayMatrixAdapters.ts +78 -0
- package/src/templates/assayMatrixBuilder.ts +59 -0
- package/src/templates/assayNormalizers.ts +34 -0
- package/src/templates/builderDefaults.ts +11 -0
- package/src/templates/builderIdUtils.ts +20 -0
- package/src/templates/builderPresetControls.ts +165 -0
- package/src/templates/builderReadUtils.ts +57 -0
- package/src/templates/builders.ts +122 -2149
- package/src/templates/calibrationCurveAdapters.ts +59 -0
- package/src/templates/calibrationCurveBuilder.ts +99 -0
- package/src/templates/calibrationNormalizers.ts +60 -0
- package/src/templates/componentBindingCatalog.ts +90 -0
- package/src/templates/componentBindingHelpers.ts +93 -0
- package/src/templates/componentBindings.ts +12 -461
- package/src/templates/componentDoseResponseProps.ts +42 -0
- package/src/templates/componentGenericProps.ts +77 -0
- package/src/templates/componentPlateHelpers.ts +29 -0
- package/src/templates/componentPlateMapProps.ts +32 -0
- package/src/templates/componentPropsFactory.ts +21 -0
- package/src/templates/componentQpcrPlateProps.ts +28 -0
- package/src/templates/componentTargetResolvers.ts +69 -0
- package/src/templates/componentTemplateProps.ts +78 -0
- package/src/templates/controlSchemaClone.ts +32 -0
- package/src/templates/controlSchemaConstants.ts +11 -0
- package/src/templates/controlSchemaMerge.ts +40 -0
- package/src/templates/controlSchemaTargets.ts +87 -0
- package/src/templates/controlSchemaTypes.ts +20 -0
- package/src/templates/controlSchemas.ts +22 -636
- package/src/templates/defaultBioTemplateBuilder.ts +124 -0
- package/src/templates/doseResponseAdapters.ts +45 -0
- package/src/templates/doseResponseBuilder.ts +44 -0
- package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
- package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
- package/src/templates/flowCytometryPanelBuilder.ts +53 -0
- package/src/templates/flowNormalizers.ts +58 -0
- package/src/templates/flowPanelAdapters.ts +58 -0
- package/src/templates/index.ts +2 -0
- package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
- package/src/templates/instrumentRunAdapters.ts +163 -0
- package/src/templates/instrumentRunBuilder.ts +97 -0
- package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
- package/src/templates/plateGeometry.ts +62 -0
- package/src/templates/plateMapAdapters.ts +36 -0
- package/src/templates/plateMapBuilder.ts +43 -0
- package/src/templates/presetControlSchemas.ts +258 -0
- package/src/templates/presets.ts +23 -0
- package/src/templates/protocolAdapters.ts +69 -0
- package/src/templates/protocolNormalizers.ts +37 -0
- package/src/templates/protocolStepsBuilder.ts +36 -0
- package/src/templates/qpcrAdapters.ts +104 -0
- package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
- package/src/templates/qpcrPlateBuilder.ts +96 -0
- package/src/templates/reagentAdapters.ts +77 -0
- package/src/templates/reagentListBuilder.ts +30 -0
- package/src/templates/runNormalizers.ts +63 -0
- package/src/templates/sampleNormalizers.ts +58 -0
- package/src/templates/samplePrepAdapters.ts +63 -0
- package/src/templates/samplePrepBuilder.ts +51 -0
- package/src/templates/sampleSheetAdapters.ts +75 -0
- package/src/templates/sampleSheetBuilder.ts +23 -0
- package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
- package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
- package/src/templates/templateControlSchemas.ts +320 -0
- package/src/templates/templateEnvelopes.ts +137 -0
- package/src/templates/templatePackCollectionBuilder.ts +23 -0
- package/src/templates/templatePresetCollectionBuilder.ts +139 -0
- package/src/templates/templateValidators.ts +414 -0
- package/src/templates/timeCourseAdapters.ts +73 -0
- package/src/templates/timeCourseBuilder.ts +64 -0
- package/src/templates/types.ts +17 -0
- package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
- package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -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
|
@@ -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
|
-
<
|
|
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 }}
|