@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,77 @@
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
+ /** What a listing row is. */
8
+ export type FileEntryKind = 'file' | 'directory';
9
+ /** Field a listing is ordered by, after directories are grouped first. */
10
+ export type FileBrowserSortKey = 'name' | 'size' | 'modified';
11
+ /** One read-only directory tree exposed by the server. */
12
+ export interface ServerMount {
13
+ id: string;
14
+ label: string;
15
+ read_only?: boolean;
16
+ /** False when the mount is configured but currently unreachable. */
17
+ available?: boolean;
18
+ /** Child mounts, used to render the sidebar tree. */
19
+ children?: ServerMount[];
20
+ /** Item count shown beside the mount; free-form so callers can send "1.2k". */
21
+ count?: string | number;
22
+ }
23
+ /** One step of the trail from a mount root to the current directory. */
24
+ export interface FilePathCrumb {
25
+ label: string;
26
+ path: string;
27
+ }
28
+ /** A single file or directory inside a mount. */
29
+ export interface FileEntry {
30
+ name: string;
31
+ /** Mount-relative POSIX path. */
32
+ path: string;
33
+ kind: FileEntryKind;
34
+ /** Null for directories. */
35
+ size_bytes?: number | null;
36
+ modified_at?: string | null;
37
+ extension?: string;
38
+ /**
39
+ * False when the entry fails the active type rules. Non-matching entries are
40
+ * still listed — they dim rather than vanish.
41
+ */
42
+ matches_type_rules?: boolean;
43
+ /** Directories only. */
44
+ child_count?: number | null;
45
+ }
46
+ /** The contents of one directory inside a mount. */
47
+ export interface FileDirectoryListing {
48
+ mount_id: string;
49
+ path: string;
50
+ /** Null at the mount root. */
51
+ parent?: string | null;
52
+ breadcrumbs?: FilePathCrumb[];
53
+ entries?: FileEntry[];
54
+ /** Directory size before any search filter. */
55
+ total_count?: number;
56
+ /** How many entries satisfy the type rules. */
57
+ match_count?: number;
58
+ /** How many entries this response carries, after search and any cap. */
59
+ shown_count?: number;
60
+ /** True when the directory held more entries than the server will return. */
61
+ truncated?: boolean;
62
+ }
63
+ /** One item the user has picked. */
64
+ export interface FileSelection {
65
+ mount_id: string;
66
+ path: string;
67
+ name: string;
68
+ kind: FileEntryKind;
69
+ /** For a directory pick, how many files it contains. */
70
+ child_count?: number | null;
71
+ size_bytes?: number | null;
72
+ }
73
+ /** Where the user is standing in the browser. */
74
+ export interface FileBrowserLocation {
75
+ mount_id: string;
76
+ path: string;
77
+ }
@@ -0,0 +1,77 @@
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
+ interface PickerNodeBase {
5
+ path: string;
6
+ name: string;
7
+ parentPath?: string | null;
8
+ parentName?: string;
9
+ bytes?: number | null;
10
+ /** An explicit adapter failure makes a row inert, including its disclosure. */
11
+ unavailableReason?: string;
12
+ }
13
+ export interface PickerFolder extends PickerNodeBase {
14
+ kind: 'folder';
15
+ fileCount?: number | null;
16
+ formats?: Record<string, number>;
17
+ hasChildren?: boolean;
18
+ }
19
+ export interface PickerFile extends PickerNodeBase {
20
+ kind: 'file';
21
+ format: string;
22
+ /** Present only for browser-selected files. The picker does not read its bytes. */
23
+ file?: File;
24
+ }
25
+ export type PickerNode = PickerFolder | PickerFile;
26
+ export interface PickerRequest {
27
+ signal?: AbortSignal;
28
+ source?: PickerSource;
29
+ /**
30
+ * Set only when the user pressed Refresh. Adapters that cache listings (or
31
+ * ask a server to bypass its own cache) should re-read the location then and
32
+ * serve cached data otherwise; the picker keeps folder contents while it is
33
+ * open and re-reads the current location on each open.
34
+ */
35
+ refresh?: true;
36
+ }
37
+ export interface PickerAdapter {
38
+ listRoot(request?: PickerRequest): Promise<PickerNode[]>;
39
+ listChildren(path: string, request?: PickerRequest): Promise<PickerNode[]>;
40
+ search(query: string, scope: {
41
+ path: string;
42
+ recursive: boolean;
43
+ }, request?: PickerRequest): Promise<PickerNode[]>;
44
+ }
45
+ export interface PickerCapability {
46
+ /** Case-insensitive suffixes, including compound extensions such as mzML.gz. */
47
+ formats: string[];
48
+ maxBytes?: number;
49
+ /** Optional host-owned blank classification; no filename heuristics in the SDK. */
50
+ isBlank?: (node: PickerNode) => boolean;
51
+ }
52
+ export type PickerCapabilities = Partial<Record<PickerSource, PickerCapability>>;
53
+ export type PickerExclusionReason = 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable' | 'forbidden';
54
+ export interface PickerExcluded {
55
+ /** Opaque identity prevents collisions between equal filenames in different folders. */
56
+ path: string;
57
+ name: string;
58
+ reason: PickerExclusionReason;
59
+ }
60
+ export type PickerSelection = {
61
+ source: 'server';
62
+ folders: string[];
63
+ files: PickerFile[];
64
+ excluded: PickerExcluded[];
65
+ } | {
66
+ source: 'localFile';
67
+ files: File[];
68
+ relativePaths?: string[];
69
+ };
70
+ export interface PickerTreeRow {
71
+ node: PickerNode;
72
+ depth: number;
73
+ expanded: boolean;
74
+ loading: boolean;
75
+ error?: string;
76
+ }
77
+ export {};
@@ -2,6 +2,7 @@ export type { ContainerDirection, ButtonVariant, ButtonSize, ActionMenuItem, Inp
2
2
  export type * from './generated-ui';
3
3
  export type { AnalysisArtifactStatus, AnalysisArtifactStatusFilter, AnalysisArtifactSummary, AnalysisArtifactDetail, AnalysisArtifactListResponse, AnalysisArtifactTarget, AnalysisArtifactMetadataUpdate, ArtifactSaveMode, ArtifactFileSource, JsonArtifactSavePayload, FileArtifactCreatePayload, FileArtifactUpdatePayload, HandlerFileArtifactCreatePayload, HandlerFileArtifactUpdatePayload, ArtifactSavePayload, HandlerArtifactSavePayload, ArtifactSaveDialogPayload, ArtifactSaveResult, ArtifactSaveHandler, HandlerArtifactSaveHandler, ArtifactSaveDialogHandler, } from './analysisArtifactTypes';
4
4
  export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from './analysisArtifactTypes';
5
+ export type { FileBrowserLocation, FileBrowserSortKey, FileDirectoryListing, FileEntry, FileEntryKind, FilePathCrumb, FileSelection, ServerMount, } from './fileBrowserTypes';
5
6
  export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, } from './jobs';
