@morscherlab/mld-sdk 0.9.8 → 0.10.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.
Files changed (46) hide show
  1. package/dist/__stories__/experiment-helpers.d.ts +25 -0
  2. package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
  3. package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
  4. package/dist/components/AppTopBar.vue.js +61 -28
  5. package/dist/components/AppTopBar.vue.js.map +1 -1
  6. package/dist/components/AuditTrail.vue.d.ts +1 -1
  7. package/dist/components/ExperimentPopover.vue.d.ts +4 -0
  8. package/dist/components/ExperimentPopover.vue.js +138 -112
  9. package/dist/components/ExperimentPopover.vue.js.map +1 -1
  10. package/dist/components/ExperimentSelectorModal.vue.d.ts +1 -1
  11. package/dist/components/FitPanel.vue.d.ts +1 -1
  12. package/dist/components/ScientificNumber.vue.d.ts +1 -1
  13. package/dist/composables/index.d.ts +1 -0
  14. package/dist/composables/index.js +3 -0
  15. package/dist/composables/index.js.map +1 -1
  16. package/dist/composables/useAppExperiment.d.ts +34 -0
  17. package/dist/composables/useAppExperiment.js +91 -0
  18. package/dist/composables/useAppExperiment.js.map +1 -0
  19. package/dist/composables/useAuth.js +6 -1
  20. package/dist/composables/useAuth.js.map +1 -1
  21. package/dist/composables/usePlatformContext.js +68 -21
  22. package/dist/composables/usePlatformContext.js.map +1 -1
  23. package/dist/composables/useTheme.js +23 -25
  24. package/dist/composables/useTheme.js.map +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +3 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/stores/auth.d.ts +1 -1
  29. package/dist/stores/settings.d.ts +1 -1
  30. package/dist/styles.css +7029 -6880
  31. package/package.json +1 -1
  32. package/src/__stories__/experiment-helpers.ts +78 -0
  33. package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
  34. package/src/__tests__/composables/useAuth.test.ts +47 -2
  35. package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
  36. package/src/components/AppLayout.story.vue +74 -0
  37. package/src/components/AppTopBar.story.vue +29 -0
  38. package/src/components/AppTopBar.vue +38 -2
  39. package/src/components/ExperimentPopover.vue +90 -58
  40. package/src/composables/index.ts +7 -0
  41. package/src/composables/useAppExperiment.ts +143 -0
  42. package/src/composables/useAuth.ts +7 -1
  43. package/src/composables/usePlatformContext.ts +81 -25
  44. package/src/composables/useTheme.ts +33 -28
  45. package/src/index.ts +5 -0
  46. package/src/styles/components/experiment-popover.css +86 -3
@@ -1,51 +1,48 @@
1
- import { defineComponent, ref, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, withModifiers, normalizeClass, toDisplayString, createTextVNode, createCommentVNode, Fragment } from "vue";
1
+ import { defineComponent, ref, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, normalizeClass, withModifiers, toDisplayString, createCommentVNode, createTextVNode, createVNode } from "vue";
2
+ import _sfc_main$1 from "./ConfirmDialog.vue.js";
3
+ /* empty css */
2
4
  const _hoisted_1 = { class: "mld-experiment-popover__trigger-text" };
