Skip to content

Commit eca420c

Browse files
authored
Merge pull request #270 from cloudflare/fix/linting
Fix: Linting issues
2 parents 5869e41 + f908d31 commit eca420c

33 files changed

Lines changed: 242 additions & 196 deletions

File tree

src/components/byok-api-keys-modal.tsx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Tab 2: Manage existing keys with delete functionality
55
*/
66

7-
import { useState, useEffect } from 'react';
7+
import { useState, useEffect, useCallback } from 'react';
88
import { Key, Check, AlertCircle, Loader2, Plus, Settings, Trash2, Eye, Lock } from 'lucide-react';
99
import { Button } from '@/components/ui/button';
1010
import { Input } from '@/components/ui/input';
@@ -121,34 +121,7 @@ export function ByokApiKeysModal({ isOpen, onClose, onKeyAdded }: ByokApiKeysMod
121121
// Get selected provider details
122122
const provider = byokProviders.find((p) => p.id === selectedProvider);
123123

124-
// Load BYOK templates when modal opens
125-
useEffect(() => {
126-
if (isOpen) {
127-
// Reset add keys tab
128-
setSelectedProvider(null);
129-
setApiKey('');
130-
setIsSaving(false);
131-
132-
// Reset manage keys tab
133-
setDeleteDialogOpen(false);
134-
setSecretToDelete(null);
135-
setIsDeleting(false);
136-
137-
// Load data
138-
loadBYOKProviders();
139-
}
140-
}, [isOpen]);
141-
142-
// Load secrets when vault is unlocked
143-
useEffect(() => {
144-
if (isOpen && isUnlocked) {
145-
loadManagedSecrets();
146-
} else if (isOpen && !isUnlocked) {
147-
setManagedSecrets([]);
148-
}
149-
}, [isOpen, isUnlocked]);
150-
151-
const loadBYOKProviders = async () => {
124+
const loadBYOKProviders = useCallback(async () => {
152125
try {
153126
setIsLoading(true);
154127
const response = await apiClient.getBYOKTemplates();
@@ -165,9 +138,9 @@ export function ByokApiKeysModal({ isOpen, onClose, onKeyAdded }: ByokApiKeysMod
165138
} finally {
166139
setIsLoading(false);
167140
}
168-
};
141+
}, []);
169142

170-
const loadManagedSecrets = async () => {
143+
const loadManagedSecrets = useCallback(async () => {
171144
if (!isUnlocked) return;
172145

173146
try {
@@ -199,7 +172,34 @@ export function ByokApiKeysModal({ isOpen, onClose, onKeyAdded }: ByokApiKeysMod
199172
} finally {
200173
setLoadingSecrets(false);
201174
}
202-
};
175+
}, [isUnlocked, listSecrets]);
176+
177+
// Load BYOK templates when modal opens
178+
useEffect(() => {
179+
if (isOpen) {
180+
// Reset add keys tab
181+
setSelectedProvider(null);
182+
setApiKey('');
183+
setIsSaving(false);
184+
185+
// Reset manage keys tab
186+
setDeleteDialogOpen(false);
187+
setSecretToDelete(null);
188+
setIsDeleting(false);
189+
190+
// Load data
191+
loadBYOKProviders();
192+
}
193+
}, [isOpen, loadBYOKProviders]);
194+
195+
// Load secrets when vault is unlocked
196+
useEffect(() => {
197+
if (isOpen && isUnlocked) {
198+
loadManagedSecrets();
199+
} else if (isOpen && !isUnlocked) {
200+
setManagedSecrets([]);
201+
}
202+
}, [isOpen, isUnlocked, loadManagedSecrets]);
203203

204204
// Handle provider selection
205205
const handleProviderSelect = (providerId: string) => {

src/components/config-modal.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Three-mode interface: Platform Models, BYOK (Bring Your Own Key), Custom Providers
44
*/
55

6-
import { useState, useEffect, useMemo } from 'react';
6+
import { useState, useEffect, useMemo, useCallback } from 'react';
77
import { Settings, Play, RotateCcw, Info, Key } from 'lucide-react';
88
import { Button } from '@/components/ui/button';
99
import { Input } from '@/components/ui/input';
@@ -115,7 +115,7 @@ export function ConfigModal({
115115
const [loadingByok, setLoadingByok] = useState(false);
116116

117117
// Load BYOK data (filtered by agent constraints)
118-
const loadByokData = async () => {
118+
const loadByokData = useCallback(async () => {
119119
try {
120120
setLoadingByok(true);
121121
// Pass agent key to get constraint-filtered models
@@ -128,7 +128,7 @@ export function ConfigModal({
128128
} finally {
129129
setLoadingByok(false);
130130
}
131-
};
131+
}, [agentConfig.key]);
132132

133133
// Handle modal open/close lifecycle
134134
useEffect(() => {
@@ -148,7 +148,7 @@ export function ConfigModal({
148148
// Modal closed - reset for next time
149149
setIsInitialOpen(false);
150150
}
151-
}, [isOpen, isInitialOpen, userConfig]);
151+
}, [isOpen, isInitialOpen, userConfig, loadByokData]);
152152

153153
// Load BYOK data when modal opens
154154
useEffect(() => {

src/components/vault/VaultSetupWizard.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useMemo, useState } from 'react';
1+
import { useCallback, useEffect, useMemo, useState } from 'react';
22
import { useVault } from '@/hooks/use-vault';
33
import { Button } from '@/components/ui/button';
44
import { Input } from '@/components/ui/input';
@@ -33,21 +33,20 @@ export function VaultSetupWizard({ open, onComplete, onCancel }: Props) {
3333
const [error, setError] = useState<string | null>(null);
3434
const [isCreating, setIsCreating] = useState(false);
3535

36-
const resetState = () => {
36+
const resetState = useCallback(() => {
3737
setStep('setup');
3838
setMethod(null);
3939
setPassword('');
4040
setConfirmPassword('');
4141
setRecoveryCodes(null);
4242
setError(null);
4343
setIsCreating(false);
44-
};
44+
}, []);
4545

4646
useEffect(() => {
4747
if (!open) return;
4848
resetState();
49-
// eslint-disable-next-line react-hooks/exhaustive-deps
50-
}, [open]);
49+
}, [open, resetState]);
5150

5251
const passwordError = useMemo(() => {
5352
if (method !== 'password') return null;

src/contexts/auth-context.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,31 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
112112
}
113113
}, []);
114114

115+
// Setup automatic session validation (cookie-based)
116+
const setupTokenRefresh = useCallback(() => {
117+
// Clear any existing timer
118+
if (refreshTimerRef.current) {
119+
clearInterval(refreshTimerRef.current);
120+
}
121+
122+
// Set up session validation timer - less frequent since cookies handle refresh
123+
refreshTimerRef.current = setInterval(async () => {
124+
try {
125+
const response = await apiClient.getProfile(true);
126+
127+
if (!response.success) {
128+
// Session invalid, user needs to login again
129+
setUser(null);
130+
setToken(null);
131+
setSession(null);
132+
clearInterval(refreshTimerRef.current!);
133+
}
134+
} catch (error) {
135+
console.error('Session validation failed:', error);
136+
}
137+
}, TOKEN_REFRESH_INTERVAL);
138+
}, []);
139+
115140
// Check authentication status
116141
const checkAuth = useCallback(async () => {
117142
try {
@@ -142,32 +167,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
142167
} finally {
143168
setIsLoading(false);
144169
}
145-
}, []);
146-
147-
// Setup automatic session validation (cookie-based)
148-
const setupTokenRefresh = useCallback(() => {
149-
// Clear any existing timer
150-
if (refreshTimerRef.current) {
151-
clearInterval(refreshTimerRef.current);
152-
}
153-
154-
// Set up session validation timer - less frequent since cookies handle refresh
155-
refreshTimerRef.current = setInterval(async () => {
156-
try {
157-
const response = await apiClient.getProfile(true);
158-
159-
if (!response.success) {
160-
// Session invalid, user needs to login again
161-
setUser(null);
162-
setToken(null);
163-
setSession(null);
164-
clearInterval(refreshTimerRef.current!);
165-
}
166-
} catch (error) {
167-
console.error('Session validation failed:', error);
168-
}
169-
}, TOKEN_REFRESH_INTERVAL);
170-
}, []);
170+
}, [setupTokenRefresh]);
171171

172172
// Cleanup refresh timer on unmount
173173
useEffect(() => {

src/contexts/vault-context.tsx

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,22 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
155155
[]
156156
);
157157

158+
const unlockWithDerivedKey = useCallback(
159+
async (vmk: CryptoKey): Promise<void> => {
160+
const sessionKey = generateSessionKey();
161+
const encryptedVMK = await encryptVMKForSession(vmk, sessionKey);
162+
163+
const connected = await connectVaultWebSocket(encryptedVMK.ciphertext, encryptedVMK.nonce, sessionKey);
164+
if (!connected) {
165+
throw new Error('Failed to establish vault WebSocket connection');
166+
}
167+
168+
storeSession({ sessionKey });
169+
vmkRef.current = vmk;
170+
},
171+
[connectVaultWebSocket],
172+
);
173+
158174
// Fetch vault status
159175
const refreshStatus = useCallback(async () => {
160176
if (!isAuthenticated) {
@@ -276,9 +292,8 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
276292
setLoading(false);
277293
throw error;
278294
}
279-
280295
},
281-
[setLoading, setError]
296+
[setLoading, setError, unlockWithDerivedKey],
282297
);
283298

284299
// Setup with passkey (WebAuthn PRF)
@@ -381,24 +396,8 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
381396
setLoading(false);
382397
throw error;
383398
}
384-
}, [setLoading, setError, user]);
385-
386-
const unlockWithDerivedKey = async (vmk: CryptoKey): Promise<void> => {
387-
const sessionKey = generateSessionKey();
388-
const encryptedVMK = await encryptVMKForSession(vmk, sessionKey);
389-
390-
const connected = await connectVaultWebSocket(
391-
encryptedVMK.ciphertext,
392-
encryptedVMK.nonce,
393-
sessionKey
394-
);
395-
if (!connected) {
396-
throw new Error('Failed to establish vault WebSocket connection');
397-
}
399+
}, [setLoading, setError, unlockWithDerivedKey, user]);
398400

399-
storeSession({ sessionKey });
400-
vmkRef.current = vmk;
401-
};
402401

