@@ -15,18 +15,51 @@ import DocsIcon from '../../icons/DocsIcon'
1515import SqlIcon from '../../icons/SqlIcon'
1616import ChatBubbleComponent from "../../ChatBubbleComponent" ;
1717
18+ const ENDPOINTS_MAP = new Map ( [
19+ [ 'europe' , {
20+ label : 'Europe' ,
21+ endpoints : new Map ( [
22+ [ 'v1' , { label : 'API v1' , url : 'https://graphql.bitquery.io' } ] ,
23+ [ 'v2' , { label : 'API v2' , url : 'https://streaming.bitquery.io/graphql' } ] ,
24+ ] )
25+ } ] ,
26+ [ 'asia' , {
27+ label : 'Asia' ,
28+ endpoints : new Map ( [
29+ [ 'v1' , { label : 'API v1' , url : 'https://asia.graphql.bitquery.io' } ] ,
30+ [ 'v2' , { label : 'API v2' , url : 'https://asia.streaming.bitquery.io/graphql' } ] ,
31+ ] )
32+ } ] ,
33+ ] )
34+
35+ const findRegionAndApiByUrl = ( url = '' ) => {
36+ for ( const [ regionKey , region ] of ENDPOINTS_MAP ) {
37+ for ( const [ apiKey , def ] of region . endpoints ) {
38+ if ( def . url === url ) return { region : regionKey , api : apiKey }
39+ }
40+ }
41+ return { region : undefined , api : undefined }
42+ }
43+
44+ const buildUrl = ( regionKey , apiKey ) => {
45+ const region = ENDPOINTS_MAP . get ( regionKey )
46+ if ( ! region ) return ''
47+ const def = region . endpoints . get ( apiKey )
48+ return def ?. url || ''
49+ }
50+
1851const ToolbarComponent = observer ( ( {
19- queryEditor,
20- variablesEditor,
21- headersEditor,
22- docExplorerOpen,
23- toggleDocExplorer,
24- toggleCodeSnippet,
25- toggleSqlQuery,
26- sqlQueryOpen,
27- codeSnippetOpen,
28- number
29- } ) => {
52+ queryEditor,
53+ variablesEditor,
54+ headersEditor,
55+ docExplorerOpen,
56+ toggleDocExplorer,
57+ toggleCodeSnippet,
58+ toggleSqlQuery,
59+ sqlQueryOpen,
60+ codeSnippetOpen,
61+ number
62+ } ) => {
3063 const {
3164 currentQuery, updateQuery, setQuery,
3265 queryIsTransfered, setQueryIsTransfered, queryJustSaved, query
@@ -38,6 +71,8 @@ const ToolbarComponent = observer(({
3871 const [ mode , setMode ] = useState ( false )
3972 const [ dashboardOwner , setOwner ] = useState ( false )
4073 const [ selectedUrl , setSelectedUrl ] = useState ( '' )
74+ const [ selectedRegion , setSelectedRegion ] = useState ( 'europe' )
75+ const [ selectedApi , setSelectedApi ] = useState ( 'v1' )
4176
4277 useEffect ( ( ) => {
4378 if ( ( ( currentQuery . layout && ( currentQuery . account_id === user ?. id ) ) || ! currentQuery . id ) || ! currentQuery . layout ) {
@@ -49,26 +84,11 @@ const ToolbarComponent = observer(({
4984 } , [ user , JSON . stringify ( currentQuery ) ] )
5085
5186 useEffect ( ( ) => {
52- switch ( currentQuery . endpoint_url ) {
53- case 'https://graphql.bitquery.io' :
54- setSelectedUrl ( 'https://graphql.bitquery.io' )
55- break
56- case 'https://streaming.bitquery.io/graphql' :
57- setSelectedUrl ( 'https://streaming.bitquery.io/graphql' )
58- break
59- case 'https://streaming.bitquery.io/eap' :
60- setSelectedUrl ( 'https://streaming.bitquery.io/eap' )
61- break
62- case 'asia.graphql.bitquery.io' :
63- setSelectedUrl ( 'asia.graphql.bitquery.io' )
64- break
65- case 'asia.streaming.bitquery.io' :
66- setSelectedUrl ( 'asia.streaming.bitquery.io' )
67- break
68- default :
69- setSelectedUrl ( '' )
70- break
71- }
87+ const url = currentQuery . endpoint_url ?? ''
88+ setSelectedUrl ( url )
89+ const { region, api } = findRegionAndApiByUrl ( url )
90+ setSelectedRegion ( region || 'europe' )
91+ setSelectedApi ( api || ( url ? 'v1' : 'other' ) )
7292 } , [ currentQuery . endpoint_url ] )
7393
7494 const handleInputURLChange = e => {
@@ -79,6 +99,46 @@ const ToolbarComponent = observer(({
7999 setSelectedUrl ( url )
80100 }
81101
102+ const handleRegionChange = e => {
103+ const region = e . target . value
104+ setSelectedRegion ( region )
105+
106+ const regionObj = ENDPOINTS_MAP . get ( region )
107+ let nextApi = selectedApi && regionObj ?. endpoints . has ( selectedApi ) ? selectedApi : Array . from ( regionObj ?. endpoints . keys ( ) || [ 'v1' ] ) [ 0 ]
108+
109+ const nextUrl = buildUrl ( region , nextApi )
110+ updateQuery ( { endpoint_url : nextUrl } , index )
111+ setSelectedUrl ( nextUrl )
112+ }
113+
114+ const getAllApis = ( ) => {
115+ const keys = new Set ( )
116+ for ( const [ , region ] of ENDPOINTS_MAP ) {
117+ for ( const [ apiKey ] of region . endpoints ) keys . add ( apiKey )
118+ }
119+ return Array . from ( keys )
120+ }
121+
122+ const handleApiChange = e => {
123+ const api = e . target . value
124+ setSelectedApi ( api )
125+ if ( api === 'other' ) {
126+ setSelectedUrl ( '' )
127+ updateQuery ( { endpoint_url : '' } , index )
128+ return
129+ }
130+ let region = selectedRegion
131+ if ( ! ENDPOINTS_MAP . get ( region ) ?. endpoints . has ( api ) ) {
132+ for ( const [ rk , r ] of ENDPOINTS_MAP ) {
133+ if ( r . endpoints . has ( api ) ) { region = rk ; break }
134+ }
135+ setSelectedRegion ( region )
136+ }
137+ const url = buildUrl ( region , api )
138+ setSelectedUrl ( url )
139+ updateQuery ( { endpoint_url : url } , index )
140+ }
141+
82142 const switchMode = ( ) => {
83143 setMode ( ! mode )
84144 updateQuery ( { isDraggable : ! currentQuery . isDraggable , isResizable : ! currentQuery . isResizable } , index )
@@ -214,49 +274,66 @@ const ToolbarComponent = observer(({
214274 visible = { ! ! currentQuery . graphqlQueryID || ! ! currentQuery . url }
215275 /> }
216276 < InputGroup className = "input-group-fix bitquery-inputUrl" >
277+ < Form . Control
278+ as = "select"
279+ onChange = { handleApiChange }
280+ value = { selectedApi }
281+ className = "drop-down-fix"
282+ style = { { flex : '0 0 80px' , maxWidth : 80 , minWidth : 80 , paddingRight : 8 } }
283+ >
284+ { getAllApis ( ) . map ( apiKey => (
285+ < option key = { apiKey } value = { apiKey } >
286+ { Array . from ( ENDPOINTS_MAP . values ( ) ) . find ( r => r . endpoints . has ( apiKey ) ) ?. endpoints . get ( apiKey ) . label }
287+ </ option >
288+ ) ) }
289+ < option value = "other" > Other...</ option >
290+ </ Form . Control >
291+
292+ { selectedApi !== 'other' && (
217293 < Form . Control
218294 as = "select"
219- onChange = { e => handleDropdownSelect ( e . target . value ) }
220- value = { selectedUrl }
295+ onChange = { handleRegionChange }
296+ value = { selectedRegion }
221297 className = "drop-down-fix"
298+ style = { { flex : '0 0 80px' , maxWidth : 80 , minWidth : 80 } }
222299 >
223- < option value = "https://graphql.bitquery.io" > API v1</ option >
224- < option value = "https://streaming.bitquery.io/graphql" > API v2</ option >
225- < option value = "https://streaming.bitquery.io/eap" > EAP</ option >
226- < option value = "asia.graphql.bitquery.io" > prod-graphql-v1</ option >
227- < option value = "asia.streaming.bitquery.io" > prod-graphql-v2</ option >
228- < option value = "" > Other...</ option >
300+ { Array . from ( ENDPOINTS_MAP ) . filter ( ( [ , r ] ) => r . endpoints . has ( selectedApi ) ) . map ( ( [ regionKey , region ] ) => (
301+ < option key = { regionKey } value = { regionKey } > { region . label } </ option >
302+ ) ) }
229303 </ Form . Control >
304+ ) }
305+
230306 < Form . Control
231307 id = "basic-url"
232308 aria-label = "endpoint-url"
233309 value = { currentQuery . endpoint_url ?? '' }
234310 onChange = { handleInputURLChange }
235311 className = "input-url-fix"
312+ placeholder = { selectedApi === 'other' ? 'Paste your endpoint URL here' : '' }
236313 />
237314 </ InputGroup >
238315 { user ?. id && query [ number ] . graphqlQueryID && < StatisticsButton number = { number } /> }
239316 { ( user ?. role === 'admin' || user ?. role === 'poweruser' ) &&
240317 < span aria-label = "SQL Query" onClick = { toggleSqlQuery } >
241- < SqlIcon
242- className = { "bitquery-little-btn" + ( sqlQueryOpen ? " active" : '' ) }
243- data-bs-toggle = "tooltip"
244- data-bs-placement = "top"
245- title = "SQL Query"
246- />
247- </ span > }
318+ < SqlIcon
319+ className = { "bitquery-little-btn" + ( sqlQueryOpen ? " active" : '' ) }
320+ data-bs-toggle = "tooltip"
321+ data-bs-placement = "top"
322+ title = "SQL Query"
323+ />
324+ </ span > }
248325 < span aria-label = "Documentation Explorer" onClick = { toggleDocExplorer } >
249- < DocsIcon
250- className = { "bitquery-little-btn" + ( docExplorerOpen ? " active" : '' ) }
251- data-bs-toggle = "tooltip"
252- data-bs-placement = "top"
253- title = "Documentation Explorer"
254- />
255- </ span >
326+ < DocsIcon
327+ className = { "bitquery-little-btn" + ( docExplorerOpen ? " active" : '' ) }
328+ data-bs-toggle = "tooltip"
329+ data-bs-placement = "top"
330+ title = "Documentation Explorer"
331+ />
332+ </ span >
256333 < span className = "d-flex align-items-center justify-content-center bitquery-little-btn"
257- aria-label = "Code Snippet" onClick = { toggleCodeSnippet } >
258- < i className = { "bi bi-code-slash" + ( codeSnippetOpen ? " active" : '' ) } />
259- </ span >
334+ aria-label = "Code Snippet" onClick = { toggleCodeSnippet } >
335+ < i className = { "bi bi-code-slash" + ( codeSnippetOpen ? " active" : '' ) } />
336+ </ span >
260337 </ div >
261338 </ div >
262339
0 commit comments