@@ -5,6 +5,8 @@ import useJSONString from "../components/hooks/useJSONString";
55import { setSuggestions } from "@site/src/components/monaco/suggestionsProvider" ;
66import { jsonpathJoin } from "@nlighten/json-transform-core" ;
77import { JsonTransformer } from "@nlighten/json-transform" ;
8+ import JSONGzip from "@site/src/utils/JSONGzip" ;
9+ import { useLocation , useHistory } from "@docusaurus/router" ;
810
911const DEFAULT_INPUT_VALUE = `{
1012 "first_name": "John",
@@ -44,6 +46,9 @@ const transformAsync = async (input: any, definition: any) => {
4446const narrowScreen = window . innerWidth < 996 ;
4547const initialHeight = narrowScreen ? 280 : 450 ;
4648
49+ export const SHARE_QS = "shared" ;
50+ export const GZIP_MARKER = "gzip," ;
51+
4752const TransformerTester = ( ) => {
4853 const [ inputString , setInputString , parsedInput , inputError ] = useJSONString ( DEFAULT_INPUT_VALUE ) ;
4954 const [ transformerString , setTransformerString , parsedTransformer , transformerError ] =
@@ -52,6 +57,9 @@ const TransformerTester = () => {
5257 const [ outputError , setOutputError ] = useState < string | null > ( null ) ;
5358 const [ loading , setLoading ] = useState ( false ) ;
5459
60+ const location = useLocation ( )
61+ const history = useHistory ( )
62+
5563 useEffect ( ( ) => {
5664 if ( parsedInput ) {
5765 const generatedSchema = JSONSchemaUtils . generate ( parsedInput ) ;
@@ -81,28 +89,95 @@ const TransformerTester = () => {
8189 . finally ( ( ) => setLoading ( false ) ) ;
8290 }
8391
84- return < div className = "tester_grid" >
85- < h3 className = "desktop-title" > Input</ h3 >
86- < h3 className = "desktop-title" > Transformer</ h3 >
87- < h3 className = "desktop-title" > Output</ h3 >
88- < MonacoEditor language = "json" value = { inputString } onChange = { ( value ) => setInputString ( value ) } height = { initialHeight } />
89- < MonacoEditor language = "json" model = "transformer.json"
90- value = { transformerString }
91- validateVariables
92- onChange = { ( value ) => setTransformerString ( value ) }
93- height = { initialHeight } />
94- < MonacoEditor language = "json" readOnly value = { outputJSONString } height = { initialHeight } />
95- < div style = { { color : 'red' } } > { inputError ?. message } </ div >
96- < div className = "button-container" >
97- < div style = { { color : 'red' } } > { transformerError ?. message } </ div >
98- < button type = "button" className = "button button--primary transform-button shadow--lw"
99- disabled = { loading || ! ! ( inputError || transformerError ) }
100- onClick = { handleTransform } > Transform
101- </ button >
102- < div data-loader className = { loading ? undefined :"hide" } > </ div >
92+ useEffect ( ( ) => {
93+ const searchIndex = location . hash ?. indexOf ( "?" ) ;
94+ if ( searchIndex === - 1 || ! location . hash . includes ( SHARE_QS + "=" , searchIndex ) ) return ;
95+ const sp = new URLSearchParams ( location . hash . substring ( searchIndex + 1 ) ) ;
96+ if ( ! sp . has ( SHARE_QS ) ) return ;
97+ const sharedValue = sp . get ( SHARE_QS ) ;
98+ if ( ! sharedValue ) return ;
99+ try {
100+ ( sharedValue . startsWith ( GZIP_MARKER )
101+ ? JSONGzip . decompress ( sharedValue . substring ( GZIP_MARKER . length ) , "base64url" )
102+ : Promise . resolve ( JSON . parse ( sharedValue ) )
103+ )
104+ . then ( defaults => {
105+ setInputString ( JSON . stringify ( defaults . i , null , 2 ) ) ;
106+ setTransformerString ( JSON . stringify ( defaults . d , null , 2 ) ) ;
107+ history . replace ( "#" ) ;
108+ } )
109+ . catch ( e => {
110+ console . error ( e ) ;
111+ history . replace ( "#" ) ;
112+ } ) ;
113+ } catch ( e : any ) {
114+ console . error ( e ) ;
115+ history . replace ( "#" ) ;
116+ }
117+ } , [ location . hash , history . replace ] ) ;
118+
119+ const handleShare = async ( ) => {
120+ const input = JSON . stringify ( { i : parsedInput , d : parsedTransformer } ) ;
121+ const compressed = await JSONGzip . compress ( input , "base64url" , "string" ) ;
122+ const encodedInput = encodeURIComponent ( input ) ;
123+ const sharedValue = encodedInput . length > compressed . length + GZIP_MARKER . length
124+ ? GZIP_MARKER + compressed // compressed is better
125+ : encodedInput ;
126+
127+ prompt ( "Copy this value and share it" , window . location . origin + window . location . pathname + `#?${ SHARE_QS } =` + sharedValue ) ;
128+ } ;
129+
130+ return (
131+ < div className = "tester_grid" >
132+ < h3 className = "hide-on-mobile" > Input</ h3 >
133+ < h3 className = "hide-on-mobile" > Transformer</ h3 >
134+ < h3 style = { { display : "flex" , flexDirection : "row-reverse" , justifyContent : "space-between" } } >
135+ < button type = "button" className = "button button--primary button--sm share-button shadow--lw"
136+ disabled = { ! parsedTransformer }
137+ onClick = { handleShare } >
138+ < span style = { { display : 'flex' , alignItems : "center" , gap : "4px" } } >
139+ < svg className = "MuiSvgIcon-root" focusable = "false" aria-hidden = "true"
140+ viewBox = "0 0 24 24" width = { 16 } height = { 16 } fill = "currentcolor" >
141+ < path
142+ d = "M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92" > </ path >
143+ </ svg >
144+ Share Input and Transformer
145+ </ span >
146+ </ button >
147+ < span className = "hide-on-mobile" > Output</ span >
148+ </ h3 >
149+ < MonacoEditor language = "json" value = { inputString } onChange = { ( value ) => setInputString ( value ) }
150+ height = { initialHeight } />
151+ < MonacoEditor language = "json" model = "transformer.json"
152+ value = { transformerString }
153+ validateVariables
154+ onChange = { ( value ) => setTransformerString ( value ) }
155+ height = { initialHeight } />
156+ < MonacoEditor language = "json" readOnly value = { outputJSONString } height = { initialHeight } />
157+ < div style = { { color : 'red' , fontSize : "0.7em" } } > { inputError ?. message } </ div >
158+ < div className = "button-container" >
159+ < div style = { { color : 'red' , fontSize : "0.7em" } } > { transformerError ?. message } </ div >
160+ < button type = "button" className = "button button--primary transform-button shadow--lw"
161+ disabled = { loading || ! ! ( inputError || transformerError ) }
162+ onClick = { handleTransform } > Transform
163+ </ button >
164+ < div data-loader className = { loading ? undefined : "hide" } > </ div >
165+ </ div >
166+ < div style = {
167+ outputError
168+ ? { color : 'red' , fontSize : "0.7em" }
169+ : outputJSONString
170+ ? { fontSize : "0.7em" }
171+ : undefined
172+ } >
173+ { outputError ??
174+ ( outputJSONString
175+ ? "* You can open the browser console to see debug information about the transformation"
176+ : undefined )
177+ }
178+ </ div >
103179 </ div >
104- < div style = { outputError ? { color : 'red' } : outputJSONString ? { fontSize : "0.7em" } : undefined } > { outputError ?? ( outputJSONString ? "* You can open the browser console to see debug information about the transformation" : undefined ) } </ div >
105- </ div >
180+ ) ;
106181}
107182
108183export default TransformerTester ;
0 commit comments