Skip to content

Commit 7d35ea2

Browse files
committed
add debug view for active studysessions...
manual trigger via setting window.debugMode == true in browser console
1 parent 3be63af commit 7d35ea2

File tree

3 files changed

+247
-4
lines changed

3 files changed

+247
-4
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
<template>
2+
<v-card v-if="sessionController" class="session-debug ma-2" elevation="2">
3+
<v-card-title class="text-caption bg-grey-darken-3">
4+
Session Controller Debug
5+
<v-spacer></v-spacer>
6+
<v-icon size="small">mdi-bug</v-icon>
7+
</v-card-title>
8+
9+
<v-card-text class="pa-2">
10+
<v-row dense>
11+
<!-- Review Queue -->
12+
<v-col cols="12" md="4">
13+
<div class="debug-section">
14+
<div class="debug-header">
15+
<v-icon size="x-small" class="mr-1">mdi-calendar-check</v-icon>
16+
<strong>Review Queue</strong>
17+
</div>
18+
<div class="debug-stats">
19+
<span class="text-caption">Length: {{ debugInfo.reviewQueue.length }}</span>
20+
<span class="text-caption ml-2">Dequeued: {{ debugInfo.reviewQueue.dequeueCount }}</span>
21+
</div>
22+
<div v-if="debugInfo.reviewQueue.items.length > 0" class="debug-items">
23+
<div
24+
v-for="(item, idx) in debugInfo.reviewQueue.items.slice(0, 5)"
25+
:key="idx"
26+
class="debug-item"
27+
>
28+
<span class="text-caption">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>
29+
<span class="text-caption text-grey ml-1">({{ item.status }})</span>
30+
</div>
31+
<div v-if="debugInfo.reviewQueue.items.length > 5" class="text-caption text-grey">
32+
... +{{ debugInfo.reviewQueue.items.length - 5 }} more
33+
</div>
34+
</div>
35+
<div v-else class="text-caption text-grey">
36+
(empty)
37+
</div>
38+
</div>
39+
</v-col>
40+
41+
<!-- New Cards Queue -->
42+
<v-col cols="12" md="4">
43+
<div class="debug-section">
44+
<div class="debug-header">
45+
<v-icon size="x-small" class="mr-1">mdi-file-document-plus</v-icon>
46+
<strong>New Cards Queue</strong>
47+
</div>
48+
<div class="debug-stats">
49+
<span class="text-caption">Length: {{ debugInfo.newQueue.length }}</span>
50+
<span class="text-caption ml-2">Dequeued: {{ debugInfo.newQueue.dequeueCount }}</span>
51+
</div>
52+
<div v-if="debugInfo.newQueue.items.length > 0" class="debug-items">
53+
<div
54+
v-for="(item, idx) in debugInfo.newQueue.items.slice(0, 5)"
55+
:key="idx"
56+
class="debug-item"
57+
>
58+
<span class="text-caption">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>
59+
<span class="text-caption text-grey ml-1">({{ item.status }})</span>
60+
</div>
61+
<div v-if="debugInfo.newQueue.items.length > 5" class="text-caption text-grey">
62+
... +{{ debugInfo.newQueue.items.length - 5 }} more
63+
</div>
64+
</div>
65+
<div v-else class="text-caption text-grey">
66+
(empty)
67+
</div>
68+
</div>
69+
</v-col>
70+
71+
<!-- Failed Cards Queue -->
72+
<v-col cols="12" md="4">
73+
<div class="debug-section">
74+
<div class="debug-header">
75+
<v-icon size="x-small" class="mr-1">mdi-alert-circle</v-icon>
76+
<strong>Failed Cards Queue</strong>
77+
</div>
78+
<div class="debug-stats">
79+
<span class="text-caption">Length: {{ debugInfo.failedQueue.length }}</span>
80+
<span class="text-caption ml-2">Dequeued: {{ debugInfo.failedQueue.dequeueCount }}</span>
81+
</div>
82+
<div v-if="debugInfo.failedQueue.items.length > 0" class="debug-items">
83+
<div
84+
v-for="(item, idx) in debugInfo.failedQueue.items.slice(0, 5)"
85+
:key="idx"
86+
class="debug-item"
87+
>
88+
<span class="text-caption">{{ idx }}: {{ item.courseID }}::{{ item.cardID }}</span>
89+
<span class="text-caption text-grey ml-1">({{ item.status }})</span>
90+
</div>
91+
<div v-if="debugInfo.failedQueue.items.length > 5" class="text-caption text-grey">
92+
... +{{ debugInfo.failedQueue.items.length - 5 }} more
93+
</div>
94+
</div>
95+
<div v-else class="text-caption text-grey">
96+
(empty)
97+
</div>
98+
</div>
99+
</v-col>
100+
</v-row>
101+
102+
<!-- Hydrated Cards Cache -->
103+
<v-row dense>
104+
<v-col cols="12">
105+
<v-divider class="my-2"></v-divider>
106+
<div class="debug-section">
107+
<div class="debug-header">
108+
<v-icon size="x-small" class="mr-1">mdi-database</v-icon>
109+
<strong>Hydrated Cards Cache</strong>
110+
</div>
111+
<div class="debug-stats">
112+
<span class="text-caption">Cached: {{ debugInfo.hydratedCache.count }}</span>
113+
<span class="text-caption ml-2">Failed Cache: {{ debugInfo.hydratedCache.failedCacheSize }}</span>
114+
</div>
115+
<div v-if="debugInfo.hydratedCache.items.length > 0" class="debug-items">
116+
<div
117+
v-for="(item, idx) in debugInfo.hydratedCache.items.slice(0, 8)"
118+
:key="idx"
119+
class="debug-item d-inline-block mr-3"
120+
>
121+
<span class="text-caption">{{ item.courseID }}::{{ item.cardID }}</span>
122+
</div>
123+
<div v-if="debugInfo.hydratedCache.items.length > 8" class="text-caption text-grey">
124+
... +{{ debugInfo.hydratedCache.items.length - 8 }} more
125+
</div>
126+
</div>
127+
<div v-else class="text-caption text-grey">
128+
(empty)
129+
</div>
130+
</div>
131+
</v-col>
132+
</v-row>
133+
</v-card-text>
134+
</v-card>
135+
</template>
136+
137+
<script lang="ts">
138+
import { defineComponent, PropType, computed } from 'vue';
139+
import { SessionController } from '@vue-skuilder/db';
140+
141+
interface QueueDebugInfo {
142+
length: number;
143+
dequeueCount: number;
144+
items: Array<{ courseID: string; cardID: string; status: string }>;
145+
}
146+
147+
interface HydratedCacheInfo {
148+
count: number;
149+
failedCacheSize: number;
150+
items: Array<{ courseID: string; cardID: string }>;
151+
}
152+
153+
export interface SessionDebugInfo {
154+
reviewQueue: QueueDebugInfo;
155+
newQueue: QueueDebugInfo;
156+
failedQueue: QueueDebugInfo;
157+
hydratedCache: HydratedCacheInfo;
158+
}
159+
160+
export default defineComponent({
161+
name: 'SessionControllerDebug',
162+
163+
props: {
164+
sessionController: {
165+
type: Object as PropType<SessionController<any> | null>,
166+
required: true,
167+
},
168+
},
169+
170+
setup(props) {
171+
const debugInfo = computed((): SessionDebugInfo => {
172+
if (!props.sessionController) {
173+
return {
174+
reviewQueue: { length: 0, dequeueCount: 0, items: [] },
175+
newQueue: { length: 0, dequeueCount: 0, items: [] },
176+
failedQueue: { length: 0, dequeueCount: 0, items: [] },
177+
hydratedCache: { count: 0, failedCacheSize: 0, items: [] },
178+
};
179+
}
180+
181+
return props.sessionController.getDebugInfo();
182+
});
183+
184+
return {
185+
debugInfo,
186+
};
187+
},
188+
});
189+
</script>
190+
191+
<style scoped>
192+
.session-debug {
193+
font-family: 'Courier New', monospace;
194+
font-size: 0.75rem;
195+
max-height: 400px;
196+
overflow-y: auto;
197+
}
198+
199+
.debug-section {
200+
padding: 8px;
201+
background-color: rgba(255, 255, 255, 0.05);
202+
border-radius: 4px;
203+
min-height: 120px;
204+
}
205+
206+
.debug-header {
207+
display: flex;
208+
align-items: center;
209+
margin-bottom: 4px;
210+
padding-bottom: 4px;
211+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
212+
}
213+
214+
.debug-stats {
215+
margin-bottom: 8px;
216+
display: flex;
217+
gap: 8px;
218+
}
219+
220+
.debug-items {
221+
margin-top: 4px;
222+
padding-left: 8px;
223+
}
224+
225+
.debug-item {
226+
padding: 2px 0;
227+
border-left: 2px solid rgba(255, 255, 255, 0.2);
228+
padding-left: 6px;
229+
margin-bottom: 2px;
230+
}
231+
</style>

