|
140 | 140 | tokenError.classList.toggle("hidden", !message); |
141 | 141 | overlay.classList.remove("hidden"); |
142 | 142 | overlay.setAttribute("aria-hidden", "false"); |
| 143 | + document.querySelectorAll(".app-header, .tabs, main, .site-footer").forEach((el) => { |
| 144 | + el.inert = true; |
| 145 | + }); |
143 | 146 | tokenInput.focus(); |
144 | 147 | } |
145 | 148 |
|
146 | 149 | function hideOverlay() { |
147 | 150 | overlay.classList.add("hidden"); |
148 | 151 | overlay.setAttribute("aria-hidden", "true"); |
149 | 152 | tokenInput.value = ""; |
| 153 | + document.querySelectorAll(".app-header, .tabs, main, .site-footer").forEach((el) => { |
| 154 | + el.inert = false; |
| 155 | + }); |
150 | 156 | } |
151 | 157 |
|
152 | 158 | // ------------------------------------------------------------------ token |
|
159 | 165 | } |
160 | 166 | localStorage.setItem(TOKEN_KEY, token); |
161 | 167 | hideOverlay(); |
162 | | - htmx.ajax("GET", "/ui/partials/overview", { target: "#panel", swap: "innerHTML" }); |
| 168 | + openTabByName(document.querySelector(".tab.active")?.dataset.tab || "overview"); |
163 | 169 | htmx.ajax("GET", "/ui/partials/engine-pill", { target: "#engine-pill", swap: "outerHTML" }); |
164 | 170 | htmx.ajax("GET", "/ui/partials/exposure-banner", { |
165 | 171 | target: "#exposure-banner", |
|
186 | 192 |
|
187 | 193 | document.body.addEventListener("htmx:responseError", (event) => { |
188 | 194 | if (event.detail.xhr.status === 401) { |
| 195 | + const hadToken = Boolean(getToken()); |
189 | 196 | localStorage.removeItem(TOKEN_KEY); |
190 | | - showOverlay("Token rejected. Paste the current gateway token."); |
| 197 | + showOverlay(hadToken ? "Token rejected. Paste the current gateway token." : ""); |
191 | 198 | return; |
192 | 199 | } |
193 | 200 | let message = `Request failed (${event.detail.xhr.status}).`; |
|
230 | 237 | activateTab(tab); |
231 | 238 | }); |
232 | 239 | tab.addEventListener("keydown", (event) => { |
233 | | - if (!["ArrowLeft", "ArrowRight"].includes(event.key)) return; |
| 240 | + if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) return; |
| 241 | + event.preventDefault(); |
234 | 242 | const tabs = [...document.querySelectorAll(".tab")]; |
235 | | - const offset = event.key === "ArrowRight" ? 1 : -1; |
236 | | - const next = tabs[(tabs.indexOf(tab) + offset + tabs.length) % tabs.length]; |
| 243 | + const offset = ["ArrowRight", "ArrowDown"].includes(event.key) ? 1 : -1; |
| 244 | + const index = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 |
| 245 | + : (tabs.indexOf(tab) + offset + tabs.length) % tabs.length; |
| 246 | + const next = tabs[index]; |
237 | 247 | next.focus(); |
238 | 248 | next.click(); |
239 | 249 | }); |
|
261 | 271 | } |
262 | 272 | }); |
263 | 273 |
|
| 274 | + let performanceDetailsOpen = false; |
264 | 275 | document.body.addEventListener("htmx:beforeSwap", (event) => { |
265 | 276 | const target = event.detail && event.detail.target; |
| 277 | + if (target && target.id === "operations") { |
| 278 | + performanceDetailsOpen = Boolean(target.querySelector(".activity-details[open]")); |
| 279 | + } |
266 | 280 | // Download / Load / Cancel / poll refresh replace #models-list; keep open families. |
267 | 281 | if (target && target.id === "models-list") { |
268 | 282 | window.__openModelFamilies = openFamilyNames(); |
|
278 | 292 | }); |
279 | 293 |
|
280 | 294 | document.body.addEventListener("htmx:afterSwap", (event) => { |
| 295 | + if (event.detail?.target?.id === "operations") { |
| 296 | + const details = document.querySelector("#operations .activity-details"); |
| 297 | + if (details) details.open = performanceDetailsOpen; |
| 298 | + } |
281 | 299 | scheduleModelPoll(); |
282 | 300 | if (document.getElementById("test-language")) syncTestLanguages(); |
283 | 301 | // Models tab shell (or list refresh) may reintroduce filter controls. |
|
341 | 359 |
|
342 | 360 | function isFilterRailCollapsed() { |
343 | 361 | try { |
344 | | - return localStorage.getItem(FILTER_RAIL_KEY) === "1"; |
| 362 | + return localStorage.getItem(FILTER_RAIL_KEY) !== "0"; |
345 | 363 | } catch (_) { |
346 | 364 | return false; |
347 | 365 | } |
|
503 | 521 | .forEach((tile) => placeModelsAfterRow(tile)); |
504 | 522 | } |
505 | 523 |
|
| 524 | + function syncModelViews() { |
| 525 | + const installed = document.getElementById("installed-only-toggle")?.checked; |
| 526 | + const recommended = document.getElementById("recommended-only-toggle")?.checked; |
| 527 | + document.querySelectorAll("[data-model-view]").forEach((button) => { |
| 528 | + const view = button.dataset.modelView; |
| 529 | + button.setAttribute("aria-pressed", String(view === "all" ? !installed && !recommended |
| 530 | + : view === "installed" ? installed && !recommended : recommended && !installed)); |
| 531 | + }); |
| 532 | + } |
| 533 | + |
| 534 | + document.body.addEventListener("click", (event) => { |
| 535 | + const button = event.target.closest("[data-model-view]"); |
| 536 | + if (!button) return; |
| 537 | + const form = document.getElementById("models-filter-form"); |
| 538 | + const installed = document.getElementById("installed-only-toggle"); |
| 539 | + const recommended = document.getElementById("recommended-only-toggle"); |
| 540 | + if (!form || !installed || !recommended) return; |
| 541 | + installed.checked = button.dataset.modelView === "installed"; |
| 542 | + recommended.checked = button.dataset.modelView === "recommended"; |
| 543 | + installed.dispatchEvent(new Event("change", { bubbles: true })); |
| 544 | + syncModelViews(); |
| 545 | + }); |
| 546 | + |
506 | 547 | function initModelFilters() { |
| 548 | + syncModelViews(); |
507 | 549 | const form = document.getElementById("models-filter-form"); |
508 | 550 | const clear = document.getElementById("filter-clear"); |
509 | 551 | if (clear && !clear.dataset.bound) { |
|
0 commit comments