@pie-players/pie-section-player-tools-session-debugger 0.3.4 → 0.3.5
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/SectionSessionPanel.svelte +103 -67
- package/dist/section-player-tools-session-debugger.js +1199 -1169
- package/package.json +3 -3
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
currentItemIndex: number | null;
|
|
30
30
|
currentItemId: string | null;
|
|
31
31
|
visitedItemIdentifiers: string[];
|
|
32
|
+
loadingComplete: boolean;
|
|
33
|
+
totalRegistered: number;
|
|
34
|
+
totalLoaded: number;
|
|
35
|
+
itemsComplete: boolean;
|
|
36
|
+
completedCount: number;
|
|
37
|
+
totalItems: number;
|
|
32
38
|
updatedAt: number | null;
|
|
33
39
|
lastChangedItemId: string | null;
|
|
34
40
|
itemSessions: Record<string, unknown>;
|
|
@@ -39,15 +45,31 @@
|
|
|
39
45
|
currentItemId?: string;
|
|
40
46
|
visitedItemIdentifiers?: string[];
|
|
41
47
|
itemSessions?: Record<string, unknown>;
|
|
48
|
+
loadingComplete?: boolean;
|
|
49
|
+
totalRegistered?: number;
|
|
50
|
+
totalLoaded?: number;
|
|
51
|
+
itemsComplete?: boolean;
|
|
52
|
+
completedCount?: number;
|
|
53
|
+
totalItems?: number;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type SectionSessionStateLike = {
|
|
57
|
+
itemSessions?: Record<string, unknown>;
|
|
42
58
|
};
|
|
43
59
|
|
|
44
60
|
type SectionControllerLike = {
|
|
45
|
-
|
|
61
|
+
getRuntimeState?: () => SectionAttemptSliceLike | null;
|
|
62
|
+
getSessionState?: () => SectionSessionStateLike | null;
|
|
46
63
|
subscribe?: (listener: (event: { itemId?: string; timestamp?: number }) => void) => () => void;
|
|
47
64
|
};
|
|
48
65
|
|
|
49
66
|
type ToolkitCoordinatorLike = {
|
|
50
67
|
getSectionController?: (args: { sectionId: string; attemptId?: string }) => SectionControllerLike | undefined;
|
|
68
|
+
subscribeSectionEvents: (args: {
|
|
69
|
+
sectionId: string;
|
|
70
|
+
attemptId?: string;
|
|
71
|
+
listener: (event: { itemId?: string; timestamp?: number }) => void;
|
|
72
|
+
}) => () => void;
|
|
51
73
|
onSectionControllerLifecycle?: (
|
|
52
74
|
listener: (event: { type: 'ready' | 'disposed'; key?: { sectionId?: string; attemptId?: string } }) => void
|
|
53
75
|
) => () => void;
|
|
@@ -73,15 +95,29 @@
|
|
|
73
95
|
currentItemIndex: null,
|
|
74
96
|
currentItemId: null,
|
|
75
97
|
visitedItemIdentifiers: [],
|
|
98
|
+
loadingComplete: false,
|
|
99
|
+
totalRegistered: 0,
|
|
100
|
+
totalLoaded: 0,
|
|
101
|
+
itemsComplete: false,
|
|
102
|
+
completedCount: 0,
|
|
103
|
+
totalItems: 0,
|
|
76
104
|
updatedAt: null,
|
|
77
105
|
lastChangedItemId: null,
|
|
78
106
|
itemSessions: {}
|
|
79
107
|
});
|
|
80
|
-
let activeController: SectionControllerLike | null = null;
|
|
81
108
|
let unsubscribeController: (() => void) | null = null;
|
|
82
109
|
let unsubscribeLifecycle: (() => void) | null = null;
|
|
83
110
|
let controllerAvailable = $state(false);
|
|
84
|
-
let
|
|
111
|
+
let resubscribeQueued = false;
|
|
112
|
+
const subscriptionTarget: {
|
|
113
|
+
controller: SectionControllerLike | null;
|
|
114
|
+
sectionId: string;
|
|
115
|
+
attemptId?: string;
|
|
116
|
+
} = {
|
|
117
|
+
controller: null,
|
|
118
|
+
sectionId: '',
|
|
119
|
+
attemptId: undefined
|
|
120
|
+
};
|
|
85
121
|
|
|
86
122
|
function cloneSessionSnapshot<T>(value: T): T {
|
|
87
123
|
try {
|
|
@@ -111,7 +147,8 @@
|
|
|
111
147
|
controllerOverride?: SectionControllerLike | null
|
|
112
148
|
) {
|
|
113
149
|
const controller = controllerOverride || getController();
|
|
114
|
-
const sectionSlice = controller?.
|
|
150
|
+
const sectionSlice = controller?.getRuntimeState?.() || null;
|
|
151
|
+
const persistedSlice = controller?.getSessionState?.() || null;
|
|
115
152
|
controllerAvailable = Boolean(controller);
|
|
116
153
|
sessionPanelSnapshot = {
|
|
117
154
|
currentItemIndex:
|
|
@@ -123,30 +160,26 @@
|
|
|
123
160
|
? sectionSlice.currentItemId
|
|
124
161
|
: null,
|
|
125
162
|
visitedItemIdentifiers: cloneSessionSnapshot(sectionSlice?.visitedItemIdentifiers || []),
|
|
163
|
+
loadingComplete: sectionSlice?.loadingComplete === true,
|
|
164
|
+
totalRegistered: typeof sectionSlice?.totalRegistered === 'number' ? sectionSlice.totalRegistered : 0,
|
|
165
|
+
totalLoaded: typeof sectionSlice?.totalLoaded === 'number' ? sectionSlice.totalLoaded : 0,
|
|
166
|
+
itemsComplete: sectionSlice?.itemsComplete === true,
|
|
167
|
+
completedCount: typeof sectionSlice?.completedCount === 'number' ? sectionSlice.completedCount : 0,
|
|
168
|
+
totalItems: typeof sectionSlice?.totalItems === 'number' ? sectionSlice.totalItems : 0,
|
|
126
169
|
updatedAt: meta?.updatedAt || Date.now(),
|
|
127
170
|
lastChangedItemId: meta?.itemId || null,
|
|
128
|
-
itemSessions: cloneSessionSnapshot(
|
|
171
|
+
itemSessions: cloneSessionSnapshot(
|
|
172
|
+
sectionSlice?.itemSessions || persistedSlice?.itemSessions || {}
|
|
173
|
+
)
|
|
129
174
|
};
|
|
130
175
|
}
|
|
131
176
|
|
|
132
|
-
function queueRefresh(meta?: { itemId?: string; updatedAt?: number }) {
|
|
133
|
-
if (refreshQueued) return;
|
|
134
|
-
refreshQueued = true;
|
|
135
|
-
queueMicrotask(() => {
|
|
136
|
-
refreshQueued = false;
|
|
137
|
-
ensureControllerSubscription();
|
|
138
|
-
refreshFromController(
|
|
139
|
-
meta || {
|
|
140
|
-
updatedAt: Date.now()
|
|
141
|
-
}
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
177
|
function detachControllerSubscription() {
|
|
147
178
|
unsubscribeController?.();
|
|
148
179
|
unsubscribeController = null;
|
|
149
|
-
|
|
180
|
+
subscriptionTarget.controller = null;
|
|
181
|
+
subscriptionTarget.sectionId = '';
|
|
182
|
+
subscriptionTarget.attemptId = undefined;
|
|
150
183
|
}
|
|
151
184
|
|
|
152
185
|
function detachLifecycleSubscription() {
|
|
@@ -154,6 +187,13 @@
|
|
|
154
187
|
unsubscribeLifecycle = null;
|
|
155
188
|
}
|
|
156
189
|
|
|
190
|
+
function handleControllerEvent(detail: { itemId?: string; timestamp?: number }): void {
|
|
191
|
+
refreshFromController({
|
|
192
|
+
itemId: detail?.itemId,
|
|
193
|
+
updatedAt: detail?.timestamp || Date.now()
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
157
197
|
function ensureControllerSubscription() {
|
|
158
198
|
const controller = getController() || null;
|
|
159
199
|
if (!controller) {
|
|
@@ -163,32 +203,45 @@
|
|
|
163
203
|
currentItemIndex: null,
|
|
164
204
|
currentItemId: null,
|
|
165
205
|
visitedItemIdentifiers: [],
|
|
206
|
+
loadingComplete: false,
|
|
207
|
+
totalRegistered: 0,
|
|
208
|
+
totalLoaded: 0,
|
|
209
|
+
itemsComplete: false,
|
|
210
|
+
completedCount: 0,
|
|
211
|
+
totalItems: 0,
|
|
166
212
|
updatedAt: Date.now(),
|
|
167
213
|
lastChangedItemId: null,
|
|
168
214
|
itemSessions: {}
|
|
169
215
|
};
|
|
170
216
|
return;
|
|
171
217
|
}
|
|
172
|
-
|
|
218
|
+
const nextAttemptId = attemptId || undefined;
|
|
219
|
+
const isSameTarget =
|
|
220
|
+
subscriptionTarget.controller === controller &&
|
|
221
|
+
subscriptionTarget.sectionId === sectionId &&
|
|
222
|
+
subscriptionTarget.attemptId === nextAttemptId;
|
|
223
|
+
if (isSameTarget && unsubscribeController) {
|
|
224
|
+
refreshFromController(undefined, controller);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
173
227
|
detachControllerSubscription();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
controller
|
|
184
|
-
);
|
|
185
|
-
}) || null;
|
|
228
|
+
unsubscribeController = toolkitCoordinator?.subscribeSectionEvents({
|
|
229
|
+
sectionId,
|
|
230
|
+
attemptId,
|
|
231
|
+
listener: handleControllerEvent
|
|
232
|
+
}) || null;
|
|
233
|
+
subscriptionTarget.controller = controller;
|
|
234
|
+
subscriptionTarget.sectionId = sectionId;
|
|
235
|
+
subscriptionTarget.attemptId = nextAttemptId;
|
|
186
236
|
refreshFromController(undefined, controller);
|
|
187
237
|
}
|
|
188
238
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
239
|
+
function queueEnsureControllerSubscription(): void {
|
|
240
|
+
if (resubscribeQueued) return;
|
|
241
|
+
resubscribeQueued = true;
|
|
242
|
+
queueMicrotask(() => {
|
|
243
|
+
resubscribeQueued = false;
|
|
244
|
+
ensureControllerSubscription();
|
|
192
245
|
});
|
|
193
246
|
}
|
|
194
247
|
|
|
@@ -198,7 +251,7 @@
|
|
|
198
251
|
detachLifecycleSubscription();
|
|
199
252
|
unsubscribeLifecycle = toolkitCoordinator.onSectionControllerLifecycle?.((event) => {
|
|
200
253
|
if (!isMatchingSectionControllerLifecycleEvent(event, sectionId, attemptId)) return;
|
|
201
|
-
|
|
254
|
+
queueEnsureControllerSubscription();
|
|
202
255
|
refreshFromController({
|
|
203
256
|
updatedAt: Date.now()
|
|
204
257
|
});
|
|
@@ -229,20 +282,6 @@
|
|
|
229
282
|
sessionWindowY = initial.y;
|
|
230
283
|
sessionWindowWidth = initial.width;
|
|
231
284
|
sessionWindowHeight = initial.height;
|
|
232
|
-
|
|
233
|
-
const handleRuntimeSessionEvent = () => {
|
|
234
|
-
queueRefresh({
|
|
235
|
-
updatedAt: Date.now()
|
|
236
|
-
});
|
|
237
|
-
};
|
|
238
|
-
document.addEventListener('session-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
239
|
-
document.addEventListener('item-session-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
240
|
-
document.addEventListener('composition-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
241
|
-
return () => {
|
|
242
|
-
document.removeEventListener('session-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
243
|
-
document.removeEventListener('item-session-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
244
|
-
document.removeEventListener('composition-changed', handleRuntimeSessionEvent as EventListener, true);
|
|
245
|
-
};
|
|
246
285
|
});
|
|
247
286
|
|
|
248
287
|
const pointerController = createFloatingPanelPointerController({
|
|
@@ -320,19 +359,20 @@
|
|
|
320
359
|
</svg>
|
|
321
360
|
<span class="pie-section-player-tools-session-debugger__text-xs">Section controller not available for this section yet.</span>
|
|
322
361
|
</div>
|
|
323
|
-
{:else if Object.keys(sessionPanelSnapshot.itemSessions || {}).length === 0}
|
|
324
|
-
<div class="pie-section-player-tools-session-debugger__alert pie-section-player-tools-session-debugger__alert--info">
|
|
325
|
-
<svg
|
|
326
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
327
|
-
class="pie-section-player-tools-session-debugger__icon-md"
|
|
328
|
-
fill="none"
|
|
329
|
-
viewBox="0 0 24 24"
|
|
330
|
-
>
|
|
331
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
332
|
-
</svg>
|
|
333
|
-
<span class="pie-section-player-tools-session-debugger__text-xs">No section session data yet. Interact with the questions to see updates.</span>
|
|
334
|
-
</div>
|
|
335
362
|
{:else}
|
|
363
|
+
{#if Object.keys(sessionPanelSnapshot.itemSessions || {}).length === 0}
|
|
364
|
+
<div class="pie-section-player-tools-session-debugger__alert pie-section-player-tools-session-debugger__alert--info">
|
|
365
|
+
<svg
|
|
366
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
367
|
+
class="pie-section-player-tools-session-debugger__icon-md"
|
|
368
|
+
fill="none"
|
|
369
|
+
viewBox="0 0 24 24"
|
|
370
|
+
>
|
|
371
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
372
|
+
</svg>
|
|
373
|
+
<span class="pie-section-player-tools-session-debugger__text-xs">No section session data yet. Interact with the questions to see updates.</span>
|
|
374
|
+
</div>
|
|
375
|
+
{/if}
|
|
336
376
|
<div class="pie-section-player-tools-session-debugger__card">
|
|
337
377
|
<div class="pie-section-player-tools-session-debugger__card-title">
|
|
338
378
|
Item Sessions Snapshot
|
|
@@ -401,8 +441,4 @@
|
|
|
401
441
|
min-height: 0;
|
|
402
442
|
}
|
|
403
443
|
|
|
404
|
-
.pie-section-player-tools-session-debugger__resize-handle {
|
|
405
|
-
user-select: none;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
444
|
</style>
|