From 6cf512cccde1667186a3849f605af02c50d22fcc Mon Sep 17 00:00:00 2001 From: jialin Date: Sun, 14 Jun 2026 11:39:04 +0800 Subject: [PATCH] refactor(usage): split tabs into separate dirs --- .../index.tsx} | 3 +- src/pages/usage/index.tsx | 37 ++++++++++--------- .../index.tsx} | 8 ++-- .../storage-tab.tsx => storage-tab/index.tsx} | 9 +++-- .../summary-tab.tsx => summary-tab/index.tsx} | 2 +- .../components/breakdown-tabs.tsx | 2 +- .../token-tab.tsx => token-tab/index.tsx} | 8 ++-- .../{ => token-tab}/tables/apikeys-table.tsx | 8 ++-- .../{ => token-tab}/tables/models-table.tsx | 8 ++-- .../{ => token-tab}/tables/users-table.tsx | 8 ++-- 10 files changed, 49 insertions(+), 44 deletions(-) rename src/pages/usage/{components/resource-events.tsx => events-tab/index.tsx} (99%) rename src/pages/usage/{components/gpu-instances-tab.tsx => instances-tab/index.tsx} (98%) rename src/pages/usage/{components/storage-tab.tsx => storage-tab/index.tsx} (98%) rename src/pages/usage/{components/summary-tab.tsx => summary-tab/index.tsx} (99%) rename src/pages/usage/{ => token-tab}/components/breakdown-tabs.tsx (97%) rename src/pages/usage/{components/token-tab.tsx => token-tab/index.tsx} (97%) rename src/pages/usage/{ => token-tab}/tables/apikeys-table.tsx (92%) rename src/pages/usage/{ => token-tab}/tables/models-table.tsx (94%) rename src/pages/usage/{ => token-tab}/tables/users-table.tsx (92%) diff --git a/src/pages/usage/components/resource-events.tsx b/src/pages/usage/events-tab/index.tsx similarity index 99% rename from src/pages/usage/components/resource-events.tsx rename to src/pages/usage/events-tab/index.tsx index 6c55ed10..3f90a431 100644 --- a/src/pages/usage/components/resource-events.tsx +++ b/src/pages/usage/events-tab/index.tsx @@ -24,8 +24,8 @@ import { ResourceEventItem, ResourceEventsResponse } from '../apis/resource'; +import ResourceFilterBar from '../components/resource-filter-bar'; import { parseRollup } from '../utils/time-buckets'; -import ResourceFilterBar from './resource-filter-bar'; // Only these four are ever emitted (see resource_event_logger): create/delete // + the metering-window pair. updated/attached/detached exist as enum values @@ -279,6 +279,7 @@ const ResourceEvents: React.FC = () => { columns={columns as any} style={{ marginTop: 24 }} pagination={{ + size: 'middle', current: queryParams.page, pageSize: data?.pagination.perPage ?? 50, total: data?.pagination.total ?? 0, diff --git a/src/pages/usage/index.tsx b/src/pages/usage/index.tsx index 28213946..e49e48cc 100644 --- a/src/pages/usage/index.tsx +++ b/src/pages/usage/index.tsx @@ -16,11 +16,11 @@ import { useAccess, useIntl } from '@umijs/max'; import { Tabs, TabsProps } from 'antd'; import React, { useMemo, useState } from 'react'; -import GpuInstancesTab from './components/gpu-instances-tab'; -import ResourceEvents from './components/resource-events'; -import StorageTab from './components/storage-tab'; -import SummaryTab from './components/summary-tab'; -import TokenTab from './components/token-tab'; +import ResourceEvents from './events-tab'; +import GpuInstancesTab from './instances-tab'; +import StorageTab from './storage-tab'; +import SummaryTab from './summary-tab'; +import TokenTab from './token-tab'; const Usage: React.FC = () => { const access = useAccess(); @@ -28,11 +28,15 @@ const Usage: React.FC = () => { // Land on the cross-resource Summary by default. const [activeKey, setActiveKey] = useState('summary'); - const items: TabsProps['items'] = useMemo( - () => [ + const items: TabsProps['items'] = useMemo(() => { + type AccessTab = NonNullable[number] & { + access?: string; + }; + const tabs: AccessTab[] = [ { key: 'summary', label: intl.formatMessage({ id: 'usage.tabs.summary' }), + access: 'canSeeGpuService', children: }, { @@ -43,34 +47,33 @@ const Usage: React.FC = () => { { key: 'gpu-instances', label: intl.formatMessage({ id: 'usage.tabs.gpuInstances' }), + access: 'canSeeGpuService', children: }, { key: 'storage', label: intl.formatMessage({ id: 'usage.tabs.storage' }), + access: 'canSeeGpuService', children: }, { key: 'resource-events', label: intl.formatMessage({ id: 'usage.tabs.resourceEvents' }), + access: 'canSeeGpuService', children: } - ], - [intl] - ); - - // Users who can't see GPU Service (MaaS-only: no cluster, no resource usage) - // only have token usage — drop the tab shell and show Tokens directly. - if (!access.canSeeGpuService) { - return ; - } + ]; + return tabs.filter((item) => { + if (!item.access) return true; + return (access as Record)[item.access]; + }); + }, [intl, access]); return ( { } }} pagination={{ + size: 'middle', current: tablePage, pageSize: tableData?.pagination.perPage ?? 50, total: tableData?.pagination.total ?? 0, diff --git a/src/pages/usage/components/summary-tab.tsx b/src/pages/usage/summary-tab/index.tsx similarity index 99% rename from src/pages/usage/components/summary-tab.tsx rename to src/pages/usage/summary-tab/index.tsx index 55f67c21..339c2b35 100644 --- a/src/pages/usage/components/summary-tab.tsx +++ b/src/pages/usage/summary-tab/index.tsx @@ -38,13 +38,13 @@ import { ResourceBreakdownResponse, UsageSummaryResponse } from '../apis/resource'; +import ResourceFilterBar from '../components/resource-filter-bar'; import useResourceMeta from '../hooks/use-resource-meta'; import { bucketKey, generateBucketRange, Granularity } from '../utils/time-buckets'; -import ResourceFilterBar from './resource-filter-bar'; type Scope = 'self' | 'all'; diff --git a/src/pages/usage/components/breakdown-tabs.tsx b/src/pages/usage/token-tab/components/breakdown-tabs.tsx similarity index 97% rename from src/pages/usage/components/breakdown-tabs.tsx rename to src/pages/usage/token-tab/components/breakdown-tabs.tsx index f62af590..9543fee3 100644 --- a/src/pages/usage/components/breakdown-tabs.tsx +++ b/src/pages/usage/token-tab/components/breakdown-tabs.tsx @@ -1,7 +1,7 @@ import { useIntl } from '@umijs/max'; import { Tabs } from 'antd'; import React, { useMemo } from 'react'; -import { UsageFilterItem } from '../config/types'; +import { UsageFilterItem } from '../../config/types'; import ApiKeysTable from '../tables/apikeys-table'; import ModelsTable from '../tables/models-table'; import UsersTable from '../tables/users-table'; diff --git a/src/pages/usage/components/token-tab.tsx b/src/pages/usage/token-tab/index.tsx similarity index 97% rename from src/pages/usage/components/token-tab.tsx rename to src/pages/usage/token-tab/index.tsx index 2861ca2c..51adf9fc 100644 --- a/src/pages/usage/components/token-tab.tsx +++ b/src/pages/usage/token-tab/index.tsx @@ -3,13 +3,13 @@ import { formatLargeNumber } from '@/utils'; import { SimpleCard } from '@gpustack/core-ui'; import { useAccess, useIntl } from '@umijs/max'; import React, { useEffect, useMemo, useState } from 'react'; +import DailyUsage from '../components/daily-usage'; +import ExportData from '../components/export-data'; +import FilterBar from '../components/filter-bar'; import useExportTable from '../hooks/use-export-table'; import { useUsageFilters } from '../hooks/use-usage-filters'; import useQueryUsageMetaData from '../services/use-query-meta-data'; -import BreakdownTabs from './breakdown-tabs'; -import DailyUsage from './daily-usage'; -import ExportData from './export-data'; -import FilterBar from './filter-bar'; +import BreakdownTabs from './components/breakdown-tabs'; type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year'; diff --git a/src/pages/usage/tables/apikeys-table.tsx b/src/pages/usage/token-tab/tables/apikeys-table.tsx similarity index 92% rename from src/pages/usage/tables/apikeys-table.tsx rename to src/pages/usage/token-tab/tables/apikeys-table.tsx index 1c46dc55..20cc674b 100644 --- a/src/pages/usage/tables/apikeys-table.tsx +++ b/src/pages/usage/token-tab/tables/apikeys-table.tsx @@ -5,10 +5,10 @@ import { useIntl } from '@umijs/max'; import { Table } from 'antd'; import _ from 'lodash'; import { useEffect, useRef, useState } from 'react'; -import { FilterOptionType } from '../config/types'; -import useAPIKeys from '../hooks/use-apikeys-columns'; -import useQueryBreakdownList from '../services/use-query-breakdown-list'; -import getBreakdownRowKey from '../utils/get-breakdown-row-key'; +import { FilterOptionType } from '../../config/types'; +import useAPIKeys from '../../hooks/use-apikeys-columns'; +import useQueryBreakdownList from '../../services/use-query-breakdown-list'; +import getBreakdownRowKey from '../../utils/get-breakdown-row-key'; const APIKeys: React.FC<{ apiKeys: FilterOptionType[]; diff --git a/src/pages/usage/tables/models-table.tsx b/src/pages/usage/token-tab/tables/models-table.tsx similarity index 94% rename from src/pages/usage/tables/models-table.tsx rename to src/pages/usage/token-tab/tables/models-table.tsx index bb2f5bef..ac555a89 100644 --- a/src/pages/usage/tables/models-table.tsx +++ b/src/pages/usage/token-tab/tables/models-table.tsx @@ -6,10 +6,10 @@ import { useIntl } from '@umijs/max'; import { Table } from 'antd'; import _ from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; -import { BreakdownItem, FilterOptionType } from '../config/types'; -import useModelsColumns from '../hooks/use-models-columns'; -import useQueryBreakdownList from '../services/use-query-breakdown-list'; -import getBreakdownRowKey from '../utils/get-breakdown-row-key'; +import { BreakdownItem, FilterOptionType } from '../../config/types'; +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<{ routes: FilterOptionType[]; diff --git a/src/pages/usage/tables/users-table.tsx b/src/pages/usage/token-tab/tables/users-table.tsx similarity index 92% rename from src/pages/usage/tables/users-table.tsx rename to src/pages/usage/token-tab/tables/users-table.tsx index 2f2a33c7..e8d7d867 100644 --- a/src/pages/usage/tables/users-table.tsx +++ b/src/pages/usage/token-tab/tables/users-table.tsx @@ -5,10 +5,10 @@ import { useIntl } from '@umijs/max'; import { Table } from 'antd'; import _ from 'lodash'; import { useEffect, useRef, useState } from 'react'; -import { FilterOptionType } from '../config/types'; -import useUsersColumns from '../hooks/use-users-columns'; -import useQueryBreakdownList from '../services/use-query-breakdown-list'; -import getBreakdownRowKey from '../utils/get-breakdown-row-key'; +import { FilterOptionType } from '../../config/types'; +import useUsersColumns from '../../hooks/use-users-columns'; +import useQueryBreakdownList from '../../services/use-query-breakdown-list'; +import getBreakdownRowKey from '../../utils/get-breakdown-row-key'; const Users: React.FC<{ users: FilterOptionType[];