feat: add KnowledgeGraph component for visualizing, editing, and syncing handbook content with AI-driven analysis
All checks were successful
On Push to Main / test (push) Successful in 31s
On Push to Main / publish (push) Successful in 59s
On Push to Main / deploy-dev (push) Successful in 1m49s

This commit is contained in:
RaymondVerhoef
2026-05-18 22:12:19 +02:00
parent d2b067735c
commit 190d1a6e0b

View File

@@ -28,8 +28,19 @@ const KnowledgeGraph = () => {
const [relations, setRelations] = useState([]); const [relations, setRelations] = useState([]);
const reloadKb = useCallback(() => { const reloadKb = useCallback(() => {
db.getTopics().then(setTopics); Promise.all([db.getTopics(), db.getRelations()]).then(([allTopics, allRelations]) => {
db.getRelations().then(setRelations); const topicIds = new Set(allTopics.map(t => t.id));
const validRelations = allRelations
.map(r => ({
...r,
source: r.source?.id || r.source,
target: r.target?.id || r.target
}))
.filter(r => topicIds.has(r.source) && topicIds.has(r.target));
setTopics(allTopics);
setRelations(validRelations);
});
}, []); }, []);
useEffect(() => { useEffect(() => {
@@ -164,7 +175,13 @@ const KnowledgeGraph = () => {
const deleteNode = async () => { const deleteNode = async () => {
if (confirm(`Are you sure you want to delete "${selectedNode.label}"? This will also remove any relations connected to it.`)) { if (confirm(`Are you sure you want to delete "${selectedNode.label}"? This will also remove any relations connected to it.`)) {
const updatedTopics = topics.filter(t => t.id !== selectedNode.id); const updatedTopics = topics.filter(t => t.id !== selectedNode.id);
const updatedRelations = relations.filter(r => r.source !== selectedNode.id && r.target !== selectedNode.id); const updatedRelations = relations
.map(r => ({
...r,
source: r.source?.id || r.source,
target: r.target?.id || r.target
}))
.filter(r => r.source !== selectedNode.id && r.target !== selectedNode.id);
await db.saveTopics(updatedTopics); await db.saveTopics(updatedTopics);
await db.saveRelations(updatedRelations); await db.saveRelations(updatedRelations);
@@ -324,7 +341,19 @@ Analyze this graph and return ONLY the optimized JSON object with this EXACT str
} }
} }
updatedRelations = updatedRelations.filter(r => r.source !== r.target); // Ensure all relations only reference existing nodes and are normalized to string IDs
const finalTopicIds = new Set(updatedTopics.map(t => t.id));
updatedRelations = updatedRelations
.map(r => ({
...r,
source: r.source?.id || r.source,
target: r.target?.id || r.target
}))
.filter(r =>
r.source !== r.target &&
finalTopicIds.has(r.source) &&
finalTopicIds.has(r.target)
);
await db.saveTopics(updatedTopics); await db.saveTopics(updatedTopics);
await db.saveRelations(updatedRelations); await db.saveRelations(updatedRelations);