diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45d8f052a..861754ef5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,6 +109,11 @@ jobs: packages/ui/components/MarkdownEditor.extensions.test.tsx packages/ui/components/ThemeProvider.favicon.test.tsx packages/ui/components/MermaidBlock.theme.test.tsx + packages/ui/components/DiagramBlock.anchor.test.tsx + packages/ui/components/diagram/DiagramViewer.test.tsx + packages/ui/utils/diagramAnchor.test.ts + packages/ui/utils/diagramAnchorGraphviz.test.ts + packages/ui/hooks/useAnnotationHighlighter.diagramSkip.test.tsx packages/ui/components/CommentPopover.skillReferences.test.tsx packages/ui/components/SkillReferenceMenu.placement.test.tsx packages/ui/components/sidebar/FileBrowser.test.ts diff --git a/AGENTS.md b/AGENTS.md index da6a18e4c..a5526d782 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,6 +73,7 @@ plannotator/ │ │ ├── theme.css # Single source of truth for color tokens + Tailwind bridge │ │ ├── components/ # Viewer, Toolbar, Settings, etc. │ │ │ ├── icons/ # Shared SVG icon components (themeIcons, etc.) +│ │ │ ├── diagram/ # The diagram engine's viewer (DiagramViewer, DiagramCanvas, DiagramOverlay, DiagramComposer, DiagramSourcePane, DiagramPopout + hooks); DiagramBlock.tsx is the fence side │ │ │ ├── plan-diff/ # PlanDiffBadge, PlanDiffViewer, clean/raw diff views │ │ │ └── sidebar/ # SidebarContainer, SidebarTabs, VersionBrowser, ArchiveBrowser │ │ ├── shortcuts/ # Keyboard shortcut registry (see Keyboard Shortcuts section below) @@ -896,6 +897,7 @@ interface Annotation { diffContext?: 'added' | 'removed' | 'modified'; // Set when annotation created in plan diff view htmlAnchor?: HtmlElementAnchor; // Raw-HTML pinpoint: serialized element anchor for reliable restoration htmlAdditionalTargets?: HtmlAnnotationTarget[]; // Raw-HTML shift-click multi-select: extra elements this one comment covers + diagramAnchor?: DiagramAnchor; // A comment on a rendered diagram part: { v: 1, family, kind, id | from + to, label, sourceLine } (document lines); see "Diagram comments" startMeta?: { parentTagName; parentIndex; textOffset }; endMeta?: { parentTagName; parentIndex; textOffset }; } @@ -964,6 +966,8 @@ Text highlighting uses `web-highlighter` library. Code blocks use manual ` *Counts:* the panel header shows the scoped count, but the session total the decision control runs on (`feedbackAnnotationCount`) is computed from session state and is unaffected by the toggle — switching scope never changes what is submitted. Not covered: code review, single-document plan review, and live-app multi-page sessions (which already group their export by page). The compact/touch sheet reuses `AnnotationPanel`, so it gets the same toggle in its own header bar. Every panel prop is optional and additive, so a host that passes none of them (Workspaces) renders the previous panel, legacy affordance included. +**Diagram comments (Mermaid and Graphviz fences).** A comment composed on a rendered diagram part — a click on a node, edge or cluster in the inline canvas or the popout — becomes an `Annotation` on the document with ONE additive field, `diagramAnchor` (`DiagramAnchor` from `@plannotator/core/diagram-anchor`, the `htmlAnchor` precedent): `{ v: 1, family, kind, id | from + to, label, sourceLine }` (families: flowchart, state, class, er, requirement, sequence, other, graphviz; kinds: node, edge, cluster, and `diagram` for the whole diagram, which has no id), where the anchor is the diagram's OWN id for the part (sequence parts carry classes, not ids, so the codec's ids are the actor's `name`, `msg-`, `note-`, `frame-` by document order, restored with a label check because an ordinal moves) (never the rendered element id with its trailing counter, never geometry) and `sourceLine` names 1-based DOCUMENT lines (the fence's opening line is the offset, `Block.startLine`). The annotation carries the fence's `blockId`, `startOffset`/`endOffset` 0, the label as `originalText`, `type: COMMENT` and the tater identity, so it lists in the annotations rail beside text comments, exports, persists in drafts (opaque JSON), and restores after a reload: `useAnnotationHighlighter` skips rows carrying `diagramAnchor` (neither attempted nor unanchored), and `DiagramBlock` re-resolves them against every render through the engine's finder — id, then label, then unanchored — and reports through `Viewer.onRestoreReport` with its own comments as `attempted`, so App's `markdownUnanchoredIds` shows the same "Unanchored" chip a text comment gets. All three export paths (`exportAnnotations`, `exportLinkedDocAnnotations`, `exportAnnotationEntry`) print the location line `Diagram node