3
- const _hoisted_2 = {
5
+ const _hoisted_2 = ["disabled", "title"];
6
+ const _hoisted_3 = {
4
7
  key: 0,
5
- class: "mld-experiment-popover__panel"
6
- };
7
- const _hoisted_3 = { class: "mld-experiment-popover__header" };
8
- const _hoisted_4 = { class: "mld-experiment-popover__subtitle" };
9
- const _hoisted_5 = {
10
- key: 0,
11
- class: "mld-experiment-popover__body"
8
+ class: "mld-experiment-popover__spinner--inline"
12
9
  };
13
- const _hoisted_6 = {
10
+ const _hoisted_4 = {
14
11
  key: 1,
15
- class: "mld-experiment-popover__body"
16
- };
17
- const _hoisted_7 = { class: "mld-experiment-popover__card" };
18
- const _hoisted_8 = { class: "mld-experiment-popover__card-info" };
19
- const _hoisted_9 = { class: "mld-experiment-popover__card-name" };
20
- const _hoisted_10 = {
21
- key: 0,
22
- class: "mld-experiment-popover__card-status"
23
- };
24
- const _hoisted_11 = { class: "mld-experiment-popover__card-actions" };
25
- const _hoisted_12 = { class: "mld-experiment-popover__footer" };
26
- const _hoisted_13 = ["disabled"];
27
- const _hoisted_14 = {
28
- key: 0,
29
- class: "mld-experiment-popover__spinner"
30
- };
31
- const _hoisted_15 = {
32
- key: 1,
33
- class: "mld-experiment-popover__check-icon",
12
+ class: "mld-experiment-popover__save-trigger-icon",
34
13
  fill: "none",
35
14
  stroke: "currentColor",
36
15
  viewBox: "0 0 24 24"
37
16
  };
38
- const _hoisted_16 = {
17
+ const _hoisted_5 = {
39
18
  key: 2,
40
- class: "mld-experiment-popover__save-icon",
19
+ class: "mld-experiment-popover__save-trigger-icon",
41
20
  fill: "none",
42
21
  stroke: "currentColor",
43
22
  viewBox: "0 0 24 24"
44
23
  };
45
- const _hoisted_17 = {
24
+ const _hoisted_6 = {
46
25
  key: 0,
47
- class: "mld-experiment-popover__save-hint"
26
+ class: "mld-experiment-popover__panel"
48
27
  };
28
+ const _hoisted_7 = { class: "mld-experiment-popover__header" };
29
+ const _hoisted_8 = { class: "mld-experiment-popover__subtitle" };
30
+ const _hoisted_9 = {
31
+ key: 0,
32
+ class: "mld-experiment-popover__body"
33
+ };
34
+ const _hoisted_10 = {
35
+ key: 1,
36
+ class: "mld-experiment-popover__body"
37
+ };
38
+ const _hoisted_11 = { class: "mld-experiment-popover__card" };
39
+ const _hoisted_12 = { class: "mld-experiment-popover__card-info" };
40
+ const _hoisted_13 = { class: "mld-experiment-popover__card-name" };
41
+ const _hoisted_14 = {
42
+ key: 0,
43
+ class: "mld-experiment-popover__card-status"
44
+ };
45
+ const _hoisted_15 = { class: "mld-experiment-popover__card-actions" };
49
46
  const _sfc_main = /* @__PURE__ */ defineComponent({
50
47
  __name: "ExperimentPopover",
51
48
  props: {
@@ -56,7 +53,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
56
53
  saveDisabled: { type: Boolean, default: false },
57
54
  saveLoading: { type: Boolean, default: false },
58
55
  saveSuccessMessage: {},
59
- saveDisabledMessage: {}
56
+ saveDisabledMessage: {},
57
+ confirmSave: { type: Boolean, default: true },
58
+ confirmTitle: {},
59
+ confirmMessage: {}
60
60
  },
61
61
  emits: ["select", "save", "detach"],
62
62
  setup(__props, { emit: __emit }) {
@@ -65,6 +65,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
65
65
  const isOpen = ref(false);
66
66
  const popoverRef = ref(null);
67
67
  const showSuccess = ref(false);
68
+ const showConfirm = ref(false);
68
69
  function toggle() {
69
70
  isOpen.value = !isOpen.value;
70
71
  }
@@ -77,6 +78,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
77
78
  }
78
79
  function handleSave() {
79
80
  if (props.saveDisabled || props.saveLoading) return;
81
+ if (props.confirmSave) {
82
+ showConfirm.value = true;
83
+ } else {
84
+ emit("save");
85
+ }
86
+ }
87
+ function handleConfirmSave() {
88
+ showConfirm.value = false;
80
89
  emit("save");
81
90
  }
82
91
  function handleDetach() {
@@ -88,11 +97,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
88
97
  close();
89
98
  }
90
99
  }
100
+ let successTimer = null;
91
101
  watch(() => props.saveSuccessMessage, (msg) => {
102
+ if (successTimer) clearTimeout(successTimer);
92
103
  if (msg) {
93
104
  showSuccess.value = true;
94
- setTimeout(() => {
105
+ successTimer = setTimeout(() => {
95
106
  showSuccess.value = false;
107
+ successTimer = null;
96
108
  }, 3e3);
97
109
  }
98
110
  });
@@ -101,6 +113,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
101
113
  });
102
114
  onUnmounted(() => {
103
115
  document.removeEventListener("click", handleClickOutside);
116
+ if (successTimer) clearTimeout(successTimer);
104
117
  });
105
118
  function formatStatus(status) {
106
119
  return status.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
@@ -111,52 +124,88 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
111
124
  ref: popoverRef,
112
125
  class: "mld-experiment-popover"
113
126
  }, [
114
- createElementVNode("button", {
115
- type: "button",
127
+ createElementVNode("div", {
116
128
  class: normalizeClass([
117
- "mld-experiment-popover__trigger",
118
- { "mld-experiment-popover__trigger--active": isOpen.value },
119
- { "mld-experiment-popover__trigger--empty": !__props.experimentName }
120
- ]),
121
- onClick: withModifiers(toggle, ["stop"])
129
+ "mld-experiment-popover__split",
130
+ { "mld-experiment-popover__split--with-save": __props.showSave && __props.experimentName }
131
+ ])
122
132
  }, [
123
- _cache[0] || (_cache[0] = createElementVNode("svg", {
124
- class: "mld-experiment-popover__trigger-icon",
125
- fill: "none",
126
- stroke: "currentColor",
127
- viewBox: "0 0 24 24"
133
+ createElementVNode("button", {
134
+ type: "button",
135
+ class: normalizeClass([
136
+ "mld-experiment-popover__trigger",
137
+ { "mld-experiment-popover__trigger--active": isOpen.value },
138
+ { "mld-experiment-popover__trigger--empty": !__props.experimentName }
139
+ ]),
140
+ onClick: withModifiers(toggle, ["stop"])
128
141
  }, [
129
- createElementVNode("path", {
142
+ _cache[1] || (_cache[1] = createElementVNode("svg", {
143
+ class: "mld-experiment-popover__trigger-icon",
144
+ fill: "none",
145
+ stroke: "currentColor",
146
+ viewBox: "0 0 24 24"
147
+ }, [
148
+ createElementVNode("path", {
149
+ "stroke-linecap": "round",
150
+ "stroke-linejoin": "round",
151
+ "stroke-width": "1.75",
152
+ 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"
153
+ })
154
+ ], -1)),
155
+ createElementVNode("span", _hoisted_1, toDisplayString(__props.experimentName || "No experiment"), 1),
156
+ _cache[2] || (_cache[2] = createElementVNode("svg", {
157
+ class: "mld-experiment-popover__trigger-chevron",
158
+ viewBox: "0 0 24 24",
159
+ fill: "none",
160
+ stroke: "currentColor",
161
+ "stroke-width": "2",
130
162
  "stroke-linecap": "round",
131
- "stroke-linejoin": "round",
132
- "stroke-width": "1.75",
133
- 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"
134
- })
135
- ], -1)),
136
- createElementVNode("span", _hoisted_1, toDisplayString(__props.experimentName || "No experiment"), 1),
137
- _cache[1] || (_cache[1] = createElementVNode("svg", {
138
- class: "mld-experiment-popover__trigger-chevron",
139
- viewBox: "0 0 24 24",
140
- fill: "none",
141
- stroke: "currentColor",
142
- "stroke-width": "2",
143
- "stroke-linecap": "round",
144
- "stroke-linejoin": "round"
163
+ "stroke-linejoin": "round"
164
+ }, [
165
+ createElementVNode("path", { d: "m6 9 6 6 6-6" })
166
+ ], -1))
167
+ ], 2),
168
+ __props.showSave && __props.experimentName ? (openBlock(), createElementBlock("button", {
169
+ key: 0,
170
+ type: "button",
171
+ class: normalizeClass([
172
+ "mld-experiment-popover__save-trigger",
173
+ { "mld-experiment-popover__save-trigger--loading": __props.saveLoading },
174
+ { "mld-experiment-popover__save-trigger--success": showSuccess.value },
175
+ { "mld-experiment-popover__save-trigger--disabled": __props.saveDisabled && !showSuccess.value }
176
+ ]),
177
+ disabled: __props.saveDisabled && !showSuccess.value,
178
+ title: __props.saveDisabled && __props.saveDisabledMessage ? __props.saveDisabledMessage : showSuccess.value && __props.saveSuccessMessage ? __props.saveSuccessMessage : "Save to Experiment",
179
+ onClick: withModifiers(handleSave, ["stop"])
145
180
  }, [
146
- createElementVNode("path", { d: "m6 9 6 6 6-6" })
147
- ], -1))
181
+ __props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_3)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_4, [..._cache[3] || (_cache[3] = [
182
+ createElementVNode("path", {
183
+ "stroke-linecap": "round",
184
+ "stroke-linejoin": "round",
185
+ "stroke-width": "2.5",
186
+ d: "M5 13l4 4L19 7"
187
+ }, null, -1)
188
+ ])])) : (openBlock(), createElementBlock("svg", _hoisted_5, [..._cache[4] || (_cache[4] = [
189
+ createElementVNode("path", {
190
+ "stroke-linecap": "round",
191
+ "stroke-linejoin": "round",
192
+ "stroke-width": "2",
193
+ 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"
194
+ }, null, -1)
195
+ ])]))
196
+ ], 10, _hoisted_2)) : createCommentVNode("", true)
148
197
  ], 2),
149
- isOpen.value ? (openBlock(), createElementBlock("div", _hoisted_2, [
150
- createElementVNode("div", _hoisted_3, [
151
- _cache[2] || (_cache[2] = createElementVNode("div", { class: "mld-experiment-popover__title" }, "Experiment", -1)),
152
- createElementVNode("div", _hoisted_4, toDisplayString(__props.experimentName ? "Linked experiment context" : "Link to an MLD experiment"), 1)
198
+ isOpen.value ? (openBlock(), createElementBlock("div", _hoisted_6, [
199
+ createElementVNode("div", _hoisted_7, [
200
+ _cache[5] || (_cache[5] = createElementVNode("div", { class: "mld-experiment-popover__title" }, "Experiment", -1)),
201
+ createElementVNode("div", _hoisted_8, toDisplayString(__props.experimentName ? "Linked experiment context" : "Link to an MLD experiment"), 1)
153
202
  ]),
154
- !__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_5, [
203
+ !__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_9, [
155
204
  createElementVNode("button", {
156
205
  type: "button",
157
206
  class: "mld-experiment-popover__select-btn",
158
207
  onClick: handleSelect
159
- }, [..._cache[3] || (_cache[3] = [
208
+ }, [..._cache[6] || (_cache[6] = [
160
209
  createElementVNode("svg", {
161
210
  width: "14",
162
211
  height: "14",
@@ -173,9 +222,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
173
222
  ], -1),
174
223
  createTextVNode(" Select Experiment ", -1)
175
224
  ])])
176
- ])) : (openBlock(), createElementBlock("div", _hoisted_6, [
177
- createElementVNode("div", _hoisted_7, [
178
- _cache[4] || (_cache[4] = createElementVNode("div", { class: "mld-experiment-popover__card-icon" }, [
225
+ ])) : (openBlock(), createElementBlock("div", _hoisted_10, [
226
+ createElementVNode("div", _hoisted_11, [
227
+ _cache[7] || (_cache[7] = createElementVNode("div", { class: "mld-experiment-popover__card-icon" }, [
179
228
  createElementVNode("svg", {
180
229
  fill: "none",
181
230
  stroke: "currentColor",
@@ -189,11 +238,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
189
238
  })
190
239
  ])
191
240
  ], -1)),
192
- createElementVNode("div", _hoisted_8, [
193
- createElementVNode("div", _hoisted_9, toDisplayString(__props.experimentName), 1),
194
- __props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_10, toDisplayString(formatStatus(__props.experimentStatus)), 1)) : createCommentVNode("", true)
241
+ createElementVNode("div", _hoisted_12, [
242
+ createElementVNode("div", _hoisted_13, toDisplayString(__props.experimentName), 1),
243
+ __props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_14, toDisplayString(formatStatus(__props.experimentStatus)), 1)) : createCommentVNode("", true)
195
244
  ]),
196
- createElementVNode("div", _hoisted_11, [
245
+ createElementVNode("div", _hoisted_15, [
197
246
  createElementVNode("button", {
198
247
  type: "button",
199
248
  class: "mld-experiment-popover__change-btn",
@@ -207,41 +256,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
207
256
  }, " Detach ")) : createCommentVNode("", true)
208
257
  ])
209
258
  ])
210
- ])),
211
- __props.showSave ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
212
- _cache[7] || (_cache[7] = createElementVNode("div", { class: "mld-experiment-popover__divider" }, null, -1)),
213
- createElementVNode("div", _hoisted_12, [
214
- createElementVNode("button", {
215
- type: "button",
216
- class: normalizeClass([
217
- "mld-experiment-popover__save-btn",
218
- { "mld-experiment-popover__save-btn--loading": __props.saveLoading },
219
- { "mld-experiment-popover__save-btn--success": showSuccess.value }
220
- ]),
221
- disabled: __props.saveDisabled && !showSuccess.value,
222
- onClick: handleSave
223
- }, [
224
- __props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_14)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_15, [..._cache[5] || (_cache[5] = [
225
- createElementVNode("path", {
226
- "stroke-linecap": "round",
227
- "stroke-linejoin": "round",
228
- "stroke-width": "2",
229
- d: "M5 13l4 4L19 7"
230
- }, null, -1)
231
- ])])) : (openBlock(), createElementBlock("svg", _hoisted_16, [..._cache[6] || (_cache[6] = [
232
- createElementVNode("path", {
233
- "stroke-linecap": "round",
234
- "stroke-linejoin": "round",
235
- "stroke-width": "2",
236
- 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"
237
- }, null, -1)
238
- ])])),
239
- createElementVNode("span", null, toDisplayString(showSuccess.value && __props.saveSuccessMessage ? __props.saveSuccessMessage : "Save to Experiment"), 1)
240
- ], 10, _hoisted_13),
241
- __props.saveDisabled && __props.saveDisabledMessage && !showSuccess.value ? (openBlock(), createElementBlock("div", _hoisted_17, toDisplayString(__props.saveDisabledMessage), 1)) : createCommentVNode("", true)
242
- ])
243
- ], 64)) : createCommentVNode("", true)
244
- ])) : createCommentVNode("", true)
259
+ ]))
260
+ ])) : createCommentVNode("", true),
261
+ createVNode(_sfc_main$1, {
262
+ modelValue: showConfirm.value,
263
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => showConfirm.value = $event),
264
+ title: __props.confirmTitle ?? "Save to Experiment",
265
+ message: __props.confirmMessage ?? `Save current data to ${__props.experimentName}?`,
266
+ variant: "info",
267
+ "confirm-label": "Save",
268
+ loading: __props.saveLoading,
269
+ onConfirm: handleConfirmSave
270
+ }, null, 8, ["modelValue", "title", "message", "loading"])
245
271
  ], 512);