403402
// Unlock with password
404403
const unlockWithPassword = useCallback(
@@ -447,7 +446,7 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
447446
return { success: false, error: message };
448447
}
449448
},
450-
[setLoading, setError]
449+
[setLoading, setError, unlockWithDerivedKey]
451450
);
452451

453452
// Unlock with passkey
@@ -520,7 +519,7 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
520519
setLoading(false);
521520
return { success: false, error: message };
522521
}
523-
}, [setLoading, setError]);
522+
}, [setLoading, setError, unlockWithDerivedKey]);
524523

525524
// Unlock with recovery code
526525
const unlockWithRecoveryCode = useCallback(
@@ -569,7 +568,7 @@ export function VaultProvider({ children }: { children: React.ReactNode }) {
569568
return { success: false, error: message };
570569
}
571570
},
572-
[setLoading, setError]
571+
[setLoading, setError, unlockWithDerivedKey]
573572
);
574573

575574
const lockVault = useCallback(async (): Promise<void> => {

src/hooks/use-auto-scroll.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ export function useAutoScroll<T extends HTMLElement>(
3030

3131
// initial stick
3232
isAtBottomRef.current = true;
33-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
34-
// setTimeout(scrollToBottom, 0);
3533
Promise.resolve().then(scrollToBottom);
3634

3735
el.addEventListener('scroll', onScroll, { passive: true });

src/hooks/use-image-upload.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ export function useImageUpload(options: UseImageUploadOptions = {}): UseImageUpl
4545
return null;
4646
}
4747

48+
// Validate file size
49+
if (file.size > maxSizeBytes) {
50+
const maxSizeMB = (maxSizeBytes / (1024 * 1024)).toFixed(1);
51+
const fileSizeMB = (file.size / (1024 * 1024)).toFixed(1);
52+
const errorMsg = `Image too large: ${fileSizeMB}MB. Maximum allowed is ${maxSizeMB}MB.`;
53+
toast.error(errorMsg);
54+
onError?.(errorMsg);
55+
return null;
56+
}
57+
4858
return new Promise((resolve, reject) => {
4959
const reader = new FileReader();
5060

src/routes/apps/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ export default function AppsPage() {
113113
onValueChange={(v) => {
114114
handleSortChange(v);
115115
// Persist to URL and localStorage
116-
try { localStorage.setItem('apps.sort', v); } catch {}
116+
try { localStorage.setItem('apps.sort', v); } catch {
117+
console.error('Failed to persist sort to localStorage');
118+
}
117119
const next = new URLSearchParams(searchParams);
118120
next.set('sort', v);
119121
setSearchParams(next, { replace: true });

0 commit comments

Comments
 (0)