@morscherlab/mld-sdk 0.9.2 → 0.9.4
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 -8
- package/dist/composables/useExperimentSelector.js.map +1 -1
- package/dist/composables/usePluginConfig.js +1 -1
- package/dist/composables/usePluginConfig.js.map +1 -1
- package/package.json +1 -1
- package/src/composables/useExperimentSelector.ts +12 -7
- package/src/composables/usePluginConfig.ts +1 -1
|
@@ -20,15 +20,13 @@ function useExperimentSelector(options = {}) {
|
|
|
20
20
|
const page = ref(0);
|
|
21
21
|
const hasMore = computed(() => experiments.value.length < total.value);
|
|
22
22
|
async function fetchExperiments() {
|
|
23
|
+
var _a;
|
|
23
24
|
isLoading.value = true;
|
|
24
25
|
error.value = null;
|
|
25
26
|
try {
|
|
26
27
|
const params = new URLSearchParams();
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const types = (_a = getPlatformContext()) == null ? void 0 : _a.allowedExperimentTypes;
|
|
30
|
-
return (types == null ? void 0 : types.length) === 1 ? types[0] : void 0;
|
|
31
|
-
})();
|
|
28
|
+
const allowedTypes = (_a = getPlatformContext()) == null ? void 0 : _a.allowedExperimentTypes;
|
|
29
|
+
const effectiveType = experimentType ?? ((allowedTypes == null ? void 0 : allowedTypes.length) === 1 ? allowedTypes[0] : void 0);
|
|
32
30
|
if (effectiveType) params.set("experiment_type", effectiveType);
|
|
33
31
|
if (filters.status) params.set("status", filters.status);
|
|
34
32
|
if (filters.search) params.set("search", filters.search);
|
|
@@ -39,12 +37,17 @@ function useExperimentSelector(options = {}) {
|
|
|
39
37
|
const base = platformBase ?? "/api";
|
|
40
38
|
const url = `${base}/experiments${query ? `?${query}` : ""}`;
|
|
41
39
|
const data = await api.get(url);
|
|
40
|
+
let filtered = data.experiments;
|
|
41
|
+
if (!effectiveType && allowedTypes && allowedTypes.length > 1) {
|
|
42
|
+
const typeSet = new Set(allowedTypes);
|
|
43
|
+
filtered = filtered.filter((e) => typeSet.has(e.experiment_type));
|
|
44
|
+
}
|
|
42
45
|
if (page.value === 0) {
|
|
43
|
-
experiments.value =
|
|
46
|
+
experiments.value = filtered;
|
|
44
47
|
} else {
|
|
45
|
-
experiments.value = [...experiments.value, ...
|
|
48
|
+
experiments.value = [...experiments.value, ...filtered];
|
|
46
49
|
}
|
|
47
|
-
total.value = data.total;
|
|
50
|
+
total.value = effectiveType || !(allowedTypes == null ? void 0 : allowedTypes.length) ? data.total : filtered.length;
|
|
48
51
|
} catch (e) {
|
|
49
52
|
error.value = e instanceof Error ? e.message : "Failed to fetch experiments";
|
|
50
53
|
if (page.value === 0) {
|
|
@@ -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 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
|
|
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 allowedTypes = getPlatformContext()?.allowedExperimentTypes\n const effectiveType = experimentType\n ?? (allowedTypes?.length === 1 ? allowedTypes[0] : undefined)\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 // Client-side filter for multiple allowed types (backend only supports single type)\n let filtered = data.experiments\n if (!effectiveType && allowedTypes && allowedTypes.length > 1) {\n const typeSet = new Set(allowedTypes)\n filtered = filtered.filter(e => typeSet.has(e.experiment_type))\n }\n\n if (page.value === 0) {\n experiments.value = filtered\n } else {\n experiments.value = [...experiments.value, ...filtered]\n }\n total.value = effectiveType || !allowedTypes?.length ? data.total : filtered.length\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":";;AAIA,SAAS,qBAAkD;AACzD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAQ,OAA6D;AACvE;AAEA,SAAS,oBAAwC;;AAC/C,UAAO,8BAAA,mBAAsB;AAC/B;AAyBO,SAAS,sBACd,UAAwC,IACX;AAC7B,QAAM,EAAE,QAAQ,KAAK,YAAY,OAAO,gBAAgB,eAAe;AACvE,QAAM,eAAe,cAAc,kBAAA;AACnC,QAAM,MAAM,OAAA;AAEZ,QAAM,cAAc,IAAyB,EAAE;AAC/C,QAAM,QAAQ,IAAI,CAAC;AACnB,QAAM,qBAAqB,IAA8B,IAAI;AAC7D,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,QAAQ,IAAmB,IAAI;AACrC,QAAM,OAAO,IAAI,CAAC;AAElB,QAAM,UAAU,SAAS,MAAM,YAAY,MAAM,SAAS,MAAM,KAAK;AAErE,iBAAe,mBAAkC;;AAC/C,cAAU,QAAQ;AAClB,UAAM,QAAQ;AACd,QAAI;AACF,YAAM,SAAS,IAAI,gBAAA;AAEnB,YAAM,gBAAe,8BAAA,mBAAsB;AAC3C,YAAM,gBAAgB,oBAChB,6CAAc,YAAW,IAAI,aAAa,CAAC,IAAI;AACrD,UAAI,cAAe,QAAO,IAAI,mBAAmB,aAAa;AAC9D,UAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,UAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,UAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,aAAO,IAAI,SAAS,OAAO,KAAK,CAAC;AACjC,aAAO,IAAI,QAAQ,OAAO,KAAK,QAAQ,KAAK,CAAC;AAE7C,YAAM,QAAQ,OAAO,SAAA;AAErB,YAAM,OAAO,gBAAgB;AAC7B,YAAM,MAAM,GAAG,IAAI,eAAe,QAAQ,IAAI,KAAK,KAAK,EAAE;AAC1D,YAAM,OAAO,MAAM,IAAI,IAA4B,GAAG;AAGtD,UAAI,WAAW,KAAK;AACpB,UAAI,CAAC,iBAAiB,gBAAgB,aAAa,SAAS,GAAG;AAC7D,cAAM,UAAU,IAAI,IAAI,YAAY;AACpC,mBAAW,SAAS,OAAO,CAAA,MAAK,QAAQ,IAAI,EAAE,eAAe,CAAC;AAAA,MAChE;AAEA,UAAI,KAAK,UAAU,GAAG;AACpB,oBAAY,QAAQ;AAAA,MACtB,OAAO;AACL,oBAAY,QAAQ,CAAC,GAAG,YAAY,OAAO,GAAG,QAAQ;AAAA,MACxD;AACA,YAAM,QAAQ,iBAAiB,EAAC,6CAAc,UAAS,KAAK,QAAQ,SAAS;AAAA,IAC/E,SAAS,GAAG;AACV,YAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU;AAC/C,UAAI,KAAK,UAAU,GAAG;AACpB,oBAAY,QAAQ,CAAA;AACpB,cAAM,QAAQ;AAAA,MAChB;AAAA,IACF,UAAA;AACE,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA,iBAAe,WAA0B;AACvC,QAAI,CAAC,QAAQ,SAAS,UAAU,MAAO;AACvC,SAAK;AACL,UAAM,iBAAA;AAAA,EACR;AAEA,WAAS,QAAc;AACrB,SAAK,QAAQ;AACb,gBAAY,QAAQ,CAAA;AACpB,UAAM,QAAQ;AACd,qBAAA;AAAA,EACF;AAEA,WAAS,OAAO,YAAqC;AACnD,uBAAmB,QAAQ;AAAA,EAC7B;AAEA,WAAS,QAAc;AACrB,uBAAmB,QAAQ;AAC3B,YAAQ,SAAS;AACjB,YAAQ,SAAS;AACjB,YAAQ,UAAU;AAClB,SAAK,QAAQ;AAAA,EACf;AAEA,QAAM,UAA6B,SAAS;AAAA,IAC1C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,EAAA,CACV;AAGD,MAAI,gBAAsD;AAC1D;AAAA,IACE,MAAM,QAAQ;AAAA,IACd,MAAM;AACJ,UAAI,4BAA4B,aAAa;AAC7C,sBAAgB,WAAW,MAAM;AAC/B,aAAK,QAAQ;AACb,yBAAA;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAAA,EAAA;AAIF;AAAA,IACE,MAAM,CAAC,QAAQ,QAAQ,QAAQ,OAAO;AAAA,IACtC,MAAM;AACJ,WAAK,QAAQ;AACb,uBAAA;AAAA,IACF;AAAA,EAAA;AAGF,iBAAe,MAAM;AACnB,QAAI,4BAA4B,aAAa;AAAA,EAC/C,CAAC;AAED,MAAI,WAAW;AACb,qBAAA;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePluginConfig.js","sources":["../../src/composables/usePluginConfig.ts"],"sourcesContent":["import { ref, computed, onMounted, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\n\nexport interface UsePluginConfigReturn {\n config: Ref<Record<string, unknown>>\n isLoading: Ref<boolean>\n isSaving: Ref<boolean>\n error: Ref<string | null>\n isDirty: ComputedRef<boolean>\n load: () => Promise<void>\n save: () => Promise<boolean>\n reset: () => void\n}\n\nexport function usePluginConfig(pluginName?: string): UsePluginConfigReturn {\n const api = useApi()\n const { plugin } = usePlatformContext()\n\n const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? '')\n\n const config = ref<Record<string, unknown>>({})\n const savedConfig = ref<Record<string, unknown>>({})\n const isLoading = ref(false)\n const isSaving = ref(false)\n const error = ref<string | null>(null)\n\n const isDirty = computed(() => {\n return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value)\n })\n\n async function load(): Promise<void> {\n const name = resolvedName.value\n if (!name) return\n\n isLoading.value = true\n error.value = null\n try {\n const response = await api.get<{ plugin_name: string; config: Record<string, unknown> }>(\n `/api/plugins/${encodeURIComponent(name)}/config`,\n )\n config.value = { ...response.config }\n savedConfig.value = { ...response.config }\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Failed to load plugin config'\n } finally {\n isLoading.value = false\n }\n }\n\n async function save(): Promise<boolean> {\n const name = resolvedName.value\n if (!name) return false\n\n isSaving.value = true\n error.value = null\n try {\n const response = await api.
|
|
1
|
+
{"version":3,"file":"usePluginConfig.js","sources":["../../src/composables/usePluginConfig.ts"],"sourcesContent":["import { ref, computed, onMounted, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\n\nexport interface UsePluginConfigReturn {\n config: Ref<Record<string, unknown>>\n isLoading: Ref<boolean>\n isSaving: Ref<boolean>\n error: Ref<string | null>\n isDirty: ComputedRef<boolean>\n load: () => Promise<void>\n save: () => Promise<boolean>\n reset: () => void\n}\n\nexport function usePluginConfig(pluginName?: string): UsePluginConfigReturn {\n const api = useApi()\n const { plugin } = usePlatformContext()\n\n const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? '')\n\n const config = ref<Record<string, unknown>>({})\n const savedConfig = ref<Record<string, unknown>>({})\n const isLoading = ref(false)\n const isSaving = ref(false)\n const error = ref<string | null>(null)\n\n const isDirty = computed(() => {\n return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value)\n })\n\n async function load(): Promise<void> {\n const name = resolvedName.value\n if (!name) return\n\n isLoading.value = true\n error.value = null\n try {\n const response = await api.get<{ plugin_name: string; config: Record<string, unknown> }>(\n `/api/plugins/${encodeURIComponent(name)}/config`,\n )\n config.value = { ...response.config }\n savedConfig.value = { ...response.config }\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Failed to load plugin config'\n } finally {\n isLoading.value = false\n }\n }\n\n async function save(): Promise<boolean> {\n const name = resolvedName.value\n if (!name) return false\n\n isSaving.value = true\n error.value = null\n try {\n const response = await api.patch<{ plugin_name: string; config: Record<string, unknown> }>(\n `/api/plugins/${encodeURIComponent(name)}/config`,\n { config: config.value },\n )\n config.value = { ...response.config }\n savedConfig.value = { ...response.config }\n return true\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Failed to save plugin config'\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n function reset(): void {\n config.value = { ...savedConfig.value }\n error.value = null\n }\n\n onMounted(() => {\n load()\n })\n\n return {\n config,\n isLoading,\n isSaving,\n error,\n isDirty,\n load,\n save,\n reset,\n }\n}\n"],"names":[],"mappings":";;;AAeO,SAAS,gBAAgB,YAA4C;AAC1E,QAAM,MAAM,OAAA;AACZ,QAAM,EAAE,OAAA,IAAW,mBAAA;AAEnB,QAAM,eAAe,SAAS,MAAA;;AAAM,2BAAc,YAAO,UAAP,mBAAc,SAAQ;AAAA,GAAE;AAE1E,QAAM,SAAS,IAA6B,EAAE;AAC9C,QAAM,cAAc,IAA6B,EAAE;AACnD,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,WAAW,IAAI,KAAK;AAC1B,QAAM,QAAQ,IAAmB,IAAI;AAErC,QAAM,UAAU,SAAS,MAAM;AAC7B,WAAO,KAAK,UAAU,OAAO,KAAK,MAAM,KAAK,UAAU,YAAY,KAAK;AAAA,EAC1E,CAAC;AAED,iBAAe,OAAsB;AACnC,UAAM,OAAO,aAAa;AAC1B,QAAI,CAAC,KAAM;AAEX,cAAU,QAAQ;AAClB,UAAM,QAAQ;AACd,QAAI;AACF,YAAM,WAAW,MAAM,IAAI;AAAA,QACzB,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MAAA;AAE1C,aAAO,QAAQ,EAAE,GAAG,SAAS,OAAA;AAC7B,kBAAY,QAAQ,EAAE,GAAG,SAAS,OAAA;AAAA,IACpC,SAAS,GAAG;AACV,YAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU;AAAA,IACjD,UAAA;AACE,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA,iBAAe,OAAyB;AACtC,UAAM,OAAO,aAAa;AAC1B,QAAI,CAAC,KAAM,QAAO;AAElB,aAAS,QAAQ;AACjB,UAAM,QAAQ;AACd,QAAI;AACF,YAAM,WAAW,MAAM,IAAI;AAAA,QACzB,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,QACxC,EAAE,QAAQ,OAAO,MAAA;AAAA,MAAM;AAEzB,aAAO,QAAQ,EAAE,GAAG,SAAS,OAAA;AAC7B,kBAAY,QAAQ,EAAE,GAAG,SAAS,OAAA;AAClC,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU;AAC/C,aAAO;AAAA,IACT,UAAA;AACE,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AAEA,WAAS,QAAc;AACrB,WAAO,QAAQ,EAAE,GAAG,YAAY,MAAA;AAChC,UAAM,QAAQ;AAAA,EAChB;AAEA,YAAU,MAAM;AACd,SAAA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
package/package.json
CHANGED
|
@@ -56,11 +56,9 @@ export function useExperimentSelector(
|
|
|
56
56
|
try {
|
|
57
57
|
const params = new URLSearchParams()
|
|
58
58
|
// Priority: explicit option > platform context (single type) > no filter
|
|
59
|
+
const allowedTypes = getPlatformContext()?.allowedExperimentTypes
|
|
59
60
|
const effectiveType = experimentType
|
|
60
|
-
?? (
|
|
61
|
-
const types = getPlatformContext()?.allowedExperimentTypes
|
|
62
|
-
return types?.length === 1 ? types[0] : undefined
|
|
63
|
-
})()
|
|
61
|
+
?? (allowedTypes?.length === 1 ? allowedTypes[0] : undefined)
|
|
64
62
|
if (effectiveType) params.set('experiment_type', effectiveType)
|
|
65
63
|
if (filters.status) params.set('status', filters.status)
|
|
66
64
|
if (filters.search) params.set('search', filters.search)
|
|
@@ -74,12 +72,19 @@ export function useExperimentSelector(
|
|
|
74
72
|
const url = `${base}/experiments${query ? `?${query}` : ''}`
|
|
75
73
|
const data = await api.get<ExperimentListResponse>(url)
|
|
76
74
|
|
|
75
|
+
// Client-side filter for multiple allowed types (backend only supports single type)
|
|
76
|
+
let filtered = data.experiments
|
|
77
|
+
if (!effectiveType && allowedTypes && allowedTypes.length > 1) {
|
|
78
|
+
const typeSet = new Set(allowedTypes)
|
|
79
|
+
filtered = filtered.filter(e => typeSet.has(e.experiment_type))
|
|
80
|
+
}
|
|
81
|
+
|
|
77
82
|
if (page.value === 0) {
|
|
78
|
-
experiments.value =
|
|
83
|
+
experiments.value = filtered
|
|
79
84
|
} else {
|
|
80
|
-
experiments.value = [...experiments.value, ...
|
|
85
|
+
experiments.value = [...experiments.value, ...filtered]
|
|
81
86
|
}
|
|
82
|
-
total.value = data.total
|
|
87
|
+
total.value = effectiveType || !allowedTypes?.length ? data.total : filtered.length
|
|
83
88
|
} catch (e) {
|
|
84
89
|
error.value = e instanceof Error ? e.message : 'Failed to fetch experiments'
|
|
85
90
|
if (page.value === 0) {
|
|
@@ -55,7 +55,7 @@ export function usePluginConfig(pluginName?: string): UsePluginConfigReturn {
|
|
|
55
55
|
isSaving.value = true
|
|
56
56
|
error.value = null
|
|
57
57
|
try {
|
|
58
|
-
const response = await api.
|
|
58
|
+
const response = await api.patch<{ plugin_name: string; config: Record<string, unknown> }>(
|
|
59
59
|
`/api/plugins/${encodeURIComponent(name)}/config`,
|
|
60
60
|
{ config: config.value },
|
|
61
61
|
)
|