1- import React , { useCallback , useState } from 'react' ;
1+ import React , { useCallback , useMemo , useRef , useState } from 'react' ;
22import {
33 Button ,
44 css ,
@@ -12,6 +12,7 @@ import {
1212 Radio ,
1313 RadioGroup ,
1414 spacing ,
15+ SpinLoader ,
1516} from '@mongodb-js/compass-components' ;
1617import {
1718 closeExportModal ,
@@ -21,7 +22,8 @@ import {
2122import { connect } from 'react-redux' ;
2223import type { DataModelingState } from '../store/reducer' ;
2324import type { StaticModel } from '../services/data-model-storage' ;
24- import { exportToJson } from '../services/export-diagram' ;
25+ import { exportToJson , exportToPng } from '../services/export-diagram' ;
26+ import { getNodesBounds , useDiagram } from '@mongodb-js/diagramming' ;
2527
2628const nbsp = '\u00a0' ;
2729
@@ -59,15 +61,25 @@ const ExportDiagramModal = ({
5961 model,
6062 onCloseClick,
6163} : ExportDiagramModalProps ) => {
62- const [ exportFormat , setExportFormat ] = useState < 'json' | null > ( null ) ;
64+ const [ exportFormat , setExportFormat ] = useState < 'png' | 'json' | null > ( null ) ;
65+ const diagram = useDiagram ( ) ;
66+ const [ isExporting , setIsExporting ] = useState ( false ) ;
67+ const exportDiagramContainerRef = useRef < HTMLDivElement > ( null ) ;
68+ const bounds = useMemo ( ( ) => getNodesBounds ( diagram . getNodes ( ) ) , [ diagram ] ) ;
6369
64- const onExport = useCallback ( ( ) => {
70+ const onExport = useCallback ( async ( ) => {
6571 if ( ! exportFormat || ! model ) {
6672 return ;
6773 }
68- exportToJson ( diagramLabel , model ) ;
74+ setIsExporting ( true ) ;
75+ if ( exportFormat === 'json' ) {
76+ exportToJson ( diagramLabel , model ) ;
77+ } else if ( exportFormat === 'png' ) {
78+ await exportToPng ( diagramLabel , exportDiagramContainerRef , diagram ) ;
79+ }
6980 onCloseClick ( ) ;
70- } , [ exportFormat , onCloseClick , model , diagramLabel ] ) ;
81+ setIsExporting ( false ) ;
82+ } , [ exportFormat , onCloseClick , model , diagram , diagramLabel ] ) ;
7183
7284 return (
7385 < Modal
@@ -95,6 +107,17 @@ const ExportDiagramModal = ({
95107 < div className = { contentContainerStyles } >
96108 < Label htmlFor = "" > Select file format:</ Label >
97109 < RadioGroup className = { contentContainerStyles } value = { exportFormat } >
110+ < div className = { radioItemStyles } >
111+ < Icon glyph = "Diagram2" />
112+ < Radio
113+ checked = { exportFormat === 'png' }
114+ value = "png"
115+ aria-label = "PNG"
116+ onClick = { ( ) => setExportFormat ( 'png' ) }
117+ >
118+ PNG
119+ </ Radio >
120+ </ div >
98121 < div className = { radioItemStyles } >
99122 < Icon glyph = "CurlyBraces" />
100123 < Radio
@@ -108,12 +131,26 @@ const ExportDiagramModal = ({
108131 </ div >
109132 </ RadioGroup >
110133 </ div >
134+ { /* Container where we render export diagram when exporting png */ }
135+ < div
136+ style = { {
137+ width : bounds . width ,
138+ height : bounds . height ,
139+ // Fixed at bottom right corner
140+ position : 'fixed' ,
141+ top : '100vh' ,
142+ left : '100vw' ,
143+ } }
144+ ref = { exportDiagramContainerRef }
145+ />
111146 </ ModalBody >
112147 < ModalFooter className = { footerStyles } >
113148 < Button
114149 variant = "primary"
115150 onClick = { ( ) => void onExport ( ) }
116151 data-testid = "export-button"
152+ disabled = { isExporting }
153+ loadingIndicator = { < SpinLoader /> }
117154 >
118155 Export
119156 </ Button >
0 commit comments