feat(usage): add toggle to hide prediction rows on usage cards (#1420)
* feat(usage): add showPredValues setting to quota store * feat(usage): register usageShowPredValues in settings sanitizers * feat(usage): add i18n key for show predictions toggle * feat(usage): add show predictions toggle to sidebar * feat(usage): hide pred row by default, gate on showPredValues * fix(usage): gate header dropdown PaceIndicator behind showPredValues * fix(usage): gate VSCodeLayout PaceIndicator behind showPredValues * fix(usage): correct indentation drift in Header.tsx PaceIndicator blocks
This commit is contained in:
@@ -263,6 +263,7 @@ type DesktopServicesMenuProps = {
|
|||||||
showDevShutdown: boolean;
|
showDevShutdown: boolean;
|
||||||
isDevShutdownInFlight: boolean;
|
isDevShutdownInFlight: boolean;
|
||||||
onDevShutdown: () => Promise<void>;
|
onDevShutdown: () => Promise<void>;
|
||||||
|
showPredValues: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
|
const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
|
||||||
@@ -292,6 +293,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
|
|||||||
showDevShutdown,
|
showDevShutdown,
|
||||||
isDevShutdownInFlight,
|
isDevShutdownInFlight,
|
||||||
onDevShutdown,
|
onDevShutdown,
|
||||||
|
showPredValues,
|
||||||
}: DesktopServicesMenuProps) {
|
}: DesktopServicesMenuProps) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
return (
|
return (
|
||||||
@@ -468,7 +470,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
|
|||||||
className="h-1.5"
|
className="h-1.5"
|
||||||
expectedMarkerPercent={expectedMarker}
|
expectedMarkerPercent={expectedMarker}
|
||||||
/>
|
/>
|
||||||
{paceInfo ? <PaceIndicator paceInfo={paceInfo} compact /> : null}
|
{paceInfo && showPredValues ? <PaceIndicator paceInfo={paceInfo} compact /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -512,7 +514,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
|
|||||||
className="h-1.5"
|
className="h-1.5"
|
||||||
expectedMarkerPercent={expectedMarker}
|
expectedMarkerPercent={expectedMarker}
|
||||||
/>
|
/>
|
||||||
{paceInfo ? <PaceIndicator paceInfo={paceInfo} compact /> : null}
|
{paceInfo && showPredValues ? <PaceIndicator paceInfo={paceInfo} compact /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -701,6 +703,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
const isQuotaLoading = useQuotaStore((state) => state.isLoading);
|
const isQuotaLoading = useQuotaStore((state) => state.isLoading);
|
||||||
const quotaLastUpdated = useQuotaStore((state) => state.lastUpdated);
|
const quotaLastUpdated = useQuotaStore((state) => state.lastUpdated);
|
||||||
const quotaDisplayMode = useQuotaStore((state) => state.displayMode);
|
const quotaDisplayMode = useQuotaStore((state) => state.displayMode);
|
||||||
|
const showPredValues = useQuotaStore((state) => state.showPredValues);
|
||||||
const dropdownProviderIds = useQuotaStore((state) => state.dropdownProviderIds);
|
const dropdownProviderIds = useQuotaStore((state) => state.dropdownProviderIds);
|
||||||
const loadQuotaSettings = useQuotaStore((state) => state.loadSettings);
|
const loadQuotaSettings = useQuotaStore((state) => state.loadSettings);
|
||||||
const setQuotaDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
const setQuotaDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
||||||
@@ -1820,6 +1823,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
servicesTabItems={servicesTabItems}
|
servicesTabItems={servicesTabItems}
|
||||||
quotaLastUpdated={quotaLastUpdated}
|
quotaLastUpdated={quotaLastUpdated}
|
||||||
quotaDisplayMode={quotaDisplayMode}
|
quotaDisplayMode={quotaDisplayMode}
|
||||||
|
showPredValues={showPredValues}
|
||||||
quotaDisplayTabItems={quotaDisplayTabItems}
|
quotaDisplayTabItems={quotaDisplayTabItems}
|
||||||
handleDisplayModeChange={handleDisplayModeChange}
|
handleDisplayModeChange={handleDisplayModeChange}
|
||||||
handleUsageRefresh={handleUsageRefresh}
|
handleUsageRefresh={handleUsageRefresh}
|
||||||
@@ -2288,7 +2292,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
className="h-1.5"
|
className="h-1.5"
|
||||||
expectedMarkerPercent={expectedMarker}
|
expectedMarkerPercent={expectedMarker}
|
||||||
/>
|
/>
|
||||||
{paceInfo ? (
|
{paceInfo && showPredValues ? (
|
||||||
<PaceIndicator paceInfo={paceInfo} compact />
|
<PaceIndicator paceInfo={paceInfo} compact />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -2345,7 +2349,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
className="h-1.5"
|
className="h-1.5"
|
||||||
expectedMarkerPercent={expectedMarker}
|
expectedMarkerPercent={expectedMarker}
|
||||||
/>
|
/>
|
||||||
{paceInfo ? (
|
{paceInfo && showPredValues ? (
|
||||||
<PaceIndicator paceInfo={paceInfo} compact />
|
<PaceIndicator paceInfo={paceInfo} compact />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -582,6 +582,7 @@ const VSCodeHeader: React.FC<VSCodeHeaderProps> = ({ title, showBack, onBack, on
|
|||||||
const isQuotaLoading = useQuotaStore((state) => state.isLoading);
|
const isQuotaLoading = useQuotaStore((state) => state.isLoading);
|
||||||
const quotaLastUpdated = useQuotaStore((state) => state.lastUpdated);
|
const quotaLastUpdated = useQuotaStore((state) => state.lastUpdated);
|
||||||
const quotaDisplayMode = useQuotaStore((state) => state.displayMode);
|
const quotaDisplayMode = useQuotaStore((state) => state.displayMode);
|
||||||
|
const showPredValues = useQuotaStore((state) => state.showPredValues);
|
||||||
const dropdownProviderIds = useQuotaStore((state) => state.dropdownProviderIds);
|
const dropdownProviderIds = useQuotaStore((state) => state.dropdownProviderIds);
|
||||||
const loadQuotaSettings = useQuotaStore((state) => state.loadSettings);
|
const loadQuotaSettings = useQuotaStore((state) => state.loadSettings);
|
||||||
const setQuotaDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
const setQuotaDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
||||||
@@ -892,7 +893,7 @@ const VSCodeHeader: React.FC<VSCodeHeaderProps> = ({ title, showBack, onBack, on
|
|||||||
className="h-1"
|
className="h-1"
|
||||||
expectedMarkerPercent={expectedMarker}
|
expectedMarkerPercent={expectedMarker}
|
||||||
/>
|
/>
|
||||||
{paceInfo && (
|
{paceInfo && showPredValues && (
|
||||||
<div className="mt-0.5">
|
<div className="mt-0.5">
|
||||||
<PaceIndicator paceInfo={paceInfo} compact />
|
<PaceIndicator paceInfo={paceInfo} compact />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const UsageCard: React.FC<UsageCardProps> = ({
|
|||||||
onToggle,
|
onToggle,
|
||||||
}) => {
|
}) => {
|
||||||
const displayMode = useQuotaStore((state) => state.displayMode);
|
const displayMode = useQuotaStore((state) => state.displayMode);
|
||||||
|
const showPredValues = useQuotaStore((state) => state.showPredValues);
|
||||||
const displayPercent = displayMode === 'remaining' ? window.remainingPercent : window.usedPercent;
|
const displayPercent = displayMode === 'remaining' ? window.remainingPercent : window.usedPercent;
|
||||||
const barLabel = displayMode === 'remaining' ? 'remaining' : 'used';
|
const barLabel = displayMode === 'remaining' ? 'remaining' : 'used';
|
||||||
const percentLabel = formatQuotaValueLabel(window.valueLabel, displayPercent);
|
const percentLabel = formatQuotaValueLabel(window.valueLabel, displayPercent);
|
||||||
@@ -82,7 +83,7 @@ export const UsageCard: React.FC<UsageCardProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{paceInfo && (
|
{paceInfo && showPredValues && (
|
||||||
<div className="mt-1.5">
|
<div className="mt-1.5">
|
||||||
<PaceIndicator paceInfo={paceInfo} />
|
<PaceIndicator paceInfo={paceInfo} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,13 +40,15 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
|
|||||||
const setUsageAutoRefresh = useQuotaStore((state) => state.setAutoRefresh);
|
const setUsageAutoRefresh = useQuotaStore((state) => state.setAutoRefresh);
|
||||||
const setUsageRefreshInterval = useQuotaStore((state) => state.setRefreshInterval);
|
const setUsageRefreshInterval = useQuotaStore((state) => state.setRefreshInterval);
|
||||||
const setUsageDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
const setUsageDisplayMode = useQuotaStore((state) => state.setDisplayMode);
|
||||||
|
const showPredValues = useQuotaStore((state) => state.showPredValues);
|
||||||
|
const setShowPredValues = useQuotaStore((state) => state.setShowPredValues);
|
||||||
const loadUsageSettings = useQuotaStore((state) => state.loadSettings);
|
const loadUsageSettings = useQuotaStore((state) => state.loadSettings);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
void loadUsageSettings();
|
void loadUsageSettings();
|
||||||
}, [loadUsageSettings]);
|
}, [loadUsageSettings]);
|
||||||
|
|
||||||
const persistUsageSettings = React.useCallback(async (changes: { usageAutoRefresh?: boolean; usageRefreshIntervalMs?: number; usageDisplayMode?: 'usage' | 'remaining'; usageDropdownProviders?: string[] }) => {
|
const persistUsageSettings = React.useCallback(async (changes: { usageAutoRefresh?: boolean; usageRefreshIntervalMs?: number; usageDisplayMode?: 'usage' | 'remaining'; usageDropdownProviders?: string[]; usageShowPredValues?: boolean }) => {
|
||||||
try {
|
try {
|
||||||
await updateDesktopSettings(changes);
|
await updateDesktopSettings(changes);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -76,6 +78,11 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
|
|||||||
void persistUsageSettings({ usageDisplayMode: value });
|
void persistUsageSettings({ usageDisplayMode: value });
|
||||||
}, [persistUsageSettings, setUsageDisplayMode]);
|
}, [persistUsageSettings, setUsageDisplayMode]);
|
||||||
|
|
||||||
|
const handleShowPredValuesChange = React.useCallback((enabled: boolean) => {
|
||||||
|
setShowPredValues(enabled);
|
||||||
|
void persistUsageSettings({ usageShowPredValues: enabled });
|
||||||
|
}, [persistUsageSettings, setShowPredValues]);
|
||||||
|
|
||||||
const bgClass = 'bg-background';
|
const bgClass = 'bg-background';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -137,6 +144,16 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 flex items-center justify-between gap-2">
|
||||||
|
<span className="typography-micro text-muted-foreground">
|
||||||
|
{t('settings.usage.sidebar.field.showPredictions')}
|
||||||
|
</span>
|
||||||
|
<Checkbox
|
||||||
|
checked={showPredValues}
|
||||||
|
onChange={handleShowPredValuesChange}
|
||||||
|
ariaLabel={t('settings.usage.sidebar.field.showPredictions')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ScrollableOverlay outerClassName="flex-1 min-h-0" className="space-y-1 px-3 py-2 overflow-x-hidden">
|
<ScrollableOverlay outerClassName="flex-1 min-h-0" className="space-y-1 px-3 py-2 overflow-x-hidden">
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ export type DesktopSettings = {
|
|||||||
usageAutoRefresh?: boolean;
|
usageAutoRefresh?: boolean;
|
||||||
usageRefreshIntervalMs?: number;
|
usageRefreshIntervalMs?: number;
|
||||||
usageDisplayMode?: 'usage' | 'remaining';
|
usageDisplayMode?: 'usage' | 'remaining';
|
||||||
|
usageShowPredValues?: boolean;
|
||||||
usageDropdownProviders?: string[];
|
usageDropdownProviders?: string[];
|
||||||
usageSelectedModels?: Record<string, string[]>; // Map of providerId -> selected model names
|
usageSelectedModels?: Record<string, string[]>; // Map of providerId -> selected model names
|
||||||
usageCollapsedFamilies?: Record<string, string[]>; // Map of providerId -> collapsed family IDs (UsagePage)
|
usageCollapsedFamilies?: Record<string, string[]>; // Map of providerId -> collapsed family IDs (UsagePage)
|
||||||
|
|||||||
@@ -945,6 +945,7 @@ export const settingsDict = {
|
|||||||
'settings.usage.sidebar.field.displayModePlaceholder': 'Display mode',
|
'settings.usage.sidebar.field.displayModePlaceholder': 'Display mode',
|
||||||
'settings.usage.sidebar.field.displayModeUsage': 'Usage',
|
'settings.usage.sidebar.field.displayModeUsage': 'Usage',
|
||||||
'settings.usage.sidebar.field.displayModeRemaining': 'Quota remaining',
|
'settings.usage.sidebar.field.displayModeRemaining': 'Quota remaining',
|
||||||
|
'settings.usage.sidebar.field.showPredictions': 'Show predictions',
|
||||||
'settings.usage.sidebar.status.notSet': 'Not set',
|
'settings.usage.sidebar.status.notSet': 'Not set',
|
||||||
'settings.usage.page.empty.selectProvider': 'Select a provider to view usage details.',
|
'settings.usage.page.empty.selectProvider': 'Select a provider to view usage details.',
|
||||||
'settings.usage.page.header.providerUsage': '{provider} Usage',
|
'settings.usage.page.header.providerUsage': '{provider} Usage',
|
||||||
|
|||||||
@@ -912,6 +912,7 @@ export const settingsDict = {
|
|||||||
"settings.usage.sidebar.field.displayModePlaceholder": "Modo de visualización",
|
"settings.usage.sidebar.field.displayModePlaceholder": "Modo de visualización",
|
||||||
"settings.usage.sidebar.field.displayModeUsage": "Uso",
|
"settings.usage.sidebar.field.displayModeUsage": "Uso",
|
||||||
"settings.usage.sidebar.field.displayModeRemaining": "Cuota restante",
|
"settings.usage.sidebar.field.displayModeRemaining": "Cuota restante",
|
||||||
|
"settings.usage.sidebar.field.showPredictions": "Mostrar predicciones",
|
||||||
"settings.usage.sidebar.status.notSet": "No establecido",
|
"settings.usage.sidebar.status.notSet": "No establecido",
|
||||||
"settings.usage.page.empty.selectProvider": "Selecciona un proveedor para ver detalles de uso.",
|
"settings.usage.page.empty.selectProvider": "Selecciona un proveedor para ver detalles de uso.",
|
||||||
"settings.usage.page.header.providerUsage": "Uso de {provider}",
|
"settings.usage.page.header.providerUsage": "Uso de {provider}",
|
||||||
|
|||||||
@@ -912,6 +912,7 @@ export const settingsDict = {
|
|||||||
'settings.usage.sidebar.field.displayModePlaceholder': '표시 모드',
|
'settings.usage.sidebar.field.displayModePlaceholder': '표시 모드',
|
||||||
'settings.usage.sidebar.field.displayModeUsage': '사용량',
|
'settings.usage.sidebar.field.displayModeUsage': '사용량',
|
||||||
'settings.usage.sidebar.field.displayModeRemaining': '남은 할당량',
|
'settings.usage.sidebar.field.displayModeRemaining': '남은 할당량',
|
||||||
|
'settings.usage.sidebar.field.showPredictions': '예측 표시',
|
||||||
'settings.usage.sidebar.status.notSet': '설정 안 됨',
|
'settings.usage.sidebar.status.notSet': '설정 안 됨',
|
||||||
'settings.usage.page.empty.selectProvider': '사용량 세부 정보를 보려면 프로바이더를 선택하세요.',
|
'settings.usage.page.empty.selectProvider': '사용량 세부 정보를 보려면 프로바이더를 선택하세요.',
|
||||||
'settings.usage.page.header.providerUsage': '{provider} 사용량',
|
'settings.usage.page.header.providerUsage': '{provider} 사용량',
|
||||||
|
|||||||
@@ -1597,6 +1597,7 @@ export const settingsDict = {
|
|||||||
'settings.usage.sidebar.field.display': 'Wyświetlanie',
|
'settings.usage.sidebar.field.display': 'Wyświetlanie',
|
||||||
'settings.usage.sidebar.field.displayModePlaceholder': 'Tryb wyświetlania',
|
'settings.usage.sidebar.field.displayModePlaceholder': 'Tryb wyświetlania',
|
||||||
'settings.usage.sidebar.field.displayModeRemaining': 'Pozostała kwota',
|
'settings.usage.sidebar.field.displayModeRemaining': 'Pozostała kwota',
|
||||||
|
'settings.usage.sidebar.field.showPredictions': 'Pokaż prognozy',
|
||||||
'settings.usage.sidebar.field.displayModeUsage': 'Użycie',
|
'settings.usage.sidebar.field.displayModeUsage': 'Użycie',
|
||||||
'settings.usage.sidebar.field.intervalPlaceholder': 'Interwał',
|
'settings.usage.sidebar.field.intervalPlaceholder': 'Interwał',
|
||||||
'settings.usage.sidebar.status.notSet': 'Nie ustawiono',
|
'settings.usage.sidebar.status.notSet': 'Nie ustawiono',
|
||||||
|
|||||||
@@ -912,6 +912,7 @@ export const settingsDict = {
|
|||||||
"settings.usage.sidebar.field.displayModePlaceholder": "Modo de visualização",
|
"settings.usage.sidebar.field.displayModePlaceholder": "Modo de visualização",
|
||||||
"settings.usage.sidebar.field.displayModeUsage": "Uso",
|
"settings.usage.sidebar.field.displayModeUsage": "Uso",
|
||||||
"settings.usage.sidebar.field.displayModeRemaining": "Cota restante",
|
"settings.usage.sidebar.field.displayModeRemaining": "Cota restante",
|
||||||
|
"settings.usage.sidebar.field.showPredictions": "Mostrar previsões",
|
||||||
"settings.usage.sidebar.status.notSet": "Não definido",
|
"settings.usage.sidebar.status.notSet": "Não definido",
|
||||||
"settings.usage.page.empty.selectProvider": "Selecione um provedor para ver detalhes de uso.",
|
"settings.usage.page.empty.selectProvider": "Selecione um provedor para ver detalhes de uso.",
|
||||||
"settings.usage.page.header.providerUsage": "Uso de {provider}",
|
"settings.usage.page.header.providerUsage": "Uso de {provider}",
|
||||||
|
|||||||
@@ -912,6 +912,7 @@ export const settingsDict = {
|
|||||||
"settings.usage.sidebar.field.displayModePlaceholder": "Режим відображення",
|
"settings.usage.sidebar.field.displayModePlaceholder": "Режим відображення",
|
||||||
"settings.usage.sidebar.field.displayModeUsage": "Використання",
|
"settings.usage.sidebar.field.displayModeUsage": "Використання",
|
||||||
"settings.usage.sidebar.field.displayModeRemaining": "Залишок квоти",
|
"settings.usage.sidebar.field.displayModeRemaining": "Залишок квоти",
|
||||||
|
"settings.usage.sidebar.field.showPredictions": "Показувати прогнози",
|
||||||
"settings.usage.sidebar.status.notSet": "Не встановлено",
|
"settings.usage.sidebar.status.notSet": "Не встановлено",
|
||||||
"settings.usage.page.empty.selectProvider": "Виберіть провайдера, щоб переглянути деталі використання.",
|
"settings.usage.page.empty.selectProvider": "Виберіть провайдера, щоб переглянути деталі використання.",
|
||||||
"settings.usage.page.header.providerUsage": "Використання {provider}",
|
"settings.usage.page.header.providerUsage": "Використання {provider}",
|
||||||
|
|||||||
@@ -912,6 +912,7 @@ export const settingsDict = {
|
|||||||
'settings.usage.sidebar.field.displayModePlaceholder': '显示模式',
|
'settings.usage.sidebar.field.displayModePlaceholder': '显示模式',
|
||||||
'settings.usage.sidebar.field.displayModeUsage': '用量',
|
'settings.usage.sidebar.field.displayModeUsage': '用量',
|
||||||
'settings.usage.sidebar.field.displayModeRemaining': '剩余配额',
|
'settings.usage.sidebar.field.displayModeRemaining': '剩余配额',
|
||||||
|
'settings.usage.sidebar.field.showPredictions': '显示预测',
|
||||||
'settings.usage.sidebar.status.notSet': '未设置',
|
'settings.usage.sidebar.status.notSet': '未设置',
|
||||||
'settings.usage.page.empty.selectProvider': '选择一个提供商以查看用量详情。',
|
'settings.usage.page.empty.selectProvider': '选择一个提供商以查看用量详情。',
|
||||||
'settings.usage.page.header.providerUsage': '{provider} 用量',
|
'settings.usage.page.header.providerUsage': '{provider} 用量',
|
||||||
|
|||||||
@@ -790,6 +790,9 @@ const sanitizeWebSettings = (payload: unknown): DesktopSettings | null => {
|
|||||||
if (candidate.usageDisplayMode === 'usage' || candidate.usageDisplayMode === 'remaining') {
|
if (candidate.usageDisplayMode === 'usage' || candidate.usageDisplayMode === 'remaining') {
|
||||||
result.usageDisplayMode = candidate.usageDisplayMode;
|
result.usageDisplayMode = candidate.usageDisplayMode;
|
||||||
}
|
}
|
||||||
|
if (typeof candidate.usageShowPredValues === 'boolean') {
|
||||||
|
result.usageShowPredValues = candidate.usageShowPredValues;
|
||||||
|
}
|
||||||
if (Array.isArray(candidate.usageDropdownProviders)) {
|
if (Array.isArray(candidate.usageDropdownProviders)) {
|
||||||
result.usageDropdownProviders = candidate.usageDropdownProviders.filter(
|
result.usageDropdownProviders = candidate.usageDropdownProviders.filter(
|
||||||
(entry): entry is string => typeof entry === 'string' && entry.length > 0
|
(entry): entry is string => typeof entry === 'string' && entry.length > 0
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ interface QuotaSettingsState {
|
|||||||
autoRefresh: boolean;
|
autoRefresh: boolean;
|
||||||
refreshIntervalMs: number;
|
refreshIntervalMs: number;
|
||||||
displayMode: 'usage' | 'remaining';
|
displayMode: 'usage' | 'remaining';
|
||||||
|
showPredValues: boolean;
|
||||||
dropdownProviderIds: QuotaProviderId[];
|
dropdownProviderIds: QuotaProviderId[];
|
||||||
selectedModels: Record<string, string[]>; // Map of providerId -> selected model names
|
selectedModels: Record<string, string[]>; // Map of providerId -> selected model names
|
||||||
expandedFamilies: Record<string, string[]>; // Map of providerId -> EXPANDED family IDs (header dropdown - inverted)
|
expandedFamilies: Record<string, string[]>; // Map of providerId -> EXPANDED family IDs (header dropdown - inverted)
|
||||||
@@ -34,6 +35,7 @@ interface QuotaStore extends QuotaSettingsState {
|
|||||||
setAutoRefresh: (enabled: boolean) => void;
|
setAutoRefresh: (enabled: boolean) => void;
|
||||||
setRefreshInterval: (intervalMs: number) => void;
|
setRefreshInterval: (intervalMs: number) => void;
|
||||||
setDisplayMode: (mode: 'usage' | 'remaining') => void;
|
setDisplayMode: (mode: 'usage' | 'remaining') => void;
|
||||||
|
setShowPredValues: (enabled: boolean) => void;
|
||||||
setDropdownProviderIds: (providerIds: QuotaProviderId[]) => void;
|
setDropdownProviderIds: (providerIds: QuotaProviderId[]) => void;
|
||||||
setSelectedModels: (providerId: string, modelNames: string[]) => void;
|
setSelectedModels: (providerId: string, modelNames: string[]) => void;
|
||||||
toggleModelSelected: (providerId: string, modelName: string) => void;
|
toggleModelSelected: (providerId: string, modelName: string) => void;
|
||||||
@@ -53,6 +55,9 @@ const parseSettings = (data: Record<string, unknown> | null): QuotaSettingsState
|
|||||||
: DEFAULT_REFRESH_INTERVAL_MS;
|
: DEFAULT_REFRESH_INTERVAL_MS;
|
||||||
|
|
||||||
const displayMode = data?.usageDisplayMode === 'remaining' ? 'remaining' : 'usage';
|
const displayMode = data?.usageDisplayMode === 'remaining' ? 'remaining' : 'usage';
|
||||||
|
const showPredValues = typeof data?.usageShowPredValues === 'boolean'
|
||||||
|
? data.usageShowPredValues
|
||||||
|
: false;
|
||||||
const rawDropdownProviders = Array.isArray(data?.usageDropdownProviders)
|
const rawDropdownProviders = Array.isArray(data?.usageDropdownProviders)
|
||||||
? data?.usageDropdownProviders
|
? data?.usageDropdownProviders
|
||||||
: null;
|
: null;
|
||||||
@@ -88,6 +93,7 @@ const parseSettings = (data: Record<string, unknown> | null): QuotaSettingsState
|
|||||||
autoRefresh,
|
autoRefresh,
|
||||||
refreshIntervalMs,
|
refreshIntervalMs,
|
||||||
displayMode,
|
displayMode,
|
||||||
|
showPredValues,
|
||||||
dropdownProviderIds,
|
dropdownProviderIds,
|
||||||
selectedModels,
|
selectedModels,
|
||||||
expandedFamilies,
|
expandedFamilies,
|
||||||
@@ -121,6 +127,7 @@ const loadSettingsFromRuntime = async (): Promise<QuotaSettingsState> => {
|
|||||||
autoRefresh: false,
|
autoRefresh: false,
|
||||||
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
||||||
displayMode: 'usage',
|
displayMode: 'usage',
|
||||||
|
showPredValues: false,
|
||||||
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id),
|
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id),
|
||||||
selectedModels: {},
|
selectedModels: {},
|
||||||
expandedFamilies: {},
|
expandedFamilies: {},
|
||||||
@@ -139,6 +146,7 @@ export const useQuotaStore = create<QuotaStore>()(
|
|||||||
autoRefresh: false,
|
autoRefresh: false,
|
||||||
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
||||||
displayMode: 'usage',
|
displayMode: 'usage',
|
||||||
|
showPredValues: false,
|
||||||
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id),
|
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id),
|
||||||
selectedModels: {},
|
selectedModels: {},
|
||||||
expandedFamilies: {},
|
expandedFamilies: {},
|
||||||
@@ -216,6 +224,7 @@ export const useQuotaStore = create<QuotaStore>()(
|
|||||||
set({ refreshIntervalMs: clamped });
|
set({ refreshIntervalMs: clamped });
|
||||||
},
|
},
|
||||||
setDisplayMode: (mode) => set({ displayMode: mode }),
|
setDisplayMode: (mode) => set({ displayMode: mode }),
|
||||||
|
setShowPredValues: (enabled) => set({ showPredValues: enabled }),
|
||||||
setDropdownProviderIds: (providerIds) => set({ dropdownProviderIds: providerIds }),
|
setDropdownProviderIds: (providerIds) => set({ dropdownProviderIds: providerIds }),
|
||||||
|
|
||||||
setSelectedModels: (providerId, modelNames) => {
|
setSelectedModels: (providerId, modelNames) => {
|
||||||
|
|||||||
@@ -303,6 +303,10 @@ export const persistSettings = async (changes: Record<string, unknown>, ctx?: Br
|
|||||||
delete restChanges.usageAutoRefresh;
|
delete restChanges.usageAutoRefresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof restChanges.usageShowPredValues !== 'boolean') {
|
||||||
|
delete restChanges.usageShowPredValues;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof restChanges.usageRefreshIntervalMs === 'number' && Number.isFinite(restChanges.usageRefreshIntervalMs)) {
|
if (typeof restChanges.usageRefreshIntervalMs === 'number' && Number.isFinite(restChanges.usageRefreshIntervalMs)) {
|
||||||
restChanges.usageRefreshIntervalMs = Math.max(30000, Math.min(300000, Math.round(restChanges.usageRefreshIntervalMs)));
|
restChanges.usageRefreshIntervalMs = Math.max(30000, Math.min(300000, Math.round(restChanges.usageRefreshIntervalMs)));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -225,6 +225,9 @@ export const createSettingsHelpers = (dependencies) => {
|
|||||||
if (candidate.usageDisplayMode === 'usage' || candidate.usageDisplayMode === 'remaining') {
|
if (candidate.usageDisplayMode === 'usage' || candidate.usageDisplayMode === 'remaining') {
|
||||||
result.usageDisplayMode = candidate.usageDisplayMode;
|
result.usageDisplayMode = candidate.usageDisplayMode;
|
||||||
}
|
}
|
||||||
|
if (typeof candidate.usageShowPredValues === 'boolean') {
|
||||||
|
result.usageShowPredValues = candidate.usageShowPredValues;
|
||||||
|
}
|
||||||
if (Array.isArray(candidate.usageDropdownProviders)) {
|
if (Array.isArray(candidate.usageDropdownProviders)) {
|
||||||
result.usageDropdownProviders = normalizeStringArray(candidate.usageDropdownProviders);
|
result.usageDropdownProviders = normalizeStringArray(candidate.usageDropdownProviders);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user