@@ -7,6 +7,39 @@ import './postgraphiql.css';
77import { buildClientSchema , introspectionQuery , isType , GraphQLObjectType } from 'graphql' ;
88import { SubscriptionClient } from 'subscriptions-transport-ws' ;
99
10+ const defaultQuery = `\
11+ # Welcome to PostGraphile's built-in GraphiQL IDE
12+ #
13+ # GraphiQL is an in-browser tool for writing, validating, and
14+ # testing GraphQL queries.
15+ #
16+ # Type queries into this side of the screen, and you will see intelligent
17+ # typeaheads aware of the current GraphQL type schema and live syntax and
18+ # validation errors highlighted within the text.
19+ #
20+ # GraphQL queries typically start with a "{" character. Lines that starts
21+ # with a # are ignored.
22+ #
23+ # An example GraphQL query might look like:
24+ #
25+ # {
26+ # field(arg: "value") {
27+ # subField
28+ # }
29+ # }
30+ #
31+ # Keyboard shortcuts:
32+ #
33+ # Prettify Query: Shift-Ctrl-P (or press the prettify button above)
34+ #
35+ # Merge Query: Shift-Ctrl-M (or press the merge button above)
36+ #
37+ # Run Query: Ctrl-Enter (or press the play button above)
38+ #
39+ # Auto Complete: Ctrl-Space (or just start typing)
40+ #
41+ ` ;
42+
1043const isSubscription = ( { query } ) =>
1144 parse ( query ) . definitions . some (
1245 definition =>
@@ -31,49 +64,6 @@ const isValidJSON = json => {
3164 }
3265} ;
3366
34- /**
35- * The GraphiQL Explorer sidebar.
36- */
37- class ExplorerWrapper extends React . PureComponent {
38- state = {
39- query : '' ,
40- } ;
41- componentDidMount ( ) {
42- const graphiql = this . props . graphiql ;
43- // Extract query from the graphiql ref
44- if ( graphiql ) {
45- this . setState ( { query : graphiql . state . query } ) ;
46- }
47- // Set onEditQuery in the parent so that we can be notified of query changes
48- this . props . setOnEditQuery ( query => this . setState ( { query } ) ) ;
49- }
50-
51- componentDidUpdate ( prevProps ) {
52- if ( ! prevProps . graphiql && this . props . graphiql ) {
53- // Extract query from the graphiql ref
54- this . setState ( { query : this . props . graphiql . state . query } ) ;
55- }
56- }
57-
58- _onEditQuery = query => {
59- const graphiql = this . props . graphiql ;
60- if ( graphiql ) {
61- graphiql . handleEditQuery ( query ) ;
62- }
63- } ;
64- render ( ) {
65- return (
66- < GraphiQLExplorer
67- schema = { this . props . schema }
68- query = { this . state . query }
69- onEdit = { this . _onEditQuery }
70- explorerIsOpen = { this . props . explorerIsOpen }
71- onToggleExplorer = { this . props . onToggleExplorer }
72- />
73- ) ;
74- }
75- }
76-
7767const l = window . location ;
7868const websocketUrl = POSTGRAPHILE_CONFIG . graphqlUrl . match ( / ^ h t t p s ? : / )
7969 ? POSTGRAPHILE_CONFIG . graphqlUrl . replace ( / ^ h t t p / , 'ws' )
@@ -93,6 +83,7 @@ class PostGraphiQL extends React.PureComponent {
9383 // Our GraphQL schema which GraphiQL will use to do its intelligence
9484 // stuffs.
9585 schema : null ,
86+ query : '' ,
9687 showHeaderEditor : false ,
9788 headersText : '{\n"Authorization": null\n}\n' ,
9889 headersTextValid : true ,
@@ -102,6 +93,10 @@ class PostGraphiQL extends React.PureComponent {
10293 POSTGRAPHILE_CONFIG . enhanceGraphiql && POSTGRAPHILE_CONFIG . subscriptions ? 'pending' : null ,
10394 } ;
10495
96+ _onEditQuery = query => {
97+ this . setState ( { query } ) ;
98+ } ;
99+
105100 subscriptionsClient =
106101 POSTGRAPHILE_CONFIG . enhanceGraphiql && POSTGRAPHILE_CONFIG . subscriptions
107102 ? new SubscriptionClient ( websocketUrl , {
@@ -191,6 +186,13 @@ class PostGraphiQL extends React.PureComponent {
191186 // Store our event source so we can unsubscribe later.
192187 this . _eventSource = eventSource ;
193188 }
189+ const graphiql = this . graphiql ;
190+ this . setState ( { query : graphiql . _storage . get ( 'query' ) || defaultQuery } ) ;
191+ const editor = graphiql . getQueryEditor ( ) ;
192+ editor . setOption ( 'extraKeys' , {
193+ ...( editor . options . extraKeys || { } ) ,
194+ 'Shift-Alt-LeftClick' : this . _handleInspectOperation ,
195+ } ) ;
194196 }
195197
196198 componentWillUnmount ( ) {
@@ -200,6 +202,59 @@ class PostGraphiQL extends React.PureComponent {
200202 this . _eventSource = null ;
201203 }
202204
205+ _handleInspectOperation = ( cm , mousePos ) => {
206+ const parsedQuery = parse ( this . state . query || '' ) ;
207+
208+ if ( ! parsedQuery ) {
209+ console . error ( "Couldn't parse query document" ) ;
210+ return null ;
211+ }
212+
213+ var token = cm . getTokenAt ( mousePos ) ;
214+ var start = { line : mousePos . line , ch : token . start } ;
215+ var end = { line : mousePos . line , ch : token . end } ;
216+ var relevantMousePos = {
217+ start : cm . indexFromPos ( start ) ,
218+ end : cm . indexFromPos ( end ) ,
219+ } ;
220+
221+ var position = relevantMousePos ;
222+
223+ var def = parsedQuery . definitions . find ( definition => {
224+ if ( ! definition . loc ) {
225+ console . log ( 'Missing location information for definition' ) ;
226+ return false ;
227+ }
228+
229+ const { start, end } = definition . loc ;
230+ return start <= position . start && end >= position . end ;
231+ } ) ;
232+
233+ if ( ! def ) {
234+ console . error ( 'Unable to find definition corresponding to mouse position' ) ;
235+ return null ;
236+ }
237+
238+ var operationKind =
239+ def . kind === 'OperationDefinition'
240+ ? def . operation
241+ : def . kind === 'FragmentDefinition'
242+ ? 'fragment'
243+ : 'unknown' ;
244+
245+ var operationName =
246+ def . kind === 'OperationDefinition' && ! ! def . name
247+ ? def . name . value
248+ : def . kind === 'FragmentDefinition' && ! ! def . name
249+ ? def . name . value
250+ : 'unknown' ;
251+
252+ var selector = `.graphiql-explorer-root #${ operationKind } -${ operationName } ` ;
253+
254+ var el = document . querySelector ( selector ) ;
255+ el && el . scrollIntoView ( ) ;
256+ } ;
257+
203258 cancelSubscription = ( ) => {
204259 if ( this . activeSubscription !== null ) {
205260 this . activeSubscription . unsubscribe ( ) ;
@@ -522,13 +577,18 @@ class PostGraphiQL extends React.PureComponent {
522577 ) ;
523578 }
524579
580+ setGraphiqlRef = ref => {
581+ if ( ! ref ) {
582+ return ;
583+ }
584+ this . graphiql = ref ;
585+ this . setState ( { mounted : true } ) ;
586+ } ;
587+
525588 render ( ) {
526589 const { schema } = this . state ;
527590 const sharedProps = {
528- ref : ref => {
529- this . setState ( { graphiql : ref } ) ;
530- this . graphiql = ref ;
531- } ,
591+ ref : this . setGraphiqlRef ,
532592 schema : schema ,
533593 fetcher : this . fetcher ,
534594 } ;
@@ -537,14 +597,17 @@ class PostGraphiQL extends React.PureComponent {
537597 } else {
538598 return (
539599 < div className = "postgraphiql-container graphiql-container" >
540- < ExplorerWrapper
600+ < GraphiQLExplorer
541601 schema = { schema }
542- graphiql = { this . state . graphiql }
543- setOnEditQuery = { onEditQuery => this . setState ( { onEditQuery } ) }
602+ query = { this . state . query }
603+ onEdit = { this . _onEditQuery }
604+ onRunOperation = { operationName => this . graphiql . handleRunQuery ( operationName ) }
544605 explorerIsOpen = { this . state . explorerIsOpen }
545606 onToggleExplorer = { this . handleToggleExplorer }
607+ //getDefaultScalarArgValue={getDefaultScalarArgValue}
608+ //makeDefaultArg={makeDefaultArg}
546609 />
547- < GraphiQL onEditQuery = { this . state . onEditQuery } { ...sharedProps } >
610+ < GraphiQL onEditQuery = { this . _onEditQuery } query = { this . state . query } { ...sharedProps } >
548611 < GraphiQL . Logo >
549612 < div style = { { display : 'flex' , alignItems : 'center' } } >
550613 < div >
0 commit comments