Skip to content

feat: Add ability to export workflow diagram as png - #373

Open
cheryl7114 wants to merge 10 commits into
open-workflow-specification:mainfrom
cheryl7114:png-export-341
Open

feat: Add ability to export workflow diagram as png#373
cheryl7114 wants to merge 10 commits into
open-workflow-specification:mainfrom
cheryl7114:png-export-341

Conversation

@cheryl7114

Copy link
Copy Markdown
Contributor

Closes #341

Summary

This PR adds a Download as PNG button to the side panel, which allows users to export the workflow diagram as a PNG file.

Preview:
image

Key Changes

  • Added html-to-image as a dependency
  • src/lib/exportPng.ts — new utility that computes the bounding box of all nodes, translates the React Flow viewport to frame them, and uses html-to-image to render a high-resolution PNG
  • src/side-panel/MermaidActions.tsx renamed to ExportActions.tsx — component renamed to ExportActions to reflect its broader scope; PNG button added
  • src/store/DiagramEditorContext — added reactFlowInstance, isExporting, and their setters to shared context so ExportActions can access the React Flow instance and Diagram can respond to export state
  • src/react-flow/diagram/Diagram.tsx — syncs reactFlowInstance into context; flips onlyRenderVisibleElements off during export so all nodes are in the DOM when html-to-image captures them

Preview of exported PNG from Managing Github Issues (under Use Cases):
manage-github-issues (12)

Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Copilot AI lite review requested due to automatic review settings August 31, 2026 09:45
@netlify

netlify Bot commented Aug 31, 2026

Copy link
Copy Markdown

Deploy Preview for openworkflow-editor ready!

Name Link
🔨 Latest commit aa56001
🔍 Latest deploy log https://app.netlify.com/projects/openworkflow-editor/deploys/6a96deca8ae87e0008bbd3f2
😎 Deploy Preview https://deploy-preview-373--openworkflow-editor.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a PNG export capability for the React Flow diagram in the Open Workflow diagram editor, integrating a new export utility and exposing the React Flow instance through shared editor context so the side panel can trigger an image download.

Changes:

  • Add html-to-image dependency and a new exportDiagramAsPng utility for rendering the diagram to a high-resolution PNG.
  • Replace MermaidActions with a broader ExportActions component and add a “Download as PNG” button in the side panel.
  • Extend DiagramEditorContext to share reactFlowInstance, isExporting, and a diagram container ref, and adjust Diagram rendering during export.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-workspace.yaml Adds html-to-image to the workspace catalog.
pnpm-lock.yaml Locks html-to-image dependency version and metadata.
packages/open-workflow-diagram-editor/package.json Adds html-to-image as a package dependency.
packages/open-workflow-diagram-editor/src/lib/exportPng.ts New utility to compute bounds and export viewport as PNG via html-to-image.
packages/open-workflow-diagram-editor/src/side-panel/ExportActions.tsx Renamed/expanded actions UI and adds “Download as PNG” behavior.
packages/open-workflow-diagram-editor/src/side-panel/SidePanel.tsx Swaps MermaidActions for ExportActions in the footer.
packages/open-workflow-diagram-editor/src/store/DiagramEditorContext.tsx Extends context type with react-flow instance, exporting state, and container ref.
packages/open-workflow-diagram-editor/src/store/DiagramEditorContextProvider.tsx Implements new context state and exposes diagram container ref through provider.
packages/open-workflow-diagram-editor/src/react-flow/diagram/Diagram.tsx Syncs React Flow instance into context and disables visible-only rendering during export.
packages/open-workflow-diagram-editor/src/react-flow/diagram/Diagram.css Adjusts condition edge stroke styling to use a CSS variable.
packages/open-workflow-diagram-editor/src/i18n/locales/en.ts Adds English string for “Download as PNG”.
packages/open-workflow-diagram-editor/src/diagram-editor/DiagramEditor.tsx Passes diagram container ref into the context provider.
packages/open-workflow-diagram-editor/src/components/ui/sonner.css Updates Sonner toast styling selectors to match portal behavior and enforce positioning.
packages/open-workflow-diagram-editor/tests/test-utils/render-helpers.tsx Updates mocked context with new fields used by export flow.
packages/open-workflow-diagram-editor/tests/side-panel/ExportActions.test.tsx Renames tests and adds coverage for PNG export button behavior.
packages/open-workflow-diagram-editor/stories/examples/workflows/listen-to-any-forever-foreach.yaml Updates example workflow content.
.changeset/png-export.md Adds a minor changeset entry for PNG export feature.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/open-workflow-diagram-editor/src/lib/exportPng.ts
Comment thread packages/open-workflow-diagram-editor/tests/test-utils/render-helpers.tsx Outdated
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Copilot AI review requested due to automatic review settings August 31, 2026 10:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