6
7
  export type { InstrumentAlert, InstrumentAlertBody, InstrumentAlertLevel, InstrumentState, InstrumentStatus, SampleInfo, SampleInfo as InstrumentSampleInfo, SequenceProgress, } from './instrument';
7
8
  export type { LcmsContainerType, LcmsPolarity, LcmsSequenceItem, LcmsSequenceTableColumn, } from '../lcms';
@@ -10,3 +11,4 @@ export type { FormFieldType, FieldCondition, FieldValidation, FormFieldSchema, F
10
11
  export type { OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, } from './auto-group';
11
12
  export type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, } from './auth';
12
13
  export type { PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformContextOptions, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, UserSummary, } from './platform';
14
+ export type * from './filePicker';
@@ -1,7 +1,7 @@
1
- import { c as formatExperimentDate, f as BaseModal_default, h as BaseButton_default, m as useEventListener, p as useFocusTrap } from "./experiment-utils-DV3DrvE_.js";
2
- import { a as BaseSelect_default, i as BasePill_default, n as useRequestSyncState, o as normalizeOptionInput, r as EmptyState_default, s as BaseInput_default, t as Skeleton_default } from "./Skeleton-DxtwJ5gt.js";
3
- import { t as useDropdownState } from "./useDropdownState-DitCtrTT.js";
4
- import { i as useApi, u as tryUseSettingsStore } from "./errors-_W0-LbA6.js";
1
+ import { f as MintApiError, i as useApi, p as mintApiErrorFromResponse, u as tryUseSettingsStore } from "./errors-BLuqMee5.js";
2
+ import { c as formatExperimentDate, f as BaseModal_default, h as BaseButton_default, m as useEventListener, p as useFocusTrap } from "./experiment-utils-CV2Wza3z.js";
3
+ import { a as BaseSelect_default, i as BasePill_default, n as useRequestSyncState, o as normalizeOptionInput, r as EmptyState_default, s as BaseInput_default, t as Skeleton_default } from "./Skeleton-BAF3CKY7.js";
4
+ import { t as useDropdownState } from "./useDropdownState-C7hRiVQf.js";
5
5
  import { hasAllPermissions } from "./permissions.js";
