@morscherlab/mint-sdk 1.1.14 → 1.1.16

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 (26) hide show
  1. package/dist/{SettingsModal-Brvcqz4a.js → SettingsModal-DoS2fzyz.js} +3 -3
  2. package/dist/{SettingsModal-Brvcqz4a.js.map → SettingsModal-DoS2fzyz.js.map} +1 -1
  3. package/dist/components/index.js +3 -3
  4. package/dist/{components-DIciVip2.js → components-CW3hE1T3.js} +7 -7
  5. package/dist/{components-DIciVip2.js.map → components-CW3hE1T3.js.map} +1 -1
  6. package/dist/composables/index.js +5 -5
  7. package/dist/{composables-CPv3k1Yh.js → composables-CkXDe7nm.js} +3 -3
  8. package/dist/{composables-CPv3k1Yh.js.map → composables-CkXDe7nm.js.map} +1 -1
  9. package/dist/index.js +7 -7
  10. package/dist/install.js +3 -3
  11. package/dist/styles.css +20 -4
  12. package/dist/templates/index.js +2 -2
  13. package/dist/{templates-Dyyjr6wD.js → templates-CovvRZ-9.js} +2 -2
  14. package/dist/{templates-Dyyjr6wD.js.map → templates-CovvRZ-9.js.map} +1 -1
  15. package/dist/{useControlSchema-B6-PO0F6.js → useControlSchema-BhoJzWzx.js} +6 -2
  16. package/dist/useControlSchema-BhoJzWzx.js.map +1 -0
  17. package/dist/{useFormBuilder-Pgb9Td6h.js → useFormBuilder-DiEcDis2.js} +2 -2
  18. package/dist/{useFormBuilder-Pgb9Td6h.js.map → useFormBuilder-DiEcDis2.js.map} +1 -1
  19. package/dist/{useProtocolTemplates-CYCnwGtY.js → useProtocolTemplates-DHwSveE6.js} +3 -3
  20. package/dist/{useProtocolTemplates-CYCnwGtY.js.map → useProtocolTemplates-DHwSveE6.js.map} +1 -1
  21. package/package.json +1 -1
  22. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  23. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +58 -0
  24. package/src/composables/useGeneratedAnalysis.ts +5 -1
  25. package/src/styles/components/smart-group.css +5 -1
  26. package/dist/useControlSchema-B6-PO0F6.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morscherlab/mint-sdk",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "description": "MINT Platform SDK — Vue 3 components, composables, and types for plugin development. MINT = Mass-spec INtegrated Toolkit.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,3 +1,5 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
1
3
  import { flushPromises, mount } from '@vue/test-utils'
2
4
  import { createPinia } from 'pinia'
3
5
  import { describe, expect, it, vi } from 'vitest'
@@ -279,6 +281,36 @@ describe('AutoGroupModal multi-schema auto workflow', () => {
279
281
 
280
282
  expect(wrapper.find('.sg-foot .mint-button--primary').attributes('disabled')).toBeUndefined()
281
283
  })
284
+
285
+ it('should scroll the token field list when many fields exceed the modal height', () => {
286
+ const styles = readFileSync(
287
+ resolve(process.cwd(), 'src/styles/components/smart-group.css'),
288
+ 'utf8',
289
+ )
290
+ const mainPanelStyles = styles.match(/\.sg-body__main\s*\{([^}]*)\}/)?.[1]
291
+
292
+ expect(mainPanelStyles).toContain('overflow-y: auto')
293
+ })
294
+
295
+ it('should let the token field panel shrink within the fixed modal body', () => {
296
+ const styles = readFileSync(
297
+ resolve(process.cwd(), 'src/styles/components/smart-group.css'),
298
+ 'utf8',
299
+ )
300
+ const mainPanelStyles = styles.match(/\.sg-body__main\s*\{([^}]*)\}/)?.[1]
301
+
302
+ expect(mainPanelStyles).toContain('min-height: 0')
303
+ })
304
+
305
+ it('should scroll the group preview when generated groups exceed the modal height', () => {
306
+ const styles = readFileSync(
307
+ resolve(process.cwd(), 'src/styles/components/smart-group.css'),
308
+ 'utf8',
309
+ )
310
+ const sidePanelStyles = styles.match(/\.sg-body__side\s*\{([^}]*)\}/)?.[1]
311
+
312
+ expect(sidePanelStyles).toMatch(/min-height:\s*0;[\s\S]*overflow-y:\s*auto;/)
313
+ })
282
314
  })
283
315
 
