sync: multiple features from private repo

- quick-add-loading: fire-and-forget with loading placeholders, auto-open feed, SSE events, QuickAddInput redesign
- database-table-pane: TablePane + DatabaseTableView, countNodes(), event_date sort
- ui-polish-fixes: focus tab order, dim name editing, tab title sync, cost chip removal, custom sort drag-reorder, refresh button, dimension filter removal (~2,200 lines)
- node-creation-quality: description service prompt rewrite, title sanitization, extraction tool AI prompt rewrites
- feed-pane-ux: stripped kanban/grid/saved views, sort dropdown, AND dimension filtering, description preview

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
“BeeRad”
2026-02-15 17:57:32 +11:00
co-authored by Claude Opus 4.6
parent 9954792b1d
commit 2f6518207d
25 changed files with 1590 additions and 2647 deletions
+52 -17
View File
@@ -33,7 +33,7 @@ export async function GET(request: NextRequest) {
// Handle sortBy parameter (sortBy=edges|updated|created)
const sortByParam = searchParams.get('sortBy');
if (sortByParam === 'edges' || sortByParam === 'updated' || sortByParam === 'created') {
if (sortByParam === 'edges' || sortByParam === 'updated' || sortByParam === 'created' || sortByParam === 'event_date') {
filters.sortBy = sortByParam;
}
@@ -46,11 +46,13 @@ export async function GET(request: NextRequest) {
}
const nodes = await nodeService.getNodes(filters);
const total = await nodeService.countNodes(filters);
return NextResponse.json({
success: true,
data: nodes,
count: nodes.length
count: nodes.length,
total
});
} catch (error) {
console.error('Error fetching nodes:', error);
@@ -62,10 +64,24 @@ export async function GET(request: NextRequest) {
}
}
// Weak-pattern regex for post-creation quality monitoring
const WEAK_PATTERNS = /\b(discusses|explores|examines|talks about|is about|delves into|This is a)\b/i;
function sanitizeTitle(title: string): string {
let clean = title.trim();
// Strip "Title: " prefix (extraction artifact)
if (clean.startsWith('Title: ')) clean = clean.slice(7);
// Strip trailing " / X" (Twitter artifact)
if (clean.endsWith(' / X')) clean = clean.slice(0, -4);
// Collapse whitespace
clean = clean.replace(/\s+/g, ' ');
return clean.slice(0, 160);
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Validate required fields
if (!body.title) {
return NextResponse.json({
@@ -74,7 +90,11 @@ export async function POST(request: NextRequest) {
}, { status: 400 });
}
// Sanitize title (strip extraction artifacts)
body.title = sanitizeTitle(body.title);
const rawNotes = typeof body.notes === 'string' ? body.notes : null;
const eventDate = typeof body.event_date === 'string' ? body.event_date : null;
// Process provided dimensions first (needed for description generation)
const providedDimensions = Array.isArray(body.dimensions) ? body.dimensions : [];
@@ -83,19 +103,33 @@ export async function POST(request: NextRequest) {
.filter(Boolean)
.slice(0, 8);
// Generate description with all available context
let nodeDescription: string | undefined;
try {
nodeDescription = await generateDescription({
title: body.title,
notes: rawNotes || undefined,
link: body.link || undefined,
metadata: body.metadata,
dimensions: trimmedProvidedDimensions
});
} catch (error) {
console.error('Error generating description:', error);
// Continue without description - dimension assignment will use content as fallback
// Use provided description if present, otherwise auto-generate
let nodeDescription: string | undefined = typeof body.description === 'string' && body.description.trim()
? body.description.trim().slice(0, 280)
: undefined;
if (!nodeDescription) {
try {
nodeDescription = await generateDescription({
title: body.title,
notes: rawNotes || undefined,
link: body.link || undefined,
metadata: body.metadata,
dimensions: trimmedProvidedDimensions
});
} catch (error) {
console.error('Error generating description:', error);
}
}
// Final safety net — never store null/empty description
if (!nodeDescription || nodeDescription.trim().length === 0) {
nodeDescription = body.title.slice(0, 280);
}
// Monitor description quality
if (nodeDescription && WEAK_PATTERNS.test(nodeDescription)) {
console.warn(`[DescriptionQuality] Weak description for node "${body.title}": "${nodeDescription}"`);
}
// Auto-assign locked dimensions + keyword dimensions for all new nodes
@@ -129,6 +163,7 @@ export async function POST(request: NextRequest) {
title: body.title,
description: nodeDescription,
notes: rawNotes ?? undefined,
event_date: eventDate ?? undefined,
link: body.link,
dimensions: finalDimensions,
chunk: chunkToStore ?? undefined,