mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
cb4de46636
* feat: add shared EditorAnnotation type Single source of truth for the editor annotation interface, imported by both @plannotator/server and @plannotator/ui. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: editor annotation server endpoints In-memory store with POST/GET/DELETE endpoints for editor annotations. The array lives in the handler closure and dies with the server session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: editor annotation UI — polling hook, card, panel, and export - useEditorAnnotations hook with auto-disable polling (500ms interval) - EditorAnnotationCard with file path, code preview, and comment - AnnotationPanel conditionally renders editor annotation section - exportEditorAnnotations formats annotations for Claude feedback - App.tsx wires hook, includes in output memo and send feedback gate Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: VS Code extension editor annotation command Cmd+Shift+. or right-click to capture selected text as an annotation. POSTs through the cookie proxy to the plannotator server. Adds amber left-border decorations on annotated lines, cleared on panel close. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: inline comment threads, lightbulb menu, and stronger decorations Replace showInputBox with VS Code CommentController for inline annotation threads anchored to selected code. Add CodeActionProvider for lightbulb discoverability. Stronger decoration styling with gutter icon. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: VS Code theme integration for webview Bridge VS Code CSS variables to Plannotator's CSS variable system via postMessage between wrapper page and proxied iframe. Automatically adopts the active VS Code color theme (dark/light/custom) without touching any UI components or CSS files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate editor annotation polling behind VS Code detection Only poll /api/editor-annotations when running inside a VS Code webview (window.__PLANNOTATOR_VSCODE). Browser and shared URL users now have zero network cost from the editor annotations feature. Also fixes poll interval from 500ms to 2000ms. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: faster polling, prevent unnecessary re-renders, unify HTTP helper - Poll interval 2s → 500ms for snappier annotation pickup - Shallow equality check on annotation IDs prevents React re-renders when poll data is unchanged - Merge postToProxy/deleteFromProxy into single requestProxy function Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: editor annotations support in code review Wire existing editor annotation infrastructure into the review flow so VS Code users can annotate files outside the diff during code review. - Add editor annotation endpoints to review server (same 3-line pattern) - Call useEditorAnnotations hook in review App.tsx - Display editor annotations in ReviewPanel with "Editor" divider - Include editor annotations in feedback export and gating logic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
import type { EditorAnnotation } from '../types';
|
|
|
|
const POLL_INTERVAL = 500;
|
|
const IS_VSCODE = typeof window !== 'undefined' && (window as any).__PLANNOTATOR_VSCODE === true;
|
|
|
|
interface UseEditorAnnotationsReturn {
|
|
editorAnnotations: EditorAnnotation[];
|
|
deleteEditorAnnotation: (id: string) => void;
|
|
}
|
|
|
|
/**
|
|
* Polls the server for editor annotations created by the VS Code extension.
|
|
*
|
|
* Only activates when running inside a VS Code webview (detected via
|
|
* window.__PLANNOTATOR_VSCODE set by the theme bridge). In browser/shared URL
|
|
* contexts, returns an empty array with zero network cost.
|
|
*/
|
|
export function useEditorAnnotations(): UseEditorAnnotationsReturn {
|
|
const [annotations, setAnnotations] = useState<EditorAnnotation[]>([]);
|
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
|
|
const fetchAnnotations = useCallback(async () => {
|
|
try {
|
|
const res = await fetch('/api/editor-annotations');
|
|
if (!res.ok) return;
|
|
const data = await res.json();
|
|
const incoming: EditorAnnotation[] = data.annotations ?? [];
|
|
setAnnotations((prev) => {
|
|
if (prev.length === incoming.length && prev.every((a, i) => a.id === incoming[i].id)) return prev;
|
|
return incoming;
|
|
});
|
|
} catch {
|
|
// Silently fail — next poll will retry
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!IS_VSCODE) return;
|
|
|
|
// Initial fetch + start polling
|
|
fetchAnnotations();
|
|
intervalRef.current = setInterval(fetchAnnotations, POLL_INTERVAL);
|
|
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
};
|
|
}, [fetchAnnotations]);
|
|
|
|
const deleteEditorAnnotation = useCallback(async (id: string) => {
|
|
if (!IS_VSCODE) return;
|
|
try {
|
|
await fetch(`/api/editor-annotation?id=${encodeURIComponent(id)}`, { method: 'DELETE' });
|
|
setAnnotations((prev) => prev.filter((a) => a.id !== id));
|
|
} catch {
|
|
// Silently fail — next poll will reconcile
|
|
}
|
|
}, []);
|
|
|
|
return { editorAnnotations: annotations, deleteEditorAnnotation };
|
|
}
|