Skip to content

feat: add read-only Diagram tab for struts.xml config visualization#65

Open
lukaszlenart wants to merge 7 commits intomainfrom
feat/struts-diagram-tab
Open

feat: add read-only Diagram tab for struts.xml config visualization#65
lukaszlenart wants to merge 7 commits intomainfrom
feat/struts-diagram-tab

Conversation

@lukaszlenart
Copy link
Copy Markdown
Member

@lukaszlenart lukaszlenart commented Apr 5, 2026

Summary

Add a new lightweight Diagram tab for struts.xml files that replaces the deprecated GraphBuilder-based editor with a custom Swing renderer. The tab visualizes packages, actions, and results from the current file only in a hierarchical three-column layout, with hover tooltips and double-click navigation.

Screenshot 2026-04-05 at 14 40 03

Key changes

  • Disable deprecated Graph tab — gated behind -Dcom.intellij.struts2.enableGraphEditor=true to avoid IDE freezes from deprecated GraphBuilder APIs
  • New Diagram tab — toolkit-neutral model layer (diagram/model), presentation helpers (diagram/presentation), custom Swing renderer (diagram/ui), and file editor provider (diagram/fileEditor)
  • File-local scope — diagram resolves packages from the file-local StrutsRoot DOM, not the merged model, so only the current struts.xml's elements are shown
  • EDT-safe threading — tooltips and navigation pointers are precomputed under a read action during snapshot creation; double-click navigation uses Application.runReadAction(Computable) instead of the EDT-forbidden ReadAction.nonBlocking().executeSynchronously()
  • DTD validationStrutsDtdValidator detects http:// vs https:// DTD URI mismatches and surfaces them as file-level warnings in Struts2ModelInspection
  • Explicit fallback states — diagram component tracks LOADED/EMPTY/UNAVAILABLE state and renders centered placeholder messages instead of silent blank panels or stale content
  • Descriptive labels — unresolved result paths show (unresolved path) instead of raw ???; unnamed elements show (unnamed); tooltips use (unresolved) / (unknown type)

New components

Package Purpose
diagram/model Toolkit-neutral DTOs: StrutsDiagramNode, StrutsDiagramEdge, StrutsConfigDiagramModel (snapshot builder)
diagram/presentation Tooltip HTML generation and EDT-safe navigation helpers
diagram/ui Custom Swing renderer with hierarchical layout, hover, and double-click support
diagram/fileEditor PerspectiveFileEditorProvider + PerspectiveFileEditor registered in plugin.xml
dom/inspection StrutsDtdValidator shared DTD URI validation helper

Commits

  1. feat: disable deprecated Graph editor tab by default — gate old Graph tab behind JVM flag
  2. feat: add read-only Diagram tab for struts.xml config visualization — initial Diagram implementation
  3. test: add Diagram file editor provider tests and migration boundary docs — provider tests + architecture docs
  4. fix: resolve threading violations in Diagram tab — precompute tooltips/pointers under read action
  5. feat(diagram): show local packages only and add early DTD validation — file-local scoping + DTD inspection
  6. fix(diagram): use EDT-safe read action for node navigation — fix double-click EDT assertion
  7. feat(diagram): harden MVP with explicit states and clearer fallbacks — empty/error states, label polish, focused tests

Test plan

  • Open a struts.xml file in a project with a configured Struts file set
  • Verify the Diagram tab appears alongside Text (and Graph only if JVM flag is set)
  • Verify packages, actions, and results render as colored rounded-rect nodes in three columns
  • Verify edges connect packages → actions → results with labels and arrowheads
  • Hover over nodes to see tooltip HTML (action class, method, namespace, etc.)
  • Double-click a node to navigate to the corresponding XML element (no EDT exception)
  • Verify the tab does not appear for non-Struts XML files or JSP files
  • Open a valid Struts file with no packages — verify "No packages or actions found" message
  • Open a non-Struts XML — verify "Diagram is not available" message
  • Verify unresolved result paths show "(unresolved path)" not "???"
  • ./gradlew test -x rat passes (all diagram + full suite)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

🔌 Plugin artifact ready for testing!

