Add query bar, maintenance panel, and heartbeat system

- Query bar with organized/grouped search results in portal
- Maintenance panel UI for triggering and viewing maintenance status
- Heartbeat service with periodic maintenance and dirty-tracking
- Query organizer for grouping search results by tag/kind/parent
- Slide-up animation for query panel
This commit is contained in:
2026-02-03 00:55:08 +01:00
parent f65653e260
commit af568f81c2
11 changed files with 785 additions and 2 deletions

View File

@@ -2,6 +2,8 @@ import { Router, Request, Response } from 'express';
import { addNode, getNode, listNodes, updateNode, removeNode, addEdge, removeEdge, query } from '../core/store';
import { getConnections, buildTree } from '../core/graph';
import { getDb } from '../core/db';
import { determineGroupingStrategy, groupResults } from './queryOrganizer';
import { getLastReport, markDirty, runMaintenance } from './heartbeat';
const router = Router();
@@ -133,4 +135,35 @@ router.post('/search', async (req: Request, res: Response) => {
}
});
// Organized query
router.post('/query/organize', async (req: Request, res: Response) => {
try {
const { text } = req.body;
if (!text) return res.status(400).json({ error: 'text is required' });
const results = await query(text, { limit: 30 });
const strategy = determineGroupingStrategy(text);
const grouped = groupResults(results, strategy);
res.json(grouped);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
// Maintenance status
router.get('/maintenance/status', (_req: Request, res: Response) => {
const report = getLastReport();
res.json(report || { message: 'No heartbeat has run yet' });
});
// Trigger maintenance manually
router.post('/maintenance/run', async (_req: Request, res: Response) => {
try {
markDirty();
const report = await runMaintenance();
res.json(report);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
export default router;