@vue-skuilder/common-ui 0.2.26 → 0.2.28

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 (65) hide show
  1. package/dist/admin/admin.css +2 -0
  2. package/dist/admin/common-ui-admin.es.js +1394 -0
  3. package/dist/admin/common-ui-admin.es.js.map +1 -0
  4. package/dist/admin/components/CardDossierDetail.vue.d.ts +9 -0
  5. package/dist/admin/components/CardDossierDetail.vue.d.ts.map +1 -0
  6. package/dist/admin/components/LearnerCardHistory.vue.d.ts +13 -0
  7. package/dist/admin/components/LearnerCardHistory.vue.d.ts.map +1 -0
  8. package/dist/admin/components/LearnerDatasetSource.vue.d.ts +24 -0
  9. package/dist/admin/components/LearnerDatasetSource.vue.d.ts.map +1 -0
  10. package/dist/admin/components/LearnerDiagnostics.vue.d.ts +13 -0
  11. package/dist/admin/components/LearnerDiagnostics.vue.d.ts.map +1 -0
  12. package/dist/admin/components/LearnerSessionDetail.vue.d.ts +14 -0
  13. package/dist/admin/components/LearnerSessionDetail.vue.d.ts.map +1 -0
  14. package/dist/admin/components/LearnerSessionList.vue.d.ts +13 -0
  15. package/dist/admin/components/LearnerSessionList.vue.d.ts.map +1 -0
  16. package/dist/admin/components/RunDetail.vue.d.ts +12 -0
  17. package/dist/admin/components/RunDetail.vue.d.ts.map +1 -0
  18. package/dist/admin/composables/useLearnerDataset.d.ts +26 -0
  19. package/dist/admin/composables/useLearnerDataset.d.ts.map +1 -0
  20. package/dist/admin/display.d.ts +20 -0
  21. package/dist/admin/display.d.ts.map +1 -0
  22. package/dist/admin/index.d.ts +22 -0
  23. package/dist/admin/index.d.ts.map +1 -0
  24. package/dist/components/CardBrowser.vue.d.ts +5 -5
  25. package/dist/components/CardHistoryViewer.vue.d.ts +1 -1
  26. package/dist/components/CardSearchResults.vue.d.ts +1 -1
  27. package/dist/components/CourseCardBrowser.vue.d.ts +9 -9
  28. package/dist/components/CourseInformation.vue.d.ts +18 -18
  29. package/dist/components/CourseTagFilterWidget.vue.d.ts +1 -1
  30. package/dist/components/SessionControllerDebug.vue.d.ts +1 -1
  31. package/dist/components/SnackbarService.d.ts +1 -1
  32. package/dist/components/StudySession.types.d.ts +1 -1
  33. package/dist/components/StudySession.vue.d.ts +2 -2
  34. package/dist/components/TagsInput.vue.d.ts +1 -1
  35. package/dist/components/UserTagPreferences.vue.d.ts +1 -1
  36. package/dist/components/auth/UserRegistration.vue.d.ts +74 -74
  37. package/dist/components/auth/UserRegistration.vue.d.ts.map +1 -1
  38. package/dist/components/cardRendering/CardLoader.vue.d.ts +6 -6
  39. package/dist/components/cardRendering/CardViewer.vue.d.ts +2 -2
  40. package/dist/components/cardRendering/MarkdownRenderer.vue.d.ts +6 -6
  41. package/dist/components/cardRendering/MdTokenRenderer.vue.d.ts +6 -6
  42. package/dist/components/studentInputs/BaseUserInput.d.ts +2 -2
  43. package/dist/components/studentInputs/MultipleChoiceOption.vue.d.ts +6 -6
  44. package/dist/components/studentInputs/RadioMultipleChoice.types.d.ts +1 -1
  45. package/dist/components/studentInputs/RadioMultipleChoice.vue.d.ts +9 -9
  46. package/dist/components/studentInputs/TrueFalse.vue.d.ts +9 -9
  47. package/dist/components/studentInputs/UserInputNumber.vue.d.ts +2 -2
  48. package/dist/components/studentInputs/UserInputString.vue.d.ts +3 -3
  49. package/dist/components/studentInputs/fillInInput.vue.d.ts +3 -3
  50. package/dist/composables/CompositionViewable.d.ts +2 -2
  51. package/dist/composables/Displayable.d.ts +1 -1
  52. package/dist/stores/useAuthStore.d.ts +82 -82
  53. package/dist/stores/useAuthStore.d.ts.map +1 -1
  54. package/dist/stores/useConfigStore.d.ts +1 -1
  55. package/package.json +18 -5
  56. package/src/admin/components/CardDossierDetail.vue +99 -0
  57. package/src/admin/components/LearnerCardHistory.vue +196 -0
  58. package/src/admin/components/LearnerDatasetSource.vue +97 -0
  59. package/src/admin/components/LearnerDiagnostics.vue +68 -0
  60. package/src/admin/components/LearnerSessionDetail.vue +439 -0
  61. package/src/admin/components/LearnerSessionList.vue +175 -0
  62. package/src/admin/components/RunDetail.vue +166 -0
  63. package/src/admin/composables/useLearnerDataset.ts +66 -0
  64. package/src/admin/display.ts +73 -0
  65. package/src/admin/index.ts +27 -0
