@morscherlab/mint-sdk 1.3.0-beta.4 → 1.3.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +23 -140
  2. package/dist/{ResourcePickerListInternal-c3IT8PIu.js → ResourcePickerListInternal-BEXnyBNz.js} +7 -3
  3. package/dist/ResourcePickerListInternal-BEXnyBNz.js.map +1 -0
  4. package/dist/components/WellPlate.colors.d.ts +1 -5
  5. package/dist/components/WellPlate.rendering.d.ts +5 -2
  6. package/dist/components/index.d.ts +32 -17
  7. package/dist/components/index.js +3 -3
  8. package/dist/{components-CF0XMy8W.js → components-C-CAD2Ma.js} +84 -134
  9. package/dist/components-C-CAD2Ma.js.map +1 -0
  10. package/dist/composables/index.d.ts +0 -3
  11. package/dist/composables/index.js +4 -4
  12. package/dist/composables/useAutoGroup.d.ts +1 -1
  13. package/dist/composables/useBioTemplateComponents.d.ts +15 -3
  14. package/dist/composables/useBioTemplateControls.d.ts +5 -1
  15. package/dist/composables/useBioTemplatePackWorkspace.d.ts +2 -0
  16. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +5 -1
  17. package/dist/composables/useBioTemplateWorkspace.d.ts +5 -1
  18. package/dist/composables/useExperimentSave.d.ts +5 -1
  19. package/dist/composables/useGroupAssignment.d.ts +5 -1
  20. package/dist/composables/usePlatformContext.d.ts +3 -0
  21. package/dist/composables/useTemplateCollection.d.ts +5 -1
  22. package/dist/composables-BKhsoONv.js +591 -0
  23. package/dist/composables-BKhsoONv.js.map +1 -0
  24. package/dist/index.js +24 -24
  25. package/dist/index.js.map +1 -1
  26. package/dist/install.js +1 -1
  27. package/dist/lcms.d.ts +11 -11
  28. package/dist/styles.css +50 -143
  29. package/dist/templates/index.js +1 -1
  30. package/dist/{templates-Bj9hZ7iV.js → templates-DcxyATPT.js} +31 -44
  31. package/dist/templates-DcxyATPT.js.map +1 -0
  32. package/dist/types/auth.d.ts +0 -31
  33. package/dist/types/index.d.ts +1 -1
  34. package/dist/types/platform.d.ts +2 -0
  35. package/dist/utils/rack.d.ts +16 -16
  36. package/dist/{validation-B4Y8_eEe.js → validation-kbTxfKYD.js} +50 -12
  37. package/dist/validation-kbTxfKYD.js.map +1 -0
  38. package/package.json +1 -6
  39. package/src/__tests__/components/AppTopBar.test.ts +24 -8
  40. package/src/__tests__/components/EmptyState.test.ts +15 -0
  41. package/src/__tests__/components/FileUploader.test.ts +6 -9
  42. package/src/__tests__/components/WellPlate.decoration.test.ts +4 -28
  43. package/src/__tests__/components/WellPlate.rendering.test.ts +20 -33
  44. package/src/__tests__/components/WellPlate.sampleTypeIndicator.test.ts +7 -7
  45. package/src/__tests__/docs/frontendDocsCatalog.test.ts +2 -2
  46. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  47. package/src/__tests__/styles/menusShellRefresh.test.ts +8 -2
  48. package/src/__tests__/templates/templatesDeprecation.test.ts +58 -11
  49. package/src/components/AppTopBar.vue +5 -4
  50. package/src/components/EmptyState.vue +3 -1
  51. package/src/components/FileUploader.vue +30 -46
  52. package/src/components/WellPlate.colors.ts +6 -10
  53. package/src/components/WellPlate.legend.ts +4 -4
  54. package/src/components/WellPlate.rendering.ts +9 -8
  55. package/src/components/WellPlate.vue +5 -22
  56. package/src/components/index.ts +32 -17
  57. package/src/composables/autoGroup/index.ts +1 -1
  58. package/src/composables/index.ts +0 -7
  59. package/src/composables/useAutoGroup.ts +1 -1
  60. package/src/composables/useBioTemplateComponents.ts +15 -3
  61. package/src/composables/useBioTemplateControls.ts +5 -1
  62. package/src/composables/useBioTemplatePackWorkspace.ts +2 -0
  63. package/src/composables/useBioTemplatePresetWorkspace.ts +5 -1
  64. package/src/composables/useBioTemplateWorkspace.ts +5 -1
  65. package/src/composables/useExperimentSave.ts +5 -1
  66. package/src/composables/useGroupAssignment.ts +5 -1
  67. package/src/composables/useTemplateCollection.ts +5 -1
  68. package/src/index.ts +1 -1
  69. package/src/lcms.ts +11 -11
  70. package/src/styles/components/app-top-bar.css +7 -31
  71. package/src/styles/components/empty-state.css +3 -2
  72. package/src/styles/components/file-uploader.css +22 -55
  73. package/src/styles/components/well-plate.css +18 -55
  74. package/src/types/auth.ts +0 -41
  75. package/src/types/index.ts +0 -5
  76. package/src/types/platform.ts +2 -0
  77. package/src/utils/rack.ts +16 -16
  78. package/dist/ResourcePickerListInternal-c3IT8PIu.js.map +0 -1
  79. package/dist/__tests__/composables/useAuth.test.d.ts +0 -1
  80. package/dist/__tests__/composables/usePasskey.test.d.ts +0 -1
  81. package/dist/components-CF0XMy8W.js.map +0 -1
  82. package/dist/composables/useAuth.d.ts +0 -47
  83. package/dist/composables/usePasskey.d.ts +0 -10
  84. package/dist/composables/useWellPlateEditor.d.ts +0 -33
  85. package/dist/composables-Dlyz_Aiv.js +0 -1256
  86. package/dist/composables-Dlyz_Aiv.js.map +0 -1
  87. package/dist/plotly.min-DDhZCNEM.js +0 -168582
  88. package/dist/plotly.min-DDhZCNEM.js.map +0 -1
  89. package/dist/templates-Bj9hZ7iV.js.map +0 -1
  90. package/dist/validation-B4Y8_eEe.js.map +0 -1
  91. package/src/__tests__/composables/useAuth.test.ts +0 -290
  92. package/src/__tests__/composables/usePasskey.test.ts +0 -38
  93. package/src/composables/useAuth.ts +0 -470
  94. package/src/composables/usePasskey.ts +0 -216
  95. package/src/composables/useWellPlateEditor.ts +0 -415
