@morscherlab/mld-sdk 0.8.3 → 0.9.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.
- package/dist/composables/useExperimentSelector.js +11 -3
- package/dist/composables/useExperimentSelector.js.map +1 -1
- package/dist/composables/usePlatformContext.d.ts +2 -0
- package/dist/types/platform.d.ts +1 -0
- package/package.json +1 -1
- package/src/composables/useExperimentSelector.ts +13 -3
- package/src/types/platform.ts +3 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ref, computed, reactive, watch, onScopeDispose } from "vue";
|
|
2
2
|
import { useApi } from "./useApi.js";
|
|
3
|
+
function getPlatformContext() {
|
|
4
|
+
if (typeof window === "undefined") return void 0;
|
|
5
|
+
return window.__MLD_PLATFORM__;
|
|
6
|
+
}
|
|
3
7
|
function getPlatformApiUrl() {
|
|
4
8
|
var _a;
|
|
5
|
-
|
|
6
|
-
return (_a = window.__MLD_PLATFORM__) == null ? void 0 : _a.platformApiUrl;
|
|
9
|
+
return (_a = getPlatformContext()) == null ? void 0 : _a.platformApiUrl;
|
|
7
10
|
}
|
|
8
11
|
function useExperimentSelector(options = {}) {
|
|
9
12
|
const { limit = 100, immediate = false, experimentType, apiBaseUrl } = options;
|
|
@@ -21,7 +24,12 @@ function useExperimentSelector(options = {}) {
|
|
|
21
24
|
error.value = null;
|
|
22
25
|
try {
|
|
23
26
|
const params = new URLSearchParams();
|
|
24
|
-
|
|
27
|
+
const effectiveType = experimentType ?? (() => {
|
|
28
|
+
var _a;
|
|
29
|
+
const types = (_a = getPlatformContext()) == null ? void 0 : _a.allowedExperimentTypes;
|
|
30
|
+
return (types == null ? void 0 : types.length) === 1 ? types[0] : void 0;
|
|
31
|
+
})();
|
|
32
|
+
if (effectiveType) params.set("experiment_type", effectiveType);
|
|
25
33
|
if (filters.status) params.set("status", filters.status);
|
|
26
34
|
if (filters.search) params.set("search", filters.search);
|
|
27
35
|
if (filters.project) params.set("project", filters.project);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExperimentSelector.js","sources":["../../src/composables/useExperimentSelector.ts"],"sourcesContent":["import { ref, reactive, computed, watch, onScopeDispose, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport type { ExperimentSummary, ExperimentListResponse, ExperimentFilters, PlatformContext } from '../types'\n\nfunction
|
|
1
|
+
{"version":3,"file":"useExperimentSelector.js","sources":["../../src/composables/useExperimentSelector.ts"],"sourcesContent":["import { ref, reactive, computed, watch, onScopeDispose, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport type { ExperimentSummary, ExperimentListResponse, ExperimentFilters, PlatformContext } from '../types'\n\nfunction getPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MLD_PLATFORM__?: PlatformContext }).__MLD_PLATFORM__\n}\n\nfunction getPlatformApiUrl(): string | undefined {\n return getPlatformContext()?.platformApiUrl\n}\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n experiments: Ref<ExperimentSummary[]>\n total: Ref<number>\n selectedExperiment: Ref<ExperimentSummary | null>\n filters: ExperimentFilters\n isLoading: Ref<boolean>\n error: Ref<string | null>\n page: Ref<number>\n hasMore: ComputedRef<boolean>\n fetch: () => Promise<void>\n loadMore: () => Promise<void>\n reset: () => void\n select: (experiment: ExperimentSummary) => void\n clear: () => void\n}\n\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const { limit = 100, immediate = false, experimentType, apiBaseUrl } = options\n const platformBase = apiBaseUrl ?? getPlatformApiUrl()\n const api = useApi()\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const isLoading = ref(false)\n const error = ref<string | null>(null)\n const page = ref(0)\n\n const hasMore = computed(() => experiments.value.length < total.value)\n\n async function fetchExperiments(): Promise<void> {\n isLoading.value = true\n error.value = null\n try {\n const params = new URLSearchParams()\n // Priority: explicit option > platform context (single type) > no filter\n const effectiveType = experimentType\n ?? (() => {\n const types = getPlatformContext()?.allowedExperimentTypes\n return types?.length === 1 ? types[0] : undefined\n })()\n if (effectiveType) params.set('experiment_type', effectiveType)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n params.set('limit', String(limit))\n params.set('skip', String(page.value * limit))\n\n const query = params.toString()\n // Use absolute platform URL in integrated mode to bypass plugin's baseURL\n const base = platformBase ?? '/api'\n const url = `${base}/experiments${query ? `?${query}` : ''}`\n const data = await api.get<ExperimentListResponse>(url)\n\n if (page.value === 0) {\n experiments.value = data.experiments\n } else {\n experiments.value = [...experiments.value, ...data.experiments]\n }\n total.value = data.total\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Failed to fetch experiments'\n if (page.value === 0) {\n experiments.value = []\n total.value = 0\n }\n } finally {\n isLoading.value = false\n }\n }\n\n async function loadMore(): Promise<void> {\n if (!hasMore.value || isLoading.value) return\n page.value++\n await fetchExperiments()\n }\n\n function reset(): void {\n page.value = 0\n experiments.value = []\n total.value = 0\n fetchExperiments()\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n page.value = 0\n }\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n })\n\n // Debounced watch on search filter\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n watch(\n () => filters.search,\n () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n page.value = 0\n fetchExperiments()\n }, 300)\n },\n )\n\n // Immediate watch on status/project filters (no debounce needed)\n watch(\n () => [filters.status, filters.project],\n () => {\n page.value = 0\n fetchExperiments()\n },\n )\n\n onScopeDispose(() => {\n if (debounceTimer) clearTimeout(debounceTimer)\n })\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n page,\n hasMore,\n fetch: fetchExperiments,\n loadMore,\n reset,\n select,\n clear,\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -52,6 +52,7 @@ export declare function usePlatformContext(options?: PlatformContextOptions): {
|
|
|
52
52
|
role: string;
|
|
53
53
|
} | undefined;
|
|
54
54
|
theme: "light" | "dark" | "system";
|
|
55
|
+
allowedExperimentTypes?: string[] | null | undefined;
|
|
55
56
|
features?: {
|
|
56
57
|
experiments?: boolean | undefined;
|
|
57
58
|
passkey?: boolean | undefined;
|
|
@@ -84,6 +85,7 @@ export declare function usePlatformContext(options?: PlatformContextOptions): {
|
|
|
84
85
|
role: string;
|
|
85
86
|
} | undefined;
|
|
86
87
|
theme: "light" | "dark" | "system";
|
|
88
|
+
allowedExperimentTypes?: string[] | null | undefined;
|
|
87
89
|
features?: {
|
|
88
90
|
experiments?: boolean | undefined;
|
|
89
91
|
passkey?: boolean | undefined;
|
package/dist/types/platform.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,9 +2,13 @@ import { ref, reactive, computed, watch, onScopeDispose, type Ref, type Computed
|
|
|
2
2
|
import { useApi } from './useApi'
|
|
3
3
|
import type { ExperimentSummary, ExperimentListResponse, ExperimentFilters, PlatformContext } from '../types'
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function getPlatformContext(): PlatformContext | undefined {
|
|
6
6
|
if (typeof window === 'undefined') return undefined
|
|
7
|
-
return (window as unknown as { __MLD_PLATFORM__?: PlatformContext }).__MLD_PLATFORM__
|
|
7
|
+
return (window as unknown as { __MLD_PLATFORM__?: PlatformContext }).__MLD_PLATFORM__
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getPlatformApiUrl(): string | undefined {
|
|
11
|
+
return getPlatformContext()?.platformApiUrl
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
export interface UseExperimentSelectorOptions {
|
|
@@ -51,7 +55,13 @@ export function useExperimentSelector(
|
|
|
51
55
|
error.value = null
|
|
52
56
|
try {
|
|
53
57
|
const params = new URLSearchParams()
|
|
54
|
-
|
|
58
|
+
// Priority: explicit option > platform context (single type) > no filter
|
|
59
|
+
const effectiveType = experimentType
|
|
60
|
+
?? (() => {
|
|
61
|
+
const types = getPlatformContext()?.allowedExperimentTypes
|
|
62
|
+
return types?.length === 1 ? types[0] : undefined
|
|
63
|
+
})()
|
|
64
|
+
if (effectiveType) params.set('experiment_type', effectiveType)
|
|
55
65
|
if (filters.status) params.set('status', filters.status)
|
|
56
66
|
if (filters.search) params.set('search', filters.search)
|
|
57
67
|
if (filters.project) params.set('project', filters.project)
|
package/src/types/platform.ts
CHANGED
|
@@ -64,6 +64,9 @@ export interface PlatformContext {
|
|
|
64
64
|
// Theme preference
|
|
65
65
|
theme: 'light' | 'dark' | 'system'
|
|
66
66
|
|
|
67
|
+
// Allowed experiment types for this plugin (from admin config)
|
|
68
|
+
allowedExperimentTypes?: string[] | null
|
|
69
|
+
|
|
67
70
|
// Features enabled in platform
|
|
68
71
|
features?: {
|
|
69
72
|
experiments?: boolean
|