/** * Usage page — top-level tab shell. * * - Summary: cross-resource overview (KPIs + trend + by-type breakdown + donut) * - Tokens: existing per-request token usage page (untouched) * - GPU Instances: per-instance compute usage * - Storage: PV capacity usage * - Resource Events: lifecycle event list (created / metered / deleted / ...) * * Resource Events is kept as a tab (not a separate route) so the page filter * set stays consistent across all views. * * The previous implementation lived in this file; it now lives in * ``components/token-tab.tsx`` so we can host it as a tab pane. */ import { useAccess, useIntl } from '@umijs/max'; import { Tabs, TabsProps } from 'antd'; import React, { useMemo, useState } from 'react'; 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(); const intl = useIntl(); // Land on the cross-resource Summary by default. const [activeKey, setActiveKey] = useState('summary'); 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: }, { key: 'tokens', label: intl.formatMessage({ id: 'usage.tabs.tokens' }), children: }, { 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: } ]; return tabs.filter((item) => { if (!item.access) return true; return (access as Record)[item.access]; }); }, [intl, access]); return ( ); }; export default Usage;