From a04674c72f98942c3c5b7441f11a61dde7887ec6 Mon Sep 17 00:00:00 2001 From: "Apple\\Apple" Date: Wed, 4 Jun 2025 21:33:24 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20enhance=20model=20display?= =?UTF-8?q?=20with=20category=20counts=20and=20consistent=20styling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit improves the model display interface with several enhancements: 1. Add model count badges to each category tab and dropdown menu item 2. Highlight active category with red badge and use grey for inactive ones 3. Optimize performance by caching category counts with useMemo 4. Standardize model tag rendering across components: - Replace direct Tag component with centralized renderModelTag function - Update renderModelTag to use stringToColor for consistent coloring - Remove redundant color calculations in LogsTable These changes improve the UI by providing users with visual cues about model distribution across categories while ensuring consistent styling throughout the application. --- web/src/components/table/ModelPricing.js | 83 +++++++++++++++++------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/web/src/components/table/ModelPricing.js b/web/src/components/table/ModelPricing.js index 8c76b049..66e7c1af 100644 --- a/web/src/components/table/ModelPricing.js +++ b/web/src/components/table/ModelPricing.js @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useRef, useMemo, useState } from 'react'; -import { API, copy, showError, showInfo, showSuccess, getModelCategories, renderModelTag } from '../../helpers/index.js'; +import { API, copy, showError, showInfo, showSuccess, getModelCategories, renderModelTag } from '../../helpers'; import { useTranslation } from 'react-i18next'; import { @@ -315,6 +315,20 @@ const ModelPricing = () => { const modelCategories = getModelCategories(t); + const categoryCounts = useMemo(() => { + const counts = {}; + if (models.length > 0) { + counts['all'] = models.length; + + Object.entries(modelCategories).forEach(([key, category]) => { + if (key !== 'all') { + counts[key] = models.filter(model => category.filter(model)).length; + } + }); + } + return counts; + }, [models, modelCategories]); + const renderArrow = (items, pos, handleArrowClick) => { const style = { width: 32, @@ -332,15 +346,29 @@ const ModelPricing = () => { - {items.map(item => ( - setActiveKey(item.itemKey)} - icon={modelCategories[item.itemKey]?.icon} - > - {modelCategories[item.itemKey]?.label || item.itemKey} - - ))} + {items.map(item => { + const key = item.itemKey; + const modelCount = categoryCounts[key] || 0; + + return ( + setActiveKey(item.itemKey)} + icon={modelCategories[item.itemKey]?.icon} + > +
+ {modelCategories[item.itemKey]?.label || item.itemKey} + + {modelCount} + +
+
+ ); + })} } > @@ -374,18 +402,29 @@ const ModelPricing = () => { > {Object.entries(modelCategories) .filter(([key]) => availableCategories.includes(key)) - .map(([key, category]) => ( - - {category.icon && {category.icon}} - {category.label} - - } - itemKey={key} - key={key} - /> - ))} + .map(([key, category]) => { + const modelCount = categoryCounts[key] || 0; + + return ( + + {category.icon && {category.icon}} + {category.label} + + {modelCount} + + + } + itemKey={key} + key={key} + /> + ); + })} ); };