1+ import { saveAs } from 'file-saver' ;
12import { toast } from 'react-toastify' ;
23import parser from '../graph-builder/graphml/parser' ;
34import { actionType as T } from '../reducer' ;
@@ -84,6 +85,41 @@ const saveAction = (state) => {
8485 getGraphFun ( state ) . saveToDisk ( ) ;
8586} ;
8687
88+ const saveAsJson = ( state ) => {
89+ if ( ! getGraphFun ( state ) ) {
90+ toast . error ( 'No graph open to export.' ) ;
91+ return ;
92+ }
93+ try {
94+ const graphJson = getGraphFun ( state ) . jsonifyGraph ( ) ;
95+ const cleanExport = {
96+ projectName : graphJson . projectName || 'Untitled' ,
97+ authorName : graphJson . authorName || '' ,
98+ nodes : graphJson . nodes . map ( ( n ) => ( {
99+ id : n . id ,
100+ label : n . label ,
101+ position : n . position ,
102+ style : n . style ,
103+ } ) ) ,
104+ edges : graphJson . edges . map ( ( e ) => ( {
105+ id : e . id ,
106+ label : e . label ,
107+ source : e . source ,
108+ target : e . target ,
109+ style : e . style ,
110+ } ) ) ,
111+ } ;
112+ const str = JSON . stringify ( cleanExport , null , 2 ) ;
113+ const bytes = new TextEncoder ( ) . encode ( str ) ;
114+ const blob = new Blob ( [ bytes ] , { type : 'application/json;charset=utf-8' } ) ;
115+ const fileName = `${ cleanExport . projectName } .json` ;
116+ saveAs ( blob , fileName ) ;
117+ toast . success ( 'Exported as JSON successfully!' ) ;
118+ } catch ( error ) {
119+ toast . error ( 'Failed to export JSON.' ) ;
120+ }
121+ } ;
122+
87123async function saveGraphMLFile ( state ) {
88124 if ( state . curGraphInstance ) {
89125 const graph = state . graphs [ state . curGraphIndex ] ;
@@ -114,7 +150,8 @@ const readFile = async (state, setState, file, fileHandle) => {
114150 }
115151 const fr = new FileReader ( ) ;
116152 const projectName = file . name ;
117- if ( file . name . split ( '.' ) . pop ( ) === 'graphml' ) {
153+ const ext = file . name . split ( '.' ) . pop ( ) ;
154+ if ( ext === 'graphml' ) {
118155 fr . onload = ( x ) => {
119156 parser ( x . target . result ) . then ( ( { authorName } ) => {
120157 setState ( {
@@ -127,6 +164,26 @@ const readFile = async (state, setState, file, fileHandle) => {
127164 } ;
128165 if ( fileHandle ) fr . readAsText ( await fileHandle . getFile ( ) ) ;
129166 else fr . readAsText ( file ) ;
167+ } else if ( ext === 'json' ) {
168+ fr . onload = ( x ) => {
169+ try {
170+ const parsed = JSON . parse ( x . target . result ) ;
171+ setState ( {
172+ type : T . ADD_GRAPH ,
173+ payload : {
174+ projectName : parsed . projectName || file . name ,
175+ graphML : null ,
176+ fileHandle : null ,
177+ fileName : file . name ,
178+ authorName : parsed . authorName || '' ,
179+ importedJson : parsed ,
180+ } ,
181+ } ) ;
182+ } catch {
183+ toast . error ( 'Invalid JSON file.' ) ;
184+ }
185+ } ;
186+ fr . readAsText ( file ) ;
130187 }
131188 }
132189} ;
@@ -232,5 +289,5 @@ export {
232289 createFile , readFile , readTextFile , newProject , clearAll , editDetails , undo , redo ,
233290 openShareModal , openSettingModal , viewHistory , resetAfterClear , toggleLogs ,
234291 copySelected , pasteClipboard ,
235- toggleServer , optionModalToggle , contribute , openSearchPanel ,
292+ toggleServer , optionModalToggle , contribute , openSearchPanel , saveAsJson ,
236293} ;
0 commit comments