@vue-skuilder/common-ui 0.2.34 → 0.2.36
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/_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs +13 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPrimitive.mjs +15 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPropertyKey.mjs +10 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/typeof.mjs +12 -0
- package/dist/_virtual/_plugin-vue_export-helper.mjs +9 -0
- package/dist/_virtual/_rolldown/runtime.mjs +7 -0
- package/dist/admin/admin.css +1 -1
- package/dist/admin/common-ui-admin.es.js +1074 -473
- package/dist/admin/common-ui-admin.es.js.map +1 -1
- package/dist/admin/components/EChart.vue.d.ts +14 -0
- package/dist/admin/components/EChart.vue.d.ts.map +1 -0
- package/dist/admin/components/LearnerDiagnostics.vue.d.ts +3 -3
- package/dist/admin/components/LearnerDiagnostics.vue.d.ts.map +1 -1
- package/dist/admin/components/LearnerTagElo.vue.d.ts +14 -0
- package/dist/admin/components/LearnerTagElo.vue.d.ts.map +1 -0
- package/dist/admin/index.d.ts +1 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/assets/index.css +2 -1
- package/dist/components/CardBrowser.mjs +63 -0
- package/dist/components/CardBrowser.mjs.map +1 -0
- package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs +50 -0
- package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardHistoryViewer.mjs +70 -0
- package/dist/components/CardHistoryViewer.mjs.map +1 -0
- package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs +108 -0
- package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardSearch.mjs +26 -0
- package/dist/components/CardSearch.mjs.map +1 -0
- package/dist/components/CardSearch.vue_vue_type_script_lang.mjs +17 -0
- package/dist/components/CardSearch.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardSearchResults.mjs +32 -0
- package/dist/components/CardSearchResults.mjs.map +1 -0
- package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs +71 -0
- package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseCardBrowser.mjs +175 -0
- package/dist/components/CourseCardBrowser.mjs.map +1 -0
- package/dist/components/CourseCardBrowser.vue.d.ts +3 -3
- package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs +173 -0
- package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseInformation.mjs +132 -0
- package/dist/components/CourseInformation.mjs.map +1 -0
- package/dist/components/CourseInformation.vue.d.ts +3 -3
- package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs +56 -0
- package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseTagFilterWidget.mjs +114 -0
- package/dist/components/CourseTagFilterWidget.mjs.map +1 -0
- package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs +65 -0
- package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/HeatMap.mjs +40 -0
- package/dist/components/HeatMap.mjs.map +1 -0
- package/dist/components/HeatMap.vue_vue_type_script_lang.mjs +211 -0
- package/dist/components/HeatMap.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/PaginatingToolbar.mjs +94 -0
- package/dist/components/PaginatingToolbar.mjs.map +1 -0
- package/dist/components/PaginatingToolbar.vue.d.ts +3 -3
- package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs +36 -0
- package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SessionControllerDebug.mjs +130 -0
- package/dist/components/SessionControllerDebug.mjs.map +1 -0
- package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs +45 -0
- package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SkMouseTrap.mjs +66 -0
- package/dist/components/SkMouseTrap.mjs.map +1 -0
- package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs +31 -0
- package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SkMouseTrapToolTip.mjs +28 -0
- package/dist/components/SkMouseTrapToolTip.mjs.map +1 -0
- package/dist/components/SkMouseTrapToolTip.vue.d.ts +1 -1
- package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs +91 -0
- package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SnackbarService.mjs +24 -0
- package/dist/components/SnackbarService.mjs.map +1 -0
- package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs +34 -0
- package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SnackbarService2.mjs +40 -0
- package/dist/components/SnackbarService2.mjs.map +1 -0
- package/dist/components/StudySession.mjs +123 -0
- package/dist/components/StudySession.mjs.map +1 -0
- package/dist/components/StudySession.vue_vue_type_script_lang.mjs +280 -0
- package/dist/components/StudySession.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/StudySessionTimer.mjs +50 -0
- package/dist/components/StudySessionTimer.mjs.map +1 -0
- package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs +43 -0
- package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/TagsInput.mjs +45 -0
- package/dist/components/TagsInput.mjs.map +1 -0
- package/dist/components/TagsInput.vue_vue_type_script_lang.mjs +117 -0
- package/dist/components/TagsInput.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/UserTagPreferences.mjs +205 -0
- package/dist/components/UserTagPreferences.mjs.map +1 -0
- package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs +139 -0
- package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/RequestPasswordReset.mjs +96 -0
- package/dist/components/auth/RequestPasswordReset.mjs.map +1 -0
- package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs +47 -0
- package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/ResetPassword.mjs +129 -0
- package/dist/components/auth/ResetPassword.mjs.map +1 -0
- package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs +69 -0
- package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/UserChip.mjs +9 -0
- package/dist/components/auth/UserChip.mjs.map +1 -0
- package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs +213 -0
- package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserLogin.mjs +9 -0
- package/dist/components/auth/UserLogin.mjs.map +1 -0
- package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs +155 -0
- package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.mjs +9 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.mjs.map +1 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs +126 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserRegistration.mjs +147 -0
- package/dist/components/auth/UserRegistration.mjs.map +1 -0
- package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs +130 -0
- package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/VerifyEmail.mjs +118 -0
- package/dist/components/auth/VerifyEmail.mjs.map +1 -0
- package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs +59 -0
- package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/AudioAutoPlayer.mjs +9 -0
- package/dist/components/cardRendering/AudioAutoPlayer.mjs.map +1 -0
- package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs +69 -0
- package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CardLoader.mjs +31 -0
- package/dist/components/cardRendering/CardLoader.mjs.map +1 -0
- package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs +75 -0
- package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CardViewer.mjs +39 -0
- package/dist/components/cardRendering/CardViewer.mjs.map +1 -0
- package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs +66 -0
- package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CodeBlockRenderer.mjs +8 -0
- package/dist/components/cardRendering/CodeBlockRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs +44 -0
- package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRenderer.mjs +21 -0
- package/dist/components/cardRendering/MarkdownRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs +24 -0
- package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRendererHelpers.mjs +79 -0
- package/dist/components/cardRendering/MarkdownRendererHelpers.mjs.map +1 -0
- package/dist/components/cardRendering/MdTokenRenderer.mjs +9 -0
- package/dist/components/cardRendering/MdTokenRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs +176 -0
- package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/studentInputs/BaseUserInput.mjs +54 -0
- package/dist/components/studentInputs/BaseUserInput.mjs.map +1 -0
- package/dist/components/studentInputs/MultipleChoiceOption.mjs +26 -0
- package/dist/components/studentInputs/MultipleChoiceOption.mjs.map +1 -0
- package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs +76 -0
- package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/RadioMultipleChoice.mjs +33 -0
- package/dist/components/studentInputs/RadioMultipleChoice.mjs.map +1 -0
- package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs +105 -0
- package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/TrueFalse.mjs +19 -0
- package/dist/components/studentInputs/TrueFalse.mjs.map +1 -0
- package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs +21 -0
- package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputNumber.mjs +33 -0
- package/dist/components/studentInputs/UserInputNumber.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs +25 -0
- package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputString.mjs +22 -0
- package/dist/components/studentInputs/UserInputString.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs +23 -0
- package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/fillInInput.mjs +25 -0
- package/dist/components/studentInputs/fillInInput.mjs.map +1 -0
- package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs +26 -0
- package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/composables/CompositionViewable.mjs +65 -0
- package/dist/composables/CompositionViewable.mjs.map +1 -0
- package/dist/composables/Displayable.mjs +36 -0
- package/dist/composables/Displayable.mjs.map +1 -0
- package/dist/composables/useAuthUI.mjs +38 -0
- package/dist/composables/useAuthUI.mjs.map +1 -0
- package/dist/composables/useEntitlements.mjs +58 -0
- package/dist/composables/useEntitlements.mjs.map +1 -0
- package/dist/index.mjs +49 -0
- package/dist/plugins/pinia.mjs +12 -0
- package/dist/plugins/pinia.mjs.map +1 -0
- package/dist/services/authAPI.mjs +159 -0
- package/dist/services/authAPI.mjs.map +1 -0
- package/dist/stores/useAuthStore.mjs +68 -0
- package/dist/stores/useAuthStore.mjs.map +1 -0
- package/dist/stores/useCardPreviewModeStore.mjs +20 -0
- package/dist/stores/useCardPreviewModeStore.mjs.map +1 -0
- package/dist/stores/useConfigStore.mjs +60 -0
- package/dist/stores/useConfigStore.mjs.map +1 -0
- package/dist/utils/SkldrMouseTrap.mjs +48 -0
- package/dist/utils/SkldrMouseTrap.mjs.map +1 -0
- package/dist/utils/passwordValidation.mjs +12 -0
- package/dist/utils/passwordValidation.mjs.map +1 -0
- package/package.json +8 -8
- package/src/admin/components/EChart.vue +59 -0
- package/src/admin/components/LearnerDiagnostics.vue +8 -4
- package/src/admin/components/LearnerTagElo.vue +563 -0
- package/src/admin/index.ts +1 -0
- package/dist/MarkdownRenderer-U_iPiA2x.mjs +0 -4966
- package/dist/MarkdownRenderer-U_iPiA2x.mjs.map +0 -1
- package/dist/assets/MarkdownRenderer.css +0 -1
- package/dist/common-ui.es.js +0 -5090
- package/dist/common-ui.es.js.map +0 -1
- package/dist/common-ui.umd.js +0 -77
- package/dist/common-ui.umd.js.map +0 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { defineComponent as e } from "vue";
|
|
3
|
+
import t from "moment";
|
|
4
|
+
//#region src/components/HeatMap.vue?vue&type=script&lang.ts
|
|
5
|
+
var n = e({
|
|
6
|
+
name: "HeatMap",
|
|
7
|
+
props: {
|
|
8
|
+
activityRecords: {
|
|
9
|
+
type: Array,
|
|
10
|
+
default: () => []
|
|
11
|
+
},
|
|
12
|
+
activityRecordsGetter: {
|
|
13
|
+
type: Function,
|
|
14
|
+
default: null
|
|
15
|
+
},
|
|
16
|
+
inactiveColor: {
|
|
17
|
+
type: Object,
|
|
18
|
+
default: () => ({
|
|
19
|
+
h: 0,
|
|
20
|
+
s: 0,
|
|
21
|
+
l: .9
|
|
22
|
+
})
|
|
23
|
+
},
|
|
24
|
+
activeColor: {
|
|
25
|
+
type: Object,
|
|
26
|
+
default: () => ({
|
|
27
|
+
h: 155,
|
|
28
|
+
s: 1,
|
|
29
|
+
l: .5
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
cellSize: {
|
|
33
|
+
type: Number,
|
|
34
|
+
default: 12
|
|
35
|
+
},
|
|
36
|
+
cellMargin: {
|
|
37
|
+
type: Number,
|
|
38
|
+
default: 3
|
|
39
|
+
},
|
|
40
|
+
enableSeasonalColors: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: !0
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
data() {
|
|
46
|
+
return {
|
|
47
|
+
isLoading: !1,
|
|
48
|
+
localActivityRecords: [],
|
|
49
|
+
heatmapData: {},
|
|
50
|
+
weeks: [],
|
|
51
|
+
tooltipData: null,
|
|
52
|
+
tooltipStyle: {},
|
|
53
|
+
maxInRange: 0
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
computed: {
|
|
57
|
+
width() {
|
|
58
|
+
return 53 * (this.cellSize + this.cellMargin);
|
|
59
|
+
},
|
|
60
|
+
height() {
|
|
61
|
+
return 7 * (this.cellSize + this.cellMargin);
|
|
62
|
+
},
|
|
63
|
+
effectiveActivityRecords() {
|
|
64
|
+
let e = Array.isArray(this.localActivityRecords) && this.localActivityRecords.length > 0, t = e ? this.localActivityRecords : this.activityRecords || [];
|
|
65
|
+
return console.log("Using effectiveActivityRecords, count:", t.length, "source:", e ? "local" : "prop"), t;
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
watch: { activityRecords: {
|
|
69
|
+
handler() {
|
|
70
|
+
this.processRecords(), this.createWeeksData();
|
|
71
|
+
},
|
|
72
|
+
immediate: !0
|
|
73
|
+
} },
|
|
74
|
+
async created() {
|
|
75
|
+
if (this.activityRecordsGetter) try {
|
|
76
|
+
this.isLoading = !0, console.log("Fetching activity records using getter...");
|
|
77
|
+
let e = await this.activityRecordsGetter();
|
|
78
|
+
Array.isArray(e) ? (this.localActivityRecords = e.filter((e) => {
|
|
79
|
+
if (!e || !e.timeStamp) return !1;
|
|
80
|
+
try {
|
|
81
|
+
let n = t(e.timeStamp);
|
|
82
|
+
return n.isValid() && n.year() > 2e3 && n.year() < 2100;
|
|
83
|
+
} catch {
|
|
84
|
+
return !1;
|
|
85
|
+
}
|
|
86
|
+
}), console.log(`Received ${e.length} records, ${this.localActivityRecords.length} valid after filtering`), this.processRecords(), this.createWeeksData()) : (console.error("Activity records getter did not return an array:", e), this.localActivityRecords = []);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("Error fetching activity records:", e), this.localActivityRecords = [];
|
|
89
|
+
} finally {
|
|
90
|
+
this.isLoading = !1;
|
|
91
|
+
}
|
|
92
|
+
else console.log("No activityRecordsGetter provided, using direct activityRecords prop");
|
|
93
|
+
},
|
|
94
|
+
methods: {
|
|
95
|
+
toDateString(e) {
|
|
96
|
+
let n = t(e);
|
|
97
|
+
return t.months()[n.month()] + " " + n.date();
|
|
98
|
+
},
|
|
99
|
+
processRecords() {
|
|
100
|
+
let e = this.effectiveActivityRecords || [];
|
|
101
|
+
console.log(`Processing ${e.length} records`);
|
|
102
|
+
let n = {};
|
|
103
|
+
if (e.length === 0) {
|
|
104
|
+
console.log("No records to process"), this.heatmapData = n;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let r = /* @__PURE__ */ new Set(), i = {}, a = 0, o = 0;
|
|
108
|
+
for (let s = 0; s < e.length; s++) {
|
|
109
|
+
let c = e[s];
|
|
110
|
+
if (!c || typeof c != "object" || !c.timeStamp) {
|
|
111
|
+
o++;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
let e;
|
|
116
|
+
if (typeof c.timeStamp == "string") e = t(c.timeStamp).format("YYYY-MM-DD");
|
|
117
|
+
else if (typeof c.timeStamp == "number") e = t(new Date(c.timeStamp)).format("YYYY-MM-DD");
|
|
118
|
+
else if (typeof c.timeStamp == "object") e = typeof c.timeStamp.format == "function" ? c.timeStamp.format("YYYY-MM-DD") : c.timeStamp instanceof Date ? t(c.timeStamp).format("YYYY-MM-DD") : t(String(c.timeStamp)).format("YYYY-MM-DD");
|
|
119
|
+
else {
|
|
120
|
+
o++;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (t(e, "YYYY-MM-DD", !0).isValid()) {
|
|
124
|
+
n[e] = (n[e] || 0) + 1, r.add(e);
|
|
125
|
+
let t = e.substring(0, 7);
|
|
126
|
+
i[t] = (i[t] || 0) + 1, a++;
|
|
127
|
+
} else o++;
|
|
128
|
+
} catch {
|
|
129
|
+
o++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
console.log(`Processed ${a} valid dates, ${o} invalid dates`), console.log(`Found ${r.size} unique dates`), console.log("Date distribution by month:", i), this.heatmapData = n;
|
|
133
|
+
},
|
|
134
|
+
createWeeksData() {
|
|
135
|
+
this.weeks = [], this.maxInRange = 0;
|
|
136
|
+
let e = t(), n = e.clone().subtract(52, "weeks"), r = n.clone().startOf("week");
|
|
137
|
+
console.log("Creating weeks data from", n.format("YYYY-MM-DD"), "to", e.format("YYYY-MM-DD")), Object.keys(this.heatmapData).length === 0 && console.log("No heatmap data available to display");
|
|
138
|
+
let i = Object.keys(this.heatmapData).slice(0, 5);
|
|
139
|
+
for (console.log("Sample dates in heatmap data:", i); r.isSameOrBefore(e);) {
|
|
140
|
+
let e = [];
|
|
141
|
+
for (let t = 0; t < 7; t++) {
|
|
142
|
+
let t = r.format("YYYY-MM-DD"), n = {
|
|
143
|
+
date: t,
|
|
144
|
+
count: this.heatmapData[t] || 0
|
|
145
|
+
};
|
|
146
|
+
e.push(n), n.count > this.maxInRange && (this.maxInRange = n.count), r.add(1, "day");
|
|
147
|
+
}
|
|
148
|
+
this.weeks.push(e);
|
|
149
|
+
}
|
|
150
|
+
console.log("Weeks data created, maxInRange:", this.maxInRange);
|
|
151
|
+
let a = 0, o = 0;
|
|
152
|
+
Object.values(this.heatmapData).forEach((e) => {
|
|
153
|
+
a++, o += e;
|
|
154
|
+
}), console.log(`Activity summary: ${o} activities across ${a} days`);
|
|
155
|
+
},
|
|
156
|
+
getColor(e) {
|
|
157
|
+
if (this.maxInRange === 0) return this.hslToString(this.inactiveColor);
|
|
158
|
+
let n = e === 0 ? 0 : Math.min(2 * e / this.maxInRange, 1), r = this.activeColor;
|
|
159
|
+
if (this.enableSeasonalColors) {
|
|
160
|
+
let e = t();
|
|
161
|
+
e.month() === 11 && e.date() >= 5 ? r = Math.random() > .5 ? {
|
|
162
|
+
h: 350,
|
|
163
|
+
s: .8,
|
|
164
|
+
l: .5
|
|
165
|
+
} : {
|
|
166
|
+
h: 135,
|
|
167
|
+
s: .8,
|
|
168
|
+
l: .4
|
|
169
|
+
} : e.month() === 9 && e.date() >= 25 && (r = Math.random() > .5 ? {
|
|
170
|
+
h: 0,
|
|
171
|
+
s: 0,
|
|
172
|
+
l: 0
|
|
173
|
+
} : Math.random() > .5 ? {
|
|
174
|
+
h: 30,
|
|
175
|
+
s: 1,
|
|
176
|
+
l: .5
|
|
177
|
+
} : {
|
|
178
|
+
h: 270,
|
|
179
|
+
s: 1,
|
|
180
|
+
l: .5
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
let i = r.h, a = this.interpolate(this.inactiveColor.s, r.s, n), o = this.interpolate(this.inactiveColor.l, r.l, n);
|
|
184
|
+
return this.hslToString({
|
|
185
|
+
h: i,
|
|
186
|
+
s: a,
|
|
187
|
+
l: o
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
interpolate(e, t, n) {
|
|
191
|
+
return e + (t - e) * n;
|
|
192
|
+
},
|
|
193
|
+
hslToString(e) {
|
|
194
|
+
return `hsl(${e.h}, ${e.s * 100}%, ${e.l * 100}%)`;
|
|
195
|
+
},
|
|
196
|
+
showTooltip(e, t) {
|
|
197
|
+
this.tooltipData = e, this.tooltipStyle = {
|
|
198
|
+
position: "absolute",
|
|
199
|
+
left: `${t.pageX + 10}px`,
|
|
200
|
+
top: `${t.pageY + 10}px`
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
hideTooltip() {
|
|
204
|
+
this.tooltipData = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
//#endregion
|
|
209
|
+
export { n as default };
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=HeatMap.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeatMap.vue_vue_type_script_lang.mjs","names":[],"sources":["../../src/components/HeatMap.vue"],"sourcesContent":["<template>\n <div>\n <svg :width=\"width\" :height=\"height\">\n <g\n v-for=\"(week, weekIndex) in weeks\"\n :key=\"weekIndex\"\n :transform=\"`translate(${weekIndex * (cellSize + cellMargin)}, 0)`\"\n >\n <rect\n v-for=\"(day, dayIndex) in week\"\n :key=\"day.date\"\n :x=\"0\"\n :y=\"dayIndex * (cellSize + cellMargin)\"\n :width=\"cellSize\"\n :height=\"cellSize\"\n :fill=\"getColor(day.count)\"\n @mouseover=\"showTooltip(day, $event)\"\n @mouseout=\"hideTooltip\"\n />\n </g>\n </svg>\n <div v-if=\"tooltipData\" class=\"tooltip\" :style=\"tooltipStyle\">\n {{ tooltipData.count }} review{{ tooltipData.count !== 1 ? 's' : '' }} on {{ toDateString(tooltipData.date) }}\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType } from 'vue';\nimport moment from 'moment';\nimport { DayData, Color, ActivityRecord } from './HeatMap.types';\n\nexport default defineComponent({\n name: 'HeatMap',\n\n props: {\n // Accept activity records directly as a prop\n activityRecords: {\n type: Array as PropType<ActivityRecord[]>,\n default: () => [],\n },\n // Accept a function that can retrieve activity records\n activityRecordsGetter: {\n type: Function as PropType<() => Promise<ActivityRecord[]>>,\n default: null,\n },\n // Customize colors\n inactiveColor: {\n type: Object as PropType<Color>,\n default: () => ({ h: 0, s: 0, l: 0.9 }),\n },\n activeColor: {\n type: Object as PropType<Color>,\n default: () => ({ h: 155, s: 1, l: 0.5 }),\n },\n // Customize size\n cellSize: {\n type: Number,\n default: 12,\n },\n cellMargin: {\n type: Number,\n default: 3,\n },\n // Enable/disable seasonal colors\n enableSeasonalColors: {\n type: Boolean,\n default: true,\n },\n },\n\n data() {\n return {\n isLoading: false,\n localActivityRecords: [] as ActivityRecord[],\n heatmapData: {} as { [key: string]: number },\n weeks: [] as DayData[][],\n tooltipData: null as DayData | null,\n tooltipStyle: {} as { [key: string]: string },\n maxInRange: 0,\n };\n },\n\n computed: {\n width(): number {\n return 53 * (this.cellSize + this.cellMargin);\n },\n height(): number {\n return 7 * (this.cellSize + this.cellMargin);\n },\n effectiveActivityRecords(): ActivityRecord[] {\n const useLocal = Array.isArray(this.localActivityRecords) && this.localActivityRecords.length > 0;\n const records = useLocal ? this.localActivityRecords : this.activityRecords || [];\n console.log('Using effectiveActivityRecords, count:', records.length, 'source:', useLocal ? 'local' : 'prop');\n return records;\n },\n },\n\n watch: {\n activityRecords: {\n handler() {\n this.processRecords();\n this.createWeeksData();\n },\n immediate: true,\n },\n },\n\n async created() {\n if (this.activityRecordsGetter) {\n try {\n this.isLoading = true;\n console.log('Fetching activity records using getter...');\n \n // Ensure the getter is called safely with proper error handling\n let result = await this.activityRecordsGetter();\n \n // Handle the result - ensure it's an array of activity records\n if (Array.isArray(result)) {\n // Filter out records with invalid timestamps before processing\n this.localActivityRecords = result.filter(record => {\n if (!record || !record.timeStamp) return false;\n \n // Basic validation check for timestamps\n try {\n const m = moment(record.timeStamp);\n return m.isValid() && m.year() > 2000 && m.year() < 2100;\n } catch (e) {\n return false;\n }\n });\n \n console.log(`Received ${result.length} records, ${this.localActivityRecords.length} valid after filtering`);\n \n // Process the loaded records\n this.processRecords();\n this.createWeeksData();\n } else {\n console.error('Activity records getter did not return an array:', result);\n this.localActivityRecords = [];\n }\n } catch (error) {\n console.error('Error fetching activity records:', error);\n this.localActivityRecords = [];\n } finally {\n this.isLoading = false;\n }\n } else {\n console.log('No activityRecordsGetter provided, using direct activityRecords prop');\n }\n },\n\n methods: {\n toDateString(d: string): string {\n const m = moment(d);\n return moment.months()[m.month()] + ' ' + m.date();\n },\n\n processRecords() {\n const records = this.effectiveActivityRecords || [];\n console.log(`Processing ${records.length} records`);\n\n const data: { [key: string]: number } = {};\n\n if (records.length === 0) {\n console.log('No records to process');\n this.heatmapData = data;\n return;\n }\n\n // Sample logging of a few records to understand structure without flooding console\n const uniqueDates = new Set<string>();\n const dateDistribution: Record<string, number> = {};\n let validCount = 0;\n let invalidCount = 0;\n \n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n \n if (!record || typeof record !== 'object' || !record.timeStamp) {\n invalidCount++;\n continue;\n }\n \n try {\n // Attempt to normalize the timestamp\n let normalizedDate: string;\n \n if (typeof record.timeStamp === 'string') {\n // For ISO strings, parse directly with moment\n normalizedDate = moment(record.timeStamp).format('YYYY-MM-DD');\n } else if (typeof record.timeStamp === 'number') {\n // For numeric timestamps, use Date constructor then moment\n normalizedDate = moment(new Date(record.timeStamp)).format('YYYY-MM-DD');\n } else if (typeof record.timeStamp === 'object') {\n // For objects (like Moment), try toString() or direct parsing\n if (typeof record.timeStamp.format === 'function') {\n // It's likely a Moment object\n normalizedDate = record.timeStamp.format('YYYY-MM-DD');\n } else if (record.timeStamp instanceof Date) {\n normalizedDate = moment(record.timeStamp).format('YYYY-MM-DD');\n } else {\n // Try to parse it as a string representation\n normalizedDate = moment(String(record.timeStamp)).format('YYYY-MM-DD');\n }\n } else {\n // Unhandled type\n invalidCount++;\n continue;\n }\n \n // Verify the date is valid before using it\n if (moment(normalizedDate, 'YYYY-MM-DD', true).isValid()) {\n data[normalizedDate] = (data[normalizedDate] || 0) + 1;\n uniqueDates.add(normalizedDate);\n \n // Track distribution by month for debugging\n const month = normalizedDate.substring(0, 7); // YYYY-MM\n dateDistribution[month] = (dateDistribution[month] || 0) + 1;\n \n validCount++;\n } else {\n invalidCount++;\n }\n } catch (e) {\n invalidCount++;\n }\n }\n \n // Log summary statistics\n console.log(`Processed ${validCount} valid dates, ${invalidCount} invalid dates`);\n console.log(`Found ${uniqueDates.size} unique dates`);\n console.log('Date distribution by month:', dateDistribution);\n\n this.heatmapData = data;\n },\n\n createWeeksData() {\n // Reset weeks and max count\n this.weeks = [];\n this.maxInRange = 0;\n \n const end = moment();\n const start = end.clone().subtract(52, 'weeks');\n const day = start.clone().startOf('week');\n \n console.log('Creating weeks data from', start.format('YYYY-MM-DD'), 'to', end.format('YYYY-MM-DD'));\n \n // Ensure we have data to display\n if (Object.keys(this.heatmapData).length === 0) {\n console.log('No heatmap data available to display');\n }\n\n // For debugging, log some sample dates from the heatmap data\n const sampleDates = Object.keys(this.heatmapData).slice(0, 5);\n console.log('Sample dates in heatmap data:', sampleDates);\n \n // Build the week data structure\n while (day.isSameOrBefore(end)) {\n const weekData: DayData[] = [];\n for (let i = 0; i < 7; i++) {\n const date = day.format('YYYY-MM-DD');\n const count = this.heatmapData[date] || 0;\n const dayData: DayData = {\n date,\n count,\n };\n weekData.push(dayData);\n if (dayData.count > this.maxInRange) {\n this.maxInRange = dayData.count;\n }\n\n day.add(1, 'day');\n }\n this.weeks.push(weekData);\n }\n \n console.log('Weeks data created, maxInRange:', this.maxInRange);\n \n // Calculate summary stats for display\n let totalDaysWithActivity = 0;\n let totalActivity = 0;\n \n Object.values(this.heatmapData).forEach(count => {\n totalDaysWithActivity++;\n totalActivity += count;\n });\n \n console.log(`Activity summary: ${totalActivity} activities across ${totalDaysWithActivity} days`);\n },\n\n getColor(count: number): string {\n if (this.maxInRange === 0) return this.hslToString(this.inactiveColor);\n\n const t = count === 0 ? 0 : Math.min((2 * count) / this.maxInRange, 1);\n\n let seasonalColor: Color = this.activeColor;\n\n if (this.enableSeasonalColors) {\n const now = moment();\n if (now.month() === 11 && now.date() >= 5) {\n // Christmas colors\n seasonalColor = Math.random() > 0.5 ? { h: 350, s: 0.8, l: 0.5 } : { h: 135, s: 0.8, l: 0.4 };\n } else if (now.month() === 9 && now.date() >= 25) {\n // Halloween colors\n seasonalColor =\n Math.random() > 0.5\n ? { h: 0, s: 0, l: 0 }\n : Math.random() > 0.5\n ? { h: 30, s: 1, l: 0.5 }\n : { h: 270, s: 1, l: 0.5 };\n }\n }\n\n const h = seasonalColor.h;\n const s = this.interpolate(this.inactiveColor.s, seasonalColor.s, t);\n const l = this.interpolate(this.inactiveColor.l, seasonalColor.l, t);\n\n return this.hslToString({ h, s, l });\n },\n\n interpolate(start: number, end: number, t: number): number {\n return start + (end - start) * t;\n },\n\n hslToString(color: Color): string {\n return `hsl(${color.h}, ${color.s * 100}%, ${color.l * 100}%)`;\n },\n\n showTooltip(day: DayData, event: MouseEvent) {\n this.tooltipData = day;\n this.tooltipStyle = {\n position: 'absolute',\n left: `${event.pageX + 10}px`,\n top: `${event.pageY + 10}px`,\n };\n },\n\n hideTooltip() {\n this.tooltipData = null;\n },\n },\n});\n</script>\n\n<style scoped>\n.tooltip {\n background-color: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 5px;\n border-radius: 3px;\n font-size: 12px;\n}\n</style>\n"],"mappings":";;;;AAgCA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,OAAO;EAEL,iBAAiB;GACf,MAAM;GACN,eAAe,EAAE;GAClB;EAED,uBAAuB;GACrB,MAAM;GACN,SAAS;GACV;EAED,eAAe;GACb,MAAM;GACN,gBAAgB;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;IAAK;GACvC;EACD,aAAa;GACX,MAAM;GACN,gBAAgB;IAAE,GAAG;IAAK,GAAG;IAAG,GAAG;IAAK;GACzC;EAED,UAAU;GACR,MAAM;GACN,SAAS;GACV;EACD,YAAY;GACV,MAAM;GACN,SAAS;GACV;EAED,sBAAsB;GACpB,MAAM;GACN,SAAS;GACV;EACF;CAED,OAAO;AACL,SAAO;GACL,WAAW;GACX,sBAAsB,EAAC;GACvB,aAAa,EAAC;GACd,OAAO,EAAC;GACR,aAAa;GACb,cAAc,EAAC;GACf,YAAY;GACb;;CAGH,UAAU;EACR,QAAgB;AACd,UAAO,MAAM,KAAK,WAAW,KAAK;;EAEpC,SAAiB;AACf,UAAO,KAAK,KAAK,WAAW,KAAK;;EAEnC,2BAA6C;GAC3C,IAAM,IAAW,MAAM,QAAQ,KAAK,qBAAoB,IAAK,KAAK,qBAAqB,SAAS,GAC1F,IAAU,IAAW,KAAK,uBAAuB,KAAK,mBAAmB,EAAE;AAEjF,UADA,QAAQ,IAAI,0CAA0C,EAAQ,QAAQ,WAAW,IAAW,UAAU,OAAO,EACtG;;EAEV;CAED,OAAO,EACL,iBAAiB;EACf,UAAU;AAER,GADA,KAAK,gBAAgB,EACrB,KAAK,iBAAiB;;EAExB,WAAW;EACZ,EACF;CAED,MAAM,UAAU;AACd,MAAI,KAAK,sBACP,KAAI;AAEF,GADA,KAAK,YAAY,IACjB,QAAQ,IAAI,4CAA4C;GAGxD,IAAI,IAAS,MAAM,KAAK,uBAAuB;AAG/C,GAAI,MAAM,QAAQ,EAAO,IAEvB,KAAK,uBAAuB,EAAO,QAAO,MAAU;AAClD,QAAI,CAAC,KAAU,CAAC,EAAO,UAAW,QAAO;AAGzC,QAAI;KACF,IAAM,IAAI,EAAO,EAAO,UAAU;AAClC,YAAO,EAAE,SAAQ,IAAK,EAAE,MAAK,GAAI,OAAQ,EAAE,MAAK,GAAI;YAC1C;AACV,YAAO;;KAET,EAEF,QAAQ,IAAI,YAAY,EAAO,OAAM,YAAa,KAAK,qBAAqB,OAAM,wBAAyB,EAG3G,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,KAEtB,QAAQ,MAAM,oDAAoD,EAAO,EACzE,KAAK,uBAAuB,EAAE;WAEzB,GAAO;AAEd,GADA,QAAQ,MAAM,oCAAoC,EAAM,EACxD,KAAK,uBAAuB,EAAE;YACtB;AACR,QAAK,YAAY;;MAGnB,SAAQ,IAAI,uEAAuE;;CAIvF,SAAS;EACP,aAAa,GAAmB;GAC9B,IAAM,IAAI,EAAO,EAAE;AACnB,UAAO,EAAO,QAAQ,CAAC,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM;;EAGpD,iBAAiB;GACf,IAAM,IAAU,KAAK,4BAA4B,EAAE;AACnD,WAAQ,IAAI,cAAc,EAAQ,OAAM,UAAW;GAEnD,IAAM,IAAkC,EAAE;AAE1C,OAAI,EAAQ,WAAW,GAAG;AAExB,IADA,QAAQ,IAAI,wBAAwB,EACpC,KAAK,cAAc;AACnB;;GAIF,IAAM,oBAAc,IAAI,KAAa,EAC/B,IAA2C,EAAE,EAC/C,IAAa,GACb,IAAe;AAEnB,QAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAAK;IACvC,IAAM,IAAS,EAAQ;AAEvB,QAAI,CAAC,KAAU,OAAO,KAAW,YAAY,CAAC,EAAO,WAAW;AAC9D;AACA;;AAGF,QAAI;KAEF,IAAI;AAEJ,SAAI,OAAO,EAAO,aAAc,SAE9B,KAAiB,EAAO,EAAO,UAAU,CAAC,OAAO,aAAa;cACrD,OAAO,EAAO,aAAc,SAErC,KAAiB,EAAO,IAAI,KAAK,EAAO,UAAU,CAAC,CAAC,OAAO,aAAa;cAC/D,OAAO,EAAO,aAAc,SAErC,CAOE,IAPE,OAAO,EAAO,UAAU,UAAW,aAEpB,EAAO,UAAU,OAAO,aAAa,GAC7C,EAAO,qBAAqB,OACpB,EAAO,EAAO,UAAU,CAAC,OAAO,aAAa,GAG7C,EAAO,OAAO,EAAO,UAAU,CAAC,CAAC,OAAO,aAAa;UAEnE;AAEL;AACA;;AAIF,SAAI,EAAO,GAAgB,cAAc,GAAK,CAAC,SAAS,EAAE;AAExD,MADA,EAAK,MAAmB,EAAK,MAAmB,KAAK,GACrD,EAAY,IAAI,EAAe;MAG/B,IAAM,IAAQ,EAAe,UAAU,GAAG,EAAE;AAG5C,MAFA,EAAiB,MAAU,EAAiB,MAAU,KAAK,GAE3D;WAEA;YAEQ;AACV;;;AASJ,GAJA,QAAQ,IAAI,aAAa,EAAU,gBAAiB,EAAY,gBAAiB,EACjF,QAAQ,IAAI,SAAS,EAAY,KAAI,eAAgB,EACrD,QAAQ,IAAI,+BAA+B,EAAiB,EAE5D,KAAK,cAAc;;EAGrB,kBAAkB;AAGhB,GADA,KAAK,QAAQ,EAAE,EACf,KAAK,aAAa;GAElB,IAAM,IAAM,GAAQ,EACd,IAAQ,EAAI,OAAO,CAAC,SAAS,IAAI,QAAQ,EACzC,IAAM,EAAM,OAAO,CAAC,QAAQ,OAAO;AAKzC,GAHA,QAAQ,IAAI,4BAA4B,EAAM,OAAO,aAAa,EAAE,MAAM,EAAI,OAAO,aAAa,CAAC,EAG/F,OAAO,KAAK,KAAK,YAAY,CAAC,WAAW,KAC3C,QAAQ,IAAI,uCAAuC;GAIrD,IAAM,IAAc,OAAO,KAAK,KAAK,YAAY,CAAC,MAAM,GAAG,EAAE;AAI7D,QAHA,QAAQ,IAAI,iCAAiC,EAAY,EAGlD,EAAI,eAAe,EAAI,GAAE;IAC9B,IAAM,IAAsB,EAAE;AAC9B,SAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;KAC1B,IAAM,IAAO,EAAI,OAAO,aAAa,EAE/B,IAAmB;MACvB;MACA,OAHY,KAAK,YAAY,MAAS;MAIvC;AAMD,KALA,EAAS,KAAK,EAAQ,EAClB,EAAQ,QAAQ,KAAK,eACvB,KAAK,aAAa,EAAQ,QAG5B,EAAI,IAAI,GAAG,MAAM;;AAEnB,SAAK,MAAM,KAAK,EAAS;;AAG3B,WAAQ,IAAI,mCAAmC,KAAK,WAAW;GAG/D,IAAI,IAAwB,GACxB,IAAgB;AAOpB,GALA,OAAO,OAAO,KAAK,YAAY,CAAC,SAAQ,MAAS;AAE/C,IADA,KACA,KAAiB;KACjB,EAEF,QAAQ,IAAI,qBAAqB,EAAa,qBAAsB,EAAqB,OAAQ;;EAGnG,SAAS,GAAuB;AAC9B,OAAI,KAAK,eAAe,EAAG,QAAO,KAAK,YAAY,KAAK,cAAc;GAEtE,IAAM,IAAI,MAAU,IAAI,IAAI,KAAK,IAAK,IAAI,IAAS,KAAK,YAAY,EAAE,EAElE,IAAuB,KAAK;AAEhC,OAAI,KAAK,sBAAsB;IAC7B,IAAM,IAAM,GAAQ;AACpB,IAAI,EAAI,OAAM,KAAM,MAAM,EAAI,MAAK,IAAK,IAEtC,IAAgB,KAAK,QAAO,GAAI,KAAM;KAAE,GAAG;KAAK,GAAG;KAAK,GAAG;KAAI,GAAI;KAAE,GAAG;KAAK,GAAG;KAAK,GAAG;KAAK,GACpF,EAAI,OAAM,KAAM,KAAK,EAAI,MAAK,IAAK,OAE5C,IACE,KAAK,QAAO,GAAI,KACZ;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;KAAE,GACnB,KAAK,QAAO,GAAI,KAChB;KAAE,GAAG;KAAI,GAAG;KAAG,GAAG;KAAI,GACtB;KAAE,GAAG;KAAK,GAAG;KAAG,GAAG;KAAK;;GAIlC,IAAM,IAAI,EAAc,GAClB,IAAI,KAAK,YAAY,KAAK,cAAc,GAAG,EAAc,GAAG,EAAE,EAC9D,IAAI,KAAK,YAAY,KAAK,cAAc,GAAG,EAAc,GAAG,EAAE;AAEpE,UAAO,KAAK,YAAY;IAAE;IAAG;IAAG;IAAG,CAAC;;EAGtC,YAAY,GAAe,GAAa,GAAmB;AACzD,UAAO,KAAS,IAAM,KAAS;;EAGjC,YAAY,GAAsB;AAChC,UAAO,OAAO,EAAM,EAAE,IAAI,EAAM,IAAI,IAAI,KAAK,EAAM,IAAI,IAAI;;EAG7D,YAAY,GAAc,GAAmB;AAE3C,GADA,KAAK,cAAc,GACnB,KAAK,eAAe;IAClB,UAAU;IACV,MAAM,GAAG,EAAM,QAAQ,GAAG;IAC1B,KAAK,GAAG,EAAM,QAAQ,GAAG;IAC1B;;EAGH,cAAc;AACZ,QAAK,cAAc;;EAEtB;CACF,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "../_virtual/_plugin-vue_export-helper.mjs";
|
|
3
|
+
import t from "./PaginatingToolbar.vue_vue_type_script_lang.mjs";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import { createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, openBlock as c, resolveComponent as l, toDisplayString as u, withCtx as d } from "vue";
|
|
6
|
+
//#region src/components/PaginatingToolbar.vue
|
|
7
|
+
var f = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "ms-2 text-subtitle-2",
|
|
10
|
+
"data-cy": "paginating-toolbar-subtitle"
|
|
11
|
+
};
|
|
12
|
+
function _sfc_render(e, t, p, m, h, g) {
|
|
13
|
+
let _ = l("v-toolbar-title"), v = l("v-spacer"), y = l("v-icon"), b = l("v-btn"), x = l("v-select"), S = l("v-toolbar");
|
|
14
|
+
return c(), n(S, { density: "compact" }, {
|
|
15
|
+
default: d(() => [
|
|
16
|
+
s(_, null, {
|
|
17
|
+
default: d(() => [a("span", null, u(e.title), 1), e.subtitle ? (c(), i("span", f, u(e.subtitle), 1)) : r("", !0)]),
|
|
18
|
+
_: 1
|
|
19
|
+
}),
|
|
20
|
+
s(v),
|
|
21
|
+
s(b, {
|
|
22
|
+
variant: "text",
|
|
23
|
+
icon: "",
|
|
24
|
+
color: "secondary",
|
|
25
|
+
disabled: e.page == 1,
|
|
26
|
+
onClick: t[0] || (t[0] = (t) => e.$emit("first"))
|
|
27
|
+
}, {
|
|
28
|
+
default: d(() => [s(y, null, {
|
|
29
|
+
default: d(() => t[5] || (t[5] = [o("mdi-page-first")])),
|
|
30
|
+
_: 1
|
|
31
|
+
})]),
|
|
32
|
+
_: 1
|
|
33
|
+
}, 8, ["disabled"]),
|
|
34
|
+
s(b, {
|
|
35
|
+
variant: "text",
|
|
36
|
+
icon: "",
|
|
37
|
+
color: "secondary",
|
|
38
|
+
disabled: e.page == 1,
|
|
39
|
+
onClick: t[1] || (t[1] = (t) => e.$emit("prev"))
|
|
40
|
+
}, {
|
|
41
|
+
default: d(() => [s(y, null, {
|
|
42
|
+
default: d(() => t[6] || (t[6] = [o("mdi-chevron-left")])),
|
|
43
|
+
_: 1
|
|
44
|
+
})]),
|
|
45
|
+
_: 1
|
|
46
|
+
}, 8, ["disabled"]),
|
|
47
|
+
s(x, {
|
|
48
|
+
"model-value": e.page,
|
|
49
|
+
items: e.pages,
|
|
50
|
+
class: "pageSelect",
|
|
51
|
+
density: "compact",
|
|
52
|
+
"hide-details": "",
|
|
53
|
+
"return-object": !1,
|
|
54
|
+
variant: "outlined",
|
|
55
|
+
"onUpdate:modelValue": t[2] || (t[2] = (t) => e.$emit("set-page", t))
|
|
56
|
+
}, {
|
|
57
|
+
selection: d(({ item: e }) => [o(u(e.value), 1)]),
|
|
58
|
+
_: 1
|
|
59
|
+
}, 8, ["model-value", "items"]),
|
|
60
|
+
s(b, {
|
|
61
|
+
variant: "text",
|
|
62
|
+
icon: "",
|
|
63
|
+
color: "secondary",
|
|
64
|
+
disabled: e.page == e.pages.length,
|
|
65
|
+
onClick: t[3] || (t[3] = (t) => e.$emit("next"))
|
|
66
|
+
}, {
|
|
67
|
+
default: d(() => [s(y, null, {
|
|
68
|
+
default: d(() => t[7] || (t[7] = [o("mdi-chevron-right")])),
|
|
69
|
+
_: 1
|
|
70
|
+
})]),
|
|
71
|
+
_: 1
|
|
72
|
+
}, 8, ["disabled"]),
|
|
73
|
+
s(b, {
|
|
74
|
+
variant: "text",
|
|
75
|
+
icon: "",
|
|
76
|
+
color: "secondary",
|
|
77
|
+
disabled: e.page == e.pages.length,
|
|
78
|
+
onClick: t[4] || (t[4] = (t) => e.$emit("last"))
|
|
79
|
+
}, {
|
|
80
|
+
default: d(() => [s(y, null, {
|
|
81
|
+
default: d(() => t[8] || (t[8] = [o("mdi-page-last")])),
|
|
82
|
+
_: 1
|
|
83
|
+
})]),
|
|
84
|
+
_: 1
|
|
85
|
+
}, 8, ["disabled"])
|
|
86
|
+
]),
|
|
87
|
+
_: 1
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
var p = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-a75fea7e"]]);
|
|
91
|
+
//#endregion
|
|
92
|
+
export { p as default };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=PaginatingToolbar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaginatingToolbar.mjs","names":[],"sources":["../../src/components/PaginatingToolbar.vue"],"sourcesContent":["<template>\n <v-toolbar density=\"compact\">\n <v-toolbar-title>\n <span>{{ title }}</span>\n <span v-if=\"subtitle\" class=\"ms-2 text-subtitle-2\" data-cy=\"paginating-toolbar-subtitle\">{{ subtitle }}</span>\n </v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == 1\" @click=\"$emit('first')\">\n <v-icon>mdi-page-first</v-icon>\n </v-btn>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == 1\" @click=\"$emit('prev')\">\n <v-icon>mdi-chevron-left</v-icon>\n </v-btn>\n\n <v-select\n :model-value=\"page\"\n :items=\"pages\"\n class=\"pageSelect\"\n density=\"compact\"\n hide-details\n :return-object=\"false\"\n variant=\"outlined\"\n @update:model-value=\"(val: unknown) => $emit('set-page', val)\"\n >\n <template #selection=\"{ item }\">\n {{ item.value }}\n </template>\n </v-select>\n\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == pages.length\" @click=\"$emit('next')\">\n <v-icon>mdi-chevron-right</v-icon>\n </v-btn>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == pages.length\" @click=\"$emit('last')\">\n <v-icon>mdi-page-last</v-icon>\n </v-btn>\n </v-toolbar>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType } from 'vue';\nimport type { PaginatingToolbarProps, PaginatingToolbarEvents } from './PaginatingToolbar.types';\n\nexport default defineComponent({\n name: 'PaginatingToolbar',\n\n props: {\n pages: {\n type: Array as PropType<number[]>,\n required: true,\n },\n page: {\n type: Number,\n required: true,\n },\n title: {\n type: String,\n required: false,\n default: '',\n },\n subtitle: {\n type: String,\n required: false,\n default: '',\n },\n } as const,\n\n emits: ['first', 'prev', 'next', 'last', 'set-page'],\n});\n</script>\n\n<style scoped>\n.pageSelect {\n max-width: 60px;\n}\n</style>\n"],"mappings":";;;;;;;CAAA,KAAA;CAI4B,OAAM;CAAuB,WAAQ;;;;aAH/D,EAkCY,GAAA,EAlCD,SAAQ,WAAS,EAAA;EAD9B,SAAA,QAKsB;GAHlB,EAGkB,GAAA,MAAA;IALtB,SAAA,QAG8B,CAAxB,EAAwB,QAAA,MAAA,EAAf,EAAA,MAAK,EAAA,EAAA,EACF,EAAA,YAAA,GAAA,EAAZ,EAA8G,QAA9G,GAA8G,EAAlB,EAAA,SAAQ,EAAA,EAAA,IAJ1G,EAAA,IAAA,GAAA,CAAA,CAAA;IAAA,GAAA;;GAMI,EAAqB,EAAA;GACrB,EAEQ,GAAA;IAFD,SAAQ;IAAO,MAAA;IAAK,OAAM;IAAa,UAAU,EAAA,QAAI;IAAQ,SAAK,EAAA,OAAA,EAAA,MAAA,MAAE,EAAA,MAAK,QAAA;;IAPpF,SAAA,QAQqC,CAA/B,EAA+B,GAAA,MAAA;KARrC,SAAA,QAQ4B,EAAA,OAAA,EAAA,KAAA,CAR5B,EAQc,iBAAc,CAAA,EAAA;KAR5B,GAAA;;IAAA,GAAA;;GAUI,EAEQ,GAAA;IAFD,SAAQ;IAAO,MAAA;IAAK,OAAM;IAAa,UAAU,EAAA,QAAI;IAAQ,SAAK,EAAA,OAAA,EAAA,MAAA,MAAE,EAAA,MAAK,OAAA;;IAVpF,SAAA,QAWuC,CAAjC,EAAiC,GAAA,MAAA;KAXvC,SAAA,QAW8B,EAAA,OAAA,EAAA,KAAA,CAX9B,EAWc,mBAAgB,CAAA,EAAA;KAX9B,GAAA;;IAAA,GAAA;;GAcI,EAaW,GAAA;IAZR,eAAa,EAAA;IACb,OAAO,EAAA;IACR,OAAM;IACN,SAAQ;IACR,gBAAA;IACC,iBAAe;IAChB,SAAQ;IACP,uBAAkB,EAAA,OAAA,EAAA,MAAG,MAAiB,EAAA,MAAK,YAAa,EAAG;;IAEjD,WAAS,GACF,EADM,cAAI,CAxBlC,EAAA,EAyBW,EAAK,MAAK,EAAA,EAAA,CAAA,CAAA;IAzBrB,GAAA;;GA6BI,EAEQ,GAAA;IAFD,SAAQ;IAAO,MAAA;IAAK,OAAM;IAAa,UAAU,EAAA,QAAQ,EAAA,MAAM;IAAS,SAAK,EAAA,OAAA,EAAA,MAAA,MAAE,EAAA,MAAK,OAAA;;IA7B/F,SAAA,QA8BwC,CAAlC,EAAkC,GAAA,MAAA;KA9BxC,SAAA,QA8B+B,EAAA,OAAA,EAAA,KAAA,CA9B/B,EA8Bc,oBAAiB,CAAA,EAAA;KA9B/B,GAAA;;IAAA,GAAA;;GAgCI,EAEQ,GAAA;IAFD,SAAQ;IAAO,MAAA;IAAK,OAAM;IAAa,UAAU,EAAA,QAAQ,EAAA,MAAM;IAAS,SAAK,EAAA,OAAA,EAAA,MAAA,MAAE,EAAA,MAAK,OAAA;;IAhC/F,SAAA,QAiCoC,CAA9B,EAA8B,GAAA,MAAA;KAjCpC,SAAA,QAiC2B,EAAA,OAAA,EAAA,KAAA,CAjC3B,EAiCc,gBAAa,CAAA,EAAA;KAjC3B,GAAA;;IAAA,GAAA;;;EAAA,GAAA"}
|
|
@@ -18,7 +18,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
18
18
|
readonly required: false;
|
|
19
19
|
readonly default: "";
|
|
20
20
|
};
|
|
21
|
-
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("
|
|
21
|
+
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("next" | "prev" | "first" | "last" | "set-page")[], "next" | "prev" | "first" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
|
|
22
22
|
readonly pages: {
|
|
23
23
|
readonly type: PropType<number[]>;
|
|
24
24
|
readonly required: true;
|
|
@@ -38,9 +38,9 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
38
38
|
readonly default: "";
|
|
39
39
|
};
|
|
40
40
|
}>> & Readonly<{
|
|
41
|
-
onFirst?: ((...args: any[]) => any) | undefined;
|
|
42
|
-
onPrev?: ((...args: any[]) => any) | undefined;
|
|
43
41
|
onNext?: ((...args: any[]) => any) | undefined;
|
|
42
|
+
onPrev?: ((...args: any[]) => any) | undefined;
|
|
43
|
+
onFirst?: ((...args: any[]) => any) | undefined;
|
|
44
44
|
onLast?: ((...args: any[]) => any) | undefined;
|
|
45
45
|
"onSet-page"?: ((...args: any[]) => any) | undefined;
|
|
46
46
|
}>, {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineComponent as e } from "vue";
|
|
2
|
+
//#region src/components/PaginatingToolbar.vue?vue&type=script&lang.ts
|
|
3
|
+
var t = e({
|
|
4
|
+
name: "PaginatingToolbar",
|
|
5
|
+
props: {
|
|
6
|
+
pages: {
|
|
7
|
+
type: Array,
|
|
8
|
+
required: !0
|
|
9
|
+
},
|
|
10
|
+
page: {
|
|
11
|
+
type: Number,
|
|
12
|
+
required: !0
|
|
13
|
+
},
|
|
14
|
+
title: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: !1,
|
|
17
|
+
default: ""
|
|
18
|
+
},
|
|
19
|
+
subtitle: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: !1,
|
|
22
|
+
default: ""
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
emits: [
|
|
26
|
+
"first",
|
|
27
|
+
"prev",
|
|
28
|
+
"next",
|
|
29
|
+
"last",
|
|
30
|
+
"set-page"
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export { t as default };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=PaginatingToolbar.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaginatingToolbar.vue_vue_type_script_lang.mjs","names":[],"sources":["../../src/components/PaginatingToolbar.vue"],"sourcesContent":["<template>\n <v-toolbar density=\"compact\">\n <v-toolbar-title>\n <span>{{ title }}</span>\n <span v-if=\"subtitle\" class=\"ms-2 text-subtitle-2\" data-cy=\"paginating-toolbar-subtitle\">{{ subtitle }}</span>\n </v-toolbar-title>\n <v-spacer></v-spacer>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == 1\" @click=\"$emit('first')\">\n <v-icon>mdi-page-first</v-icon>\n </v-btn>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == 1\" @click=\"$emit('prev')\">\n <v-icon>mdi-chevron-left</v-icon>\n </v-btn>\n\n <v-select\n :model-value=\"page\"\n :items=\"pages\"\n class=\"pageSelect\"\n density=\"compact\"\n hide-details\n :return-object=\"false\"\n variant=\"outlined\"\n @update:model-value=\"(val: unknown) => $emit('set-page', val)\"\n >\n <template #selection=\"{ item }\">\n {{ item.value }}\n </template>\n </v-select>\n\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == pages.length\" @click=\"$emit('next')\">\n <v-icon>mdi-chevron-right</v-icon>\n </v-btn>\n <v-btn variant=\"text\" icon color=\"secondary\" :disabled=\"page == pages.length\" @click=\"$emit('last')\">\n <v-icon>mdi-page-last</v-icon>\n </v-btn>\n </v-toolbar>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType } from 'vue';\nimport type { PaginatingToolbarProps, PaginatingToolbarEvents } from './PaginatingToolbar.types';\n\nexport default defineComponent({\n name: 'PaginatingToolbar',\n\n props: {\n pages: {\n type: Array as PropType<number[]>,\n required: true,\n },\n page: {\n type: Number,\n required: true,\n },\n title: {\n type: String,\n required: false,\n default: '',\n },\n subtitle: {\n type: String,\n required: false,\n default: '',\n },\n } as const,\n\n emits: ['first', 'prev', 'next', 'last', 'set-page'],\n});\n</script>\n\n<style scoped>\n.pageSelect {\n max-width: 60px;\n}\n</style>\n"],"mappings":";;AA0CA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,OAAO;EACL,OAAO;GACL,MAAM;GACN,UAAU;GACX;EACD,MAAM;GACJ,MAAM;GACN,UAAU;GACX;EACD,OAAO;GACL,MAAM;GACN,UAAU;GACV,SAAS;GACV;EACD,UAAU;GACR,MAAM;GACN,UAAU;GACV,SAAS;GACV;EACH;CAEA,OAAO;EAAC;EAAS;EAAQ;EAAQ;EAAQ;EAAW;CACrD,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "../_virtual/_plugin-vue_export-helper.mjs";
|
|
3
|
+
import t from "./SessionControllerDebug.vue_vue_type_script_lang.mjs";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import { Fragment as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, openBlock as l, renderList as u, resolveComponent as d, toDisplayString as f, withCtx as p } from "vue";
|
|
6
|
+
//#region src/components/SessionControllerDebug.vue
|
|
7
|
+
var m = { class: "debug-section" }, h = { class: "debug-header" }, g = { class: "debug-stats" }, _ = { class: "text-caption" }, v = { class: "text-caption ml-2" }, y = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "debug-items"
|
|
10
|
+
}, b = { class: "text-caption" }, x = { class: "text-caption text-grey ml-1" }, S = {
|
|
11
|
+
class: "text-caption ml-1",
|
|
12
|
+
style: { color: "#90caf9" }
|
|
13
|
+
}, C = {
|
|
14
|
+
key: 0,
|
|
15
|
+
class: "text-caption text-grey"
|
|
16
|
+
}, w = {
|
|
17
|
+
key: 1,
|
|
18
|
+
class: "text-caption text-grey"
|
|
19
|
+
}, T = { class: "debug-section" }, E = { class: "debug-header" }, D = { class: "debug-stats" }, O = { class: "text-caption" }, k = { class: "text-caption ml-2" }, A = {
|
|
20
|
+
key: 0,
|
|
21
|
+
class: "debug-items"
|
|
22
|
+
}, j = { class: "text-caption" }, M = { class: "text-caption text-grey ml-1" }, N = {
|
|
23
|
+
key: 0,
|
|
24
|
+
class: "text-caption text-grey"
|
|
25
|
+
}, P = {
|
|
26
|
+
key: 1,
|
|
27
|
+
class: "text-caption text-grey"
|
|
28
|
+
}, F = { class: "debug-section" }, I = { class: "debug-header" }, L = { class: "debug-stats" }, R = { class: "text-caption" }, z = { class: "text-caption ml-2" }, B = {
|
|
29
|
+
key: 0,
|
|
30
|
+
class: "debug-items"
|
|
31
|
+
}, V = { class: "text-caption" }, H = {
|
|
32
|
+
key: 0,
|
|
33
|
+
class: "text-caption text-grey"
|
|
34
|
+
}, U = {
|
|
35
|
+
key: 1,
|
|
36
|
+
class: "text-caption text-grey"
|
|
37
|
+
};
|
|
38
|
+
function _sfc_render(e, t, W, ee, te, G) {
|
|
39
|
+
let K = d("v-spacer"), q = d("v-icon"), J = d("v-card-title"), Y = d("v-col"), X = d("v-row"), Z = d("v-divider"), Q = d("v-card-text"), $ = d("v-card");
|
|
40
|
+
return e.sessionController ? (l(), r($, {
|
|
41
|
+
key: 0,
|
|
42
|
+
class: "session-debug ma-2",
|
|
43
|
+
elevation: "2"
|
|
44
|
+
}, {
|
|
45
|
+
default: p(() => [c(J, { class: "text-caption bg-grey-darken-3" }, {
|
|
46
|
+
default: p(() => [
|
|
47
|
+
t[1] || (t[1] = s(" Session Controller Debug ")),
|
|
48
|
+
c(K),
|
|
49
|
+
c(q, { size: "small" }, {
|
|
50
|
+
default: p(() => t[0] || (t[0] = [s("mdi-bug")])),
|
|
51
|
+
_: 1
|
|
52
|
+
})
|
|
53
|
+
]),
|
|
54
|
+
_: 1
|
|
55
|
+
}), c(Q, { class: "pa-2" }, {
|
|
56
|
+
default: p(() => [c(X, { dense: "" }, {
|
|
57
|
+
default: p(() => [c(Y, {
|
|
58
|
+
cols: "12",
|
|
59
|
+
md: "8"
|
|
60
|
+
}, {
|
|
61
|
+
default: p(() => [o("div", m, [
|
|
62
|
+
o("div", h, [c(q, {
|
|
63
|
+
size: "x-small",
|
|
64
|
+
class: "mr-1"
|
|
65
|
+
}, {
|
|
66
|
+
default: p(() => t[2] || (t[2] = [s("mdi-sort")])),
|
|
67
|
+
_: 1
|
|
68
|
+
}), t[3] || (t[3] = o("strong", null, "Supply Queue", -1))]),
|
|
69
|
+
o("div", g, [o("span", _, "Length: " + f(e.debugInfo.supplyQueue.length), 1), o("span", v, "Dequeued: " + f(e.debugInfo.supplyQueue.dequeueCount), 1)]),
|
|
70
|
+
e.debugInfo.supplyQueue.items.length > 0 ? (l(), a("div", y, [(l(!0), a(n, null, u(e.debugInfo.supplyQueue.items.slice(0, 8), (t, n) => (l(), a("div", {
|
|
71
|
+
key: n,
|
|
72
|
+
class: "debug-item"
|
|
73
|
+
}, [
|
|
74
|
+
o("span", b, f(n) + ": " + f(t.courseID) + "::" + f(t.cardID), 1),
|
|
75
|
+
o("span", x, "(" + f(t.status) + ")", 1),
|
|
76
|
+
o("span", S, f(e.fmtScore(t.score)), 1)
|
|
77
|
+
]))), 128)), e.debugInfo.supplyQueue.items.length > 8 ? (l(), a("div", C, " ... +" + f(e.debugInfo.supplyQueue.items.length - 8) + " more ", 1)) : i("", !0)])) : (l(), a("div", w, " (empty) "))
|
|
78
|
+
])]),
|
|
79
|
+
_: 1
|
|
80
|
+
}), c(Y, {
|
|
81
|
+
cols: "12",
|
|
82
|
+
md: "4"
|
|
83
|
+
}, {
|
|
84
|
+
default: p(() => [o("div", T, [
|
|
85
|
+
o("div", E, [c(q, {
|
|
86
|
+
size: "x-small",
|
|
87
|
+
class: "mr-1"
|
|
88
|
+
}, {
|
|
89
|
+
default: p(() => t[4] || (t[4] = [s("mdi-alert-circle")])),
|
|
90
|
+
_: 1
|
|
91
|
+
}), t[5] || (t[5] = o("strong", null, "Failed Cards Queue", -1))]),
|
|
92
|
+
o("div", D, [o("span", O, "Length: " + f(e.debugInfo.failedQueue.length), 1), o("span", k, "Dequeued: " + f(e.debugInfo.failedQueue.dequeueCount), 1)]),
|
|
93
|
+
e.debugInfo.failedQueue.items.length > 0 ? (l(), a("div", A, [(l(!0), a(n, null, u(e.debugInfo.failedQueue.items.slice(0, 5), (e, t) => (l(), a("div", {
|
|
94
|
+
key: t,
|
|
95
|
+
class: "debug-item"
|
|
96
|
+
}, [o("span", j, f(t) + ": " + f(e.courseID) + "::" + f(e.cardID), 1), o("span", M, "(" + f(e.status) + ")", 1)]))), 128)), e.debugInfo.failedQueue.items.length > 5 ? (l(), a("div", N, " ... +" + f(e.debugInfo.failedQueue.items.length - 5) + " more ", 1)) : i("", !0)])) : (l(), a("div", P, " (empty) "))
|
|
97
|
+
])]),
|
|
98
|
+
_: 1
|
|
99
|
+
})]),
|
|
100
|
+
_: 1
|
|
101
|
+
}), c(X, { dense: "" }, {
|
|
102
|
+
default: p(() => [c(Y, { cols: "12" }, {
|
|
103
|
+
default: p(() => [c(Z, { class: "my-2" }), o("div", F, [
|
|
104
|
+
o("div", I, [c(q, {
|
|
105
|
+
size: "x-small",
|
|
106
|
+
class: "mr-1"
|
|
107
|
+
}, {
|
|
108
|
+
default: p(() => t[6] || (t[6] = [s("mdi-database")])),
|
|
109
|
+
_: 1
|
|
110
|
+
}), t[7] || (t[7] = o("strong", null, "Hydrated Cards Cache", -1))]),
|
|
111
|
+
o("div", L, [o("span", R, "Cached: " + f(e.debugInfo.hydratedCache.count), 1), o("span", z, "Failed Cache: " + f(e.debugInfo.hydratedCache.failedCacheSize), 1)]),
|
|
112
|
+
e.debugInfo.hydratedCache.items.length > 0 ? (l(), a("div", B, [(l(!0), a(n, null, u(e.debugInfo.hydratedCache.items.slice(0, 8), (e, t) => (l(), a("div", {
|
|
113
|
+
key: t,
|
|
114
|
+
class: "debug-item d-inline-block mr-3"
|
|
115
|
+
}, [o("span", V, f(e.courseID) + "::" + f(e.cardID), 1)]))), 128)), e.debugInfo.hydratedCache.items.length > 8 ? (l(), a("div", H, " ... +" + f(e.debugInfo.hydratedCache.items.length - 8) + " more ", 1)) : i("", !0)])) : (l(), a("div", U, " (empty) "))
|
|
116
|
+
])]),
|
|
117
|
+
_: 1
|
|
118
|
+
})]),
|
|
119
|
+
_: 1
|
|
120
|
+
})]),
|
|
121
|
+
_: 1
|
|
122
|
+
})]),
|
|
123
|
+
_: 1
|
|
124
|
+
})) : i("", !0);
|
|
125
|
+
}
|
|
126
|
+
var W = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-641ac170"]]);
|
|
127
|
+
//#endregion
|
|
128
|
+
export { W as default };
|
|
129
|
+
|
|
130
|
+
//# sourceMappingURL=SessionControllerDebug.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionControllerDebug.mjs","names":[],"sources":["../../src/components/SessionControllerDebug.vue"],"sourcesContent":["<template>\n <v-card v-if=\"sessionController\" class=\"session-debug ma-2\" elevation=\"2\">\n <v-card-title class=\"text-caption bg-grey-darken-3\">\n Session Controller Debug\n <v-spacer></v-spacer>\n <v-icon size=\"small\">mdi-bug</v-icon>\n </v-card-title>\n\n <v-card-text class=\"pa-2\">\n <v-row dense>\n <!-- Supply Queue (new + review, rank-ordered) -->\n <v-col cols=\"12\" md=\"8\">\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-sort</v-icon>\n <strong>Supply Queue</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Length: {{ debugInfo.supplyQueue.length }}</span>\n <span class=\"text-caption ml-2\">Dequeued: {{ debugInfo.supplyQueue.dequeueCount }}</span>\n </div>\n <div v-if=\"debugInfo.supplyQueue.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.supplyQueue.items.slice(0, 8)\"\n :key=\"idx\"\n class=\"debug-item\"\n >\n <span class=\"text-caption\">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>\n <span class=\"text-caption text-grey ml-1\">({{ item.status }})</span>\n <span class=\"text-caption ml-1\" style=\"color:#90caf9\">{{ fmtScore(item.score) }}</span>\n </div>\n <div v-if=\"debugInfo.supplyQueue.items.length > 8\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.supplyQueue.items.length - 8 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n\n <!-- Failed Cards Queue -->\n <v-col cols=\"12\" md=\"4\">\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-alert-circle</v-icon>\n <strong>Failed Cards Queue</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Length: {{ debugInfo.failedQueue.length }}</span>\n <span class=\"text-caption ml-2\">Dequeued: {{ debugInfo.failedQueue.dequeueCount }}</span>\n </div>\n <div v-if=\"debugInfo.failedQueue.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.failedQueue.items.slice(0, 5)\"\n :key=\"idx\"\n class=\"debug-item\"\n >\n <span class=\"text-caption\">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>\n <span class=\"text-caption text-grey ml-1\">({{ item.status }})</span>\n </div>\n <div v-if=\"debugInfo.failedQueue.items.length > 5\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.failedQueue.items.length - 5 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n </v-row>\n\n <!-- Hydrated Cards Cache -->\n <v-row dense>\n <v-col cols=\"12\">\n <v-divider class=\"my-2\"></v-divider>\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-database</v-icon>\n <strong>Hydrated Cards Cache</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Cached: {{ debugInfo.hydratedCache.count }}</span>\n <span class=\"text-caption ml-2\">Failed Cache: {{ debugInfo.hydratedCache.failedCacheSize }}</span>\n </div>\n <div v-if=\"debugInfo.hydratedCache.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.hydratedCache.items.slice(0, 8)\"\n :key=\"idx\"\n class=\"debug-item d-inline-block mr-3\"\n >\n <span class=\"text-caption\">{{ item.courseID }}::{{ item.cardID }}</span>\n </div>\n <div v-if=\"debugInfo.hydratedCache.items.length > 8\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.hydratedCache.items.length - 8 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n </v-row>\n </v-card-text>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType, computed, ref, onMounted, onUnmounted } from 'vue';\nimport { SessionController } from '@vue-skuilder/db';\n\ninterface QueueDebugInfo {\n length: number;\n dequeueCount: number;\n items: Array<{ courseID: string; cardID: string; status: string; score?: number }>;\n}\n\ninterface HydratedCacheInfo {\n count: number;\n failedCacheSize: number;\n items: Array<{ courseID: string; cardID: string }>;\n}\n\nexport interface SessionDebugInfo {\n supplyQueue: QueueDebugInfo;\n failedQueue: QueueDebugInfo;\n hydratedCache: HydratedCacheInfo;\n}\n\nexport default defineComponent({\n name: 'SessionControllerDebug',\n\n props: {\n sessionController: {\n type: Object as PropType<SessionController<any> | null>,\n required: true,\n },\n },\n\n setup(props) {\n const refreshTrigger = ref(0);\n let pollInterval: NodeJS.Timeout | null = null;\n\n onMounted(() => {\n // Poll every 500ms to update debug display\n pollInterval = setInterval(() => {\n refreshTrigger.value++;\n }, 500);\n });\n\n onUnmounted(() => {\n if (pollInterval) {\n clearInterval(pollInterval);\n }\n });\n\n const debugInfo = computed((): SessionDebugInfo => {\n // Create dependency on refreshTrigger to force updates\n refreshTrigger.value;\n\n if (!props.sessionController) {\n return {\n supplyQueue: { length: 0, dequeueCount: 0, items: [] },\n failedQueue: { length: 0, dequeueCount: 0, items: [] },\n hydratedCache: { count: 0, failedCacheSize: 0, items: [] },\n };\n }\n\n return props.sessionController.getDebugInfo();\n });\n\n /** Format a rank score: finite → 2dp, `+INF` → REQ (required), missing → ''. */\n const fmtScore = (score?: number): string => {\n if (score === undefined) return '';\n if (!Number.isFinite(score)) return 'REQ';\n return score.toFixed(2);\n };\n\n return {\n debugInfo,\n fmtScore,\n };\n },\n});\n</script>\n\n<style scoped>\n.session-debug {\n font-family: 'Courier New', monospace;\n font-size: 0.75rem;\n max-height: 400px;\n overflow-y: auto;\n}\n\n.debug-section {\n padding: 8px;\n background-color: rgba(255, 255, 255, 0.05);\n border-radius: 4px;\n min-height: 120px;\n}\n\n.debug-header {\n display: flex;\n align-items: center;\n margin-bottom: 4px;\n padding-bottom: 4px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.debug-stats {\n margin-bottom: 8px;\n display: flex;\n gap: 8px;\n}\n\n.debug-items {\n margin-top: 4px;\n padding-left: 8px;\n}\n\n.debug-item {\n padding: 2px 0;\n border-left: 2px solid rgba(255, 255, 255, 0.2);\n padding-left: 6px;\n margin-bottom: 2px;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { computed as e, defineComponent as t, onMounted as n, onUnmounted as r, ref as i } from "vue";
|
|
3
|
+
//#region src/components/SessionControllerDebug.vue?vue&type=script&lang.ts
|
|
4
|
+
var a = t({
|
|
5
|
+
name: "SessionControllerDebug",
|
|
6
|
+
props: { sessionController: {
|
|
7
|
+
type: Object,
|
|
8
|
+
required: !0
|
|
9
|
+
} },
|
|
10
|
+
setup(t) {
|
|
11
|
+
let a = i(0), o = null;
|
|
12
|
+
n(() => {
|
|
13
|
+
o = setInterval(() => {
|
|
14
|
+
a.value++;
|
|
15
|
+
}, 500);
|
|
16
|
+
}), r(() => {
|
|
17
|
+
o && clearInterval(o);
|
|
18
|
+
});
|
|
19
|
+
let s = e(() => (a.value, t.sessionController ? t.sessionController.getDebugInfo() : {
|
|
20
|
+
supplyQueue: {
|
|
21
|
+
length: 0,
|
|
22
|
+
dequeueCount: 0,
|
|
23
|
+
items: []
|
|
24
|
+
},
|
|
25
|
+
failedQueue: {
|
|
26
|
+
length: 0,
|
|
27
|
+
dequeueCount: 0,
|
|
28
|
+
items: []
|
|
29
|
+
},
|
|
30
|
+
hydratedCache: {
|
|
31
|
+
count: 0,
|
|
32
|
+
failedCacheSize: 0,
|
|
33
|
+
items: []
|
|
34
|
+
}
|
|
35
|
+
})), fmtScore = (e) => e === void 0 ? "" : Number.isFinite(e) ? e.toFixed(2) : "REQ";
|
|
36
|
+
return {
|
|
37
|
+
debugInfo: s,
|
|
38
|
+
fmtScore
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
//#endregion
|
|
43
|
+
export { a as default };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=SessionControllerDebug.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionControllerDebug.vue_vue_type_script_lang.mjs","names":[],"sources":["../../src/components/SessionControllerDebug.vue"],"sourcesContent":["<template>\n <v-card v-if=\"sessionController\" class=\"session-debug ma-2\" elevation=\"2\">\n <v-card-title class=\"text-caption bg-grey-darken-3\">\n Session Controller Debug\n <v-spacer></v-spacer>\n <v-icon size=\"small\">mdi-bug</v-icon>\n </v-card-title>\n\n <v-card-text class=\"pa-2\">\n <v-row dense>\n <!-- Supply Queue (new + review, rank-ordered) -->\n <v-col cols=\"12\" md=\"8\">\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-sort</v-icon>\n <strong>Supply Queue</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Length: {{ debugInfo.supplyQueue.length }}</span>\n <span class=\"text-caption ml-2\">Dequeued: {{ debugInfo.supplyQueue.dequeueCount }}</span>\n </div>\n <div v-if=\"debugInfo.supplyQueue.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.supplyQueue.items.slice(0, 8)\"\n :key=\"idx\"\n class=\"debug-item\"\n >\n <span class=\"text-caption\">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>\n <span class=\"text-caption text-grey ml-1\">({{ item.status }})</span>\n <span class=\"text-caption ml-1\" style=\"color:#90caf9\">{{ fmtScore(item.score) }}</span>\n </div>\n <div v-if=\"debugInfo.supplyQueue.items.length > 8\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.supplyQueue.items.length - 8 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n\n <!-- Failed Cards Queue -->\n <v-col cols=\"12\" md=\"4\">\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-alert-circle</v-icon>\n <strong>Failed Cards Queue</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Length: {{ debugInfo.failedQueue.length }}</span>\n <span class=\"text-caption ml-2\">Dequeued: {{ debugInfo.failedQueue.dequeueCount }}</span>\n </div>\n <div v-if=\"debugInfo.failedQueue.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.failedQueue.items.slice(0, 5)\"\n :key=\"idx\"\n class=\"debug-item\"\n >\n <span class=\"text-caption\">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>\n <span class=\"text-caption text-grey ml-1\">({{ item.status }})</span>\n </div>\n <div v-if=\"debugInfo.failedQueue.items.length > 5\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.failedQueue.items.length - 5 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n </v-row>\n\n <!-- Hydrated Cards Cache -->\n <v-row dense>\n <v-col cols=\"12\">\n <v-divider class=\"my-2\"></v-divider>\n <div class=\"debug-section\">\n <div class=\"debug-header\">\n <v-icon size=\"x-small\" class=\"mr-1\">mdi-database</v-icon>\n <strong>Hydrated Cards Cache</strong>\n </div>\n <div class=\"debug-stats\">\n <span class=\"text-caption\">Cached: {{ debugInfo.hydratedCache.count }}</span>\n <span class=\"text-caption ml-2\">Failed Cache: {{ debugInfo.hydratedCache.failedCacheSize }}</span>\n </div>\n <div v-if=\"debugInfo.hydratedCache.items.length > 0\" class=\"debug-items\">\n <div\n v-for=\"(item, idx) in debugInfo.hydratedCache.items.slice(0, 8)\"\n :key=\"idx\"\n class=\"debug-item d-inline-block mr-3\"\n >\n <span class=\"text-caption\">{{ item.courseID }}::{{ item.cardID }}</span>\n </div>\n <div v-if=\"debugInfo.hydratedCache.items.length > 8\" class=\"text-caption text-grey\">\n ... +{{ debugInfo.hydratedCache.items.length - 8 }} more\n </div>\n </div>\n <div v-else class=\"text-caption text-grey\">\n (empty)\n </div>\n </div>\n </v-col>\n </v-row>\n </v-card-text>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType, computed, ref, onMounted, onUnmounted } from 'vue';\nimport { SessionController } from '@vue-skuilder/db';\n\ninterface QueueDebugInfo {\n length: number;\n dequeueCount: number;\n items: Array<{ courseID: string; cardID: string; status: string; score?: number }>;\n}\n\ninterface HydratedCacheInfo {\n count: number;\n failedCacheSize: number;\n items: Array<{ courseID: string; cardID: string }>;\n}\n\nexport interface SessionDebugInfo {\n supplyQueue: QueueDebugInfo;\n failedQueue: QueueDebugInfo;\n hydratedCache: HydratedCacheInfo;\n}\n\nexport default defineComponent({\n name: 'SessionControllerDebug',\n\n props: {\n sessionController: {\n type: Object as PropType<SessionController<any> | null>,\n required: true,\n },\n },\n\n setup(props) {\n const refreshTrigger = ref(0);\n let pollInterval: NodeJS.Timeout | null = null;\n\n onMounted(() => {\n // Poll every 500ms to update debug display\n pollInterval = setInterval(() => {\n refreshTrigger.value++;\n }, 500);\n });\n\n onUnmounted(() => {\n if (pollInterval) {\n clearInterval(pollInterval);\n }\n });\n\n const debugInfo = computed((): SessionDebugInfo => {\n // Create dependency on refreshTrigger to force updates\n refreshTrigger.value;\n\n if (!props.sessionController) {\n return {\n supplyQueue: { length: 0, dequeueCount: 0, items: [] },\n failedQueue: { length: 0, dequeueCount: 0, items: [] },\n hydratedCache: { count: 0, failedCacheSize: 0, items: [] },\n };\n }\n\n return props.sessionController.getDebugInfo();\n });\n\n /** Format a rank score: finite → 2dp, `+INF` → REQ (required), missing → ''. */\n const fmtScore = (score?: number): string => {\n if (score === undefined) return '';\n if (!Number.isFinite(score)) return 'REQ';\n return score.toFixed(2);\n };\n\n return {\n debugInfo,\n fmtScore,\n };\n },\n});\n</script>\n\n<style scoped>\n.session-debug {\n font-family: 'Courier New', monospace;\n font-size: 0.75rem;\n max-height: 400px;\n overflow-y: auto;\n}\n\n.debug-section {\n padding: 8px;\n background-color: rgba(255, 255, 255, 0.05);\n border-radius: 4px;\n min-height: 120px;\n}\n\n.debug-header {\n display: flex;\n align-items: center;\n margin-bottom: 4px;\n padding-bottom: 4px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.debug-stats {\n margin-bottom: 8px;\n display: flex;\n gap: 8px;\n}\n\n.debug-items {\n margin-top: 4px;\n padding-left: 8px;\n}\n\n.debug-item {\n padding: 2px 0;\n border-left: 2px solid rgba(255, 255, 255, 0.2);\n padding-left: 6px;\n margin-bottom: 2px;\n}\n</style>\n"],"mappings":";;;AAiIA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,OAAO,EACL,mBAAmB;EACjB,MAAM;EACN,UAAU;EACX,EACF;CAED,MAAM,GAAO;EACX,IAAM,IAAiB,EAAI,EAAE,EACzB,IAAsC;AAS1C,EAPA,QAAgB;AAEd,OAAe,kBAAkB;AAC/B,MAAe;MACd,IAAI;IACP,EAEF,QAAkB;AAChB,GAAI,KACF,cAAc,EAAa;IAE7B;EAEF,IAAM,IAAY,SAEhB,EAAe,OAEV,EAAM,oBAQJ,EAAM,kBAAkB,cAAc,GAPpC;GACL,aAAa;IAAE,QAAQ;IAAG,cAAc;IAAG,OAAO,EAAC;IAAG;GACtD,aAAa;IAAE,QAAQ;IAAG,cAAc;IAAG,OAAO,EAAC;IAAG;GACtD,eAAe;IAAE,OAAO;IAAG,iBAAiB;IAAG,OAAO,EAAC;IAAG;GAC3D,EAIH,EAGI,YAAY,MACZ,MAAU,KAAA,IAAkB,KAC3B,OAAO,SAAS,EAAM,GACpB,EAAM,QAAQ,EAAE,GADa;AAItC,SAAO;GACL;GACA;GACD;;CAEJ,CAAC"}
|