refactor(usage): split tabs into separate dirs
This commit is contained in:
+2
-1
@@ -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
@@ -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.
|
||||||
|
|||||||
+4
-4
@@ -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
-1
@@ -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';
|
||||||
|
|
||||||
+4
-4
@@ -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[];
|
||||||
+4
-4
@@ -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[];
|
||||||
+4
-4
@@ -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[];
|
||||||
Reference in New Issue
Block a user