6
6
  import { Fragment, Teleport, Transition, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, getCurrentInstance, getCurrentScope, isRef, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, onUnmounted, openBlock, reactive, ref, renderList, renderSlot, shallowRef, toDisplayString, toValue, unref, useId, useSlots, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
7
7
  import { autoUpdate, computePosition, flip, offset, shift } from "@floating-ui/dom";
@@ -2382,7 +2382,11 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2382
2382
  default: false
2383
2383
  },
2384
2384
  size: { default: "md" },
2385
- mode: { default: "file" }
2385
+ mode: { default: "file" },
2386
+ showFiles: {
2387
+ type: Boolean,
2388
+ default: true
2389
+ }
2386
2390
  },
2387
2391
  emits: [
2388
2392
  "upload",
@@ -2398,8 +2402,9 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2398
2402
  const selectedFiles = ref([]);
2399
2403
  const folderName = ref(null);
2400
2404
  const isFolder = computed(() => props.mode === "folder");
2405
+ const isMixed = computed(() => props.mode === "file+folder");
2401
2406
  const acceptLabel = computed(() => {
2402
- if (!props.accept) return "any file";
2407
+ if (!props.accept) return isFolder.value ? "a folder" : "any file";
2403
2408
  return props.accept.split(",").map((a) => a.trim().replace(".", "").toUpperCase()).join(", ");
2404
2409
  });
2405
2410
  const maxSizeLabel = computed(() => {
@@ -2560,28 +2565,36 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2560
2565
  if (firstPath) return firstPath.split("/")[0];
2561
2566
  return null;
2562
2567
  }
2563
- function handleDrop(event) {
2568
+ async function handleDrop(event) {
2564
2569
  event.preventDefault();
2565
2570
  isDragOver.value = false;
2566
2571
  if (props.disabled) return;
2567
- if (isFolder.value && event.dataTransfer?.items) handleFolderDrop(event.dataTransfer.items);
2568
- else if (event.dataTransfer?.files) handleFiles(event.dataTransfer.files);
2572
+ try {
2573
+ if (props.mode !== "file" && event.dataTransfer?.items?.length) await handleFolderDrop(event.dataTransfer.items);
2574
+ else if (event.dataTransfer?.files) handleFiles(event.dataTransfer.files);
2575
+ } catch (cause) {
2576
+ emit("error", cause instanceof Error ? cause.message : "Could not read the dropped folder.");
2577
+ }
2569
2578
  }
2570
2579
  async function handleFolderDrop(items) {
2571
2580
  const files = [];
2572
2581
  const relativePaths = [];
2573
2582
  let folderNameFromDrop;
2574
- for (const item of Array.from(items)) {
2583
+ const dropped = Array.from(items, (item) => {
2575
2584
  const entry = item.webkitGetAsEntry?.();
2576
- if (entry?.isDirectory) {
2577
- folderNameFromDrop = entry.name;
2578
- await readDirectory(entry, files, relativePaths, entry.name);
2579
- } else if (entry?.isFile) {
2580
- const file = await getFile(entry);
2581
- if (file) {
2582
- files.push(file);
2583
- relativePaths.push(file.name);
2584
- }
2585
+ return {
2586
+ entry,
2587
+ file: entry ? null : item.getAsFile?.()
2588
+ };
2589
+ });
2590
+ for (const { entry, file: droppedFile } of dropped) if (entry?.isDirectory) {
2591
+ folderNameFromDrop = entry.name;
2592
+ await readDirectory(entry, files, relativePaths, entry.name);
2593
+ } else {
2594
+ const file = entry?.isFile ? await getFile(entry) : droppedFile;
2595
+ if (file) {
2596
+ files.push(file);
2597
+ relativePaths.push(file.name);
2585
2598
  }
2586
2599
  }
2587
2600
  if (files.length > 0) handleFiles(files, folderNameFromDrop, relativePaths);
@@ -2644,7 +2657,7 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2644
2657
  createElementVNode("div", {
2645
2658
  role: "button",
2646
2659
  tabindex: "0",
2647
- "aria-label": __props.disabled ? "File upload disabled" : "Click or drag files to upload",
2660
+ "aria-label": __props.disabled ? "File upload disabled" : isMixed.value ? "Drop files or a folder, or click to choose files" : isFolder.value ? "Click or drag a folder to upload" : "Click or drag files to upload",
2648
2661
  "aria-disabled": __props.disabled,
2649
2662
  class: normalizeClass([
2650
2663
  "mint-file-uploader__dropzone",
@@ -2672,9 +2685,9 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2672
2685
  createElementVNode("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" }, null, -1),
2673
2686
  createElementVNode("path", { d: "m16 16-4-4-4 4" }, null, -1),
2674
2687
  createElementVNode("path", { d: "M12 12v9" }, null, -1)
2675
- ])])), createElementVNode("p", _hoisted_7$6, " Drop " + toDisplayString(acceptLabel.value) + " or click ", 1)])], 42, _hoisted_2$8),
2688
+ ])])), createElementVNode("p", _hoisted_7$6, toDisplayString(isMixed.value ? "Drop files or a folder, or click to choose files" : `Drop ${acceptLabel.value} or click`), 1)])], 42, _hoisted_2$8),
2676
2689
  _ctx.$slots.actions ? (openBlock(), createElementBlock("div", _hoisted_8$5, [renderSlot(_ctx.$slots, "actions")])) : createCommentVNode("", true),
