@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
@@ -1,9 +1,10 @@
1
- import { n as useRequestSyncState } from "./Skeleton-DxtwJ5gt.js";
2
- import { B as currentExperimentFromContext, U as resolveCurrentExperimentId, V as getInjectedPlatformContext, et as useEventStream, lt as PLUGIN_SECRET_FORMAT_KEY } from "./useControlSchema-aMZlb4Sc.js";
3
- import { a as useAuthStore, d as useSettingsStore, i as useApi, n as AuthenticationRequiredError, r as authenticationRequiredError, t as readErrorMessage } from "./errors-_W0-LbA6.js";
4
- import { i as usePlatformContext } from "./useFormBuilder-TCxNnqeb.js";
5
- import { bn as rowLabel, pn as PLATE_CONFIGS, yn as rowIndex } from "./templates-Qq113pyZ.js";
6
- import { computed, getCurrentInstance, onMounted, onUnmounted, ref, shallowRef, toValue, watch } from "vue";
1
+ import { a as useAuthStore, d as useSettingsStore, i as useApi, n as AuthenticationRequiredError, r as authenticationRequiredError, t as readErrorMessage } from "./errors-BLuqMee5.js";
2
+ import { n as useRequestSyncState } from "./Skeleton-BAF3CKY7.js";
3
+ import { B as currentExperimentFromContext, U as resolveCurrentExperimentId, V as getInjectedPlatformContext, et as useEventStream, lt as PLUGIN_SECRET_FORMAT_KEY } from "./useControlSchema-DldpxNOP.js";
4
+ import { n as pickerFormat } from "./validation-uwoJGEb6.js";
5
+ import { i as usePlatformContext } from "./useFormBuilder-z5L_dUIy.js";
6
+ import { bn as rowLabel, pn as PLATE_CONFIGS, yn as rowIndex } from "./templates-CmGfmBRA.js";
7
+ import { computed, getCurrentInstance, getCurrentScope, onMounted, onScopeDispose, onUnmounted, ref, shallowRef, toValue, watch } from "vue";
7
8
  import axios from "axios";
8
9
  //#region src/composables/useAuth.ts
9
10
  var TOKEN_REFRESH_MARGIN_MS = 300 * 1e3;
@@ -749,6 +750,212 @@ function usePluginConfig(pluginName) {
749
750
  };
750
751
  }
751
752
  //#endregion