Download from Actions artifacts

Artifact: struts2-261.18970.1

Introduce a lightweight Swing-based Diagram tab alongside the existing
(disabled-by-default) Graph tab. The new tab renders packages, actions,
and results in a hierarchical layout with tooltips and click-to-navigate,
without depending on the deprecated GraphBuilder APIs.

New components:
- diagram/model: toolkit-neutral DTOs (node, edge, snapshot builder)
- diagram/presentation: reusable tooltip/navigation helpers
- diagram/ui: custom Swing renderer with hover and double-click support
- diagram/fileEditor: PerspectiveFileEditorProvider + editor registration

Made-with: Cursor
Add focused tests for Struts2DiagramFileEditorProvider verifying it
accepts struts.xml in file sets and rejects plain XML, JSP, and Java
files. Document the toolkit-neutral model layer as the migration
boundary between the current Swing renderer and a future Diagrams API.

Made-with: Cursor
Precompute tooltip HTML and navigation pointers during model snapshot
creation (under read action) so Swing event handlers on the EDT never
access DOM/PSI directly.

Changes:
- StrutsDiagramNode: replace DomElement with precomputed tooltipHtml
  and SmartPsiElementPointer for navigation
- StrutsConfigDiagramModel.build(): compute tooltips and create smart
  pointers during snapshot (must be called under read action)
- StrutsDiagramPresentation: split into computeTooltipHtml (build-time)
  and navigateToElement (EDT-safe via ReadAction.nonBlocking)
- Struts2DiagramFileEditor: wrap build() in ReadAction.nonBlocking
  with progress dialog for initial load
- Struts2DiagramComponent: use precomputed node.getTooltipHtml()
  instead of calling into DOM on hover

Made-with: Cursor
Diagram model now resolves packages from the file-local StrutsRoot DOM
instead of the merged StrutsModel, so only the current struts.xml's
packages/actions/results are displayed.

DTD validation is extracted into a shared StrutsDtdValidator helper and
wired into Struts2ModelInspection.checkFileElement() as a file-level
warning, so users see http:// vs https:// issues while editing rather
than only when opening the Diagram tab. The Diagram-specific
notification is removed since the inspection now covers it earlier.

- Add StrutsDtdValidator shared helper for DTD URI checks
- Add DTD check to Struts2ModelInspection with WARNING severity
- Remove Diagram-side DTD notification (replaced by inspection)
- Handle null model in Struts2DiagramFileEditor.reset()
- Add StrutsConfigDiagramModelTest for local-file filtering
- Add StrutsDtdValidatorTest for DTD validation logic
- Add highlighting test for valid https:// DTD

Made-with: Cursor
Replace ReadAction.nonBlocking().executeSynchronously() with
Application.runReadAction(Computable) in navigateToElement() so
double-clicking a Diagram node no longer throws an EDT assertion.

The NBRA path asserts background-thread usage, but the mouse handler
always runs on the EDT. The regular runReadAction is appropriate here
since the work is just a SmartPsiElementPointer dereference.

Adds a regression test verifying pointer resolution through the
same Application.runReadAction path.

Made-with: Cursor
Unify the editor rebuild path so initial load and reset() always
reflect the current model state instead of retaining stale content.
Add LOADED/EMPTY/UNAVAILABLE states to the diagram component with
centered placeholder messages for non-loaded states. Replace raw
??? placeholders with descriptive labels ((unresolved path),
(unnamed), (unknown type)). Extend tests to cover empty files,
null models, rebuild transitions, and label clarity.

Made-with: Cursor
@lukaszlenart lukaszlenart force-pushed the feat/struts-diagram-tab branch from 24f171c to 211efe2 Compare April 5, 2026 12:45
Replace display-based equals/hashCode (kind+name) in StrutsDiagramNode
with a stable ID derived from the backing XML element's text offset.
This prevents node collisions when duplicate action names or result
paths exist across packages.

Add focused tests for duplicate-name regression, edge topology and
labels, editor lifecycle (creation and reset), and DTD validator
classification outcomes.

Made-with: Cursor
@lukaszlenart lukaszlenart marked this pull request as ready for review April 5, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant