@morscherlab/mint-sdk 1.2.0-beta.9 → 1.2.0

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 (152) hide show
  1. package/README.md +30 -0
  2. package/dist/{ExperimentPopover-oL0fg_A0.js → ExperimentPopover-CJdNlCZb.js} +21 -14
  3. package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-BeEOomw_.js → ExperimentSelectorModal-DCXmwKNS.js} +5 -5
  5. package/dist/{ExperimentSelectorModal-BeEOomw_.js.map → ExperimentSelectorModal-DCXmwKNS.js.map} +1 -1
  6. package/dist/{SettingsModal-Dphh3RrI.js → SettingsModal-BYR20I4c.js} +5 -5
  7. package/dist/{SettingsModal-Dphh3RrI.js.map → SettingsModal-BYR20I4c.js.map} +1 -1
  8. package/dist/{Skeleton-DxtwJ5gt.js → Skeleton-BAF3CKY7.js} +3 -3
  9. package/dist/{Skeleton-DxtwJ5gt.js.map → Skeleton-BAF3CKY7.js.map} +1 -1
  10. package/dist/__tests__/apiErrors.test.d.ts +1 -0
  11. package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
  12. package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
  13. package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
  14. package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
  15. package/dist/__tests__/components/iconButtonIconSizing.test.d.ts +1 -0
  16. package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
  17. package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
  18. package/dist/apiErrors.d.ts +26 -0
  19. package/dist/components/BaseInput.vue.d.ts +1 -1
  20. package/dist/components/BaseSelect.vue.d.ts +1 -1
  21. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  22. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  23. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
  24. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  25. package/dist/components/DatePicker.vue.d.ts +1 -1
  26. package/dist/components/DateTimePicker.vue.d.ts +1 -1
  27. package/dist/components/FileBrowserModal.vue.d.ts +99 -0
  28. package/dist/components/FilePicker.vue.d.ts +32 -0
  29. package/dist/components/FileUploader.vue.d.ts +5 -2
  30. package/dist/components/FormulaInput.vue.d.ts +1 -1
  31. package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
  32. package/dist/components/MobileSupportGate.vue.d.ts +1 -1
  33. package/dist/components/MoleculeInput.vue.d.ts +1 -1
  34. package/dist/components/NumberInput.vue.d.ts +1 -1
  35. package/dist/components/PlotlyChart.vue.d.ts +59 -0
  36. package/dist/components/ResourceCard.vue.d.ts +1 -1
  37. package/dist/components/SecretInput.vue.d.ts +1 -1
  38. package/dist/components/SequenceInput.vue.d.ts +1 -1
  39. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  40. package/dist/components/TagsInput.vue.d.ts +1 -1
  41. package/dist/components/TimePicker.vue.d.ts +1 -1
  42. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  43. package/dist/components/UnitInput.vue.d.ts +1 -1
  44. package/dist/components/WellPlate.vue.d.ts +1 -1
  45. package/dist/components/fileBrowserPresentation.d.ts +10 -0
  46. package/dist/components/index.d.ts +4 -0
  47. package/dist/components/index.js +8 -8
  48. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
  49. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
  50. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
  51. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
  52. package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
  53. package/dist/{components-CgAUzF8F.js → components-DIum5hkx.js} +4286 -1866
  54. package/dist/components-DIum5hkx.js.map +1 -0
  55. package/dist/composables/filePicker/localFiles.d.ts +3 -0
  56. package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
  57. package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
  58. package/dist/composables/filePicker/validation.d.ts +5 -0
  59. package/dist/composables/index.d.ts +2 -0
  60. package/dist/composables/index.js +10 -10
  61. package/dist/composables/useApi.d.ts +14 -7
  62. package/dist/composables/useFileBrowser.d.ts +55 -0
  63. package/dist/composables/useFilePicker.d.ts +189 -0
  64. package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
  65. package/dist/{composables-B_pia3hO.js → composables-mFXsTA4g.js} +300 -11
  66. package/dist/composables-mFXsTA4g.js.map +1 -0
  67. package/dist/{errors-_W0-LbA6.js → errors-BLuqMee5.js} +78 -15
  68. package/dist/errors-BLuqMee5.js.map +1 -0
  69. package/dist/{experiment-Cwl9AYxw.js → experiment-CVDRAnqp.js} +2 -2
  70. package/dist/{experiment-Cwl9AYxw.js.map → experiment-CVDRAnqp.js.map} +1 -1
  71. package/dist/{experiment-utils-DV3DrvE_.js → experiment-utils-CV2Wza3z.js} +1 -1
  72. package/dist/{experiment-utils-DV3DrvE_.js.map → experiment-utils-CV2Wza3z.js.map} +1 -1
  73. package/dist/index.d.ts +1 -0
  74. package/dist/index.js +15 -15
  75. package/dist/install.js +2 -2
  76. package/dist/stores/index.js +2 -2
  77. package/dist/styles.css +2369 -1377
  78. package/dist/templates/index.js +2 -2
  79. package/dist/{templates-Qq113pyZ.js → templates-CmGfmBRA.js} +2 -2
  80. package/dist/{templates-Qq113pyZ.js.map → templates-CmGfmBRA.js.map} +1 -1
  81. package/dist/types/fileBrowserTypes.d.ts +77 -0
  82. package/dist/types/filePicker.d.ts +77 -0
  83. package/dist/types/index.d.ts +2 -0
  84. package/dist/{useControlSchema-aMZlb4Sc.js → useControlSchema-DldpxNOP.js} +42 -37
  85. package/dist/useControlSchema-DldpxNOP.js.map +1 -0
  86. package/dist/{useDropdownState-DitCtrTT.js → useDropdownState-C7hRiVQf.js} +2 -2
  87. package/dist/{useDropdownState-DitCtrTT.js.map → useDropdownState-C7hRiVQf.js.map} +1 -1
  88. package/dist/{useExperimentSelector-I8HC8hUu.js → useExperimentSelector-CEcIaueJ.js} +4 -4
  89. package/dist/{useExperimentSelector-I8HC8hUu.js.map → useExperimentSelector-CEcIaueJ.js.map} +1 -1
  90. package/dist/{useFormBuilder-TCxNnqeb.js → useFormBuilder-z5L_dUIy.js} +2 -2
  91. package/dist/{useFormBuilder-TCxNnqeb.js.map → useFormBuilder-z5L_dUIy.js.map} +1 -1
  92. package/dist/{useProtocolTemplates-BmX_iVBR.js → validation-uwoJGEb6.js} +53 -8
  93. package/dist/validation-uwoJGEb6.js.map +1 -0
  94. package/package.json +1 -1
  95. package/src/__tests__/apiErrors.test.ts +81 -0
  96. package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
  97. package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
  98. package/src/__tests__/components/FilePicker.state.test.ts +287 -0
  99. package/src/__tests__/components/FilePicker.test.ts +487 -0
  100. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
  101. package/src/__tests__/components/PlotlyChart.test.ts +305 -0
  102. package/src/__tests__/components/SegmentedControl.test.ts +19 -0
  103. package/src/__tests__/components/iconButtonIconSizing.test.ts +18 -0
  104. package/src/__tests__/composables/useApi.test.ts +92 -9
  105. package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
  106. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
  107. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
  108. package/src/__tests__/composables/usePluginClient.test.ts +3 -0
  109. package/src/apiErrors.ts +85 -0
  110. package/src/components/ExperimentPopover.vue +10 -2
  111. package/src/components/FileBrowserModal.story.vue +203 -0
  112. package/src/components/FileBrowserModal.vue +384 -0
  113. package/src/components/FilePicker.story.vue +44 -0
  114. package/src/components/FilePicker.vue +284 -0
  115. package/src/components/FileUploader.vue +32 -14
  116. package/src/components/GeneratedPlotlyResult.vue +34 -69
  117. package/src/components/GeneratedResultRenderer.vue +0 -5
  118. package/src/components/PlotlyChart.story.vue +61 -0
  119. package/src/components/PlotlyChart.vue +233 -0
  120. package/src/components/SegmentedControl.vue +2 -2
  121. package/src/components/fileBrowserPresentation.ts +39 -0
  122. package/src/components/index.ts +5 -0
  123. package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
  124. package/src/components/internal/FileBrowserListingInternal.vue +197 -0
  125. package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
  126. package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
  127. package/src/components/internal/FilePickerTreeInternal.vue +238 -0
  128. package/src/composables/filePicker/localFiles.ts +58 -0
  129. package/src/composables/filePicker/usePickerNavigation.ts +220 -0
  130. package/src/composables/filePicker/usePickerSelection.ts +259 -0
  131. package/src/composables/filePicker/validation.ts +41 -0
  132. package/src/composables/index.ts +7 -0
  133. package/src/composables/useApi.ts +57 -13
  134. package/src/composables/useFileBrowser.ts +314 -0
  135. package/src/composables/useFilePicker.ts +366 -0
  136. package/src/composables/useGeneratedAnalysis.ts +10 -17
  137. package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
  138. package/src/composables/usePluginClient.ts +3 -0
  139. package/src/index.ts +3 -0
  140. package/src/styles/components/file-browser-modal.css +489 -0
  141. package/src/styles/components/file-picker.css +502 -0
  142. package/src/styles/components/icon-button.css +9 -0
  143. package/src/styles/index.css +3 -0
  144. package/src/types/fileBrowserTypes.ts +85 -0
  145. package/src/types/filePicker.ts +72 -0
  146. package/src/types/index.ts +14 -0
  147. package/dist/ExperimentPopover-oL0fg_A0.js.map +0 -1
  148. package/dist/components-CgAUzF8F.js.map +0 -1
  149. package/dist/composables-B_pia3hO.js.map +0 -1
  150. package/dist/errors-_W0-LbA6.js.map +0 -1
  151. package/dist/useControlSchema-aMZlb4Sc.js.map +0 -1
  152. package/dist/useProtocolTemplates-BmX_iVBR.js.map +0 -1
