feat: add GraphControls component and useGraphData hook for knowledge graph management

This commit is contained in:
RaymondVerhoef
2026-05-27 15:05:26 +02:00
parent 3aa32c383e
commit 7b6a5b4bf0
4 changed files with 577 additions and 128 deletions

View File

@@ -53,7 +53,15 @@ export async function upsertTopic(topic) {
// ── Relations ────────────────────────────────────────────────────────────────
export async function getRelations() {
return pb.collection('relations').getFullList();
const records = await pb.collection('relations').getFullList();
// Always return plain string IDs for source/target.
// PocketBase can return populated objects when relation fields are expanded;
// normalising here means callers never need the `r.source?.id || r.source` dance.
return records.map(r => ({
...r,
source: typeof r.source === 'object' && r.source !== null ? r.source.id : r.source,
target: typeof r.target === 'object' && r.target !== null ? r.target.id : r.target,
}));
}
export async function saveRelations(relations) {
@@ -234,6 +242,17 @@ export async function getLeaderboard() {
return entries.sort((a, b) => (b.points || 0) - (a.points || 0));
}
/**
* Fetch every test_results record across all users, newest first.
* Used by the Contributions page to build per-user heatmaps, streaks,
* perfect-score counts, and the recent-activity feed in a single query.
*/
export async function getAllTestResults() {
try {
return await pb.collection('test_results').getFullList({ sort: '-created' });
} catch { return []; }
}
export async function upsertLeaderboardEntry(userId, name, pointsDelta, testsCompletedDelta = 0) {
try {
const r = await pb.collection('leaderboard').getFirstListItem(`user_id="${userId}"`);