feat(admin): 默认过滤实时负载禁用项

实时负载默认仅展示平台和模型均启用的来源,并增加全部状态、仅看禁用筛选及重置行为测试。
This commit is contained in:
2026-08-03 15:43:49 +08:00
parent ad8cdd525b
commit b56769512f
2 changed files with 39 additions and 3 deletions
@@ -37,6 +37,7 @@ describe('filterAndSortRealtimeLoad', () => {
const result = filterAndSortRealtimeLoad(statuses, platforms, { const result = filterAndSortRealtimeLoad(statuses, platforms, {
query: '平台', query: '平台',
platformId: '', platformId: '',
availability: 'enabled',
modelType: '', modelType: '',
runtimeState: '', runtimeState: '',
sortField: 'load', sortField: 'load',
@@ -50,6 +51,7 @@ describe('filterAndSortRealtimeLoad', () => {
const queued = filterAndSortRealtimeLoad(statuses, platforms, { const queued = filterAndSortRealtimeLoad(statuses, platforms, {
query: '', query: '',
platformId: '', platformId: '',
availability: 'enabled',
modelType: 'image_generate', modelType: 'image_generate',
runtimeState: 'queued', runtimeState: 'queued',
sortField: 'queued', sortField: 'queued',
@@ -59,6 +61,7 @@ describe('filterAndSortRealtimeLoad', () => {
const attention = filterAndSortRealtimeLoad(statuses, platforms, { const attention = filterAndSortRealtimeLoad(statuses, platforms, {
query: '', query: '',
platformId: '', platformId: '',
availability: 'all',
modelType: '', modelType: '',
runtimeState: 'attention', runtimeState: 'attention',
sortField: 'load', sortField: 'load',
@@ -69,4 +72,19 @@ describe('filterAndSortRealtimeLoad', () => {
expect(attention.map((item) => item.platformModelId)).toEqual(['model-b']); expect(attention.map((item) => item.platformModelId)).toEqual(['model-b']);
expect(statuses.map((item) => item.platformModelId)).toEqual(['model-a', 'model-b']); expect(statuses.map((item) => item.platformModelId)).toEqual(['model-a', 'model-b']);
}); });
it('hides disabled entries by default and supports all or disabled-only filters', () => {
const base = {
query: '',
platformId: '',
modelType: '',
runtimeState: '',
sortField: 'load' as const,
sortDirection: 'desc' as const,
now: Date.now(),
};
expect(filterAndSortRealtimeLoad(statuses, platforms, { ...base, availability: 'enabled' }).map((item) => item.platformModelId)).toEqual(['model-a']);
expect(filterAndSortRealtimeLoad(statuses, platforms, { ...base, availability: 'all' }).map((item) => item.platformModelId)).toEqual(['model-b', 'model-a']);
expect(filterAndSortRealtimeLoad(statuses, platforms, { ...base, availability: 'disabled' }).map((item) => item.platformModelId)).toEqual(['model-b']);
});
}); });
+21 -3
View File
@@ -19,6 +19,7 @@ export function RealtimeLoadPanel(props: {
const [restoreSavingId, setRestoreSavingId] = useState<string | null>(null); const [restoreSavingId, setRestoreSavingId] = useState<string | null>(null);
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const [platformId, setPlatformId] = useState(''); const [platformId, setPlatformId] = useState('');
const [availability, setAvailability] = useState<RealtimeLoadAvailability>('enabled');
const [modelType, setModelType] = useState(''); const [modelType, setModelType] = useState('');
const [runtimeState, setRuntimeState] = useState(''); const [runtimeState, setRuntimeState] = useState('');
const [sortField, setSortField] = useState<RealtimeLoadSortField>('load'); const [sortField, setSortField] = useState<RealtimeLoadSortField>('load');
@@ -33,21 +34,22 @@ export function RealtimeLoadPanel(props: {
() => filterAndSortRealtimeLoad(props.modelRateLimits, platformMap, { () => filterAndSortRealtimeLoad(props.modelRateLimits, platformMap, {
query, query,
platformId, platformId,
availability,
modelType, modelType,
runtimeState, runtimeState,
sortField, sortField,
sortDirection, sortDirection,
now, now,
}), }),
[modelType, now, platformId, platformMap, props.modelRateLimits, query, runtimeState, sortDirection, sortField], [availability, modelType, now, platformId, platformMap, props.modelRateLimits, query, runtimeState, sortDirection, sortField],
); );
const hasActiveFilters = Boolean(query || platformId || modelType || runtimeState); const hasActiveFilters = Boolean(query || platformId || modelType || runtimeState || availability !== 'all');
const advancedFilterCount = [ const advancedFilterCount = [
modelType, modelType,
runtimeState, runtimeState,
sortDirection === 'desc' ? '' : sortDirection, sortDirection === 'desc' ? '' : sortDirection,
].filter(Boolean).length; ].filter(Boolean).length;
const hasActiveSettings = Boolean(query || platformId || advancedFilterCount || sortField !== 'load'); const hasActiveSettings = Boolean(query || platformId || availability !== 'enabled' || advancedFilterCount || sortField !== 'load');
useEffect(() => { useEffect(() => {
const timer = window.setInterval(() => setNow(Date.now()), 1000); const timer = window.setInterval(() => setNow(Date.now()), 1000);
@@ -112,6 +114,7 @@ export function RealtimeLoadPanel(props: {
function resetFilters() { function resetFilters() {
setQuery(''); setQuery('');
setPlatformId(''); setPlatformId('');
setAvailability('enabled');
setModelType(''); setModelType('');
setRuntimeState(''); setRuntimeState('');
setSortField('load'); setSortField('load');
@@ -153,6 +156,15 @@ export function RealtimeLoadPanel(props: {
<option value="rpm">RPM</option> <option value="rpm">RPM</option>
<option value="priority"></option> <option value="priority"></option>
</Select> </Select>
<Select
aria-label="启用状态筛选"
value={availability}
onChange={(event) => setAvailability(event.target.value as RealtimeLoadAvailability)}
>
<option value="enabled"></option>
<option value="all"></option>
<option value="disabled"></option>
</Select>
<div className="compactAdminToolbarActions"> <div className="compactAdminToolbarActions">
<Button type="button" variant="outline" size="sm" onClick={() => setFilterDialogOpen(true)}> <Button type="button" variant="outline" size="sm" onClick={() => setFilterDialogOpen(true)}>
<SlidersHorizontal size={14} /> <SlidersHorizontal size={14} />
@@ -422,6 +434,7 @@ export function filterAndSortRealtimeLoad(
options: { options: {
query: string; query: string;
platformId: string; platformId: string;
availability: RealtimeLoadAvailability;
modelType: string; modelType: string;
runtimeState: string; runtimeState: string;
sortField: RealtimeLoadSortField; sortField: RealtimeLoadSortField;
@@ -447,6 +460,8 @@ export function filterAndSortRealtimeLoad(
const cooling = cooldownRemainingMs(status.modelCooldownUntil, options.now) > 0 || const cooling = cooldownRemainingMs(status.modelCooldownUntil, options.now) > 0 ||
cooldownRemainingMs(status.platformCooldownUntil, options.now) > 0; cooldownRemainingMs(status.platformCooldownUntil, options.now) > 0;
const disabled = !status.enabled || status.platformStatus !== 'enabled'; const disabled = !status.enabled || status.platformStatus !== 'enabled';
const matchesAvailability = options.availability === 'all' ||
(options.availability === 'disabled' ? disabled : !disabled);
const queuedTasks = admissionQueueDepth(status); const queuedTasks = admissionQueueDepth(status);
const matchesRuntime = !options.runtimeState || const matchesRuntime = !options.runtimeState ||
(options.runtimeState === 'high' && status.loadRatio >= 0.8) || (options.runtimeState === 'high' && status.loadRatio >= 0.8) ||
@@ -456,6 +471,7 @@ export function filterAndSortRealtimeLoad(
return (!keyword || text.includes(keyword)) && return (!keyword || text.includes(keyword)) &&
(!options.platformId || status.platformId === options.platformId) && (!options.platformId || status.platformId === options.platformId) &&
(!options.modelType || status.modelType.includes(options.modelType)) && (!options.modelType || status.modelType.includes(options.modelType)) &&
matchesAvailability &&
matchesRuntime; matchesRuntime;
}); });
const direction = options.sortDirection === 'asc' ? 1 : -1; const direction = options.sortDirection === 'asc' ? 1 : -1;
@@ -466,6 +482,8 @@ export function filterAndSortRealtimeLoad(
}); });
} }
export type RealtimeLoadAvailability = 'enabled' | 'disabled' | 'all';
function realtimeLoadSortValue(status: ModelRateLimitStatus, field: RealtimeLoadSortField) { function realtimeLoadSortValue(status: ModelRateLimitStatus, field: RealtimeLoadSortField) {
if (field === 'queued') return admissionQueueDepth(status); if (field === 'queued') return admissionQueueDepth(status);
if (field === 'concurrent') return status.concurrent.currentValue; if (field === 'concurrent') return status.concurrent.currentValue;