753
+ //#region src/composables/useFileBrowser.ts
754
+ /**
755
+ * Drives FileBrowserModal against the platform's `/api/filesystem` routes.
756
+ *
757
+ * Requires the `filesystem.browse` permission and a deployment that declares
758
+ * mounts; with none configured the routes are absent and `mounts` stays empty.
759
+ */
760
+ function useFileBrowser(options = {}) {
761
+ const injectedContext = getInjectedPlatformContext();
762
+ const api = useApi({ baseUrl: options.apiBaseUrl ?? injectedContext?.platformApiUrl });
763
+ const sync = useRequestSyncState("Could not read the server mounts.");
764
+ const mounts = ref([]);
765
+ const mountId = shallowRef("");
766
+ const path = shallowRef("");
767
+ const parent = ref(null);
768
+ const entries = ref([]);
769
+ const breadcrumbs = ref([]);
770
+ const totalCount = ref(null);
771
+ const matchCount = ref(null);
772
+ const shownCount = ref(null);
773
+ const truncated = ref(false);
774
+ const search = shallowRef("");
775
+ const sort = shallowRef("name");
776
+ const selected = ref([]);
777
+ const mountsLoading = shallowRef(false);
778
+ const listingLoading = shallowRef(false);
779
+ const listingReady = shallowRef(false);
780
+ const isLoading = computed(() => mountsLoading.value || listingLoading.value);
781
+ let listToken = 0;
782
+ let mountsToken = 0;
783
+ let disposed = false;
784
+ let listingController;
785
+ let mountsController;
786
+ let searchTimer;
787
+ function resetListing() {
788
+ listingReady.value = false;
789
+ entries.value = [];
790
+ breadcrumbs.value = [];
791
+ parent.value = null;
792
+ totalCount.value = null;
793
+ matchCount.value = null;
794
+ shownCount.value = null;
795
+ truncated.value = false;
796
+ }
797
+ function typeRuleParams() {
798
+ return (toValue(options.typeRules) ?? []).map((rule) => `&type_rules=${encodeURIComponent(rule)}`).join("");
799
+ }
800
+ /** Prefer the API's own `detail` over axios's "Request failed with status N". */
801
+ function describe(cause, fallback) {
802
+ const detail = cause?.response?.data?.detail;
803
+ return typeof detail === "string" && detail ? detail : sync.readErrorMessage(cause, fallback);
804
+ }
805
+ function fail(cause, fallback) {
806
+ sync.setError(new Error(describe(cause, fallback)), fallback);
807
+ }
808
+ function statusOf(cause) {
809
+ return cause?.response?.status;
810
+ }
811
+ async function loadMounts() {
812
+ const token = ++mountsToken;
813
+ mountsController?.abort();
814
+ mountsController = new AbortController();
815
+ mountsLoading.value = true;
816
+ try {
817
+ const data = await api.get("/filesystem/mounts", { signal: mountsController.signal });
818
+ if (disposed || token !== mountsToken) return false;
819
+ mounts.value = data.mounts ?? [];
820
+ sync.clearError();
821
+ sync.markLoaded();
822
+ return true;
823
+ } catch (cause) {
824
+ if (disposed || token !== mountsToken) return false;
825
+ if (statusOf(cause) === 404) {
826
+ mounts.value = [];
827
+ sync.clearError();
828
+ sync.markLoaded();
829
+ return true;
830
+ }
831
+ mounts.value = [];
832
+ fail(cause, "Could not read the server mounts.");
833
+ return false;
834
+ } finally {
835
+ if (token === mountsToken) mountsLoading.value = false;
836
+ }
837
+ }
838
+ async function navigate(location) {
839
+ if (disposed || !location.mount_id) return;
840
+ clearTimeout(searchTimer);
841
+ const token = ++listToken;
842
+ listingController?.abort();
843
+ listingController = new AbortController();
844
+ listingLoading.value = true;
845
+ mountId.value = location.mount_id;
846
+ path.value = location.path;
847
+ resetListing();
848
+ sync.clearError();
849
+ try {
850
+ const query = `mount_id=${encodeURIComponent(location.mount_id)}&path=${encodeURIComponent(location.path)}&sort=${sort.value}` + (search.value ? `&search=${encodeURIComponent(search.value)}` : "") + typeRuleParams();
851
+ const listing = await api.get(`/filesystem/browse?${query}`, { signal: listingController.signal });
852
+ if (disposed || token !== listToken) return;
853
+ mountId.value = listing.mount_id;
854
+ path.value = listing.path;
855
+ parent.value = listing.parent ?? null;
856
+ entries.value = listing.entries ?? [];
857
+ breadcrumbs.value = listing.breadcrumbs ?? [];
858
+ totalCount.value = listing.total_count ?? null;
859
+ matchCount.value = listing.match_count ?? null;
860
+ shownCount.value = listing.shown_count ?? listing.entries?.length ?? null;
861
+ truncated.value = listing.truncated ?? false;
862
+ listingReady.value = true;
863
+ sync.clearError();
864
+ sync.markLoaded();
865
+ } catch (cause) {
866
+ if (disposed || token !== listToken) return;
867
+ entries.value = [];
868
+ fail(cause, "Could not read that folder.");
869
+ } finally {
870
+ if (token === listToken) listingLoading.value = false;
871
+ }
872
+ }
873
+ async function init() {
874
+ if (disposed) return;
875
+ const navigationToken = listToken;
876
+ if (!await loadMounts() || disposed || navigationToken !== listToken) return;
877
+ const preferred = toValue(options.initialMountId);
878
+ const reachable = (mount) => mount.available !== false;
879
+ const target = mounts.value.find((mount) => mount.id === preferred && reachable(mount)) ?? mounts.value.find(reachable);
880
+ if (target) await navigate({
881
+ mount_id: target.id,
882
+ path: ""
883
+ });
884
+ else {
885
+ mountId.value = "";
886
+ path.value = "";
887
+ resetListing();
888
+ }
889
+ }
890
+ async function refresh() {
891
+ if (disposed) return;
892
+ if (mountId.value) await navigate({
893
+ mount_id: mountId.value,
894
+ path: path.value
895
+ });
896
+ else await init();
897
+ }
898
+ function selectCurrentFolder() {
899
+ if (!mountId.value || !listingReady.value || isLoading.value || sync.error.value) return;
900
+ const crumb = breadcrumbs.value[breadcrumbs.value.length - 1];
901
+ const key = JSON.stringify([mountId.value, path.value]);
902
+ if (selected.value.some((item) => JSON.stringify([item.mount_id, item.path]) === key)) return;
903
+ selected.value = [...selected.value, {
904
+ mount_id: mountId.value,
905
+ path: path.value,
906
+ name: crumb?.label ?? path.value,
907
+ kind: "directory",
908
+ child_count: totalCount.value
909
+ }];
910
+ }
911
+ function clear() {
912
+ selected.value = [];
913
+ }
914
+ watch(search, () => {
915
+ if (!mountId.value) return;
916
+ clearTimeout(searchTimer);
917
+ searchTimer = setTimeout(() => {
918
+ refresh();
919
+ }, 250);
920
+ });
921
+ watch(sort, () => {
922
+ if (mountId.value) refresh();
923
+ });
924
+ watch(() => toValue(options.typeRules), () => {
925
+ if (mountId.value) refresh();
926
+ }, { deep: true });
927
+ if (getCurrentScope()) onScopeDispose(() => {
928
+ disposed = true;
929
+ ++listToken;
930
+ ++mountsToken;
931
+ clearTimeout(searchTimer);
932
+ listingController?.abort();
933
+ mountsController?.abort();
934
+ });
935
+ return {
936
+ mounts,
937
+ mountId,
938
+ path,
939
+ parent,
940
+ entries,
941
+ breadcrumbs,
942
+ totalCount,
943
+ matchCount,
944
+ shownCount,
945
+ truncated,
946
+ search,
947
+ sort,
948
+ selected,
949
+ isLoading,
950
+ error: sync.error,
951
+ init,
952
+ navigate,
953
+ refresh,
954
+ selectCurrentFolder,
955
+ clear
956
+ };
957
+ }
958
+ //#endregion
752
959
  //#region src/composables/analysisArtifactTarget.ts
