@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
package/src/lcms.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { LcmsPlateCell, LcmsPlateType } from './utils/rack'
|
|
2
|
+
|
|
3
|
+
export type LcmsPolarity = 'POS' | 'NEG' | 'BOTH'
|
|
4
|
+
export type LcmsContainerType = 'VIAL' | 'PLATE'
|
|
5
|
+
|
|
6
|
+
export interface LcmsSequenceItem {
|
|
7
|
+
sample_type: string
|
|
8
|
+
file_name: string
|
|
9
|
+
sample_id: string
|
|
10
|
+
path: string
|
|
11
|
+
instrument_method: string
|
|
12
|
+
position: string
|
|
13
|
+
injection_volume: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LcmsSequenceTableColumn {
|
|
17
|
+
key: keyof LcmsSequenceItem | 'index' | 'actions'
|
|
18
|
+
label: string
|
|
19
|
+
align?: 'left' | 'right'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_LCMS_SEQUENCE_COLUMNS: LcmsSequenceTableColumn[] = [
|
|
23
|
+
{ key: 'index', label: '#' },
|
|
24
|
+
{ key: 'sample_type', label: 'Type' },
|
|
25
|
+
{ key: 'file_name', label: 'File Name' },
|
|
26
|
+
{ key: 'position', label: 'Position' },
|
|
27
|
+
{ key: 'instrument_method', label: 'Method' },
|
|
28
|
+
{ key: 'injection_volume', label: 'Inj Vol', align: 'right' },
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
export function extractLcmsCommonPrefix(fileNames: readonly string[]): string {
|
|
32
|
+
if (fileNames.length === 0) return ''
|
|
33
|
+
const stripped = fileNames.map(fileName => fileName.replace(/_\d{3}$/, ''))
|
|
34
|
+
const prefixes = stripped.map((fileName) => {
|
|
35
|
+
const match = fileName.match(/^(.+?)_(POS|NEG)_/i)
|
|
36
|
+
return match ? match[1] : fileName.replace(/_[^_]+$/, '')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
let common = prefixes[0] ?? ''
|
|
40
|
+
for (const prefix of prefixes.slice(1)) {
|
|
41
|
+
while (common && !prefix.startsWith(common)) {
|
|
42
|
+
const index = common.lastIndexOf('_')
|
|
43
|
+
common = index > 0 ? common.substring(0, index) : common.substring(0, common.length - 1)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return common
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function extractLcmsSampleName(fileName: string, prefix = ''): string {
|
|
50
|
+
let name = fileName.replace(/_\d{3}$/, '')
|
|
51
|
+
if (prefix && name.startsWith(prefix)) {
|
|
52
|
+
name = name.substring(prefix.length).replace(/^_+/, '')
|
|
53
|
+
}
|
|
54
|
+
name = name.replace(/^(POS|NEG)_/i, '')
|
|
55
|
+
return name || fileName
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function lcmsWellIdFromPosition(position: string): string {
|
|
59
|
+
return position.includes(':') ? position.split(':').pop() ?? position : position
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function inferLcmsPlateTypeFromWellIds(wellIds: readonly string[]): LcmsPlateType | null {
|
|
63
|
+
let maxCol = 0
|
|
64
|
+
let maxRow = 0
|
|
65
|
+
for (const wellId of wellIds) {
|
|
66
|
+
const match = wellId.match(/^([A-Z])(\d+)$/i)
|
|
67
|
+
if (!match) continue
|
|
68
|
+
maxRow = Math.max(maxRow, match[1].toUpperCase().charCodeAt(0) - 64)
|
|
69
|
+
maxCol = Math.max(maxCol, Number(match[2]))
|
|
70
|
+
}
|
|
71
|
+
if (maxCol === 0 && maxRow === 0) return null
|
|
72
|
+
return maxCol <= 9 && maxRow <= 6 ? '54vial' : '96well'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function reconstructLcmsPlateCellsFromSequenceItems(
|
|
76
|
+
items: readonly LcmsSequenceItem[],
|
|
77
|
+
): { cells: LcmsPlateCell[]; plateType: LcmsPlateType } | null {
|
|
78
|
+
const unknownItems = items.filter(item => item.sample_type === 'Unknown')
|
|
79
|
+
if (unknownItems.length === 0) return null
|
|
80
|
+
|
|
81
|
+
const prefix = extractLcmsCommonPrefix(unknownItems.map(item => item.file_name))
|
|
82
|
+
const seen = new Set<string>()
|
|
83
|
+
const cells: LcmsPlateCell[] = []
|
|
84
|
+
|
|
85
|
+
for (const item of unknownItems) {
|
|
86
|
+
const wellId = lcmsWellIdFromPosition(item.position)
|
|
87
|
+
if (seen.has(wellId)) continue
|
|
88
|
+
seen.add(wellId)
|
|
89
|
+
|
|
90
|
+
const match = wellId.match(/^([A-Z])(\d+)$/i)
|
|
91
|
+
if (!match) continue
|
|
92
|
+
cells.push({
|
|
93
|
+
row: match[1].toUpperCase(),
|
|
94
|
+
column: Number(match[2]),
|
|
95
|
+
sample_name: extractLcmsSampleName(item.file_name, prefix),
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (cells.length === 0) return null
|
|
100
|
+
const plateType = inferLcmsPlateTypeFromWellIds(cells.map(cell => `${cell.row}${cell.column}`))
|
|
101
|
+
if (!plateType) return null
|
|
102
|
+
return { cells, plateType }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function basenameFromWindowsPath(path: string | null | undefined): string {
|
|
106
|
+
if (!path) return ''
|
|
107
|
+
return path.split(/[\\/]/).pop() ?? path
|
|
108
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const ADMIN_ROLE = 'admin'
|
|
2
|
+
|
|
3
|
+
export const ADMIN_PANEL_PERMISSIONS = [
|
|
4
|
+
'users.view',
|
|
5
|
+
'users.invite',
|
|
6
|
+
'users.manage',
|
|
7
|
+
'platform.configure',
|
|
8
|
+
'platform.view_logs',
|
|
9
|
+
'plugins.configure',
|
|
10
|
+
'plugins.install',
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
export type AccessAudience = 'all' | 'admin' | 'user'
|
|
14
|
+
export type AccessAudienceInput = AccessAudience | readonly AccessAudience[]
|
|
15
|
+
|
|
16
|
+
export interface RoleInfo {
|
|
17
|
+
id?: number
|
|
18
|
+
slug: string
|
|
19
|
+
name?: string
|
|
20
|
+
color?: string
|
|
21
|
+
permissions?: readonly string[] | null
|
|
22
|
+
project_scope?: 'all' | 'assigned' | string
|
|
23
|
+
plugin_access?: readonly string[] | 'all' | null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PermissionUser {
|
|
27
|
+
role?: string | null
|
|
28
|
+
role_obj?: RoleInfo | null
|
|
29
|
+
roleObj?: RoleInfo | null
|
|
30
|
+
permissions?: readonly string[] | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AccessPolicy {
|
|
34
|
+
audience?: AccessAudienceInput
|
|
35
|
+
visibleFor?: AccessAudienceInput
|
|
36
|
+
requiresAuth?: boolean
|
|
37
|
+
requiresAdmin?: boolean
|
|
38
|
+
permissions?: readonly string[]
|
|
39
|
+
anyPermissions?: readonly string[]
|
|
40
|
+
plugin?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AccessControlled {
|
|
44
|
+
access?: AccessPolicy
|
|
45
|
+
visibleFor?: AccessAudienceInput
|
|
46
|
+
requiresAdmin?: boolean
|
|
47
|
+
permissions?: readonly string[]
|
|
48
|
+
anyPermissions?: readonly string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getRoleInfo(user: PermissionUser | null | undefined): RoleInfo | null {
|
|
52
|
+
return user?.roleObj ?? user?.role_obj ?? null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isAdminRole(role: string | null | undefined): boolean {
|
|
56
|
+
return role === ADMIN_ROLE
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function isAdminUser(user: PermissionUser | null | undefined): boolean {
|
|
60
|
+
return isAdminRole(user?.role) || getRoleInfo(user)?.slug === ADMIN_ROLE
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getAccessAudience(user: PermissionUser | null | undefined): Exclude<AccessAudience, 'all'> {
|
|
64
|
+
return isAdminUser(user) ? 'admin' : 'user'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getUserPermissions(user: PermissionUser | null | undefined): string[] {
|
|
68
|
+
const rolePermissions = getRoleInfo(user)?.permissions
|
|
69
|
+
if (rolePermissions?.length) return [...rolePermissions]
|
|
70
|
+
return [...(user?.permissions ?? [])]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function hasAllPermissions(
|
|
74
|
+
user: PermissionUser | null | undefined,
|
|
75
|
+
permissions: readonly string[] = [],
|
|
76
|
+
): boolean {
|
|
77
|
+
if (permissions.length === 0) return true
|
|
78
|
+
if (isAdminUser(user)) return true
|
|
79
|
+
const granted = new Set(getUserPermissions(user))
|
|
80
|
+
return permissions.every(permission => granted.has(permission))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function hasAnyPermission(
|
|
84
|
+
user: PermissionUser | null | undefined,
|
|
85
|
+
permissions: readonly string[] = [],
|
|
86
|
+
): boolean {
|
|
87
|
+
if (permissions.length === 0) return true
|
|
88
|
+
if (isAdminUser(user)) return true
|
|
89
|
+
const granted = new Set(getUserPermissions(user))
|
|
90
|
+
return permissions.some(permission => granted.has(permission))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function canAccessAdmin(user: PermissionUser | null | undefined): boolean {
|
|
94
|
+
return isAdminUser(user) || hasAnyPermission(user, ADMIN_PANEL_PERMISSIONS)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function canAccessPlugin(
|
|
98
|
+
user: PermissionUser | null | undefined,
|
|
99
|
+
pluginName: string | null | undefined,
|
|
100
|
+
): boolean {
|
|
101
|
+
if (!pluginName) return true
|
|
102
|
+
const access = getRoleInfo(user)?.plugin_access
|
|
103
|
+
if (!access || access === 'all') return true
|
|
104
|
+
return Array.isArray(access) && access.includes(pluginName)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function normalizeAccessPolicy(rule: AccessControlled | AccessPolicy | undefined): AccessPolicy {
|
|
108
|
+
if (!rule) return {}
|
|
109
|
+
const { access: nested, ...direct } = rule as AccessPolicy & { access?: AccessPolicy }
|
|
110
|
+
return {
|
|
111
|
+
...(nested ?? {}),
|
|
112
|
+
...direct,
|
|
113
|
+
...('visibleFor' in rule && rule.visibleFor !== undefined ? { visibleFor: rule.visibleFor } : {}),
|
|
114
|
+
...('requiresAdmin' in rule && rule.requiresAdmin !== undefined ? { requiresAdmin: rule.requiresAdmin } : {}),
|
|
115
|
+
...('permissions' in rule && rule.permissions !== undefined ? { permissions: rule.permissions } : {}),
|
|
116
|
+
...('anyPermissions' in rule && rule.anyPermissions !== undefined ? { anyPermissions: rule.anyPermissions } : {}),
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function canAccessByPolicy(
|
|
121
|
+
user: PermissionUser | null | undefined,
|
|
122
|
+
rule: AccessControlled | AccessPolicy | undefined,
|
|
123
|
+
isAuthenticated = user !== null && user !== undefined,
|
|
124
|
+
): boolean {
|
|
125
|
+
const policy = normalizeAccessPolicy(rule)
|
|
126
|
+
if (policy.requiresAuth && !isAuthenticated) return false
|
|
127
|
+
if (policy.requiresAdmin && !isAdminUser(user)) return false
|
|
128
|
+
if (!audienceAllowsUser(policy.visibleFor ?? policy.audience, user)) return false
|
|
129
|
+
if (!hasAllPermissions(user, policy.permissions)) return false
|
|
130
|
+
if (!hasAnyPermission(user, policy.anyPermissions)) return false
|
|
131
|
+
if (policy.plugin && !canAccessPlugin(user, policy.plugin)) return false
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function audienceAllowsUser(
|
|
136
|
+
audience: AccessAudienceInput | undefined,
|
|
137
|
+
user: PermissionUser | null | undefined,
|
|
138
|
+
): boolean {
|
|
139
|
+
if (audience === undefined) return true
|
|
140
|
+
const allowed = Array.isArray(audience) ? audience : [audience]
|
|
141
|
+
if (allowed.includes('all')) return true
|
|
142
|
+
return allowed.includes(getAccessAudience(user))
|
|
143
|
+
}
|
package/src/stores/auth.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
3
|
import type { AuthConfig, UserInfo } from '../types'
|
|
4
|
+
import {
|
|
5
|
+
canAccessAdmin as canUserAccessAdmin,
|
|
6
|
+
canAccessPlugin as canUserAccessPlugin,
|
|
7
|
+
getAccessAudience,
|
|
8
|
+
getUserPermissions,
|
|
9
|
+
hasAllPermissions,
|
|
10
|
+
hasAnyPermission,
|
|
11
|
+
isAdminUser,
|
|
12
|
+
} from '../permissions'
|
|
4
13
|
|
|
5
14
|
const AUTH_TOKEN_KEY = 'mint-auth-token'
|
|
6
15
|
const AUTH_EXPIRES_KEY = 'mint-auth-expires'
|
|
@@ -73,9 +82,10 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
73
82
|
return authConfig.value.authRequired && !isAuthenticated.value
|
|
74
83
|
})
|
|
75
84
|
|
|
76
|
-
const isAdmin = computed(() =>
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
const isAdmin = computed(() => isAdminUser(userInfo.value))
|
|
86
|
+
const userType = computed(() => getAccessAudience(userInfo.value))
|
|
87
|
+
const permissions = computed(() => getUserPermissions(userInfo.value))
|
|
88
|
+
const canAccessAdmin = computed(() => canUserAccessAdmin(userInfo.value))
|
|
79
89
|
|
|
80
90
|
const canRegister = computed(() => {
|
|
81
91
|
return authConfig.value.registrationEnabled
|
|
@@ -126,6 +136,18 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
126
136
|
username.value = info.username
|
|
127
137
|
}
|
|
128
138
|
|
|
139
|
+
function hasPermission(...perms: string[]): boolean {
|
|
140
|
+
return hasAllPermissions(userInfo.value, perms)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function hasAnyPermissionForUser(...perms: string[]): boolean {
|
|
144
|
+
return hasAnyPermission(userInfo.value, perms)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function canAccessPlugin(pluginName: string): boolean {
|
|
148
|
+
return canUserAccessPlugin(userInfo.value, pluginName)
|
|
149
|
+
}
|
|
150
|
+
|
|
129
151
|
function setAuthConfig(config: AuthConfig) {
|
|
130
152
|
authConfig.value = config
|
|
131
153
|
}
|
|
@@ -161,6 +183,9 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
161
183
|
isAuthenticated,
|
|
162
184
|
needsAuth,
|
|
163
185
|
isAdmin,
|
|
186
|
+
userType,
|
|
187
|
+
permissions,
|
|
188
|
+
canAccessAdmin,
|
|
164
189
|
canRegister,
|
|
165
190
|
|
|
166
191
|
// Actions
|
|
@@ -172,6 +197,9 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
172
197
|
setUserInfo,
|
|
173
198
|
setError,
|
|
174
199
|
setLoading,
|
|
200
|
+
hasPermission,
|
|
201
|
+
hasAnyPermission: hasAnyPermissionForUser,
|
|
202
|
+
canAccessPlugin,
|
|
175
203
|
logout,
|
|
176
204
|
}
|
|
177
205
|
})
|