From e1bc3b35ebd623b6821f515556f5f80837fdb1a0 Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Sat, 7 Mar 2026 01:28:39 +0000 Subject: [PATCH] feat(dashboard): add provider, modality, and capability filters to Model Registry This commit enhances the Model Registry UI by adding dropdown filters for Provider, Modality (Text/Image/Audio), and Capabilities (Tool Calling/Reasoning) alongside the existing text search. The filtering logic has been refactored to be non-destructive and apply instantly on the client side. --- static/js/dashboard.js | 27 ++++++++++++- static/js/pages/models.js | 80 ++++++++++++++++++++++++++++----------- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/static/js/dashboard.js b/static/js/dashboard.js index 312d9177..aa88c90f 100644 --- a/static/js/dashboard.js +++ b/static/js/dashboard.js @@ -284,8 +284,31 @@ class Dashboard {

Model Registry

Manage model availability and custom pricing

-
- +
+ + + +
diff --git a/static/js/pages/models.js b/static/js/pages/models.js index 726d963f..2790d6ae 100644 --- a/static/js/pages/models.js +++ b/static/js/pages/models.js @@ -30,14 +30,59 @@ class ModelsPage { tableBody.innerHTML = 'No models found in registry'; return; } + + const searchInput = document.getElementById('model-search'); + const providerFilter = document.getElementById('model-provider-filter'); + const modalityFilter = document.getElementById('model-modality-filter'); + const capabilityFilter = document.getElementById('model-capability-filter'); + + const q = searchInput ? searchInput.value.toLowerCase() : ''; + const providerVal = providerFilter ? providerFilter.value : ''; + const modalityVal = modalityFilter ? modalityFilter.value : ''; + const capabilityVal = capabilityFilter ? capabilityFilter.value : ''; + + // Apply filters non-destructively + let filteredModels = this.models.filter(m => { + // Text search + if (q && !(m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q) || m.provider.toLowerCase().includes(q))) { + return false; + } + + // Provider filter + if (providerVal) { + if (providerVal === 'other') { + const known = ['openai', 'anthropic', 'google', 'deepseek', 'xai', 'meta', 'cohere', 'mistral']; + if (known.includes(m.provider.toLowerCase())) return false; + } else if (m.provider.toLowerCase() !== providerVal) { + return false; + } + } + + // Modality filter + if (modalityVal) { + const mods = m.modalities && m.modalities.input ? m.modalities.input.map(x => x.toLowerCase()) : []; + if (!mods.includes(modalityVal)) return false; + } + + // Capability filter + if (capabilityVal === 'tool_call' && !m.tool_call) return false; + if (capabilityVal === 'reasoning' && !m.reasoning) return false; + + return true; + }); + + if (filteredModels.length === 0) { + tableBody.innerHTML = 'No models match the selected filters'; + return; + } // Sort by provider then name - this.models.sort((a, b) => { + filteredModels.sort((a, b) => { if (a.provider !== b.provider) return a.provider.localeCompare(b.provider); return a.name.localeCompare(b.name); }); - tableBody.innerHTML = this.models.map(model => { + tableBody.innerHTML = filteredModels.map(model => { const statusClass = model.enabled ? 'success' : 'secondary'; const statusIcon = model.enabled ? 'check-circle' : 'ban'; @@ -150,27 +195,18 @@ class ModelsPage { } setupEventListeners() { - const searchInput = document.getElementById('model-search'); - if (searchInput) { - searchInput.oninput = (e) => this.filterModels(e.target.value); - } - } + const attachFilter = (id) => { + const el = document.getElementById(id); + if (el) { + el.addEventListener('input', () => this.renderModelsTable()); + el.addEventListener('change', () => this.renderModelsTable()); + } + }; - filterModels(query) { - if (!query) { - this.renderModelsTable(); - return; - } - - const q = query.toLowerCase(); - const originalModels = this.models; - this.models = this.models.filter(m => - m.id.toLowerCase().includes(q) || - m.name.toLowerCase().includes(q) || - m.provider.toLowerCase().includes(q) - ); - this.renderModelsTable(); - this.models = originalModels; + attachFilter('model-search'); + attachFilter('model-provider-filter'); + attachFilter('model-modality-filter'); + attachFilter('model-capability-filter'); } }