@morscherlab/mint-sdk 1.1.0 → 1.1.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.
Files changed (99) hide show
  1. package/dist/{EmptyState-DgBRoYAy.js → EmptyState-LMPS3keb.js} +3 -193
  2. package/dist/EmptyState-LMPS3keb.js.map +1 -0
  3. package/dist/{ExperimentPopover-BFw3QX8L.js → ExperimentPopover-D6_RGzTY.js} +113 -35
  4. package/dist/ExperimentPopover-D6_RGzTY.js.map +1 -0
  5. package/dist/{ExperimentSelectorModal-BBWXC7KW.js → ExperimentSelectorModal-DcQ38zua.js} +9 -11
  6. package/dist/ExperimentSelectorModal-DcQ38zua.js.map +1 -0
  7. package/dist/{SettingsModal-Dpg-X1OM.js → SettingsModal-Ccq2z-Ms.js} +9 -6
  8. package/dist/SettingsModal-Ccq2z-Ms.js.map +1 -0
  9. package/dist/__stories__/experiment-helpers.d.ts +3 -0
  10. package/dist/__tests__/stores/experiment.test.d.ts +1 -0
  11. package/dist/{analysisArtifactTypes-ejqR8MX3.js → analysisArtifactTypes-DQ0MjwHZ.js} +1 -1
  12. package/dist/{analysisArtifactTypes-ejqR8MX3.js.map → analysisArtifactTypes-DQ0MjwHZ.js.map} +1 -1
  13. package/dist/components/ExperimentPopover.vue.d.ts +5 -0
  14. package/dist/components/ExperimentSelectorModal.vue.d.ts +1 -5
  15. package/dist/components/PluginWorkspaceView.props.d.ts +1 -4
  16. package/dist/components/PluginWorkspaceView.vue.d.ts +0 -1
  17. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
  18. package/dist/components/index.js +7 -7
  19. package/dist/{components-Ci_BTx00.js → components-CV5zuWa8.js} +24 -29
  20. package/dist/components-CV5zuWa8.js.map +1 -0
  21. package/dist/composables/experiment-utils.d.ts +10 -0
  22. package/dist/composables/index.d.ts +2 -2
  23. package/dist/composables/index.js +11 -10
  24. package/dist/composables/useAppExperiment.d.ts +29 -17
  25. package/dist/composables/usePlatformContext.d.ts +3 -3
  26. package/dist/{composables-C0VEJ73O.js → composables-CW8NRXLB.js} +5 -5
  27. package/dist/{composables-C0VEJ73O.js.map → composables-CW8NRXLB.js.map} +1 -1
  28. package/dist/experiment-Y9Iz7KYi.js +95 -0
  29. package/dist/experiment-Y9Iz7KYi.js.map +1 -0
  30. package/dist/{experiment-utils-CxkruZ3G.js → experiment-utils-7Yw-h0tD.js} +16 -2
  31. package/dist/{experiment-utils-CxkruZ3G.js.map → experiment-utils-7Yw-h0tD.js.map} +1 -1
  32. package/dist/index.js +16 -15
  33. package/dist/index.js.map +1 -1
  34. package/dist/install.js +7 -7
  35. package/dist/{plotly.min-BR53hja4.js → plotly.min-c2Sez60c.js} +1 -1
  36. package/dist/{plotly.min-BR53hja4.js.map → plotly.min-c2Sez60c.js.map} +1 -1
  37. package/dist/stores/auth.d.ts +6 -6
  38. package/dist/stores/experiment.d.ts +166 -0
  39. package/dist/stores/index.d.ts +1 -0
  40. package/dist/stores/index.js +3 -2
  41. package/dist/styles.css +188 -0
  42. package/dist/templates/index.js +4 -4
  43. package/dist/{templates-Cdj93S9C.js → templates-CJRFiWUX.js} +2 -2
  44. package/dist/{templates-Cdj93S9C.js.map → templates-CJRFiWUX.js.map} +1 -1
  45. package/dist/types/auth.d.ts +1 -1
  46. package/dist/types/index.js +1 -1
  47. package/dist/types/platform.d.ts +1 -1
  48. package/dist/{auth-B87xM--s.js → useApi-CDBq6z23.js} +191 -2
  49. package/dist/useApi-CDBq6z23.js.map +1 -0
  50. package/dist/{useControlSchema-B_qgU4rW.js → useControlSchema-BEAgLyyx.js} +5 -4
  51. package/dist/{useControlSchema-B_qgU4rW.js.map → useControlSchema-BEAgLyyx.js.map} +1 -1
  52. package/dist/{useDropdownState-gVaMXtwW.js → useDropdownState-Be-ug_ci.js} +2 -2
  53. package/dist/{useDropdownState-gVaMXtwW.js.map → useDropdownState-Be-ug_ci.js.map} +1 -1
  54. package/dist/{useExperimentSelector-BuQZRgMt.js → useExperimentSelector-DFg_iEHI.js} +36 -16
  55. package/dist/useExperimentSelector-DFg_iEHI.js.map +1 -0
  56. package/dist/{useFormBuilder-D1G5J5Z5.js → useFormBuilder-CR9pBApW.js} +2 -2
  57. package/dist/{useFormBuilder-D1G5J5Z5.js.map → useFormBuilder-CR9pBApW.js.map} +1 -1
  58. package/dist/{useProtocolTemplates-DeaOmMaw.js → useProtocolTemplates-DXeIHMwV.js} +38 -42
  59. package/dist/useProtocolTemplates-DXeIHMwV.js.map +1 -0
  60. package/package.json +1 -1
  61. package/src/__stories__/experiment-helpers.ts +12 -9
  62. package/src/__tests__/components/AppTopBar.test.ts +10 -6
  63. package/src/__tests__/components/ExperimentPopover.test.ts +64 -0
  64. package/src/__tests__/components/ExperimentSelectorModal.test.ts +86 -41
  65. package/src/__tests__/components/PluginWorkspaceView.test.ts +103 -19
  66. package/src/__tests__/components/SettingsModal.test.ts +29 -1
  67. package/src/__tests__/composables/experiment-utils.test.ts +33 -0
  68. package/src/__tests__/composables/useAppExperiment.test.ts +331 -92
  69. package/src/__tests__/composables/useAuth.test.ts +2 -2
  70. package/src/__tests__/composables/useExperimentSelector.test.ts +71 -0
  71. package/src/__tests__/composables/usePlatformContext.test.ts +5 -1
  72. package/src/__tests__/stores/experiment.test.ts +300 -0
  73. package/src/components/AppTopBar.vue +0 -2
  74. package/src/components/ExperimentPopover.story.vue +59 -0
  75. package/src/components/ExperimentPopover.vue +96 -6
  76. package/src/components/ExperimentSelectorModal.story.vue +6 -16
  77. package/src/components/ExperimentSelectorModal.vue +8 -4
  78. package/src/components/PluginWorkspaceView.props.ts +1 -4
  79. package/src/components/PluginWorkspaceView.story.vue +12 -5
  80. package/src/components/PluginWorkspaceView.vue +0 -2
  81. package/src/components/SettingsModal.vue +6 -1
  82. package/src/composables/experiment-utils.ts +22 -0
  83. package/src/composables/index.ts +1 -2
  84. package/src/composables/useAppExperiment.ts +57 -67
  85. package/src/composables/useAuth.ts +1 -1
  86. package/src/composables/useExperimentSelector.ts +45 -13
  87. package/src/stores/experiment.ts +120 -0
  88. package/src/stores/index.ts +1 -0
  89. package/src/styles/components/experiment-popover.css +105 -0
  90. package/src/types/auth.ts +1 -1
  91. package/src/types/platform.ts +1 -1
  92. package/dist/EmptyState-DgBRoYAy.js.map +0 -1
  93. package/dist/ExperimentPopover-BFw3QX8L.js.map +0 -1
  94. package/dist/ExperimentSelectorModal-BBWXC7KW.js.map +0 -1
  95. package/dist/SettingsModal-Dpg-X1OM.js.map +0 -1
  96. package/dist/auth-B87xM--s.js.map +0 -1
  97. package/dist/components-Ci_BTx00.js.map +0 -1
  98. package/dist/useExperimentSelector-BuQZRgMt.js.map +0 -1
  99. package/dist/useProtocolTemplates-DeaOmMaw.js.map +0 -1
