Skip to content

feat: export the application graph as a PNG image - #386

Open
pujitha24 wants to merge 1 commit into
radius-project:mainfrom
pujitha24:feat/app-graph-export
Open

pujitha24 wants to merge 1 commit into
radius-project:mainfrom
pujitha24:feat/app-graph-export

Conversation

@pujitha24

Copy link
Copy Markdown

Summary

Adds a Download graph as PNG button to the application graph's controls, under zoom in, zoom out and fit view. It exports the whole graph, not just the part in view, as a PNG at its natural size on a white background. The file is named <application>-graph.png.

Reason for change

#33 asks for buttons next to the app graph that export the current diagram as an image or PDF, so it can be shared outside the dashboard. In the issue thread, willtsai pointed to React Flow's download image example, and this PR follows it: html-to-image's toPng on .react-flow__viewport, with a transform built from the node bounds. The bounds come from getNodesBounds, the current name of getRectOfNodes in reactflow 11.11.

Fixes #33

Details

  • Where the button lives. It is a ControlButton inside the existing React Flow <Controls> in @radapp.io/rad-components. That keeps the package free of Backstage and MUI, as described in the code organization docs.
  • Format. It exports PNG only. PDF would need a second dependency, and an image covers the issue's "PDF or image".
  • New dependency. @radapp.io/rad-components now depends on html-to-image, pinned to exactly 1.11.11 (MIT, no dependencies, released February 2023, no known advisories). I tested the latest versions in the browser: 1.11.12 and 1.11.13 leave React Flow's SVG edges out of the image, so the export shows only the nodes. 1.11.11 keeps them, and it is also the version React Flow's own example pins. .github/dependabot.yml is synced from radius-project/.github, so I didn't add an ignore rule there. Instead, a unit test checks the installed version and explains why, so a Dependabot bump to 1.11.12 or later fails CI with that reason. The only yarn.lock change is the new entry, and yarn install --immutable passes.
  • File name. The real getGraph response (ApplicationGraphResponse) has only resources and no name. ApplicationTab now fills in the graph name from the application ID, so the file is named after the application.
  • Button states. The button is disabled while an export is running and when the graph has no resources. If the export fails, the graph shows a role="alert" message, which clears on the next attempt.

How to test

  1. Run kubectl proxy and yarn dev, then open an application and go to its App Graph tab.
  2. Click the download button, the fourth button in the controls at the bottom left. Its accessible name and tooltip are "Download graph as PNG".
  3. A file named <application>-graph.png downloads. It shows every node and edge, even if you zoomed or panned first.

Screenshots

Taken in headless Chromium at a 1440x1000 viewport against yarn start. The Radius API responses were route-mocked in the same way as packages/app/e2e-tests/radiusGraph.test.ts, using the repo's multi-tier.json graph fixture without a name, matching the real API.

Before (main) After: download control added to the graph controls
before after

Close-up of the control: control

The downloaded file: todo-app-graph.png, 439x770. It has all four nodes and three edges.

exported file

Tests run

  • yarn install --immutable: passes.
  • yarn tsc: passes.
  • yarn lint:all: passes.
  • yarn format:check: passes.
  • yarn test:all: 55 suites and 484 tests pass. The skipped suite and tests were already skipped on main. Coverage thresholds are met, including the rad-components ones.
  • New AppGraph tests mock html-to-image. They cover the labelled control, the download and its file name, the failure alert and retry, the disabled state while exporting and for an empty graph, the image size and transform from the node bounds, the file name rules, and the version pin.
  • I ran the new tests against the code without this change, and they fail there. That includes the ApplicationTab test that names the graph after the application.
  • Browser check (Playwright): the download control works, the downloaded PNG contains every node and edge, and it is the same full-graph image after zooming in four times.

Not verified

  • I did not test against a live Radius cluster, and I only checked Chromium.
  • I didn't add a Storybook or component e2e test for the export. The real rasterising was checked with Playwright against the dashboard, as described above.
  • docs/design/2026-09-radius-backstage-plugin.md, which is a draft, proposes moving the graph renderer into a shared graph-react package later. This control is self-contained in AppGraph.tsx, so it should move along with the renderer.

File change summary

File Summary of change
packages/rad-components/src/components/appgraph/AppGraph.tsx Adds exportGraphToPng (whole-graph bounds plus padding, white background) and graphImageFileName. Adds the "Download graph as PNG" ControlButton with its in-progress and empty-graph guards, and a role="alert" panel shown when the export fails
packages/rad-components/src/components/appgraph/__test__/AppGraph.test.tsx Tests for the control, download, failure and retry, guards, sizing, file name, and the version pin
packages/rad-components/package.json, yarn.lock Adds html-to-image 1.11.11
plugins/plugin-radius/src/components/resources/ApplicationTab.tsx Names the graph after the application, since the getGraph response has no name
plugins/plugin-radius/src/components/resources/ApplicationTab.test.tsx Tests the name fallback

Add a "Download graph as PNG" button to the application graph controls,
next to zoom in, zoom out and fit view. It renders the whole graph at
its natural size on a white background with html-to-image, following
React Flow's download-image example, and downloads it as
<application>-graph.png.

html-to-image is pinned to 1.11.11 because 1.11.12 and 1.11.13 leave
React Flow's SVG edges out of the image; a test records the pin.

The getGraph response has no name, so the application tab now names the
graph after the application.

Fixes radius-project#33

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-opus-5-5 (via Claude Code)
@pujitha24
pujitha24 requested review from a team as code owners October 1, 2026 21:46

This branch has not been deployed

No deployments
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.

Application Graph exporting

1 participant