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:
Erman HAVUÇ
2026-05-26 01:54:24 +03:00
committed by GitHub
parent ceee53576b
commit 684d55f4aa
16 changed files with 57 additions and 7 deletions
+8 -4
View File
@@ -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">
+1
View File
@@ -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} 用量',
+3
View File
@@ -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
+9
View File
@@ -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);
} }