mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-27 04:00:37 +00:00
fix: show configured badge on selected model chip
This commit is contained in:
@@ -401,6 +401,7 @@
|
||||
<button class="composer-model-chip" id="composerModelChip" type="button" onclick="toggleModelDropdown()" title="Conversation model">
|
||||
<span class="composer-model-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg></span>
|
||||
<span class="composer-model-label" id="composerModelLabel"></span>
|
||||
<span class="composer-model-badge" id="composerModelBadge" hidden></span>
|
||||
<span class="composer-model-chevron" aria-hidden="true"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
</button>
|
||||
<select id="modelSelect" class="composer-model-select" title="Conversation model" aria-hidden="true" tabindex="-1">
|
||||
|
||||
+5
-1
@@ -838,10 +838,14 @@
|
||||
.reasoning-option:hover{background:rgba(255,255,255,.07);}
|
||||
.reasoning-option.selected{background:var(--accent-bg);}
|
||||
.composer-model-wrap{position:relative;flex:0 1 auto;min-width:0;}
|
||||
.composer-model-chip{display:inline-flex;align-items:center;gap:8px;max-width:220px;padding:8px 10px 8px 12px;border-radius:999px;border:1px solid transparent;background-color:transparent;color:var(--muted);font-weight:500;cursor:pointer;transition:color .15s,background-color .15s,border-color .15s;}
|
||||
.composer-model-chip{display:inline-flex;align-items:center;gap:8px;max-width:280px;padding:8px 10px 8px 12px;border-radius:999px;border:1px solid transparent;background-color:transparent;color:var(--muted);font-weight:500;cursor:pointer;transition:color .15s,background-color .15s,border-color .15s;}
|
||||
.composer-model-chip:hover{color:var(--text);background-color:var(--hover-bg);}
|
||||
.composer-model-chip.active{color:var(--text);background:var(--accent-bg);border-color:var(--accent-bg);}
|
||||
.composer-model-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||||
.composer-model-badge{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:2px 7px;border-radius:999px;font-size:10px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;border:1px solid transparent;}
|
||||
.composer-model-badge[hidden]{display:none;}
|
||||
.composer-model-badge--primary{background:rgba(50,184,198,.16);border-color:rgba(50,184,198,.32);color:#8fe7ef;}
|
||||
.composer-model-badge--fallback{background:rgba(255,184,77,.14);border-color:rgba(255,184,77,.28);color:#ffd18a;}
|
||||
.composer-model-icon,.composer-model-chevron{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:1;}
|
||||
.composer-model-select{position:absolute!important;left:-9999px!important;width:1px!important;height:1px!important;opacity:0!important;pointer-events:none!important;}
|
||||
.composer-right{display:flex;gap:8px;align-items:center;flex-shrink:0;}
|
||||
|
||||
+17
-1
@@ -337,12 +337,28 @@ function syncModelChip(){
|
||||
const sel=$('modelSelect');
|
||||
const chip=$('composerModelChip');
|
||||
const label=$('composerModelLabel');
|
||||
const badgeEl=$('composerModelBadge');
|
||||
const dd=$('composerModelDropdown');
|
||||
if(!sel||!chip||!label) return;
|
||||
// Don't show a model label until boot has finished loading to prevent flash of wrong default
|
||||
if(!S._bootReady){ label.textContent=''; chip.title='Conversation model'; return; }
|
||||
if(!S._bootReady){
|
||||
label.textContent='';
|
||||
chip.title='Conversation model';
|
||||
if(badgeEl){
|
||||
badgeEl.textContent='';
|
||||
badgeEl.hidden=true;
|
||||
badgeEl.className='composer-model-badge';
|
||||
}
|
||||
return;
|
||||
}
|
||||
const opt=_selectedModelOption();
|
||||
label.textContent=opt?opt.textContent:getModelLabel(sel.value||'');
|
||||
const badge=_getConfiguredModelBadge(sel.value||'',window._configuredModelBadges||{});
|
||||
if(badgeEl){
|
||||
badgeEl.textContent=badge&&badge.label?badge.label:'';
|
||||
badgeEl.hidden=!badgeEl.textContent;
|
||||
badgeEl.className='composer-model-badge'+(badge&&badge.role?` composer-model-badge--${badge.role}`:'');
|
||||
}
|
||||
chip.title=sel.value||'Conversation model';
|
||||
chip.classList.toggle('active',!!(dd&&dd.classList.contains('open')));
|
||||
}
|
||||
|
||||
@@ -89,7 +89,11 @@ def test_get_available_models_cache_preserves_configured_model_badges(tmp_path,
|
||||
|
||||
|
||||
def test_ui_renders_model_badges_from_api_payload():
|
||||
js = (Path(__file__).resolve().parent.parent / "static" / "ui.js").read_text(encoding="utf-8")
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
js = (root / "static" / "ui.js").read_text(encoding="utf-8")
|
||||
html = (root / "static" / "index.html").read_text(encoding="utf-8")
|
||||
css = (root / "static" / "style.css").read_text(encoding="utf-8")
|
||||
|
||||
assert "window._configuredModelBadges=data.configured_model_badges||{};" in js, (
|
||||
"populateModelDropdown() deve guardar configured_model_badges do /api/models "
|
||||
"para que o dropdown reflita a cadeia configurada atual."
|
||||
@@ -102,3 +106,18 @@ def test_ui_renders_model_badges_from_api_payload():
|
||||
"A UI precisa de um helper de matching resiliente para religar badges mesmo quando "
|
||||
"o update do catálogo mudar prefixos/formas do model ID."
|
||||
)
|
||||
assert 'id="composerModelBadge"' in html, (
|
||||
"O chip principal do modelo precisa de um container dedicado para exibir o badge "
|
||||
"do modelo selecionado fora do dropdown."
|
||||
)
|
||||
assert "composer-model-badge" in css, (
|
||||
"O badge do chip principal precisa de estilo próprio para ficar visível ao lado "
|
||||
"do nome do modelo selecionado."
|
||||
)
|
||||
assert "const badge=_getConfiguredModelBadge(sel.value||'',window._configuredModelBadges||{});" in js, (
|
||||
"syncModelChip() deve buscar o badge configurado do modelo selecionado e projetá-lo "
|
||||
"no chip principal da composer."
|
||||
)
|
||||
assert "badgeEl.textContent=badge&&badge.label?badge.label:'';" in js, (
|
||||
"syncModelChip() deve preencher o texto do badge visível no chip principal quando houver metadata configurada."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user