2677
- isFolder.value && folderName.value && selectedFiles.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_9$3, [createElementVNode("div", _hoisted_10$3, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "mint-file-uploader__folder-icon-wrapper" }, [createElementVNode("svg", {
2690
+ __props.showFiles && isFolder.value && folderName.value && selectedFiles.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_9$3, [createElementVNode("div", _hoisted_10$3, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "mint-file-uploader__folder-icon-wrapper" }, [createElementVNode("svg", {
2678
2691
  class: "mint-file-uploader__folder-icon",
2679
2692
  fill: "none",
2680
2693
  stroke: "currentColor",
@@ -2696,7 +2709,7 @@ var FileUploader_default = /* @__PURE__ */ defineComponent({
2696
2709
  "stroke-linejoin": "round",
2697
2710
  viewBox: "0 0 24 24"
2698
2711
  }, [createElementVNode("path", { d: "M18 6 6 18" }), createElementVNode("path", { d: "m6 6 12 12" })], -1)])])])) : createCommentVNode("", true),
2699
- !isFolder.value && selectedFiles.value.length > 0 ? (openBlock(), createBlock(TransitionGroup, {
2712
+ __props.showFiles && !isFolder.value && selectedFiles.value.length > 0 ? (openBlock(), createBlock(TransitionGroup, {
2700
2713
  key: 2,
2701
2714
  tag: "ul",
2702
2715
  name: "mint-file-uploader-item",
@@ -3406,14 +3419,6 @@ var SESSION_NOT_FOUND_DETAIL = "Session not found";
3406
3419
  var MAX_RESULT_CACHE_ENTRIES = 32;
3407
3420
  var MAX_RESULT_RETRIES = 3;
3408
3421
  var DOWNLOAD_URL_REFRESH_SKEW_MS = 3e4;
3409
- var GeneratedAnalysisRequestError = class extends Error {
3410
- constructor(status, detail) {
3411
- super(typeof detail === "string" ? detail : `Request failed (${status})`);
3412
- this.status = status;
3413
- this.detail = detail;
3414
- this.name = "GeneratedAnalysisRequestError";
3415
- }
3416
- };
3417
3422
  function createGeneratedAnalysisTransport(options = {}) {
3418
3423
  const fetcher = options.fetcher ?? globalThis.fetch.bind(globalThis);
3419
3424
  const getAccessToken = options.getAccessToken ?? readStoredAccessToken;
@@ -3894,7 +3899,7 @@ function createPluginJobs(options, manifestPath) {
3894
3899
  downloadRefreshTimers.delete(jobId);
3895
3900
  }
3896
3901
  function handleManagedDownloadRefreshFailure(job, cause) {
3897
- if (cause instanceof GeneratedAnalysisRequestError) {
3902
+ if (cause instanceof MintApiError) {
3898
3903
  if (cause.status === 404 || cause.status === 410) {
3899
3904
  discardCachedResult(job.job_id);
3900
3905
  jobs.value = jobs.value.map((candidate) => candidate.job_id === job.job_id ? {
@@ -4047,7 +4052,7 @@ function createPluginJobs(options, manifestPath) {
4047
4052
  });
4048
4053
  if (!response.ok) {
4049
4054
  const payload = await response.json().catch(() => null);
4050
- throw new GeneratedAnalysisRequestError(response.status, payload?.detail);
4055
+ throw mintApiErrorFromResponse(response.status, payload, { requestId: response.headers.get("X-Request-ID") });
4051
4056
  }
4052
4057
  return await response.json();
4053
4058
  }
@@ -4151,13 +4156,13 @@ function createGeneratedSessionStorage(candidate) {
4151
4156
  };
4152
4157
  }
4153
4158
  function isSessionNotFoundError(error) {
4154
- return error instanceof GeneratedAnalysisRequestError && error.status === 404 && error.detail === SESSION_NOT_FOUND_DETAIL;
4159
+ return error instanceof MintApiError && error.status === 404 && (error.detail === SESSION_NOT_FOUND_DETAIL || error.message === SESSION_NOT_FOUND_DETAIL);
4155
4160
  }
4156
4161
  function isRetryableResultError(error) {
4157
- return !(error instanceof GeneratedAnalysisRequestError) || error.status === 409 || error.status === 429 || error.status >= 500;
4162
+ return !(error instanceof MintApiError) || error.status === 409 || error.status === 429 || error.status >= 500;
4158
4163
  }
4159
4164
  function isRetryableJobLookupError(error) {
4160
- return !(error instanceof GeneratedAnalysisRequestError) || error.status === 408 || error.status === 429 || error.status >= 500;
4165
+ return !(error instanceof MintApiError) || error.status === 408 || error.status === 429 || error.status >= 500;
4161
4166
  }
4162
4167
  function isManagedDownloadResult(result) {
4163
4168
  return result.kind === "artifact" && result.managed === true;
@@ -7183,4 +7188,4 @@ function useControlSchema(controls, options = {}) {
7183
7188
  //#endregion
7184
7189
  export { resolveJobCapabilities as $, useConcentrationUnits as A, formatTimeSlot as At, currentExperimentFromContext as B, MultiSelect_default as Bt, controlsToViewIds as C, addMinutes as Ct, getTypeDefault as D, findNearestTimeSlotIndex as Dt, getFieldRegistryEntry as E, findAvailableSlots as Et, ATOMIC_WEIGHTS as F, rangesOverlap as Ft, createGeneratedAnalysisTransport as G, BaseToggle_default as Gt, parseExperimentId as H, useSelectionLimit as Ht, useChemicalFormula as I, snapToSlot as It, isActiveJobStatus as J, BaseTextarea_default as Jt, useGeneratedAnalysis as K, BaseCheckbox_default as Kt, GeneratedPathInput_default as L, toMinutes as Lt, SequenceInput_default as M, generateTimeSlots as Mt, useSequenceUtils as N, isTimeInRange as Nt, ConcentrationInput_default as O, formatDuration as Ot, FormulaInput_default as P, parseTime as Pt, normalizeJobState as Q, ArtifactSelectorModal_default as R, useTimeUtils as Rt, controlsToTopBarSettingsConfig as S, TimePicker_default as St, getDefaultControlView as T, durationMinutes as Tt, resolveCurrentExperimentId as U, BaseSlider_default as Ut, getInjectedPlatformContext as V, useListSelection as Vt, resolveCurrentPluginId as W, BaseRadioGroup_default as Wt, jobStatusLabel as X, isTerminalJobStatus as Y, normalizeJobPercent as Z, controlsToFormSchema as _, pluginSecretLabel as _t, defineDoseCalculatorControlProps as a, AlertBox_default as at, controlsToSettingsSchema as b, usesPluginSecretReferences as bt, defineWellPlateDoseComponentBindings as c, SecretInput_default as ct, defineControlModel as d, PLUGIN_SECRET_REF_KEY as dt, useEventStream as et, resolveControlModel as f, clearPluginSecret as ft, mergeControlWorkspaceOptions as g, pluginSecretId as gt, controlValuesToComponentProps as h, keepPluginSecret as ht, useControlSchema as i, _plugin_vue_export_helper_default as it, MoleculeInput_default as j, fromMinutes as jt, UnitInput_default as k, formatTime as kt, defineWellPlateDoseControlProps as l, PLUGIN_SECRET_FORMAT_KEY as lt, controlValuesToComponentBindingsById as m, isPluginSecretRef as mt, defineControls as n, isObjectLike as nt, defineDoseDesignControlModel as o, FileUploader_default as ot, controlValuesToComponentBindings as p, isPluginSecretLocked as pt, usePluginJobs as q, Tooltip_default as qt, getControlDefaults as r, isRecord as rt, defineWellPlateControlProps as s, NumberInput_default as st, defineControlComponentBindings as t, DateTimePicker_default as tt, useControlWorkspace as u, PLUGIN_SECRET_FORMAT_REF as ut, controlsToSectionFormSchema as v, pluginSecretState as vt, controlsToViewItems as w, compareTime as wt, controlsToSidebarPanels as x, TagsInput_default as xt, controlsToSectionFormSchemas as y, setPluginSecret as yt, useAnalysisArtifacts as z, DatePicker_default as zt };
7185
7190
 
7186
- //# sourceMappingURL=useControlSchema-aMZlb4Sc.js.map
7191
+ //# sourceMappingURL=useControlSchema-DldpxNOP.js.map