@@ -0,0 +1,1394 @@
1
+ import { Fragment as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, nextTick as l, normalizeClass as u, onMounted as d, openBlock as f, ref as p, renderList as m, resolveComponent as h, shallowRef as g, toDisplayString as _, unref as v, watch as y, withCtx as b, withKeys as x } from "vue";
2
+ import { SESSION_FLAGS as S, cardDossiers as C, dumpFileName as w, eloLedger as T, fetchLearnerDump as E, fmtAnswer as D, fmtDelta as O, fmtDuration as k, fromDump as A, isSkillTag as j, parseLearnerDump as M, recordPerformance as N, runText as P, scoredTagDeltas as F, servedTags as I, sessionDetail as L, sessionText as R, shortTag as z, summarizeSessions as B } from "@vue-skuilder/db/diagnostics";
3
+ //#region \0rolldown/runtime.js
4
+ var V = Object.defineProperty, __name = (e, t) => V(e, "name", {
5
+ value: t,
6
+ configurable: !0
7
+ });
8
+ //#endregion
9
+ //#region src/admin/composables/useLearnerDataset.ts
10
+ function useLearnerDataset() {
11
+ let e = g(null), t = g(null), n = p(!1), r = p(null);
12
+ async function load(i, a) {
13
+ n.value = !0, r.value = null;
14
+ try {
15
+ let n = await i();
16
+ t.value = A(n, a), e.value = n;
17
+ } catch (e) {
18
+ r.value = e instanceof Error ? e.message : String(e);
19
+ } finally {
20
+ n.value = !1;
21
+ }
22
+ }
23
+ function loadFromCouch(e) {
24
+ return load(() => E({
25
+ ...e,
26
+ auth: { kind: "cookie" }
27
+ }), e.courseId);
28
+ }
29
+ function loadFromFile(e, t) {
30
+ return load(async () => M(await e.text()), t);
31
+ }
32
+ return {
33
+ dump: e,
34
+ dataset: t,
35
+ loading: n,
36
+ error: r,
37
+ loadFromCouch,
38
+ loadFromFile
39
+ };
40
+ }
41
+ function downloadLearnerDump(e) {
42
+ let t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), n = URL.createObjectURL(t), r = document.createElement("a");
43
+ r.href = n, r.download = w(e), r.click(), URL.revokeObjectURL(n);
44
+ }
45
+ //#endregion
46
+ //#region src/admin/components/LearnerDatasetSource.vue?vue&type=script&setup=true&lang.ts
47
+ var H = { class: "d-flex flex-wrap align-center ga-2" }, U = {
48
+ key: 1,
49
+ class: "d-flex flex-wrap align-center ga-2 mt-3"
50
+ }, W = /* @__PURE__ */ c({
51
+ __name: "LearnerDatasetSource",
52
+ props: {
53
+ couchUrl: {},
54
+ courseId: {},
55
+ initialUsername: {},
56
+ autoload: { type: Boolean }
57
+ },
58
+ emits: ["loaded"],
59
+ setup(c, { emit: l }) {
60
+ let u = c, m = l, { dump: g, dataset: S, loading: C, error: w, loadFromCouch: T, loadFromFile: E } = useLearnerDataset(), D = p(u.initialUsername ?? ""), O = p(null), k = t(() => {
61
+ let e = S.value?.sessions ?? [];
62
+ return e.length ? `${e[0].startTime.slice(0, 10)} .. ${e[e.length - 1].startTime.slice(0, 10)}` : "";
63
+ });
64
+ function loadLive() {
65
+ !u.couchUrl || !u.courseId || !D.value || T({
66
+ couchUrl: u.couchUrl,
67
+ courseId: u.courseId,
68
+ username: D.value
69
+ });
70
+ }
71
+ function onFile(e) {
72
+ let t = e.target, n = t.files?.[0];
73
+ n && E(n, u.courseId), t.value = "";
74
+ }
75
+ return y(S, (e) => {
76
+ e && g.value && m("loaded", e, g.value);
77
+ }), d(() => {
78
+ u.autoload && loadLive();
79
+ }), (t, c) => {
80
+ let l = h("v-text-field"), u = h("v-btn"), d = h("v-alert"), p = h("v-spacer"), m = h("v-card-text"), y = h("v-card");
81
+ return f(), n(y, { variant: "outlined" }, {
82
+ default: b(() => [s(m, null, {
83
+ default: b(() => [
84
+ a("div", H, [
85
+ s(l, {
86
+ modelValue: D.value,
87
+ "onUpdate:modelValue": c[0] || (c[0] = (e) => D.value = e),
88
+ label: "Learner",
89
+ density: "compact",
90
+ "hide-details": "",
91
+ style: { "max-width": "16rem" },
92
+ disabled: !t.couchUrl || !t.courseId,
93
+ onKeydown: x(loadLive, ["enter"])
94
+ }, null, 8, ["modelValue", "disabled"]),
95
+ s(u, {
96
+ color: "primary",
97
+ loading: v(C),
98
+ disabled: !t.couchUrl || !t.courseId || !D.value,
99
+ onClick: loadLive
100
+ }, {
101
+ default: b(() => c[3] || (c[3] = [o(" Load ")])),
102
+ _: 1
103
+ }, 8, ["loading", "disabled"]),
104
+ c[5] || (c[5] = a("span", { class: "text-medium-emphasis mx-2" }, "or", -1)),
105
+ s(u, {
106
+ variant: "tonal",
107
+ "prepend-icon": "mdi-file-upload-outline",
108
+ onClick: c[1] || (c[1] = (e) => O.value?.click())
109
+ }, {
110
+ default: b(() => c[4] || (c[4] = [o(" Open dump file ")])),
111
+ _: 1
112
+ }),
113
+ a("input", {
114
+ ref_key: "fileInput",
115
+ ref: O,
116
+ type: "file",
117
+ accept: ".json,application/json",
118
+ hidden: "",
119
+ onChange: onFile
120
+ }, null, 544)
121
+ ]),
122
+ v(w) ? (f(), n(d, {
123
+ key: 0,
124
+ type: "error",
125
+ variant: "tonal",
126
+ density: "compact",
127
+ class: "mt-3"
128
+ }, {
129
+ default: b(() => [o(_(v(w)), 1)]),
130
+ _: 1
131
+ })) : r("", !0),
132
+ v(S) && v(g) ? (f(), i("div", U, [
133
+ a("span", null, [
134
+ a("strong", null, _(v(S).username), 1),
135
+ o(" · " + _(v(S).sessions.length) + " sessions ", 1),
136
+ k.value ? (f(), i(e, { key: 0 }, [o("(" + _(k.value) + ")", 1)], 64)) : r("", !0),
137
+ o(" · " + _(v(S).cardHistories.length) + " cards seen · as of " + _(v(S).asOf.slice(0, 16)) + "Z ", 1),
138
+ v(S).cards ? r("", !0) : (f(), i(e, { key: 1 }, [o("· no course slice")], 64))
139
+ ]),
140
+ s(p),
141
+ s(u, {
142
+ variant: "text",
143
+ size: "small",
144
+ "prepend-icon": "mdi-download",
145
+ onClick: c[2] || (c[2] = (e) => v(downloadLearnerDump)(v(g)))
146
+ }, {
147
+ default: b(() => c[6] || (c[6] = [o(" Save dump ")])),
148
+ _: 1
149
+ })
150
+ ])) : r("", !0)
151
+ ]),
152
+ _: 1
153
+ })]),
154
+ _: 1
155
+ });
156
+ };
157
+ }
158
+ }), G = {
159
+ churned: {
160
+ icon: "mdi-autorenew",
161
+ color: "warning"
162
+ },
163
+ "out-of-content": {
164
+ icon: "mdi-cup-off-outline",
165
+ color: "error"
166
+ },
167
+ walked: {
168
+ icon: "mdi-exit-run",
169
+ color: "error"
170
+ },
171
+ stalled: {
172
+ icon: "mdi-arrow-collapse-horizontal",
173
+ color: "grey"
174
+ },
175
+ grinding: {
176
+ icon: "mdi-alert-octagon-outline",
177
+ color: "warning"
178
+ }
179
+ };
180
+ function statusColor(e) {
181
+ return e === "closed" ? "success" : e === "abandoned" ? "warning" : "error";
182
+ }
183
+ function accuracyClass(e) {
184
+ return e === null ? "text-disabled" : e >= .8 ? "text-success" : e < .5 ? "text-error" : "";
185
+ }
186
+ function deltaClass(e) {
187
+ return e === null || e === 0 ? "text-disabled" : e > 0 ? "text-success" : "text-error";
188
+ }
189
+ function deltaColor(e) {
190
+ return e > 0 ? "success" : e < 0 ? "error" : "grey";
191
+ }
192
+ function fmtTime(e) {
193
+ if (!e) return "—";
194
+ let t = new Date(e);
195
+ return Number.isNaN(t.getTime()) ? e : t.toLocaleString();
196
+ }
197
+ function fmtClock(e) {
198
+ let t = new Date(e);
199
+ return Number.isNaN(t.getTime()) ? e : t.toLocaleTimeString(void 0, { hour12: !1 });
200
+ }
201
+ function shortId(e, t = 28) {
202
+ return e.length > t ? `…${e.slice(-(t - 2))}` : e;
203
+ }
204
+ function useCopy() {
205
+ let e = p(null), t = null;
206
+ async function copy(n, r) {
207
+ try {
208
+ await navigator.clipboard.writeText(n), e.value = r, t && clearTimeout(t), t = setTimeout(() => e.value = null, 1400);
209
+ } catch (e) {
210
+ console.warn("[admin] clipboard write failed", e);
211
+ }
212
+ }
213
+ return {
214
+ copied: e,
215
+ copy
216
+ };
217
+ }
218
+ //#endregion
219
+ //#region src/admin/components/CardDossierDetail.vue?vue&type=script&setup=true&lang.ts
220
+ var ee = {
221
+ key: 0,
222
+ class: "text-caption mb-2"
223
+ }, te = { class: "text-medium-emphasis" }, ne = { class: "d-flex flex-wrap mb-2 ga-1" }, re = {
224
+ key: 0,
225
+ class: "text-caption text-disabled"
226
+ }, ie = { class: "text-caption text-medium-emphasis mb-2" }, ae = {
227
+ key: 0,
228
+ class: "text-error"
229
+ }, oe = { class: "text-no-wrap" }, se = {
230
+ key: 2,
231
+ class: "text-disabled"
232
+ }, K = {
233
+ class: "text-truncate",
234
+ style: { "max-width": "200px" }
235
+ }, ce = /* @__PURE__ */ c({
236
+ __name: "CardDossierDetail",
237
+ props: {
238
+ dossier: {},
239
+ interpreters: {}
240
+ },
241
+ setup(t) {
242
+ function perf(e) {
243
+ let t = N(e);
244
+ return t === null ? "—" : t.toFixed(2);
245
+ }
246
+ function fmtInterval(e) {
247
+ return e ? e < 3600 ? `${Math.round(e / 60)}m` : e < 86400 ? `${Math.round(e / 3600)}h` : `${Math.round(e / 86400)}d` : "none";
248
+ }
249
+ return (t, c) => {
250
+ let l = h("v-chip"), d = h("v-icon"), p = h("v-table");
251
+ return f(), i("div", null, [
252
+ t.dossier.card && Object.keys(t.dossier.card.data).length ? (f(), i("div", ee, [(f(!0), i(e, null, m(t.dossier.card.data, (e, t) => (f(), i("span", {
253
+ key: t,
254
+ class: "mr-3"
255
+ }, [a("span", te, _(t) + ":", 1), o(" " + _(v(D)(e, 60)), 1)]))), 128))])) : r("", !0),
256
+ a("div", ne, [(f(!0), i(e, null, m(t.dossier.card?.tags ?? [], (e) => (f(), n(l, {
257
+ key: e,
258
+ size: "x-small",
259
+ variant: "outlined",
260
+ color: v(j)(t.interpreters, e) ? "primary" : void 0
261
+ }, {
262
+ default: b(() => [o(_(e), 1)]),
263
+ _: 2
264
+ }, 1032, ["color"]))), 128)), t.dossier.card ? r("", !0) : (f(), i("span", re, "no course data in this dataset"))]),
265
+ a("div", ie, [o(" lapses " + _(t.dossier.lapses) + " · streak " + _(t.dossier.streak) + " · best interval " + _(fmtInterval(t.dossier.bestIntervalSeconds)) + " · ", 1), t.dossier.pendingReview ? (f(), i(e, { key: 0 }, [o(" next review " + _(v(fmtTime)(t.dossier.pendingReview.reviewTime)) + " ", 1), t.dossier.pendingReview.overdue ? (f(), i("span", ae, "(overdue)")) : r("", !0)], 64)) : (f(), i(e, { key: 1 }, [o("no review scheduled")], 64))]),
266
+ s(p, {
267
+ density: "compact",
268
+ class: "sk-record-table"
269
+ }, {
270
+ default: b(() => [c[2] || (c[2] = a("thead", null, [a("tr", null, [
271
+ a("th", null, "#"),
272
+ a("th", null, "When"),
273
+ a("th", null, "Result"),
274
+ a("th", null, "Perf"),
275
+ a("th", null, "Prior att."),
276
+ a("th", null, "Time"),
277
+ a("th", null, "Answer")
278
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(t.dossier.records, (e, t) => (f(), i("tr", {
279
+ key: t,
280
+ class: u(e.isCorrect === !1 ? "sk-fail-row" : "")
281
+ }, [
282
+ a("td", null, _(t + 1), 1),
283
+ a("td", oe, _(v(fmtTime)(e.timeStamp)), 1),
284
+ a("td", null, [e.isCorrect === !0 ? (f(), n(d, {
285
+ key: 0,
286
+ size: "small",
287
+ color: "success"
288
+ }, {
289
+ default: b(() => c[0] || (c[0] = [o("mdi-check")])),
290
+ _: 1
291
+ })) : e.isCorrect === !1 ? (f(), n(d, {
292
+ key: 1,
293
+ size: "small",
294
+ color: "error"
295
+ }, {
296
+ default: b(() => c[1] || (c[1] = [o("mdi-close")])),
297
+ _: 1
298
+ })) : (f(), i("span", se, "—"))]),
299
+ a("td", null, _(perf(e)), 1),
300
+ a("td", null, _(e.priorAttemps ?? "—"), 1),
301
+ a("td", null, _(((e.timeSpent ?? 0) / 1e3).toFixed(1)) + "s", 1),
302
+ a("td", K, _(v(D)(e.userAnswer)), 1)
303
+ ], 2))), 128))])]),
304
+ _: 1
305
+ })
306
+ ]);
307
+ };
308
+ }
309
+ }), q = /* @__PURE__ */ __name((e, t) => {
310
+ let n = e.__vccOpts || e;
311
+ for (let [e, r] of t) n[e] = r;
312
+ return n;
313
+ }, "default"), J = /* @__PURE__ */ q(ce, [["__scopeId", "data-v-76b0a622"]]), le = { class: "text-caption text-medium-emphasis mb-4" }, ue = { class: "text-h6" }, de = { class: "text-caption" }, fe = { class: "d-flex align-center flex-wrap mb-3 ga-3" }, pe = {
314
+ class: "d-flex align-center flex-wrap ga-2",
315
+ style: { width: "100%" }
316
+ }, me = { class: "text-body-2 font-weight-medium" }, he = { class: "text-caption text-medium-emphasis" }, ge = {
317
+ key: 2,
318
+ class: "text-caption"
319
+ }, _e = {
320
+ key: 0,
321
+ class: "ml-1 text-disabled"
322
+ }, Y = /* @__PURE__ */ q(/* @__PURE__ */ c({
323
+ __name: "LearnerCardHistory",
324
+ props: {
325
+ dataset: {},
326
+ interpreters: {},
327
+ focus: {}
328
+ },
329
+ setup(c) {
330
+ let d = c, g = t(() => C(d.dataset)), x = p("all"), S = p(""), w = p([]), T = p(null), E = t(() => ({
331
+ stuck: g.value.filter((e) => e.stuck).length,
332
+ failed: g.value.filter((e) => e.fails > 0).length,
333
+ frozen: g.value.filter((e) => e.frozenElo).length
334
+ })), D = t(() => [
335
+ {
336
+ label: "cards seen",
337
+ value: g.value.length,
338
+ color: "primary"
339
+ },
340
+ {
341
+ label: "total attempts",
342
+ value: g.value.reduce((e, t) => e + t.attempts, 0),
343
+ color: "primary"
344
+ },
345
+ {
346
+ label: "total fails",
347
+ value: g.value.reduce((e, t) => e + t.fails, 0),
348
+ color: "error"
349
+ },
350
+ {
351
+ label: "time on cards",
352
+ value: k(g.value.reduce((e, t) => e + t.totalTimeMs, 0) / 1e3),
353
+ color: "grey"
354
+ },
355
+ {
356
+ label: "stuck reviews",
357
+ value: E.value.stuck,
358
+ color: "error"
359
+ },
360
+ {
361
+ label: "frozen ELO",
362
+ value: E.value.frozen,
363
+ color: "warning"
364
+ }
365
+ ]), O = t(() => {
366
+ let e = g.value;
367
+ x.value === "stuck" ? e = e.filter((e) => e.stuck) : x.value === "failed" ? e = e.filter((e) => e.fails > 0) : x.value === "frozen" && (e = e.filter((e) => e.frozenElo));
368
+ let t = S.value?.trim().toLowerCase();
369
+ return t && (e = e.filter((e) => e.cardId.toLowerCase().includes(t) || (e.card?.questionType ?? "").toLowerCase().includes(t) || (e.card?.tags ?? []).some((e) => e.toLowerCase().includes(t)) || Object.values(e.card?.data ?? {}).some((e) => typeof e == "string" && e.toLowerCase().includes(t)))), e;
370
+ });
371
+ function headline(e) {
372
+ let t = Object.values(e.card?.data ?? {}).find((e) => typeof e == "string" && e.length <= 40);
373
+ return typeof t == "string" ? t : "";
374
+ }
375
+ async function applyFocus(e) {
376
+ !e || !g.value.some((t) => t.cardId === e) || (x.value = "all", S.value = e, w.value = [e], await l(), document.querySelector(`[data-card="${CSS.escape(e)}"]`)?.scrollIntoView({
377
+ behavior: "smooth",
378
+ block: "center"
379
+ }), T.value = e, setTimeout(() => {
380
+ T.value === e && (T.value = null);
381
+ }, 2200));
382
+ }
383
+ return y(() => d.focus, (e) => void applyFocus(e), { immediate: !0 }), (t, c) => {
384
+ let l = h("v-icon"), d = h("v-card"), p = h("v-col"), y = h("v-row"), C = h("v-btn"), A = h("v-btn-toggle"), j = h("v-text-field"), M = h("v-alert"), N = h("v-spacer"), P = h("v-chip"), F = h("v-expansion-panel-title"), I = h("v-expansion-panel-text"), L = h("v-expansion-panel"), R = h("v-expansion-panels");
385
+ return f(), i("div", null, [
386
+ a("p", le, [
387
+ c[5] || (c[5] = o(" Every card the learner has met, most painful first (time sunk × failures), with its pending review and current card ELO. ")),
388
+ s(l, {
389
+ size: "x-small",
390
+ color: "error"
391
+ }, {
392
+ default: b(() => c[3] || (c[3] = [o("mdi-sync-alert")])),
393
+ _: 1
394
+ }),
395
+ c[6] || (c[6] = o(" is a failed card holding an overdue review; ")),
396
+ s(l, {
397
+ size: "x-small",
398
+ color: "warning"
399
+ }, {
400
+ default: b(() => c[4] || (c[4] = [o("mdi-snowflake")])),
401
+ _: 1
402
+ }),
403
+ c[7] || (c[7] = o(" is a repeatedly failed card whose ELO has fewer updates than failures. "))
404
+ ]),
405
+ s(y, {
406
+ dense: "",
407
+ class: "mb-2"
408
+ }, {
409
+ default: b(() => [(f(!0), i(e, null, m(D.value, (e) => (f(), n(p, {
410
+ key: e.label,
411
+ cols: "6",
412
+ sm: "4",
413
+ md: "2"
414
+ }, {
415
+ default: b(() => [s(d, {
416
+ variant: "tonal",
417
+ color: e.color,
418
+ class: "pa-2 text-center"
419
+ }, {
420
+ default: b(() => [a("div", ue, _(e.value), 1), a("div", de, _(e.label), 1)]),
421
+ _: 2
422
+ }, 1032, ["color"])]),
423
+ _: 2
424
+ }, 1024))), 128))]),
425
+ _: 1
426
+ }),
427
+ a("div", fe, [s(A, {
428
+ modelValue: x.value,
429
+ "onUpdate:modelValue": c[0] || (c[0] = (e) => x.value = e),
430
+ density: "compact",
431
+ color: "primary",
432
+ variant: "outlined"
433
+ }, {
434
+ default: b(() => [
435
+ s(C, {
436
+ value: "all",
437
+ size: "small"
438
+ }, {
439
+ default: b(() => [o("All (" + _(g.value.length) + ")", 1)]),
440
+ _: 1
441
+ }),
442
+ s(C, {
443
+ value: "stuck",
444
+ size: "small"
445
+ }, {
446
+ default: b(() => [s(l, {
447
+ start: "",
448
+ size: "small",
449
+ color: "error"
450
+ }, {
451
+ default: b(() => c[8] || (c[8] = [o("mdi-sync-alert")])),
452
+ _: 1
453
+ }), o(" Stuck (" + _(E.value.stuck) + ") ", 1)]),
454
+ _: 1
455
+ }),
456
+ s(C, {
457
+ value: "failed",
458
+ size: "small"
459
+ }, {
460
+ default: b(() => [o("Ever failed (" + _(E.value.failed) + ")", 1)]),
461
+ _: 1
462
+ }),
463
+ s(C, {
464
+ value: "frozen",
465
+ size: "small"
466
+ }, {
467
+ default: b(() => [s(l, {
468
+ start: "",
469
+ size: "small",
470
+ color: "warning"
471
+ }, {
472
+ default: b(() => c[9] || (c[9] = [o("mdi-snowflake")])),
473
+ _: 1
474
+ }), o(" Frozen ELO (" + _(E.value.frozen) + ") ", 1)]),
475
+ _: 1
476
+ })
477
+ ]),
478
+ _: 1
479
+ }, 8, ["modelValue"]), s(j, {
480
+ modelValue: S.value,
481
+ "onUpdate:modelValue": c[1] || (c[1] = (e) => S.value = e),
482
+ density: "compact",
483
+ variant: "outlined",
484
+ "hide-details": "",
485
+ clearable: "",
486
+ placeholder: "filter by card / tag / type / content",
487
+ "prepend-inner-icon": "mdi-magnify",
488
+ style: { "max-width": "320px" }
489
+ }, null, 8, ["modelValue"])]),
490
+ g.value.length === 0 ? (f(), n(M, {
491
+ key: 0,
492
+ type: "info",
493
+ variant: "tonal"
494
+ }, {
495
+ default: b(() => c[10] || (c[10] = [o("No card history for this learner.")])),
496
+ _: 1
497
+ })) : (f(), n(R, {
498
+ key: 1,
499
+ modelValue: w.value,
500
+ "onUpdate:modelValue": c[2] || (c[2] = (e) => w.value = e),
501
+ multiple: "",
502
+ variant: "accordion"
503
+ }, {
504
+ default: b(() => [(f(!0), i(e, null, m(O.value, (e) => (f(), n(L, {
505
+ key: e.cardId,
506
+ value: e.cardId,
507
+ "data-card": e.cardId,
508
+ class: u(e.cardId === T.value ? "sk-card-flash" : "")
509
+ }, {
510
+ default: b(() => [s(F, null, {
511
+ default: b(() => [a("div", pe, [
512
+ e.stuck ? (f(), n(l, {
513
+ key: 0,
514
+ color: "error",
515
+ size: "small",
516
+ title: "failed + overdue review"
517
+ }, {
518
+ default: b(() => c[11] || (c[11] = [o("mdi-sync-alert")])),
519
+ _: 1
520
+ })) : r("", !0),
521
+ e.frozenElo ? (f(), n(l, {
522
+ key: 1,
523
+ color: "warning",
524
+ size: "small",
525
+ title: "repeatedly failed, ELO barely updated"
526
+ }, {
527
+ default: b(() => c[12] || (c[12] = [o(" mdi-snowflake ")])),
528
+ _: 1
529
+ })) : r("", !0),
530
+ a("span", me, _(e.card?.questionType ?? "card"), 1),
531
+ a("code", he, _(v(shortId)(e.cardId, 24)), 1),
532
+ headline(e) ? (f(), i("span", ge, _(headline(e)), 1)) : r("", !0),
533
+ s(N),
534
+ e.fails > 0 ? (f(), n(P, {
535
+ key: 3,
536
+ size: "x-small",
537
+ color: "error",
538
+ variant: "tonal"
539
+ }, {
540
+ default: b(() => [o(_(e.fails) + " fail" + _(e.fails === 1 ? "" : "s"), 1)]),
541
+ _: 2
542
+ }, 1024)) : r("", !0),
543
+ s(P, {
544
+ size: "x-small",
545
+ variant: "tonal"
546
+ }, {
547
+ default: b(() => [o(_(e.attempts) + " view" + _(e.attempts === 1 ? "" : "s"), 1)]),
548
+ _: 2
549
+ }, 1024),
550
+ s(P, {
551
+ size: "x-small",
552
+ variant: "tonal",
553
+ color: "grey"
554
+ }, {
555
+ default: b(() => [o(_(v(k)(e.totalTimeMs / 1e3)), 1)]),
556
+ _: 2
557
+ }, 1024),
558
+ e.pendingReview ? (f(), n(P, {
559
+ key: 4,
560
+ size: "x-small",
561
+ color: e.pendingReview.overdue ? "error" : "success",
562
+ variant: "flat"
563
+ }, {
564
+ default: b(() => [o(" review " + _(e.pendingReview.overdue ? "overdue" : "scheduled"), 1)]),
565
+ _: 2
566
+ }, 1032, ["color"])) : r("", !0),
567
+ s(P, {
568
+ size: "x-small",
569
+ variant: "tonal",
570
+ color: e.frozenElo ? "warning" : void 0
571
+ }, {
572
+ default: b(() => [o(" ELO " + _(e.cardElo === null ? "?" : Math.round(e.cardElo)) + " ", 1), e.cardEloCount === null ? r("", !0) : (f(), i("span", _e, "/" + _(e.cardEloCount), 1))]),
573
+ _: 2
574
+ }, 1032, ["color"])
575
+ ])]),
576
+ _: 2
577
+ }, 1024), s(I, null, {
578
+ default: b(() => [s(J, {
579
+ dossier: e,
580
+ interpreters: t.interpreters
581
+ }, null, 8, ["dossier", "interpreters"])]),
582
+ _: 2
583
+ }, 1024)]),
584
+ _: 2
585
+ }, 1032, [
586
+ "value",
587
+ "data-card",
588
+ "class"
589
+ ]))), 128))]),
590
+ _: 1
591
+ }, 8, ["modelValue"]))
592
+ ]);
593
+ };
594
+ }
595
+ }), [["__scopeId", "data-v-bb6b302b"]]), ve = { class: "sk-run-detail" }, ye = {
596
+ key: 0,
597
+ class: "mb-2"
598
+ }, be = { class: "text-right" }, xe = { class: "text-right" }, Se = { class: "text-right" }, Ce = { class: "text-right" }, we = {
599
+ key: 1,
600
+ class: "mb-2"
601
+ }, Te = { class: "text-right" }, Ee = { class: "text-right" }, De = { class: "text-right" }, Oe = {
602
+ key: 2,
603
+ class: "mb-2"
604
+ }, ke = {
605
+ key: 1,
606
+ title: "runner-up"
607
+ }, Ae = ["onClick"], je = { class: "text-right" }, Me = { class: "text-caption font-weight-medium" }, Ne = ["onClick"], Pe = { class: "text-medium-emphasis" }, Fe = { class: "text-no-wrap" }, Ie = { class: "text-no-wrap" }, Le = { class: "text-right text-no-wrap" }, Re = { class: "text-caption" }, ze = {
608
+ key: 3,
609
+ class: "mb-2"
610
+ }, Be = { class: "sk-hint-block" }, Ve = {
611
+ key: 4,
612
+ class: "text-caption text-medium-emphasis"
613
+ }, He = { key: 2 }, X = /* @__PURE__ */ q(/* @__PURE__ */ c({
614
+ __name: "RunDetail",
615
+ props: { run: {} },
616
+ emits: ["open-card"],
617
+ setup(c, { emit: l }) {
618
+ let d = c, p = l, g = t(() => {
619
+ let e = d.run.unselectedNew, t = [];
620
+ return e?.nextInLine && t.push({
621
+ label: "next new card in line",
622
+ card: e.nextInLine
623
+ }), e?.topGenerated && t.push({
624
+ label: "top-generated new card (sunk)",
625
+ card: e.topGenerated
626
+ }), t;
627
+ });
628
+ function fmtScore(e) {
629
+ return Math.abs(e) >= .01 || e === 0 ? e.toFixed(2) : e.toExponential(1);
630
+ }
631
+ return (t, c) => {
632
+ let l = h("v-table"), d = h("v-icon");
633
+ return f(), i("div", ve, [
634
+ t.run.generators?.length ? (f(), i("div", ye, [c[1] || (c[1] = a("div", { class: "text-caption font-weight-medium" }, "generators", -1)), s(l, {
635
+ density: "compact",
636
+ class: "sk-mini-table"
637
+ }, {
638
+ default: b(() => [c[0] || (c[0] = a("thead", null, [a("tr", null, [
639
+ a("th"),
640
+ a("th", { class: "text-right" }, "cards"),
641
+ a("th", { class: "text-right" }, "new"),
642
+ a("th", { class: "text-right" }, "review"),
643
+ a("th", { class: "text-right" }, "top")
644
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(t.run.generators, (e) => (f(), i("tr", { key: e.name }, [
645
+ a("td", null, _(e.name), 1),
646
+ a("td", be, _(e.cardCount), 1),
647
+ a("td", xe, _(e.newCount), 1),
648
+ a("td", Se, _(e.reviewCount), 1),
649
+ a("td", Ce, _(e.topScore.toFixed(2)), 1)
650
+ ]))), 128))])]),
651
+ _: 1
652
+ })])) : r("", !0),
653
+ t.run.filters?.length ? (f(), i("div", we, [c[3] || (c[3] = a("div", { class: "text-caption font-weight-medium" }, "filters", -1)), s(l, {
654
+ density: "compact",
655
+ class: "sk-mini-table"
656
+ }, {
657
+ default: b(() => [c[2] || (c[2] = a("thead", null, [a("tr", null, [
658
+ a("th"),
659
+ a("th", { class: "text-right" }, "boosted"),
660
+ a("th", { class: "text-right" }, "penalized"),
661
+ a("th", { class: "text-right" }, "passed"),
662
+ a("th", { class: "text-right" }, "removed")
663
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(t.run.filters, (e) => (f(), i("tr", { key: e.name }, [
664
+ a("td", null, _(e.name), 1),
665
+ a("td", Te, _(e.boosted), 1),
666
+ a("td", Ee, _(e.penalized), 1),
667
+ a("td", De, _(e.passed), 1),
668
+ a("td", { class: u(["text-right", e.removed > 0 ? "text-error" : ""]) }, _(e.removed), 3)
669
+ ]))), 128))])]),
670
+ _: 1
671
+ })])) : r("", !0),
672
+ t.run.cards?.length ? (f(), i("div", Oe, [c[6] || (c[6] = a("div", { class: "text-caption font-weight-medium" }, "selection", -1)), s(l, {
673
+ density: "compact",
674
+ class: "sk-mini-table"
675
+ }, {
676
+ default: b(() => [c[5] || (c[5] = a("thead", null, [a("tr", null, [
677
+ a("th"),
678
+ a("th", null, "card"),
679
+ a("th", null, "origin"),
680
+ a("th", null, "generator"),
681
+ a("th", { class: "text-right" }, "score")
682
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(t.run.cards, (e) => (f(), i("tr", {
683
+ key: e.cardId,
684
+ class: u(e.selected ? "" : "text-medium-emphasis")
685
+ }, [
686
+ a("td", null, [e.selected ? (f(), n(d, {
687
+ key: 0,
688
+ size: "x-small",
689
+ color: "success"
690
+ }, {
691
+ default: b(() => c[4] || (c[4] = [o("mdi-check")])),
692
+ _: 1
693
+ })) : (f(), i("span", ke, "·"))]),
694
+ a("td", null, [a("a", {
695
+ class: "sk-card-link",
696
+ onClick: (t) => p("open-card", e.cardId)
697
+ }, _(e.cardId), 9, Ae)]),
698
+ a("td", null, _(e.origin), 1),
699
+ a("td", null, _(e.generator ?? "—"), 1),
700
+ a("td", je, _(fmtScore(e.score)), 1)
701
+ ], 2))), 128))])]),
702
+ _: 1
703
+ })])) : r("", !0),
704
+ (f(!0), i(e, null, m(g.value, (t) => (f(), i("div", {
705
+ key: t.label,
706
+ class: "mb-2"
707
+ }, [a("div", Me, [
708
+ o(_(t.label) + ": ", 1),
709
+ a("a", {
710
+ class: "sk-card-link",
711
+ onClick: (e) => p("open-card", t.card.cardId)
712
+ }, _(t.card.cardId), 9, Ne),
713
+ a("span", Pe, " (" + _(t.card.origin) + ", " + _(t.card.generator ?? "?") + ") final " + _(fmtScore(t.card.score)), 1)
714
+ ]), s(l, {
715
+ density: "compact",
716
+ class: "sk-mini-table"
717
+ }, {
718
+ default: b(() => [a("tbody", null, [(f(!0), i(e, null, m(t.card.trail, (e, t) => (f(), i("tr", { key: t }, [
719
+ a("td", Fe, _(e.action), 1),
720
+ a("td", Ie, _(e.strategyName), 1),
721
+ a("td", Le, _(fmtScore(e.score)), 1),
722
+ a("td", Re, _(e.reason), 1)
723
+ ]))), 128))])]),
724
+ _: 2
725
+ }, 1024)]))), 128)),
726
+ t.run.hints ? (f(), i("div", ze, [c[7] || (c[7] = a("div", { class: "text-caption font-weight-medium" }, "hints", -1)), a("pre", Be, _(JSON.stringify(t.run.hints, null, 2)), 1)])) : r("", !0),
727
+ t.run.discardedTail ? (f(), i("div", Ve, [
728
+ o(" discarded tail: " + _(t.run.discardedTail.count) + " cards ", 1),
729
+ t.run.discardedTail.scoreRange ? (f(), i(e, { key: 0 }, [o(" · score [" + _(t.run.discardedTail.scoreRange[0].toFixed(2)) + ", " + _(t.run.discardedTail.scoreRange[1].toFixed(2)) + "] ", 1)], 64)) : r("", !0),
730
+ t.run.discardedTail.eloRange ? (f(), i(e, { key: 1 }, [o(" · ELO [" + _(Math.round(t.run.discardedTail.eloRange[0])) + ", " + _(Math.round(t.run.discardedTail.eloRange[1])) + "] ", 1)], 64)) : r("", !0),
731
+ t.run.discardedTail.note ? (f(), i("div", He, _(t.run.discardedTail.note), 1)) : r("", !0)
732
+ ])) : r("", !0)
733
+ ]);
734
+ };
735
+ }
736
+ }), [["__scopeId", "data-v-ffc34f95"]]), Ue = { class: "d-flex align-center flex-wrap mb-4 ga-2" }, We = { class: "text-caption text-medium-emphasis" }, Ge = { class: "text-right" }, Ke = { class: "text-right" }, qe = {
737
+ key: 1,
738
+ class: "text-caption text-disabled"
739
+ }, Je = { class: "sk-hint-block" }, Ye = { class: "sk-hint-block" }, Xe = { class: "text-caption text-medium-emphasis mb-4" }, Ze = { class: "text-right" }, Qe = { class: "text-right" }, $e = { class: "text-disabled" }, et = { class: "text-right" }, tt = { class: "d-flex flex-wrap ga-5" }, nt = { class: "text-caption text-medium-emphasis" }, rt = { class: "text-h6 text-success" }, it = { class: "text-caption text-medium-emphasis" }, at = { class: "text-h6 text-error" }, ot = { class: "text-h6" }, st = { class: "text-caption text-disabled" }, ct = { class: "d-flex align-center flex-wrap mb-2 ga-3" }, lt = {
740
+ key: 4,
741
+ class: "sk-timeline"
742
+ }, ut = { class: "sk-tl-time text-caption text-disabled" }, dt = { class: "sk-tl-gutter" }, ft = {
743
+ key: 0,
744
+ class: "sk-tl-body"
745
+ }, pt = { class: "d-flex align-center flex-wrap ga-1" }, mt = { class: "font-weight-medium" }, ht = { class: "text-caption text-medium-emphasis ml-2" }, gt = {
746
+ key: 1,
747
+ class: "text-caption text-error ml-2"
748
+ }, _t = {
749
+ key: 1,
750
+ class: "sk-tl-body"
751
+ }, vt = ["title", "onClick"], yt = { class: "text-caption" }, bt = { class: "text-caption text-medium-emphasis ml-2" }, xt = {
752
+ key: 0,
753
+ class: "text-caption text-disabled ml-2"
754
+ }, Z = /* @__PURE__ */ q(/* @__PURE__ */ c({
755
+ __name: "LearnerSessionDetail",
756
+ props: {
757
+ dataset: {},
758
+ sessionId: {},
759
+ interpreters: {}
760
+ },
761
+ emits: ["open-card"],
762
+ setup(c, { emit: l }) {
763
+ let d = c, g = l, y = t(() => L(d.dataset, d.sessionId, d.interpreters)), x = t(() => y.value.summary.doc), C = t(() => I(y.value?.timeline ?? [], d.interpreters)), w = t(() => T(y.value?.timeline ?? [])), E = t(() => y.value?.timeline.filter((e) => e.kind === "response").length ?? 0), A = p("all"), M = t(() => {
764
+ let e = y.value?.timeline ?? [];
765
+ return !A.value || A.value === "all" ? e : e.filter((e) => e.kind === A.value);
766
+ }), N = p(/* @__PURE__ */ new Set());
767
+ function toggle(e) {
768
+ let t = new Set(N.value);
769
+ t.has(e) ? t.delete(e) : t.add(e), N.value = t;
770
+ }
771
+ let { copied: B, copy: V } = useCopy();
772
+ function asText() {
773
+ return y.value ? R(d.dataset.username, y.value, {
774
+ servedTags: C.value,
775
+ eloLedger: w.value
776
+ }, d.interpreters) : "";
777
+ }
778
+ let H = t(() => {
779
+ let e = y.value?.summary;
780
+ if (!e) return "";
781
+ let t = k(e.doc.plannedSeconds);
782
+ return e.durationSeconds === null ? `— of ${t}` : `${k(e.durationSeconds)} of ${t}`;
783
+ });
784
+ function skillTags(e) {
785
+ return e.filter((e) => j(d.interpreters, e)).slice(0, 3);
786
+ }
787
+ function fmtNum(e) {
788
+ return e === null ? "—" : Number.isInteger(e) ? String(e) : e.toFixed(1);
789
+ }
790
+ function fmtHints(e) {
791
+ return e == null ? "none" : JSON.stringify(e, null, 2);
792
+ }
793
+ function entryIcon(e) {
794
+ return e.kind === "run" ? "mdi-cog-refresh-outline" : e.isCorrect === !0 ? "mdi-check-circle-outline" : e.isCorrect === !1 ? "mdi-close-circle-outline" : "mdi-circle-small";
795
+ }
796
+ function entryColor(e) {
797
+ return e.kind === "run" ? "primary" : e.isCorrect === !0 ? "success" : e.isCorrect === !1 ? "error" : "grey";
798
+ }
799
+ function rowClass(e) {
800
+ return e.kind === "run" ? "sk-tl-run" : e.isCorrect === !1 ? "sk-tl-fail" : "";
801
+ }
802
+ return (t, c) => {
803
+ let l = h("v-alert"), d = h("v-chip"), p = h("v-icon"), T = h("v-spacer"), k = h("v-btn"), I = h("v-table"), L = h("v-card"), R = h("v-col"), U = h("v-row"), W = h("v-btn-toggle");
804
+ return f(), i("div", null, [y.value ? (f(), i(e, { key: 1 }, [
805
+ a("div", Ue, [
806
+ s(d, {
807
+ size: "small",
808
+ variant: "flat",
809
+ color: v(statusColor)(x.value.status)
810
+ }, {
811
+ default: b(() => [o(_(x.value.status), 1)]),
812
+ _: 1
813
+ }, 8, ["color"]),
814
+ s(d, {
815
+ size: "small",
816
+ variant: "tonal"
817
+ }, {
818
+ default: b(() => [o(_(v(fmtTime)(x.value.startTime)), 1)]),
819
+ _: 1
820
+ }),
821
+ s(d, {
822
+ size: "small",
823
+ variant: "tonal",
824
+ color: "grey"
825
+ }, {
826
+ default: b(() => [o(_(H.value), 1)]),
827
+ _: 1
828
+ }),
829
+ (f(!0), i(e, null, m(y.value.summary.flags, (e) => (f(), n(d, {
830
+ key: e,
831
+ size: "small",
832
+ variant: "tonal",
833
+ color: v(G)[e].color,
834
+ title: v(S)[e].help
835
+ }, {
836
+ default: b(() => [s(p, {
837
+ start: "",
838
+ size: "small"
839
+ }, {
840
+ default: b(() => [o(_(v(G)[e].icon), 1)]),
841
+ _: 2
842
+ }, 1024), o(" " + _(v(S)[e].label), 1)]),
843
+ _: 2
844
+ }, 1032, ["color", "title"]))), 128)),
845
+ s(T),
846
+ a("code", We, _(t.sessionId), 1),
847
+ s(k, {
848
+ variant: "text",
849
+ size: "small",
850
+ "prepend-icon": v(B) === "session" ? "mdi-check" : "mdi-clipboard-text-outline",
851
+ color: v(B) === "session" ? "success" : void 0,
852
+ onClick: c[0] || (c[0] = (e) => v(V)(asText(), "session"))
853
+ }, {
854
+ default: b(() => [o(_(v(B) === "session" ? "Copied" : "Copy as text"), 1)]),
855
+ _: 1
856
+ }, 8, ["prepend-icon", "color"])
857
+ ]),
858
+ y.value.responsesMissing ? (f(), n(l, {
859
+ key: 0,
860
+ type: "warning",
861
+ variant: "tonal",
862
+ density: "compact",
863
+ class: "mb-4"
864
+ }, {
865
+ default: b(() => [o(" The session records " + _(x.value.tally?.responses) + " responses but only " + _(E.value) + " card records carry its id. The timeline is incomplete. ", 1)]),
866
+ _: 1
867
+ })) : r("", !0),
868
+ s(U, { class: "mb-2" }, {
869
+ default: b(() => [s(R, {
870
+ cols: "12",
871
+ md: "6"
872
+ }, {
873
+ default: b(() => [s(L, {
874
+ variant: "outlined",
875
+ class: "pa-3 h-100"
876
+ }, {
877
+ default: b(() => [
878
+ c[4] || (c[4] = a("div", { class: "text-subtitle-2 mb-1" }, "Learner state", -1)),
879
+ c[5] || (c[5] = a("div", { class: "text-caption text-medium-emphasis mb-3" }, " What the navigator was choosing against, and what moved. ", -1)),
880
+ y.value.summary.state.length ? (f(), n(I, {
881
+ key: 0,
882
+ density: "compact",
883
+ class: "sk-mini-table"
884
+ }, {
885
+ default: b(() => [c[3] || (c[3] = a("thead", null, [a("tr", null, [
886
+ a("th"),
887
+ a("th", { class: "text-right" }, "Start"),
888
+ a("th", { class: "text-right" }, "End"),
889
+ a("th", { class: "text-right" }, "Δ")
890
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(y.value.summary.state, (e) => (f(), i("tr", { key: e.label }, [
891
+ a("td", null, _(e.label), 1),
892
+ a("td", Ge, _(fmtNum(e.from)), 1),
893
+ a("td", Ke, _(fmtNum(e.to)), 1),
894
+ a("td", { class: u(["text-right", v(deltaClass)(e.delta)]) }, _(v(O)(e.delta)), 3)
895
+ ]))), 128))])]),
896
+ _: 1
897
+ })) : (f(), i("div", qe, "No state snapshot recorded."))
898
+ ]),
899
+ _: 1
900
+ })]),
901
+ _: 1
902
+ }), s(R, {
903
+ cols: "12",
904
+ md: "6"
905
+ }, {
906
+ default: b(() => [s(L, {
907
+ variant: "outlined",
908
+ class: "pa-3 h-100"
909
+ }, {
910
+ default: b(() => [
911
+ c[6] || (c[6] = a("div", { class: "text-subtitle-2 mb-1" }, "Session hints", -1)),
912
+ c[7] || (c[7] = a("div", { class: "text-caption text-medium-emphasis mb-3" }, " What outcome observers told the navigator. They act only through these. ", -1)),
913
+ c[8] || (c[8] = a("span", { class: "text-caption font-weight-medium" }, "at open", -1)),
914
+ a("pre", Je, _(fmtHints(x.value.config?.initHints)), 1),
915
+ c[9] || (c[9] = a("span", { class: "text-caption font-weight-medium" }, "at close", -1)),
916
+ a("pre", Ye, _(fmtHints(x.value.finalHints)), 1)
917
+ ]),
918
+ _: 1
919
+ })]),
920
+ _: 1
921
+ })]),
922
+ _: 1
923
+ }),
924
+ a("div", Xe, [o(" batch limit " + _(x.value.config?.defaultBatchLimit ?? "?") + " · " + _(x.value.config?.sourceCount ?? "?") + " source(s) · opening queues supply " + _(x.value.initialQueues?.supplyQ ?? "?") + " / failed " + _(x.value.initialQueues?.failedQ ?? "?") + " ", 1), x.value.tally ? (f(), i(e, { key: 0 }, [o(" · ended with " + _(x.value.tally.failedQRemaining) + " still in the failed queue", 1)], 64)) : r("", !0)]),
925
+ C.value.length ? (f(), n(L, {
926
+ key: 1,
927
+ variant: "outlined",
928
+ class: "pa-3 mb-4"
929
+ }, {
930
+ default: b(() => [
931
+ c[11] || (c[11] = a("div", { class: "text-subtitle-2 mb-1" }, "Served tags", -1)),
932
+ c[12] || (c[12] = a("div", { class: "text-caption text-medium-emphasis mb-2" }, " What this sitting put in front of the learner, by content tag. A response with several tags counts toward each. ", -1)),
933
+ s(I, {
934
+ density: "compact",
935
+ class: "sk-mini-table"
936
+ }, {
937
+ default: b(() => [c[10] || (c[10] = a("thead", null, [a("tr", null, [
938
+ a("th", null, "Tag"),
939
+ a("th", { class: "text-right" }, "Resp."),
940
+ a("th", { class: "text-right" }, "Cards"),
941
+ a("th", { class: "text-right" }, "Accuracy"),
942
+ a("th", { class: "text-right" }, "Time")
943
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(C.value, (n) => (f(), i("tr", { key: n.tag }, [
944
+ a("td", null, [a("code", { class: u(v(j)(t.interpreters, n.tag) ? "text-primary" : "") }, _(n.tag), 3)]),
945
+ a("td", Ze, _(n.responses), 1),
946
+ a("td", Qe, _(n.cards), 1),
947
+ a("td", { class: u(["text-right", v(accuracyClass)(n.accuracy)]) }, [n.accuracy === null ? (f(), i(e, { key: 0 }, [o("—")], 64)) : (f(), i(e, { key: 1 }, [o(_(Math.round(n.accuracy * 100)) + "% ", 1), a("span", $e, "(" + _(n.correct) + "/" + _(n.correct + n.incorrect) + ")", 1)], 64))], 2),
948
+ a("td", et, _((n.totalTimeMs / 1e3).toFixed(1)) + "s", 1)
949
+ ]))), 128))])]),
950
+ _: 1
951
+ })
952
+ ]),
953
+ _: 1
954
+ })) : r("", !0),
955
+ w.value ? (f(), n(L, {
956
+ key: 2,
957
+ variant: "outlined",
958
+ class: "pa-3 mb-4"
959
+ }, {
960
+ default: b(() => [
961
+ c[15] || (c[15] = a("div", { class: "text-subtitle-2 mb-1" }, "ELO ledger", -1)),
962
+ c[16] || (c[16] = a("div", { class: "text-caption text-medium-emphasis mb-3" }, " The per-response learner global-ELO exchanges that net to the session's ELO move. Wins above the learner's level pay little; losses below it cost a lot, so a high hit rate can still net negative. ", -1)),
963
+ a("div", tt, [
964
+ a("div", null, [c[13] || (c[13] = a("div", { class: "text-caption text-medium-emphasis" }, "net", -1)), a("div", { class: u(["text-h6", v(deltaClass)(w.value.net)]) }, _(v(O)(w.value.net)), 3)]),
965
+ a("div", null, [a("div", nt, "gained · " + _(w.value.wins) + " win(s)", 1), a("div", rt, _(v(O)(w.value.gained)), 1)]),
966
+ a("div", null, [a("div", it, "lost · " + _(w.value.losses) + " loss(es)", 1), a("div", at, _(v(O)(w.value.lost)), 1)]),
967
+ a("div", null, [
968
+ c[14] || (c[14] = a("div", { class: "text-caption text-medium-emphasis" }, "exchanges", -1)),
969
+ a("div", ot, _(w.value.count), 1),
970
+ a("div", st, "of " + _(E.value) + " response(s)", 1)
971
+ ])
972
+ ])
973
+ ]),
974
+ _: 1
975
+ })) : r("", !0),
976
+ a("div", ct, [c[17] || (c[17] = a("h2", { class: "text-h6" }, "Timeline", -1)), s(W, {
977
+ modelValue: A.value,
978
+ "onUpdate:modelValue": c[1] || (c[1] = (e) => A.value = e),
979
+ density: "compact",
980
+ color: "primary",
981
+ variant: "outlined"
982
+ }, {
983
+ default: b(() => [
984
+ s(k, {
985
+ value: "all",
986
+ size: "small"
987
+ }, {
988
+ default: b(() => [o("All (" + _(y.value.timeline.length) + ")", 1)]),
989
+ _: 1
990
+ }),
991
+ s(k, {
992
+ value: "response",
993
+ size: "small"
994
+ }, {
995
+ default: b(() => [o("Responses (" + _(E.value) + ")", 1)]),
996
+ _: 1
997
+ }),
998
+ s(k, {
999
+ value: "run",
1000
+ size: "small"
1001
+ }, {
1002
+ default: b(() => [o("Runs (" + _(y.value.timeline.length - E.value) + ")", 1)]),
1003
+ _: 1
1004
+ })
1005
+ ]),
1006
+ _: 1
1007
+ }, 8, ["modelValue"])]),
1008
+ y.value.timeline.length === 0 ? (f(), n(l, {
1009
+ key: 3,
1010
+ type: "info",
1011
+ variant: "tonal"
1012
+ }, {
1013
+ default: b(() => c[18] || (c[18] = [o("Nothing recorded for this session.")])),
1014
+ _: 1
1015
+ })) : (f(), i("div", lt, [(f(!0), i(e, null, m(M.value, (l, h) => (f(), i("div", {
1016
+ key: h,
1017
+ class: u(["sk-tl-row", rowClass(l)])
1018
+ }, [
1019
+ a("div", ut, _(v(fmtClock)(l.at)), 1),
1020
+ a("div", dt, [s(p, {
1021
+ size: "small",
1022
+ color: entryColor(l)
1023
+ }, {
1024
+ default: b(() => [o(_(entryIcon(l)), 1)]),
1025
+ _: 2
1026
+ }, 1032, ["color"])]),
1027
+ l.kind === "run" ? (f(), i("div", ft, [a("div", pt, [
1028
+ a("span", mt, _(l.run.label), 1),
1029
+ l.run.mode ? (f(), n(d, {
1030
+ key: 0,
1031
+ size: "x-small",
1032
+ variant: "tonal"
1033
+ }, {
1034
+ default: b(() => [o(_(l.run.mode), 1)]),
1035
+ _: 2
1036
+ }, 1024)) : r("", !0),
1037
+ a("span", ht, " generated " + _(l.run.generatedCount) + " → selected " + _(l.run.finalCount) + " (" + _(l.run.newSelected) + " new, " + _(l.run.reviewsSelected) + " review) ", 1),
1038
+ l.run.generatedCount > 0 && l.run.finalCount === 0 ? (f(), i("span", gt, " nothing survived ")) : r("", !0),
1039
+ typeof l.run.userElo == "number" ? (f(), n(d, {
1040
+ key: 2,
1041
+ size: "x-small",
1042
+ variant: "tonal",
1043
+ color: "grey",
1044
+ class: "ml-2"
1045
+ }, {
1046
+ default: b(() => [o(" ELO " + _(Math.round(l.run.userElo)), 1)]),
1047
+ _: 2
1048
+ }, 1024)) : r("", !0),
1049
+ s(T),
1050
+ s(k, {
1051
+ icon: N.value.has(l.run.runId) ? "mdi-chevron-up" : "mdi-chevron-down",
1052
+ size: "x-small",
1053
+ variant: "text",
1054
+ onClick: (e) => toggle(l.run.runId)
1055
+ }, null, 8, ["icon", "onClick"]),
1056
+ s(k, {
1057
+ icon: v(B) === l.run.runId ? "mdi-check" : "mdi-content-copy",
1058
+ size: "x-small",
1059
+ variant: "text",
1060
+ color: v(B) === l.run.runId ? "success" : void 0,
1061
+ title: "Copy run as text",
1062
+ onClick: (e) => v(V)(v(P)(l.run), l.run.runId)
1063
+ }, null, 8, [
1064
+ "icon",
1065
+ "color",
1066
+ "onClick"
1067
+ ])
1068
+ ]), N.value.has(l.run.runId) ? (f(), n(X, {
1069
+ key: 0,
1070
+ run: l.run,
1071
+ class: "mt-1",
1072
+ onOpenCard: c[2] || (c[2] = (e) => g("open-card", e))
1073
+ }, null, 8, ["run"])) : r("", !0)])) : (f(), i("div", _t, [
1074
+ a("a", {
1075
+ class: "sk-card-link",
1076
+ title: `Open ${l.cardId} in card history`,
1077
+ onClick: (e) => g("open-card", l.cardId)
1078
+ }, [o(_(l.questionType ?? "card") + " ", 1), a("code", yt, _(v(shortId)(l.cardId)), 1)], 8, vt),
1079
+ (f(!0), i(e, null, m(skillTags(l.tags), (e) => (f(), n(d, {
1080
+ key: e,
1081
+ size: "x-small",
1082
+ variant: "outlined",
1083
+ color: "primary",
1084
+ class: "ml-1"
1085
+ }, {
1086
+ default: b(() => [o(_(v(z)(t.interpreters, e)), 1)]),
1087
+ _: 2
1088
+ }, 1024))), 128)),
1089
+ a("span", bt, [o(_((l.timeSpentMs / 1e3).toFixed(1)) + "s ", 1), l.priorAttempts ? (f(), i(e, { key: 0 }, [o(" · attempt " + _(l.priorAttempts + 1), 1)], 64)) : r("", !0)]),
1090
+ l.userAnswer == null ? r("", !0) : (f(), i("span", xt, "“" + _(v(D)(l.userAnswer)) + "”", 1)),
1091
+ l.elo ? (f(), i(e, { key: 1 }, [s(d, {
1092
+ size: "x-small",
1093
+ variant: "tonal",
1094
+ color: v(deltaColor)(l.elo.global.delta),
1095
+ class: "ml-2",
1096
+ title: `learner global ELO ${l.elo.global.before} → ${l.elo.global.after} · userScore ${l.elo.userScore.toFixed(2)}`
1097
+ }, {
1098
+ default: b(() => [o(" ELO " + _(v(O)(l.elo.global.delta)), 1)]),
1099
+ _: 2
1100
+ }, 1032, ["color", "title"]), (f(!0), i(e, null, m(v(F)(l.elo), (e) => (f(), n(d, {
1101
+ key: e.tag,
1102
+ size: "x-small",
1103
+ variant: "text",
1104
+ color: v(deltaColor)(e.delta),
1105
+ class: "sk-elo-tag",
1106
+ title: `${e.tag}: ${e.before} → ${e.after} (score ${e.score?.toFixed(2)})`
1107
+ }, {
1108
+ default: b(() => [o(_(v(z)(t.interpreters, e.tag)) + " " + _(v(O)(e.delta)), 1)]),
1109
+ _: 2
1110
+ }, 1032, ["color", "title"]))), 128))], 64)) : r("", !0)
1111
+ ]))
1112
+ ], 2))), 128))]))
1113
+ ], 64)) : (f(), n(l, {
1114
+ key: 0,
1115
+ type: "info",
1116
+ variant: "tonal"
1117
+ }, {
1118
+ default: b(() => [o("No session with id " + _(t.sessionId) + ".", 1)]),
1119
+ _: 1
1120
+ }))]);
1121
+ };
1122
+ }
1123
+ }), [["__scopeId", "data-v-36c9215c"]]), St = { class: "text-h6" }, Ct = { class: "text-caption" }, wt = { class: "d-flex align-center flex-wrap mb-3 ga-3" }, Tt = ["onClick"], Et = { class: "text-no-wrap" }, Dt = { class: "text-right" }, Q = { class: "text-right" }, Ot = {
1124
+ key: 1,
1125
+ class: "text-disabled"
1126
+ }, kt = { class: "text-right" }, At = { class: "text-no-wrap text-caption" }, jt = { class: "text-no-wrap text-caption" }, Mt = { key: 0 }, Nt = {
1127
+ key: 0,
1128
+ class: "text-disabled"
1129
+ }, Pt = { class: "text-right" }, $ = /* @__PURE__ */ q(/* @__PURE__ */ c({
1130
+ __name: "LearnerSessionList",
1131
+ props: {
1132
+ dataset: {},
1133
+ interpreters: {}
1134
+ },
1135
+ emits: ["open"],
1136
+ setup(c, { emit: l }) {
1137
+ let d = c, g = l, y = t(() => B(d.dataset, d.interpreters)), x = p("all"), C = t(() => {
1138
+ let e = /* @__PURE__ */ new Map();
1139
+ for (let t of y.value) for (let n of t.flags) e.set(n, (e.get(n) ?? 0) + 1);
1140
+ return [...e.entries()].map(([e, t]) => ({
1141
+ flag: e,
1142
+ count: t
1143
+ })).sort((e, t) => t.count - e.count);
1144
+ }), w = t(() => !x.value || x.value === "all" ? y.value : y.value.filter((e) => e.flags.includes(x.value))), T = t(() => {
1145
+ let e = y.value, t = e.filter((e) => e.doc.status === "closed").length, n = e.reduce((e, t) => e + (t.doc.tally?.responses ?? 0), 0), r = e.reduce((e, t) => e + (t.doc.tally?.correct ?? 0), 0), i = e.reduce((e, t) => e + (t.durationSeconds ?? 0), 0);
1146
+ return [
1147
+ {
1148
+ label: "sessions",
1149
+ value: e.length,
1150
+ color: "primary"
1151
+ },
1152
+ {
1153
+ label: "completed",
1154
+ value: t,
1155
+ color: "success"
1156
+ },
1157
+ {
1158
+ label: "not completed",
1159
+ value: e.length - t,
1160
+ color: "error"
1161
+ },
1162
+ {
1163
+ label: "responses",
1164
+ value: n,
1165
+ color: "primary"
1166
+ },
1167
+ {
1168
+ label: "overall acc.",
1169
+ value: n > 0 ? `${Math.round(r / n * 100)}%` : "—",
1170
+ color: "primary"
1171
+ },
1172
+ {
1173
+ label: "time studied",
1174
+ value: k(i),
1175
+ color: "grey"
1176
+ }
1177
+ ];
1178
+ });
1179
+ function deltas(e) {
1180
+ let t = [];
1181
+ e.eloNet !== null && t.push({
1182
+ label: "elo",
1183
+ delta: Math.round(e.eloNet)
1184
+ });
1185
+ for (let n of d.interpreters?.progressMetrics ?? []) {
1186
+ let r = e.state.find((e) => e.label === n);
1187
+ r && t.push({
1188
+ label: n,
1189
+ delta: r.delta
1190
+ });
1191
+ }
1192
+ return t;
1193
+ }
1194
+ function clockText(e) {
1195
+ let t = k(e.doc.plannedSeconds);
1196
+ return e.durationSeconds === null ? `— of ${t}` : `${k(e.durationSeconds)} of ${t}`;
1197
+ }
1198
+ return (t, c) => {
1199
+ let l = h("v-card"), d = h("v-col"), p = h("v-row"), E = h("v-btn"), D = h("v-icon"), k = h("v-btn-toggle"), A = h("v-alert"), j = h("v-chip"), M = h("v-table");
1200
+ return f(), i("div", null, [
1201
+ c[4] || (c[4] = a("p", { class: "text-caption text-medium-emphasis mb-4" }, [
1202
+ o(" One row per sitting. Flags name a specific way the session failed to do its job; open one to read its interleaved timeline of responses and pipeline runs. "),
1203
+ a("strong", null, "Δ"),
1204
+ o(" is movement across the session: ELO, then any progress metrics the course declares. ")
1205
+ ], -1)),
1206
+ s(p, {
1207
+ dense: "",
1208
+ class: "mb-2"
1209
+ }, {
1210
+ default: b(() => [(f(!0), i(e, null, m(T.value, (e) => (f(), n(d, {
1211
+ key: e.label,
1212
+ cols: "6",
1213
+ sm: "4",
1214
+ md: "2"
1215
+ }, {
1216
+ default: b(() => [s(l, {
1217
+ variant: "tonal",
1218
+ color: e.color,
1219
+ class: "pa-2 text-center"
1220
+ }, {
1221
+ default: b(() => [a("div", St, _(e.value), 1), a("div", Ct, _(e.label), 1)]),
1222
+ _: 2
1223
+ }, 1032, ["color"])]),
1224
+ _: 2
1225
+ }, 1024))), 128))]),
1226
+ _: 1
1227
+ }),
1228
+ a("div", wt, [s(k, {
1229
+ modelValue: x.value,
1230
+ "onUpdate:modelValue": c[0] || (c[0] = (e) => x.value = e),
1231
+ density: "compact",
1232
+ color: "primary",
1233
+ variant: "outlined"
1234
+ }, {
1235
+ default: b(() => [s(E, {
1236
+ value: "all",
1237
+ size: "small"
1238
+ }, {
1239
+ default: b(() => [o("All (" + _(y.value.length) + ")", 1)]),
1240
+ _: 1
1241
+ }), (f(!0), i(e, null, m(C.value, (e) => (f(), n(E, {
1242
+ key: e.flag,
1243
+ value: e.flag,
1244
+ size: "small",
1245
+ title: v(S)[e.flag].help
1246
+ }, {
1247
+ default: b(() => [s(D, {
1248
+ start: "",
1249
+ size: "small",
1250
+ color: v(G)[e.flag].color
1251
+ }, {
1252
+ default: b(() => [o(_(v(G)[e.flag].icon), 1)]),
1253
+ _: 2
1254
+ }, 1032, ["color"]), o(" " + _(v(S)[e.flag].label) + " (" + _(e.count) + ") ", 1)]),
1255
+ _: 2
1256
+ }, 1032, ["value", "title"]))), 128))]),
1257
+ _: 1
1258
+ }, 8, ["modelValue"])]),
1259
+ y.value.length === 0 ? (f(), n(A, {
1260
+ key: 0,
1261
+ type: "info",
1262
+ variant: "tonal"
1263
+ }, {
1264
+ default: b(() => c[1] || (c[1] = [o(" No study sessions recorded. Session records began with a framework release; there is no backfill, so earlier activity shows only in card history. ")])),
1265
+ _: 1
1266
+ })) : (f(), n(M, {
1267
+ key: 1,
1268
+ density: "compact",
1269
+ class: "sk-admin-table"
1270
+ }, {
1271
+ default: b(() => [c[3] || (c[3] = a("thead", null, [a("tr", null, [
1272
+ a("th", null, "Started"),
1273
+ a("th", null, "Status"),
1274
+ a("th", { class: "text-right" }, "Cards"),
1275
+ a("th", { class: "text-right" }, "Acc."),
1276
+ a("th", { class: "text-right" }, "Runs"),
1277
+ a("th", null, "Clock"),
1278
+ a("th", null, "Δ"),
1279
+ a("th", null, "Flags"),
1280
+ a("th")
1281
+ ])], -1)), a("tbody", null, [(f(!0), i(e, null, m(w.value, (t) => (f(), i("tr", {
1282
+ key: t.doc.sessionId,
1283
+ class: "sk-admin-row",
1284
+ onClick: (e) => g("open", t.doc.sessionId)
1285
+ }, [
1286
+ a("td", Et, _(v(fmtTime)(t.doc.startTime)), 1),
1287
+ a("td", null, [s(j, {
1288
+ size: "x-small",
1289
+ variant: "flat",
1290
+ color: v(statusColor)(t.doc.status)
1291
+ }, {
1292
+ default: b(() => [o(_(t.doc.status), 1)]),
1293
+ _: 2
1294
+ }, 1032, ["color"])]),
1295
+ a("td", Dt, _(t.doc.tally?.cardsPresented ?? "—"), 1),
1296
+ a("td", Q, [t.accuracy === null ? (f(), i("span", Ot, "—")) : (f(), i("span", {
1297
+ key: 0,
1298
+ class: u(v(accuracyClass)(t.accuracy))
1299
+ }, _(Math.round(t.accuracy * 100)) + "% ", 3))]),
1300
+ a("td", kt, _(t.doc.runs?.length ?? 0), 1),
1301
+ a("td", At, _(clockText(t)), 1),
1302
+ a("td", jt, [(f(!0), i(e, null, m(deltas(t), (t, n) => (f(), i(e, { key: t.label }, [n > 0 ? (f(), i("span", Mt, " · ")) : r("", !0), a("span", { class: u(v(deltaClass)(t.delta)) }, _(v(O)(t.delta)) + "\xA0" + _(t.label), 3)], 64))), 128)), deltas(t).length === 0 ? (f(), i("span", Nt, "—")) : r("", !0)]),
1303
+ a("td", null, [(f(!0), i(e, null, m(t.flags, (e) => (f(), n(D, {
1304
+ key: e,
1305
+ size: "small",
1306
+ class: "mr-1",
1307
+ color: v(G)[e].color,
1308
+ title: `${v(S)[e].label}: ${v(S)[e].help}`
1309
+ }, {
1310
+ default: b(() => [o(_(v(G)[e].icon), 1)]),
1311
+ _: 2
1312
+ }, 1032, ["color", "title"]))), 128))]),
1313
+ a("td", Pt, [s(D, {
1314
+ size: "small",
1315
+ class: "text-disabled"
1316
+ }, {
1317
+ default: b(() => c[2] || (c[2] = [o("mdi-chevron-right")])),
1318
+ _: 1
1319
+ })])
1320
+ ], 8, Tt))), 128))])]),
1321
+ _: 1
1322
+ }))
1323
+ ]);
1324
+ };
1325
+ }
1326
+ }), [["__scopeId", "data-v-5c46cc58"]]), Ft = /* @__PURE__ */ c({
1327
+ __name: "LearnerDiagnostics",
1328
+ props: {
1329
+ dataset: {},
1330
+ interpreters: {}
1331
+ },
1332
+ setup(t) {
1333
+ let r = t, a = p("sessions"), c = p(null), l = p(void 0);
1334
+ function openCard(e) {
1335
+ l.value = void 0, a.value = "cards", setTimeout(() => l.value = e);
1336
+ }
1337
+ return y(() => r.dataset, () => {
1338
+ a.value = "sessions", c.value = null, l.value = void 0;
1339
+ }), (t, r) => {
1340
+ let u = h("v-tab"), d = h("v-tabs"), p = h("v-btn");
1341
+ return f(), i("div", null, [s(d, {
1342
+ modelValue: a.value,
1343
+ "onUpdate:modelValue": r[0] || (r[0] = (e) => a.value = e),
1344
+ density: "compact",
1345
+ class: "mb-4"
1346
+ }, {
1347
+ default: b(() => [s(u, { value: "sessions" }, {
1348
+ default: b(() => [o("Sessions (" + _(t.dataset.sessions.length) + ")", 1)]),
1349
+ _: 1
1350
+ }), s(u, { value: "cards" }, {
1351
+ default: b(() => [o("Cards (" + _(t.dataset.cardHistories.length) + ")", 1)]),
1352
+ _: 1
1353
+ })]),
1354
+ _: 1
1355
+ }, 8, ["modelValue"]), a.value === "sessions" ? (f(), i(e, { key: 0 }, [c.value ? (f(), i(e, { key: 0 }, [s(p, {
1356
+ variant: "text",
1357
+ size: "small",
1358
+ "prepend-icon": "mdi-arrow-left",
1359
+ class: "mb-2",
1360
+ onClick: r[1] || (r[1] = (e) => c.value = null)
1361
+ }, {
1362
+ default: b(() => r[3] || (r[3] = [o(" All sessions ")])),
1363
+ _: 1
1364
+ }), s(Z, {
1365
+ dataset: t.dataset,
1366
+ "session-id": c.value,
1367
+ interpreters: t.interpreters,
1368
+ onOpenCard: openCard
1369
+ }, null, 8, [
1370
+ "dataset",
1371
+ "session-id",
1372
+ "interpreters"
1373
+ ])], 64)) : (f(), n($, {
1374
+ key: 1,
1375
+ dataset: t.dataset,
1376
+ interpreters: t.interpreters,
1377
+ onOpen: r[2] || (r[2] = (e) => c.value = e)
1378
+ }, null, 8, ["dataset", "interpreters"]))], 64)) : (f(), n(Y, {
1379
+ key: 1,
1380
+ dataset: t.dataset,
1381
+ interpreters: t.interpreters,
1382
+ focus: l.value
1383
+ }, null, 8, [
1384
+ "dataset",
1385
+ "interpreters",
1386
+ "focus"
1387
+ ]))]);
1388
+ };
1389
+ }
1390
+ });
1391
+ //#endregion
1392
+ export { J as CardDossierDetail, Y as LearnerCardHistory, W as LearnerDatasetSource, Ft as LearnerDiagnostics, Z as LearnerSessionDetail, $ as LearnerSessionList, X as RunDetail, downloadLearnerDump, useLearnerDataset };
1393
+
1394
+ //# sourceMappingURL=common-ui-admin.es.js.map