@morscherlab/mint-sdk 1.0.0-beta.7 → 1.0.0-rc.1
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/dist/__tests__/composables/useProtocolTemplates.test.d.ts +1 -0
- package/dist/__tests__/stores/settings.test.d.ts +1 -0
- package/dist/{auth-QQj2kkze.js → auth-CBG3bWEc.js} +50 -20
- package/dist/auth-CBG3bWEc.js.map +1 -0
- package/dist/components/SettingsModal.vue.d.ts +5 -0
- package/dist/components/index.js +2 -2
- package/dist/{components-DihbSJjU.js → components-5KSfsVqf.js} +49 -29
- package/dist/components-5KSfsVqf.js.map +1 -0
- package/dist/composables/index.js +3 -3
- package/dist/{composables-BcgZ6diz.js → composables-D4Myb30a.js} +3 -3
- package/dist/{composables-BcgZ6diz.js.map → composables-D4Myb30a.js.map} +1 -1
- package/dist/index.js +5 -5
- package/dist/install.js +2 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +16 -0
- package/dist/templates/index.js +1 -1
- package/dist/{templates-Cyt0Suwf.js → templates-BSlxwV2c.js} +12 -8
- package/dist/templates-BSlxwV2c.js.map +1 -0
- package/dist/{useExperimentData-CM6Y0u5L.js → useExperimentData-BbbdI5xT.js} +97 -25
- package/dist/useExperimentData-BbbdI5xT.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/components/GroupAssigner.test.ts +18 -0
- package/src/__tests__/composables/useApi.test.ts +45 -0
- package/src/__tests__/composables/useAuth.test.ts +20 -0
- package/src/__tests__/composables/useProtocolTemplates.test.ts +64 -0
- package/src/__tests__/stores/settings.test.ts +78 -0
- package/src/components/AppAvatarMenu.vue +6 -3
- package/src/components/AppTopBar.vue +15 -10
- package/src/components/AuditTrail.vue +1 -1
- package/src/components/Calendar.vue +6 -2
- package/src/components/ConcentrationInput.vue +3 -2
- package/src/components/GroupAssigner.vue +8 -3
- package/src/components/NumberInput.vue +5 -3
- package/src/components/SampleHierarchyTree.vue +3 -2
- package/src/components/SettingsModal.vue +7 -0
- package/src/components/UnitInput.vue +6 -2
- package/src/components/WellPlate.vue +3 -3
- package/src/composables/useApi.ts +113 -16
- package/src/composables/useAutoGroup.ts +13 -8
- package/src/composables/useProtocolTemplates.ts +13 -1
- package/src/composables/useRackEditor.ts +3 -2
- package/src/stores/auth.ts +48 -23
- package/src/stores/settings.ts +10 -0
- package/src/styles/components/settings-modal.css +9 -0
- package/dist/auth-QQj2kkze.js.map +0 -1
- package/dist/components-DihbSJjU.js.map +0 -1
- package/dist/templates-Cyt0Suwf.js.map +0 -1
- package/dist/useExperimentData-CM6Y0u5L.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Bn as useConcentrationUnits, Bt as extractTemplateCollection, Fn as useControlWorkspace, In as getFieldRegistryEntry, Ln as getTypeDefault, Nt as createTemplateCollection, _ as toBioTemplateComponentPropsByComponent$1, _t as createBioTemplatePresetCollectionFromControls, an as getBioTemplatePackInfo, b as toBioTemplateComponentUsage, d as getBioTemplateComponentProps$1, g as toBioTemplateComponentProps, gt as createBioTemplatePresetCollection, h as toBioTemplateComponentImports, ht as createBioTemplatePackCollection, i as createBioTemplateControlToolkit, m as toBioTemplateComponentBindingsById, p as toBioTemplateComponentBindings, tn as getBioTemplatePresetInfo, u as getBioTemplateComponentBindings, v as toBioTemplateComponentPropsById, y as toBioTemplateComponentSnippets, zt as ensureTemplateFromCollection } from "./templates-
|
|
2
|
-
import { r as useSettingsStore, t as useAuthStore } from "./auth-
|
|
1
|
+
import { Bn as useConcentrationUnits, Bt as extractTemplateCollection, Fn as useControlWorkspace, In as getFieldRegistryEntry, Ln as getTypeDefault, Nt as createTemplateCollection, _ as toBioTemplateComponentPropsByComponent$1, _t as createBioTemplatePresetCollectionFromControls, an as getBioTemplatePackInfo, b as toBioTemplateComponentUsage, d as getBioTemplateComponentProps$1, g as toBioTemplateComponentProps, gt as createBioTemplatePresetCollection, h as toBioTemplateComponentImports, ht as createBioTemplatePackCollection, i as createBioTemplateControlToolkit, m as toBioTemplateComponentBindingsById, p as toBioTemplateComponentBindings, tn as getBioTemplatePresetInfo, u as getBioTemplateComponentBindings, v as toBioTemplateComponentPropsById, y as toBioTemplateComponentSnippets, zt as ensureTemplateFromCollection } from "./templates-BSlxwV2c.js";
|
|
2
|
+
import { r as useSettingsStore, t as useAuthStore } from "./auth-CBG3bWEc.js";
|
|
3
3
|
import { computed, effectScope, getCurrentScope, onMounted, onScopeDispose, onUnmounted, provide, reactive, readonly, ref, shallowRef, toRaw, toValue, watch } from "vue";
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
//#region src/composables/useSortedItems.ts
|
|
@@ -784,10 +784,56 @@ var apiClientInstance = null;
|
|
|
784
784
|
var interceptorAttached = false;
|
|
785
785
|
function joinUrlPath(baseUrl, path) {
|
|
786
786
|
if (!path) return baseUrl;
|
|
787
|
+
if (path.startsWith("?") || path.startsWith("#")) return `${baseUrl.replace(/\/+$/, "")}${path}`;
|
|
787
788
|
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
788
789
|
const normalizedPath = path.replace(/^\/+/, "/");
|
|
789
790
|
return `${normalizedBase}${normalizedPath.startsWith("/") ? normalizedPath : `/${normalizedPath}`}`;
|
|
790
791
|
}
|
|
792
|
+
function getBasePath(baseUrl) {
|
|
793
|
+
if (!baseUrl) return "/";
|
|
794
|
+
try {
|
|
795
|
+
const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
796
|
+
return new URL(baseUrl, origin).pathname.replace(/\/+$/, "") || "/";
|
|
797
|
+
} catch {
|
|
798
|
+
return baseUrl.replace(/^https?:\/\/[^/]+/i, "").replace(/\/+$/, "") || "/";
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
function normalizeRequestUrl(baseUrl, url) {
|
|
802
|
+
if (!url || /^https?:\/\//.test(url)) return url;
|
|
803
|
+
const basePath = getBasePath(baseUrl);
|
|
804
|
+
if (basePath === "/") return url;
|
|
805
|
+
const normalizedUrl = url.startsWith("/") ? url : `/${url}`;
|
|
806
|
+
if (normalizedUrl === basePath || normalizedUrl.startsWith(`${basePath}?`) || normalizedUrl.startsWith(`${basePath}#`)) return normalizedUrl.slice(basePath.length);
|
|
807
|
+
if (normalizedUrl.startsWith(`${basePath}/`)) return normalizedUrl.slice(basePath.length) || "";
|
|
808
|
+
return url;
|
|
809
|
+
}
|
|
810
|
+
function asMutableHeaders(headers) {
|
|
811
|
+
return headers ? headers : null;
|
|
812
|
+
}
|
|
813
|
+
function hasAuthorizationHeader(headers) {
|
|
814
|
+
const bag = asMutableHeaders(headers);
|
|
815
|
+
if (!bag) return false;
|
|
816
|
+
if (typeof bag.has === "function") return bag.has("Authorization");
|
|
817
|
+
return Object.keys(bag).some((key) => key.toLowerCase() === "authorization");
|
|
818
|
+
}
|
|
819
|
+
function setAuthorizationHeader(headers, value) {
|
|
820
|
+
const bag = asMutableHeaders(headers);
|
|
821
|
+
if (!bag) return;
|
|
822
|
+
if (typeof bag.set === "function") {
|
|
823
|
+
bag.set("Authorization", value);
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
bag.Authorization = value;
|
|
827
|
+
}
|
|
828
|
+
function deleteAuthorizationHeader(headers) {
|
|
829
|
+
const bag = asMutableHeaders(headers);
|
|
830
|
+
if (!bag) return;
|
|
831
|
+
if (typeof bag.delete === "function") {
|
|
832
|
+
bag.delete("Authorization");
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
for (const key of Object.keys(bag)) if (key.toLowerCase() === "authorization") delete bag[key];
|
|
836
|
+
}
|
|
791
837
|
function getApiClient() {
|
|
792
838
|
if (!apiClientInstance) apiClientInstance = axios.create({ headers: { "Content-Type": "application/json" } });
|
|
793
839
|
return apiClientInstance;
|
|
@@ -800,37 +846,50 @@ function useApi(options = {}) {
|
|
|
800
846
|
if (!authStore.isInitialized) authStore.initialize();
|
|
801
847
|
if (!interceptorAttached) {
|
|
802
848
|
apiClient.interceptors.request.use((config) => {
|
|
803
|
-
|
|
849
|
+
const request = config;
|
|
850
|
+
if (request._mintSkipAuth) {
|
|
851
|
+
delete request._mintSkipAuth;
|
|
852
|
+
deleteAuthorizationHeader(request.headers);
|
|
853
|
+
return request;
|
|
854
|
+
}
|
|
855
|
+
const currentAuthStore = useAuthStore();
|
|
856
|
+
if (currentAuthStore.token && config.headers && !hasAuthorizationHeader(config.headers)) setAuthorizationHeader(config.headers, `Bearer ${currentAuthStore.token}`);
|
|
804
857
|
return config;
|
|
805
858
|
});
|
|
806
859
|
interceptorAttached = true;
|
|
807
860
|
}
|
|
861
|
+
function getBaseUrl() {
|
|
862
|
+
return options.baseUrl ?? settingsStore.getApiBaseUrl();
|
|
863
|
+
}
|
|
864
|
+
function normalizeUrl(url) {
|
|
865
|
+
return normalizeRequestUrl(getBaseUrl(), url);
|
|
866
|
+
}
|
|
808
867
|
function requestConfig(config) {
|
|
809
868
|
const base = {
|
|
810
|
-
baseURL:
|
|
869
|
+
baseURL: getBaseUrl(),
|
|
811
870
|
timeout: options.timeout ?? settingsStore.requestTimeout,
|
|
812
871
|
...config
|
|
813
872
|
};
|
|
814
|
-
if (options.withAuth === false)
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
873
|
+
if (options.withAuth === false) {
|
|
874
|
+
base._mintSkipAuth = true;
|
|
875
|
+
deleteAuthorizationHeader(base.headers);
|
|
876
|
+
}
|
|
818
877
|
return base;
|
|
819
878
|
}
|
|
820
879
|
async function get(url, config) {
|
|
821
|
-
return (await apiClient.get(url, requestConfig(config))).data;
|
|
880
|
+
return (await apiClient.get(normalizeUrl(url), requestConfig(config))).data;
|
|
822
881
|
}
|
|
823
882
|
async function post(url, data, config) {
|
|
824
|
-
return (await apiClient.post(url, data, requestConfig(config))).data;
|
|
883
|
+
return (await apiClient.post(normalizeUrl(url), data, requestConfig(config))).data;
|
|
825
884
|
}
|
|
826
885
|
async function put(url, data, config) {
|
|
827
|
-
return (await apiClient.put(url, data, requestConfig(config))).data;
|
|
886
|
+
return (await apiClient.put(normalizeUrl(url), data, requestConfig(config))).data;
|
|
828
887
|
}
|
|
829
888
|
async function patch(url, data, config) {
|
|
830
|
-
return (await apiClient.patch(url, data, requestConfig(config))).data;
|
|
889
|
+
return (await apiClient.patch(normalizeUrl(url), data, requestConfig(config))).data;
|
|
831
890
|
}
|
|
832
891
|
async function del(url, config) {
|
|
833
|
-
return (await apiClient.delete(url, requestConfig(config))).data;
|
|
892
|
+
return (await apiClient.delete(normalizeUrl(url), requestConfig(config))).data;
|
|
834
893
|
}
|
|
835
894
|
async function upload(url, file, fieldName = "file", additionalData) {
|
|
836
895
|
const formData = new FormData();
|
|
@@ -838,10 +897,10 @@ function useApi(options = {}) {
|
|
|
838
897
|
if (additionalData) Object.entries(additionalData).forEach(([key, value]) => {
|
|
839
898
|
if (value !== void 0 && value !== null) formData.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
840
899
|
});
|
|
841
|
-
return (await apiClient.post(url, formData, requestConfig({ headers: { "Content-Type": void 0 } }))).data;
|
|
900
|
+
return (await apiClient.post(normalizeUrl(url), formData, requestConfig({ headers: { "Content-Type": void 0 } }))).data;
|
|
842
901
|
}
|
|
843
902
|
async function download(url, filename) {
|
|
844
|
-
const response = await apiClient.get(url, requestConfig({ responseType: "blob" }));
|
|
903
|
+
const response = await apiClient.get(normalizeUrl(url), requestConfig({ responseType: "blob" }));
|
|
845
904
|
const blob = new Blob([response.data]);
|
|
846
905
|
const blobUrl = URL.createObjectURL(blob);
|
|
847
906
|
if (filename) {
|
|
@@ -857,7 +916,8 @@ function useApi(options = {}) {
|
|
|
857
916
|
return blobUrl;
|
|
858
917
|
}
|
|
859
918
|
function buildUrl(path) {
|
|
860
|
-
|
|
919
|
+
const baseUrl = getBaseUrl();
|
|
920
|
+
return joinUrlPath(baseUrl, normalizeRequestUrl(baseUrl, path));
|
|
861
921
|
}
|
|
862
922
|
function buildWsUrl(path) {
|
|
863
923
|
return joinUrlPath(settingsStore.getWsBaseUrl(), path);
|
|
@@ -2213,8 +2273,9 @@ function computeGroups(allSamples, columns, enabledFields, outlierActions, delim
|
|
|
2213
2273
|
const keyParts = [];
|
|
2214
2274
|
for (const idx of enabledIndices) if (idx < row.length && idx < columns.length) keyParts.push(row[idx]);
|
|
2215
2275
|
const groupKey = keyParts.join(" / ");
|
|
2216
|
-
|
|
2217
|
-
|
|
2276
|
+
const group = groupMap.get(groupKey);
|
|
2277
|
+
if (group) group.push(sample);
|
|
2278
|
+
else groupMap.set(groupKey, [sample]);
|
|
2218
2279
|
const fields = {};
|
|
2219
2280
|
for (const col of columns) if (col.index < row.length) fields[col.name] = row[col.index];
|
|
2220
2281
|
metadata.push({
|
|
@@ -2299,8 +2360,9 @@ function computeGroupsFromCsv(csvData, columns, enabledFields) {
|
|
|
2299
2360
|
for (const row of csvData.rows) {
|
|
2300
2361
|
const sampleName = row[csvData.sampleColumn];
|
|
2301
2362
|
const groupKey = enabledCols.map((col) => row[col.originalName ?? col.name]).join(" / ");
|
|
2302
|
-
|
|
2303
|
-
|
|
2363
|
+
const group = groupMap.get(groupKey);
|
|
2364
|
+
if (group) group.push(sampleName);
|
|
2365
|
+
else groupMap.set(groupKey, [sampleName]);
|
|
2304
2366
|
const fields = {};
|
|
2305
2367
|
for (const col of columns) fields[col.name] = row[col.originalName ?? col.name];
|
|
2306
2368
|
metadata.push({
|
|
@@ -2339,7 +2401,8 @@ function useAutoGroup() {
|
|
|
2339
2401
|
const enabledFields = ref(/* @__PURE__ */ new Set());
|
|
2340
2402
|
const isTabularMode = computed(() => (inputMode.value === "csv" || inputMode.value === "experiment") && csvData.value !== null);
|
|
2341
2403
|
const samples = computed(() => {
|
|
2342
|
-
|
|
2404
|
+
const data = csvData.value;
|
|
2405
|
+
if (isTabularMode.value && data) return data.rows.map((r) => r[data.sampleColumn]);
|
|
2343
2406
|
return rawText.value.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
2344
2407
|
});
|
|
2345
2408
|
const hasOutliers = computed(() => outliers.value.length > 0);
|
|
@@ -3737,8 +3800,9 @@ function useRackEditor(initialRacks, options) {
|
|
|
3737
3800
|
return count;
|
|
3738
3801
|
});
|
|
3739
3802
|
function reset() {
|
|
3740
|
-
|
|
3741
|
-
|
|
3803
|
+
const rack = createDefaultRack("Rack 1", 0);
|
|
3804
|
+
racks.value = [rack];
|
|
3805
|
+
activeRackId.value = rack.id;
|
|
3742
3806
|
}
|
|
3743
3807
|
return {
|
|
3744
3808
|
racks,
|
|
@@ -4246,10 +4310,18 @@ var BUILT_IN_TEMPLATES = [
|
|
|
4246
4310
|
}
|
|
4247
4311
|
];
|
|
4248
4312
|
var STORAGE_KEY = "mint-custom-protocol-templates";
|
|
4313
|
+
function isStepTemplate(value) {
|
|
4314
|
+
if (!value || typeof value !== "object") return false;
|
|
4315
|
+
const candidate = value;
|
|
4316
|
+
return typeof candidate.id === "string" && typeof candidate.type === "string" && typeof candidate.name === "string" && Array.isArray(candidate.parameters);
|
|
4317
|
+
}
|
|
4249
4318
|
function loadCustomTemplates() {
|
|
4250
4319
|
try {
|
|
4251
4320
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
4252
|
-
if (stored)
|
|
4321
|
+
if (stored) {
|
|
4322
|
+
const parsed = JSON.parse(stored);
|
|
4323
|
+
return Array.isArray(parsed) ? parsed.filter(isStepTemplate) : [];
|
|
4324
|
+
}
|
|
4253
4325
|
} catch {}
|
|
4254
4326
|
return [];
|
|
4255
4327
|
}
|
|
@@ -4411,4 +4483,4 @@ function useExperimentData(options = {}) {
|
|
|
4411
4483
|
//#endregion
|
|
4412
4484
|
export { useTheme as $, useAutoGroup as A, DATE_PRESET_OPTIONS as B, useSampleGroups as C, DEFAULT_COLORS as D, hslToHex as E, usePlatformContext as F, datePresetToISO as G, EXPERIMENT_STATUS_OPTIONS as H, useExperimentSelector as I, getExperimentStatusVariant as J, formatExperimentDate as K, useRequestSyncState as L, useDoseCalculator as M, APP_EXPERIMENT_KEY as N, extractSamplesFromDesignData as O, useAppExperiment as P, useForm as Q, useDebouncedWatch as R, useExpansionSet as S, hexToHsl as T, EXPERIMENT_STATUS_VARIANT_MAP as U, EXPERIMENT_STATUS_LABELS as V, SORT_OPTIONS as W, evaluateCondition as X, resolveExperimentCode as Y, useFormBuilder as Z, useExperimentSave as _, generateDilutionSeries as a, useSortedItems as at, resolveCurrentExperimentId as b, useRackEditor as c, useBioTemplateWorkspace as d, useToast as et, getBioTemplateComponentProps as f, useTemplateCollection as g, useBioTemplateControls as h, DEFAULT_UNITS as i, compareSortValues as it, useWellPlateEditor as j, parseCSV as k, useBioTemplatePresetWorkspace as l, useBioTemplateComponents as m, useProtocolTemplates as n, normalizeSearchQuery as nt, useReagentSeries as o, toBioTemplateComponentPropsByComponent as p, formatExperimentStatus as q, DEFAULT_PRESETS as r, useTextSearch as rt, useGroupAssignment as s, useExperimentData as t, candidateMatchesSearch as tt, useBioTemplatePackWorkspace as u, currentExperimentFromContext as v, deriveShade as w, useScheduleDrag as x, getInjectedPlatformContext as y, useApi as z };
|
|
4413
4485
|
|
|
4414
|
-
//# sourceMappingURL=useExperimentData-
|
|
4486
|
+
//# sourceMappingURL=useExperimentData-BbbdI5xT.js.map
|