Compare commits
2 changed files with 5 additions and 32 deletions
|
|
@ -615,27 +615,6 @@ function buildQuestionLi(q) {
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot / restore open `<details>` state across a re-render, scoped to
|
|
||||||
// one section root. renderQuestions only manages `#questions-section`, so it
|
|
||||||
// keeps its own section-local pair rather than reaching into tabs.js's
|
|
||||||
// `MANAGED_SECTION_IDS`-based helpers (which aren't in this module's scope —
|
|
||||||
// referencing them threw `ReferenceError: snapshotOpenDetails is not defined`
|
|
||||||
// and aborted refreshState). Sections that should survive a refresh carry a
|
|
||||||
// stable `data-restore-key`.
|
|
||||||
function snapshotOpenDetails(root) {
|
|
||||||
const open = new Set();
|
|
||||||
for (const d of root.querySelectorAll('details[data-restore-key]')) {
|
|
||||||
if (d.open) open.add(d.dataset.restoreKey);
|
|
||||||
}
|
|
||||||
return open;
|
|
||||||
}
|
|
||||||
function restoreOpenDetails(root, open) {
|
|
||||||
if (!open.size) return;
|
|
||||||
for (const d of root.querySelectorAll('details[data-restore-key]')) {
|
|
||||||
if (open.has(d.dataset.restoreKey)) d.open = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderQuestions() {
|
export function renderQuestions() {
|
||||||
const root = $('questions-section');
|
const root = $('questions-section');
|
||||||
// #questions-section only lives on /dashboard.html (Y3R C4LL tab);
|
// #questions-section only lives on /dashboard.html (Y3R C4LL tab);
|
||||||
|
|
@ -646,7 +625,7 @@ export function renderQuestions() {
|
||||||
// any expanded sections. The keyed-cache approach reuses question
|
// any expanded sections. The keyed-cache approach reuses question
|
||||||
// <li> nodes (preserving textarea/checkbox state) and only rebuilds
|
// <li> nodes (preserving textarea/checkbox state) and only rebuilds
|
||||||
// cache-miss rows, so we no longer wipe the DOM at the start.
|
// cache-miss rows, so we no longer wipe the DOM at the start.
|
||||||
const openDetails = snapshotOpenDetails(root);
|
const openDetails = snapshotOpenDetails();
|
||||||
const fmt = (n) => new Date(n * 1000).toISOString().replace('T', ' ').slice(0, 19);
|
const fmt = (n) => new Date(n * 1000).toISOString().replace('T', ' ').slice(0, 19);
|
||||||
const allPending = questionsState.pending;
|
const allPending = questionsState.pending;
|
||||||
|
|
||||||
|
|
@ -771,7 +750,7 @@ export function renderQuestions() {
|
||||||
const histEl = root.querySelector('.q-history');
|
const histEl = root.querySelector('.q-history');
|
||||||
if (histEl) histEl.open = true;
|
if (histEl) histEl.open = true;
|
||||||
}
|
}
|
||||||
restoreOpenDetails(root, openDetails);
|
restoreOpenDetails(openDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format a remaining-seconds count as the `⏳ …` TTL chip text on a
|
// Format a remaining-seconds count as the `⏳ …` TTL chip text on a
|
||||||
|
|
|
||||||
|
|
@ -664,9 +664,8 @@ struct DashboardState {
|
||||||
/// `None` when no status is set.
|
/// `None` when no status is set.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
status_set_at: Option<i64>,
|
status_set_at: Option<i64>,
|
||||||
/// Full context-window size from the most recent completed turn
|
/// Input token count from the most recent completed turn (`ctx_usage.input_tokens`).
|
||||||
/// (`ctx_usage.context_tokens()` = input + cache-read + cache-creation).
|
/// `None` until the first turn finishes.
|
||||||
/// `None` until the first turn finishes. Drives the `ctx·Nk` card badge.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
ctx_tokens: Option<u64>,
|
ctx_tokens: Option<u64>,
|
||||||
/// Effective context-window budget for the current model. Same
|
/// Effective context-window budget for the current model. Same
|
||||||
|
|
@ -715,12 +714,7 @@ async fn api_dashboard_state(State(state): State<AppState>) -> axum::Json<Dashbo
|
||||||
.bus
|
.bus
|
||||||
.api_context_window()
|
.api_context_window()
|
||||||
.unwrap_or_else(|| crate::events::context_window_tokens(&model));
|
.unwrap_or_else(|| crate::events::context_window_tokens(&model));
|
||||||
// Full context-window size = input + cache-read + cache-creation. Using
|
let ctx_tokens = state.bus.last_ctx_usage().map(|u| u.input_tokens);
|
||||||
// raw `input_tokens` here reported only the *uncached* sliver, which is
|
|
||||||
// ~0 once prompt caching kicks in — so every card showed `ctx·0k`. Match
|
|
||||||
// the agent page (which ships the whole `ctx_usage` and sums it) and the
|
|
||||||
// cache-TTL logic in turn.rs, both of which use `context_tokens()`.
|
|
||||||
let ctx_tokens = state.bus.last_ctx_usage().map(|u| u.context_tokens());
|
|
||||||
axum::Json(DashboardState {
|
axum::Json(DashboardState {
|
||||||
status_text,
|
status_text,
|
||||||
status_set_at,
|
status_set_at,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue