refactor(usage): split tabs into separate dirs

This commit is contained in:
jialin
2026-06-14 19:14:18 +08:00
committed by jialin
parent 6f56e614f3
commit 6cf512cccd
10 changed files with 49 additions and 44 deletions
@@ -24,8 +24,8 @@ import {
ResourceEventItem, ResourceEventItem,
ResourceEventsResponse ResourceEventsResponse
} from '../apis/resource'; } from '../apis/resource';
import ResourceFilterBar from '../components/resource-filter-bar';
import { parseRollup } from '../utils/time-buckets'; import { parseRollup } from '../utils/time-buckets';
import ResourceFilterBar from './resource-filter-bar';
// Only these four are ever emitted (see resource_event_logger): create/delete // Only these four are ever emitted (see resource_event_logger): create/delete
// + the metering-window pair. updated/attached/detached exist as enum values // + the metering-window pair. updated/attached/detached exist as enum values
@@ -279,6 +279,7 @@ const ResourceEvents: React.FC = () => {
columns={columns as any} columns={columns as any}
style={{ marginTop: 24 }} style={{ marginTop: 24 }}
pagination={{ pagination={{
size: 'middle',
current: queryParams.page, current: queryParams.page,
pageSize: data?.pagination.perPage ?? 50, pageSize: data?.pagination.perPage ?? 50,
total: data?.pagination.total ?? 0, total: data?.pagination.total ?? 0,
+20 -17
View File
@@ -16,11 +16,11 @@
import { useAccess, useIntl } from '@umijs/max'; import { useAccess, useIntl } from '@umijs/max';
import { Tabs, TabsProps } from 'antd'; import { Tabs, TabsProps } from 'antd';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import GpuInstancesTab from './components/gpu-instances-tab'; import ResourceEvents from './events-tab';
import ResourceEvents from './components/resource-events'; import GpuInstancesTab from './instances-tab';
import StorageTab from './components/storage-tab'; import StorageTab from './storage-tab';
import SummaryTab from './components/summary-tab'; import SummaryTab from './summary-tab';
import TokenTab from './components/token-tab'; import TokenTab from './token-tab';
const Usage: React.FC = () => { const Usage: React.FC = () => {
const access = useAccess(); const access = useAccess();
@@ -28,11 +28,15 @@ const Usage: React.FC = () => {
// Land on the cross-resource Summary by default. // Land on the cross-resource Summary by default.
const [activeKey, setActiveKey] = useState<string>('summary'); const [activeKey, setActiveKey] = useState<string>('summary');
const items: TabsProps['items'] = useMemo( const items: TabsProps['items'] = useMemo(() => {
() => [ type AccessTab = NonNullable<TabsProps['items']>[number] & {
access?: string;
};
const tabs: AccessTab[] = [
{ {
key: 'summary', key: 'summary',
label: intl.formatMessage({ id: 'usage.tabs.summary' }), label: intl.formatMessage({ id: 'usage.tabs.summary' }),
access: 'canSeeGpuService',
children: <SummaryTab /> children: <SummaryTab />
}, },
{ {
@@ -43,34 +47,33 @@ const Usage: React.FC = () => {
{ {
key: 'gpu-instances', key: 'gpu-instances',
label: intl.formatMessage({ id: 'usage.tabs.gpuInstances' }), label: intl.formatMessage({ id: 'usage.tabs.gpuInstances' }),
access: 'canSeeGpuService',
children: <GpuInstancesTab /> children: <GpuInstancesTab />
}, },
{ {
key: 'storage', key: 'storage',
label: intl.formatMessage({ id: 'usage.tabs.storage' }), label: intl.formatMessage({ id: 'usage.tabs.storage' }),
access: 'canSeeGpuService',
children: <StorageTab /> children: <StorageTab />
}, },
{ {
key: 'resource-events', key: 'resource-events',
label: intl.formatMessage({ id: 'usage.tabs.resourceEvents' }), label: intl.formatMessage({ id: 'usage.tabs.resourceEvents' }),
access: 'canSeeGpuService',
children: <ResourceEvents /> children: <ResourceEvents />
} }
], ];
[intl] return tabs.filter((item) => {
); if (!item.access) return true;
return (access as Record<string, boolean>)[item.access];
// 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. }, [intl, access]);
if (!access.canSeeGpuService) {
return <TokenTab />;
}
return ( return (
<Tabs <Tabs
activeKey={activeKey} activeKey={activeKey}
onChange={setActiveKey} onChange={setActiveKey}
items={items} items={items}
destroyOnHidden
// The content area adds 24px top padding; on table pages that space is // The content area adds 24px top padding; on table pages that space is
// filled immediately, but here it sits empty above the tab bar and reads // filled immediately, but here it sits empty above the tab bar and reads
// as too tall. Pull the tab bar up to ~flush with the header divider. // as too tall. Pull the tab bar up to ~flush with the header divider.
@@ -26,6 +26,10 @@ import {
ResourceBreakdownRequest, ResourceBreakdownRequest,
ResourceBreakdownResponse ResourceBreakdownResponse
} from '../apis/resource'; } from '../apis/resource';
import MetricChartCard from '../components/metric-chart-card';
import MetricLabel from '../components/metric-label';
import ResourceExportData from '../components/resource-export-data';
import ResourceFilterBar from '../components/resource-filter-bar';
import useResourceMeta from '../hooks/use-resource-meta'; import useResourceMeta from '../hooks/use-resource-meta';
import { instanceTypeLabel } from '../utils/format-instance-type'; import { instanceTypeLabel } from '../utils/format-instance-type';
import { import {
@@ -35,10 +39,6 @@ import {
parseRollup parseRollup
} from '../utils/time-buckets'; } from '../utils/time-buckets';
import { buildTrendSeries } from '../utils/trend-series'; import { buildTrendSeries } from '../utils/trend-series';
import MetricChartCard from './metric-chart-card';
import MetricLabel from './metric-label';
import ResourceExportData from './resource-export-data';
import ResourceFilterBar from './resource-filter-bar';
type Scope = 'self' | 'all'; type Scope = 'self' | 'all';
type Metric = 'gpu_hours' | 'instance_hours'; type Metric = 'gpu_hours' | 'instance_hours';
@@ -24,6 +24,10 @@ import {
ResourceBreakdownRequest, ResourceBreakdownRequest,
ResourceBreakdownResponse ResourceBreakdownResponse
} from '../apis/resource'; } from '../apis/resource';
import MetricChartCard from '../components/metric-chart-card';
import MetricLabel from '../components/metric-label';
import ResourceExportData from '../components/resource-export-data';
import ResourceFilterBar from '../components/resource-filter-bar';
import useResourceMeta from '../hooks/use-resource-meta'; import useResourceMeta from '../hooks/use-resource-meta';
import { import {
bucketKey, bucketKey,
@@ -32,10 +36,6 @@ import {
parseRollup parseRollup
} from '../utils/time-buckets'; } from '../utils/time-buckets';
import { buildTrendSeries } from '../utils/trend-series'; import { buildTrendSeries } from '../utils/trend-series';
import MetricChartCard from './metric-chart-card';
import MetricLabel from './metric-label';
import ResourceExportData from './resource-export-data';
import ResourceFilterBar from './resource-filter-bar';
type Scope = 'self' | 'all'; type Scope = 'self' | 'all';
type Metric = 'storage_gb_days' | 'storage_gb_hours'; type Metric = 'storage_gb_days' | 'storage_gb_hours';
@@ -500,6 +500,7 @@ const StorageTab: React.FC = () => {
} }
}} }}
pagination={{ pagination={{
size: 'middle',
current: tablePage, current: tablePage,
pageSize: tableData?.pagination.perPage ?? 50, pageSize: tableData?.pagination.perPage ?? 50,
total: tableData?.pagination.total ?? 0, total: tableData?.pagination.total ?? 0,
@@ -38,13 +38,13 @@ import {
ResourceBreakdownResponse, ResourceBreakdownResponse,
UsageSummaryResponse UsageSummaryResponse
} from '../apis/resource'; } from '../apis/resource';
import ResourceFilterBar from '../components/resource-filter-bar';
import useResourceMeta from '../hooks/use-resource-meta'; import useResourceMeta from '../hooks/use-resource-meta';
import { import {
bucketKey, bucketKey,
generateBucketRange, generateBucketRange,
Granularity Granularity
} from '../utils/time-buckets'; } from '../utils/time-buckets';
import ResourceFilterBar from './resource-filter-bar';
type Scope = 'self' | 'all'; type Scope = 'self' | 'all';
@@ -1,7 +1,7 @@
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { UsageFilterItem } from '../config/types'; import { UsageFilterItem } from '../../config/types';
import ApiKeysTable from '../tables/apikeys-table'; import ApiKeysTable from '../tables/apikeys-table';
import ModelsTable from '../tables/models-table'; import ModelsTable from '../tables/models-table';
import UsersTable from '../tables/users-table'; import UsersTable from '../tables/users-table';
@@ -3,13 +3,13 @@ import { formatLargeNumber } from '@/utils';
import { SimpleCard } from '@gpustack/core-ui'; import { SimpleCard } from '@gpustack/core-ui';
import { useAccess, useIntl } from '@umijs/max'; import { useAccess, useIntl } from '@umijs/max';
import React, { useEffect, useMemo, useState } from 'react'; 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 useExportTable from '../hooks/use-export-table';
import { useUsageFilters } from '../hooks/use-usage-filters'; import { useUsageFilters } from '../hooks/use-usage-filters';
import useQueryUsageMetaData from '../services/use-query-meta-data'; import useQueryUsageMetaData from '../services/use-query-meta-data';
import BreakdownTabs from './breakdown-tabs'; import BreakdownTabs from './components/breakdown-tabs';
import DailyUsage from './daily-usage';
import ExportData from './export-data';
import FilterBar from './filter-bar';
type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year'; type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year';
@@ -5,10 +5,10 @@ import { useIntl } from '@umijs/max';
import { Table } from 'antd'; import { Table } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { FilterOptionType } from '../config/types'; import { FilterOptionType } from '../../config/types';
import useAPIKeys from '../hooks/use-apikeys-columns'; import useAPIKeys from '../../hooks/use-apikeys-columns';
import useQueryBreakdownList from '../services/use-query-breakdown-list'; import useQueryBreakdownList from '../../services/use-query-breakdown-list';
import getBreakdownRowKey from '../utils/get-breakdown-row-key'; import getBreakdownRowKey from '../../utils/get-breakdown-row-key';
const APIKeys: React.FC<{ const APIKeys: React.FC<{
apiKeys: FilterOptionType[]; apiKeys: FilterOptionType[];
@@ -6,10 +6,10 @@ import { useIntl } from '@umijs/max';
import { Table } from 'antd'; import { Table } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { BreakdownItem, FilterOptionType } from '../config/types'; import { BreakdownItem, FilterOptionType } from '../../config/types';
import useModelsColumns from '../hooks/use-models-columns'; import useModelsColumns from '../../hooks/use-models-columns';
import useQueryBreakdownList from '../services/use-query-breakdown-list'; import useQueryBreakdownList from '../../services/use-query-breakdown-list';
import getBreakdownRowKey from '../utils/get-breakdown-row-key'; import getBreakdownRowKey from '../../utils/get-breakdown-row-key';
const Models: React.FC<{ const Models: React.FC<{
routes: FilterOptionType[]; routes: FilterOptionType[];
@@ -5,10 +5,10 @@ import { useIntl } from '@umijs/max';
import { Table } from 'antd'; import { Table } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { FilterOptionType } from '../config/types'; import { FilterOptionType } from '../../config/types';
import useUsersColumns from '../hooks/use-users-columns'; import useUsersColumns from '../../hooks/use-users-columns';
import useQueryBreakdownList from '../services/use-query-breakdown-list'; import useQueryBreakdownList from '../../services/use-query-breakdown-list';
import getBreakdownRowKey from '../utils/get-breakdown-row-key'; import getBreakdownRowKey from '../../utils/get-breakdown-row-key';
const Users: React.FC<{ const Users: React.FC<{
users: FilterOptionType[]; users: FilterOptionType[];