@@ -1,415 +0,0 @@
1
- import { ref, computed, toRaw, type ComputedRef } from 'vue'
2
- import type {
3
- PlateMapEditorState,
4
- PlateMap,
5
- SampleType,
6
- WellPlateFormat,
7
- } from '../types'
8
- import { SAMPLE_COLOR_SCALE as DEFAULT_PALETTE } from '../utils/color'
9
-
10
-
11
- const MAX_HISTORY = 50
12
-
13
- interface HistoryEntry {
14
- plates: PlateMap[]
15
- samples: SampleType[]
16
- }
17
-
18
- export interface UseWellPlateEditorOptions {
19
- maxHistory?: number
20
- defaultFormat?: WellPlateFormat
21
- }
22
-
23
- export interface UseWellPlateEditorReturn {
24
- state: ComputedRef<PlateMapEditorState>
25
- plates: ComputedRef<PlateMap[]>
26
- activePlate: ComputedRef<PlateMap | undefined>
27
- samples: ComputedRef<SampleType[]>
28
- selectedWells: ComputedRef<string[]>
29
- activeSampleId: ComputedRef<string | undefined>
30
- canUndo: ComputedRef<boolean>
31
- canRedo: ComputedRef<boolean>
32
- setActivePlate: (plateId: string) => void
33
- setActiveSample: (sampleId: string | undefined) => void
34
- setSelectedWells: (wellIds: string[]) => void
35
- addPlate: (name?: string, format?: WellPlateFormat) => PlateMap
36
- removePlate: (plateId: string) => void
37
- addSample: (name: string, color?: string) => SampleType
38
- removeSample: (sampleId: string) => void
39
- assignSample: (wellIds: string[], sampleId: string | undefined) => void
40
- clearWells: (wellIds: string[]) => void
41
- undo: () => void
42
- redo: () => void
43
- exportData: (format: 'json' | 'csv') => string
44
- importData: (data: string, format: 'json' | 'csv') => boolean
45
- loadState: (state: Partial<PlateMapEditorState>) => void
46
- reset: () => void
47
- }
48
-
49
- function createEmptyPlate(
50
- name: string,
51
- format: WellPlateFormat,
52
- id?: string
53
- ): PlateMap {
54
- return {
55
- id: id || `plate-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
56
- name,
57
- format,
58
- wells: {},
59
- }
60
- }
61
-
62
- function generateSampleId(): string {
63
- return `sample-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
64
- }
65
-
66
- function cloneValue<T>(value: T): T {
67
- return structuredClone(toRaw(value))
68
- }
69
-
70
- /** Manages multi-plate well-plate state with sample assignment, selection, and undo/redo history. */
71
- export function useWellPlateEditor(
72
- initialState?: Partial<PlateMapEditorState>,
73
- options: UseWellPlateEditorOptions = {}
74
- ): UseWellPlateEditorReturn {
75
- const { maxHistory = MAX_HISTORY, defaultFormat = 96 } = options
76
-
77
- const defaultPlate = createEmptyPlate('Plate 1', defaultFormat)
78
-
79
- const internalState = ref<PlateMapEditorState>({
80
- plates: initialState?.plates || [defaultPlate],
81
- activePlateId: initialState?.activePlateId || defaultPlate.id,
82
- samples: initialState?.samples || [],
83
- selectedWells: initialState?.selectedWells || [],
84
- activeSampleId: initialState?.activeSampleId,
85
- })
86
-
87
- const history = ref<HistoryEntry[]>([])
88
- const historyIndex = ref(-1)
89
-
90
- const state = computed(() => internalState.value)
91
- const plates = computed(() => internalState.value.plates)
92
- const activePlate = computed(() =>
93
- internalState.value.plates.find(p => p.id === internalState.value.activePlateId)
94
- )
95
- const samples = computed(() => internalState.value.samples)
96
- const selectedWells = computed(() => internalState.value.selectedWells)
97
- const activeSampleId = computed(() => internalState.value.activeSampleId)
98
-
99
- const canUndo = computed(() => historyIndex.value >= 0)
100
- const canRedo = computed(() => historyIndex.value < history.value.length - 1)
101
-
102
- function saveToHistory() {
103
- const entry: HistoryEntry = {
104
- plates: cloneValue(internalState.value.plates),
105
- samples: cloneValue(internalState.value.samples),
106
- }
107
-
108
- if (historyIndex.value < history.value.length - 1) {
109
- history.value = history.value.slice(0, historyIndex.value + 1)
110
- }
111
-
112
- history.value.push(entry)
113
-
114
- if (history.value.length > maxHistory) {
115
- history.value.shift()
116
- } else {
117
- historyIndex.value++
118
- }
119
- }
120
-
121
- function setActivePlate(plateId: string) {
122
- if (internalState.value.plates.some(p => p.id === plateId)) {
123
- internalState.value.activePlateId = plateId
124
- internalState.value.selectedWells = []
125
- }
126
- }
127
-
128
- function setActiveSample(sampleId: string | undefined) {
129
- internalState.value.activeSampleId = sampleId
130
- }
131
-
132
- function setSelectedWells(wellIds: string[]) {
133
- internalState.value.selectedWells = wellIds
134
- }
135
-
136
- function addPlate(name?: string, format?: WellPlateFormat): PlateMap {
137
- saveToHistory()
138
- const plateNumber = internalState.value.plates.length + 1
139
- const plate = createEmptyPlate(
140
- name || `Plate ${plateNumber}`,
141
- format || defaultFormat
142
- )
143
- internalState.value.plates.push(plate)
144
- internalState.value.activePlateId = plate.id
145
- internalState.value.selectedWells = []
146
- return plate
147
- }
148
-
149
- function removePlate(plateId: string) {
150
- if (internalState.value.plates.length <= 1) return
151
-
152
- saveToHistory()
153
- const index = internalState.value.plates.findIndex(p => p.id === plateId)
154
- if (index === -1) return
155
-
156
- internalState.value.plates.splice(index, 1)
157
- if (internalState.value.activePlateId === plateId) {
158
- internalState.value.activePlateId = internalState.value.plates[0].id
159
- internalState.value.selectedWells = []
160
- }
161
- }
162
-
163
- function addSample(name: string, color?: string): SampleType {
164
- saveToHistory()
165
- const sample: SampleType = {
166
- id: generateSampleId(),
167
- name,
168
- color: color || DEFAULT_PALETTE[internalState.value.samples.length % DEFAULT_PALETTE.length],
169
- count: 0,
170
- }
171
- internalState.value.samples.push(sample)
172
- return sample
173
- }
174
-
175
- function removeSample(sampleId: string) {
176
- saveToHistory()
177
- const index = internalState.value.samples.findIndex(s => s.id === sampleId)
178
- if (index === -1) return
179
-
180
- internalState.value.samples.splice(index, 1)
181
-
182
- for (const plate of internalState.value.plates) {
183
- for (const well of Object.values(plate.wells)) {
184
- if (well.sampleType === sampleId) {
185
- delete well.sampleType
186
- well.state = 'empty'
187
- }
188
- }
189
- }
190
-
191
- if (internalState.value.activeSampleId === sampleId) {
192
- internalState.value.activeSampleId = undefined
193
- }
194
-
195
- updateSampleCounts()
196
- }
197
-
198
- function assignSample(wellIds: string[], sampleId: string | undefined) {
199
- if (wellIds.length === 0) return
200
-
201
- saveToHistory()
202
- const plate = activePlate.value
203
- if (!plate) return
204
-
205
- for (const wellId of wellIds) {
206
- const well = plate.wells[wellId] || {
207
- id: wellId,
208
- row: wellId.charCodeAt(0) - 65,
209
- col: parseInt(wellId.slice(1)) - 1,
210
- state: 'empty',
211
- }
212
-
213
- if (sampleId) {
214
- well.sampleType = sampleId
215
- well.state = 'filled'
216
- } else {
217
- delete well.sampleType
218
- well.state = 'empty'
219
- }
220
-
221
- plate.wells[wellId] = well
222
- }
223
- updateSampleCounts()
224
- }
225
-
226
- function clearWells(wellIds: string[]) {
227
- assignSample(wellIds, undefined)
228
- }
229
-
230
- function updateSampleCounts() {
231
- const counts: Record<string, number> = {}
232
-
233
- for (const plate of internalState.value.plates) {
234
- for (const well of Object.values(plate.wells)) {
235
- if (well.sampleType) {
236
- counts[well.sampleType] = (counts[well.sampleType] || 0) + 1
237
- }
238
- }
239
- }
240
-
241
- for (const sample of internalState.value.samples) {
242
- sample.count = counts[sample.id] || 0
243
- }
244
- }
245
-
246
- function undo() {
247
- if (!canUndo.value) return
248
-
249
- const entry = history.value[historyIndex.value]
250
- historyIndex.value--
251
-
252
- internalState.value.plates = cloneValue(entry.plates)
253
- internalState.value.samples = cloneValue(entry.samples)
254
-
255
- const activePlateExists = internalState.value.plates.some(p => p.id === internalState.value.activePlateId)
256
- if (!activePlateExists) {
257
- internalState.value.activePlateId = internalState.value.plates[0]?.id || ''
258
- }
259
- internalState.value.selectedWells = []
260
- }
261
-
262
- function redo() {
263
- if (!canRedo.value) return
264
-
265
- historyIndex.value++
266
- const entry = history.value[historyIndex.value]
267
-
268
- internalState.value.plates = cloneValue(entry.plates)
269
- internalState.value.samples = cloneValue(entry.samples)
270
- internalState.value.selectedWells = []
271
- }
272
-
273
- function exportData(format: 'json' | 'csv'): string {
274
- if (format === 'json') {
275
- return JSON.stringify({
276
- plates: internalState.value.plates,
277
- samples: internalState.value.samples,
278
- }, null, 2)
279
- }
280
-
281
- const sampleMap = new Map(internalState.value.samples.map(s => [s.id, s.name]))
282
- const rows = ['Plate,Well,Sample Type,Sample Name']
283
-
284
- for (const plate of internalState.value.plates) {
285
- for (const [wellId, well] of Object.entries(plate.wells)) {
286
- if (well.sampleType) {
287
- const sampleName = sampleMap.get(well.sampleType) || ''
288
- rows.push(`"${plate.name}","${wellId}","${well.sampleType}","${sampleName}"`)
289
- }
290
- }
291
- }
292
-
293
- return rows.join('\n')
294
- }
295
-
296
- function importData(data: string, format: 'json' | 'csv'): boolean {
297
- try {
298
- saveToHistory()
299
-
300
- if (format === 'json') {
301
- const parsed = JSON.parse(data)
302
- if (parsed.plates && Array.isArray(parsed.plates)) {
303
- internalState.value.plates = parsed.plates
304
- internalState.value.activePlateId = parsed.plates[0]?.id || ''
305
- }
306
- if (parsed.samples && Array.isArray(parsed.samples)) {
307
- internalState.value.samples = parsed.samples
308
- }
309
- internalState.value.selectedWells = []
310
- updateSampleCounts()
311
- return true
312
- }
313
-
314
- const lines = data.trim().split('\n')
315
- if (lines.length < 2) return false
316
-
317
- const plateMap = new Map<string, PlateMap>()
318
- const sampleMap = new Map<string, SampleType>()
319
-
320
- for (let i = 1; i < lines.length; i++) {
321
- const parts = lines[i].match(/(?:[^",]+|"[^"]*")+/g)
322
- if (!parts || parts.length < 4) continue
323
-
324
- const plateName = parts[0].replace(/^"|"$/g, '')
325
- const wellId = parts[1].replace(/^"|"$/g, '')
326
- const sampleId = parts[2].replace(/^"|"$/g, '')
327
- const sampleName = parts[3].replace(/^"|"$/g, '')
328
-
329
- if (!plateMap.has(plateName)) {
330
- plateMap.set(plateName, createEmptyPlate(plateName, defaultFormat))
331
- }
332
-
333
- if (sampleId && !sampleMap.has(sampleId)) {
334
- sampleMap.set(sampleId, {
335
- id: sampleId,
336
- name: sampleName || sampleId,
337
- color: DEFAULT_PALETTE[sampleMap.size % DEFAULT_PALETTE.length],
338
- count: 0,
339
- })
340
- }
341
-
342
- const plate = plateMap.get(plateName)!
343
- plate.wells[wellId] = {
344
- id: wellId,
345
- row: wellId.charCodeAt(0) - 65,
346
- col: parseInt(wellId.slice(1)) - 1,
347
- state: sampleId ? 'filled' : 'empty',
348
- sampleType: sampleId || undefined,
349
- }
350
- }
351
-
352
- internalState.value.plates = Array.from(plateMap.values())
353
- internalState.value.samples = Array.from(sampleMap.values())
354
- internalState.value.activePlateId = internalState.value.plates[0]?.id || ''
355
- internalState.value.selectedWells = []
356
- updateSampleCounts()
357
- return true
358
- } catch {
359
- return false
360
- }
361
- }
362
-
363
- function loadState(state: Partial<PlateMapEditorState>) {
364
- saveToHistory()
365
- if (state.plates && state.plates.length > 0) {
366
- internalState.value.plates = cloneValue(state.plates)
367
- internalState.value.activePlateId = state.activePlateId ?? state.plates[0].id
368
- }
369
- if (state.samples) {
370
- internalState.value.samples = cloneValue(state.samples)
371
- }
372
- internalState.value.selectedWells = state.selectedWells ?? []
373
- internalState.value.activeSampleId = state.activeSampleId
374
- updateSampleCounts()
375
- }
376
-
377
- function reset() {
378
- const plate = createEmptyPlate('Plate 1', defaultFormat)
379
- internalState.value = {
380
- plates: [plate],
381
- activePlateId: plate.id,
382
- samples: [],
383
- selectedWells: [],
384
- activeSampleId: undefined,
385
- }
386
- history.value = []
387
- historyIndex.value = -1
388
- }
389
-
390
- return {
391
- state,
392
- plates,
393
- activePlate,
394
- samples,
395
- selectedWells,
396
- activeSampleId,
397
- canUndo,
398
- canRedo,
399
- setActivePlate,
400
- setActiveSample,
401
- setSelectedWells,
402
- addPlate,
403
- removePlate,
404
- addSample,
405
- removeSample,
406
- assignSample,
407
- clearWells,
408
- undo,
409
- redo,
410
- exportData,
411
- importData,
412
- loadState,
413
- reset,
414
- }
415
- }