Fix focus and add timing information about request timing

This commit is contained in:
2025-08-26 08:23:50 +02:00
parent e5e4677a5e
commit 9dd2f02633

View File

@@ -12,6 +12,27 @@ import { Window } from '@tauri-apps/api/window';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { useTheme } from 'next-themes'; import { useTheme } from 'next-themes';
// Debug timing utility
const debugTiming = (operation: string, startTime: number) => {
const duration = Date.now() - startTime;
const message = `⏱️ ${operation}: ${duration}ms`;
console.log(message);
return duration;
};
// Enhanced fetch with timing
const fetchWithTiming = async (url: string, options: RequestInit, operation: string) => {
const startTime = Date.now();
try {
const response = await fetch(url, options);
debugTiming(operation, startTime);
return response;
} catch (error) {
debugTiming(`${operation} (FAILED)`, startTime);
throw error;
}
};
interface Note { interface Note {
id: string; id: string;
epochTime: number; epochTime: number;
@@ -72,9 +93,18 @@ const Index = () => {
const [isGotoOpen, setIsGotoOpen] = useState(false); const [isGotoOpen, setIsGotoOpen] = useState(false);
const [gotoDateInput, setGotoDateInput] = useState(''); const [gotoDateInput, setGotoDateInput] = useState('');
const [cacheMode, setCacheMode] = useState<'global' | 'scoped'>('global'); const [cacheMode, setCacheMode] = useState<'global' | 'scoped'>('global');
const [debugInfo, setDebugInfo] = useState<string[]>([]);
const [showDebugPanel, setShowDebugPanel] = useState(false);
const { resolvedTheme, setTheme } = useTheme(); const { resolvedTheme, setTheme } = useTheme();
// Debug logging function that updates UI state
const addDebugInfo = (message: string) => {
const timestamp = new Date().toLocaleTimeString();
const debugMessage = `[${timestamp}] ${message}`;
setDebugInfo(prev => [...prev.slice(-19), debugMessage]); // Keep last 20 messages
};
const previousNoteRef = useRef<HTMLDivElement>(null); const previousNoteRef = useRef<HTMLDivElement>(null);
const currentNoteRef = useRef<HTMLTextAreaElement>(null); const currentNoteRef = useRef<HTMLTextAreaElement>(null);
const scratchRef = useRef<HTMLTextAreaElement>(null); const scratchRef = useRef<HTMLTextAreaElement>(null);
@@ -281,14 +311,14 @@ const Index = () => {
letterCount: letterCount, letterCount: letterCount,
}; };
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(document), body: JSON.stringify(document),
}); }, 'Create Note');
if (response.status !== 202) { if (response.status !== 202) {
throw new Error('Failed to create note'); throw new Error('Failed to create note');
@@ -342,14 +372,14 @@ const Index = () => {
letterCount: letterCount, letterCount: letterCount,
}; };
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(document), body: JSON.stringify(document),
}); }, 'Update Note');
if (response.status !== 202) { if (response.status !== 202) {
throw new Error('Failed to update note'); throw new Error('Failed to update note');
@@ -375,12 +405,12 @@ const Index = () => {
// Delete a note // Delete a note
const deleteNote = async (id: string) => { const deleteNote = async (id: string) => {
try { try {
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents/${id}`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/documents/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
}); }, 'Delete Note');
if (response.status !== 202) { if (response.status !== 202) {
throw new Error('Failed to delete note'); throw new Error('Failed to delete note');
@@ -412,12 +442,14 @@ const Index = () => {
// Load notes from Meilisearch // Load notes from Meilisearch
const loadNotes = async (offset = 0, limit = 500) => { const loadNotes = async (offset = 0, limit = 500) => {
const loadStartTime = Date.now();
try { try {
setIsLoading(true); setIsLoading(true);
if (offset === 0) { if (offset === 0) {
setCacheMode('global'); setCacheMode('global');
addDebugInfo(`📝 Loading notes (offset: ${offset}, limit: ${limit})`);
} }
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -429,7 +461,7 @@ const Index = () => {
limit, limit,
sort: ['date:desc'], sort: ['date:desc'],
}), }),
}); }, 'Load Notes');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to load notes'); throw new Error('Failed to load notes');
@@ -444,11 +476,17 @@ const Index = () => {
setPreviousNote(notes[0]); setPreviousNote(notes[0]);
setCurrentNoteIndex(0); setCurrentNoteIndex(0);
} }
const loadTime = Date.now() - loadStartTime;
addDebugInfo(`✅ Loaded ${notes.length} notes in ${loadTime}ms`);
} else { } else {
setNoteCache(prev => [...prev, ...notes]); setNoteCache(prev => [...prev, ...notes]);
const loadTime = Date.now() - loadStartTime;
addDebugInfo(`✅ Loaded ${notes.length} additional notes in ${loadTime}ms`);
} }
} catch (error) { } catch (error) {
console.error('Error loading notes:', error); console.error('Error loading notes:', error);
const loadTime = Date.now() - loadStartTime;
addDebugInfo(`❌ Failed to load notes after ${loadTime}ms`);
toast({ toast({
title: "Error", title: "Error",
description: "Failed to load notes. Please check your connection.", description: "Failed to load notes. Please check your connection.",
@@ -466,7 +504,7 @@ const Index = () => {
setCacheMode('scoped'); setCacheMode('scoped');
// Load a larger set to find the target note and surrounding context // Load a larger set to find the target note and surrounding context
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -478,7 +516,7 @@ const Index = () => {
limit: 1000, limit: 1000,
sort: ['date:desc'], sort: ['date:desc'],
}), }),
}); }, 'Load Notes Around Note');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to load notes'); throw new Error('Failed to load notes');
@@ -515,16 +553,16 @@ const Index = () => {
setCacheMode('scoped'); setCacheMode('scoped');
const [beforeRes, afterRes] = await Promise.all([ const [beforeRes, afterRes] = await Promise.all([
fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: meiliHeaders, headers: meiliHeaders,
body: JSON.stringify({ q: '', filter: `date <= ${targetMs}`, sort: ['date:desc'], limit: beforeLimit }), body: JSON.stringify({ q: '', filter: `date <= ${targetMs}`, sort: ['date:desc'], limit: beforeLimit }),
}), }, 'Load Notes Around Date (Before)'),
fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: meiliHeaders, headers: meiliHeaders,
body: JSON.stringify({ q: '', filter: `date >= ${targetMs}`, sort: ['date:asc'], limit: afterLimit }), body: JSON.stringify({ q: '', filter: `date >= ${targetMs}`, sort: ['date:asc'], limit: afterLimit }),
}), }, 'Load Notes Around Date (After)'),
]); ]);
const [beforeData, afterData] = await Promise.all([ const [beforeData, afterData] = await Promise.all([
@@ -566,8 +604,12 @@ const Index = () => {
return; return;
} }
const searchStartTime = Date.now();
console.log(`🔍 Starting search for: "${query}"`);
addDebugInfo(`🔍 Searching for: "${query}"`);
try { try {
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -583,7 +625,7 @@ const Index = () => {
highlightPostTag: '</mark>', highlightPostTag: '</mark>',
sort: ['date:desc'], sort: ['date:desc'],
}), }),
}); }, 'Search Notes');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to search notes'); throw new Error('Failed to search notes');
@@ -596,8 +638,15 @@ const Index = () => {
})); }));
setSearchResults(results); setSearchResults(results);
const searchTime = Date.now() - searchStartTime;
debugTiming(`Search Results (${results.length} found)`, searchStartTime);
addDebugInfo(`✅ Search complete: ${results.length} results in ${searchTime}ms`);
console.log(`✅ Search complete: ${results.length} results found`);
} catch (error) { } catch (error) {
console.error('Error searching notes:', error); console.error('Error searching notes:', error);
const searchTime = Date.now() - searchStartTime;
debugTiming('Search (FAILED)', searchStartTime);
addDebugInfo(`❌ Search failed after ${searchTime}ms`);
toast({ toast({
title: "Error", title: "Error",
description: "Failed to search notes. Please try again.", description: "Failed to search notes. Please try again.",
@@ -656,7 +705,7 @@ const Index = () => {
const threshold = cleanupThreshold[0]; const threshold = cleanupThreshold[0];
const minCount = minLetterCount[0]; const minCount = minLetterCount[0];
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -667,7 +716,7 @@ const Index = () => {
filter: `topLetterFrequency > ${threshold} OR letterCount < ${minCount}`, filter: `topLetterFrequency > ${threshold} OR letterCount < ${minCount}`,
sort: ['date:desc'], sort: ['date:desc'],
}), }),
}); }, 'Get Problematic Notes');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to get problematic notes'); throw new Error('Failed to get problematic notes');
@@ -836,15 +885,27 @@ const Index = () => {
} }
}; };
// Handle window focus to restore focus to the current note field
const handleWindowFocus = () => {
// Only restore focus if no modal is open and the current note field exists
if (!isSearchOpen && !isGotoOpen && !isCleanupOpen && currentNoteRef.current) {
currentNoteRef.current.focus();
console.log('🎯 Focus restored on window focus');
}
};
document.addEventListener('keydown', handleKeyDown); document.addEventListener('keydown', handleKeyDown);
window.addEventListener('focus', handleWindowFocus);
return () => { return () => {
document.removeEventListener('keydown', handleKeyDown); document.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('focus', handleWindowFocus);
// Clear any pending save timeout on cleanup // Clear any pending save timeout on cleanup
if (saveTimeoutRef.current) { if (saveTimeoutRef.current) {
clearTimeout(saveTimeoutRef.current); clearTimeout(saveTimeoutRef.current);
} }
}; };
}, [currentNote, previousNote, scratchPad, isPreviousNoteModified]); }, [currentNote, previousNote, scratchPad, isPreviousNoteModified, isSearchOpen, isGotoOpen, isCleanupOpen]);
// Auto-save functions // Auto-save functions
const handleCurrentNoteBlur = () => { const handleCurrentNoteBlur = () => {
@@ -868,7 +929,7 @@ const Index = () => {
// Load latest scratch // Load latest scratch
const loadLatestScratch = async () => { const loadLatestScratch = async () => {
try { try {
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -879,7 +940,7 @@ const Index = () => {
sort: ['date:desc'], sort: ['date:desc'],
limit: 1, limit: 1,
}), }),
}); }, 'Load Latest Scratch');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to load latest scratch'); throw new Error('Failed to load latest scratch');
@@ -914,14 +975,14 @@ const Index = () => {
content: content, content: content,
}; };
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/documents`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/documents`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(document), body: JSON.stringify(document),
}); }, 'Save Scratch');
if (response.status !== 202) { if (response.status !== 202) {
throw new Error('Failed to save scratch'); throw new Error('Failed to save scratch');
@@ -957,11 +1018,11 @@ const Index = () => {
// Check if an index exists // Check if an index exists
const indexExists = async (index: string): Promise<boolean> => { const indexExists = async (index: string): Promise<boolean> => {
try { try {
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${index}`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${index}`, {
headers: { headers: {
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
}); }, `Check Index ${index}`);
return response.status === 200; return response.status === 200;
} catch (error) { } catch (error) {
console.error(`Error checking if index ${index} exists:`, error); console.error(`Error checking if index ${index} exists:`, error);
@@ -971,10 +1032,15 @@ const Index = () => {
// Initialize Meilisearch indexes // Initialize Meilisearch indexes
const initializeIndexes = async () => { const initializeIndexes = async () => {
const initStartTime = Date.now();
try { try {
console.log('🚀 Starting initialization...');
addDebugInfo('🚀 Starting initialization...');
// Initialize notes index // Initialize notes index
if (!(await indexExists(NOTE_INDEX))) { if (!(await indexExists(NOTE_INDEX))) {
await fetch(`${MEILISEARCH_ENDPOINT}/indexes`, { const indexStart = Date.now();
await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -984,41 +1050,42 @@ const Index = () => {
uid: NOTE_INDEX, uid: NOTE_INDEX,
primaryKey: 'id', primaryKey: 'id',
}), }),
}); }, 'Initialize Notes Index');
addDebugInfo(`⏱️ Initialize Notes Index: ${Date.now() - indexStart}ms`);
} }
// Configure notes index settings // Configure notes index settings
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/sortable-attributes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/sortable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}); }, 'Configure Notes Sortable Attributes');
// Set ranking rules to prioritize sorting // Set ranking rules to prioritize sorting
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/ranking-rules`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/ranking-rules`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['sort', 'words', 'typo', 'proximity', 'attribute', 'exactness']), body: JSON.stringify(['sort', 'words', 'typo', 'proximity', 'attribute', 'exactness']),
}); }, 'Configure Notes Ranking Rules');
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/filterable-attributes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['date', 'topLetter', 'letterCount', 'topLetterFrequency']), body: JSON.stringify(['date', 'topLetter', 'letterCount', 'topLetterFrequency']),
}); }, 'Configure Notes Filterable Attributes');
// Initialize scratch index // Initialize scratch index
if (!(await indexExists(SCRATCH_INDEX))) { if (!(await indexExists(SCRATCH_INDEX))) {
await fetch(`${MEILISEARCH_ENDPOINT}/indexes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -1028,31 +1095,31 @@ const Index = () => {
uid: SCRATCH_INDEX, uid: SCRATCH_INDEX,
primaryKey: 'id', primaryKey: 'id',
}), }),
}); }, 'Initialize Scratch Index');
} }
// Configure scratch index settings // Configure scratch index settings
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/sortable-attributes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/sortable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}); }, 'Configure Scratch Sortable Attributes');
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/filterable-attributes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}); }, 'Configure Scratch Filterable Attributes');
// Initialize settings index // Initialize settings index
if (!(await indexExists(SETTINGS_INDEX))) { if (!(await indexExists(SETTINGS_INDEX))) {
await fetch(`${MEILISEARCH_ENDPOINT}/indexes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -1062,26 +1129,33 @@ const Index = () => {
uid: SETTINGS_INDEX, uid: SETTINGS_INDEX,
primaryKey: 'key', primaryKey: 'key',
}), }),
}); }, 'Initialize Settings Index');
} }
// Configure settings index // Configure settings index
await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/settings/filterable-attributes`, { await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(['key', 'value']), body: JSON.stringify(['key', 'value']),
}); }, 'Configure Settings Filterable Attributes');
setIsInitialized(true); setIsInitialized(true);
const totalTime = Date.now() - initStartTime;
debugTiming('Total Initialization', initStartTime);
addDebugInfo(`✅ Total Initialization: ${totalTime}ms`);
console.log('✅ Initialization complete');
toast({ toast({
title: "Initialization complete", title: "Initialization complete",
description: "All indexes have been configured successfully.", description: "All indexes have been configured successfully.",
}); });
} catch (error) { } catch (error) {
console.error('Error initializing indexes:', error); console.error('Error initializing indexes:', error);
const totalTime = Date.now() - initStartTime;
debugTiming('Initialization (FAILED)', initStartTime);
addDebugInfo(`❌ Initialization FAILED: ${totalTime}ms`);
toast({ toast({
title: "Initialization failed", title: "Initialization failed",
description: "Failed to initialize indexes. Please check your connection.", description: "Failed to initialize indexes. Please check your connection.",
@@ -1090,6 +1164,17 @@ const Index = () => {
} }
}; };
// Immediate focus when component mounts
useEffect(() => {
// Focus the current note field immediately with a small delay to ensure DOM is ready
const focusTimer = setTimeout(() => {
currentNoteRef.current?.focus();
console.log('🎯 Focus set on current note field');
}, 100);
return () => clearTimeout(focusTimer);
}, []);
useEffect(() => { useEffect(() => {
const initIndexes = async () => { const initIndexes = async () => {
await initializeIndexes(); await initializeIndexes();
@@ -1100,9 +1185,20 @@ const Index = () => {
useEffect(() => { useEffect(() => {
const loadInitialData = async () => { const loadInitialData = async () => {
if (isInitialized) { if (isInitialized) {
const dataLoadStartTime = Date.now();
console.log('📊 Starting data loading...');
addDebugInfo('📊 Starting data loading...');
await loadNotes(); await loadNotes();
await loadLatestScratch(); await loadLatestScratch();
await loadFontSizeSetting(); await loadFontSizeSetting();
const totalTime = Date.now() - dataLoadStartTime;
debugTiming('Total Data Loading', dataLoadStartTime);
addDebugInfo(`✅ Total Data Loading: ${totalTime}ms`);
console.log('✅ Data loading complete');
// Re-focus after data loading to ensure focus is maintained
currentNoteRef.current?.focus(); currentNoteRef.current?.focus();
} }
}; };
@@ -1127,7 +1223,7 @@ const Index = () => {
// Load font size setting // Load font size setting
const loadFontSizeSetting = async () => { const loadFontSizeSetting = async () => {
try { try {
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/search`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -1138,7 +1234,7 @@ const Index = () => {
filter: 'key = "fontSize"', filter: 'key = "fontSize"',
limit: 1, limit: 1,
}), }),
}); }, 'Load Font Size Setting');
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
@@ -1160,14 +1256,14 @@ const Index = () => {
updatedAt: new Date().getTime(), updatedAt: new Date().getTime(),
}; };
const response = await fetch(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/documents`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/documents`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`,
}, },
body: JSON.stringify(document), body: JSON.stringify(document),
}); }, 'Save Font Size Setting');
if (response.status !== 202) { if (response.status !== 202) {
throw new Error('Failed to save font size setting'); throw new Error('Failed to save font size setting');
@@ -1219,10 +1315,38 @@ const Index = () => {
<Trash2 className="h-8 w-8" /> <Trash2 className="h-8 w-8" />
Cleanup Cleanup
</Button> </Button>
<Button
onClick={() => setShowDebugPanel(!showDebugPanel)}
size="sm"
variant="outline"
className={getTextClass('base')}
>
{showDebugPanel ? 'Hide' : 'Show'} Debug
</Button>
</div> </div>
</div> </div>
</header> </header>
{/* Debug Panel */}
{showDebugPanel && (
<div className="bg-muted border-b border-border p-4 max-h-48 overflow-y-auto">
<div className={`${getTextClass('xl')} font-semibold mb-2`}>Debug Information</div>
<div className="space-y-1">
{debugInfo.length > 0 ? (
debugInfo.map((info, index) => (
<div key={index} className={`${getTextClass('base')} font-mono text-xs`}>
{info}
</div>
))
) : (
<div className={`${getTextClass('base')} text-muted-foreground`}>
No debug information available yet...
</div>
)}
</div>
</div>
)}
{/* Main Content */} {/* Main Content */}
<div className="flex-1 flex p-4 gap-4 overflow-hidden"> <div className="flex-1 flex p-4 gap-4 overflow-hidden">
{/* Left Panel - 70% */} {/* Left Panel - 70% */}