sync: feed pane UX from private repo

- Strip kanban, grid, and saved views from ViewsOverlay (1103→631 lines)
- Add sort order dropdown (Updated/Edges/Created) with localStorage persistence
- Polish filter button, dropdown, and filter chips
- Switch to server-side dimension filtering with AND logic (dimensionsMatch=all)
- Add description preview and edge count to node cards
- Add 'created' sort option and dimensionsMatch param to types, service, API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
“BeeRad”
2026-02-15 13:19:42 +11:00
co-authored by Claude Opus 4.6
parent 86f43c9975
commit 2940e142c8
4 changed files with 251 additions and 695 deletions
+20 -7
View File
@@ -10,7 +10,7 @@ export class NodeService {
// PostgreSQL path removed in SQLite-only consolidation
private async getNodesSQLite(filters: NodeFilters = {}): Promise<Node[]> {
const { dimensions, search, limit = 100, offset = 0, sortBy } = filters;
const { dimensions, search, limit = 100, offset = 0, sortBy, dimensionsMatch = 'any' } = filters;
const sqlite = getSQLiteClient();
// Use nodes_v view for array-like dimensions behavior (exclude embedding BLOB for performance)
@@ -28,12 +28,23 @@ export class NodeService {
// Filter by dimensions (SQLite JOIN with node_dimensions)
if (dimensions && dimensions.length > 0) {
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 (dimensionsMatch === 'all' && dimensions.length > 1) {
// AND logic: node must have ALL specified dimensions
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 {
// OR logic: node must have at least one of the specified dimensions
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);
}
}
// Text search in title, description, and content (SQLite LIKE with COLLATE NOCASE)
@@ -62,6 +73,8 @@ export class NodeService {
} else if (sortBy === 'edges') {
// Sort by edge count (most connected first)
query += ' ORDER BY edge_count DESC, n.updated_at DESC';
} else if (sortBy === 'created') {
query += ' ORDER BY n.created_at DESC';
} else {
query += ' ORDER BY n.updated_at DESC';
}