mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
fix(explorer): resolve 3 code-review bugs in GraphWorkspace, DecisionWorkspace, and index.css
- GraphWorkspace: set isRunningPredictions=true before link-prediction fetch and false in finally block; pass isRunningPredictions prop to LazyGraphInspectorPanel so the inspector button disables and shows a spinner during the request (was declared but never wired — broke noUnusedLocals TypeScript build) - DecisionWorkspace: add AbortController to the /api/decisions useEffect so the fetch is cancelled on unmount; add per-call AbortController to handleSelectDecision for /api/decisions/:id/chain; add res.ok guards before .json() on both fetches; encodeURIComponent on decision_id to prevent path-injection edge cases - index.css: add missing @keyframes skeleton-pulse rule (0%/100% opacity 0.45, 50% opacity 0.85) — KGOverviewTab skeletonBarStyle referenced this animation but it was never defined, leaving skeleton bars static Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3ea1283626
commit
670027fd22
@@ -63,3 +63,9 @@ code, pre, .mono {
|
||||
.animate-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* Skeleton pulse animation for loading placeholders */
|
||||
@keyframes skeleton-pulse {
|
||||
0%, 100% { opacity: 0.45; }
|
||||
50% { opacity: 0.85; }
|
||||
}
|
||||
|
||||
@@ -203,15 +203,21 @@ export function DecisionWorkspace() {
|
||||
const [filterQuery, setFilterQuery] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setListLoading(true);
|
||||
fetch("/api/decisions")
|
||||
.then((res) => res.json())
|
||||
fetch("/api/decisions", { signal: controller.signal })
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error(`Failed to load decisions: ${res.status}`);
|
||||
return res.json();
|
||||
})
|
||||
.then((data) => {
|
||||
setDecisions(data);
|
||||
if (data.length > 0) void handleSelectDecision(data[0]);
|
||||
})
|
||||
.catch(console.error)
|
||||
.catch((err) => { if (err.name !== "AbortError") console.error(err); })
|
||||
.finally(() => setListLoading(false));
|
||||
return () => controller.abort();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const filteredDecisions = useMemo(() => {
|
||||
@@ -229,15 +235,18 @@ export function DecisionWorkspace() {
|
||||
setSelectedDecision(d);
|
||||
setLoading(true);
|
||||
setChain([]);
|
||||
const controller = new AbortController();
|
||||
try {
|
||||
const res = await fetch(`/api/decisions/${d.decision_id}/chain`);
|
||||
const res = await fetch(`/api/decisions/${encodeURIComponent(d.decision_id)}/chain`, { signal: controller.signal });
|
||||
if (!res.ok) throw new Error(`Failed to load chain: ${res.status}`);
|
||||
const data = await res.json();
|
||||
setChain(data.chain || []);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if ((e as DOMException).name !== "AbortError") console.error(e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
return () => controller.abort();
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -816,6 +816,7 @@ export function GraphWorkspace() {
|
||||
|
||||
const handleRunPredictions = useCallback(async () => {
|
||||
if (!selectedNodeId) return;
|
||||
setIsRunningPredictions(true);
|
||||
try {
|
||||
const response = await fetch("/api/enrich/links", {
|
||||
method: "POST",
|
||||
@@ -835,6 +836,8 @@ export function GraphWorkspace() {
|
||||
} catch (predictionError) {
|
||||
console.error("[GraphWorkspace] prediction failed", predictionError);
|
||||
setPredictions([]);
|
||||
} finally {
|
||||
setIsRunningPredictions(false);
|
||||
}
|
||||
}, [predictionType, selectedNodeId]);
|
||||
|
||||
@@ -1609,6 +1612,7 @@ export function GraphWorkspace() {
|
||||
predictionType={predictionType}
|
||||
onPredictionTypeChange={setPredictionType}
|
||||
onRunPredictions={() => void handleRunPredictions()}
|
||||
isRunningPredictions={isRunningPredictions}
|
||||
pathTargetId={pathTargetId}
|
||||
onPathTargetChange={setPathTargetId}
|
||||
onTracePath={() => void handleTracePath()}
|
||||
|
||||
Reference in New Issue
Block a user