feat: enhance KnowledgeGraph with edge styles, node navigation, and AI analysis scopes; update GraphControls and NodeDetailPanel for improved relation management
This commit is contained in:
@@ -1,13 +1,25 @@
|
||||
import { RotateCcw, RefreshCw, AlertCircle } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { RotateCcw, RefreshCw, AlertCircle, ChevronDown } from 'lucide-react';
|
||||
import Button from '../../ui/Button';
|
||||
import SuggestionsQueue from '../SuggestionsQueue';
|
||||
|
||||
const SCOPE_OPTIONS = [
|
||||
{ value: 'full', label: 'Full Analysis', tier: 'Opus', hint: 'Merges · Deletions · Relations · Relevance' },
|
||||
{ value: 'relations', label: 'Relations Only', tier: 'Sonnet', hint: 'Suggest missing logical connections' },
|
||||
{ value: 'relevance', label: 'Relevance Only', tier: 'Sonnet', hint: 'Re-score learning_relevance for all unlocked topics' },
|
||||
];
|
||||
|
||||
/**
|
||||
* Sidebar controls panel: the exclude-nodes toggle, the AI analysis button,
|
||||
* the snapshot restore row, and the R42 suggestions queue.
|
||||
* Sidebar controls panel: the exclude-nodes toggle, the AI analysis button
|
||||
* (with scope selector), the snapshot restore row, and the R42 suggestions queue.
|
||||
*
|
||||
* Kept intentionally thin — all async logic lives in the KnowledgeGraph
|
||||
* orchestrator and is injected via props.
|
||||
*
|
||||
* The scope selector is local state here; it produces a scope string that is
|
||||
* forwarded to onAnalyze(scope). Scope options map to different AI tiers:
|
||||
* full → reasoning (Opus) — expensive full quality pass
|
||||
* relations / relevance → standard (Sonnet) — targeted cheaper sub-task
|
||||
*/
|
||||
export default function GraphControls({
|
||||
showExcludeNodes,
|
||||
@@ -21,6 +33,10 @@ export default function GraphControls({
|
||||
onRestore,
|
||||
isRestoring,
|
||||
}) {
|
||||
const [scope, setScope] = useState('full');
|
||||
|
||||
const selectedOption = SCOPE_OPTIONS.find(o => o.value === scope) ?? SCOPE_OPTIONS[0];
|
||||
|
||||
const snapshotLabel = snapshotMeta
|
||||
? new Date(snapshotMeta.ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
||||
: null;
|
||||
@@ -38,13 +54,35 @@ export default function GraphControls({
|
||||
</label>
|
||||
|
||||
<div className="space-y-2">
|
||||
{/* Scope selector */}
|
||||
<div className="relative">
|
||||
<select
|
||||
value={scope}
|
||||
onChange={e => setScope(e.target.value)}
|
||||
disabled={isAnalyzing || isRestoring || disabled}
|
||||
className="w-full border border-bg-warm rounded-[var(--r-sm)] pl-3 pr-8 py-1.5 text-xs bg-paper appearance-none disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
title={selectedOption.hint}
|
||||
>
|
||||
{SCOPE_OPTIONS.map(o => (
|
||||
<option key={o.value} value={o.value}>
|
||||
{o.label} — {o.tier}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown
|
||||
size={12}
|
||||
className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-fg-muted"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-fg-muted leading-snug">{selectedOption.hint}</p>
|
||||
|
||||
<Button
|
||||
onClick={onAnalyze}
|
||||
onClick={() => onAnalyze(scope)}
|
||||
disabled={isAnalyzing || isRestoring || disabled}
|
||||
className="w-full flex justify-center items-center gap-2"
|
||||
>
|
||||
<RefreshCw size={16} className={isAnalyzing ? 'animate-spin' : ''} />
|
||||
{isAnalyzing ? 'Analyzing Graph…' : 'Analyze & Optimize Graph'}
|
||||
{isAnalyzing ? 'Analyzing…' : 'Analyze & Optimize Graph'}
|
||||
</Button>
|
||||
|
||||
{/* Restore row — only visible after a bulkSave has written a snapshot */}
|
||||
@@ -58,7 +96,7 @@ export default function GraphControls({
|
||||
<RotateCcw size={12} className={isRestoring ? 'animate-spin' : ''} />
|
||||
{isRestoring
|
||||
? 'Restoring…'
|
||||
: `Restore to ${snapshotLabel} · ${snapshotMeta.topicCount}t ${snapshotMeta.relationCount}r`}
|
||||
: `↩ Restore to ${snapshotLabel} · ${snapshotMeta.topicCount}t ${snapshotMeta.relationCount}r`}
|
||||
</button>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user