packages/common-ui/src/components/StudySession.vue

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<v-progress-circular v-if="loading" color="primary" indeterminate size="32" width="4" />
77
</v-row>
88

9+
<!-- Debug Panel (only visible if window.debugMode is true) -->
10+
<session-controller-debug v-if="debugMode" :session-controller="sessionController" />
11+
912
<br />
1013

1114
<div v-if="sessionFinished" class="text-h4">
@@ -76,6 +79,7 @@ import SkMouseTrap from './SkMouseTrap.vue';
7679
import { alertUser } from './SnackbarService';
7780
import StudySessionTimer from './StudySessionTimer.vue';
7881
import CardViewer from './cardRendering/CardViewer.vue';
82+
import SessionControllerDebug from './SessionControllerDebug.vue';
7983
8084
import { CourseElo, Status, toCourseElo, ViewData } from '@vue-skuilder/common';
8185
import {
@@ -119,6 +123,7 @@ export default defineComponent({
119123
StudySessionTimer,
120124
SkMouseTrap,
121125
HeatMap,
126+
SessionControllerDebug,
122127
},
123128
124129
props: {
@@ -180,6 +185,7 @@ export default defineComponent({
180185
timeRemaining: 300, // 5 minutes * 60 seconds
181186
intervalHandler: null as NodeJS.Timeout | null,
182187
cardType: '',
188+
debugMode: (window as any).debugMode === true,
183189
};
184190
},
185191
@@ -376,7 +382,13 @@ export default defineComponent({
376382
console.log(`[StudySession] StudySession.processResponse is running...`);
377383
// DEBUG: Added logging to track hanging issue - can be removed if issue resolved
378384
// console.log(`[StudySession] About to call logCardRecord...`);
379-
const cardHistory = this.logCardRecord(r);
385+
386+
let cardHistory;
387+
try {
388+
cardHistory = this.logCardRecord(r);
389+
} catch (e: unknown) {
390+
console.log(`Caught ${e} during putCardHistory...`)
391+
}
380392
// console.log(`[StudySession] logCardRecord called, cardHistory promise created...`);
381393
382394
// Get view constraints for response processing
@@ -473,10 +485,9 @@ export default defineComponent({
473485
},
474486
475487
async logCardRecord(r: CardRecord): Promise<CardHistory<CardRecord>> {
476-
// DEBUG: Added logging to track hanging issue - can be removed if issue resolved
477-
// console.log(`[StudySession] About to call user.putCardRecord...`);
488+
console.log(`[StudySession] About to call user.putCardRecord...`);
478489
const result = await this.user!.putCardRecord(r);
479-
// console.log(`[StudySession] user.putCardRecord completed`);
490+
console.log(`[StudySession] user.putCardRecord completed`);
480491
return result;
481492
},
482493

packages/common-ui/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export * from './composables/useEntitlements';
3535

3636
export { default as StudySession } from './components/StudySession.vue';
3737
export { default as StudySessionTimer } from './components/StudySessionTimer.vue';
38+
export { default as SessionControllerDebug } from './components/SessionControllerDebug.vue';
3839
export type { StudySessionConfig } from './components/StudySession.types';
3940

4041
/*

0 commit comments

Comments
 (0)