@@ -0,0 +1,502 @@
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-upload {
390
+ display: flex;
391
+ flex-direction: column;
392
+ gap: 8px;
393
+ padding: 12px 18px;
394
+ flex-shrink: 0;
395
+ color: var(--text-muted);
396
+ font-size: 11px;
397
+ }
398
+ .mint-picker__local-title {
399
+ flex: 1;
400
+ }
401
+ @media (max-width: 600px) {
402
+ .mint-picker-dialog .mint-file-browser-dialog__header {
403
+ padding: 10px;
404
+ gap: 6px;
405
+ flex-wrap: nowrap;
406
+ }
407
+ .mint-picker__search .mint-input {
408
+ font-size: 12px;
409
+ padding-right: 8px;
410
+ }
411
+ .mint-picker__search > kbd {
412
+ display: none;
413
+ }
414
+ .mint-picker__pathbar {
415
+ padding-inline: 8px;
416
+ gap: 2px;
417
+ }
418
+ .mint-picker__workspace {
419
+ grid-template-columns: minmax(0, 1fr);
420
+ height: 390px;
421
+ }
422
+ .mint-picker__preview {
423
+ display: none;
424
+ }
425
+ .mint-picker__workspace:has(.mint-picker__exclusion) {
426
+ grid-template-columns: minmax(0, 1fr) 160px;
427
+ }
428
+ .mint-picker__workspace:has(.mint-picker__exclusion) .mint-picker__preview {
429
+ display: flex;
430
+ }
431
+ .mint-picker__row {
432
+ gap: 4px;
433
+ padding-right: 5px;
434
+ }
435
+ .mint-picker__name {
436
+ font-size: 12px;
437
+ }
438
+ .mint-picker__footer {
439
+ align-items: stretch;
440
+ flex-direction: column;
441
+ gap: 8px;
442
+ }
443
+ .mint-picker__actions {
444
+ justify-content: flex-end;
445
+ }
446
+ .mint-picker__receipt {
447
+ min-height: 24px;
448
+ }
449
+ }
450
+ @media (max-height: 600px) {
451
+ .mint-picker {
452
+ overflow-y: auto;
453
+ }
454
+ .mint-picker__workspace {
455
+ min-height: 220px;
456
+ }
457
+ }
458
+
459
+ /* The source highlight slides between fixed-size SDK icon buttons. */
460
+ .mint-picker__source-indicator {
461
+ box-sizing: border-box;
462
+ position: absolute;
463
+ inset: 2px auto 2px 2px;
464
+ width: 32px;
465
+ border: 1px solid var(--border-color);
466
+ border-radius: var(--radius-md);
467
+ background: var(--bg-secondary);
468
+ box-shadow: var(--shadow-sm);
469
+ pointer-events: none;
470
+ transform: translateX(calc(var(--picker-source-index, 0) * 34px));
471
+ transition: transform 180ms ease-out;
472
+ }
473
+ .mint-picker__sources .mint-icon-button {
474
+ position: relative;
475
+ width: 32px;
476
+ height: 32px;
477
+ }
478
+ .mint-picker__sources .mint-icon-button[aria-pressed='true'] {
479
+ color: var(--text-primary);
480
+ background: transparent;
481
+ }
482
+ .mint-picker__source-panel {
483
+ animation: mint-picker-source-in 180ms ease-out;
484
+ }
485
+ @keyframes mint-picker-source-in {
486
+ from {
487
+ opacity: 0;
488
+ transform: translateY(4px);
489
+ }
490
+ to {
491
+ opacity: 1;
492
+ transform: translateY(0);
493
+ }
494
+ }
495
+ @media (prefers-reduced-motion: reduce) {
496
+ .mint-picker__source-indicator {
497
+ transition: none;
498
+ }
499
+ .mint-picker__source-panel {
500
+ animation: none;
501
+ }
502
+ }
@@ -167,6 +167,15 @@
167
167
  height: 1.5rem;
