@morscherlab/mint-sdk 1.2.0-beta.11 → 1.2.0-beta.13

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 (74) hide show
  1. package/dist/{ExperimentPopover-oL0fg_A0.js → ExperimentPopover-BIZKoRTT.js} +19 -12
  2. package/dist/ExperimentPopover-BIZKoRTT.js.map +1 -0
  3. package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
  4. package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
  5. package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
  6. package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
  7. package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
  8. package/dist/components/FileBrowserModal.vue.d.ts +99 -0
  9. package/dist/components/FilePicker.vue.d.ts +32 -0
  10. package/dist/components/fileBrowserPresentation.d.ts +10 -0
  11. package/dist/components/index.d.ts +3 -0
  12. package/dist/components/index.js +3 -3
  13. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
  14. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
  15. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
  16. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
  17. package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
  18. package/dist/{components-CgAUzF8F.js → components-DuQRC810.js} +3727 -1521
  19. package/dist/components-DuQRC810.js.map +1 -0
  20. package/dist/composables/filePicker/localFiles.d.ts +3 -0
  21. package/dist/composables/filePicker/usePickerNavigation.d.ts +95 -0
  22. package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
  23. package/dist/composables/filePicker/validation.d.ts +5 -0
  24. package/dist/composables/index.d.ts +2 -0
  25. package/dist/composables/index.js +3 -3
  26. package/dist/composables/useFileBrowser.d.ts +55 -0
  27. package/dist/composables/useFilePicker.d.ts +190 -0
  28. package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
  29. package/dist/{composables-B_pia3hO.js → composables-hY2Q2xPI.js} +289 -3
  30. package/dist/composables-hY2Q2xPI.js.map +1 -0
  31. package/dist/index.js +5 -5
  32. package/dist/install.js +1 -1
  33. package/dist/styles.css +2232 -1259
  34. package/dist/types/fileBrowserTypes.d.ts +77 -0
  35. package/dist/types/filePicker.d.ts +69 -0
  36. package/dist/types/index.d.ts +2 -0
  37. package/dist/{useProtocolTemplates-BmX_iVBR.js → validation-nBbSn1TI.js} +46 -2
  38. package/dist/validation-nBbSn1TI.js.map +1 -0
  39. package/package.json +1 -1
  40. package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
  41. package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
  42. package/src/__tests__/components/FilePicker.state.test.ts +160 -0
  43. package/src/__tests__/components/FilePicker.test.ts +328 -0
  44. package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
  45. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
  46. package/src/components/ExperimentPopover.vue +10 -2
  47. package/src/components/FileBrowserModal.story.vue +203 -0
  48. package/src/components/FileBrowserModal.vue +384 -0
  49. package/src/components/FilePicker.vue +301 -0
  50. package/src/components/fileBrowserPresentation.ts +39 -0
  51. package/src/components/index.ts +4 -0
  52. package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
  53. package/src/components/internal/FileBrowserListingInternal.vue +197 -0
  54. package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
  55. package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
  56. package/src/components/internal/FilePickerTreeInternal.vue +238 -0
  57. package/src/composables/filePicker/localFiles.ts +55 -0
  58. package/src/composables/filePicker/usePickerNavigation.ts +199 -0
  59. package/src/composables/filePicker/usePickerSelection.ts +242 -0
  60. package/src/composables/filePicker/validation.ts +40 -0
  61. package/src/composables/index.ts +7 -0
  62. package/src/composables/useFileBrowser.ts +314 -0
  63. package/src/composables/useFilePicker.ts +347 -0
  64. package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
  65. package/src/styles/components/file-browser-modal.css +489 -0
  66. package/src/styles/components/file-picker.css +501 -0
  67. package/src/styles/index.css +3 -0
  68. package/src/types/fileBrowserTypes.ts +85 -0
  69. package/src/types/filePicker.ts +65 -0
  70. package/src/types/index.ts +14 -0
  71. package/dist/ExperimentPopover-oL0fg_A0.js.map +0 -1
  72. package/dist/components-CgAUzF8F.js.map +0 -1
  73. package/dist/composables-B_pia3hO.js.map +0 -1
  74. package/dist/useProtocolTemplates-BmX_iVBR.js.map +0 -1
