feat(usage): add plugin injection points for org / user-group filters and org breakdown tab
- token & resource filter bars render a plugin slot (UsageFilterBar / ResourceUsageFilterBar) for the organization / user-group filters - breakdown tabs read plugin-provided extra sub-tabs (breakdownExtraTabs / resourceBreakdownExtraTabs) so the enterprise plugin can inject the Organization sub-tab - thread the org / user-group filter state through the token filter hook and the resource tabs / breakdown tables / summary / export dialog - standardize the organization label on the principal name; resource export date formatted to date-only
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { getGPUStackPlugin } from '@/plugins';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Tabs } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
@@ -6,6 +7,24 @@ import ApiKeysTable from '../tables/apikeys-table';
|
||||
import ModelsTable from '../tables/models-table';
|
||||
import UsersTable from '../tables/users-table';
|
||||
|
||||
// A breakdown sub-tab contributed by a plugin (e.g. the enterprise
|
||||
// Organization tab). ``useVisible`` is a React hook the host calls
|
||||
// unconditionally per descriptor (stable array length → hook-safe) so the
|
||||
// plugin can gate visibility on its own runtime state (e.g. platform-wide
|
||||
// "All" context).
|
||||
export interface BreakdownExtraTab {
|
||||
key: string;
|
||||
labelId: string;
|
||||
useVisible?: () => boolean;
|
||||
Component: React.ComponentType<{
|
||||
filters: BreakdownFilters;
|
||||
dateRange: { start_date: string; end_date: string };
|
||||
scope: string;
|
||||
pageResetKey?: number;
|
||||
refreshKey?: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
const BreakdownTabs: React.FC<{
|
||||
dateRange: {
|
||||
start_date: string;
|
||||
@@ -18,7 +37,37 @@ const BreakdownTabs: React.FC<{
|
||||
}> = ({ filters, dateRange, scope, pageResetKey = 0, refreshKey = 0 }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const extraTabs: BreakdownExtraTab[] =
|
||||
getGPUStackPlugin()?.usage?.breakdownExtraTabs ?? [];
|
||||
// Call each descriptor's visibility hook here (outside useMemo) so React's
|
||||
// rules of hooks hold; the plugin's array is stable, so call order is too.
|
||||
const extraVisible = extraTabs.map((tab) =>
|
||||
tab.useVisible ? tab.useVisible() : true
|
||||
);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const extraItems = extraTabs
|
||||
.map((tab, index) => ({ tab, visible: extraVisible[index] }))
|
||||
.filter(({ visible }) => visible)
|
||||
.map(({ tab }) => {
|
||||
const Component = tab.Component;
|
||||
return {
|
||||
key: tab.key,
|
||||
label: intl.formatMessage({ id: tab.labelId }),
|
||||
forceRender: true,
|
||||
children: (
|
||||
<Component
|
||||
key={tab.key}
|
||||
filters={filters}
|
||||
dateRange={dateRange}
|
||||
scope={scope}
|
||||
pageResetKey={pageResetKey}
|
||||
refreshKey={refreshKey}
|
||||
/>
|
||||
)
|
||||
};
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'models',
|
||||
@@ -65,13 +114,24 @@ const BreakdownTabs: React.FC<{
|
||||
/>
|
||||
)
|
||||
}
|
||||
].filter((item) => {
|
||||
if (item.key === 'users') {
|
||||
return scope === 'all';
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [filters, dateRange, pageResetKey, refreshKey, scope]);
|
||||
]
|
||||
.filter((item) => {
|
||||
if (item.key === 'users') {
|
||||
return scope === 'all';
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.concat(extraItems);
|
||||
}, [
|
||||
filters,
|
||||
dateRange,
|
||||
pageResetKey,
|
||||
refreshKey,
|
||||
scope,
|
||||
extraTabs,
|
||||
extraVisible,
|
||||
intl
|
||||
]);
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: 16 }}>
|
||||
|
||||
Reference in New Issue
Block a user