fix: improve note interactions and markdown LaTeX support
## Bug Fixes ### Note Card Actions - Fix broken size change functionality (missing state declaration) - Implement React 19 useOptimistic for instant UI feedback - Add startTransition for non-blocking updates - Ensure smooth animations without page refresh - All note actions now work: pin, archive, color, size, checklist ### Markdown LaTeX Rendering - Add remark-math and rehype-katex plugins - Support inline equations with dollar sign syntax - Support block equations with double dollar sign syntax - Import KaTeX CSS for proper styling - Equations now render correctly instead of showing raw LaTeX ## Technical Details - Replace undefined currentNote references with optimistic state - Add optimistic updates before server actions for instant feedback - Use router.refresh() in transitions for smart cache invalidation - Install remark-math, rehype-katex, and katex packages ## Testing - Build passes successfully with no TypeScript errors - Dev server hot-reloads changes correctly
This commit is contained in:
100
keep-notes/app/api/admin/embeddings/validate/route.ts
Normal file
100
keep-notes/app/api/admin/embeddings/validate/route.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { auth } from '@/auth'
|
||||
import { validateEmbedding } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
* Admin endpoint to validate all embeddings in the database
|
||||
* Returns a list of notes with invalid embeddings
|
||||
*/
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
// Check if user is admin
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
select: { role: true }
|
||||
})
|
||||
|
||||
if (!user || user.role !== 'ADMIN') {
|
||||
return NextResponse.json({ error: 'Forbidden - Admin only' }, { status: 403 })
|
||||
}
|
||||
|
||||
// Fetch all notes with embeddings
|
||||
const allNotes = await prisma.note.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
embedding: true
|
||||
}
|
||||
})
|
||||
|
||||
const invalidNotes: Array<{
|
||||
id: string
|
||||
title: string
|
||||
issues: string[]
|
||||
}> = []
|
||||
|
||||
let validCount = 0
|
||||
let missingCount = 0
|
||||
let invalidCount = 0
|
||||
|
||||
for (const note of allNotes) {
|
||||
// Check if embedding is missing
|
||||
if (!note.embedding) {
|
||||
missingCount++
|
||||
invalidNotes.push({
|
||||
id: note.id,
|
||||
title: note.title || 'Untitled',
|
||||
issues: ['Missing embedding']
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse and validate embedding
|
||||
try {
|
||||
const embedding = JSON.parse(note.embedding)
|
||||
const validation = validateEmbedding(embedding)
|
||||
|
||||
if (!validation.valid) {
|
||||
invalidCount++
|
||||
invalidNotes.push({
|
||||
id: note.id,
|
||||
title: note.title || 'Untitled',
|
||||
issues: validation.issues
|
||||
})
|
||||
} else {
|
||||
validCount++
|
||||
}
|
||||
} catch (error) {
|
||||
invalidCount++
|
||||
invalidNotes.push({
|
||||
id: note.id,
|
||||
title: note.title || 'Untitled',
|
||||
issues: [`Failed to parse embedding: ${error}`]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
summary: {
|
||||
total: allNotes.length,
|
||||
valid: validCount,
|
||||
missing: missingCount,
|
||||
invalid: invalidCount
|
||||
},
|
||||
invalidNotes
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[EMBEDDING_VALIDATION] Error:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: String(error) },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user