246
272
  };
247
273
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExperimentPopover.vue.js","sources":["../../src/components/ExperimentPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n experimentName?: string\n experimentStatus?: string\n showSave?: boolean\n showDetach?: boolean\n saveDisabled?: boolean\n saveLoading?: boolean\n saveSuccessMessage?: string\n saveDisabledMessage?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showSave: false,\n showDetach: false,\n saveDisabled: false,\n saveLoading: false,\n})\n\nconst emit = defineEmits<{\n select: []\n save: []\n detach: []\n}>()\n\nconst isOpen = ref(false)\nconst popoverRef = ref<HTMLElement | null>(null)\nconst showSuccess = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleSelect() {\n emit('select')\n close()\n}\n\nfunction handleSave() {\n if (props.saveDisabled || props.saveLoading) return\n emit('save')\n}\n\nfunction handleDetach() {\n emit('detach')\n close()\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n if (popoverRef.value && !popoverRef.value.contains(event.target as Node)) {\n close()\n }\n}\n\n// Show success state when saveSuccessMessage changes from empty to a value\nwatch(() => props.saveSuccessMessage, (msg) => {\n if (msg) {\n showSuccess.value = true\n setTimeout(() => {\n showSuccess.value = false\n }, 3000)\n }\n})\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n\n// Format status for display (e.g., \"ready_to_extract\" -> \"Ready to extract\")\nfunction formatStatus(status: string): string {\n return status.replace(/_/g, ' ').replace(/^\\w/, c => c.toUpperCase())\n}\n</script>\n\n<template>\n <div ref=\"popoverRef\" class=\"mld-experiment-popover\">\n <!-- Trigger button -->\n <button\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__trigger',\n { 'mld-experiment-popover__trigger--active': isOpen },\n { 'mld-experiment-popover__trigger--empty': !experimentName },\n ]\"\n @click.stop=\"toggle\"\n >\n <!-- Flask icon -->\n <svg class=\"mld-experiment-popover__trigger-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n 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\"\n />\n </svg>\n <span class=\"mld-experiment-popover__trigger-text\">\n {{ experimentName || 'No experiment' }}\n </span>\n <!-- Chevron -->\n <svg class=\"mld-experiment-popover__trigger-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Popover panel -->\n <div v-if=\"isOpen\" class=\"mld-experiment-popover__panel\">\n <!-- Header -->\n <div class=\"mld-experiment-popover__header\">\n <div class=\"mld-experiment-popover__title\">Experiment</div>\n <div class=\"mld-experiment-popover__subtitle\">\n {{ experimentName ? 'Linked experiment context' : 'Link to an MLD experiment' }}\n </div>\n </div>\n\n <!-- No experiment selected -->\n <div v-if=\"!experimentName\" class=\"mld-experiment-popover__body\">\n <button type=\"button\" class=\"mld-experiment-popover__select-btn\" @click=\"handleSelect\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n Select Experiment\n </button>\n </div>\n\n <!-- Experiment selected -->\n <div v-else class=\"mld-experiment-popover__body\">\n <div class=\"mld-experiment-popover__card\">\n <div class=\"mld-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n 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\"\n />\n </svg>\n </div>\n <div class=\"mld-experiment-popover__card-info\">\n <div class=\"mld-experiment-popover__card-name\">{{ experimentName }}</div>\n <div v-if=\"experimentStatus\" class=\"mld-experiment-popover__card-status\">\n {{ formatStatus(experimentStatus) }}\n </div>\n </div>\n <div class=\"mld-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mld-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mld-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n </div>\n\n <!-- Save section -->\n <template v-if=\"showSave\">\n <div class=\"mld-experiment-popover__divider\" />\n <div class=\"mld-experiment-popover__footer\">\n <button\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__save-btn',\n { 'mld-experiment-popover__save-btn--loading': saveLoading },\n { 'mld-experiment-popover__save-btn--success': showSuccess },\n ]\"\n :disabled=\"saveDisabled && !showSuccess\"\n @click=\"handleSave\"\n >\n <!-- Loading spinner -->\n <span v-if=\"saveLoading\" class=\"mld-experiment-popover__spinner\" />\n <!-- Success check -->\n <svg v-else-if=\"showSuccess\" class=\"mld-experiment-popover__check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <!-- Save icon -->\n <svg v-else class=\"mld-experiment-popover__save-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n <!-- Label -->\n <span>{{ showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment' }}</span>\n </button>\n <div v-if=\"saveDisabled && saveDisabledMessage && !showSuccess\" class=\"mld-experiment-popover__save-hint\">\n {{ saveDisabledMessage }}\n </div>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/experiment-popover.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeClass","_toDisplayString","_openBlock","_Fragment"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,UAAM,QAAQ;AAOd,UAAM,OAAO;AAMb,UAAM,SAAS,IAAI,KAAK;AACxB,UAAM,aAAa,IAAwB,IAAI;AAC/C,UAAM,cAAc,IAAI,KAAK;AAE7B,aAAS,SAAS;AAChB,aAAO,QAAQ,CAAC,OAAO;AAAA,IACzB;AAEA,aAAS,QAAQ;AACf,aAAO,QAAQ;AAAA,IACjB;AAEA,aAAS,eAAe;AACtB,WAAK,QAAQ;AACb,YAAA;AAAA,IACF;AAEA,aAAS,aAAa;AACpB,UAAI,MAAM,gBAAgB,MAAM,YAAa;AAC7C,WAAK,MAAM;AAAA,IACb;AAEA,aAAS,eAAe;AACtB,WAAK,QAAQ;AACb,YAAA;AAAA,IACF;AAEA,aAAS,mBAAmB,OAAmB;AAC7C,UAAI,WAAW,SAAS,CAAC,WAAW,MAAM,SAAS,MAAM,MAAc,GAAG;AACxE,cAAA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,MAAM,MAAM,oBAAoB,CAAC,QAAQ;AAC7C,UAAI,KAAK;AACP,oBAAY,QAAQ;AACpB,mBAAW,MAAM;AACf,sBAAY,QAAQ;AAAA,QACtB,GAAG,GAAI;AAAA,MACT;AAAA,IACF,CAAC;AAED,cAAU,MAAM;AACd,eAAS,iBAAiB,SAAS,kBAAkB;AAAA,IACvD,CAAC;AAED,gBAAY,MAAM;AAChB,eAAS,oBAAoB,SAAS,kBAAkB;AAAA,IAC1D,CAAC;AAGD,aAAS,aAAa,QAAwB;AAC5C,aAAO,OAAO,QAAQ,MAAM,GAAG,EAAE,QAAQ,OAAO,CAAA,MAAK,EAAE,YAAA,CAAa;AAAA,IACtE;;0BAIEA,mBAgHM,OAAA;AAAA,iBAhHG;AAAA,QAAJ,KAAI;AAAA,QAAa,OAAM;AAAA,MAAA;QAE1BC,mBAyBS,UAAA;AAAA,UAxBP,MAAK;AAAA,UACJ,OAAKC,eAAA;AAAA;yDAAoG,OAAA,MAAA;AAAA,yDAA+D,QAAA,eAAA;AAAA,UAAc;UAKtL,uBAAY,QAAM,CAAA,MAAA,CAAA;AAAA,QAAA;oCAGnBD,mBAOM,OAAA;AAAA,YAPD,OAAM;AAAA,YAAuC,MAAK;AAAA,YAAO,QAAO;AAAA,YAAe,SAAQ;AAAA,UAAA;YAC1FA,mBAKE,QAAA;AAAA,cAJA,kBAAe;AAAA,cACf,mBAAgB;AAAA,cAChB,gBAAa;AAAA,cACb,GAAE;AAAA,YAAA;;UAGNA,mBAEO,QAFP,YAEOE,gBADF,QAAA,kBAAc,eAAA,GAAA,CAAA;AAAA,oCAGnBF,mBAEM,OAAA;AAAA,YAFD,OAAM;AAAA,YAA0C,SAAQ;AAAA,YAAY,MAAK;AAAA,YAAO,QAAO;AAAA,YAAe,gBAAa;AAAA,YAAI,kBAAe;AAAA,YAAQ,mBAAgB;AAAA,UAAA;YACjKA,mBAAyB,QAAA,EAAnB,GAAE,gBAAc;AAAA,UAAA;;QAKf,OAAA,SAAXG,UAAA,GAAAJ,mBAiFM,OAjFN,YAiFM;AAAA,UA/EJC,mBAKM,OALN,YAKM;AAAA,YAJJ,OAAA,CAAA,MAAA,OAAA,CAAA,IAAAA,mBAA2D,OAAA,EAAtD,OAAM,gCAAA,GAAgC,cAAU,EAAA;AAAA,YACrDA,mBAEM,OAFN,YAEME,gBADD,QAAA,iBAAc,8BAAA,2BAAA,GAAA,CAAA;AAAA,UAAA;WAKT,QAAA,kBAAZC,aAAAJ,mBAOM,OAPN,YAOM;AAAA,YANJC,mBAKS,UAAA;AAAA,cALD,MAAK;AAAA,cAAS,OAAM;AAAA,cAAsC,SAAO;AAAA,YAAA;cACvEA,mBAEM,OAAA;AAAA,gBAFD,OAAM;AAAA,gBAAK,QAAO;AAAA,gBAAK,MAAK;AAAA,gBAAO,QAAO;AAAA,gBAAe,SAAQ;AAAA,cAAA;gBACpEA,mBAA2F,QAAA;AAAA,kBAArF,kBAAe;AAAA,kBAAQ,mBAAgB;AAAA,kBAAQ,gBAAa;AAAA,kBAAI,GAAE;AAAA,gBAAA;;8BACpE,uBAER,EAAA;AAAA,YAAA;iBAIFG,UAAA,GAAAJ,mBA2BM,OA3BN,YA2BM;AAAA,YA1BJC,mBAyBM,OAzBN,YAyBM;AAAA,wCAxBJA,mBASM,OAAA,EATD,OAAM,uCAAmC;AAAA,gBAC5CA,mBAOM,OAAA;AAAA,kBAPD,MAAK;AAAA,kBAAO,QAAO;AAAA,kBAAe,SAAQ;AAAA,gBAAA;kBAC7CA,mBAKE,QAAA;AAAA,oBAJA,kBAAe;AAAA,oBACf,mBAAgB;AAAA,oBAChB,gBAAa;AAAA,oBACb,GAAE;AAAA,kBAAA;;;cAIRA,mBAKM,OALN,YAKM;AAAA,gBAJJA,mBAAyE,OAAzE,YAAyEE,gBAAvB,QAAA,cAAc,GAAA,CAAA;AAAA,gBACrD,QAAA,oBAAXC,UAAA,GAAAJ,mBAEM,OAFN,aAEMG,gBADD,aAAa,QAAA,gBAAgB,CAAA,GAAA,CAAA;;cAGpCF,mBAOM,OAPN,aAOM;AAAA,gBANJA,mBAES,UAAA;AAAA,kBAFD,MAAK;AAAA,kBAAS,OAAM;AAAA,kBAAsC,SAAO;AAAA,gBAAA,GAAc,UAEvF;AAAA,gBACc,QAAA,2BAAdD,mBAES,UAAA;AAAA;kBAFiB,MAAK;AAAA,kBAAS,OAAM;AAAA,kBAAsC,SAAO;AAAA,gBAAA,GAAc,UAEzG;;;;UAMU,QAAA,yBAAhBA,mBA8BWK,UAAA,EAAA,KAAA,KAAA;AAAA,sCA7BTJ,mBAA+C,OAAA,EAA1C,OAAM,kCAAA,GAAiC,MAAA,EAAA;AAAA,YAC5CA,mBA2BM,OA3BN,aA2BM;AAAA,cA1BJA,mBAsBS,UAAA;AAAA,gBArBP,MAAK;AAAA,gBACJ,OAAKC,eAAA;AAAA;iEAAmH,QAAA,YAAA;AAAA,iEAA4E,YAAA,MAAA;AAAA,gBAAW;gBAK/M,UAAU,QAAA,gBAAY,CAAK,YAAA;AAAA,gBAC3B,SAAO;AAAA,cAAA;gBAGI,QAAA,eAAZE,aAAAJ,mBAAmE,QAAnE,WAAmE,KAEnD,YAAA,SAAhBI,UAAA,GAAAJ,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA;AAAA,kBADJC,mBAA2F,QAAA;AAAA,oBAArF,kBAAe;AAAA,oBAAQ,mBAAgB;AAAA,oBAAQ,gBAAa;AAAA,oBAAI,GAAE;AAAA,kBAAA;yBAG1EG,aAAAJ,mBAEM,OAFN,aAEM,CAAA,GAAA,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA;AAAA,kBADJC,mBAAwK,QAAA;AAAA,oBAAlK,kBAAe;AAAA,oBAAQ,mBAAgB;AAAA,oBAAQ,gBAAa;AAAA,oBAAI,GAAE;AAAA,kBAAA;;gBAG1EA,mBAAgG,QAAA,MAAAE,gBAAvF,YAAA,SAAe,QAAA,qBAAqB,QAAA,qBAAkB,oBAAA,GAAA,CAAA;AAAA,cAAA;cAEtD,QAAA,gBAAgB,QAAA,uBAAmB,CAAK,YAAA,sBAAnDH,mBAEM,OAFN,aAEMG,gBADD,QAAA,mBAAmB,GAAA,CAAA;;;;;;;;"}
1
+ {"version":3,"file":"ExperimentPopover.vue.js","sources":["../../src/components/ExperimentPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onUnmounted } from 'vue'\nimport ConfirmDialog from './ConfirmDialog.vue'\n\ninterface Props {\n experimentName?: string\n experimentStatus?: string\n showSave?: boolean\n showDetach?: boolean\n saveDisabled?: boolean\n saveLoading?: boolean\n saveSuccessMessage?: string\n saveDisabledMessage?: string\n confirmSave?: boolean\n confirmTitle?: string\n confirmMessage?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showSave: false,\n showDetach: false,\n saveDisabled: false,\n saveLoading: false,\n confirmSave: true,\n})\n\nconst emit = defineEmits<{\n select: []\n save: []\n detach: []\n}>()\n\nconst isOpen = ref(false)\nconst popoverRef = ref<HTMLElement | null>(null)\nconst showSuccess = ref(false)\nconst showConfirm = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleSelect() {\n emit('select')\n close()\n}\n\nfunction handleSave() {\n if (props.saveDisabled || props.saveLoading) return\n if (props.confirmSave) {\n showConfirm.value = true\n } else {\n emit('save')\n }\n}\n\nfunction handleConfirmSave() {\n showConfirm.value = false\n emit('save')\n}\n\nfunction handleDetach() {\n emit('detach')\n close()\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n if (popoverRef.value && !popoverRef.value.contains(event.target as Node)) {\n close()\n }\n}\n\nlet successTimer: ReturnType<typeof setTimeout> | null = null\n\n// Show success state when saveSuccessMessage changes from empty to a value\nwatch(() => props.saveSuccessMessage, (msg) => {\n if (successTimer) clearTimeout(successTimer)\n if (msg) {\n showSuccess.value = true\n successTimer = setTimeout(() => {\n showSuccess.value = false\n successTimer = null\n }, 3000)\n }\n})\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n if (successTimer) clearTimeout(successTimer)\n})\n\n// Format status for display (e.g., \"ready_to_extract\" -> \"Ready to extract\")\nfunction formatStatus(status: string): string {\n return status.replace(/_/g, ' ').replace(/^\\w/, c => c.toUpperCase())\n}\n</script>\n\n<template>\n <div ref=\"popoverRef\" class=\"mld-experiment-popover\">\n <!-- Split trigger: experiment pill + inline save -->\n <div\n :class=\"[\n 'mld-experiment-popover__split',\n { 'mld-experiment-popover__split--with-save': showSave && experimentName },\n ]\"\n >\n <!-- Left: experiment trigger (opens popover) -->\n <button\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__trigger',\n { 'mld-experiment-popover__trigger--active': isOpen },\n { 'mld-experiment-popover__trigger--empty': !experimentName },\n ]\"\n @click.stop=\"toggle\"\n >\n <!-- Flask icon -->\n <svg class=\"mld-experiment-popover__trigger-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n 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\"\n />\n </svg>\n <span class=\"mld-experiment-popover__trigger-text\">\n {{ experimentName || 'No experiment' }}\n </span>\n <!-- Chevron -->\n <svg class=\"mld-experiment-popover__trigger-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Right: inline save button (direct action) -->\n <button\n v-if=\"showSave && experimentName\"\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__save-trigger',\n { 'mld-experiment-popover__save-trigger--loading': saveLoading },\n { 'mld-experiment-popover__save-trigger--success': showSuccess },\n { 'mld-experiment-popover__save-trigger--disabled': saveDisabled && !showSuccess },\n ]\"\n :disabled=\"saveDisabled && !showSuccess\"\n :title=\"saveDisabled && saveDisabledMessage ? saveDisabledMessage : showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment'\"\n @click.stop=\"handleSave\"\n >\n <!-- Loading spinner -->\n <span v-if=\"saveLoading\" class=\"mld-experiment-popover__spinner--inline\" />\n <!-- Success check -->\n <svg v-else-if=\"showSuccess\" class=\"mld-experiment-popover__save-trigger-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.5\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <!-- Save icon -->\n <svg v-else class=\"mld-experiment-popover__save-trigger-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n </button>\n </div>\n\n <!-- Popover panel -->\n <div v-if=\"isOpen\" class=\"mld-experiment-popover__panel\">\n <!-- Header -->\n <div class=\"mld-experiment-popover__header\">\n <div class=\"mld-experiment-popover__title\">Experiment</div>\n <div class=\"mld-experiment-popover__subtitle\">\n {{ experimentName ? 'Linked experiment context' : 'Link to an MLD experiment' }}\n </div>\n </div>\n\n <!-- No experiment selected -->\n <div v-if=\"!experimentName\" class=\"mld-experiment-popover__body\">\n <button type=\"button\" class=\"mld-experiment-popover__select-btn\" @click=\"handleSelect\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n Select Experiment\n </button>\n </div>\n\n <!-- Experiment selected -->\n <div v-else class=\"mld-experiment-popover__body\">\n <div class=\"mld-experiment-popover__card\">\n <div class=\"mld-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n 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\"\n />\n </svg>\n </div>\n <div class=\"mld-experiment-popover__card-info\">\n <div class=\"mld-experiment-popover__card-name\">{{ experimentName }}</div>\n <div v-if=\"experimentStatus\" class=\"mld-experiment-popover__card-status\">\n {{ formatStatus(experimentStatus) }}\n </div>\n </div>\n <div class=\"mld-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mld-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mld-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Save confirmation dialog -->\n <ConfirmDialog\n v-model=\"showConfirm\"\n :title=\"confirmTitle ?? 'Save to Experiment'\"\n :message=\"confirmMessage ?? `Save current data to ${experimentName}?`\"\n variant=\"info\"\n confirm-label=\"Save\"\n :loading=\"saveLoading\"\n @confirm=\"handleConfirmSave\"\n />\n </div>\n</template>\n\n<style>\n@import '../styles/components/experiment-popover.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeClass","_toDisplayString","_openBlock","_createVNode","ConfirmDialog"],"mappings":"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"}
@@ -19,9 +19,9 @@ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, imp
19
19
  }>, {
20
20
  size: ModalSize;
21
21
  title: string;
22
- showFilters: boolean;
23
22
  currentExperimentId: number | null;
24
23
  groupByProject: boolean;
24
+ showFilters: boolean;
25
25
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
26
26
  listRef: HTMLDivElement;
27
27
  }, any>;