@@ -0,0 +1,501 @@
1
+ /* Unified picker: search-first header, Finder tree, metadata preview and receipt. */
2
+ .mint-picker-dialog {
3
+ width: 800px;
4
+ }
5
+ .mint-picker-dialog .mint-file-browser-dialog__header {
6
+ padding: 15px 18px;
7
+ gap: 12px;
8
+ }
9
+ .mint-picker-dialog .mint-file-browser-dialog__footer {
10
+ padding: 12px 18px;
11
+ background: var(--bg-primary);
12
+ }
13
+ .mint-picker__search {
14
+ display: flex;
15
+ align-items: center;
16
+ position: relative;
17
+ flex: 1;
18
+ min-width: 0;
19
+ }
20
+ .mint-picker__search > svg {
21
+ position: absolute;
22
+ left: 12px;
23
+ width: 16px;
24
+ height: 16px;
25
+ color: var(--text-muted);
26
+ pointer-events: none;
27
+ }
28
+ .mint-picker__search .mint-input {
29
+ width: 100%;
30
+ padding-left: 36px;
31
+ padding-right: 36px;
32
+ background: var(--bg-primary);
33
+ font-size: 13px;
34
+ }
35
+ .mint-picker__search > kbd {
36
+ position: absolute;
37
+ right: 12px;
38
+ font-family: var(--font-mono);
39
+ font-size: 11px;
40
+ border: 1px solid var(--border-color);
41
+ border-radius: var(--radius-sm);
42
+ padding: 1px 5px;
43
+ color: var(--text-secondary);
44
+ background: var(--bg-secondary);
45
+ }
46
+ .mint-picker__sources {
47
+ position: relative;
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 2px;
51
+ background: var(--bg-primary);
52
+ padding: 2px;
53
+ border-radius: var(--radius-md);
54
+ flex-shrink: 0;
55
+ }
56
+ .mint-picker {
57
+ display: flex;
58
+ flex-direction: column;
59
+ min-height: 0;
60
+ }
61
+ .mint-picker__pathbar {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 6px;
65
+ padding: 7px 18px;
66
+ border-block: 1px solid var(--border-color);
67
+ background: var(--bg-primary);
68
+ flex-shrink: 0;
69
+ }
70
+ .mint-picker__breadcrumbs {
71
+ display: flex;
72
+ align-items: center;
73
+ min-width: 0;
74
+ flex: 1;
75
+ overflow-x: auto;
76
+ color: var(--text-muted);
77
+ }
78
+ .mint-picker__breadcrumbs .mint-button {
79
+ font-family: var(--font-mono);
80
+ font-size: 11px;
81
+ padding-inline: 5px;
82
+ flex-shrink: 0;
83
+ }
84
+ .mint-picker__scope {
85
+ font-size: 11px;
86
+ flex-shrink: 0;
87
+ }
88
+ .mint-picker__scope[aria-pressed='true'] {
89
+ color: var(--color-primary);
90
+ background: var(--color-primary-soft);
91
+ }
92
+ .mint-picker__workspace {
93
+ display: grid;
94
+ grid-template-columns: minmax(0, 1fr) 208px;
95
+ height: 344px;
96
+ min-height: 0;
97
+ }
98
+ .mint-picker__tree {
99
+ padding: 7px;
100
+ background: var(--bg-primary);
101
+ overflow-y: auto;
102
+ min-height: 0;
103
+ min-width: 0;
104
+ }
105
+ .mint-picker__row {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 6px;
109
+ min-height: 40px;
110
+ padding: 5px 10px 5px calc(2px + var(--picker-depth, 0) * 14px);
111
+ border-radius: var(--radius-md);
112
+ cursor: pointer;
113
+ margin-bottom: 2px;
114
+ border: 1px solid transparent;
115
+ }
116
+ .mint-picker__row:hover {
117
+ background: var(--bg-hover);
118
+ }
119
+ .mint-picker__row--selected,
120
+ .mint-picker__row--selected:hover {
121
+ background: var(--color-primary-soft);
122
+ border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
123
+ color: var(--text-primary);
124
+ }
125
+ .mint-picker__row:focus-visible {
126
+ outline: none;
127
+ box-shadow: inset 0 0 0 2px var(--color-primary);
128
+ }
129
+ .mint-picker__row--child {
130
+ min-height: 30px;
131
+ padding-block: 1px;
132
+ }
133
+ .mint-picker__disclosure {
134
+ flex-shrink: 0;
135
+ }
136
+ .mint-picker__disclosure-spacer {
137
+ width: var(--form-height-sm);
138
+ flex-shrink: 0;
139
+ }
140
+ .mint-picker__disclosure svg {
141
+ width: 10px;
142
+ height: 10px;
143
+ transition: transform 120ms;
144
+ }
145
+ .mint-picker__chevron--open {
146
+ transform: rotate(90deg);
147
+ }
148
+ .mint-picker__node-icon {
149
+ width: 16px;
150
+ height: 16px;
151
+ flex-shrink: 0;
152
+ color: var(--text-muted);
153
+ }
154
+ .mint-picker__row--selected .mint-picker__node-icon {
155
+ color: var(--color-primary);
156
+ }
157
+ .mint-picker__row-name {
158
+ flex: 1;
159
+ min-width: 0;
160
+ display: flex;
161
+ flex-direction: column;
162
+ gap: 3px;
163
+ }
164
+ .mint-picker__name {
165
+ overflow: hidden;
166
+ text-overflow: ellipsis;
167
+ white-space: nowrap;
168
+ font-size: 13px;
169
+ }
170
+ .mint-picker__row--selected .mint-picker__name {
171
+ font-weight: 600;
172
+ }
173
+ .mint-picker__name mark {
174
+ background: color-mix(in srgb, var(--mint-warning) 32%, transparent);
175
+ color: inherit;
176
+ border-radius: 2px;
177
+ }
178
+ .mint-picker__formats {
179
+ display: flex;
180
+ flex-wrap: wrap;
181
+ gap: 4px;
182
+ }
183
+ .mint-picker__formats > span {
184
+ color: var(--text-secondary);
185
+ background: var(--bg-secondary);
186
+ padding: 1px 4px;
187
+ border: 1px solid var(--border-color);
188
+ border-radius: var(--radius-sm);
189
+ font: 10px var(--font-mono);
190
+ }
191
+ .mint-picker__row-meta {
192
+ display: flex;
193
+ align-items: flex-end;
194
+ flex-direction: column;
195
+ gap: 3px;
196
+ flex-shrink: 0;
197
+ font: 10px var(--font-mono);
198
+ color: var(--text-muted);
199
+ }
200
+ .mint-picker__partial {
201
+ background: var(--mint-warning-bg);
202
+ color: var(--mint-warning-text);
203
+ padding: 2px 5px;
204
+ border-radius: var(--radius-sm);
205
+ }
206
+ .mint-picker__parent-name {
207
+ font: 10px var(--font-mono);
208
+ color: var(--text-muted);
209
+ overflow: hidden;
210
+ text-overflow: ellipsis;
211
+ white-space: nowrap;
212
+ }
213
+ .mint-picker__row--unreadable,
214
+ .mint-picker__row--unreadable:hover {
215
+ cursor: not-allowed;
216
+ color: var(--text-muted);
217
+ background: repeating-linear-gradient(
218
+ 135deg,
219
+ transparent,
220
+ transparent 5px,
221
+ color-mix(in srgb, var(--text-muted) 6%, transparent) 5px,
222
+ color-mix(in srgb, var(--text-muted) 6%, transparent) 10px
223
+ );
224
+ }
225
+ .mint-picker__row--unreadable .mint-picker__name {
226
+ text-decoration: line-through;
227
+ }
228
+ .mint-picker__branch-error {
229
+ padding: 6px 12px;
230
+ color: var(--mint-error);
231
+ font-size: 12px;
232
+ }
233
+ .mint-picker__skeleton {
234
+ display: flex;
235
+ flex-direction: column;
236
+ gap: 8px;
237
+ padding: 8px;
238
+ }
239
+ .mint-picker__empty {
240
+ display: flex;
241
+ flex-direction: column;
242
+ justify-content: center;
243
+ align-items: center;
244
+ gap: 12px;
245
+ min-height: 180px;
246
+ padding: 24px;
247
+ font-size: 12px;
248
+ color: var(--text-secondary);
249
+ text-align: center;
250
+ }
251
+ .mint-picker__preview {
252
+ border-left: 1px solid var(--border-color);
253
+ display: flex;
254
+ flex-direction: column;
255
+ min-height: 0;
256
+ background: var(--bg-secondary);
257
+ }
258
+ .mint-picker__preview-heading {
259
+ padding: 10px 13px;
260
+ border-bottom: 1px solid var(--border-color);
261
+ font-size: 10px;
262
+ font-weight: 600;
263
+ text-transform: uppercase;
264
+ letter-spacing: 0.1em;
265
+ color: var(--text-muted);
266
+ }
267
+ .mint-picker__preview-content {
268
+ display: flex;
269
+ flex-direction: column;
270
+ gap: 10px;
271
+ padding: 14px 13px;
272
+ overflow-y: auto;
273
+ min-height: 0;
274
+ flex: 1;
275
+ }
276
+ .mint-picker__preview-icon {
277
+ display: grid;
278
+ place-items: center;
279
+ width: 52px;
280
+ height: 52px;
281
+ flex-shrink: 0;
282
+ border-radius: 13px;
283
+ background: linear-gradient(135deg, var(--color-primary), var(--color-purple));
284
+ color: white;
285
+ margin: 0 auto;
286
+ }
287
+ .mint-picker__preview-icon svg {
288
+ width: 26px;
289
+ height: 26px;
290
+ }
291
+ .mint-picker__preview-name {
292
+ font-size: 12px;
293
+ text-align: center;
294
+ overflow-wrap: anywhere;
295
+ }
296
+ .mint-picker__metadata {
297
+ display: flex;
298
+ flex-direction: column;
299
+ gap: 7px;
300
+ margin: 0;
301
+ font-size: 11px;
302
+ }
303
+ .mint-picker__metadata > div {
304
+ display: grid;
305
+ grid-template-columns: 44px minmax(0, 1fr);
306
+ gap: 5px;
307
+ }
308
+ .mint-picker__metadata dt {
309
+ color: var(--text-muted);
310
+ }
311
+ .mint-picker__metadata dd {
312
+ margin: 0;
313
+ font: 10px/1.5 var(--font-mono);
314
+ overflow-wrap: anywhere;
315
+ }
316
+ .mint-picker__ready {
317
+ margin-top: auto;
318
+ border: 1px solid var(--mint-success);
319
+ border-radius: 999px;
320
+ background: var(--mint-success-bg);
321
+ color: var(--mint-success-hover);
322
+ text-align: center;
323
+ padding: 4px;
324
+ font-size: 10px;
325
+ }
326
+ .mint-picker__preview-empty {
327
+ color: var(--text-muted);
328
+ font-size: 12px;
329
+ text-align: center;
330
+ padding: 32px 16px;
331
+ }
332
+ .mint-picker__skipped {
333
+ background: var(--mint-warning-bg);
334
+ color: var(--mint-warning-text);
335
+ white-space: normal;
336
+ }
337
+ .mint-picker__exclusion {
338
+ display: flex;
339
+ flex-direction: column;
340
+ gap: 4px;
341
+ font-size: 11px;
342
+ overflow-wrap: anywhere;
343
+ padding-bottom: 8px;
344
+ border-bottom: 1px solid var(--border-color);
345
+ }
346
+ .mint-picker__exclusion span {
347
+ color: var(--text-muted);
348
+ }
349
+ .mint-picker__preview-error {
350
+ display: flex;
351
+ flex-direction: column;
352
+ gap: 8px;
353
+ font-size: 11px;
354
+ color: var(--mint-error);
355
+ }
356
+ .mint-picker__footer {
357
+ display: flex;
358
+ align-items: center;
359
+ gap: 12px;
360
+ width: 100%;
361
+ }
362
+ .mint-picker__receipt {
363
+ display: flex;
364
+ align-items: center;
365
+ gap: 6px;
366
+ flex: 1;
367
+ min-width: 0;
368
+ flex-wrap: wrap;
369
+ font-size: 11px;
370
+ color: var(--text-secondary);
371
+ }
372
+ .mint-picker__receipt > span {
373
+ overflow-wrap: anywhere;
374
+ }
375
+ .mint-picker__badge {
376
+ padding: 3px 7px;
377
+ border-radius: var(--radius-sm);
378
+ color: var(--color-primary);
379
+ border: 1px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
380
+ background: var(--color-primary-soft);
381
+ font: 10px var(--font-mono);
382
+ }
383
+ .mint-picker__actions {
384
+ display: flex;
385
+ align-items: center;
386
+ gap: 8px;
387
+ flex-shrink: 0;
388
+ }
389
+ .mint-picker__local-actions {
390
+ display: flex;
391
+ align-items: center;
392
+ gap: 8px;
393
+ padding: 8px 14px;
394
+ flex-shrink: 0;
395
+ }
396
+ .mint-picker__local-actions > span {
397
+ color: var(--text-muted);
398
+ font-size: 11px;
399
+ }
400
+ @media (max-width: 600px) {
401
+ .mint-picker-dialog .mint-file-browser-dialog__header {
402
+ padding: 10px;
403
+ gap: 6px;
404
+ flex-wrap: nowrap;
405
+ }
406
+ .mint-picker__search .mint-input {
407
+ font-size: 12px;
408
+ padding-right: 8px;
409
+ }
410
+ .mint-picker__search > kbd {
411
+ display: none;
412
+ }
413
+ .mint-picker__pathbar {
414
+ padding-inline: 8px;
415
+ gap: 2px;
416
+ }
417
+ .mint-picker__workspace {
418
+ grid-template-columns: minmax(0, 1fr);
419
+ height: 390px;
420
+ }
421
+ .mint-picker__preview {
422
+ display: none;
423
+ }
424
+ .mint-picker__workspace:has(.mint-picker__exclusion) {
425
+ grid-template-columns: minmax(0, 1fr) 160px;
426
+ }
427
+ .mint-picker__workspace:has(.mint-picker__exclusion) .mint-picker__preview {
428
+ display: flex;
429
+ }
430
+ .mint-picker__row {
431
+ gap: 4px;
432
+ padding-right: 5px;
433
+ }
434
+ .mint-picker__name {
435
+ font-size: 12px;
436
+ }
437
+ .mint-picker__footer {
438
+ align-items: stretch;
439
+ flex-direction: column;
440
+ gap: 8px;
441
+ }
442
+ .mint-picker__actions {
443
+ justify-content: flex-end;
444
+ }
445
+ .mint-picker__receipt {
446
+ min-height: 24px;
447
+ }
448
+ }
449
+ @media (max-height: 600px) {
450
+ .mint-picker {
451
+ overflow-y: auto;
452
+ }
453
+ .mint-picker__workspace {
454
+ min-height: 220px;
455
+ }
456
+ }
457
+
458
+ /* The source highlight slides between fixed-size SDK icon buttons. */
459
+ .mint-picker__source-indicator {
460
+ box-sizing: border-box;
461
+ position: absolute;
462
+ inset: 2px auto 2px 2px;
463
+ width: 32px;
464
+ border: 1px solid var(--border-color);
465
+ border-radius: var(--radius-md);
466
+ background: var(--bg-secondary);
467
+ box-shadow: var(--shadow-sm);
468
+ pointer-events: none;
469
+ transform: translateX(calc(var(--picker-source-index, 0) * 34px));
470
+ transition: transform 180ms ease-out;
471
+ }
472
+ .mint-picker__sources .mint-icon-button {
473
+ position: relative;
474
+ width: 32px;
475
+ height: 32px;
476
+ }
477
+ .mint-picker__sources .mint-icon-button[aria-pressed='true'] {
478
+ color: var(--text-primary);
479
+ background: transparent;
480
+ }
481
+ .mint-picker__source-panel {
482
+ animation: mint-picker-source-in 180ms ease-out;
483
+ }
484
+ @keyframes mint-picker-source-in {
485
+ from {
486
+ opacity: 0;
487
+ transform: translateY(4px);
488
+ }
489
+ to {
490
+ opacity: 1;
491
+ transform: translateY(0);
492
+ }
493
+ }
494
+ @media (prefers-reduced-motion: reduce) {
495
+ .mint-picker__source-indicator {
496
+ transition: none;
497
+ }
498
+ .mint-picker__source-panel {
499
+ animation: none;
500
+ }
501
+ }
@@ -90,6 +90,7 @@
90
90
  @import './components/experiment-code-badge.css';
