Skip to content

Commit 875c8a1

Browse files
Enhance document visibility handling and CWD synchronization
- Added `isDocumentVisible` function to check document visibility. - Updated `updateTimelineTruncationNotice` and `scrollMessagesToBottom` to respect visibility state. - Introduced `normalizeSessionCwdForThread` and `syncCwdInputFromSessionState` for consistent CWD handling. - Modified polling functions to avoid unnecessary operations when the document is hidden. - Enhanced event listeners to manage session state and CWD updates based on visibility. - Improved `isTurnCollapsed` logic in `sessionTimeline.js` for better turn visibility management.
1 parent 53d0a7d commit 875c8a1

5 files changed

Lines changed: 77 additions & 11 deletions

File tree

Buffaly.CodexEmbedded.Web/wwwroot/app.js

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,14 @@ function updateTimelineTruncationNotice() {
273273
timelineTruncationNotice.classList.toggle("hidden", !shouldShow);
274274
}
275275

276+
function isDocumentVisible() {
277+
if (typeof document === "undefined") {
278+
return true;
279+
}
280+
281+
return document.visibilityState !== "hidden";
282+
}
283+
276284
function scrollMessagesToBottom(smooth = false) {
277285
if (!chatMessages) {
278286
return;
@@ -288,6 +296,31 @@ function scrollMessagesToBottom(smooth = false) {
288296
updateTimelineTruncationNotice();
289297
}
290298

299+
function normalizeSessionCwdForThread(threadId, cwdValue) {
300+
const normalizedFromState = normalizeProjectCwd(cwdValue || "");
301+
if (normalizedFromState) {
302+
return normalizedFromState;
303+
}
304+
305+
const entry = getCatalogEntryByThreadId(threadId || "");
306+
return normalizeProjectCwd(entry?.cwd || "");
307+
}
308+
309+
function syncCwdInputFromSessionState(state, options = {}) {
310+
if (!cwdInput || !state) {
311+
return;
312+
}
313+
314+
const nextCwd = normalizeSessionCwdForThread(state.threadId || "", state.cwd || "");
315+
const force = options.force === true;
316+
if (!force && cwdInput.value.trim() === nextCwd) {
317+
return;
318+
}
319+
320+
cwdInput.value = nextCwd;
321+
localStorage.setItem(STORAGE_CWD_KEY, nextCwd);
322+
}
323+
291324
function setJumpCollapseMode(enabled) {
292325
const hasState = !!getActiveSessionState();
293326
const next = !!enabled && hasState;
@@ -3628,6 +3661,9 @@ function startVsSelectionPolling() {
36283661

36293662
refreshVsSelectionSnapshot({ force: true }).catch(() => {});
36303663
vsSelectionPollTimer = setInterval(() => {
3664+
if (!isDocumentVisible()) {
3665+
return;
3666+
}
36313667
refreshVsSelectionSnapshot().catch(() => {});
36323668
}, VS_SELECTION_POLL_INTERVAL_MS);
36333669
}
@@ -3993,8 +4029,8 @@ async function queuePrompt(sessionId, promptText, images = [], options = {}) {
39934029
return false;
39944030
}
39954031

3996-
const turnCwd = cwdInput.value.trim();
39974032
const state = sessions.get(sessionId);
4033+
const turnCwd = normalizeSessionCwdForThread(state?.threadId || "", state?.cwd || "") || cwdInput.value.trim();
39984034
const turnModel = normalizeModelValue(state?.model || "");
39994035
const turnEffort = normalizeReasoningEffort(state?.reasoningEffort || "");
40004036

@@ -4127,8 +4163,8 @@ function restoreQueuedPromptForEditing(text, images = []) {
41274163

41284164
function startTurn(sessionId, promptText, images = [], options = {}) {
41294165
const turnInput = buildTurnInput(promptText, images, { trimText: true });
4130-
const turnCwd = cwdInput.value.trim();
41314166
const state = sessions.get(sessionId);
4167+
const turnCwd = normalizeSessionCwdForThread(state?.threadId || "", state?.cwd || "") || cwdInput.value.trim();
41324168
const turnModel = normalizeModelValue(state?.model || "");
41334169
if (!sessionId || !turnInput.hasContent) {
41344170
return false;
@@ -4474,14 +4510,19 @@ function restartTimelinePolling() {
44744510
}
44754511

44764512
const shouldInitialLoad = timelineCursor === null;
4477-
pollTimelineOnce(shouldInitialLoad, generation).catch((error) => {
4478-
handleTimelinePollError(error);
4479-
});
4513+
const runTimelinePoll = (initial) => {
4514+
if (!isDocumentVisible()) {
4515+
return;
4516+
}
44804517

4481-
timelinePollTimer = setInterval(() => {
4482-
pollTimelineOnce(false, generation).catch((error) => {
4518+
pollTimelineOnce(initial, generation).catch((error) => {
44834519
handleTimelinePollError(error);
44844520
});
4521+
};
4522+
runTimelinePoll(shouldInitialLoad);
4523+
4524+
timelinePollTimer = setInterval(() => {
4525+
runTimelinePoll(false);
44854526
}, TIMELINE_POLL_INTERVAL_MS);
44864527
}
44874528

@@ -4681,6 +4722,9 @@ function setActiveSession(sessionId, options = {}) {
46814722
}
46824723
stopSessionBtn.disabled = false;
46834724
const state = sessions.get(sessionId);
4725+
if (changed && state) {
4726+
syncCwdInputFromSessionState(state);
4727+
}
46844728
markThreadCompletionSeen(state?.threadId || "");
46854729
if (state?.threadId) {
46864730
const preferred = getPreferredModelForThread(state.threadId);
@@ -5176,6 +5220,9 @@ function startSessionListSync() {
51765220
stopSessionListSync();
51775221
return;
51785222
}
5223+
if (!isDocumentVisible()) {
5224+
return;
5225+
}
51795226
send("session_list");
51805227
}, SESSION_LIST_SYNC_INTERVAL_MS);
51815228
}
@@ -6030,6 +6077,9 @@ function handleServerEvent(frame) {
60306077
state.cwd = nextCwd;
60316078
sidebarStateChanged = true;
60326079
sessionConfigChanged = true;
6080+
if (sessionId === activeSessionId) {
6081+
syncCwdInputFromSessionState(state, { force: true });
6082+
}
60336083
}
60346084
}
60356085

@@ -6701,6 +6751,10 @@ cwdInput.addEventListener("change", () => {
67016751
const normalized = normalizeProjectCwd(cwdInput.value.trim());
67026752
cwdInput.value = normalized;
67036753
localStorage.setItem(STORAGE_CWD_KEY, normalized);
6754+
const activeState = getActiveSessionState();
6755+
if (activeState) {
6756+
activeState.cwd = normalized || null;
6757+
}
67046758
if (normalized) {
67056759
selectedProjectKey = getProjectKeyFromCwd(normalized);
67066760
}
@@ -7306,7 +7360,19 @@ window.addEventListener("focus", () => {
73067360
document.addEventListener("visibilitychange", () => {
73077361
if (document.visibilityState === "visible") {
73087362
refreshVsSelectionSnapshot({ force: true }).catch(() => {});
7363+
if (socket && socket.readyState === WebSocket.OPEN) {
7364+
startSessionListSync();
7365+
send("session_list");
7366+
}
7367+
restartTimelinePolling();
7368+
return;
7369+
}
7370+
7371+
if (timelinePollTimer) {
7372+
clearInterval(timelinePollTimer);
7373+
timelinePollTimer = null;
73097374
}
7375+
stopSessionListSync();
73107376
});
73117377

73127378
applySavedUiSettings();

Buffaly.CodexEmbedded.Web/wwwroot/sessionTimeline.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,14 +550,14 @@
550550
return true;
551551
}
552552

553-
if (this.isUserAnchorsMode()) {
554-
return true;
555-
}
556-
557553
if (this.turnCollapsedById.has(turn.turnId)) {
558554
return this.turnCollapsedById.get(turn.turnId) === true;
559555
}
560556

557+
if (this.isUserAnchorsMode()) {
558+
return true;
559+
}
560+
561561
return turn.isInFlight !== true;
562562
}
563563

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)