@@ -1,7 +1,5 @@
1
- import { p as BaseButton_default } from "./experiment-utils-CxkruZ3G.js";
2
- import { r as useSettingsStore, t as useAuthStore } from "./auth-B87xM--s.js";
1
+ import { m as BaseButton_default } from "./experiment-utils-7Yw-h0tD.js";
3
2
  import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, toDisplayString, useAttrs, withCtx } from "vue";
4
- import axios from "axios";
5
3
  //#region src/components/BaseInput.vue?vue&type=script&setup=true&lang.ts
6
4
  var _hoisted_1$3 = [
7
5
  "type",
@@ -258,194 +256,6 @@ var BasePill_default = /* @__PURE__ */ defineComponent({
258
256
  }
259
257
  });
260
258
  //#endregion
261
- //#region src/composables/useApi.ts
262
- var apiClientInstance = null;
263
- var interceptorAttached = false;
264
- function joinUrlPath(baseUrl, path) {
265
- if (/^https?:\/\//i.test(path)) return path;
266
- if (!path) return baseUrl;
267
- if (path.startsWith("?") || path.startsWith("#")) return `${baseUrl.replace(/\/+$/, "")}${path}`;
268
- const normalizedBase = baseUrl.replace(/\/+$/, "");
269
- const normalizedPath = path.replace(/^\/+/, "/");
270
- return `${normalizedBase}${normalizedPath.startsWith("/") ? normalizedPath : `/${normalizedPath}`}`;
271
- }
272
- function getBasePath(baseUrl) {
273
- if (!baseUrl) return "/";
274
- try {
275
- const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
276
- return new URL(baseUrl, origin).pathname.replace(/\/+$/, "") || "/";
277
- } catch {
278
- return baseUrl.replace(/^https?:\/\/[^/]+/i, "").replace(/\/+$/, "") || "/";
279
- }
280
- }
281
- function normalizeRequestUrl(baseUrl, url) {
282
- if (!url || /^https?:\/\//.test(url)) return url;
283
- const basePath = getBasePath(baseUrl);
284
- if (basePath === "/") return url;
285
- const normalizedUrl = url.startsWith("/") ? url : `/${url}`;
286
- if (normalizedUrl === basePath || normalizedUrl.startsWith(`${basePath}?`) || normalizedUrl.startsWith(`${basePath}#`)) return normalizedUrl.slice(basePath.length);
287
- if (normalizedUrl.startsWith(`${basePath}/`)) return normalizedUrl.slice(basePath.length) || "";
288
- return url;
289
- }
290
- function asMutableHeaders(headers) {
291
- return headers ? headers : null;
292
- }
293
- function hasAuthorizationHeader(headers) {
294
- const bag = asMutableHeaders(headers);
295
- if (!bag) return false;
296
- if (typeof bag.has === "function") return bag.has("Authorization");
297
- return Object.keys(bag).some((key) => key.toLowerCase() === "authorization");
298
- }
299
- function setAuthorizationHeader(headers, value) {
300
- const bag = asMutableHeaders(headers);
301
- if (!bag) return;
302
- if (typeof bag.set === "function") {
303
- bag.set("Authorization", value);
304
- return;
305
- }
306
- bag.Authorization = value;
307
- }
308
- function deleteAuthorizationHeader(headers) {
309
- const bag = asMutableHeaders(headers);
310
- if (!bag) return;
311
- if (typeof bag.delete === "function") {
312
- bag.delete("Authorization");
313
- return;
314
- }
315
- for (const key of Object.keys(bag)) if (key.toLowerCase() === "authorization") delete bag[key];
316
- }
317
- function getAuthorizationHeader(headers) {
318
- const bag = asMutableHeaders(headers);
319
- if (!bag) return void 0;
320
- if (typeof bag.get === "function") return bag.get("Authorization");
321
- const key = Object.keys(bag).find((candidate) => candidate.toLowerCase() === "authorization");
322
- return key ? bag[key] : void 0;
323
- }
324
- /** Raised when an authenticated SDK request is rejected because the login is no longer valid. */
325
- var AuthenticationRequiredError = class extends Error {
326
- code = "AUTHENTICATION_REQUIRED";
327
- status = 401;
328
- constructor(cause) {
329
- super("Authentication required. Please sign in again.");
330
- this.cause = cause;
331
- this.name = "AuthenticationRequiredError";
332
- }
333
- };
334
- /** @internal Convert a rejected authenticated request into the SDK's public auth error. */
335
- function authenticationRequiredError(cause, rejectedToken) {
336
- const currentAuthStore = useAuthStore();
337
- if (rejectedToken && currentAuthStore.token === rejectedToken) currentAuthStore.clearToken();
338
- return new AuthenticationRequiredError(cause);
339
- }
340
- function getApiClient() {
341
- if (!apiClientInstance) apiClientInstance = axios.create({ headers: { "Content-Type": "application/json" } });
342
- return apiClientInstance;
343
- }
344
- /** Axios-based API client that injects the plugin base URL and JWT auth header on every request. */
345
- function useApi(options = {}) {
346
- const settingsStore = useSettingsStore();
347
- const authStore = useAuthStore();
348
- const apiClient = getApiClient();
349
- if (!authStore.isInitialized) authStore.initialize();
350
- if (!interceptorAttached) {
351
- apiClient.interceptors.request.use((config) => {
352
- const request = config;
353
- if (request._mintSkipAuth) {
354
- deleteAuthorizationHeader(request.headers);
355
- return request;
356
- }
357
- const currentAuthStore = useAuthStore();
358
- if (currentAuthStore.token && config.headers && !hasAuthorizationHeader(config.headers)) setAuthorizationHeader(config.headers, `Bearer ${currentAuthStore.token}`);
359
- if (getAuthorizationHeader(config.headers) === `Bearer ${currentAuthStore.token}`) request._mintAuthToken = currentAuthStore.token ?? void 0;
360
- return config;
361
- });
362
- apiClient.interceptors.response.use((response) => response, (error) => {
363
- if (axios.isAxiosError(error) && error.response?.status === 401) {
364
- const request = error.config;
365
- if (request?._mintSkipAuth !== true) return Promise.reject(authenticationRequiredError(error, request?._mintAuthToken));
366
- }
367
- return Promise.reject(error);
368
- });
369
- interceptorAttached = true;
370
- }
371
- function getBaseUrl() {
372
- return options.baseUrl ?? settingsStore.getApiBaseUrl();
373
- }
374
- function normalizeUrl(url) {
375
- return normalizeRequestUrl(getBaseUrl(), url);
376
- }
377
- function requestConfig(config) {
378
- const base = {
379
- baseURL: getBaseUrl(),
380
- timeout: options.timeout ?? settingsStore.requestTimeout,
381
- ...config
382
- };
383
- if (options.withAuth === false) {
384
- base._mintSkipAuth = true;
385
- deleteAuthorizationHeader(base.headers);
386
- }
387
- return base;
388
- }
389
- async function get(url, config) {
390
- return (await apiClient.get(normalizeUrl(url), requestConfig(config))).data;
391
- }
392
- async function post(url, data, config) {
393
- return (await apiClient.post(normalizeUrl(url), data, requestConfig(config))).data;
394
- }
395
- async function put(url, data, config) {
396
- return (await apiClient.put(normalizeUrl(url), data, requestConfig(config))).data;
397
- }
398
- async function patch(url, data, config) {
399
- return (await apiClient.patch(normalizeUrl(url), data, requestConfig(config))).data;
400
- }
401
- async function del(url, config) {
402
- return (await apiClient.delete(normalizeUrl(url), requestConfig(config))).data;
403
- }
404
- async function upload(url, file, fieldName = "file", additionalData) {
405
- const formData = new FormData();
406
- formData.append(fieldName, file);
407
- if (additionalData) Object.entries(additionalData).forEach(([key, value]) => {
408
- if (value !== void 0 && value !== null) formData.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
409
- });
410
- return (await apiClient.post(normalizeUrl(url), formData, requestConfig({ headers: { "Content-Type": void 0 } }))).data;
411
- }
412
- async function download(url, filename) {
413
- const response = await apiClient.get(normalizeUrl(url), requestConfig({ responseType: "blob" }));
414
- const blob = new Blob([response.data]);
415
- const blobUrl = URL.createObjectURL(blob);
416
- if (filename) {
417
- const link = document.createElement("a");
418
- link.href = blobUrl;
419
- link.download = filename;
420
- document.body.appendChild(link);
421
- link.click();
422
- document.body.removeChild(link);
423
- setTimeout(() => URL.revokeObjectURL(blobUrl), 100);
424
- return "";
425
- }
426
- return blobUrl;
427
- }
428
- function buildUrl(path) {
429
- const baseUrl = getBaseUrl();
430
- return joinUrlPath(baseUrl, normalizeRequestUrl(baseUrl, path));
431
- }
432
- function buildWsUrl(path) {
433
- return joinUrlPath(settingsStore.getWsBaseUrl(), path);
434
- }
435
- return {
436
- client: apiClient,
437
- get,
438
- post,
439
- put,
440
- patch,
441
- delete: del,
442
- upload,
443
- download,
444
- buildUrl,
445
- buildWsUrl
446
- };
447
- }
448
- //#endregion
449
259
  //#region src/composables/useRequestSyncState.ts
450
260
  /** Shared loading/error/timestamp state for generated plugin request helpers. */
451
261
  function useRequestSyncState(defaultErrorMessage = "Request failed.") {
@@ -642,6 +452,6 @@ var EmptyState_default = /* @__PURE__ */ defineComponent({
642
452
  }
643
453
  });
644
454
  //#endregion
645
- export { authenticationRequiredError as a, BaseSelect_default as c, AuthenticationRequiredError as i, normalizeOptionInput as l, Skeleton_default as n, useApi as o, useRequestSyncState as r, BasePill_default as s, EmptyState_default as t, BaseInput_default as u };
455
+ export { BaseSelect_default as a, BasePill_default as i, Skeleton_default as n, normalizeOptionInput as o, useRequestSyncState as r, BaseInput_default as s, EmptyState_default as t };
646
456
 
647
- //# sourceMappingURL=EmptyState-DgBRoYAy.js.map
457
+ //# sourceMappingURL=EmptyState-LMPS3keb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState-LMPS3keb.js","names":[],"sources":["../src/components/BaseInput.vue","../src/components/BaseInput.vue","../src/utils/options.ts","../src/components/BaseSelect.vue","../src/components/BaseSelect.vue","../src/components/BasePill.vue","../src/components/BasePill.vue","../src/composables/useRequestSyncState.ts","../src/components/Skeleton.vue","../src/components/Skeleton.vue","../src/components/EmptyState.vue","../src/components/EmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Renders a styled `<input>` supporting text/number/email types, size, error, and readonly states. */\nimport type { InputType } from '../types'\n\ninterface Props {\n modelValue?: string | number\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n min?: number\n max?: number\n step?: number\n list?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = props.type === 'number'\n ? (target.value === '' ? null : Number(target.value))\n : target.value\n emit('update:modelValue', value as string | number)\n}\n</script>\n\n<template>\n <input\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n error ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n\n<style>\n@import '../styles/components/input.css';\n</style>\n","<script setup lang=\"ts\">\n/** Renders a styled `<input>` supporting text/number/email types, size, error, and readonly states. */\nimport type { InputType } from '../types'\n\ninterface Props {\n modelValue?: string | number\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n min?: number\n max?: number\n step?: number\n list?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = props.type === 'number'\n ? (target.value === '' ? null : Number(target.value))\n : target.value\n emit('update:modelValue', value as string | number)\n}\n</script>\n\n<template>\n <input\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n error ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n\n<style>\n@import '../styles/components/input.css';\n</style>\n","export type OptionLike<TValue extends string | number> = {\n value: TValue\n label: string\n}\n\nexport function normalizeOptionInput<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(option: TOption | TValue): TOption {\n if (typeof option === 'object') return option\n\n return {\n value: option,\n label: String(option),\n } as TOption\n}\n\nexport function findOptionByDomValue<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(options: TOption[], value: string): TOption | undefined {\n return options.find(option => String(option.value) === value)\n}\n","<script setup lang=\"ts\">\n/** Renders a native `<select>` element with size, error, and disabled states. */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n})\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput)\n)\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n emit('update:modelValue', option?.value ?? target.value)\n}\n</script>\n\n<template>\n <div v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"modelValue\"\n :disabled=\"disabled\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n error ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/select.css';\n</style>\n","<script setup lang=\"ts\">\n/** Renders a native `<select>` element with size, error, and disabled states. */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n})\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput)\n)\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n emit('update:modelValue', option?.value ?? target.value)\n}\n</script>\n\n<template>\n <div v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"modelValue\"\n :disabled=\"disabled\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n error ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/select.css';\n</style>\n","<script setup lang=\"ts\">\n/** Compact label for tags, status indicators, and badges; supports removable and icon slots. */\nimport type { PillVariant, PillColor, PillSize } from '../types'\n\n/**\n * BasePill - Compact label component for tags, status indicators, and badges.\n *\n * @example\n * ```vue\n * <BasePill variant=\"success\">Active</BasePill>\n * <BasePill variant=\"warning\" removable @remove=\"handleRemove\">Tag</BasePill>\n * <BasePill :icon=\"true\">\n * <template #icon><CheckIcon /></template>\n * Verified\n * </BasePill>\n * ```\n */\ninterface Props {\n /** Visual style variant */\n variant?: PillVariant\n /** Semantic color modifier — use with variant=\"outline\" for colored outlines */\n color?: PillColor\n /** Size of the pill */\n size?: PillSize\n /** Show remove button */\n removable?: boolean\n /** Disable interaction */\n disabled?: boolean\n /** Show icon slot */\n icon?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'default',\n color: undefined,\n size: 'md',\n removable: false,\n disabled: false,\n icon: false,\n})\n\n/**\n * @event remove - Emitted when the remove button is clicked\n */\nconst emit = defineEmits<{\n remove: []\n}>()\n\nfunction handleRemove(event: MouseEvent) {\n event.stopPropagation()\n if (!props.disabled) {\n emit('remove')\n }\n}\n</script>\n\n<template>\n <span\n :class=\"[\n 'mint-pill',\n `mint-pill--${variant}`,\n color && `mint-pill--${color}`,\n `mint-pill--${size}`,\n { 'mint-pill--disabled': disabled, 'mint-pill--with-icon': icon },\n ]\"\n >\n <span v-if=\"icon\" class=\"mint-pill__icon\">\n <slot name=\"icon\" />\n </span>\n <span class=\"mint-pill__label\">\n <slot />\n </span>\n <button\n v-if=\"removable && !disabled\"\n type=\"button\"\n class=\"mint-pill__remove\"\n aria-label=\"Remove\"\n @click=\"handleRemove\"\n >\n <svg class=\"mint-pill__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n</template>\n\n<style>\n@import '../styles/components/pill.css';\n</style>\n","<script setup lang=\"ts\">\n/** Compact label for tags, status indicators, and badges; supports removable and icon slots. */\nimport type { PillVariant, PillColor, PillSize } from '../types'\n\n/**\n * BasePill - Compact label component for tags, status indicators, and badges.\n *\n * @example\n * ```vue\n * <BasePill variant=\"success\">Active</BasePill>\n * <BasePill variant=\"warning\" removable @remove=\"handleRemove\">Tag</BasePill>\n * <BasePill :icon=\"true\">\n * <template #icon><CheckIcon /></template>\n * Verified\n * </BasePill>\n * ```\n */\ninterface Props {\n /** Visual style variant */\n variant?: PillVariant\n /** Semantic color modifier — use with variant=\"outline\" for colored outlines */\n color?: PillColor\n /** Size of the pill */\n size?: PillSize\n /** Show remove button */\n removable?: boolean\n /** Disable interaction */\n disabled?: boolean\n /** Show icon slot */\n icon?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'default',\n color: undefined,\n size: 'md',\n removable: false,\n disabled: false,\n icon: false,\n})\n\n/**\n * @event remove - Emitted when the remove button is clicked\n */\nconst emit = defineEmits<{\n remove: []\n}>()\n\nfunction handleRemove(event: MouseEvent) {\n event.stopPropagation()\n if (!props.disabled) {\n emit('remove')\n }\n}\n</script>\n\n<template>\n <span\n :class=\"[\n 'mint-pill',\n `mint-pill--${variant}`,\n color && `mint-pill--${color}`,\n `mint-pill--${size}`,\n { 'mint-pill--disabled': disabled, 'mint-pill--with-icon': icon },\n ]\"\n >\n <span v-if=\"icon\" class=\"mint-pill__icon\">\n <slot name=\"icon\" />\n </span>\n <span class=\"mint-pill__label\">\n <slot />\n </span>\n <button\n v-if=\"removable && !disabled\"\n type=\"button\"\n class=\"mint-pill__remove\"\n aria-label=\"Remove\"\n @click=\"handleRemove\"\n >\n <svg class=\"mint-pill__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n</template>\n\n<style>\n@import '../styles/components/pill.css';\n</style>\n","import { ref, type Ref } from 'vue'\n\nexport type RequestSyncSuccessKind = 'load' | 'save' | 'run'\n\nexport interface RequestSyncRunOptions {\n success?: RequestSyncSuccessKind\n errorMessage?: string\n}\n\nexport interface UseRequestSyncStateReturn {\n /** Whether a request is in progress. */\n loading: Ref<boolean>\n /** Message from the last failed request, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load operation, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save operation, or null. */\n lastSavedAt: Ref<Date | null>\n /** Timestamp of the last successful run operation, or null. */\n lastRunAt: Ref<Date | null>\n /** Clear the current error without changing loading or timestamps. */\n clearError: () => void\n /** Convert thrown values into a developer-facing error message. */\n readErrorMessage: (value: unknown, fallback?: string) => string\n /** Store and return a normalized error message. */\n setError: (value: unknown, fallback?: string) => string\n /** Mark the resource as successfully loaded. */\n markLoaded: (date?: Date) => void\n /** Mark the resource as successfully saved. */\n markSaved: (date?: Date) => void\n /** Mark the operation as successfully run. */\n markRun: (date?: Date) => void\n /** Run a request with shared loading/error handling and optional sync marking. */\n run: <T>(operation: () => Promise<T>, options?: RequestSyncRunOptions) => Promise<T>\n}\n\n/** Shared loading/error/timestamp state for generated plugin request helpers. */\nexport function useRequestSyncState(\n defaultErrorMessage = 'Request failed.',\n): UseRequestSyncStateReturn {\n const loading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedAt = ref<Date | null>(null)\n const lastSavedAt = ref<Date | null>(null)\n const lastRunAt = ref<Date | null>(null)\n\n function clearError(): void {\n error.value = null\n }\n\n function readErrorMessage(value: unknown, fallback = defaultErrorMessage): string {\n if (value instanceof Error && value.message) {\n return value.message\n }\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message\n ) {\n return (value as { message: string }).message\n }\n return fallback\n }\n\n function setError(value: unknown, fallback?: string): string {\n const message = readErrorMessage(value, fallback)\n error.value = message\n return message\n }\n\n function markLoaded(date = new Date()): void {\n lastLoadedAt.value = date\n }\n\n function markSaved(date = new Date()): void {\n lastSavedAt.value = date\n }\n\n function markRun(date = new Date()): void {\n lastRunAt.value = date\n }\n\n async function run<T>(\n operation: () => Promise<T>,\n options: RequestSyncRunOptions = {},\n ): Promise<T> {\n loading.value = true\n clearError()\n try {\n const response = await operation()\n if (options.success === 'load') {\n markLoaded()\n } else if (options.success === 'save') {\n markSaved()\n } else if (options.success === 'run') {\n markRun()\n }\n return response\n } catch (err) {\n setError(err, options.errorMessage)\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n lastLoadedAt,\n lastSavedAt,\n lastRunAt,\n clearError,\n readErrorMessage,\n setError,\n markLoaded,\n markSaved,\n markRun,\n run,\n }\n}\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => {\n const base = ['bg-bg-hover']\n\n switch (props.variant) {\n case 'circular':\n base.push('rounded-full')\n if (!props.width && !props.height) {\n base.push('w-10 h-10')\n }\n break\n case 'rectangular':\n base.push('rounded-none')\n if (!props.height) base.push('h-24')\n break\n case 'rounded':\n base.push('rounded-mint')\n if (!props.height) base.push('h-24')\n break\n default:\n base.push('rounded')\n if (!props.height) base.push('h-4')\n if (!props.width) base.push('w-full')\n }\n\n switch (props.animation) {\n case 'pulse':\n base.push('animate-pulse')\n break\n case 'wave':\n base.push('skeleton-wave')\n break\n }\n\n return base\n})\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n\n<style>\n@import '../styles/components/skeleton.css';\n</style>\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => {\n const base = ['bg-bg-hover']\n\n switch (props.variant) {\n case 'circular':\n base.push('rounded-full')\n if (!props.width && !props.height) {\n base.push('w-10 h-10')\n }\n break\n case 'rectangular':\n base.push('rounded-none')\n if (!props.height) base.push('h-24')\n break\n case 'rounded':\n base.push('rounded-mint')\n if (!props.height) base.push('h-24')\n break\n default:\n base.push('rounded')\n if (!props.height) base.push('h-4')\n if (!props.width) base.push('w-full')\n }\n\n switch (props.animation) {\n case 'pulse':\n base.push('animate-pulse')\n break\n case 'wave':\n base.push('skeleton-wave')\n break\n }\n\n return base\n})\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n\n<style>\n@import '../styles/components/skeleton.css';\n</style>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n color?: 'primary' | 'cta' | 'success' | 'warning' | 'error' | 'muted'\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n color: 'primary',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${color}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${color}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <slot />\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/empty-state.css';\n</style>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n color?: 'primary' | 'cta' | 'success' | 'warning' | 'error' | 'muted'\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n color: 'primary',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${color}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${color}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <slot />\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/empty-state.css';\n</style>\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { n as __exportAll } from "./chunk-BoAXSpZd.js";
2
- import { c as formatExperimentStatus, d as BaseModal_default, p as BaseButton_default } from "./experiment-utils-CxkruZ3G.js";
3
- import { t as useDropdownState } from "./useDropdownState-gVaMXtwW.js";
4
- import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onUnmounted, openBlock, ref, renderSlot, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
2
+ import { f as BaseModal_default, l as formatExperimentStatus, m as BaseButton_default } from "./experiment-utils-7Yw-h0tD.js";
3
+ import { t as useDropdownState } from "./useDropdownState-Be-ug_ci.js";
4
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onUnmounted, openBlock, ref, renderSlot, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
5
5
  //#region src/components/ConfirmDialog.vue?vue&type=script&setup=true&lang.ts
6
6
  var _hoisted_1$1 = { class: "mint-confirm" };
7
7
  var _hoisted_2$1 = {
@@ -99,25 +99,39 @@ var ConfirmDialog_default = /* @__PURE__ */ defineComponent({
99
99
  });
100
100
  //#endregion
101
101
  //#region src/components/ExperimentPopover.vue?vue&type=script&setup=true&lang.ts
102
- var _hoisted_1 = ["title", "aria-expanded"];
102
+ var _hoisted_1 = [
103
+ "title",
104
+ "aria-label",
105
+ "aria-busy",
106
+ "aria-expanded"
107
+ ];
103
108
  var _hoisted_2 = {
104
109
  key: 0,
105
- class: "mint-experiment-popover__trigger-text"
110
+ class: "mint-experiment-popover__trigger-skeleton",
111
+ "aria-hidden": "true"
106
112
  };
107
113
  var _hoisted_3 = {
108
114
  key: 1,
109
- class: "mint-experiment-popover__trigger-code"
115
+ class: "mint-experiment-popover__trigger-text"
110
116
  };
111
117
  var _hoisted_4 = {
112
118
  key: 2,
113
119
  class: "mint-experiment-popover__trigger-text"
114
120
  };
115
- var _hoisted_5 = ["disabled", "title"];
121
+ var _hoisted_5 = {
122
+ key: 3,
123
+ class: "mint-experiment-popover__trigger-code"
124
+ };
116
125
  var _hoisted_6 = {
126
+ key: 4,
127
+ class: "mint-experiment-popover__trigger-text"
128
+ };
129
+ var _hoisted_7 = ["disabled", "title"];
130
+ var _hoisted_8 = {
117
131
  key: 0,
118
132
  class: "mint-experiment-popover__spinner--inline"
119
133
  };
120
- var _hoisted_7 = {
134
+ var _hoisted_9 = {
121
135
  key: 1,
122
136
  class: "mint-experiment-popover__save-trigger-icon",
123
137
  "aria-hidden": "true",
@@ -125,7 +139,7 @@ var _hoisted_7 = {
125
139
  stroke: "currentColor",
126
140
  viewBox: "0 0 24 24"
127
141
  };
128
- var _hoisted_8 = {
142
+ var _hoisted_10 = {
129
143
  key: 2,
130
144
  class: "mint-experiment-popover__save-trigger-icon",
131
145
  "aria-hidden": "true",
@@ -133,38 +147,59 @@ var _hoisted_8 = {
133
147
  stroke: "currentColor",
134
148
  viewBox: "0 0 24 24"
135
149
  };
136
- var _hoisted_9 = {
150
+ var _hoisted_11 = {
137
151
  key: 0,
138
152
  class: "mint-experiment-popover__panel"
139
153
  };
140
- var _hoisted_10 = { class: "mint-experiment-popover__header" };
141
- var _hoisted_11 = { class: "mint-experiment-popover__subtitle" };
142
- var _hoisted_12 = {
154
+ var _hoisted_12 = { class: "mint-experiment-popover__header" };
155
+ var _hoisted_13 = { class: "mint-experiment-popover__subtitle" };
156
+ var _hoisted_14 = {
143
157
  key: 0,
144
158
  class: "mint-experiment-popover__body"
145
159
  };
146
- var _hoisted_13 = {
160
+ var _hoisted_15 = { class: "mint-experiment-popover__card-actions" };
161
+ var _hoisted_16 = {
147
162
  key: 1,
148
163
  class: "mint-experiment-popover__body"
149
164
  };
150
- var _hoisted_14 = { class: "mint-experiment-popover__card" };
151
- var _hoisted_15 = { class: "mint-experiment-popover__card-info" };
152
- var _hoisted_16 = {
165
+ var _hoisted_17 = {
166
+ class: "mint-experiment-popover__card mint-experiment-popover__card--error",
167
+ role: "alert"
168
+ };
169
+ var _hoisted_18 = { class: "mint-experiment-popover__card-info" };
170
+ var _hoisted_19 = { class: "mint-experiment-popover__card-message" };
171
+ var _hoisted_20 = { class: "mint-experiment-popover__card-actions" };
172
+ var _hoisted_21 = {
173
+ key: 2,
174
+ class: "mint-experiment-popover__body"
175
+ };
176
+ var _hoisted_22 = {
177
+ key: 3,
178
+ class: "mint-experiment-popover__body"
179
+ };
180
+ var _hoisted_23 = { class: "mint-experiment-popover__card" };
181
+ var _hoisted_24 = { class: "mint-experiment-popover__card-info" };
182
+ var _hoisted_25 = {
153
183
  key: 0,
154
184
  class: "mint-experiment-popover__card-code"
155
185
  };
156
- var _hoisted_17 = { class: "mint-experiment-popover__card-name" };
157
- var _hoisted_18 = {
186
+ var _hoisted_26 = { class: "mint-experiment-popover__card-name" };
187
+ var _hoisted_27 = {
158
188
  key: 1,
159
189
  class: "mint-experiment-popover__card-status"
160
190
  };
161
- var _hoisted_19 = { class: "mint-experiment-popover__card-actions" };
191
+ var _hoisted_28 = { class: "mint-experiment-popover__card-actions" };
162
192
  var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
163
193
  __name: "ExperimentPopover",
164
194
  props: {
165
195
  experimentName: {},
166
196
  experimentCode: {},
167
197
  experimentStatus: {},
198
+ isResolving: {
199
+ type: Boolean,
200
+ default: false
201
+ },
202
+ error: {},
168
203
  showSave: {
169
204
  type: Boolean,
170
205
  default: false
@@ -198,6 +233,18 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
198
233
  setup(__props, { emit: __emit }) {
199
234
  /** Floating popover showing the active experiment with save, detach, and select actions. */
200
235
  const props = __props;
236
+ const isUnresolved = computed(() => props.isResolving || !!props.error);
237
+ const hasExperiment = computed(() => !!props.experimentName || !!props.experimentCode);
238
+ const panelSubtitle = computed(() => {
239
+ if (props.isResolving) return "Loading experiment…";
240
+ if (props.error) return "Could not load this experiment";
241
+ return hasExperiment.value ? "Linked experiment context" : "Link to an MINT experiment";
242
+ });
243
+ const triggerLabel = computed(() => {
244
+ if (props.isResolving) return "Loading experiment";
245
+ if (props.error) return "Experiment unavailable";
246
+ return props.experimentName || props.experimentCode || "No experiment";
247
+ });
201
248
  const emit = __emit;
202
249
  const { isOpen, rootRef: popoverRef, close, toggle } = useDropdownState({ closeOnEscape: false });
203
250
  const showSuccess = ref(false);
@@ -244,9 +291,13 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
244
291
  class: normalizeClass([
245
292
  "mint-experiment-popover__trigger",
246
293
  { "mint-experiment-popover__trigger--active": unref(isOpen) },
247
- { "mint-experiment-popover__trigger--empty": !__props.experimentCode && !__props.experimentName }
294
+ { "mint-experiment-popover__trigger--empty": !isUnresolved.value && !hasExperiment.value },
295
+ { "mint-experiment-popover__trigger--loading": __props.isResolving },
296
+ { "mint-experiment-popover__trigger--error": !__props.isResolving && !!__props.error }
248
297
  ]),
249
- title: __props.experimentName || __props.experimentCode || void 0,
298
+ title: isUnresolved.value ? triggerLabel.value : __props.experimentName || __props.experimentCode || void 0,
299
+ "aria-label": isUnresolved.value ? triggerLabel.value : void 0,
300
+ "aria-busy": __props.isResolving || void 0,
250
301
  "aria-expanded": unref(isOpen),
251
302
  onClick: _cache[0] || (_cache[0] = withModifiers((...args) => unref(toggle) && unref(toggle)(...args), ["stop"]))
252
303
  }, [
@@ -262,7 +313,7 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
262
313
  "stroke-width": "1.75",
263
314
  d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
264
315
  })], -1)),
265
- __props.experimentName ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(__props.experimentName), 1)) : __props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(__props.experimentCode), 1)) : (openBlock(), createElementBlock("span", _hoisted_4, "No experiment")),
316
+ __props.isResolving ? (openBlock(), createElementBlock("span", _hoisted_2)) : __props.error ? (openBlock(), createElementBlock("span", _hoisted_3, "Experiment unavailable")) : __props.experimentName ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(__props.experimentName), 1)) : __props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(__props.experimentCode), 1)) : (openBlock(), createElementBlock("span", _hoisted_6, "No experiment")),
266
317
  _cache[3] || (_cache[3] = createElementVNode("svg", {
267
318
  class: "mint-experiment-popover__trigger-chevron",
268
319
  "aria-hidden": "true",
@@ -286,22 +337,49 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
286
337
  title: __props.saveDisabled && __props.saveDisabledMessage ? __props.saveDisabledMessage : showSuccess.value && __props.saveSuccessMessage ? __props.saveSuccessMessage : "Save to Experiment",
287
338
  "aria-label": "Save to experiment",
288
339
  onClick: withModifiers(handleSave, ["stop"])
289
- }, [__props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_6)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_7, [..._cache[4] || (_cache[4] = [createElementVNode("path", {
340
+ }, [__props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_8)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_9, [..._cache[4] || (_cache[4] = [createElementVNode("path", {
290
341
  "stroke-linecap": "round",
291
342
  "stroke-linejoin": "round",
292
343
  "stroke-width": "2.5",
293
344
  d: "M5 13l4 4L19 7"
294
- }, null, -1)])])) : (openBlock(), createElementBlock("svg", _hoisted_8, [..._cache[5] || (_cache[5] = [createElementVNode("path", {
345
+ }, null, -1)])])) : (openBlock(), createElementBlock("svg", _hoisted_10, [..._cache[5] || (_cache[5] = [createElementVNode("path", {
295
346
  "stroke-linecap": "round",
296
347
  "stroke-linejoin": "round",
297
348
  "stroke-width": "2",
298
349
  d: "M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
299
- }, null, -1)])]))], 10, _hoisted_5)) : createCommentVNode("", true)], 2),
300
- unref(isOpen) ? (openBlock(), createElementBlock("div", _hoisted_9, [createElementVNode("div", _hoisted_10, [_cache[6] || (_cache[6] = createElementVNode("div", { class: "mint-experiment-popover__title" }, "Experiment", -1)), createElementVNode("div", _hoisted_11, toDisplayString(__props.experimentName ? "Linked experiment context" : "Link to an MINT experiment"), 1)]), !__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_12, [createElementVNode("button", {
350
+ }, null, -1)])]))], 10, _hoisted_7)) : createCommentVNode("", true)], 2),
351
+ unref(isOpen) ? (openBlock(), createElementBlock("div", _hoisted_11, [createElementVNode("div", _hoisted_12, [_cache[6] || (_cache[6] = createElementVNode("div", { class: "mint-experiment-popover__title" }, "Experiment", -1)), createElementVNode("div", _hoisted_13, toDisplayString(panelSubtitle.value), 1)]), __props.isResolving ? (openBlock(), createElementBlock("div", _hoisted_14, [_cache[7] || (_cache[7] = createStaticVNode("<div class=\"mint-experiment-popover__card\" aria-busy=\"true\"><div class=\"mint-experiment-popover__card-icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.75\" d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"></path></svg></div><div class=\"mint-experiment-popover__card-info\"><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--code\"></span><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--name\"></span><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--status\"></span></div></div>", 1)), createElementVNode("div", _hoisted_15, [createElementVNode("button", {
352
+ type: "button",
353
+ class: "mint-experiment-popover__change-btn",
354
+ onClick: handleSelect
355
+ }, " Change "), __props.showDetach ? (openBlock(), createElementBlock("button", {
356
+ key: 0,
357
+ type: "button",
358
+ class: "mint-experiment-popover__detach-btn",
359
+ onClick: handleDetach
360
+ }, " Detach ")) : createCommentVNode("", true)])])) : __props.error ? (openBlock(), createElementBlock("div", _hoisted_16, [createElementVNode("div", _hoisted_17, [_cache[9] || (_cache[9] = createElementVNode("div", { class: "mint-experiment-popover__card-icon mint-experiment-popover__card-icon--error" }, [createElementVNode("svg", {
361
+ fill: "none",
362
+ stroke: "currentColor",
363
+ viewBox: "0 0 24 24"
364
+ }, [createElementVNode("path", {
365
+ "stroke-linecap": "round",
366
+ "stroke-linejoin": "round",
367
+ "stroke-width": "1.75",
368
+ d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
369
+ })])], -1)), createElementVNode("div", _hoisted_18, [_cache[8] || (_cache[8] = createElementVNode("div", { class: "mint-experiment-popover__card-name" }, "Experiment unavailable", -1)), createElementVNode("div", _hoisted_19, toDisplayString(__props.error), 1)])]), createElementVNode("div", _hoisted_20, [createElementVNode("button", {
370
+ type: "button",
371
+ class: "mint-experiment-popover__change-btn",
372
+ onClick: handleSelect
373
+ }, " Change "), __props.showDetach ? (openBlock(), createElementBlock("button", {
374
+ key: 0,
375
+ type: "button",
376
+ class: "mint-experiment-popover__detach-btn",
377
+ onClick: handleDetach
378
+ }, " Detach ")) : createCommentVNode("", true)])])) : !__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_21, [createElementVNode("button", {
301
379
  type: "button",
302
380
  class: "mint-experiment-popover__select-btn",
303
381
  onClick: handleSelect
304
- }, [..._cache[7] || (_cache[7] = [createElementVNode("svg", {
382
+ }, [..._cache[10] || (_cache[10] = [createElementVNode("svg", {
305
383
  width: "14",
306
384
  height: "14",
307
385
  fill: "none",
@@ -312,7 +390,7 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
312
390
  "stroke-linejoin": "round",
313
391
  "stroke-width": "2",
314
392
  d: "M12 4v16m8-8H4"
315
- })], -1), createTextVNode(" Select Experiment ", -1)])])])) : (openBlock(), createElementBlock("div", _hoisted_13, [createElementVNode("div", _hoisted_14, [_cache[8] || (_cache[8] = createElementVNode("div", { class: "mint-experiment-popover__card-icon" }, [createElementVNode("svg", {
393
+ })], -1), createTextVNode(" Select Experiment ", -1)])])])) : (openBlock(), createElementBlock("div", _hoisted_22, [createElementVNode("div", _hoisted_23, [_cache[11] || (_cache[11] = createElementVNode("div", { class: "mint-experiment-popover__card-icon" }, [createElementVNode("svg", {
316
394
  fill: "none",
317
395
  stroke: "currentColor",
318
396
  viewBox: "0 0 24 24"
@@ -321,11 +399,11 @@ var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
321
399
  "stroke-linejoin": "round",
322
400
  "stroke-width": "1.75",
323
401
  d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
324
- })])], -1)), createElementVNode("div", _hoisted_15, [
325
- __props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_16, toDisplayString(__props.experimentCode), 1)) : createCommentVNode("", true),
326
- createElementVNode("div", _hoisted_17, toDisplayString(__props.experimentName), 1),
327
- __props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_18, toDisplayString(unref(formatExperimentStatus)(__props.experimentStatus)), 1)) : createCommentVNode("", true)
328
- ])]), createElementVNode("div", _hoisted_19, [createElementVNode("button", {
402
+ })])], -1)), createElementVNode("div", _hoisted_24, [
403
+ __props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_25, toDisplayString(__props.experimentCode), 1)) : createCommentVNode("", true),
404
+ createElementVNode("div", _hoisted_26, toDisplayString(__props.experimentName), 1),
405
+ __props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_27, toDisplayString(unref(formatExperimentStatus)(__props.experimentStatus)), 1)) : createCommentVNode("", true)
406
+ ])]), createElementVNode("div", _hoisted_28, [createElementVNode("button", {
329
407
  type: "button",
330
408
  class: "mint-experiment-popover__change-btn",
331
409
  onClick: handleSelect
@@ -361,4 +439,4 @@ var ExperimentPopover_default = ExperimentPopover_vue_vue_type_script_setup_true
361
439
  //#endregion
362
440
  export { ExperimentPopover_exports as n, ConfirmDialog_default as r, ExperimentPopover_default as t };
363
441
 
364
- //# sourceMappingURL=ExperimentPopover-BFw3QX8L.js.map
442
+ //# sourceMappingURL=ExperimentPopover-D6_RGzTY.js.map