91
91
  @import './components/experiment-selector-modal.css';
92
92
  @import './components/artifact-selector-modal.css';
93
+ @import './components/file-browser-modal.css';
93
94
  @import './components/artifact-save-dialog.css';
94
95
  @import './components/experiment-popover.css';
95
96
  @import './components/fit-panel.css';
@@ -100,3 +101,5 @@
100
101
  @import './components/mobile-support-gate.css';
101
102
  @import './components/plugin-icon.css';
102
103
  @import './components/reagent-editor.css';
104
+
105
+ @import './components/file-picker.css';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Types for browsing read-only server mounts.
3
+ *
4
+ * These mirror the `mint_sdk.filesystem` wire models. MINT records the path of
5
+ * data that already sits on a mount; it never copies it.
6
+ */
7
+
8
+ /** What a listing row is. */
9
+ export type FileEntryKind = 'file' | 'directory'
10
+
11
+ /** Field a listing is ordered by, after directories are grouped first. */
12
+ export type FileBrowserSortKey = 'name' | 'size' | 'modified'
13
+
14
+ /** One read-only directory tree exposed by the server. */
15
+ export interface ServerMount {
16
+ id: string
17
+ label: string
18
+ read_only?: boolean
19
+ /** False when the mount is configured but currently unreachable. */
20
+ available?: boolean
21
+ /** Child mounts, used to render the sidebar tree. */
22
+ children?: ServerMount[]
23
+ /** Item count shown beside the mount; free-form so callers can send "1.2k". */
24
+ count?: string | number
25
+ }
26
+
27
+ /** One step of the trail from a mount root to the current directory. */
28
+ export interface FilePathCrumb {
29
+ label: string
30
+ path: string
31
+ }
32
+
33
+ /** A single file or directory inside a mount. */
34
+ export interface FileEntry {
35
+ name: string
36
+ /** Mount-relative POSIX path. */
37
+ path: string
38
+ kind: FileEntryKind
39
+ /** Null for directories. */
40
+ size_bytes?: number | null
41
+ modified_at?: string | null
42
+ extension?: string
43
+ /**
44
+ * False when the entry fails the active type rules. Non-matching entries are
45
+ * still listed — they dim rather than vanish.
46
+ */
47
+ matches_type_rules?: boolean
48
+ /** Directories only. */
49
+ child_count?: number | null
50
+ }
51
+
52
+ /** The contents of one directory inside a mount. */
53
+ export interface FileDirectoryListing {
54
+ mount_id: string
55
+ path: string
56
+ /** Null at the mount root. */
57
+ parent?: string | null
58
+ breadcrumbs?: FilePathCrumb[]
59
+ entries?: FileEntry[]
60
+ /** Directory size before any search filter. */
61
+ total_count?: number
62
+ /** How many entries satisfy the type rules. */
63
+ match_count?: number
64
+ /** How many entries this response carries, after search and any cap. */
65
+ shown_count?: number
66
+ /** True when the directory held more entries than the server will return. */
67
+ truncated?: boolean
68
+ }
69
+
70
+ /** One item the user has picked. */
71
+ export interface FileSelection {
72
+ mount_id: string
73
+ path: string
74
+ name: string
75
+ kind: FileEntryKind
76
+ /** For a directory pick, how many files it contains. */
77
+ child_count?: number | null
78
+ size_bytes?: number | null
79
+ }
80
+
81
+ /** Where the user is standing in the browser. */
82
+ export interface FileBrowserLocation {
83
+ mount_id: string
84
+ path: string
85
+ }
@@ -0,0 +1,65 @@
1
+ /** Sources are supplied by the host; the SDK never infers a host filesystem path. */
2
+ export type PickerSource = 'server' | 'localFile'
3
+ export type PickerSelectionMode = 'single-file' | 'multi-file' | 'folder' | 'folder+files'
4
+
5
+ interface PickerNodeBase {
6
+ path: string
7
+ name: string
8
+ parentPath?: string | null
9
+ parentName?: string
10
+ bytes?: number | null
11
+ /** An explicit adapter failure makes a row inert, including its disclosure. */
12
+ unavailableReason?: string
13
+ }
14
+ export interface PickerFolder extends PickerNodeBase {
15
+ kind: 'folder'
16
+ fileCount?: number | null
17
+ formats?: Record<string, number>
18
+ hasChildren?: boolean
19
+ }
20
+ export interface PickerFile extends PickerNodeBase {
21
+ kind: 'file'
22
+ format: string
23
+ /** Present only for browser-selected files. The picker does not read its bytes. */
24
+ file?: File
25
+ }
26
+ export type PickerNode = PickerFolder | PickerFile
27
+ export interface PickerRequest {
28
+ signal?: AbortSignal
29
+ source?: PickerSource
30
+ }
31
+ export interface PickerAdapter {
32
+ listRoot(request?: PickerRequest): Promise<PickerNode[]>
33
+ listChildren(path: string, request?: PickerRequest): Promise<PickerNode[]>
34
+ search(
35
+ query: string,
36
+ scope: { path: string; recursive: boolean },
37
+ request?: PickerRequest,
38
+ ): Promise<PickerNode[]>
39
+ }
40
+ export interface PickerCapability {
41
+ /** Case-insensitive suffixes, including compound extensions such as mzML.gz. */
42
+ formats: string[]
43
+ maxBytes?: number
44
+ /** Optional host-owned blank classification; no filename heuristics in the SDK. */
45
+ isBlank?: (node: PickerNode) => boolean
46
+ }
47
+ export type PickerCapabilities = Partial<Record<PickerSource, PickerCapability>>
48
+ export type PickerExclusionReason =
49
+ 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable'
50
+ export interface PickerExcluded {
51
+ /** Opaque identity prevents collisions between equal filenames in different folders. */
52
+ path: string
53
+ name: string
54
+ reason: PickerExclusionReason
55
+ }
56
+ export type PickerSelection =
57
+ | { source: 'server'; folders: string[]; files: PickerFile[]; excluded: PickerExcluded[] }
58
+ | { source: 'localFile'; files: File[] }
59
+ export interface PickerTreeRow {
60
+ node: PickerNode
61
+ depth: number
62
+ expanded: boolean
63
+ loading: boolean
64
+ error?: string
65
+ }
@@ -208,6 +208,18 @@ export type {
208
208
  } from './analysisArtifactTypes'
209
209
  export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from './analysisArtifactTypes'
210
210
 
211
+ // File browser types
212
+ export type {
213
+ FileBrowserLocation,
214
+ FileBrowserSortKey,
215
+ FileDirectoryListing,
216
+ FileEntry,
217
+ FileEntryKind,
218
+ FilePathCrumb,
219
+ FileSelection,
220
+ ServerMount,
221
+ } from './fileBrowserTypes'
222
+
211
223
  export type {
212
224
  JobListPayload,
213
225
  JobProgress,
@@ -297,3 +309,5 @@ export type {
297
309
  TableDensity,
298
310
  UserSummary,
299
311
  } from './platform'
312
+
313
+ export type * from './filePicker'