feat: Implement provider groupings with account calculator and compre… (#113)
* feat: Implement provider groupings with account calculator and comprehensive fixes - Add provider detection utilities (detectProvider, PROVIDER_REGISTRY) for Claude/Gemini/Others categorization - Implement grouping logic (groupModelsByProvider, calculateProviderStats, calculateAccountStats) with health status calculation - Create useProviderGrouping hook for collapsible state management and persistence - Add ProviderGroup component with health indicators, progress bars, and model visibility integration - Enhance CloudAccountList with account-level calculator showing overall percentage and earliest reset time - Implement grid layout selector (auto/2-col/3-col/list) with config persistence and tooltips - Add global quota aggregate bar across all accounts in top statistics - Fix model visibility settings regression by accessing account.quota.models instead of account.quota - Show 'Rate Limited' instead of '0%' for exhausted quotas with consistent getQuotaLabel function - Add comprehensive i18n translations for layout selector and rate limited labels (en, zh-CN, ru) - Disable batch operations when provider groupings are enabled to prevent conflicts - Include unit tests for provider detection logic and grouping functionality Addresses critical issues: model list regression, rate limited display, layout control, global quota visibility, and consistent quota labeling across all components. * fix: resolve ESLint no-ex-assign violations in proxy service - Fix exception parameter reassignment in catch blocks - Rename catch parameters to avoid no-ex-assign rule violations - Maintain same error handling logic while complying with linting rules * fix: add missing Models tab to settings page - Add Models tab between General and Proxy tabs - Import and integrate ModelVisibilitySettings component - Fix critical regression where model visibility settings were inaccessible * fix: add missing React hook imports in settings route * test: remove obsolete tests for removed controller APIs --------- Co-authored-by: Draculabo <[email protected]>
This commit is contained in:
1 parent
118fad567e
commit
1e59a1c901
12 files changed
+1237
-97
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
|
||||
import { useAppConfig } from '@/hooks/useAppConfig';
|
||||
import { CloudAccount } from '@/types/cloudAccount';
|
||||
import { groupModelsByProvider, type AccountStats } from '@/utils/provider-grouping';
|
||||
|
||||
export interface UseProviderGroupingResult {
|
||||
enabled: boolean;
|
||||
getAccountStats: (account: CloudAccount) => AccountStats;
|
||||
isProviderCollapsed: (accountId: string, providerKey: string) => boolean;
|
||||
toggleProviderCollapse: (accountId: string, providerKey: string) => void;
|
||||
isAccountCollapsed: (accountId: string) => boolean;
|
||||
toggleAccountCollapse: (accountId: string) => void;
|
||||
}
|
||||
|
||||
export function useProviderGrouping(): UseProviderGroupingResult {
|
||||
const { config } = useAppConfig();
|
||||
|
||||
// Collapse state is managed locally per session for responsive toggling.
|
||||
// Provider groups default to expanded on each page load.
|
||||
const [collapsedProviders, setCollapsedProviders] = useState<Record<string, string[]>>({});
|
||||
const [collapsedAccounts, setCollapsedAccounts] = useState<string[]>([]);
|
||||
|
||||
const enabled = config?.provider_groupings_enabled ?? false;
|
||||
const visibilitySettings = config?.model_visibility ?? {};
|
||||
|
||||
const getAccountStats = useCallback(
|
||||
(account: CloudAccount): AccountStats => {
|
||||
const models = account.quota?.models ?? {};
|
||||
return groupModelsByProvider(models, visibilitySettings);
|
||||
},
|
||||
[visibilitySettings],
|
||||
);
|
||||
|
||||
const isProviderCollapsed = useCallback(
|
||||
(accountId: string, providerKey: string): boolean => {
|
||||
return collapsedProviders[accountId]?.includes(providerKey) ?? false;
|
||||
},
|
||||
[collapsedProviders],
|
||||
);
|
||||
|
||||
const toggleProviderCollapse = useCallback((accountId: string, providerKey: string): void => {
|
||||
setCollapsedProviders((prev) => {
|
||||
const accountCollapsed = prev[accountId] ?? [];
|
||||
const isCollapsed = accountCollapsed.includes(providerKey);
|
||||
return {
|
||||
...prev,
|
||||
[accountId]: isCollapsed
|
||||
? accountCollapsed.filter((k) => k !== providerKey)
|
||||
: [...accountCollapsed, providerKey],
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
const isAccountCollapsed = useCallback(
|
||||
(accountId: string): boolean => {
|
||||
return collapsedAccounts.includes(accountId);
|
||||
},
|
||||
[collapsedAccounts],
|
||||
);
|
||||
|
||||
const toggleAccountCollapse = useCallback((accountId: string): void => {
|
||||
setCollapsedAccounts((prev) =>
|
||||
prev.includes(accountId) ? prev.filter((id) => id !== accountId) : [...prev, accountId],
|
||||
);
|
||||
}, []);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
enabled,
|
||||
getAccountStats,
|
||||
isProviderCollapsed,
|
||||
toggleProviderCollapse,
|
||||
isAccountCollapsed,
|
||||
toggleAccountCollapse,
|
||||
}),
|
||||
[
|
||||
enabled,
|
||||
getAccountStats,
|
||||
isProviderCollapsed,
|
||||
toggleProviderCollapse,
|
||||
isAccountCollapsed,
|
||||
toggleAccountCollapse,
|
||||
],
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user