fix: drop the dead admin jump links; stop a test flake at its source
Admin links - The [data-admin-jump] click handler had been pasted inside discoverModels(), so it only registered once someone pressed Search in AI Model Management, and re-registered on every later search. Normally nothing intercepted the click, so href="#" did what it says: jump to the top and leave "#" in the URL. - This is an app, so the pointers are plain text naming the sections rather than links, and the handler is gone. Test flake - admin-clinical-assistant-wiring failed about 1 run in 4 with "Unable to deserialize cloned data due to invalid or unsupported version": node:test reads a test file's results back over the child's stdout, and app.js's own console.log landed inside a serialized frame. - The page's console is now forwarded to stderr (jsdom 29: forwardTo). Verified: child stdout clean, 0 failures in 32 stress runs (was 6 in 24), and three full-suite runs at 668/668. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
parent
adcea2a0ca
commit
609305538a
3 changed files with 12 additions and 16 deletions
|
|
@ -296,7 +296,7 @@
|
|||
<strong class="admin-row-label">Model availability</strong>
|
||||
<div style="flex:1;display:flex;flex-direction:column;gap:8px;min-width:0;">
|
||||
<p style="margin:0;font-size:12px;color:var(--g500);">Models users may select in the Clinical Assistant. Leave a list empty to keep only the configured model.</p>
|
||||
<p style="margin:0;font-size:12px;color:var(--g500);">To make a new model appear here, add it from the gateway: chat models in <a href="#" data-admin-jump="admin-model-search" style="color:var(--blue);font-weight:600;">AI Model Management</a> above, image models in <a href="#" data-admin-jump="admin-image-search" style="color:var(--blue);font-weight:600;">Image Generation</a> below — search, press <strong>+ Add</strong>, and it shows up in this list.</p>
|
||||
<p style="margin:0;font-size:12px;color:var(--g500);">To make a new model appear here, add it from the gateway: chat models under <strong>AI Model Management</strong> above, image models under <strong>Image Generation</strong> below — search there, press <strong>+ Add</strong>, and it shows up in this list.</p>
|
||||
<div>
|
||||
<div style="font-size:12px;font-weight:600;color:var(--g600);margin-bottom:2px;">Chat models</div>
|
||||
<div id="assistant-allowed-chat-models" aria-label="Chat models available to the Clinical Assistant"></div>
|
||||
|
|
|
|||
|
|
@ -909,19 +909,6 @@ initImageSettings();
|
|||
|
||||
container.innerHTML = '<p style="color:var(--g400);font-size:13px;"><i class="fas fa-spinner fa-spin"></i> Querying provider API...</p>';
|
||||
if (hint) hint.style.display = 'none';
|
||||
// The Clinical Assistant lists models but cannot add them; adding happens in
|
||||
// AI Model Management, one section up. Without this the two sections look
|
||||
// unrelated and there is no visible way to get a new model into the list.
|
||||
document.addEventListener('click', function(event) {
|
||||
var jump = event.target.closest && event.target.closest('[data-admin-jump]');
|
||||
if (!jump) return;
|
||||
event.preventDefault();
|
||||
var target = document.getElementById(jump.getAttribute('data-admin-jump'));
|
||||
if (!target) return;
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
target.focus({ preventScroll: true });
|
||||
});
|
||||
|
||||
|
||||
fetch('/api/admin/config/models/discover?q=' + encodeURIComponent(search), { headers: getAuthHeaders() })
|
||||
.then(function(r) { return r.json(); })
|
||||
|
|
|
|||
|
|
@ -3,10 +3,19 @@ const assert = require('node:assert/strict');
|
|||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { pathToFileURL } = require('node:url');
|
||||
const { JSDOM } = require('jsdom');
|
||||
const { JSDOM, VirtualConsole } = require('jsdom');
|
||||
const { Console } = require('node:console');
|
||||
const root = path.join(__dirname, '..');
|
||||
const read = file => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
const tick = () => new Promise(resolve => setImmediate(resolve));
|
||||
// The page's console goes to stderr, never stdout. node:test reads each test
|
||||
// file's results back over stdout as serialized frames; app.js's own log line
|
||||
// ("✅ App.js loaded") written there could land inside a frame and fail the
|
||||
// whole file with "Unable to deserialize cloned data" — about 1 run in 4.
|
||||
function pageConsole() {
|
||||
// jsdom 29 renamed sendTo() to forwardTo().
|
||||
return new VirtualConsole().forwardTo(new Console({ stdout: process.stderr, stderr: process.stderr }));
|
||||
}
|
||||
|
||||
function browserGlobals(t, dom, fetch, toasts) {
|
||||
const values = { window: dom.window, document: dom.window.document, fetch, getAuthHeaders: () => ({ 'X-Test': 'synthetic' }), showToast: (...args) => toasts.push(args) };
|
||||
|
|
@ -20,7 +29,7 @@ function browserGlobals(t, dom, fetch, toasts) {
|
|||
}
|
||||
|
||||
test('native admin initializer preserves lazy navigation, assistant actions and read-only ENV budget metadata', async t => {
|
||||
const dom = new JSDOM('<button class="tab-btn active" data-tab="home">Home</button><button class="tab-btn" data-tab="admin">Admin</button><div id="home-tab" class="tab-content" data-component="home" data-loaded="1"></div><div id="admin-tab" class="tab-content" data-component="admin"></div>', { runScripts: 'outside-only', url: 'https://app.example' });
|
||||
const dom = new JSDOM('<button class="tab-btn active" data-tab="home">Home</button><button class="tab-btn" data-tab="admin">Admin</button><div id="home-tab" class="tab-content" data-component="home" data-loaded="1"></div><div id="admin-tab" class="tab-content" data-component="admin"></div>', { runScripts: 'outside-only', url: 'https://app.example', virtualConsole: pageConsole() });
|
||||
const calls = []; const toasts = [];
|
||||
const fetch = async (url, options = {}) => {
|
||||
calls.push({ url, options });
|
||||
|
|
|
|||
Loading…
Reference in a new issue