168
168
  }
169
169
 
170
+ /* A bare <svg> in the slot has no intrinsic size and collapses to 0 width as a
171
+ flex item; fill the sized icon box so callers need not size their icon. */
172
+ .mint-icon-button__icon--sm > svg,
173
+ .mint-icon-button__icon--md > svg,
174
+ .mint-icon-button__icon--lg > svg {
175
+ width: 100%;
176
+ height: 100%;
177
+ }
178
+
170
179
  /* Spinner */
171
180
  .mint-icon-button__spinner {
172
181
  animation: mint-spin 1s linear infinite;
@@ -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,72 @@
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
+ * Set only when the user pressed Refresh. Adapters that cache listings (or
32
+ * ask a server to bypass its own cache) should re-read the location then and
33
+ * serve cached data otherwise; the picker keeps folder contents while it is
34
+ * open and re-reads the current location on each open.
35
+ */
36
+ refresh?: true
37
+ }
38
+ export interface PickerAdapter {
39
+ listRoot(request?: PickerRequest): Promise<PickerNode[]>
40
+ listChildren(path: string, request?: PickerRequest): Promise<PickerNode[]>
41
+ search(
42
+ query: string,
43
+ scope: { path: string; recursive: boolean },
44
+ request?: PickerRequest,
45
+ ): Promise<PickerNode[]>
46
+ }
47
+ export interface PickerCapability {
48
+ /** Case-insensitive suffixes, including compound extensions such as mzML.gz. */
49
+ formats: string[]
50
+ maxBytes?: number
51
+ /** Optional host-owned blank classification; no filename heuristics in the SDK. */
52
+ isBlank?: (node: PickerNode) => boolean
53
+ }
54
+ export type PickerCapabilities = Partial<Record<PickerSource, PickerCapability>>
55
+ export type PickerExclusionReason =
56
+ 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable' | 'forbidden'
57
+ export interface PickerExcluded {
58
+ /** Opaque identity prevents collisions between equal filenames in different folders. */
59
+ path: string
60
+ name: string
61
+ reason: PickerExclusionReason
62
+ }
63
+ export type PickerSelection =
64
+ | { source: 'server'; folders: string[]; files: PickerFile[]; excluded: PickerExcluded[] }
65
+ | { source: 'localFile'; files: File[]; relativePaths?: string[] }
66
+ export interface PickerTreeRow {
67
+ node: PickerNode
68
+ depth: number
69
+ expanded: boolean
70
+ loading: boolean
71
+ error?: string
72
+ }
@@ -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'