Add graphiql-explorer to canvas' graphiql instance

The graphiql-explorer makes it easy to explore the schema and build
queries simply by checking the boxes next to fields from the schema

test plan:
  - /graphiql still works as expected, but includes the explorer panel
  - canvas features that leverage graphql still work as expected
    (since the version of the graphql js client was updated)

Change-Id: Ief625c6fb59e4e32e23a177f3b566aae271ab108
Reviewed-on: https://gerrit.instructure.com/181586
Tested-by: Jenkins
Reviewed-by: Carl Kibler <ckibler@instructure.com>
QA-Review: Carl Kibler <ckibler@instructure.com>
Product-Review: Ed Schiebel <eschiebel@instructure.com>
This commit is contained in:
Ed Schiebel 2019-02-13 10:29:15 -05:00
parent df1e123392
commit 0f6321312c
5 changed files with 180 additions and 21 deletions

View File

@ -18,18 +18,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import GraphiQL from 'graphiql'
import axios from 'axios'
import 'graphiql/graphiql.css'
import GraphiQLApp from '../graphiql/GraphiQLApp'
function fetcher (params) {
return axios.post(
'/api/graphql',
JSON.stringify(params),
{
headers: {'Content-Type': 'application/json'},
}
).then(({data}) => data)
}
ReactDOM.render(<GraphiQL fetcher={fetcher} />, document.getElementById('graphiql'))
ReactDOM.render(<GraphiQLApp/>, document.getElementById('graphiql'))

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import GraphiQLExplorer from 'graphiql-explorer';
// makeDefaultArg and getDefulatScalarArgValue
// are used to fill in the default argument for
// fields that require one. To see a more complete
// implementation, should we decide to do something
// more deluxe, see
// https://github.com/OneGraph/graphiql-explorer-example/blob/master/src/CustomArgs.js
export function makeDefaultArg(_parentField, _arg) {
return false;
}
export function getDefaultScalarArgValue(parentField, arg, argType) {
// so there's a good chance we get something, or nothing,
// but probably not an error
if (argType.name === 'ID') {
return {kind: 'StringValue', value: '1'}
}
return GraphiQLExplorer.defaultValue(argType);
}

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2018 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import GraphiQL from 'graphiql'
import GraphiQLExplorer from 'graphiql-explorer'
import {getIntrospectionQuery, buildClientSchema} from 'graphql';
import axios from 'axios'
import 'graphiql/graphiql.css'
import {makeDefaultArg, getDefaultScalarArgValue} from './CustomArgs';
import StorageAPI from 'graphiql/dist/utility/StorageAPI'
function fetcher (params) {
return axios.post(
'/api/graphql',
JSON.stringify(params),
{
headers: {'Content-Type': 'application/json'},
}
).then(({data}) => data)
}
const DEFAULT_QUERY = `{
allCourses {
_id,
name
}
}`
export default class GraphiQLApp extends React.Component {
constructor(props) {
super(props)
this._graphql = null
this._storage = new StorageAPI()
// "true" or missing => open. explicit "false" => closed
const explorerPaneOpen = this._storage.get('explorerPaneOpen') !== 'false'
this.state = {
schema: null,
query: DEFAULT_QUERY,
explorerIsOpen: explorerPaneOpen
}
}
componentDidMount() {
return fetcher({
query: getIntrospectionQuery(),
}).then(result => {
this.setState({
schema: buildClientSchema(result.data)
})
})
}
_handleEditQuery = (query) => {
this.setState({query})
}
_handleToggleExplorer = () => {
this.setState((state, _props) => {
const isOpen = !state.explorerIsOpen
this._storage.set('explorerPaneOpen', isOpen.toString())
return {explorerIsOpen: isOpen}
})
}
render() {
const {query, schema, explorerIsOpen} = this.state
return (
<div className="graphiql-container">
<GraphiQLExplorer
schema={schema}
query={query}
onEdit={this._handleEditQuery}
explorerIsOpen={explorerIsOpen}
onToggleExplorer={this._handleToggleExplorer}
getDefaultScalarArgValue={getDefaultScalarArgValue}
makeDefaultArg={makeDefaultArg}
/>
<GraphiQL
ref={ref => {this._graphiql = ref}}
fetcher={fetcher}
schema={schema}
query={query}
onEditQuery={this._handleEditQuery}
>
<GraphiQL.Toolbar>
<GraphiQL.Button
onClick={() => this._graphiql.handlePrettifyQuery()}
label="Prettify"
title="Prettify Query (Shift-Ctrl-P)"
/>
<GraphiQL.Button
onClick={() => this._graphiql.handleToggleHistory()}
label="History"
title="Show History"
/>
<GraphiQL.Button
onClick={this._handleToggleExplorer}
label="Explorer"
title="Toggle Explorer"
/>
</GraphiQL.Toolbar>
</GraphiQL>
</div>
)
}
}

View File

@ -63,7 +63,8 @@
"formdata-polyfill": "^3.0.9",
"fullcalendar": "https://github.com/instructure/fullcalendar.git#1108dd1c991a029ec6fd7de3337737ec5295ba97",
"graphiql": "^0.11.2",
"graphql": "^0.13.2",
"graphiql-explorer": "^0.3.6",
"graphql": "^14",
"graphql-tag": "^2.8.0",
"i18n-js": "^3",
"ic-ajax": "~2.0.1",

View File

@ -8914,6 +8914,11 @@ graceful-fs@~2.0.3:
dependencies:
raphael "^2.1.4"
graphiql-explorer@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/graphiql-explorer/-/graphiql-explorer-0.3.6.tgz#4696815ba81e63d6bdaf9962427038db44cec0d7"
integrity sha512-jTPtwxPaZUjZ6zlFIfbdpLTnPj80/FUFBC9Ij19DUIZ3OfL4E+27dMF5UdYLP+7vpqZixCcT4bP611XZlvYIxg==
graphiql@^0.11.2:
version "0.11.11"
resolved "https://registry.yarnpkg.com/graphiql/-/graphiql-0.11.11.tgz#eeaf9a38927dbe8c6ecbf81e700735e16ec50e71"
@ -9005,12 +9010,12 @@ graphql-tag@^2.8.0:
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.0.tgz#87da024be863e357551b2b8700e496ee2d4353ae"
integrity sha512-9FD6cw976TLLf9WYIUPCaaTpniawIjHWZSwIRZSjrfufJamcXbVVYfN2TWvJYbw0Xf2JjYbl1/f2+wDnBVw3/w==
graphql@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270"
integrity sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==
graphql@^14:
version "14.1.1"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.1.1.tgz#d5d77df4b19ef41538d7215d1e7a28834619fac0"
integrity sha512-C5zDzLqvfPAgTtP8AUPIt9keDabrdRAqSWjj2OPRKrKxI9Fb65I36s1uCs1UUBFnSWTdO7hyHi7z1ZbwKMKF6Q==
dependencies:
iterall "^1.2.1"
iterall "^1.2.2"
growl@1.10.5:
version "1.10.5"
@ -10922,7 +10927,7 @@ istanbul@^0.4.0:
which "^1.1.1"
wordwrap "^1.0.0"
iterall@^1.2.1:
iterall@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==