1- import { useCallback , useRef } from 'react' ;
1+ import { useCallback , useRef , useState } from 'react' ;
22import { useStore } from '../store/store' ;
33import { DEFAULT_QUERY } from '../core/clickhouse/client' ;
44import { ClickHouseFormat , FORMAT_METADATA } from '../core/types/formats' ;
55
6+ function encodeBase64Url ( str : string ) : string {
7+ const bytes = new TextEncoder ( ) . encode ( str ) ;
8+ const binary = String . fromCharCode ( ...bytes ) ;
9+ return btoa ( binary ) . replace ( / \+ / g, '-' ) . replace ( / \/ / g, '_' ) . replace ( / = + $ / , '' ) ;
10+ }
11+
12+ function decodeBase64Url ( encoded : string ) : string {
13+ const base64 = encoded . replace ( / - / g, '+' ) . replace ( / _ / g, '/' ) ;
14+ const binary = atob ( base64 ) ;
15+ const bytes = Uint8Array . from ( binary , ( c ) => c . charCodeAt ( 0 ) ) ;
16+ return new TextDecoder ( ) . decode ( bytes ) ;
17+ }
18+
19+ export { encodeBase64Url , decodeBase64Url } ;
20+
621export function QueryInput ( ) {
722 const query = useStore ( ( s ) => s . query ) ;
823 const setQuery = useStore ( ( s ) => s . setQuery ) ;
@@ -15,6 +30,17 @@ export function QueryInput() {
1530 const queryTiming = useStore ( ( s ) => s . queryTiming ) ;
1631
1732 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
33+ const [ shareLabel , setShareLabel ] = useState ( 'Share' ) ;
34+
35+ const handleShare = useCallback ( ( ) => {
36+ const url = new URL ( window . location . href ) ;
37+ url . search = '' ;
38+ url . searchParams . set ( 'q' , encodeBase64Url ( query ) ) ;
39+ url . searchParams . set ( 'f' , format ) ;
40+ navigator . clipboard . writeText ( url . toString ( ) ) ;
41+ setShareLabel ( 'Copied!' ) ;
42+ setTimeout ( ( ) => setShareLabel ( 'Share' ) , 2000 ) ;
43+ } , [ query , format ] ) ;
1844
1945 const handleExecute = useCallback ( ( ) => {
2046 executeQuery ( ) ;
@@ -94,6 +120,9 @@ export function QueryInput() {
94120 >
95121 Upload
96122 </ button >
123+ < button className = "query-btn secondary" onClick = { handleShare } title = "Copy shareable URL to clipboard" >
124+ { shareLabel }
125+ </ button >
97126 < button className = "query-btn secondary" onClick = { handleReset } disabled = { isLoading } >
98127 Reset
99128 </ button >
0 commit comments