Group tool libraries by model and component role
This commit is contained in:
@@ -23,7 +23,7 @@ Bestätigung startet den Build. Audio Separator besitzt einen eigenen Installer
|
|||||||
BS-/MelBand-RoFormer-Pakete werden einschließlich passender YAML-Konfiguration
|
BS-/MelBand-RoFormer-Pakete werden einschließlich passender YAML-Konfiguration
|
||||||
geladen; ungeprüfte Hub-Dateien werden dadurch nicht freigeschaltet. Die einzelnen Laufzeiten stehen
|
geladen; ungeprüfte Hub-Dateien werden dadurch nicht freigeschaltet. Die einzelnen Laufzeiten stehen
|
||||||
nicht mehr separat in der Seitenleiste. Bibliothek und Profile verwenden
|
nicht mehr separat in der Seitenleiste. Bibliothek und Profile verwenden
|
||||||
kompakte, aufklappbare Zeilen: Details, API-Freigabe, Komponenten und Aktionen
|
kompakte, aufklappbare Zeilen. Bibliotheken gruppieren die Dateien nach Hauptgewichten, Vision-/Audio-Projektoren, Textencodern, VAE, Konfigurationen und weiteren Zusatzkomponenten; nur vorhandene Gruppen werden angezeigt. Unbekannte Rollen bleiben separat sichtbar. In den Zeilen: Details, API-Freigabe, Komponenten und Aktionen
|
||||||
stehen in der geöffneten Zeile. Downloads behalten Fortschritt, Geschwindigkeit,
|
stehen in der geöffneten Zeile. Downloads behalten Fortschritt, Geschwindigkeit,
|
||||||
Restzeit und Warteschlangenaktionen. Der laufende Betrieb wird zentral unter
|
Restzeit und Warteschlangenaktionen. Der laufende Betrieb wird zentral unter
|
||||||
**Steuerung** angezeigt; Testbereiche behalten ihre jeweiligen Formulare.
|
**Steuerung** angezeigt; Testbereiche behalten ihre jeweiligen Formulare.
|
||||||
|
|||||||
+6
-1
@@ -32,7 +32,12 @@ window.CatalogUI = (() => {
|
|||||||
}
|
}
|
||||||
function renderLibrary() {
|
function renderLibrary() {
|
||||||
const openRows=new Set([...root.querySelectorAll('.detail-row[open]')].map(x=>x.dataset.rowId));
|
const openRows=new Set([...root.querySelectorAll('.detail-row[open]')].map(x=>x.dataset.rowId));
|
||||||
el('hub-results').innerHTML = state.entries.filter(x => x.kind === kind).map(x => `<details class="detail-row" data-row-id="${escape(x.id)}" ${openRows.has(x.id)?'open':''}><summary class="detail-summary"><strong class="hub-filename">${escape(x.file)}</strong><span>${escape(x.role_label)}</span><span>${size(x.size)}</span><span>${x.used_by_profiles?.length?`${x.used_by_profiles.length} Profil(e)`:'Nicht zugeordnet'}</span></summary><div class="detail-body"><p class="hub-filename">Quelle: ${escape(x.repo)}</p><p>${x.profile_eligible?'Modelldatei · über ein Profil verwenden':'Zusatzdatei · wird einem Modellprofil unter Komponenten zugeordnet'}</p><details><summary>Version und Integrität</summary><p class="hub-filename">Revision ${escape(x.revision)}</p><p>${x.upstream_hash_verified ? 'SHA-256 mit Quelle geprüft' : 'SHA-256 lokal erfasst; Größe mit Quelle geprüft'}</p></details>${executionHTML(x.execution)}${x.used_by_profiles?.length?`<p class="warning">Verwendet von Profil: ${x.used_by_profiles.map(p=>escape(p.name)).join(", ")}. Bitte zuerst das Profil löschen.</p>`:""}<div class="card-actions">${x.profile_eligible===true?`<button data-profile-model="${x.id}">${kind==='video'?'Als Videomodell verwenden':'Profil anlegen'}</button>`:""}<button type="button" class="secondary" data-delete-model="${x.id}" ${x.used_by_profiles?.length?"disabled":""}>Datei löschen</button></div></div></details>`).join('') || '<div class="empty wide"><h3>Deine Bibliothek ist noch leer</h3><p>Unter „Entdecken“ kannst du Dateien für diesen Bereich auswählen und herunterladen.</p></div>';
|
const entries = state.entries.filter(x => x.kind === kind);
|
||||||
|
const groups = [['model', kind==='chat'?'Sprachmodelle · Hauptgewichte':'Modelle · Hauptgewichte'],['vision_projector','Vision-Projektoren'],['audio_projector','Audio-Projektoren'],['text_encoder','Textencoder'],['vae','VAE · Decoder'],['configuration','Konfigurationen'],['auxiliary','Tokenizer und weitere Zusatzkomponenten']];
|
||||||
|
const row = x => `<details class="detail-row" data-row-id="${escape(x.id)}" ${openRows.has(x.id)?'open':''}><summary class="detail-summary"><strong class="hub-filename">${escape(x.file)}</strong><span>${escape(x.role_label)}</span><span>${size(x.size)}</span><span>${x.used_by_profiles?.length?`${x.used_by_profiles.length} Profil(e)`:'Nicht zugeordnet'}</span></summary><div class="detail-body"><p class="hub-filename">Quelle: ${escape(x.repo)}</p><p>${x.profile_eligible?'Modelldatei · über ein Profil verwenden':'Zusatzdatei · wird einem Modellprofil unter Komponenten zugeordnet'}</p><details><summary>Version und Integrität</summary><p class="hub-filename">Revision ${escape(x.revision)}</p><p>${x.upstream_hash_verified ? 'SHA-256 mit Quelle geprüft' : 'SHA-256 lokal erfasst; Größe mit Quelle geprüft'}</p></details>${executionHTML(x.execution)}${x.used_by_profiles?.length?`<p class="warning">Verwendet von Profil: ${x.used_by_profiles.map(p=>escape(p.name)).join(", ")}. Bitte zuerst das Profil löschen.</p>`:""}<div class="card-actions">${x.profile_eligible===true?`<button data-profile-model="${x.id}">${kind==='video'?'Als Videomodell verwenden':'Profil anlegen'}</button>`:""}<button type="button" class="secondary" data-delete-model="${x.id}" ${x.used_by_profiles?.length?"disabled":""}>Datei löschen</button></div></div></details>`;
|
||||||
|
const known = new Set(groups.map(([role])=>role));
|
||||||
|
const sections = [...groups, ['other','Weitere Dateien · Zuordnung unbekannt']];
|
||||||
|
el('hub-results').innerHTML = sections.map(([role,label])=>{const files=entries.filter(x=>role==='other'?!known.has(x.role):x.role===role);return files.length?`<section class="library-group" aria-label="${escape(label)}"><h3>${escape(label)} <span class="small muted">(${files.length})</span></h3><div class="detail-list">${files.map(row).join('')}</div></section>`:'';}).join('') || '<div class="empty wide"><h3>Deine Bibliothek ist noch leer</h3><p>Unter „Entdecken“ kannst du Dateien für diesen Bereich auswählen und herunterladen.</p></div>';
|
||||||
root.querySelectorAll('[data-delete-model]').forEach(b=>b.onclick=async()=>{const entry=state.entries.find(x=>x.id===b.dataset.deleteModel);if(!entry||!confirm(`Datei „${entry.file}“ (${size(entry.size)}) dauerhaft von Athena löschen?`))return;b.disabled=true;try{await api('/delete',{id:entry.id});message('Datei aus der Bibliothek gelöscht.');await refresh();}catch(error){message(error.message);b.disabled=false;}});
|
root.querySelectorAll('[data-delete-model]').forEach(b=>b.onclick=async()=>{const entry=state.entries.find(x=>x.id===b.dataset.deleteModel);if(!entry||!confirm(`Datei „${entry.file}“ (${size(entry.size)}) dauerhaft von Athena löschen?`))return;b.disabled=true;try{await api('/delete',{id:entry.id});message('Datei aus der Bibliothek gelöscht.');await refresh();}catch(error){message(error.message);b.disabled=false;}});
|
||||||
}
|
}
|
||||||
function renderJob() {
|
function renderJob() {
|
||||||
|
|||||||
@@ -45,3 +45,6 @@ nav a.nav-sub{padding-left:28px;font-size:12px;color:var(--deck-tone-a4bda8, #a4
|
|||||||
|
|
||||||
/* Control is a focused mode chooser; detailed API configuration lives in settings. */
|
/* Control is a focused mode chooser; detailed API configuration lives in settings. */
|
||||||
.control-modes{display:flex;gap:12px;margin:24px 0 20px}.control-modes button{min-width:110px;margin:0;font-size:15px}.control-card{max-width:900px}.control-heading{display:flex;align-items:center;justify-content:space-between;gap:16px}.control-heading h2{margin:0;font-size:25px}.control-card>.card-actions{margin-top:18px}.control-api{border-top:1px solid var(--deck-tone-303a37,#303a37);margin-top:24px;padding-top:8px}.control-api h3{font-size:14px}.control-api>div{display:grid;grid-template-columns:130px minmax(0,1fr);gap:14px;margin:12px 0;font-size:13px}.control-api span{color:var(--deck-tone-97a79e,#97a79e)}.control-api code{overflow-wrap:anywhere}.control-details{border-top:1px solid var(--deck-tone-303a37,#303a37);padding-top:16px;margin-top:20px}.control-card .small{font-size:12px}@media(max-width:600px){.control-modes{gap:8px}.control-modes button{min-width:0;flex:1;padding:12px}.control-api>div{grid-template-columns:1fr;gap:4px}}
|
.control-modes{display:flex;gap:12px;margin:24px 0 20px}.control-modes button{min-width:110px;margin:0;font-size:15px}.control-card{max-width:900px}.control-heading{display:flex;align-items:center;justify-content:space-between;gap:16px}.control-heading h2{margin:0;font-size:25px}.control-card>.card-actions{margin-top:18px}.control-api{border-top:1px solid var(--deck-tone-303a37,#303a37);margin-top:24px;padding-top:8px}.control-api h3{font-size:14px}.control-api>div{display:grid;grid-template-columns:130px minmax(0,1fr);gap:14px;margin:12px 0;font-size:13px}.control-api span{color:var(--deck-tone-97a79e,#97a79e)}.control-api code{overflow-wrap:anywhere}.control-details{border-top:1px solid var(--deck-tone-303a37,#303a37);padding-top:16px;margin-top:20px}.control-card .small{font-size:12px}@media(max-width:600px){.control-modes{gap:8px}.control-modes button{min-width:0;flex:1;padding:12px}.control-api>div{grid-template-columns:1fr;gap:4px}}
|
||||||
|
|
||||||
|
.library-group + .library-group { margin-top: 1.5rem; }
|
||||||
|
.library-group > h3 { margin: .5rem 0 .75rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user