@@ -32,8 +32,8 @@ declare const __VLS_component: import('vue').DefineComponent<Props, {}, {}, {},
32
32
  progress: number;
33
33
  indeterminate: boolean;
34
34
  state: FitState;
35
- results: FitResultSummary[];
36
35
  cancelLabel: string;
36
+ results: FitResultSummary[];
37
37
  progressLabel: string;
38
38
  runLabel: string;
39
39
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
@@ -7,8 +7,8 @@ interface Props {
7
7
  copyable?: boolean;
8
8
  }
9
9
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
10
+ copyable: boolean;
10
11
  precision: number;
11
12
  notation: NumberNotation;
12
- copyable: boolean;
13
13
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLSpanElement>;
14
14
  export default _default;
@@ -22,3 +22,4 @@ export { useExperimentSelector, type UseExperimentSelectorOptions, type UseExper
22
22
  export { formatExperimentDate, datePresetToISO, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, EXPERIMENT_STATUS_LABELS, DATE_PRESET_OPTIONS, SORT_OPTIONS, } from './experiment-utils';
23
23
  export { useExperimentData, type UseExperimentDataOptions, type UseExperimentDataReturn, } from './useExperimentData';
24
24
  export { getFieldRegistryEntry, getTypeDefault, type RegistryEntry, } from './formBuilderRegistry';
25
+ export { useAppExperiment, APP_EXPERIMENT_KEY, type UseAppExperimentOptions, type UseAppExperimentReturn, type AppExperimentState, } from './useAppExperiment';
@@ -22,7 +22,9 @@ import { useExperimentSelector } from "./useExperimentSelector.js";
22
22
  import { DATE_PRESET_OPTIONS, EXPERIMENT_STATUS_LABELS, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, SORT_OPTIONS, datePresetToISO, formatExperimentDate } from "./experiment-utils.js";
23
23
  import { useExperimentData } from "./useExperimentData.js";
24
24
  import { getFieldRegistryEntry, getTypeDefault } from "./formBuilderRegistry.js";
25
+ import { APP_EXPERIMENT_KEY, useAppExperiment } from "./useAppExperiment.js";
25
26
  export {
27
+ APP_EXPERIMENT_KEY,
26
28
  ATOMIC_WEIGHTS,
27
29
  DATE_PRESET_OPTIONS,
28
30
  DEFAULT_COLORS,
@@ -47,6 +49,7 @@ export {
47
49
  rangesOverlap,
48
50
  snapToSlot,
49
51
  useApi,
52
+ useAppExperiment,
50
53
  useAsync,
51
54
  useAsyncBatch,
52
55
  useAuth,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,34 @@
1
+ import { Ref, ComputedRef, InjectionKey } from 'vue';
2
+ import { ExperimentSummary, ExperimentStatus } from '../types';
3
+ export interface UseAppExperimentOptions {
4
+ onSelect?: (experiment: ExperimentSummary) => void | Promise<void>;
5
+ onSave?: () => string | null | Promise<string | null>;
6
+ onDetach?: () => void;
7
+ saveDisabled?: Ref<boolean> | ComputedRef<boolean>;
8
+ saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>;
9
+ }
10
+ export interface UseAppExperimentReturn {
11
+ set: (experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) => void;
12
+ clear: () => void;
13
+ experimentName: Readonly<Ref<string | undefined>>;
14
+ experimentId: Readonly<Ref<number | null>>;
15
+ }
16
+ export interface AppExperimentState {
17
+ experimentName: Ref<string | undefined>;
18
+ experimentStatus: Ref<ExperimentStatus | undefined>;
19
+ experimentId: Ref<number | null>;
20
+ showModal: Ref<boolean>;
21
+ saveLoading: Ref<boolean>;
22
+ saveSuccessMessage: Ref<string | undefined>;
23
+ showSave: Ref<boolean>;
24
+ showDetach: ComputedRef<boolean>;
25
+ closeModal: () => void;
26
+ saveDisabled: ComputedRef<boolean>;
27
+ saveDisabledMessage: ComputedRef<string | undefined>;
28
+ openModal: () => void;
29
+ handleSelect: (experiment: ExperimentSummary) => void;
30
+ handleSave: () => Promise<void>;
31
+ handleDetach: () => void;
32
+ }
33
+ export declare const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState>;
34
+ export declare function useAppExperiment(options?: UseAppExperimentOptions): UseAppExperimentReturn;
@@ -0,0 +1,91 @@
1
+ import { ref, computed, toValue, onScopeDispose, provide, readonly } from "vue";
2
+ const APP_EXPERIMENT_KEY = Symbol("app-experiment");
3
+ function useAppExperiment(options = {}) {
4
+ const experimentName = ref();
5
+ const experimentStatus = ref();
6
+ const experimentId = ref(null);
7
+ const showModal = ref(false);
8
+ const saveLoading = ref(false);
9
+ const saveSuccessMessage = ref();
10
+ let successTimer = null;
11
+ const showSave = ref(!!options.onSave);
12
+ const showDetach = computed(() => experimentId.value !== null);
13
+ const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false);
14
+ const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage));
15
+ function set(experiment) {
16
+ experimentId.value = experiment.id;
17
+ experimentName.value = experiment.name;
18
+ experimentStatus.value = experiment.status;
19
+ }
20
+ function clear() {
21
+ experimentId.value = null;
22
+ experimentName.value = void 0;
23
+ experimentStatus.value = void 0;
24
+ }
25
+ function openModal() {
26
+ showModal.value = true;
27
+ }
28
+ function closeModal() {
29
+ showModal.value = false;
30
+ }
31
+ function handleSelect(experiment) {
32
+ var _a;
33
+ set(experiment);
34
+ showModal.value = false;
35
+ (_a = options.onSelect) == null ? void 0 : _a.call(options, experiment);
36
+ }
37
+ async function handleSave() {
38
+ if (!options.onSave || saveLoading.value) return;
39
+ saveLoading.value = true;
40
+ try {
41
+ const message = await options.onSave();
42
+ if (message) {
43
+ saveSuccessMessage.value = message;
44
+ if (successTimer) clearTimeout(successTimer);
45
+ successTimer = setTimeout(() => {
46
+ saveSuccessMessage.value = void 0;
47
+ successTimer = null;
48
+ }, 3e3);
49
+ }
50
+ } finally {
51
+ saveLoading.value = false;
52
+ }
53
+ }
54
+ function handleDetach() {
55
+ var _a;
56
+ clear();
57
+ (_a = options.onDetach) == null ? void 0 : _a.call(options);
58
+ }
59
+ onScopeDispose(() => {
60
+ if (successTimer) clearTimeout(successTimer);
61
+ });
62
+ const state = {
63
+ experimentName,
64
+ experimentStatus,
65
+ experimentId,
66
+ showModal,
67
+ saveLoading,
68
+ saveSuccessMessage,
69
+ showSave,
70
+ showDetach,
71
+ saveDisabled,
72
+ saveDisabledMessage,
73
+ openModal,
74
+ closeModal,
75
+ handleSelect,
76
+ handleSave,
77
+ handleDetach
78
+ };
79
+ provide(APP_EXPERIMENT_KEY, state);
80
+ return {
81
+ set,
82
+ clear,
83
+ experimentName: readonly(experimentName),
84
+ experimentId: readonly(experimentId)
85
+ };
86
+ }
87
+ export {
88
+ APP_EXPERIMENT_KEY,
89
+ useAppExperiment
90
+ };
91
+ //# sourceMappingURL=useAppExperiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAppExperiment.js","sources":["../../src/composables/useAppExperiment.ts"],"sourcesContent":["import {\n ref,\n computed,\n readonly,\n provide,\n toValue,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\n\nexport interface UseAppExperimentOptions {\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n}\n\nexport interface UseAppExperimentReturn {\n set: (experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) => void\n clear: () => void\n experimentName: Readonly<Ref<string | undefined>>\n experimentId: Readonly<Ref<number | null>>\n}\n\nexport interface AppExperimentState {\n experimentName: Ref<string | undefined>\n experimentStatus: Ref<ExperimentStatus | undefined>\n experimentId: Ref<number | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n openModal: () => void\n handleSelect: (experiment: ExperimentSummary) => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const experimentName = ref<string | undefined>()\n const experimentStatus = ref<ExperimentStatus | undefined>()\n const experimentId = ref<number | null>(null)\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n\n function set(experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) {\n experimentId.value = experiment.id\n experimentName.value = experiment.name\n experimentStatus.value = experiment.status\n }\n\n function clear() {\n experimentId.value = null\n experimentName.value = undefined\n experimentStatus.value = undefined\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n function handleSelect(experiment: ExperimentSummary) {\n set(experiment)\n showModal.value = false\n options.onSelect?.(experiment)\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentStatus,\n experimentId,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n openModal,\n closeModal,\n handleSelect,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n set,\n clear,\n experimentName: readonly(experimentName),\n experimentId: readonly(experimentId),\n }\n}\n"],"names":[],"mappings":";AA8CO,MAAM,qBAAuD,OAAO,gBAAgB;AAEpF,SAAS,iBAAiB,UAAmC,IAA4B;AAC9F,QAAM,iBAAiB,IAAA;AACvB,QAAM,mBAAmB,IAAA;AACzB,QAAM,eAAe,IAAmB,IAAI;AAC5C,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,cAAc,IAAI,KAAK;AAC7B,QAAM,qBAAqB,IAAA;AAE3B,MAAI,eAAqD;AAEzD,QAAM,WAAW,IAAI,CAAC,CAAC,QAAQ,MAAM;AACrC,QAAM,aAAa,SAAS,MAAM,aAAa,UAAU,IAAI;AAC7D,QAAM,eAAe,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK,KAAK;AAC1E,QAAM,sBAAsB,SAAS,MAAM,QAAQ,QAAQ,mBAAmB,CAAC;AAE/E,WAAS,IAAI,YAA+D;AAC1E,iBAAa,QAAQ,WAAW;AAChC,mBAAe,QAAQ,WAAW;AAClC,qBAAiB,QAAQ,WAAW;AAAA,EACtC;AAEA,WAAS,QAAQ;AACf,iBAAa,QAAQ;AACrB,mBAAe,QAAQ;AACvB,qBAAiB,QAAQ;AAAA,EAC3B;AAEA,WAAS,YAAY;AACnB,cAAU,QAAQ;AAAA,EACpB;AAEA,WAAS,aAAa;AACpB,cAAU,QAAQ;AAAA,EACpB;AAEA,WAAS,aAAa,YAA+B;;AACnD,QAAI,UAAU;AACd,cAAU,QAAQ;AAClB,kBAAQ,aAAR,iCAAmB;AAAA,EACrB;AAEA,iBAAe,aAAa;AAC1B,QAAI,CAAC,QAAQ,UAAU,YAAY,MAAO;AAC1C,gBAAY,QAAQ;AACpB,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,OAAA;AAC9B,UAAI,SAAS;AACX,2BAAmB,QAAQ;AAC3B,YAAI,2BAA2B,YAAY;AAC3C,uBAAe,WAAW,MAAM;AAC9B,6BAAmB,QAAQ;AAC3B,yBAAe;AAAA,QACjB,GAAG,GAAI;AAAA,MACT;AAAA,IACF,UAAA;AACE,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF;AAEA,WAAS,eAAe;;AACtB,UAAA;AACA,kBAAQ,aAAR;AAAA,EACF;AAEA,iBAAe,MAAM;AACnB,QAAI,2BAA2B,YAAY;AAAA,EAC7C,CAAC;AAED,QAAM,QAA4B;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,UAAQ,oBAAoB,KAAK;AAEjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,gBAAgB,SAAS,cAAc;AAAA,IACvC,cAAc,SAAS,YAAY;AAAA,EAAA;AAEvC;"}