packages/open-workflow-diagram-editor/src/side-panel/ExportActions.tsx:92

  • The export flow uses a hard-coded setTimeout(..., 50) to wait for React Flow to render non-visible nodes. This time-based delay can be flaky on slower/faster devices and adds unnecessary latency. Prefer waiting for one or two animation frames so the export reliably happens after the DOM has updated.
    packages/open-workflow-diagram-editor/src/components/ui/sonner.css:42
  • The Sonner styles are now applied to every [data-sonner-*] toaster on the page. Since this package can be embedded in other apps, this can unintentionally restyle a host application's own Sonner toasts. You already set className="dec:toaster" on the editor’s <Sonner> (see src/components/ui/sonner.tsx:30-33), so these rules can be safely scoped to only that toaster.
  [data-sonner-toaster] {
    --width: 300px !important;
    position: fixed !important;
    top: var(--offset, 32px) !important;
    bottom: auto !important;

.changeset/png-export.md:5

  • Changeset summary text is inconsistent with the existing Changesets style (sentence case, proper casing for acronyms like PNG, and punctuation). This becomes user-facing release notes, so it should be polished.
add png export button for react flow diagram

Comment thread packages/open-workflow-diagram-editor/src/components/ui/sonner.css
Comment thread packages/open-workflow-diagram-editor/src/lib/exportPng.ts Outdated
Comment thread packages/open-workflow-diagram-editor/src/lib/exportPng.ts Outdated
Comment thread packages/open-workflow-diagram-editor/src/lib/exportPng.ts
Comment thread packages/open-workflow-diagram-editor/src/side-panel/ExportActions.tsx Outdated
edges: RF.Edge[];
taskReferences: Set<string>;
selectedNodeId: string | null;
reactFlowInstance: RF.ReactFlowInstance | null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont fully understand why reactFlowInstance or diagramDivRef is needed here? You should be able to access in the Export file directly using something like
const reactFlowInstance = RF.useReactFlow() That would remove a lot of complexity

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useReactFlow() needs the calling component to be rendered inside the <ReactFlow> component itself. In our tree, <ReactFlow> lives inside Diagram, and ExportActions (via SidePanel) is not a descendant:

ReactFlowProvider
  └── DiagramEditorContextProvider
        ├── Diagram
        │     └── <ReactFlow>   ← useReactFlow() only works inside here
        └── SidePanel
              └── ExportActions ← sibling, useReactFlow() would throw here

So ExportActions can't call useReactFlow() directly. The instance has to be captured inside Diagram (where <ReactFlow> renders) and shared via context. Same reasoning applies to diagramDivRef. ExportActions has no other way to reach it since it sits outside the canvas subtree

@lornakelly lornakelly Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useReactFlow() only needs to be inside <ReactFlowProvider>, not inside <ReactFlow> itself. That's the
whole point of the provider - it holds the store so components outside the canvas can still reach it.

Had a quick look and if you do the following in WorkflowActions.tsx and it should work

import { useReactFlow } from "@xyflow/react";


const { isExporting, setIsExporting, diagramDivRef } = useDiagramEditorContext();


// delete line 
const { reactFlowInstance, setIsExporting, diagramDivRef } = useDiagramEditorContext();

// add
const reactFlowInstance = useReactFlow();

also delete

    if (reactFlowInstance === null) return;

and change

disabled={reactFlowInstance === null}  >    disabled={isExporting}

Test and if that works you can remove it from context etc

@lornakelly lornakelly Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, you should be able to remove the diagramDivRef from context and have something like this in the file as well

const diagramDomNode = useStore((s) => s.domNode)

Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
@cheryl7114
cheryl7114 requested review from Copilot and removed request for Copilot September 1, 2026 13:57
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
Copilot AI review requested due to automatic review settings September 1, 2026 14:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 20 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

packages/open-workflow-diagram-editor/tests/side-panel/WorkflowActions.test.tsx:18

  • vi.waitFor isn’t used elsewhere in this test suite (other tests import waitFor from @testing-library/react) and may not exist in the Vitest API, which would break type-checking/runtime. Import waitFor from @testing-library/react here as well.
    packages/open-workflow-diagram-editor/tests/side-panel/WorkflowActions.test.tsx:141
  • Use waitFor from @testing-library/react instead of vi.waitFor so the assertion retry mechanism works consistently with the rest of the test suite.

This issue also appears on line 162 of the same file.

packages/open-workflow-diagram-editor/tests/side-panel/WorkflowActions.test.tsx:164

  • Use waitFor from @testing-library/react instead of vi.waitFor so the assertion retry mechanism works consistently with the rest of the test suite.

Comment thread packages/open-workflow-diagram-editor/tests/lib/exportPng.test.ts
Signed-off-by: Cheryl Kong <cherylkong50@gmail.com>
throw new Error("No nodes to export");
}

const { x: minX, y: minY, width, height } = getNodesBounds(nodes);

@lornakelly lornakelly Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be safer here to have reactFlowInstance.getNodesBounds(nodes);. The instance passes nodeLookup, which has the already resolved positions, so nested workflows get the right box. It looks ok on the ones I tested but could be an issue in the future

Like we have it in const nodes above, you can see the doc here as well https://reactflow.dev/api-reference/types/react-flow-instance

cursor: pointer;
}
}
} No newline at end of file

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just fix the newline here so file has no changes

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.

feat: Add ability to export workflow diagram as image

3 participants