@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.
- package/dist/__stories__/experiment-helpers.d.ts +25 -0
- package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
- package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
- package/dist/components/AppTopBar.vue.js +61 -28
- package/dist/components/AppTopBar.vue.js.map +1 -1
- package/dist/components/AuditTrail.vue.d.ts +1 -1
- package/dist/components/ExperimentPopover.vue.d.ts +4 -0
- package/dist/components/ExperimentPopover.vue.js +138 -112
- package/dist/components/ExperimentPopover.vue.js.map +1 -1
- package/dist/components/ExperimentSelectorModal.vue.d.ts +1 -1
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/ScientificNumber.vue.d.ts +1 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +3 -0
- package/dist/composables/index.js.map +1 -1
- package/dist/composables/useAppExperiment.d.ts +34 -0
- package/dist/composables/useAppExperiment.js +91 -0
- package/dist/composables/useAppExperiment.js.map +1 -0
- package/dist/composables/useAuth.js +6 -1
- package/dist/composables/useAuth.js.map +1 -1
- package/dist/composables/usePlatformContext.js +68 -21
- package/dist/composables/usePlatformContext.js.map +1 -1
- package/dist/composables/useTheme.js +23 -25
- package/dist/composables/useTheme.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/stores/auth.d.ts +1 -1
- package/dist/stores/settings.d.ts +1 -1
- package/dist/styles.css +7029 -6880
- package/package.json +1 -1
- package/src/__stories__/experiment-helpers.ts +78 -0
- package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
- package/src/__tests__/composables/useAuth.test.ts +47 -2
- package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
- package/src/components/AppLayout.story.vue +74 -0
- package/src/components/AppTopBar.story.vue +29 -0
- package/src/components/AppTopBar.vue +38 -2
- package/src/components/ExperimentPopover.vue +90 -58
- package/src/composables/index.ts +7 -0
- package/src/composables/useAppExperiment.ts +143 -0
- package/src/composables/useAuth.ts +7 -1
- package/src/composables/usePlatformContext.ts +81 -25
- package/src/composables/useTheme.ts +33 -28
- package/src/index.ts +5 -0
- package/src/styles/components/experiment-popover.css +86 -3
|
@@ -1,51 +1,48 @@
|
|
|
1
|
-
import { defineComponent, ref, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode,
|
|
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-
|
|
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
|
|
10
|
+
const _hoisted_4 = {
|
|
14
11
|
key: 1,
|
|
15
|
-
class: "mld-experiment-
|
|
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
|
|
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
|
|
24
|
+
const _hoisted_6 = {
|
|
46
25
|
key: 0,
|
|
47
|
-
class: "mld-experiment-
|
|
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("
|
|
115
|
-
type: "button",
|
|
127
|
+
createElementVNode("div", {
|
|
116
128
|
class: normalizeClass([
|
|
117
|
-
"mld-experiment-
|
|
118
|
-
{ "mld-experiment-
|
|
119
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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("
|
|
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
|
-
|
|
133
|
-
d: "
|
|
134
|
-
|
|
135
|
-
],
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
147
|
-
|
|
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",
|
|
150
|
-
createElementVNode("div",
|
|
151
|
-
_cache[
|
|
152
|
-
createElementVNode("div",
|
|
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",
|
|
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[
|
|
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",
|
|
177
|
-
createElementVNode("div",
|
|
178
|
-
_cache[
|
|
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",
|
|
193
|
-
createElementVNode("div",
|
|
194
|
-
__props.experimentStatus ? (openBlock(), createElementBlock("div",
|
|
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",
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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":"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"}
|
|
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;"}
|