284
316
  describe('SampleSelector — QC overlay regression', () => {
@@ -1489,6 +1489,64 @@ describe('useGeneratedAnalysis', () => {
1489
1489
  }
1490
1490
  })
1491
1491
 
1492
+ it('should keep polling when a stale list response overlaps an active job lookup', async () => {
1493
+ vi.useFakeTimers()
1494
+ const queued = activeJob('live-job')
1495
+ const running = activeJob('live-job', 'running')
1496
+ const completed = completedJob('live-job')
1497
+ const jobRequest = deferred<Response>()
1498
+ const staleRefresh = deferred<Response>()
1499
+ const transport = vi.fn<GeneratedAnalysisTransport>()
1500
+ .mockResolvedValueOnce(response(manifest))
1501
+ .mockResolvedValueOnce(response({ sessions: [] }))
1502
+ .mockResolvedValueOnce(response({
1503
+ id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1504
+ }))
1505
+ .mockResolvedValueOnce(response({ jobs: [queued] }))
1506
+ .mockReturnValueOnce(jobRequest.promise)
1507
+ .mockReturnValueOnce(staleRefresh.promise)
1508
+ .mockResolvedValueOnce(response({ jobs: [completed] }))
1509
+ const scope = effectScope()
1510
+ const generated = scope.run(() => useGeneratedAnalysis({
1511
+ baseUrl: '/api/demo',
1512
+ transport,
1513
+ storage: memoryStorage(),
1514
+ createId: () => 'tab-1',
1515
+ pollInterval: 10,
1516
+ stream: false,
1517
+ }))!
1518
+ let waiting: Promise<GeneratedAnalysisJob> | undefined
1519
+
1520
+ try {
1521
+ await generated.initialize()
1522
+ waiting = generated.waitForJob('live-job')
1523
+ void waiting.catch(() => undefined)
1524
+
1525
+ vi.advanceTimersByTime(10)
1526
+ await vi.waitFor(() => {
1527
+ if (transport.mock.calls.length !== 6) throw new Error('Concurrent job requests did not start')
1528
+ })
1529
+ jobRequest.resolve(response(running))
1530
+ await vi.waitFor(() => {
1531
+ if (generated.jobs.value[0]?.status !== 'running') throw new Error('Job lookup did not resolve')
1532
+ })
1533
+ staleRefresh.resolve(response({ jobs: [running] }))
1534
+ await vi.advanceTimersByTimeAsync(10)
1535
+ await vi.waitFor(() => {
1536
+ if (transport.mock.calls.length !== 7) throw new Error('Next list poll was not scheduled')
1537
+ })
1538
+
1539
+ await expect(waiting).resolves.toMatchObject({
1540
+ job_id: 'live-job',
1541
+ status: 'completed',
1542
+ })
1543
+ } finally {
1544
+ scope.stop()
1545
+ await waiting?.catch(() => undefined)
1546
+ vi.useRealTimers()
1547
+ }
1548
+ })
1549
+
1492
1550
  it('does not regress a terminal job when a stale snapshot arrives without a concurrent update', async () => {
1493
1551
  const completed = completedJob('terminal-job')
1494
1552
  const staleQueued = activeJob('terminal-job')
@@ -459,7 +459,11 @@ function createPluginJobs(
459
459
  const revision = jobsRevision
460
460
  const pending = request<{ jobs: GeneratedAnalysisJobInput[] }>('/jobs', { method: 'GET' })
461
461
  .then((payload) => {
462
- if (disposed || revision !== jobsRevision) return jobs.value
462
+ if (disposed) return jobs.value
463
+ if (revision !== jobsRevision) {
464
+ if (jobs.value.some(job => ACTIVE_STATUSES.has(job.status))) schedulePoll()
465
+ return jobs.value
466
+ }
463
467
  replaceJobs(payload.jobs)
464
468
  error.value = null
465
469
  if (!paused && !streamConnected && jobs.value.some(job => ACTIVE_STATUSES.has(job.status))) {
@@ -93,7 +93,9 @@
93
93
  .sg-body__main {
94
94
  padding: 1rem 1.25rem;
95
95
  min-width: 0;
96
- overflow: hidden;
96
+ min-height: 0;
97
+ overflow-x: hidden;
98
+ overflow-y: auto;
97
99
  display: flex; flex-direction: column; gap: 0.75rem;
98
100
  }
99
101
  .sg-body__side {
@@ -102,6 +104,8 @@
102
104
  padding: 1.125rem 1.25rem;
103
105
  display: flex; flex-direction: column;
104
106
  min-width: 0;
107
+ min-height: 0;
108
+ overflow-y: auto;
105
109
  gap: 0.75rem;
106
110
  }
107
111