753
960
  var EXPERIMENT_ID = "experiment_id";
754
961
  var ARTIFACT_PLUGIN_ID = "artifact_plugin_id";
@@ -1522,7 +1729,8 @@ function createPluginClient(contract, options) {
1522
1729
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1523
1730
  const api = useApi({
1524
1731
  baseUrl: parts.baseUrl,
1525
- withAuth: endpoint.requiresAuth !== false
1732
+ withAuth: endpoint.requiresAuth !== false,
1733
+ typedErrors: true
1526
1734
  });
1527
1735
  const config = endpointRequestConfig(endpoint, parts.query, callOptions);
1528
1736
  if (endpoint.method === "get") return api.get(parts.path, config);
@@ -1553,7 +1761,8 @@ async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
1553
1761
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1554
1762
  const api = useApi({
1555
1763
  baseUrl: parts.baseUrl,
1556
- withAuth: endpoint.requiresAuth !== false
1764
+ withAuth: endpoint.requiresAuth !== false,
1765
+ typedErrors: true
1557
1766
  });
1558
1767
  const body = endpoint.hasBody ? requestBodyFromPayload(payload, parts.requestPayload, endpoint) : payload;
1559
1768
  if (endpoint.requestContentType === OCTET_STREAM) {
@@ -1578,7 +1787,8 @@ async function downloadPluginEndpoint(contract, endpoint, payload, options = {})
1578
1787
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1579
1788
  const api = useApi({
1580
1789
  baseUrl: parts.baseUrl,
1581
- withAuth: endpoint.requiresAuth !== false
1790
+ withAuth: endpoint.requiresAuth !== false,
1791
+ typedErrors: true
1582
1792
  });
1583
1793
  const config = {
1584
1794
  ...endpointRequestConfig(endpoint, parts.query, { signal: options.signal }) ?? {},
@@ -1890,6 +2100,85 @@ function useCurrentExperiment(options = {}) {
1890
2100
  };
1891
2101
  }
1892
2102
  //#endregion
1893
- export { useAsync as A, createPluginResourceClient as C, buildAnalysisArtifactTargetQuery as D, useCommandHistory as E, resolvePluginFrontendBase as M, usePasskey as N, parseAnalysisArtifactTarget as O, useAuth as P, wellIdsInRectangle as S, useOptimisticMutation as T, createWellPlateWells as _, pluginFormDataFromPayload as a, useWellPainting as b, usePluginClient as c, buildPluginEndpointUrl as d, resolvePluginBaseUrl as f, createRowConditions as g, createColumnConditions as h, getPluginPageSelectorItems as i, useAsyncBatch as j, usePluginConfig as k, usePluginEventStream as l, useWellPlateValidation as m, downloadBlob as n, uploadPluginEndpoint as o, runWellPlateValidation as p, downloadPluginEndpoint as r, useCurrentExperiment as s, createPluginClient as t, usePluginSettings as u, useWellPlateAdapter as v, useResourceCrud as w, wellIdToCoordinate as x, coordinateToWellId as y };
2103
+ //#region src/composables/usePlatformFilePickerAdapter.ts
2104
+ /** Opaque picker identity; decode before passing a selection to a mount-scoped API. */
2105
+ function encodePlatformPickerPath(mountId, path = "") {
2106
+ return JSON.stringify([mountId, path]);
2107
+ }
2108
+ function decodePlatformPickerPath(path) {
2109
+ const decoded = JSON.parse(path);
2110
+ if (!Array.isArray(decoded) || decoded.length !== 2 || !decoded.every((item) => typeof item === "string") || !decoded[0]) throw new Error("Invalid platform picker path.");
2111
+ return {
2112
+ mountId: decoded[0],
2113
+ path: decoded[1]
2114
+ };
2115
+ }
2116
+ /** Adapt the authenticated MINT mount API without exposing absolute host paths. */
2117
+ function usePlatformFilePickerAdapter(options = {}) {
2118
+ const api = useApi({ baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl });
2119
+ const mountLabels = /* @__PURE__ */ new Map();
2120
+ async function listRoot(request) {
2121
+ try {
2122
+ const { mounts } = await api.get("/filesystem/mounts", { signal: request?.signal });
2123
+ return mounts.map((mount) => {
2124
+ mountLabels.set(mount.id, mount.label);
2125
+ return {
2126
+ kind: "folder",
2127
+ path: encodePlatformPickerPath(mount.id),
2128
+ name: mount.label,
2129
+ parentPath: null,
2130
+ parentName: "Server mounts",
2131
+ unavailableReason: mount.available === false ? "This mount is offline." : void 0
2132
+ };
2133
+ });
2134
+ } catch (cause) {
2135
+ if (cause.response?.status === 404) return [];
2136
+ throw cause;
2137
+ }
2138
+ }
2139
+ async function listChildren(path, request) {
2140
+ const location = decodePlatformPickerPath(path);
2141
+ const query = new URLSearchParams({
2142
+ mount_id: location.mountId,
2143
+ path: location.path
2144
+ });
2145
+ const listing = await api.get(`/filesystem/browse?${query}`, { signal: request?.signal });
2146
+ if (listing.truncated) throw new Error("This directory exceeds the server listing limit. Choose a smaller data directory.");
2147
+ return (listing.entries ?? []).map((entry) => ({
2148
+ kind: entry.kind === "directory" ? "folder" : "file",
2149
+ path: encodePlatformPickerPath(location.mountId, entry.path),
2150
+ parentPath: path,
2151
+ parentName: `${mountLabels.get(location.mountId) ?? location.mountId}${location.path ? ` / ${location.path}` : ""}`,
2152
+ name: entry.name,
2153
+ bytes: entry.size_bytes,
2154
+ ...entry.kind === "directory" ? { hasChildren: entry.child_count !== 0 } : { format: pickerFormat(entry.name) }
2155
+ }));
2156
+ }
2157
+ return {
2158
+ listRoot,
2159
+ listChildren,
2160
+ async search(query, scope, request) {
2161
+ const matches = [];
2162
+ const queue = [scope.path];
2163
+ const visited = /* @__PURE__ */ new Set();
2164
+ while (queue.length) {
2165
+ request?.signal?.throwIfAborted();
2166
+ const path = queue.shift();
2167
+ if (visited.has(path)) continue;
2168
+ visited.add(path);
2169
+ if (visited.size > 500) throw new Error("Search reached its folder limit. Search a smaller location or turn off Subfolders.");
2170
+ const nodes = path ? await listChildren(path, request) : await listRoot(request);
2171
+ for (const node of nodes) {
2172
+ if (node.name.toLowerCase().includes(query.toLowerCase())) matches.push(node);
2173
+ if (scope.recursive && node.kind === "folder" && !node.unavailableReason) queue.push(node.path);
2174
+ }
2175
+ if (matches.length > 1e4) throw new Error("Too many search results. Use a more specific search.");
2176
+ }
2177
+ return matches;
2178
+ }
2179
+ };
2180
+ }
2181
+ //#endregion
2182
+ export { buildAnalysisArtifactTargetQuery as A, useWellPainting as C, useResourceCrud as D, createPluginResourceClient as E, useAsyncBatch as F, resolvePluginFrontendBase as I, usePasskey as L, useFileBrowser as M, usePluginConfig as N, useOptimisticMutation as O, useAsync as P, useAuth as R, coordinateToWellId as S, wellIdsInRectangle as T, useWellPlateValidation as _, downloadBlob as a, createWellPlateWells as b, pluginFormDataFromPayload as c, usePluginClient as d, usePluginEventStream as f, runWellPlateValidation as g, resolvePluginBaseUrl as h, createPluginClient as i, parseAnalysisArtifactTarget as j, useCommandHistory as k, uploadPluginEndpoint as l, buildPluginEndpointUrl as m, encodePlatformPickerPath as n, downloadPluginEndpoint as o, usePluginSettings as p, usePlatformFilePickerAdapter as r, getPluginPageSelectorItems as s, decodePlatformPickerPath as t, useCurrentExperiment as u, createColumnConditions as v, wellIdToCoordinate as w, useWellPlateAdapter as x, createRowConditions as y };
1894
2183
 
1895
- //# sourceMappingURL=composables-B_pia3hO.js.map
2184
+ //# sourceMappingURL=composables-mFXsTA4g.js.map