@morscherlab/mint-sdk 1.3.0-beta.5 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morscherlab/mint-sdk",
3
- "version": "1.3.0-beta.5",
3
+ "version": "1.3.0-beta.6",
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",
@@ -1211,6 +1211,14 @@ describe('AppTopBar', () => {
1211
1211
  expect(wrapper.get('.mint-topbar__plugin-name').text()).toBe('LC-MS Analysis')
1212
1212
  })
1213
1213
 
1214
+ it('should render the platform display name when integrated', () => {
1215
+ mockPlatformCtx({ isIntegrated: true, plugin: { ...integratedPlugin, display_name: 'LC-MS Peak Review' } })
1216
+
1217
+ const wrapper = createWrapper()
1218
+
1219
+ expect(wrapper.get('.mint-topbar__plugin-name').text()).toBe('LC-MS Peak Review')
1220
+ })
1221
+
1214
1222
  it('should not render the plugin version when integrated', () => {
1215
1223
  mockPlatformCtx({ isIntegrated: true, plugin: integratedPlugin })
1216
1224
 
@@ -3,16 +3,13 @@ import { describe, expect, it } from 'vitest'
3
3
  import FileUploader from '../../components/FileUploader.vue'
4
4
 
5
5
  describe('FileUploader', () => {
6
- it('should prompt to release with the dragged file count when files are dragged over', async () => {
7
- const wrapper = mount(FileUploader, { props: { multiple: true } })
8
- await wrapper.get('.mint-file-uploader__dropzone').trigger('dragover', {
9
- dataTransfer: { items: { length: 3 } },
10
- })
11
- expect(wrapper.get('.mint-file-uploader__text').text()).toBe('Release to add 3 files')
6
+ it('should name the accepted formats in the prompt when accept is set', () => {
7
+ const wrapper = mount(FileUploader, { props: { accept: '.raw, .mzML' } })
8
+ expect(wrapper.get('.mint-file-uploader__text').text()).toBe('Drop RAW, MZML or click')
12
9
  })
13
10
 
14
- it('should list accepted formats as written when accept and maxSize are set', () => {
15
- const wrapper = mount(FileUploader, { props: { accept: '.raw, .mzML', maxSize: 2 * 1024 ** 3 } })
16
- expect(wrapper.get('.mint-file-uploader__formats').text()).toBe('.raw .mzML · max 2.0 GB')
11
+ it('should prompt for any file when accept is not set', () => {
12
+ const wrapper = mount(FileUploader)
13
+ expect(wrapper.get('.mint-file-uploader__text').text()).toBe('Drop any file or click')
17
14
  })
18
15
  })
@@ -53,12 +53,19 @@ function undeprecatedValueExports(file: string): string[] {
53
53
 
54
54
  describe('templates deprecation', () => {
55
55
  it('should expose deprecated component tags to TypeScript consumers', () => {
56
- const names = ['BioTemplateRenderer', 'SmartGroupModal', 'SampleSelector', 'DoseDesignWorkspaceView']
56
+ const names = ['BioTemplateRenderer', 'SmartGroupModal', 'DoseDesignWorkspaceView']
57
57
  const tagged = exportsOf(COMPONENTS_INDEX).filter(isDeprecated).map(symbol => symbol.getName())
58
58
 
59
59
  expect(names.filter(name => !tagged.includes(name))).toEqual([])
60
60
  })
61
61
 
62
+ it('should not tag components that stay public in MINT 1.4', () => {
63
+ const names = ['SampleSelector', 'SequenceProgressBar', 'InstrumentStateBadge']
64
+ const tagged = exportsOf(COMPONENTS_INDEX).filter(isDeprecated).map(symbol => symbol.getName())
65
+
66
+ expect(names.filter(name => tagged.includes(name))).toEqual([])
67
+ })
68
+
62
69
  it('should tag every template value export when the templates move out in MINT 1.4', () => {
63
70
  expect(undeprecatedValueExports(TEMPLATES_INDEX)).toEqual([])
64
71
  })
@@ -145,7 +145,10 @@ const hasPlatformPageSelector = computed(() =>
145
145
  )
146
146
  const hasPageSelector = computed(() => (props.pageSelector?.length ?? 0) > 1 || hasPlatformPageSelector.value)
147
147
  /** Integrated plugins show their name as a static identity in place of the title; the page selector replaces it. */
148
- const identityName = computed(() => (isIntegrated.value && !hasPageSelector.value ? plugin.value?.name : undefined))
148
+ // Platforms before 1.3 send no display_name.
149
+ const identityName = computed(() =>
150
+ isIntegrated.value && !hasPageSelector.value ? plugin.value?.display_name || plugin.value?.name : undefined,
151
+ )
149
152
  const hasPillNav = computed(() => !!props.pillNav?.length)
150
153
  const hasAccountMenu = computed(() => !!props.accountMenu?.length)
151
154
  const hasTitleGroup = computed(
@@ -31,7 +31,6 @@ const emit = defineEmits<{
31
31
  }>()
32
32
 
33
33
  const isDragOver = ref(false)
34
- const dragCount = ref(0)
35
34
  const inputRef = ref<HTMLInputElement>()
36
35
  const selectedFiles = ref<File[]>([])
37
36
  const folderName = ref<string | null>(null)
@@ -45,14 +44,9 @@ watch(() => [props.files, props.rootName] as const, ([files, rootName]) => {
45
44
  const isFolder = computed(() => props.mode === 'folder')
46
45
  const isMixed = computed(() => props.mode === 'file+folder')
47
46
 
48
- const promptText = computed(() => {
49
- if (isDragOver.value) {
50
- if (isFolder.value || dragCount.value === 0) return 'Release to add'
51
- return `Release to add ${dragCount.value} file${dragCount.value === 1 ? '' : 's'}`
52
- }
53
- if (isMixed.value) return 'Drop files or a folder, or click to choose files'
54
- if (isFolder.value) return 'Drop a folder, or click to choose'
55
- return props.multiple ? 'Drop files, or click to choose' : 'Drop a file, or click to choose'
47
+ const acceptLabel = computed(() => {
48
+ if (!props.accept) return isFolder.value ? 'a folder' : 'any file'
49
+ return props.accept.split(',').map(a => a.trim().replace('.', '').toUpperCase()).join(', ')
56
50
  })
57
51
 
58
52
  const maxSizeLabel = computed(() => {
@@ -69,12 +63,6 @@ const maxSizeLabel = computed(() => {
69
63
  return `${props.maxSize} bytes`
70
64
  })
71
65
 
72
- /** Accepted formats exactly as the caller wrote them, plus the size cap. */
73
- const formatsLabel = computed(() => [
74
- props.accept?.split(',').map(a => a.trim()).filter(Boolean).join(' '),
75
- maxSizeLabel.value && `max ${maxSizeLabel.value}`,
76
- ].filter(Boolean).join(' · '))
77
-
78
66
  const fileTypeMap: Record<string, { color: string; label: string }> = {
79
67
  csv: { color: '#10B981', label: 'CSV' },
80
68
  tsv: { color: '#10B981', label: 'TSV' },
@@ -272,7 +260,6 @@ function handleDragOver(event: DragEvent) {
272
260
  event.preventDefault()
273
261
  if (!props.disabled) {
274
262
  isDragOver.value = true
275
- dragCount.value = event.dataTransfer?.items?.length ?? 0
276
263
  }
277
264
  }
278
265
 
@@ -359,37 +346,34 @@ function formatFileSize(bytes: number): string {
359
346
  />
360
347
 
361
348
  <div class="mint-file-uploader__content">
362
- <span class="mint-file-uploader__icon-tile">
363
- <svg
364
- v-if="isFolder"
365
- class="mint-file-uploader__icon"
366
- fill="none"
367
- stroke="currentColor"
368
- stroke-width="1.5"
369
- stroke-linecap="round"
370
- stroke-linejoin="round"
371
- viewBox="0 0 24 24"
372
- >
373
- <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
374
- </svg>
375
- <svg
376
- v-else
377
- class="mint-file-uploader__icon"
378
- fill="none"
379
- stroke="currentColor"
380
- stroke-width="1.5"
381
- stroke-linecap="round"
382
- stroke-linejoin="round"
383
- viewBox="0 0 24 24"
384
- >
385
- <path d="M12 16V4M7 9l5-5 5 5M4 20h16" />
386
- </svg>
387
- </span>
349
+ <svg
350
+ v-if="isFolder"
351
+ class="mint-file-uploader__icon"
352
+ fill="none"
353
+ stroke="currentColor"
354
+ stroke-width="1.5"
355
+ stroke-linecap="round"
356
+ stroke-linejoin="round"
357
+ viewBox="0 0 24 24"
358
+ >
359
+ <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
360
+ </svg>
361
+ <svg
362
+ v-else
363
+ class="mint-file-uploader__icon"
364
+ fill="none"
365
+ stroke="currentColor"
366
+ stroke-width="1.5"
367
+ stroke-linecap="round"
368
+ stroke-linejoin="round"
369
+ viewBox="0 0 24 24"
370
+ >
371
+ <path d="M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" /><path d="m16 16-4-4-4 4" /><path d="M12 12v9" />
372
+ </svg>
388
373
 
389
- <div class="mint-file-uploader__copy">
390
- <p class="mint-file-uploader__text">{{ promptText }}</p>
391
- <p v-if="formatsLabel" class="mint-file-uploader__formats">{{ formatsLabel }}</p>
392
- </div>
374
+ <p class="mint-file-uploader__text">
375
+ {{ isMixed ? 'Drop files or a folder, or click to choose files' : `Drop ${acceptLabel} or click` }}
376
+ </p>
393
377
  </div>
394
378
  </div>
395
379
 
@@ -86,8 +86,8 @@ export { /** @deprecated Removed in MINT 1.4. */ default as SampleLegend } from
86
86
  export { /** @deprecated Removed in MINT 1.4. */ default as ExperimentTimeline } from './ExperimentTimeline.vue'
87
87
 
88
88
  // Sample management components
89
- /** Interactive sample list with drag-and-drop group assignment, color labeling, and smart-group support. @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */
90
- export { /** @deprecated Removed in MINT 1.4. */ default as SampleSelector } from './SampleSelector.vue'
89
+ /** Interactive sample list with drag-and-drop group assignment, color labeling, and smart-group support. */
90
+ export { default as SampleSelector } from './SampleSelector.vue'
91
91
  /** Smart Group modal wired to the `useAutoGroup` engine. @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */
92
92
  export { /** @deprecated Removed in MINT 1.4. */ default as AutoGroupModal } from './AutoGroupModal.vue'
93
93
  /** Drag-and-drop two-zone assigner for splitting sample groups into control and treatment arms. @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */
@@ -114,7 +114,7 @@ export { default as ProtocolStepEditor } from './ProtocolStepEditor.vue'
114
114
  export { default as PlotlyChart } from './PlotlyChart.vue'
115
115
  export { default as ScientificNumber } from './ScientificNumber.vue'
116
116
  export { default as ChemicalFormula } from './ChemicalFormula.vue'
117
- /** Displays LC/MS or GC/MS acquisition sequence progress with ETA and remaining-time labels. @deprecated Scheduled for removal in MINT 1.4; instrument UI moves to the mld-ms plugins. */
117
+ /** Displays LC/MS or GC/MS acquisition sequence progress with ETA and remaining-time labels. */
118
118
  export { default as SequenceProgressBar } from './SequenceProgressBar.vue'
119
119
  /** Status badge for instrument states: a tone dot (or dash / hollow shape for offline, never-reported and inactive) plus a label. */
120
120
  export { default as InstrumentStateBadge } from './InstrumentStateBadge.vue'
@@ -14,113 +14,80 @@
14
14
 
15
15
  .mint-file-uploader__dropzone {
16
16
  position: relative;
17
- border: 1px dashed var(--_control-border-strong);
17
+ border: 2px dashed var(--border-color);
18
18
  border-radius: var(--radius-lg);
19
19
  cursor: pointer;
20
20
  background: var(--bg-secondary);
21
21
  transition: border-color 0.15s ease, background-color 0.15s ease;
22
22
  }
23
23
 
24
- /* 2g: hover only changes the surface; the border change is reserved for dragover. */
25
24
  .mint-file-uploader__dropzone:hover {
26
- background: var(--bg-hover);
25
+ border-color: var(--color-primary);
26
+ background: color-mix(in srgb, var(--color-primary) 3%, var(--bg-secondary));
27
27
  }
28
28
 
29
29
  .mint-file-uploader__dropzone:focus-visible {
30
- outline: none;
31
- box-shadow: var(--focus-ring-offset);
30
+ outline: 2px solid var(--color-primary);
31
+ outline-offset: 2px;
32
32
  }
33
33
 
34
- .mint-file-uploader__dropzone--dragover,
35
- .mint-file-uploader__dropzone--dragover:hover {
36
- border: 1.5px solid var(--color-primary);
37
- background: var(--color-primary-soft);
34
+ .mint-file-uploader__dropzone--dragover {
35
+ border-color: var(--color-primary);
36
+ background: color-mix(in srgb, var(--color-primary) 5%, var(--bg-secondary));
38
37
  }
39
38
 
40
- .mint-file-uploader__dropzone--disabled,
41
- .mint-file-uploader__dropzone--disabled:hover {
42
- background: var(--bg-tertiary);
39
+ .mint-file-uploader__dropzone--disabled {
43
40
  opacity: var(--mint-disabled-opacity);
44
41
  cursor: not-allowed;
45
42
  }
46
43
 
47
44
  .mint-file-uploader__dropzone--sm {
48
- padding: 0.75rem;
45
+ padding: 1.25rem;
49
46
  }
50
47
 
51
48
  .mint-file-uploader__dropzone--md {
52
- padding: 1.125rem;
49
+ padding: 1.5rem;
53
50
  }
54
51
 
55
52
  .mint-file-uploader__dropzone--lg {
56
- padding: 1.5rem;
53
+ padding: 2rem;
57
54
  }
58
55
 
59
56
  /* ==========================================================================
60
- Content area — compact row: icon tile + prompt + accepted formats
57
+ Content area
61
58
  ========================================================================== */
62
59
 
63
60
  .mint-file-uploader__content {
64
61
  display: flex;
62
+ flex-direction: column;
65
63
  align-items: center;
66
- gap: 0.75rem;
64
+ text-align: center;
67
65
  }
68
66
 
69
67
  .mint-file-uploader__input {
70
68
  display: none;
71
69
  }
72
70
 
73
- .mint-file-uploader__icon-tile {
74
- display: flex;
75
- align-items: center;
76
- justify-content: center;
77
- flex-shrink: 0;
71
+ .mint-file-uploader__icon {
78
72
  width: 2rem;
79
73
  height: 2rem;
80
- border-radius: var(--radius-md);
81
- background: var(--bg-tertiary);
82
- color: var(--text-secondary);
83
- transition: background-color 0.15s ease, color 0.15s ease;
84
- }
85
-
86
- .mint-file-uploader__dropzone--dragover .mint-file-uploader__icon-tile {
87
- background: var(--color-primary);
88
- color: white;
89
- }
90
-
91
- .mint-file-uploader__icon {
92
- width: 1rem;
93
- height: 1rem;
94
- stroke-width: 1.8;
74
+ color: var(--text-muted);
75
+ margin-bottom: 0.5rem;
95
76
  }
96
77
 
97
- .mint-file-uploader__copy {
98
- display: flex;
99
- flex-direction: column;
100
- gap: 0.125rem;
101
- min-width: 0;
78
+ .mint-file-uploader__dropzone:hover .mint-file-uploader__icon,
79
+ .mint-file-uploader__dropzone--dragover .mint-file-uploader__icon {
80
+ color: var(--color-primary);
102
81
  }
103
82
 
104
83
  .mint-file-uploader__text {
105
- color: var(--text-primary);
84
+ color: var(--text-secondary);
106
85
  font-size: 0.8125rem;
107
86
  font-weight: 500;
108
87
  margin: 0;
109
88
  padding: 0;
110
89
  }
111
90
 
112
- .mint-file-uploader__dropzone--dragover .mint-file-uploader__text {
113
- color: var(--_ink-primary);
114
- }
115
-
116
- .mint-file-uploader__formats {
117
- color: var(--text-secondary);
118
- font-family: var(--font-mono);
119
- font-size: 0.6875rem;
120
- margin: 0;
121
- padding: 0;
122
- }
123
-
124
91
  /* ==========================================================================
125
92
  Actions slot
126
93
  ========================================================================== */
@@ -4,6 +4,8 @@ import type { RoleInfo } from '../permissions'
4
4
  export interface PluginInfo {
5
5
  id: string
6
6
  name: string
7
+ /** Name to show in the UI; the platform falls back to the plugin ID. Absent before MINT 1.3. */
8
+ display_name?: string
7
9
  version: string
8
10
  plugin_type?: string
9
11
  description?: string