Compare commits
2
Commits
1afeaf0e15
...
4f598f7422
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f598f7422 | ||
|
|
7b1b017d8c |
@@ -138,9 +138,24 @@ if ($_vv_ai) $validTabs[] = 'ai';
|
|||||||
|
|
||||||
if (!in_array($tab, $validTabs)) $tab = 'monitor';
|
if (!in_array($tab, $validTabs)) $tab = 'monitor';
|
||||||
$tabLabels = ['monitor' => 'Monitor', 'scheduler' => 'Scheduler', 'docker' => 'Docker', 'watchdog' => 'Watchdog', 'partnership' => 'Partnership', 'fallback' => 'FallBack', 'arrs' => 'Arrs', 'rsync' => 'Rsync', 'auth' => 'Auth Stack', 'settings' => 'Settings', 'ai' => 'AI'];
|
$tabLabels = ['monitor' => 'Monitor', 'scheduler' => 'Scheduler', 'docker' => 'Docker', 'watchdog' => 'Watchdog', 'partnership' => 'Partnership', 'fallback' => 'FallBack', 'arrs' => 'Arrs', 'rsync' => 'Rsync', 'auth' => 'Auth Stack', 'settings' => 'Settings', 'ai' => 'AI'];
|
||||||
|
|
||||||
|
// Cache stamp for the stylesheet and script below. Both are served straight off the plugin
|
||||||
|
// directory at a path that never changes, so a browser holding an old copy keeps using it after
|
||||||
|
// a git pull. This page's own markup is generated fresh every request, so the two fall out of
|
||||||
|
// step: markup from the new commit rendering against a stylesheet from the old one. That is not
|
||||||
|
// a theoretical failure — it broke the Monitor AI row on 2026-08-09, when placement moved from
|
||||||
|
// inline spans into the stylesheet and only half of that arrived in the browser.
|
||||||
|
//
|
||||||
|
// mtime rather than a hand-bumped version: it changes on exactly the event that matters, a pull
|
||||||
|
// rewriting the file, and cannot be forgotten. Falling back to time() when the stat fails errs
|
||||||
|
// toward re-fetching rather than toward the stale copy that caused the problem.
|
||||||
|
$_vv_asset_rev = [];
|
||||||
|
foreach (['css/varaverk.css', 'js/varaverk.js'] as $_vv_a) {
|
||||||
|
$_vv_asset_rev[$_vv_a] = @filemtime(__DIR__ . '/' . $_vv_a) ?: time();
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/plugins/<?=$plugin?>/css/varaverk.css">
|
<link rel="stylesheet" href="/plugins/<?=$plugin?>/css/varaverk.css?v=<?=$_vv_asset_rev['css/varaverk.css']?>">
|
||||||
|
|
||||||
<div id="varaverk-wrap" class="unapi">
|
<div id="varaverk-wrap" class="unapi">
|
||||||
|
|
||||||
@@ -173,4 +188,4 @@ $tabLabels = ['monitor' => 'Monitor', 'scheduler' => 'Scheduler', 'docker' => 'D
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/plugins/<?=$plugin?>/js/varaverk.js"></script>
|
<script src="/plugins/<?=$plugin?>/js/varaverk.js?v=<?=$_vv_asset_rev['js/varaverk.js']?>"></script>
|
||||||
|
|||||||
@@ -256,7 +256,13 @@ body.vv-fullscreen #displaybox { padding-left: 1rem !important; padding-top: .5r
|
|||||||
there it inherited a cap from `.vv-card > div { flex:1; overflow-y:auto }`. Out here both are
|
there it inherited a cap from `.vv-card > div { flex:1; overflow-y:auto }`. Out here both are
|
||||||
content-driven, so forty saved chats — or a ledger with both hosts and a footer — would make
|
content-driven, so forty saved chats — or a ledger with both hosts and a footer — would make
|
||||||
the card the tallest thing in its column and set the height it is supposed to be following.
|
the card the tallest thing in its column and set the height it is supposed to be following.
|
||||||
The h3 pins and the body takes what is left, the same shape the monitor grid above uses. */
|
The h3 pins and the body takes what is left, the same shape the monitor grid above uses.
|
||||||
|
|
||||||
|
align-self alone does not finish the job, which is why vvAiRowSync() in monitor.php sets a
|
||||||
|
max-height on both. A stretched item's own content still feeds grid track sizing — the track
|
||||||
|
is sized from content first and stretched afterwards — so a card long enough grows the row it
|
||||||
|
was meant to fit inside, and stretching to that row then changes nothing. The cap is measured
|
||||||
|
from the Assistant, which is the one card here whose height is its own business. */
|
||||||
#vv-monitor-ai #vv-ai-chats-card,
|
#vv-monitor-ai #vv-ai-chats-card,
|
||||||
#vv-monitor-ai #vv-ai-tokens-card {
|
#vv-monitor-ai #vv-ai-tokens-card {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
|
|||||||
@@ -2087,6 +2087,36 @@ function vvRenderTokens() {
|
|||||||
box.innerHTML = h;
|
box.innerHTML = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── AI row height ────────────────────────────────────────────────────────────
|
||||||
|
// Conversations and Tokens are capped to the Assistant and scroll inside that cap. CSS cannot
|
||||||
|
// state this on its own: align-self:stretch makes an item fill its grid track, but the track was
|
||||||
|
// sized from the item's own content first, so a card with a long list simply grows the row and
|
||||||
|
// then dutifully fills the bigger row. Measuring the Assistant breaks that circle — it is the
|
||||||
|
// only card in the row whose height is decided by nothing but itself.
|
||||||
|
//
|
||||||
|
// Applied only in the eight-column layout. Below 1025px the Assistant drops to a row of its own
|
||||||
|
// and stops being what these two sit beside, so a cap taken from it would describe nothing.
|
||||||
|
function vvAiRowSync() {
|
||||||
|
const asst = document.getElementById('vv-ai-assistant-card');
|
||||||
|
const chats = document.getElementById('vv-ai-chats-card');
|
||||||
|
const toks = document.getElementById('vv-ai-tokens-card');
|
||||||
|
const stats = document.getElementById('vv-ai-stats-card');
|
||||||
|
if (!asst || !chats) return;
|
||||||
|
|
||||||
|
if (!window.matchMedia('(min-width: 1025px)').matches) {
|
||||||
|
chats.style.maxHeight = '';
|
||||||
|
if (toks) toks.style.maxHeight = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const h = asst.offsetHeight;
|
||||||
|
chats.style.maxHeight = h + 'px';
|
||||||
|
// Tokens is in the second row, under AI — its share is what the Assistant leaves once the
|
||||||
|
// first row and the 12px gap are taken. Floored so it stays a card rather than a sliver on a
|
||||||
|
// short viewport where the AI card happens to be tall.
|
||||||
|
if (toks && stats) toks.style.maxHeight = Math.max(140, h - stats.offsetHeight - 12) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
// Delegated on the container, which survives every render — the rows inside do not, and binding
|
// Delegated on the container, which survives every render — the rows inside do not, and binding
|
||||||
// per row would rebind the whole list on each poll to no purpose.
|
// per row would rebind the whole list on each poll to no purpose.
|
||||||
if (document.getElementById('vv-ai-tokens-body')) {
|
if (document.getElementById('vv-ai-tokens-body')) {
|
||||||
@@ -2822,5 +2852,20 @@ if (document.getElementById('vv-mon-ai-chat')) {
|
|||||||
});
|
});
|
||||||
vvMonChatList = VvAiChatList({ into: 'vv-mon-ai-chats', chat: vvMonChat });
|
vvMonChatList = VvAiChatList({ into: 'vv-mon-ai-chats', chat: vvMonChat });
|
||||||
vvMonChatList.reload();
|
vvMonChatList.reload();
|
||||||
|
|
||||||
|
// Re-measured rather than computed once. The Assistant changes height when the transcript is
|
||||||
|
// expanded, and the AI card above changes when its first real payload replaces "Loading...";
|
||||||
|
// both move the ceiling these two cards sit under. Observing the two sources covers each
|
||||||
|
// without watching the cards being adjusted, so there is no feedback loop. The resize listener
|
||||||
|
// is for crossing the 1025px breakpoint, which changes whether a cap applies at all.
|
||||||
|
vvAiRowSync();
|
||||||
|
if (window.ResizeObserver) {
|
||||||
|
const ro = new ResizeObserver(vvAiRowSync);
|
||||||
|
['vv-ai-assistant-card', 'vv-ai-stats-card'].forEach(id => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (el) ro.observe(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', vvAiRowSync);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user