@morscherlab/mint-sdk 1.0.63 → 1.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -2
- package/dist/EmptyState-D1c4RdC7.js +638 -0
- package/dist/EmptyState-D1c4RdC7.js.map +1 -0
- package/dist/{ExperimentPopover-BbPkIFsI.js → ExperimentPopover-BFw3QX8L.js} +10 -9
- package/dist/{ExperimentPopover-BbPkIFsI.js.map → ExperimentPopover-BFw3QX8L.js.map} +1 -1
- package/dist/{ExperimentSelectorModal-DZeSd-yr.js → ExperimentSelectorModal-B7w6k3Y8.js} +12 -216
- package/dist/ExperimentSelectorModal-B7w6k3Y8.js.map +1 -0
- package/dist/{SettingsModal-CJgLadsN.js → SettingsModal-DPDwCbXK.js} +12 -9
- package/dist/{SettingsModal-CJgLadsN.js.map → SettingsModal-DPDwCbXK.js.map} +1 -1
- package/dist/__tests__/components/GeneratedPlotlyResult.test.d.ts +1 -0
- package/dist/__tests__/components/GeneratedPluginView.test.d.ts +1 -0
- package/dist/__tests__/components/GeneratedResultRenderer.test.d.ts +1 -0
- package/dist/__tests__/components/InstrumentAlertLog.test.d.ts +1 -0
- package/dist/__tests__/composables/useGeneratedAnalysis.test.d.ts +1 -0
- package/dist/__tests__/generatedUi.test.d.ts +1 -0
- package/dist/{analysisArtifactTypes-Cu40dzSG.js → analysisArtifactTypes-ejqR8MX3.js} +1 -1
- package/dist/analysisArtifactTypes-ejqR8MX3.js.map +1 -0
- package/dist/{auth-DZAwEeis.js → auth-B87xM--s.js} +1 -1
- package/dist/{auth-DZAwEeis.js.map → auth-B87xM--s.js.map} +1 -1
- package/dist/chunk-BoAXSpZd.js +33 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/AutoGroupModal.vue.d.ts +2 -2
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
- package/dist/components/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/ComponentBindingRenderer.vue.d.ts +1 -1
- package/dist/components/ConfirmDialog.vue.d.ts +1 -1
- package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
- package/dist/components/ExperimentTimeline.vue.d.ts +1 -1
- package/dist/components/FileUploader.vue.d.ts +4 -2
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/FormActions.vue.d.ts +1 -1
- package/dist/components/FormBuilder.vue.d.ts +1 -1
- package/dist/components/GeneratedPathInput.vue.d.ts +12 -0
- package/dist/components/GeneratedPlotlyResult.vue.d.ts +11 -0
- package/dist/components/GeneratedPluginView.vue.d.ts +10 -0
- package/dist/components/GeneratedResultRenderer.vue.d.ts +6 -0
- package/dist/components/JobsStatusTray.vue.d.ts +5 -1
- package/dist/components/LcmsSequenceTable.vue.d.ts +1 -1
- package/dist/components/SampleLegend.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +2 -2
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +8 -9
- package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +2 -2
- package/dist/{components-DdzHh3a_.js → components-UfkPN1bK.js} +2255 -2303
- package/dist/components-UfkPN1bK.js.map +1 -0
- package/dist/composables/index.d.ts +2 -3
- package/dist/composables/index.js +10 -11
- package/dist/composables/platformContextHelpers.d.ts +0 -2
- package/dist/composables/useAnalysisArtifacts.d.ts +1 -3
- package/dist/composables/useGeneratedAnalysis.d.ts +62 -0
- package/dist/composables/useJobsStatusTray.d.ts +48 -4
- package/dist/composables/usePlatformContext.d.ts +3 -0
- package/dist/composables/usePluginClient.d.ts +6 -3
- package/dist/{composables-BUUphBqg.js → composables-B512bWJP.js} +155 -74
- package/dist/composables-B512bWJP.js.map +1 -0
- package/dist/experiment-utils-CxkruZ3G.js +392 -0
- package/dist/experiment-utils-CxkruZ3G.js.map +1 -0
- package/dist/generated/schema.d.ts +7 -0
- package/dist/generated-ui/main.d.ts +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -18
- package/dist/index.js.map +1 -1
- package/dist/install.js +7 -8
- package/dist/install.js.map +1 -1
- package/dist/plotly.min-BR53hja4.js +180634 -0
- package/dist/plotly.min-BR53hja4.js.map +1 -0
- package/dist/stores/auth.d.ts +2 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +10543 -10404
- package/dist/templates/index.js +4 -3
- package/dist/templates/packs.d.ts +0 -1
- package/dist/{templates-CNbPQNID.js → templates-Cttbjbyc.js} +2 -4
- package/dist/templates-Cttbjbyc.js.map +1 -0
- package/dist/types/analysisArtifactTypes.d.ts +0 -8
- package/dist/types/form-builder.d.ts +1 -1
- package/dist/types/generated-ui.d.ts +170 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +1 -1
- package/dist/types/instrument.d.ts +1 -0
- package/dist/types/jobs.d.ts +7 -1
- package/dist/types/platform.d.ts +2 -0
- package/dist/{useControlSchema-BZNdalmL.js → useControlSchema-Dallso-L.js} +1852 -171
- package/dist/useControlSchema-Dallso-L.js.map +1 -0
- package/dist/{useDropdownState-Bb-c_PeE.js → useDropdownState-gVaMXtwW.js} +2 -2
- package/dist/{useDropdownState-Bb-c_PeE.js.map → useDropdownState-gVaMXtwW.js.map} +1 -1
- package/dist/{useExperimentSelector-DRbj6vse.js → useExperimentSelector-BMjzNcf2.js} +4 -255
- package/dist/useExperimentSelector-BMjzNcf2.js.map +1 -0
- package/dist/{useFormBuilder-DKekvXRs.js → useFormBuilder-BXaaDI41.js} +2 -2
- package/dist/{useFormBuilder-DKekvXRs.js.map → useFormBuilder-BXaaDI41.js.map} +1 -1
- package/dist/{useAnalysisArtifacts-C3l0a0vu.js → useProtocolTemplates-BP7_4RGQ.js} +307 -475
- package/dist/useProtocolTemplates-BP7_4RGQ.js.map +1 -0
- package/package.json +7 -3
- package/src/__tests__/components/GeneratedPathInput.test.ts +132 -0
- package/src/__tests__/components/GeneratedPlotlyResult.test.ts +117 -0
- package/src/__tests__/components/GeneratedPluginView.test.ts +230 -0
- package/src/__tests__/components/GeneratedResultRenderer.test.ts +93 -0
- package/src/__tests__/components/InstrumentAlertLog.test.ts +59 -0
- package/src/__tests__/composables/formBuilderRegistry.test.ts +5 -1
- package/src/__tests__/composables/useAnalysisArtifacts.test.ts +1 -74
- package/src/__tests__/composables/useApi.test.ts +8 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +1740 -0
- package/src/__tests__/composables/useJobsStatusTray.test.ts +179 -1
- package/src/__tests__/composables/usePlatformContext.test.ts +28 -0
- package/src/__tests__/composables/usePluginClient.test.ts +366 -20
- package/src/__tests__/composables/usePluginConfig.test.ts +323 -7
- package/src/__tests__/docs/extractDocsTemplates.test.ts +0 -1
- package/src/__tests__/generatedUi.test.ts +119 -0
- package/src/__tests__/templates/templates.test.ts +1 -1
- package/src/components/FileUploader.vue +49 -11
- package/src/components/GeneratedPathInput.vue +218 -0
- package/src/components/GeneratedPlotlyResult.vue +87 -0
- package/src/components/GeneratedPluginView.vue +279 -0
- package/src/components/GeneratedResultRenderer.vue +137 -0
- package/src/components/InstrumentAlertLog.vue +2 -2
- package/src/components/JobsStatusTray.vue +14 -8
- package/src/components/index.ts +4 -0
- package/src/composables/formBuilderRegistry.ts +2 -0
- package/src/composables/index.ts +18 -5
- package/src/composables/platformContextHelpers.ts +3 -10
- package/src/composables/useAnalysisArtifacts.ts +0 -48
- package/src/composables/useApi.ts +1 -0
- package/src/composables/useGeneratedAnalysis.ts +1252 -0
- package/src/composables/useJobsStatusTray.ts +234 -45
- package/src/composables/usePluginClient.ts +152 -25
- package/src/composables/usePluginConfig.ts +156 -20
- package/src/generated/schema.ts +130 -0
- package/src/generated-ui/main.ts +21 -0
- package/src/index.ts +3 -0
- package/src/jobs.ts +5 -0
- package/src/plotly-dist.d.ts +3 -0
- package/src/templates/packs.ts +0 -3
- package/src/types/analysisArtifactTypes.ts +0 -9
- package/src/types/form-builder.ts +1 -0
- package/src/types/generated-ui.ts +176 -0
- package/src/types/index.ts +2 -1
- package/src/types/instrument.ts +1 -0
- package/src/types/jobs.ts +10 -1
- package/src/types/platform.ts +2 -0
- package/dist/BaseButton-Dgqrze41.js +0 -74
- package/dist/BaseButton-Dgqrze41.js.map +0 -1
- package/dist/BaseModal-B9UA8Y_I.js +0 -165
- package/dist/BaseModal-B9UA8Y_I.js.map +0 -1
- package/dist/BaseSelect-ekgr9fDo.js +0 -179
- package/dist/BaseSelect-ekgr9fDo.js.map +0 -1
- package/dist/ExperimentPopover-Ryusjrhv.js +0 -4
- package/dist/ExperimentSelectorModal-Cg4-LXBD.js +0 -5
- package/dist/ExperimentSelectorModal-DZeSd-yr.js.map +0 -1
- package/dist/SettingsModal-Bl_9w2Y3.js +0 -5
- package/dist/analysisArtifactTypes-Cu40dzSG.js.map +0 -1
- package/dist/components-DdzHh3a_.js.map +0 -1
- package/dist/composables/analysisArtifactTarget.d.ts +0 -5
- package/dist/composables-BUUphBqg.js.map +0 -1
- package/dist/experiment-utils-Bfa7CwPU.js +0 -108
- package/dist/experiment-utils-Bfa7CwPU.js.map +0 -1
- package/dist/templates-CNbPQNID.js.map +0 -1
- package/dist/useAnalysisArtifacts-C3l0a0vu.js.map +0 -1
- package/dist/useControlSchema-BZNdalmL.js.map +0 -1
- package/dist/useEventListener-CfVkP9Xz.js +0 -57
- package/dist/useEventListener-CfVkP9Xz.js.map +0 -1
- package/dist/useExperimentSelector-DRbj6vse.js.map +0 -1
- package/src/__tests__/composables/analysisArtifactTarget.test.ts +0 -77
- package/src/composables/analysisArtifactTarget.ts +0 -53
- /package/dist/__tests__/{composables/analysisArtifactTarget.test.d.ts → components/GeneratedPathInput.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { a as authenticationRequiredError, i as AuthenticationRequiredError, o as useApi, r as useRequestSyncState } from "./EmptyState-D1c4RdC7.js";
|
|
2
|
+
import { H as getInjectedPlatformContext, V as currentExperimentFromContext, W as resolveCurrentExperimentId } from "./useControlSchema-Dallso-L.js";
|
|
3
|
+
import { r as useSettingsStore, t as useAuthStore } from "./auth-B87xM--s.js";
|
|
4
|
+
import { i as usePlatformContext } from "./useFormBuilder-BXaaDI41.js";
|
|
5
5
|
import { computed, getCurrentInstance, onMounted, onUnmounted, ref, shallowRef, toValue, watch } from "vue";
|
|
6
6
|
import axios from "axios";
|
|
7
7
|
//#region src/composables/useAuth.ts
|
|
@@ -614,13 +614,39 @@ function useAsyncBatch(asyncFns) {
|
|
|
614
614
|
}
|
|
615
615
|
//#endregion
|
|
616
616
|
//#region src/composables/usePluginConfig.ts
|
|
617
|
+
var PLATFORM_OWNED_SETTINGS_KEY$1 = "allowed_experiment_types";
|
|
618
|
+
function cloneConfig(config) {
|
|
619
|
+
return JSON.parse(JSON.stringify(config));
|
|
620
|
+
}
|
|
621
|
+
function hasOwnConfig(config, key) {
|
|
622
|
+
return Object.prototype.hasOwnProperty.call(config, key);
|
|
623
|
+
}
|
|
624
|
+
function changedTopLevelKeys(current, saved) {
|
|
625
|
+
return new Set([...new Set([...Object.keys(current), ...Object.keys(saved)])].filter((key) => JSON.stringify(current[key]) !== JSON.stringify(saved[key])));
|
|
626
|
+
}
|
|
627
|
+
function topLevelConfigPatch(current, keys) {
|
|
628
|
+
return Object.fromEntries([...keys].map((key) => [key, hasOwnConfig(current, key) ? current[key] : null]));
|
|
629
|
+
}
|
|
630
|
+
function platformOwnedConfigPatch(config) {
|
|
631
|
+
return { [PLATFORM_OWNED_SETTINGS_KEY$1]: hasOwnConfig(config, PLATFORM_OWNED_SETTINGS_KEY$1) ? config[PLATFORM_OWNED_SETTINGS_KEY$1] : null };
|
|
632
|
+
}
|
|
633
|
+
function responseConfigPayload(response) {
|
|
634
|
+
return response.config ?? response.settings ?? {};
|
|
635
|
+
}
|
|
617
636
|
/** Loads, saves, and tracks dirty state for a plugin's persistent configuration via the platform API. */
|
|
618
637
|
function usePluginConfig(pluginName) {
|
|
619
|
-
const
|
|
638
|
+
const injectedContext = getInjectedPlatformContext();
|
|
620
639
|
const { plugin } = usePlatformContext();
|
|
621
|
-
const
|
|
640
|
+
const platformApi = useApi();
|
|
641
|
+
const pluginApi = useApi({ baseUrl: injectedContext?.plugin?.api_prefix ?? plugin.value?.api_prefix });
|
|
642
|
+
const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? injectedContext?.plugin?.name ?? "");
|
|
643
|
+
const usesPluginSettingsApi = computed(() => {
|
|
644
|
+
const currentPlugin = injectedContext?.plugin ?? plugin.value;
|
|
645
|
+
return currentPlugin?.settings_api === "plugin" && resolvedName.value === currentPlugin.name;
|
|
646
|
+
});
|
|
622
647
|
const config = ref({});
|
|
623
648
|
const savedConfig = ref({});
|
|
649
|
+
const revision = ref(null);
|
|
624
650
|
const request = useRequestSyncState("Plugin config request failed.");
|
|
625
651
|
const isLoading = ref(false);
|
|
626
652
|
const isSaving = ref(false);
|
|
@@ -635,12 +661,17 @@ function usePluginConfig(pluginName) {
|
|
|
635
661
|
if (!name) return;
|
|
636
662
|
isLoading.value = true;
|
|
637
663
|
try {
|
|
638
|
-
const response = await request.run(() =>
|
|
664
|
+
const response = usesPluginSettingsApi.value ? await request.run(() => pluginApi.get("/settings"), {
|
|
665
|
+
success: "load",
|
|
666
|
+
errorMessage: "Failed to load plugin config"
|
|
667
|
+
}) : await request.run(() => platformApi.get(`/plugins/${encodeURIComponent(name)}/config`), {
|
|
639
668
|
success: "load",
|
|
640
669
|
errorMessage: "Failed to load plugin config"
|
|
641
670
|
});
|
|
642
|
-
|
|
643
|
-
|
|
671
|
+
const responseConfig = responseConfigPayload(response);
|
|
672
|
+
config.value = cloneConfig(responseConfig);
|
|
673
|
+
savedConfig.value = cloneConfig(responseConfig);
|
|
674
|
+
revision.value = response.revision ?? null;
|
|
644
675
|
} catch {} finally {
|
|
645
676
|
isLoading.value = false;
|
|
646
677
|
}
|
|
@@ -650,12 +681,39 @@ function usePluginConfig(pluginName) {
|
|
|
650
681
|
if (!name) return false;
|
|
651
682
|
isSaving.value = true;
|
|
652
683
|
try {
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
684
|
+
const payload = cloneConfig(config.value);
|
|
685
|
+
let response;
|
|
686
|
+
let nextRevision = revision.value;
|
|
687
|
+
if (usesPluginSettingsApi.value) {
|
|
688
|
+
response = await request.run(() => pluginApi.put("/settings", payload, revision.value ? { headers: { "If-Match": `"${revision.value}"` } } : void 0), {
|
|
689
|
+
success: "save",
|
|
690
|
+
errorMessage: "Failed to save plugin config"
|
|
691
|
+
});
|
|
692
|
+
nextRevision = response.revision ?? nextRevision;
|
|
693
|
+
} else {
|
|
694
|
+
const dirtyKeys = changedTopLevelKeys(payload, savedConfig.value);
|
|
695
|
+
const platformOwnedChanged = dirtyKeys.has(PLATFORM_OWNED_SETTINGS_KEY$1);
|
|
696
|
+
const typedKeys = [...dirtyKeys].filter((key) => key !== PLATFORM_OWNED_SETTINGS_KEY$1);
|
|
697
|
+
if (typedKeys.length) {
|
|
698
|
+
response = await request.run(() => platformApi.patch(`/plugins/${encodeURIComponent(name)}/config`, { config: topLevelConfigPatch(payload, typedKeys) }), {
|
|
699
|
+
success: "save",
|
|
700
|
+
errorMessage: "Failed to save plugin config"
|
|
701
|
+
});
|
|
702
|
+
nextRevision = response.revision ?? nextRevision;
|
|
703
|
+
}
|
|
704
|
+
if (platformOwnedChanged) {
|
|
705
|
+
response = await request.run(() => platformApi.patch(`/plugins/${encodeURIComponent(name)}/config`, { config: platformOwnedConfigPatch(payload) }), {
|
|
706
|
+
success: "save",
|
|
707
|
+
errorMessage: "Failed to save plugin config"
|
|
708
|
+
});
|
|
709
|
+
nextRevision = response.revision ?? nextRevision;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (!response) return true;
|
|
713
|
+
const responseConfig = responseConfigPayload(response);
|
|
714
|
+
config.value = cloneConfig(responseConfig);
|
|
715
|
+
savedConfig.value = cloneConfig(responseConfig);
|
|
716
|
+
revision.value = response.revision ?? nextRevision;
|
|
659
717
|
return true;
|
|
660
718
|
} catch {
|
|
661
719
|
return false;
|
|
@@ -664,7 +722,7 @@ function usePluginConfig(pluginName) {
|
|
|
664
722
|
}
|
|
665
723
|
}
|
|
666
724
|
function reset() {
|
|
667
|
-
config.value =
|
|
725
|
+
config.value = cloneConfig(savedConfig.value);
|
|
668
726
|
request.clearError();
|
|
669
727
|
}
|
|
670
728
|
onMounted(() => {
|
|
@@ -684,41 +742,6 @@ function usePluginConfig(pluginName) {
|
|
|
684
742
|
};
|
|
685
743
|
}
|
|
686
744
|
//#endregion
|
|
687
|
-
//#region src/composables/analysisArtifactTarget.ts
|
|
688
|
-
var EXPERIMENT_ID = "experiment_id";
|
|
689
|
-
var ARTIFACT_PLUGIN_ID = "artifact_plugin_id";
|
|
690
|
-
var ARTIFACT_KEY = "artifact_key";
|
|
691
|
-
var ARTIFACT_ID = "artifact_id";
|
|
692
|
-
function parsePositiveInteger(value) {
|
|
693
|
-
if (value === null || !/^\d+$/.test(value)) return void 0;
|
|
694
|
-
const parsed = Number(value);
|
|
695
|
-
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
696
|
-
}
|
|
697
|
-
/** Build the canonical query used to open one analysis artifact in a plugin. */
|
|
698
|
-
function buildAnalysisArtifactTargetQuery(target) {
|
|
699
|
-
const query = new URLSearchParams();
|
|
700
|
-
query.set(EXPERIMENT_ID, String(target.experimentId));
|
|
701
|
-
query.set(ARTIFACT_PLUGIN_ID, target.artifactPluginId);
|
|
702
|
-
query.set(ARTIFACT_KEY, target.artifactKey);
|
|
703
|
-
if (target.artifactId !== void 0) query.set(ARTIFACT_ID, String(target.artifactId));
|
|
704
|
-
return query;
|
|
705
|
-
}
|
|
706
|
-
/** Parse a complete canonical target. Incomplete or invalid input is not guessed. */
|
|
707
|
-
function parseAnalysisArtifactTarget(query) {
|
|
708
|
-
const experimentId = parsePositiveInteger(query.get(EXPERIMENT_ID));
|
|
709
|
-
const artifactPluginId = query.get(ARTIFACT_PLUGIN_ID)?.trim();
|
|
710
|
-
const artifactKey = query.get(ARTIFACT_KEY)?.trim();
|
|
711
|
-
const rawArtifactId = query.get(ARTIFACT_ID);
|
|
712
|
-
const artifactId = parsePositiveInteger(rawArtifactId);
|
|
713
|
-
if (experimentId === void 0 || !artifactPluginId || !artifactKey || rawArtifactId !== null && artifactId === void 0) return null;
|
|
714
|
-
return {
|
|
715
|
-
experimentId,
|
|
716
|
-
artifactPluginId,
|
|
717
|
-
artifactKey,
|
|
718
|
-
...artifactId === void 0 ? {} : { artifactId }
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
//#endregion
|
|
722
745
|
//#region src/composables/useCommandHistory.ts
|
|
723
746
|
/** Generic command-stack state for plugin editors with undo/redo controls. */
|
|
724
747
|
function useCommandHistory(options = {}) {
|
|
@@ -1472,7 +1495,7 @@ function pluginPageIdFromPath(path, fallbackIndex) {
|
|
|
1472
1495
|
if (normalizedPath === "/") return "dashboard";
|
|
1473
1496
|
return normalizedPath.replace(/^\/+/, "").replace(/\/+/g, "-") || `page-${fallbackIndex + 1}`;
|
|
1474
1497
|
}
|
|
1475
|
-
/** Convert
|
|
1498
|
+
/** Convert resolved @mint_plugin nav_items into page selectors for the topbar and homepage PluginCards. */
|
|
1476
1499
|
function getPluginPageSelectorItems(contract) {
|
|
1477
1500
|
const pluginIcon = contract.plugin.icon ?? "";
|
|
1478
1501
|
return (contract.plugin.navItems ?? []).map((item, index) => ({
|
|
@@ -1490,7 +1513,10 @@ function createPluginClient(contract, options) {
|
|
|
1490
1513
|
const payload = hasPayload ? payloadOrOptions : void 0;
|
|
1491
1514
|
const callOptions = hasPayload ? explicitOptions : payloadOrOptions ?? explicitOptions;
|
|
1492
1515
|
const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
|
|
1493
|
-
const api = useApi({
|
|
1516
|
+
const api = useApi({
|
|
1517
|
+
baseUrl: parts.baseUrl,
|
|
1518
|
+
withAuth: endpoint.requiresAuth !== false
|
|
1519
|
+
});
|
|
1494
1520
|
const config = endpointRequestConfig(endpoint, parts.query, callOptions);
|
|
1495
1521
|
if (endpoint.method === "get") return api.get(parts.path, config);
|
|
1496
1522
|
if (endpoint.method === "delete") {
|
|
@@ -1518,7 +1544,10 @@ async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
|
|
|
1518
1544
|
"patch"
|
|
1519
1545
|
].includes(endpoint.method)) throw new Error(`[MINT SDK] Plugin upload endpoints must use POST, PUT, or PATCH; got ${endpoint.method}`);
|
|
1520
1546
|
const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
|
|
1521
|
-
const api = useApi({
|
|
1547
|
+
const api = useApi({
|
|
1548
|
+
baseUrl: parts.baseUrl,
|
|
1549
|
+
withAuth: endpoint.requiresAuth !== false
|
|
1550
|
+
});
|
|
1522
1551
|
const body = endpoint.hasBody ? requestBodyFromPayload(payload, parts.requestPayload, endpoint) : payload;
|
|
1523
1552
|
if (endpoint.requestContentType === OCTET_STREAM) {
|
|
1524
1553
|
const config = endpointRequestConfig(endpoint, parts.query, { signal: options.signal });
|
|
@@ -1540,7 +1569,10 @@ async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
|
|
|
1540
1569
|
async function downloadPluginEndpoint(contract, endpoint, payload, options = {}) {
|
|
1541
1570
|
if (endpoint.requestContentType === MULTIPART_FORM_DATA) throw new Error("[MINT SDK] Plugin download endpoints do not support multipart request bodies");
|
|
1542
1571
|
const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
|
|
1543
|
-
const api = useApi({
|
|
1572
|
+
const api = useApi({
|
|
1573
|
+
baseUrl: parts.baseUrl,
|
|
1574
|
+
withAuth: endpoint.requiresAuth !== false
|
|
1575
|
+
});
|
|
1544
1576
|
const config = {
|
|
1545
1577
|
...endpointRequestConfig(endpoint, parts.query, { signal: options.signal }) ?? {},
|
|
1546
1578
|
responseType: "blob"
|
|
@@ -1567,8 +1599,12 @@ function usePluginClient(client) {
|
|
|
1567
1599
|
function normalizePluginSettingsOptions(options = {}) {
|
|
1568
1600
|
return typeof options === "string" ? { pluginName: options } : options;
|
|
1569
1601
|
}
|
|
1602
|
+
var PLATFORM_OWNED_SETTINGS_KEY = "allowed_experiment_types";
|
|
1570
1603
|
function cloneRecord(value) {
|
|
1571
|
-
return
|
|
1604
|
+
return JSON.parse(JSON.stringify(value));
|
|
1605
|
+
}
|
|
1606
|
+
function hasOwnSetting(settings, key) {
|
|
1607
|
+
return Object.prototype.hasOwnProperty.call(settings, key);
|
|
1572
1608
|
}
|
|
1573
1609
|
function responseSettingsPayload(response) {
|
|
1574
1610
|
if (!response || typeof response !== "object") return {};
|
|
@@ -1577,6 +1613,20 @@ function responseSettingsPayload(response) {
|
|
|
1577
1613
|
if (data.settings && typeof data.settings === "object") return cloneRecord(data.settings);
|
|
1578
1614
|
return {};
|
|
1579
1615
|
}
|
|
1616
|
+
function responseSettingsRevision(response) {
|
|
1617
|
+
if (!response || typeof response !== "object") return null;
|
|
1618
|
+
const revision = response.revision;
|
|
1619
|
+
return typeof revision === "string" && revision ? revision : null;
|
|
1620
|
+
}
|
|
1621
|
+
function topLevelSettingsPatch(current, keys) {
|
|
1622
|
+
return Object.fromEntries([...keys].map((key) => [key, hasOwnSetting(current, key) ? current[key] : null]));
|
|
1623
|
+
}
|
|
1624
|
+
function changedTopLevelSettingKeys(current, saved) {
|
|
1625
|
+
return new Set([...new Set([...Object.keys(current), ...Object.keys(saved)])].filter((key) => JSON.stringify(current[key]) !== JSON.stringify(saved[key])));
|
|
1626
|
+
}
|
|
1627
|
+
function platformOwnedSettingsPatch(settings) {
|
|
1628
|
+
return { [PLATFORM_OWNED_SETTINGS_KEY]: hasOwnSetting(settings, PLATFORM_OWNED_SETTINGS_KEY) ? settings[PLATFORM_OWNED_SETTINGS_KEY] : null };
|
|
1629
|
+
}
|
|
1580
1630
|
/** Load, edit, and persist plugin settings from platform config or the plugin-local settings router. */
|
|
1581
1631
|
function usePluginSettings(options = {}) {
|
|
1582
1632
|
const resolvedOptions = normalizePluginSettingsOptions(options);
|
|
@@ -1584,13 +1634,18 @@ function usePluginSettings(options = {}) {
|
|
|
1584
1634
|
const { plugin, isIntegrated } = usePlatformContext();
|
|
1585
1635
|
const platformApi = useApi({ baseUrl: resolvedOptions.platformApiBaseUrl ?? injectedContext?.platformApiUrl });
|
|
1586
1636
|
const pluginApi = useApi({ baseUrl: resolvedOptions.apiBaseUrl ?? injectedContext?.plugin?.api_prefix });
|
|
1587
|
-
const values =
|
|
1637
|
+
const values = ref({});
|
|
1588
1638
|
const savedValues = shallowRef({});
|
|
1639
|
+
const revision = ref(null);
|
|
1589
1640
|
const request = useRequestSyncState("Plugin settings request failed.");
|
|
1590
1641
|
const isLoading = ref(false);
|
|
1591
1642
|
const isSaving = ref(false);
|
|
1592
1643
|
const resolvedPluginName = computed(() => resolvedOptions.pluginName ?? plugin.value?.name ?? injectedContext?.plugin?.name ?? "");
|
|
1593
|
-
const
|
|
1644
|
+
const usesPluginSettingsApi = computed(() => {
|
|
1645
|
+
const currentPlugin = injectedContext?.plugin ?? plugin.value;
|
|
1646
|
+
return currentPlugin?.settings_api === "plugin" && resolvedPluginName.value === currentPlugin.name;
|
|
1647
|
+
});
|
|
1648
|
+
const usesPlatformConfig = computed(() => Boolean((isIntegrated.value || injectedContext?.isIntegrated) && resolvedPluginName.value && !usesPluginSettingsApi.value));
|
|
1594
1649
|
const settings = computed(() => values.value);
|
|
1595
1650
|
const isDirty = computed(() => JSON.stringify(values.value) !== JSON.stringify(savedValues.value));
|
|
1596
1651
|
const settingsConfig = computed(() => ({
|
|
@@ -1602,21 +1657,23 @@ function usePluginSettings(options = {}) {
|
|
|
1602
1657
|
function setValues(nextValues) {
|
|
1603
1658
|
values.value = cloneRecord(nextValues);
|
|
1604
1659
|
}
|
|
1605
|
-
function applyLoaded(nextValues) {
|
|
1660
|
+
function applyLoaded(nextValues, nextRevision) {
|
|
1606
1661
|
const cloned = cloneRecord(nextValues);
|
|
1607
1662
|
values.value = cloned;
|
|
1608
1663
|
savedValues.value = cloneRecord(cloned);
|
|
1664
|
+
revision.value = nextRevision;
|
|
1609
1665
|
}
|
|
1610
1666
|
async function load() {
|
|
1611
1667
|
isLoading.value = true;
|
|
1612
1668
|
try {
|
|
1613
|
-
|
|
1669
|
+
const response = usesPlatformConfig.value ? await request.run(() => platformApi.get(`/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`), {
|
|
1614
1670
|
success: "load",
|
|
1615
1671
|
errorMessage: "Failed to load plugin settings"
|
|
1616
1672
|
}) : await request.run(() => pluginApi.get("/settings"), {
|
|
1617
1673
|
success: "load",
|
|
1618
1674
|
errorMessage: "Failed to load plugin settings"
|
|
1619
|
-
})
|
|
1675
|
+
});
|
|
1676
|
+
applyLoaded(responseSettingsPayload(response), responseSettingsRevision(response));
|
|
1620
1677
|
} catch {} finally {
|
|
1621
1678
|
isLoading.value = false;
|
|
1622
1679
|
}
|
|
@@ -1626,13 +1683,37 @@ function usePluginSettings(options = {}) {
|
|
|
1626
1683
|
isSaving.value = true;
|
|
1627
1684
|
try {
|
|
1628
1685
|
const payload = cloneRecord(values.value);
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1686
|
+
let response;
|
|
1687
|
+
if (usesPlatformConfig.value) {
|
|
1688
|
+
const dirtyKeys = changedTopLevelSettingKeys(payload, savedValues.value);
|
|
1689
|
+
const platformOwnedChanged = dirtyKeys.has(PLATFORM_OWNED_SETTINGS_KEY);
|
|
1690
|
+
const typedKeys = [...dirtyKeys].filter((key) => key !== PLATFORM_OWNED_SETTINGS_KEY);
|
|
1691
|
+
let nextRevision = revision.value;
|
|
1692
|
+
if (typedKeys.length) {
|
|
1693
|
+
response = await request.run(() => platformApi.patch(`/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`, { config: topLevelSettingsPatch(payload, typedKeys) }), {
|
|
1694
|
+
success: "save",
|
|
1695
|
+
errorMessage: "Failed to save plugin settings"
|
|
1696
|
+
});
|
|
1697
|
+
nextRevision = responseSettingsRevision(response) ?? nextRevision;
|
|
1698
|
+
}
|
|
1699
|
+
if (platformOwnedChanged) {
|
|
1700
|
+
response = await request.run(() => platformApi.patch(`/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`, { config: platformOwnedSettingsPatch(payload) }), {
|
|
1701
|
+
success: "save",
|
|
1702
|
+
errorMessage: "Failed to save plugin settings"
|
|
1703
|
+
});
|
|
1704
|
+
nextRevision = responseSettingsRevision(response) ?? nextRevision;
|
|
1705
|
+
}
|
|
1706
|
+
if (!response) return true;
|
|
1707
|
+
applyLoaded(responseSettingsPayload(response), nextRevision);
|
|
1708
|
+
return true;
|
|
1709
|
+
} else {
|
|
1710
|
+
const ifMatch = revision.value ? { headers: { "If-Match": `"${revision.value}"` } } : void 0;
|
|
1711
|
+
response = await request.run(() => pluginApi.put("/settings", payload, ifMatch), {
|
|
1712
|
+
success: "save",
|
|
1713
|
+
errorMessage: "Failed to save plugin settings"
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
applyLoaded(responseSettingsPayload(response), responseSettingsRevision(response) ?? revision.value);
|
|
1636
1717
|
return true;
|
|
1637
1718
|
} catch {
|
|
1638
1719
|
return false;
|
|
@@ -1664,13 +1745,13 @@ function usePluginSettings(options = {}) {
|
|
|
1664
1745
|
reset
|
|
1665
1746
|
};
|
|
1666
1747
|
}
|
|
1667
|
-
function streamRequestAuth(options) {
|
|
1748
|
+
function streamRequestAuth(options, policy) {
|
|
1668
1749
|
const headers = new Headers(options.headers);
|
|
1669
1750
|
const authStore = useAuthStore();
|
|
1670
1751
|
if (!authStore.isInitialized) authStore.initialize();
|
|
1671
|
-
if (authStore.token && !headers.has("Authorization")) headers.set("Authorization", `Bearer ${authStore.token}`);
|
|
1752
|
+
if (policy.requiresAuth && authStore.token && !headers.has("Authorization")) headers.set("Authorization", `Bearer ${authStore.token}`);
|
|
1672
1753
|
headers.set("Accept", "text/event-stream");
|
|
1673
|
-
const token = authStore.token;
|
|
1754
|
+
const token = policy.requiresAuth ? authStore.token : void 0;
|
|
1674
1755
|
return {
|
|
1675
1756
|
headers,
|
|
1676
1757
|
token: token && headers.get("Authorization") === `Bearer ${token}` ? token : void 0
|
|
@@ -1766,7 +1847,7 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
|
|
|
1766
1847
|
let authenticationFailed = false;
|
|
1767
1848
|
try {
|
|
1768
1849
|
const url = buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl });
|
|
1769
|
-
const requestAuth = streamRequestAuth(options);
|
|
1850
|
+
const requestAuth = streamRequestAuth(options, { requiresAuth: endpoint.requiresAuth !== false });
|
|
1770
1851
|
const response = await fetch(url, {
|
|
1771
1852
|
method: "GET",
|
|
1772
1853
|
headers: requestAuth.headers,
|
|
@@ -1923,6 +2004,6 @@ function useCurrentExperiment(options = {}) {
|
|
|
1923
2004
|
};
|
|
1924
2005
|
}
|
|
1925
2006
|
//#endregion
|
|
1926
|
-
export {
|
|
2007
|
+
export { resolvePluginFrontendBase as A, createPluginResourceClient as C, usePluginConfig as D, useCommandHistory as E, useAuth as M, useAsync as O, 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, usePasskey as j, useAsyncBatch 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 };
|
|
1927
2008
|
|
|
1928
|
-
//# sourceMappingURL=composables-
|
|
2009
|
+
//# sourceMappingURL=composables-B512bWJP.js.map
|