From 38107a67fe4a4782cd23b8a60d54d6f05713cc34 Mon Sep 17 00:00:00 2001 From: Yuxing Deng Date: Mon, 18 May 2026 23:49:57 +0800 Subject: [PATCH] refactor(usage): switch breakdown dimension from model to route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align with gpustack backend commits 7b57cd3b (add route dimension to usage breakdown) and 51fd25c8 (use model_route_id as models_called): * group_by, filters, and BreakdownItem now use the `route` dimension; `models` filter cascader is replaced with a flat `routes` selector (routes have no provider/cluster grouping). * Tab / group_by option / column header keep the user-facing "模型 / Model" wording — only the underlying data dimension changed. * Drop cluster_name / provider_type columns from the breakdown table; drop api_keys_used column per design. * Fix pre-existing excel export bug in use-export-table — string dataIndex was lodash-joined char-by-char ("input_tokens" → "i_n_p_u_t..."), array dataIndex was used as a flat key against nested rows. Rebuilt around buildSheetMeta that emits a stable field key plus a formatMap using _.get(row, path) for nested values. Sheet name kept as `models` to match the visible column label. --- src/pages/usage/apis/index.ts | 4 +- src/pages/usage/components/breakdown-tabs.tsx | 10 +- src/pages/usage/components/daily-usage.tsx | 2 +- src/pages/usage/components/export-data.tsx | 33 ++--- src/pages/usage/components/filter-bar.tsx | 130 +++--------------- src/pages/usage/config/index.ts | 2 +- src/pages/usage/config/types.ts | 4 + src/pages/usage/hooks/use-export-table.tsx | 75 +++++----- src/pages/usage/hooks/use-models-columns.tsx | 33 +---- src/pages/usage/hooks/use-usage-filters.ts | 53 ++++--- src/pages/usage/index.tsx | 6 +- .../services/use-query-breakdown-list.ts | 4 +- .../usage/services/use-query-meta-data.ts | 15 +- src/pages/usage/tables/models-table.tsx | 14 +- .../usage/utils/get-breakdown-row-key.ts | 4 +- 15 files changed, 135 insertions(+), 254 deletions(-) diff --git a/src/pages/usage/apis/index.ts b/src/pages/usage/apis/index.ts index 636d8bc3..5650800f 100644 --- a/src/pages/usage/apis/index.ts +++ b/src/pages/usage/apis/index.ts @@ -34,7 +34,7 @@ export async function queryUsageTimeSeriesData( perPage?: number; sort_by?: string; filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; @@ -51,7 +51,7 @@ export async function queryUsageTimeSeriesData( export async function queryUsageBreakdownList( params: Global.SearchParams & { filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; diff --git a/src/pages/usage/components/breakdown-tabs.tsx b/src/pages/usage/components/breakdown-tabs.tsx index 8ebbb3ab..f62af590 100644 --- a/src/pages/usage/components/breakdown-tabs.tsx +++ b/src/pages/usage/components/breakdown-tabs.tsx @@ -1,14 +1,12 @@ import { useIntl } from '@umijs/max'; import { Tabs } from 'antd'; import React, { useMemo } from 'react'; -import { GroupOption } from '../config'; import { UsageFilterItem } from '../config/types'; import ApiKeysTable from '../tables/apikeys-table'; import ModelsTable from '../tables/models-table'; import UsersTable from '../tables/users-table'; type FilterOptionType = Omit; -type GroupOptionType = GroupOption; const EMPTY_FILTERS: FilterOptionType[] = []; const BreakdownTabs: React.FC<{ @@ -20,13 +18,13 @@ const BreakdownTabs: React.FC<{ pageResetKey?: number; refreshKey?: number; filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; }> = ({ filters, dateRange, scope, pageResetKey = 0, refreshKey = 0 }) => { const intl = useIntl(); - const models = filters.models || EMPTY_FILTERS; + const routes = filters.routes || EMPTY_FILTERS; const users = filters.users || EMPTY_FILTERS; const apiKeys = filters.api_keys || EMPTY_FILTERS; @@ -39,7 +37,7 @@ const BreakdownTabs: React.FC<{ children: ( diff --git a/src/pages/usage/components/daily-usage.tsx b/src/pages/usage/components/daily-usage.tsx index 7f38c184..def1cd58 100644 --- a/src/pages/usage/components/daily-usage.tsx +++ b/src/pages/usage/components/daily-usage.tsx @@ -104,7 +104,7 @@ const DailyUsage: React.FC = (props) => { }; } - const groupDim = groupBy as 'user' | 'model' | 'api_key' | null; + const groupDim = groupBy as 'user' | 'route' | 'api_key' | null; const isCached = metric === CACHED_METRIC; const dateSet = new Set( diff --git a/src/pages/usage/components/export-data.tsx b/src/pages/usage/components/export-data.tsx index a00cd3d9..8300f79b 100644 --- a/src/pages/usage/components/export-data.tsx +++ b/src/pages/usage/components/export-data.tsx @@ -22,7 +22,7 @@ const ExportData: React.FC<{ metaData: any; granularity: string; initialState: { - activeModels: ValueType[][]; + activeRoutes: string[]; activeApiKeys: ValueType[][]; users: string[]; start_date: string; @@ -32,7 +32,7 @@ const ExportData: React.FC<{ scope: string; start_date: string; end_date: string; - models: string[]; + routes: string[]; users: string[]; api_keys: string[]; }; @@ -84,7 +84,7 @@ const ExportData: React.FC<{ ...pageParams, granularity: 'day', sort_by: '-date', - group_by: ['date', 'user', 'model', 'api_key'], + group_by: ['date', 'user', 'route', 'api_key'], filters: nextFilters, scope: initialScope, start_date: nextCommonFilters.start_date, @@ -113,25 +113,12 @@ const ExportData: React.FC<{ } }, { - title: intl.formatMessage({ id: 'usage.table.cluster' }), - dataIndex: ['model', 'identity', 'value', 'cluster_name'], + title: intl.formatMessage({ id: 'usage.filter.group.model' }), + dataIndex: ['route', 'label'], render: (text: string) => { return {text}; } }, - { - title: intl.formatMessage({ id: 'dashboard.usage.export.model' }), - dataIndex: ['model', 'identity', 'value', 'model_name'], - render: (text: string, record: any) => { - return ( - - {record?.model?.identity?.value?.provider_name - ? `${record?.model?.identity?.value?.provider_name}/${text}` - : text} - - ); - } - }, { title: intl.formatMessage({ id: 'dashboard.usage.export.user' }), dataIndex: ['user', 'label'], @@ -213,8 +200,7 @@ const ExportData: React.FC<{ jsonData: (dataSource.dataList || []).map((item: any) => ({ date: item?.date?.label, user: item?.user?.label, - cluster: item?.model?.identity?.value?.cluster_name, - model: item?.model?.identity?.value?.model_name, + route: item?.route?.label, api_key: item?.api_key?.label, input_tokens: item?.input_tokens, input_cached_tokens: item?.input_cached_tokens, @@ -226,7 +212,7 @@ const ExportData: React.FC<{ fields: [ 'date', 'user', - 'model', + 'route', 'api_key', 'input_tokens', 'input_cached_tokens', @@ -237,8 +223,7 @@ const ExportData: React.FC<{ fieldLabels: { date: intl.formatMessage({ id: 'dashboard.usage.export.date' }), user: intl.formatMessage({ id: 'dashboard.usage.export.user' }), - cluster: intl.formatMessage({ id: 'usage.table.cluster' }), - model: intl.formatMessage({ id: 'dashboard.usage.export.model' }), + route: intl.formatMessage({ id: 'usage.filter.group.model' }), api_key: intl.formatMessage({ id: 'usage.table.provider' }), input_tokens: intl.formatMessage({ id: 'usage.filter.inputTokens' @@ -286,7 +271,7 @@ const ExportData: React.FC<{ fetchExportData({ ...INITIAL_PAGE_PARAMS, granularity: 'day', - group_by: ['date', 'user', 'model', 'api_key'], + group_by: ['date', 'user', 'route', 'api_key'], filters, sort_by: '-date', scope: initialScope, diff --git a/src/pages/usage/components/filter-bar.tsx b/src/pages/usage/components/filter-bar.tsx index 3dbb5b95..1d8500da 100644 --- a/src/pages/usage/components/filter-bar.tsx +++ b/src/pages/usage/components/filter-bar.tsx @@ -1,5 +1,4 @@ import useRangePickerPreset from '@/pages/dashboard/hooks/use-rangepicker-preset'; -import ProviderLogo from '@/pages/maas-provider/components/provider-logo'; import { useModel } from '@@/plugin-model'; import { DownloadOutlined, SyncOutlined } from '@ant-design/icons'; import { @@ -32,21 +31,19 @@ interface FilterBarProps { scope: string; startDate: string; endDate: string; - selectedModels: string[]; + selectedRoutes: string[]; selectedUsers: string[]; selectedApiKeys: string[]; - modelOptions: GroupOption[]; + routeOptions: OptionType[]; userOptions: OptionType[]; apiKeyOptions: GroupOption[]; - activeModels: valueType[][]; activeApiKeys: valueType[][]; handlePickerChange: (picker: DateType) => void; onScopeChange: (value: string) => void; onDateChange: (dates: any, dateStrings: [string, string]) => void; - onModelsChange: (value: string[]) => void; + onRoutesChange: (value: string[]) => void; onUsersChange: (value: string[]) => void; onApiKeysChange: (value: string[]) => void; - handleActiveModelsChange: (value: valueType[][]) => void; handleActiveApiKeysChange: (value: valueType[][]) => void; onExport?: () => void; handleSearch?: () => void; @@ -56,7 +53,7 @@ interface FilterBarProps { scope: string; start_date: string; end_date: string; - models: string[]; + routes: string[]; users: string[]; api_keys: string[]; }; @@ -67,18 +64,17 @@ const FilterBar: React.FC = (props) => { pageType = 'page', startDate, endDate, + selectedRoutes, selectedUsers, selectedApiKeys, - modelOptions, + routeOptions, userOptions, apiKeyOptions, - activeModels, activeApiKeys, - handleActiveModelsChange, handleActiveApiKeysChange, handlePickerChange, onDateChange, - onModelsChange, + onRoutesChange, onUsersChange, onApiKeysChange, onExportChart, @@ -157,17 +153,6 @@ const FilterBar: React.FC = (props) => { ); }; - const handleOnModelsChange = (value: valueType[][], selectedOptions: any) => { - const selectedValues: string[] = value.map((item) => { - if (Array.isArray(item)) { - return item[item.length - 1] as string; // Get the last value in the array - } - return item as string; - }); - handleActiveModelsChange(value); - onModelsChange(selectedValues); - }; - const handleOnApiKeysChange = ( value: valueType[][], selectedOptions: any @@ -182,55 +167,6 @@ const FilterBar: React.FC = (props) => { onApiKeysChange(selectedValues); }; - const displayRender = (labels: any[], option: any) => { - return ( - - {labels[0]} / {labels[1]} - - } - > - {labels[0]} / {labels[1]} - - ); - }; - - const optionRender = (option: any) => { - const { data } = option; - if (!data.isParent) { - return ( - - {data.label} - {data.deleted && - renderTag(intl.formatMessage({ id: 'usage.table.deleted' }))} - - ); - } - - if (data.type === 'deployments') { - return ( - - - - {intl.formatMessage({ id: 'menu.models.deployment' })} - - - ); - } - - return ( - - - - {data.label} - - - ); - }; - const apiKeyOptionRender = (option: any) => { const { data } = option; if (!data.isParent) { @@ -303,47 +239,19 @@ const FilterBar: React.FC = (props) => { style={{ width: 240 }} onChange={onDateChange} /> -
- triggerNode.parentNode} - > -
+ value={selectedRoutes} + optionLabelRender={singleOptionRender} + onChange={onRoutesChange} + /> {initialState?.currentUser?.is_admin && ( <> + Array.isArray(dataIndex) ? dataIndex.join('_') : dataIndex; + +const buildSheetMeta = (columns: ColumnLike[]) => { + const fields: string[] = []; + const fieldLabels: Record = {}; + const formatMap: Record any> = {}; + + columns.forEach((col) => { + if (!col.dataIndex) return; + const key = toFieldKey(col.dataIndex); + fields.push(key); + fieldLabels[key] = col.title; + if (Array.isArray(col.dataIndex)) { + const path = col.dataIndex; + formatMap[key] = (_raw, row) => _.get(row, path); + } + }); + + return { fields, fieldLabels, formatMap }; +}; + const useExportTable = () => { const store = useStore(); const modelsColumns = useModelsColumns(); @@ -20,53 +48,34 @@ const useExportTable = () => { const usersTableData = store.get(usersTableDataAtom); const apiKeysTableData = store.get(apiKeysTableDataAtom); const modelsTableData = store.get(modelsTableDataAtom); + + const modelsMeta = buildSheetMeta(modelsColumns); + const apiKeysMeta = buildSheetMeta(apiKeysColumns); + const usersMeta = buildSheetMeta(usersColumns); + exportJsonToExcel({ fileName: 'table_data.xlsx', sheets: [ { jsonData: modelsTableData.dataList || [], sheetName: 'models', - fields: modelsColumns - .map((col: any) => _.join(col.dataIndex, '_')) - .filter(Boolean) as string[], - fieldLabels: modelsColumns.reduce( - (map, col) => { - map[_.join(col.dataIndex, '_')] = col.title; - return map; - }, - {} as Record - ), - formatMap: {} + fields: modelsMeta.fields, + fieldLabels: modelsMeta.fieldLabels, + formatMap: modelsMeta.formatMap }, { jsonData: apiKeysTableData.dataList || [], sheetName: 'api_keys', - fields: apiKeysColumns - .map((col: any) => col.dataIndex) - .filter(Boolean) as string[], - fieldLabels: apiKeysColumns.reduce( - (map, col) => { - map[_.join(col.dataIndex, '_')] = col.title; - return map; - }, - {} as Record - ), - formatMap: {} + fields: apiKeysMeta.fields, + fieldLabels: apiKeysMeta.fieldLabels, + formatMap: apiKeysMeta.formatMap }, { jsonData: usersTableData.dataList || [], sheetName: 'users', - fields: usersColumns - .map((col: any) => col.dataIndex) - .filter(Boolean) as string[], - fieldLabels: usersColumns.reduce( - (map, col) => { - map[_.join(col.dataIndex, '_')] = col.title; - return map; - }, - {} as Record - ), - formatMap: {} + fields: usersMeta.fields, + fieldLabels: usersMeta.fieldLabels, + formatMap: usersMeta.formatMap } ] }); diff --git a/src/pages/usage/hooks/use-models-columns.tsx b/src/pages/usage/hooks/use-models-columns.tsx index 76e5d81b..0f47f4ac 100644 --- a/src/pages/usage/hooks/use-models-columns.tsx +++ b/src/pages/usage/hooks/use-models-columns.tsx @@ -1,15 +1,10 @@ // columns.ts -import ProviderLogo from '@/pages/maas-provider/components/provider-logo'; import { AutoTooltip } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tag } from 'antd'; import { useMemo } from 'react'; import { BreakdownItem as ListItem } from '../config/types'; -interface ColumnsHookProps { - sortOrder: string[]; -} - const useModelsColumns = (): Array<{ title: string; dataIndex: string | string[]; @@ -21,8 +16,8 @@ const useModelsColumns = (): Array<{ return [ { title: intl.formatMessage({ id: 'common.table.name' }), - dataIndex: ['model', 'identity', 'value', 'model_name'], - key: 'model_name', + dataIndex: ['route', 'label'], + key: 'route_name', render: (text: string, record: ListItem) => ( {text} - {record.model?.deleted && ( + {record.route?.deleted && ( ) }, - { - title: intl.formatMessage({ id: 'usage.table.cluster' }), - dataIndex: ['model', 'identity', 'value', 'cluster_name'], - key: 'cluster_name', - render: (text: string, record: ListItem) => ( - {text || '-'} - ) - }, - { - title: intl.formatMessage({ id: 'usage.table.provider' }), - dataIndex: ['model', 'identity', 'value', 'provider_type'], - key: 'provider_type', - render: (text: string, record: ListItem) => ( - - - - {text || - (!text && intl.formatMessage({ id: 'menu.models.deployment' }))} - - - ) - }, { title: intl.formatMessage({ id: 'usage.filter.inputTokens' }), dataIndex: 'input_tokens', diff --git a/src/pages/usage/hooks/use-usage-filters.ts b/src/pages/usage/hooks/use-usage-filters.ts index ca0bf5de..8d1a2bd3 100644 --- a/src/pages/usage/hooks/use-usage-filters.ts +++ b/src/pages/usage/hooks/use-usage-filters.ts @@ -12,6 +12,9 @@ const DefaultDateConfig = { type UserOptionType = UsageFilterItem & { value: string; }; +type RouteOptionType = UsageFilterItem & { + value: string; +}; type ValueType = string | number | null; type FilterOptionType = Omit; @@ -23,6 +26,7 @@ interface UseUsageFiltersParams { models?: GroupOptionType[]; users?: UserOptionType[]; api_keys?: GroupOptionType[]; + routes?: RouteOptionType[]; }; chartFilters: { metric: string; @@ -30,7 +34,7 @@ interface UseUsageFiltersParams { granularity: string; }; initialState?: { - activeModels?: ValueType[][]; + activeRoutes?: string[]; activeApiKeys?: ValueType[][]; users?: string[]; start_date?: string; @@ -45,13 +49,13 @@ interface UseUsageFiltersParams { onFetchData?: (params: { chartFilters: UseUsageFiltersParams['chartFilters']; filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; commonFilters: { scope: string; - models: string[]; + routes: string[]; users: string[]; api_keys: string[]; start_date: string; @@ -70,7 +74,7 @@ export const useUsageFilters = ({ onFetchData }: UseUsageFiltersParams) => { const { - activeModels: initialActiveModels = [], + activeRoutes: initialActiveRoutes = [], activeApiKeys: initialActiveApiKeys = [], users: initialUsers = [], start_date = '', @@ -93,7 +97,7 @@ export const useUsageFilters = ({ const [commonFilters, setCommonFilters] = useState({ scope: initialScope, - models: extractSelectedValues(initialActiveModels), + routes: initialActiveRoutes, users: initialUsers || [], api_keys: extractSelectedValues(initialActiveApiKeys), start_date: @@ -104,11 +108,9 @@ export const useUsageFilters = ({ end_date: end_date || dayjs().format('YYYY-MM-DD') }); - const modelOptions = metaData?.models || []; + const routeOptions = metaData?.routes || []; const userOptions = metaData?.users || []; const apiKeyOptions = metaData?.api_keys || []; - const [activeModels, setActiveModels] = - useState(initialActiveModels); const [activeApiKeys, setActiveApiKeys] = useState(initialActiveApiKeys); @@ -117,12 +119,11 @@ export const useUsageFilters = ({ return; } - setActiveModels(initialActiveModels); setActiveApiKeys(initialActiveApiKeys); setCommonFilters((prev) => ({ ...prev, scope: initialScope, - models: extractSelectedValues(initialActiveModels), + routes: initialActiveRoutes, users: initialUsers || [], api_keys: extractSelectedValues(initialActiveApiKeys), start_date: @@ -135,7 +136,7 @@ export const useUsageFilters = ({ }, [ end_date, initialActiveApiKeys, - initialActiveModels, + initialActiveRoutes, initialUsers, initialScope, initialState, @@ -144,17 +145,15 @@ export const useUsageFilters = ({ const buildFilters = (selected: typeof commonFilters) => { const filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; } = {}; - if (selected.models.length > 0) { - const modelsSet = new Set(selected.models); - filters.models = modelOptions - .flatMap((group) => - group.children.filter((item) => modelsSet.has(item.value)) - ) + if (selected.routes.length > 0) { + const routesSet = new Set(selected.routes); + filters.routes = routeOptions + .filter((item) => routesSet.has(item.value)) .map((item) => ({ identity: item.identity })); @@ -184,7 +183,7 @@ export const useUsageFilters = ({ const filters = useMemo( () => buildFilters(commonFilters), - [commonFilters, modelOptions, userOptions, apiKeyOptions] + [commonFilters, routeOptions, userOptions, apiKeyOptions] ); const fetchData = ( @@ -233,16 +232,12 @@ export const useUsageFilters = ({ } }; - const handleActiveModelsChange = (value: ValueType[][]) => { - setActiveModels(value); - }; - const handleActiveApiKeysChange = (value: ValueType[][]) => { setActiveApiKeys(value); }; const handleFilterChange = ( - type: 'models' | 'users' | 'api_keys', + type: 'routes' | 'users' | 'api_keys', value: string[] ) => { const selectedValues: string[] = value.map((item) => { @@ -267,7 +262,7 @@ export const useUsageFilters = ({ const items = timeSeriesData?.items || []; const groupDim = chartFilters.group_by as | 'user' - | 'model' + | 'route' | 'api_key' | null; const metric = chartFilters.metric as keyof BreakdownItem; @@ -327,20 +322,18 @@ export const useUsageFilters = ({ scope: commonFilters.scope, startDate: commonFilters.start_date, endDate: commonFilters.end_date, - selectedModels: commonFilters.models, + selectedRoutes: commonFilters.routes, selectedUsers: commonFilters.users, selectedApiKeys: commonFilters.api_keys, - modelOptions, + routeOptions, userOptions, apiKeyOptions, activeApiKeys, - activeModels, handleSearch, - handleActiveModelsChange, handleActiveApiKeysChange, onScopeChange: handleScopeChange, onDateChange: handleDateChange, - onModelsChange: (value: string[]) => handleFilterChange('models', value), + onRoutesChange: (value: string[]) => handleFilterChange('routes', value), onUsersChange: (value: string[]) => handleFilterChange('users', value), onApiKeysChange: (value: string[]) => handleFilterChange('api_keys', value), onExportChart: handleOnExportChart diff --git a/src/pages/usage/index.tsx b/src/pages/usage/index.tsx index 1b30ac9d..1ccfa5fc 100644 --- a/src/pages/usage/index.tsx +++ b/src/pages/usage/index.tsx @@ -164,8 +164,8 @@ const Usage: React.FC = () => { filterBar.onDateChange(dates, dateStrings); handleBreakdownPageReset(); }} - onModelsChange={(value) => { - filterBar.onModelsChange(value); + onRoutesChange={(value) => { + filterBar.onRoutesChange(value); handleBreakdownPageReset(); }} onUsersChange={(value) => { @@ -228,7 +228,7 @@ const Usage: React.FC = () => { handlePickerChange={handlePickerChange} onCancel={() => setOpenExportModal(false)} initialState={{ - activeModels: filterBar.activeModels, + activeRoutes: filterBar.selectedRoutes, activeApiKeys: filterBar.activeApiKeys, users: commonFilters.users, start_date: commonFilters.start_date, diff --git a/src/pages/usage/services/use-query-breakdown-list.ts b/src/pages/usage/services/use-query-breakdown-list.ts index db3b16fe..4fa1e47e 100644 --- a/src/pages/usage/services/use-query-breakdown-list.ts +++ b/src/pages/usage/services/use-query-breakdown-list.ts @@ -31,7 +31,7 @@ export const useQueryBreakdownList = (options?: { ListItem, Global.SearchParams & { filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; @@ -46,7 +46,7 @@ export const useQueryBreakdownList = (options?: { const fetchListData = async ( params: Global.SearchParams & { filters: { - models?: FilterOptionType[]; + routes?: FilterOptionType[]; users?: FilterOptionType[]; api_keys?: FilterOptionType[]; }; diff --git a/src/pages/usage/services/use-query-meta-data.ts b/src/pages/usage/services/use-query-meta-data.ts index aded6eb0..c42c229c 100644 --- a/src/pages/usage/services/use-query-meta-data.ts +++ b/src/pages/usage/services/use-query-meta-data.ts @@ -9,6 +9,10 @@ type UserOptionType = UsageFilterItem & { value: string; }; +type RouteOptionType = UsageFilterItem & { + value: string; +}; + export default function useQueryUsageMetaData() { const { detailData, loading, cancelRequest, fetchData } = useQueryData({ @@ -20,10 +24,12 @@ export default function useQueryUsageMetaData() { models: GroupOption[]; users: UserOptionType[]; api_keys: GroupOption[]; + routes: RouteOptionType[]; }>({ models: [], users: [], - api_keys: [] + api_keys: [], + routes: [] }); // the current user sort in the first place @@ -70,7 +76,12 @@ export default function useQueryUsageMetaData() { value: item.label, label: item.identity.value.api_key_name || '' }) - }) + }), + routes: + (res?.filters?.routes || []).map((item) => ({ + ...item, + value: item.label + })) || [] }; setResult(data); }; diff --git a/src/pages/usage/tables/models-table.tsx b/src/pages/usage/tables/models-table.tsx index c91f0758..3fc333cf 100644 --- a/src/pages/usage/tables/models-table.tsx +++ b/src/pages/usage/tables/models-table.tsx @@ -6,17 +6,17 @@ import { Table } from 'antd'; import _ from 'lodash'; import { useEffect, useRef, useState } from 'react'; import { BreakdownItem, FilterOptionType } from '../config/types'; -import useUsersColumns from '../hooks/use-models-columns'; +import useModelsColumns from '../hooks/use-models-columns'; import useQueryBreakdownList from '../services/use-query-breakdown-list'; import getBreakdownRowKey from '../utils/get-breakdown-row-key'; const Models: React.FC<{ - models: FilterOptionType[]; + routes: FilterOptionType[]; dateRange: { start_date: string; end_date: string }; scope: string; pageResetKey?: number; refreshKey?: number; -}> = ({ models, dateRange, scope, pageResetKey = 0, refreshKey = 0 }) => { +}> = ({ routes, dateRange, scope, pageResetKey = 0, refreshKey = 0 }) => { const intl = useIntl(); const { loading, dataSource, fetchData } = useQueryBreakdownList({ @@ -51,7 +51,7 @@ const Models: React.FC<{ })); }; - const columns = useUsersColumns(); + const columns = useModelsColumns(); useEffect(() => { if (queryParams.page !== 1) { @@ -89,9 +89,9 @@ const Models: React.FC<{ fetchData({ ...queryParams, - group_by: ['model'], + group_by: ['route'], filters: { - models + routes }, scope: scope, ...dateRange @@ -99,7 +99,7 @@ const Models: React.FC<{ }, [ dateRange.end_date, dateRange.start_date, - models, + routes, queryParams.page, queryParams.perPage, queryParams.sort_by, diff --git a/src/pages/usage/utils/get-breakdown-row-key.ts b/src/pages/usage/utils/get-breakdown-row-key.ts index 21a2ebe6..d9814892 100644 --- a/src/pages/usage/utils/get-breakdown-row-key.ts +++ b/src/pages/usage/utils/get-breakdown-row-key.ts @@ -5,7 +5,7 @@ export const getBreakdownRowKey = ( type: string ): string => { if (type === 'models') { - return `${record.model.label}`; + return `${record.route?.label || ''}`; } if (type === 'users') { @@ -16,7 +16,7 @@ export const getBreakdownRowKey = ( return `${record.api_key.label}`; } - return `${record.date?.value || ''}-${record.model.label}-${record.user.label}-${record.api_key.label}`; + return `${record.date?.value || ''}-${record.route?.label || ''}-${record.user.label}-${record.api_key.label}`; }; export default getBreakdownRowKey;