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
+42
View File
@@ -7,6 +7,46 @@ export class NodeService {
return this.getNodesSQLite(filters);
}
async countNodes(filters: NodeFilters = {}): Promise<number> {
const { dimensions, search, dimensionsMatch = 'any',
createdAfter, createdBefore, eventAfter, eventBefore } = filters;
const sqlite = getSQLiteClient();
let query = `SELECT COUNT(*) as total FROM nodes n WHERE 1=1`;
const params: any[] = [];
if (dimensions && dimensions.length > 0) {
if (dimensionsMatch === 'all' && dimensions.length > 1) {
query += ` AND (
SELECT COUNT(DISTINCT nd.dimension) FROM node_dimensions nd
WHERE nd.node_id = n.id
AND nd.dimension IN (${dimensions.map(() => '?').join(',')})
) = ?`;
params.push(...dimensions, dimensions.length);
} else {
query += ` AND EXISTS (
SELECT 1 FROM node_dimensions nd
WHERE nd.node_id = n.id
AND nd.dimension IN (${dimensions.map(() => '?').join(',')})
)`;
params.push(...dimensions);
}
}
if (search) {
query += ` AND (n.title LIKE ? COLLATE NOCASE OR n.description LIKE ? COLLATE NOCASE OR n.notes LIKE ? COLLATE NOCASE)`;
params.push(`%${search}%`, `%${search}%`, `%${search}%`);
}
if (createdAfter) { query += ` AND n.created_at >= ?`; params.push(createdAfter); }
if (createdBefore) { query += ` AND n.created_at < ?`; params.push(createdBefore); }
if (eventAfter) { query += ` AND n.event_date >= ?`; params.push(eventAfter); }
if (eventBefore) { query += ` AND n.event_date < ?`; params.push(eventBefore); }
const result = sqlite.query<{ total: number }>(query, params);
return result.rows[0]?.total ?? 0;
}
// PostgreSQL path removed in SQLite-only consolidation
private async getNodesSQLite(filters: NodeFilters = {}): Promise<Node[]> {
@@ -94,6 +134,8 @@ export class NodeService {
query += ' ORDER BY edge_count DESC, n.updated_at DESC';
} else if (sortBy === 'created') {
query += ' ORDER BY n.created_at DESC';
} else if (sortBy === 'event_date') {
query += ' ORDER BY n.event_date IS NULL, n.event_date DESC, n.updated_at DESC';
} else {
query += ' ORDER BY n.updated_at DESC';
}