feat(dashboard): update model analytics section and enhance user charts functionality

- Renamed "Models" to "Model Call Analytics" and updated descriptions for clarity.
- Introduced a new state for top user limits in user charts, allowing users to select the number of top users displayed.
- Enhanced user charts to include total call count display and improved data processing for better analytics.
- Added new translations for updated terms in multiple languages to support internationalization.
This commit is contained in:
CaIon
2026-04-28 19:16:18 +08:00
parent 28f7e9eb2e
commit 22ef5b2f80
12 changed files with 85 additions and 19 deletions
@@ -78,7 +78,12 @@ export function ModelCharts(props: ModelChartsProps) {
<div className='flex w-full flex-col gap-3 border-b px-4 py-3 sm:px-5 lg:flex-row lg:items-center lg:justify-between'>
<div className='flex items-center gap-2'>
<PieChartIcon className='text-muted-foreground/60 size-4' />
<div className='text-sm font-semibold'>{t('Model Analytics')}</div>
<div className='text-sm font-semibold'>
{t('Model Call Analytics')}
</div>
<span className='text-muted-foreground text-xs'>
{t('Total:')} {chartData.totalCountDisplay}
</span>
</div>
<div className='bg-muted/60 inline-flex h-8 rounded-md border p-0.5'>
@@ -41,6 +41,8 @@ const USER_CHARTS: {
},
]
const TOP_USER_LIMIT_OPTIONS = [5, 10, 20, 50]
export function UserCharts() {
const { t } = useTranslation()
const { resolvedTheme } = useTheme()
@@ -55,6 +57,7 @@ export function UserCharts() {
const [selectedRange, setSelectedRange] = useState<number>(() =>
getDefaultDays(timeGranularity)
)
const [topUserLimit, setTopUserLimit] = useState(10)
const [timeRange, setTimeRange] = useState(() => {
const days = getDefaultDays(timeGranularity)
const { start, end } = getNormalizedDateRange(days)
@@ -113,9 +116,10 @@ export function UserCharts() {
processUserChartData(
isLoading ? [] : (userData ?? []),
timeGranularity,
t
t,
topUserLimit
),
[userData, isLoading, timeGranularity, t]
[userData, isLoading, timeGranularity, t, topUserLimit]
)
return (
@@ -158,6 +162,26 @@ export function UserCharts() {
))}
</div>
<div className='flex items-center gap-1.5 rounded-md border p-0.5'>
<span className='text-muted-foreground px-2 text-xs font-medium'>
{t('Top Users')}
</span>
{TOP_USER_LIMIT_OPTIONS.map((limit) => (
<button
key={limit}
type='button'
onClick={() => setTopUserLimit(limit)}
className={`rounded-[5px] px-2.5 py-1 text-xs font-medium transition-colors ${
topUserLimit === limit
? 'bg-primary text-primary-foreground shadow-sm'
: 'text-muted-foreground hover:bg-muted hover:text-foreground'
}`}
>
{t('Top {{count}}', { count: limit })}
</button>
))}
</div>
{isLoading && (
<Loader2 className='text-muted-foreground size-4 animate-spin' />
)}
@@ -184,7 +208,7 @@ export function UserCharts() {
themeReady &&
spec && (
<VChart
key={`user-${chart.value}-${resolvedTheme}`}
key={`user-${chart.value}-${topUserLimit}-${resolvedTheme}`}
spec={{
...spec,
theme: resolvedTheme === 'dark' ? 'dark' : 'light',
+2 -2
View File
@@ -86,8 +86,8 @@ const SECTION_META: Record<
descriptionKey: 'View dashboard overview and statistics',
},
models: {
titleKey: 'Models',
descriptionKey: 'View model statistics and charts',
titleKey: 'Model Call Analytics',
descriptionKey: 'View model call count analytics and charts',
},
users: {
titleKey: 'User Analytics',
+17 -5
View File
@@ -158,7 +158,6 @@ export function processChartData(
title: {
visible: true,
text: tt('Call Trend'),
subtext: `${tt('Total:')} ${formatInt(0)}`,
},
},
spec_rank_bar: {
@@ -171,10 +170,10 @@ export function processChartData(
title: {
visible: true,
text: tt('Call Count Ranking'),
subtext: `${tt('Total:')} ${formatInt(0)}`,
},
},
totalQuotaDisplay: formatQuotaTotal(0),
totalCountDisplay: formatInt(0),
}
}
@@ -426,7 +425,6 @@ export function processChartData(
title: {
visible: true,
text: tt('Call Count Distribution'),
subtext: `${tt('Total:')} ${formatInt(totalTimes)}`,
},
legends: { visible: true, orient: 'left' },
label: { visible: true },
@@ -541,7 +539,6 @@ export function processChartData(
title: {
visible: true,
text: tt('Call Trend'),
subtext: `${tt('Total:')} ${formatInt(totalTimes)}`,
},
tooltip: {
mark: {
@@ -611,7 +608,6 @@ export function processChartData(
title: {
visible: true,
text: tt('Call Count Ranking'),
subtext: `${tt('Total:')} ${formatInt(totalTimes)}`,
},
bar: {
state: {
@@ -633,6 +629,7 @@ export function processChartData(
animation: true,
},
totalQuotaDisplay: formatQuotaTotal(totalQuotaRaw),
totalCountDisplay: formatInt(totalTimes),
}
}
@@ -796,6 +793,21 @@ export function processUserChartData(
formatVal(Number(datum?.rawQuota) || 0),
},
],
updateContent: (
array: Array<{
key: string
value: string | number
datum?: Record<string, unknown>
}>
) => {
for (let i = 0; i < array.length; i++) {
const rawQuota = array[i].datum?.rawQuota
const value =
rawQuota === undefined ? array[i].value : Number(rawQuota)
array[i].value = formatVal(Number(value) || 0)
}
return array
},
},
},
color: { specified: userColorMap },
+2 -2
View File
@@ -13,8 +13,8 @@ const DASHBOARD_SECTIONS = [
},
{
id: 'models',
titleKey: 'Models',
descriptionKey: 'View model statistics and charts',
titleKey: 'Model Call Analytics',
descriptionKey: 'View model call count analytics and charts',
build: () => null,
},
{
+1
View File
@@ -75,6 +75,7 @@ export interface ProcessedChartData {
spec_model_line: VChartSpec
spec_rank_bar: VChartSpec
totalQuotaDisplay: string
totalCountDisplay: string
}
export interface ProcessedUserChartData {