mirror of
https://github.com/graphql-python/graphene.git
synced 2025-04-25 03:43:42 +03:00
Improved graphene playground with router query params
This commit is contained in:
parent
3c308b90fa
commit
18b66bd8a2
|
@ -17,7 +17,7 @@
|
||||||
"copy-webpack-plugin": "^0.2.0",
|
"copy-webpack-plugin": "^0.2.0",
|
||||||
"es6-promise": "^3.0.2",
|
"es6-promise": "^3.0.2",
|
||||||
"extract-text-webpack-plugin": "^0.9.1",
|
"extract-text-webpack-plugin": "^0.9.1",
|
||||||
"gatsby": "^0.7.2",
|
"gatsby": "^0.7.3",
|
||||||
"graphiql": "^0.4.2",
|
"graphiql": "^0.4.2",
|
||||||
"graphql": "^0.4.13",
|
"graphql": "^0.4.13",
|
||||||
"jeet": "^6.1.2",
|
"jeet": "^6.1.2",
|
||||||
|
|
234
docs/playground/GraphenePlayground.js
Normal file
234
docs/playground/GraphenePlayground.js
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { RouteHandler, Link, State } from 'react-router';
|
||||||
|
import CodeMirror from 'codemirror';
|
||||||
|
import { graphql } from 'graphql';
|
||||||
|
import GraphiQL from 'graphiql';
|
||||||
|
import schema from './schema';
|
||||||
|
import pypyjs_vm from 'pypyjs';
|
||||||
|
|
||||||
|
import 'codemirror/mode/python/python';
|
||||||
|
import 'codemirror/addon/lint/lint';
|
||||||
|
import '../css/playground.styl';
|
||||||
|
|
||||||
|
if (typeof PUBLIC_PATH === "undefined") {
|
||||||
|
var PUBLIC_PATH = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
pypyjs_vm.rootURL = `${PUBLIC_PATH}/playground/lib/`;
|
||||||
|
pypyjs_vm.cacheKey = 'graphene';
|
||||||
|
|
||||||
|
CodeMirror.registerHelper('lint', 'python', function (text, options, editor) {
|
||||||
|
return (options.errors || []).map((error) => {
|
||||||
|
var tokens = editor.getLineTokens(error.line - 1);
|
||||||
|
tokens = tokens.filter((token, pos) => {
|
||||||
|
return !!token.type || token.string.trim().length > 0;
|
||||||
|
});
|
||||||
|
if (!tokens) return [];
|
||||||
|
return {
|
||||||
|
message: `${error.name}: ${error.message}`,
|
||||||
|
severity: 'error',
|
||||||
|
type: 'syntax',
|
||||||
|
from: CodeMirror.Pos(error.line - 1, tokens[0].start),
|
||||||
|
to: CodeMirror.Pos(error.line - 1, tokens[tokens.length-1].end),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function graphQLFetcher(graphQLParams) {
|
||||||
|
return graphql(schema, graphQLParams.query);
|
||||||
|
}
|
||||||
|
|
||||||
|
var default_interpreter;
|
||||||
|
class Playground extends React.Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {pypyjs: false, stdout: '', response:''};
|
||||||
|
}
|
||||||
|
stdout() {
|
||||||
|
console.log('stdout', arguments);
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
if (default_interpreter) {
|
||||||
|
this.pypy_interpreter = default_interpreter;
|
||||||
|
this.pypy_interpreter.stdout = this.stdout.bind(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.pypy_interpreter = new pypyjs_vm({
|
||||||
|
stdin: function(){},
|
||||||
|
stdout: this.stdout.bind(this),
|
||||||
|
stderr: function(){},
|
||||||
|
rootURL: `${PUBLIC_PATH}/playground/lib/`
|
||||||
|
});
|
||||||
|
default_interpreter = this.pypy_interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pypyjs = this.pypy_interpreter.ready().then(() => {
|
||||||
|
return this.pypy_interpreter.exec(`
|
||||||
|
import graphene
|
||||||
|
import js
|
||||||
|
from collections import OrderedDict
|
||||||
|
from graphql.core.execution.executor import Executor
|
||||||
|
from graphql.core.execution.middlewares.sync import SynchronousExecutionMiddleware
|
||||||
|
from graphql.core.error import GraphQLError, format_error
|
||||||
|
|
||||||
|
def get_wrapped(f):
|
||||||
|
if hasattr(f, 'func_closure') and f.func_closure:
|
||||||
|
return get_wrapped(f.func_closure[0].cell_contents)
|
||||||
|
return f
|
||||||
|
|
||||||
|
class TrackResolver(SynchronousExecutionMiddleware):
|
||||||
|
@staticmethod
|
||||||
|
def run_resolve_fn(resolver, original_resolver):
|
||||||
|
if resolver.func.__module__ == '__main__':
|
||||||
|
line = get_wrapped(resolver.func).resolver.func_code.co_firstlineno
|
||||||
|
js.globals.markLine(line-3)
|
||||||
|
return SynchronousExecutionMiddleware.run_resolve_fn(resolver, original_resolver)
|
||||||
|
|
||||||
|
__graphene_executor = Executor([TrackResolver()], map_type=OrderedDict)
|
||||||
|
`);
|
||||||
|
}).then(() => {
|
||||||
|
this.createSchema(this.props.initialSchema);
|
||||||
|
}).then(() => {
|
||||||
|
this.setState({pypyjs: true, response:'"Execute the query for see the results"'});
|
||||||
|
});
|
||||||
|
|
||||||
|
window.markLine = (lineNo) => {
|
||||||
|
this.markLine(lineNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editor = CodeMirror(ReactDOM.findDOMNode(this.refs.schemaCode), {
|
||||||
|
value: this.props.initialSchema,
|
||||||
|
mode: "python",
|
||||||
|
theme: "graphene",
|
||||||
|
lineNumbers: true,
|
||||||
|
tabSize: 4,
|
||||||
|
indentUnit: 4,
|
||||||
|
gutters: ["CodeMirror-linenumbers", "breakpoints"],
|
||||||
|
lint: {
|
||||||
|
errors: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.editor.on("change", this.onEditorChange.bind(this));
|
||||||
|
}
|
||||||
|
onEditorChange() {
|
||||||
|
if (this.changeTimeout) {
|
||||||
|
clearTimeout(this.changeTimeout);
|
||||||
|
}
|
||||||
|
if (this.props.onEditSchema) {
|
||||||
|
var value = this.editor.getValue();
|
||||||
|
if (value != this.props.initialSchema) {
|
||||||
|
this.props.onEditSchema(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeTimeout = setTimeout(() =>
|
||||||
|
this.updateSchema()
|
||||||
|
, 300);
|
||||||
|
}
|
||||||
|
updateSchema() {
|
||||||
|
this.createSchema(this.editor.getValue());
|
||||||
|
}
|
||||||
|
createSchema(code) {
|
||||||
|
if (this.previousCode == code) return;
|
||||||
|
console.log('createSchema');
|
||||||
|
this.validSchema = null;
|
||||||
|
this.pypyjs.then(() => {
|
||||||
|
return this.pypy_interpreter.exec(`
|
||||||
|
schema = None
|
||||||
|
${code}
|
||||||
|
assert schema, 'You have to define a schema'
|
||||||
|
`)
|
||||||
|
}).then(() => {
|
||||||
|
console.log('NO ERRORS');
|
||||||
|
this.removeErrors();
|
||||||
|
this.validSchema = true;
|
||||||
|
}, (err) => {
|
||||||
|
this.editor.options.lint.errors = [];
|
||||||
|
console.log('ERRORS', err);
|
||||||
|
this.logError(err);
|
||||||
|
this.validSchema = false;
|
||||||
|
}).then(this.updateGraphiQL.bind(this));
|
||||||
|
this.previousCode = code;
|
||||||
|
}
|
||||||
|
updateGraphiQL() {
|
||||||
|
if (this.validSchema) {
|
||||||
|
this.refs.graphiql.state.schema = null;
|
||||||
|
this.refs.graphiql.componentDidMount();
|
||||||
|
this.refs.graphiql.forceUpdate();
|
||||||
|
this.refs.graphiql.refs.docExplorer.forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logError(error) {
|
||||||
|
var lines = error.trace.split('\n');
|
||||||
|
var file_errors = lines.map((errorLine) => {
|
||||||
|
return errorLine.match(/File "<string>", line (\d+)/);
|
||||||
|
}).filter((x) => !! x);
|
||||||
|
if (!file_errors.length) return;
|
||||||
|
var line = parseInt(file_errors[file_errors.length-1][1]);
|
||||||
|
error.line = line-2;
|
||||||
|
if (error.name == "ImportError" && error.message == "No module named django") {
|
||||||
|
error.message = "Django is not supported yet in Playground editor";
|
||||||
|
}
|
||||||
|
this.editor.options.lint.errors.push(error);
|
||||||
|
CodeMirror.signal(this.editor, 'change', this.editor);
|
||||||
|
}
|
||||||
|
removeErrors() {
|
||||||
|
this.editor.options.lint.errors = [];
|
||||||
|
CodeMirror.signal(this.editor, 'change', this.editor);
|
||||||
|
}
|
||||||
|
fetcher (graphQLParams) {
|
||||||
|
if (!this.validSchema) {
|
||||||
|
return graphQLFetcher(arguments);
|
||||||
|
}
|
||||||
|
return this.execute(graphQLParams.query);
|
||||||
|
}
|
||||||
|
execute(query) {
|
||||||
|
// console.log('execute', query);
|
||||||
|
return this.pypyjs.then(() => {
|
||||||
|
var x = `
|
||||||
|
import json
|
||||||
|
result = __graphene_executor.execute(schema.schema, '''${query}''')
|
||||||
|
result_dict = {};
|
||||||
|
if result.errors:
|
||||||
|
result_dict['errors'] = [format_error(e) for e in result.errors]
|
||||||
|
if result.data:
|
||||||
|
result_dict['data'] = result.data
|
||||||
|
result_json = json.dumps(result_dict)
|
||||||
|
`;
|
||||||
|
return this.pypy_interpreter.exec(x)
|
||||||
|
}
|
||||||
|
).then(() =>
|
||||||
|
this.pypy_interpreter.get(`result_json`)
|
||||||
|
).then((data) => {
|
||||||
|
var json_data = JSON.parse(data);
|
||||||
|
return json_data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
markLine(lineNo) {
|
||||||
|
console.log(lineNo);
|
||||||
|
var hlLine = this.editor.addLineClass(lineNo, "text", "activeline");
|
||||||
|
// var mark = this.editor.markText({line: lineNo, ch: 0}, {line: lineNo, ch: 10}, {className: "called-function"});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.editor.removeLineClass(lineNo, "text", "activeline");
|
||||||
|
}, 1200);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="playground">
|
||||||
|
{!this.state.pypyjs?<div className="loading" />:null}
|
||||||
|
<div className="playground-schema">
|
||||||
|
<header className="playground-schema-header">
|
||||||
|
Schema
|
||||||
|
</header>
|
||||||
|
<div className="playground-schema-editor" ref="schemaCode" />
|
||||||
|
</div>
|
||||||
|
<div className="playground-graphiql">
|
||||||
|
<GraphiQL ref="graphiql" fetcher={this.fetcher.bind(this)} response={this.state.response} onEditQuery={this.props.onEditQuery} query={this.props.initialQuery}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Playground;
|
4
docs/playground/examples/hello.graphql
Normal file
4
docs/playground/examples/hello.graphql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
query {
|
||||||
|
hello
|
||||||
|
ping(to:"Peter")
|
||||||
|
}
|
13
docs/playground/examples/hello.schema.py
Normal file
13
docs/playground/examples/hello.schema.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
hello = graphene.String()
|
||||||
|
ping = graphene.String(to=graphene.String())
|
||||||
|
|
||||||
|
def resolve_hello(self, args, info):
|
||||||
|
return 'World'
|
||||||
|
|
||||||
|
def resolve_ping(self, args, info):
|
||||||
|
return 'Pinging {}'.format(args.get('to'))
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query)
|
|
@ -60,13 +60,6 @@ if (typeof FunctionPromise === "undefined") {
|
||||||
throw "FunctionPromise object not found";
|
throw "FunctionPromise object not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some extra goodies for nodejs.
|
|
||||||
if (typeof process !== 'undefined') {
|
|
||||||
if (Object.prototype.toString.call(process) === '[object process]') {
|
|
||||||
var fs = require("fs");
|
|
||||||
var path = require("path");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create functions for handling default stdio streams.
|
// Create functions for handling default stdio streams.
|
||||||
// These will be shared by all VM instances by default.
|
// These will be shared by all VM instances by default.
|
||||||
|
|
|
@ -1,258 +1,150 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import GraphenePlayground from './GraphenePlayground';
|
||||||
import { RouteHandler, Link, State } from 'react-router';
|
|
||||||
import CodeMirror from 'codemirror';
|
|
||||||
import { graphql } from 'graphql';
|
|
||||||
import GraphiQL from 'graphiql';
|
|
||||||
import schema from './schema';
|
|
||||||
import pypyjs_vm from 'pypyjs';
|
|
||||||
|
|
||||||
import 'codemirror/mode/python/python';
|
import _ from 'lodash';
|
||||||
import 'codemirror/addon/lint/lint';
|
|
||||||
import '../css/playground.styl';
|
|
||||||
|
|
||||||
if (typeof PUBLIC_PATH === "undefined") {
|
const DEFAULT_CACHE_KEY = 'default';
|
||||||
var PUBLIC_PATH = '';
|
|
||||||
|
function filterObject(object, callback, context) {
|
||||||
|
if (!object) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var result = {};
|
||||||
|
for (var name in object) {
|
||||||
|
if (hasOwnProperty.call(object, name) &&
|
||||||
|
callback.call(context, object[name], name, object)) {
|
||||||
|
result[name] = object[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pypyjs_vm.rootURL = `${PUBLIC_PATH}/playground/lib/`;
|
|
||||||
pypyjs_vm.cacheKey = 'graphene';
|
|
||||||
|
|
||||||
var baseCode = `import graphene
|
|
||||||
|
|
||||||
class Query(graphene.ObjectType):
|
|
||||||
hello = graphene.String()
|
|
||||||
ping = graphene.String(to=graphene.String())
|
|
||||||
|
|
||||||
def resolve_hello(self, args, info):
|
|
||||||
return 'World'
|
|
||||||
|
|
||||||
def resolve_ping(self, args, info):
|
|
||||||
return 'Pinging {}'.format(args.get('to'))
|
|
||||||
|
|
||||||
schema = graphene.Schema(query=Query)
|
|
||||||
`;
|
|
||||||
|
|
||||||
CodeMirror.registerHelper('lint', 'python', function (text, options, editor) {
|
|
||||||
return (options.errors || []).map((error) => {
|
|
||||||
var tokens = editor.getLineTokens(error.line - 1);
|
|
||||||
tokens = tokens.filter((token, pos) => {
|
|
||||||
return !!token.type || token.string.trim().length > 0;
|
|
||||||
});
|
|
||||||
if (!tokens) return [];
|
|
||||||
return {
|
|
||||||
message: `${error.name}: ${error.message}`,
|
|
||||||
severity: 'error',
|
|
||||||
type: 'syntax',
|
|
||||||
from: CodeMirror.Pos(error.line - 1, tokens[0].start),
|
|
||||||
to: CodeMirror.Pos(error.line - 1, tokens[tokens.length-1].end),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// function graphQLFetcher(graphQLParams) {
|
|
||||||
// return fetch('http://swapi.graphene-python.org/graphql', {
|
|
||||||
// method: 'post',
|
|
||||||
// headers: { 'Content-Type': 'application/json' },
|
|
||||||
// body: JSON.stringify(graphQLParams),
|
|
||||||
// }).then(response => response.json());
|
|
||||||
// }
|
|
||||||
function graphQLFetcher(graphQLParams) {
|
|
||||||
return graphql(schema, graphQLParams.query);
|
|
||||||
}
|
|
||||||
// var schema = null;
|
|
||||||
|
|
||||||
function syntaxError() {
|
|
||||||
var marker = document.createElement("div");
|
|
||||||
marker.style.color = "#822";
|
|
||||||
marker.innerHTML = "●";
|
|
||||||
return marker;
|
|
||||||
}
|
|
||||||
|
|
||||||
var default_interpreter;
|
|
||||||
class Playground extends React.Component {
|
class Playground extends React.Component {
|
||||||
constructor() {
|
componentWillMount() {
|
||||||
super();
|
var sourceWasInjected = false;
|
||||||
this.state = {pypyjs: false, stdout: '', response:''};
|
var queryParams = this.context.router.getCurrentQuery();
|
||||||
}
|
|
||||||
stdout() {
|
|
||||||
console.log('stdout', arguments);
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
|
||||||
if (default_interpreter) {
|
|
||||||
this.pypy_interpreter = default_interpreter;
|
|
||||||
this.pypy_interpreter.stdout = this.stdout.bind(this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.pypy_interpreter = new pypyjs_vm({
|
|
||||||
stdin: function(){},
|
|
||||||
stdout: this.stdout.bind(this),
|
|
||||||
stderr: function(){},
|
|
||||||
rootURL: `${PUBLIC_PATH}/playground/lib/`
|
|
||||||
});
|
|
||||||
default_interpreter = this.pypy_interpreter;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pypyjs = this.pypy_interpreter.ready().then(() => {
|
var {
|
||||||
return this.pypy_interpreter.exec(`
|
cacheKey,
|
||||||
import graphene
|
noCache,
|
||||||
import js
|
} = queryParams;
|
||||||
from collections import OrderedDict
|
noCache = (noCache !== undefined) && (noCache !== 'false');
|
||||||
from graphql.core.execution.executor import Executor
|
if (noCache) {
|
||||||
from graphql.core.execution.middlewares.sync import SynchronousExecutionMiddleware
|
cacheKey = undefined;
|
||||||
from graphql.core.error import GraphQLError, format_error
|
} else if (!cacheKey) {
|
||||||
|
cacheKey = DEFAULT_CACHE_KEY;
|
||||||
|
}
|
||||||
|
this.schemaCacheKey = `rp-${cacheKey}-schema`;
|
||||||
|
this.queryCacheKey = `rp-${cacheKey}-query`;
|
||||||
|
this.cacheKey = cacheKey;
|
||||||
|
|
||||||
def get_wrapped(f):
|
var initialSchema;
|
||||||
if hasattr(f, 'func_closure') and f.func_closure:
|
var initialQuery;
|
||||||
return get_wrapped(f.func_closure[0].cell_contents)
|
var storedSchema = localStorage.getItem(this.schemaCacheKey);
|
||||||
return f
|
var storedQuery = localStorage.getItem(this.queryCacheKey);
|
||||||
|
if (noCache) {
|
||||||
class TrackResolver(SynchronousExecutionMiddleware):
|
// Use case #1
|
||||||
@staticmethod
|
// We use the noCache param to force a playground to have certain contents.
|
||||||
def run_resolve_fn(resolver, original_resolver):
|
// eg. static example apps
|
||||||
if resolver.func.__module__ == '__main__':
|
initialSchema = queryParams.schema || '';
|
||||||
line = get_wrapped(resolver.func).resolver.func_code.co_firstlineno
|
initialQuery = queryParams.query || '';
|
||||||
js.globals.markLine(line-3)
|
sourceWasInjected = true;
|
||||||
return SynchronousExecutionMiddleware.run_resolve_fn(resolver, original_resolver)
|
queryParams = {};
|
||||||
|
} else if (cacheKey === DEFAULT_CACHE_KEY) {
|
||||||
__graphene_executor = Executor([TrackResolver()], map_type=OrderedDict)
|
// Use case #2
|
||||||
`);
|
// The user loaded the playground without a custom cache key.
|
||||||
}).then(() => {
|
// Allow code injection via the URL
|
||||||
this.createSchema(baseCode);
|
// OR load code from localStorage
|
||||||
}).then(() => {
|
// OR prime the playground with some default 'hello world' code
|
||||||
this.setState({pypyjs: true, response:'"Execute the query for see the results"'});
|
if (queryParams.schema != null) {
|
||||||
});
|
initialSchema = queryParams.schema;
|
||||||
|
sourceWasInjected = queryParams.schema !== storedSchema;
|
||||||
window.markLine = (lineNo) => {
|
} else if (storedSchema != null) {
|
||||||
this.markLine(lineNo);
|
initialSchema = storedSchema;
|
||||||
|
} else {
|
||||||
|
initialSchema = require('!raw!./examples/hello.schema.py');
|
||||||
|
}
|
||||||
|
if (queryParams.query != null) {
|
||||||
|
initialQuery = queryParams.query;
|
||||||
|
sourceWasInjected = queryParams.query !== storedQuery;
|
||||||
|
} else if (storedQuery != null) {
|
||||||
|
initialQuery = storedQuery;
|
||||||
|
} else {
|
||||||
|
initialQuery = require('!raw!./examples/hello.graphql');
|
||||||
|
}
|
||||||
|
queryParams = filterObject({
|
||||||
|
schema: queryParams.schema,
|
||||||
|
query: queryParams.query,
|
||||||
|
}, v => v !== undefined);
|
||||||
|
} else if (cacheKey) {
|
||||||
|
// Use case #3
|
||||||
|
// Custom cache keys are useful in cases where you want to embed a playground
|
||||||
|
// that features both custom boilerplate code AND saves the developer's
|
||||||
|
// progress, without overwriting the default code cache. eg. a tutorial.
|
||||||
|
if (storedSchema != null) {
|
||||||
|
initialSchema = storedSchema;
|
||||||
|
} else {
|
||||||
|
initialSchema = queryParams[`schema_${cacheKey}`];
|
||||||
|
if (initialSchema != null) {
|
||||||
|
sourceWasInjected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (storedQuery != null) {
|
||||||
|
initialQuery = storedQuery;
|
||||||
|
} else {
|
||||||
|
initialQuery = queryParams[`query_${cacheKey}`];
|
||||||
|
if (initialQuery != null) {
|
||||||
|
sourceWasInjected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queryParams = {};
|
||||||
}
|
}
|
||||||
|
this.changeParams(queryParams);
|
||||||
this.editor = CodeMirror(ReactDOM.findDOMNode(this.refs.schemaCode), {
|
this.state = {initialSchema, initialQuery, sourceWasInjected};
|
||||||
value: baseCode,
|
this.queryParams = queryParams;
|
||||||
mode: "python",
|
|
||||||
theme: "graphene",
|
|
||||||
lineNumbers: true,
|
|
||||||
tabSize: 4,
|
|
||||||
indentUnit: 4,
|
|
||||||
gutters: ["CodeMirror-linenumbers", "breakpoints"],
|
|
||||||
lint: {
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.editor.on("change", this.onEditorChange.bind(this));
|
|
||||||
}
|
}
|
||||||
onEditorChange() {
|
shouldComponentUpdate() {
|
||||||
if (this.changeTimeout) {
|
return false;
|
||||||
clearTimeout(this.changeTimeout);
|
|
||||||
}
|
|
||||||
this.changeTimeout = setTimeout(() =>
|
|
||||||
this.updateSchema()
|
|
||||||
, 300);
|
|
||||||
}
|
}
|
||||||
updateSchema() {
|
changeParams(queryParams) {
|
||||||
this.createSchema(this.editor.getValue());
|
var router = this.context.router;
|
||||||
}
|
var routeName = router.getCurrentPathname();
|
||||||
createSchema(code) {
|
var params = router.getCurrentParams();
|
||||||
if (this.previousCode == code) return;
|
queryParams = _.mapValues(queryParams, encodeURIComponent);
|
||||||
console.log('createSchema');
|
router.replaceWith(routeName, params, queryParams);
|
||||||
this.validSchema = null;
|
|
||||||
this.pypyjs.then(() => {
|
|
||||||
return this.pypy_interpreter.exec(`
|
|
||||||
schema = None
|
|
||||||
${code}
|
|
||||||
assert schema, 'You have to define a schema'
|
|
||||||
`)
|
|
||||||
}).then(() => {
|
|
||||||
console.log('NO ERRORS');
|
|
||||||
this.removeErrors();
|
|
||||||
this.validSchema = true;
|
|
||||||
}, (err) => {
|
|
||||||
this.editor.options.lint.errors = [];
|
|
||||||
console.log('ERRORS', err);
|
|
||||||
this.logError(err);
|
|
||||||
this.validSchema = false;
|
|
||||||
// this.editor.setGutterMarker(5, "breakpoints", syntaxError());
|
|
||||||
}).then(this.updateGraphiQL.bind(this));
|
|
||||||
this.previousCode = code;
|
|
||||||
}
|
|
||||||
updateGraphiQL() {
|
|
||||||
if (this.validSchema) {
|
|
||||||
this.refs.graphiql.state.schema = null;
|
|
||||||
this.refs.graphiql.componentDidMount();
|
|
||||||
this.refs.graphiql.forceUpdate();
|
|
||||||
this.refs.graphiql.refs.docExplorer.forceUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logError(error) {
|
|
||||||
var lines = error.trace.split('\n');
|
|
||||||
var file_errors = lines.map((errorLine) => {
|
|
||||||
return errorLine.match(/File "<string>", line (\d+)/);
|
|
||||||
}).filter((x) => !! x);
|
|
||||||
if (!file_errors.length) return;
|
|
||||||
var line = parseInt(file_errors[file_errors.length-1][1]);
|
|
||||||
error.line = line-2;
|
|
||||||
if (error.name == "ImportError" && error.message == "No module named django") {
|
|
||||||
error.message = "Django is not supported yet in Playground editor";
|
|
||||||
}
|
|
||||||
this.editor.options.lint.errors.push(error);
|
|
||||||
CodeMirror.signal(this.editor, 'change', this.editor);
|
|
||||||
}
|
|
||||||
removeErrors() {
|
|
||||||
this.editor.options.lint.errors = [];
|
|
||||||
CodeMirror.signal(this.editor, 'change', this.editor);
|
|
||||||
}
|
|
||||||
fetcher (graphQLParams) {
|
|
||||||
if (!this.validSchema) {
|
|
||||||
return graphQLFetcher(arguments);
|
|
||||||
}
|
|
||||||
return this.execute(graphQLParams.query);
|
|
||||||
}
|
|
||||||
execute(query) {
|
|
||||||
// console.log('execute', query);
|
|
||||||
return this.pypyjs.then(() => {
|
|
||||||
var x = `
|
|
||||||
import json
|
|
||||||
result = __graphene_executor.execute(schema.schema, '''${query}''')
|
|
||||||
result_dict = {};
|
|
||||||
if result.errors:
|
|
||||||
result_dict['errors'] = [format_error(e) for e in result.errors]
|
|
||||||
if result.data:
|
|
||||||
result_dict['data'] = result.data
|
|
||||||
result_json = json.dumps(result_dict)
|
|
||||||
`;
|
|
||||||
return this.pypy_interpreter.exec(x)
|
|
||||||
}
|
|
||||||
).then(() =>
|
|
||||||
this.pypy_interpreter.get(`result_json`)
|
|
||||||
).then((data) => {
|
|
||||||
var json_data = JSON.parse(data);
|
|
||||||
return json_data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
markLine(lineNo) {
|
|
||||||
console.log(lineNo);
|
|
||||||
var hlLine = this.editor.addLineClass(lineNo, "text", "activeline");
|
|
||||||
// var mark = this.editor.markText({line: lineNo, ch: 0}, {line: lineNo, ch: 10}, {className: "called-function"});
|
|
||||||
setTimeout(() => {
|
|
||||||
this.editor.removeLineClass(lineNo, "text", "activeline");
|
|
||||||
}, 1200);
|
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (<GraphenePlayground
|
||||||
<div className="playground">
|
initialSchema={this.state.initialSchema}
|
||||||
{!this.state.pypyjs?<div className="loading" />:null}
|
initialQuery={this.state.initialQuery}
|
||||||
<div className="playground-schema">
|
onEditSchema={(source) => {
|
||||||
<header className="playground-schema-header">
|
localStorage.setItem(this.schemaCacheKey, source);
|
||||||
Schema
|
if (this.cacheKey === DEFAULT_CACHE_KEY) {
|
||||||
</header>
|
this.queryParams.schema = source;
|
||||||
<div className="playground-schema-editor" ref="schemaCode" />
|
if (!this.queryParams.query) {
|
||||||
</div>
|
this.queryParams.query = this.state.initialQuery;
|
||||||
<div className="playground-graphiql">
|
}
|
||||||
<GraphiQL ref="graphiql" fetcher={this.fetcher.bind(this)} response={this.state.response} />
|
this.changeParams(this.queryParams);
|
||||||
</div>
|
}
|
||||||
</div>
|
}}
|
||||||
);
|
onEditQuery={(source) => {
|
||||||
|
localStorage.setItem(this.queryCacheKey, source);
|
||||||
|
if (this.cacheKey === DEFAULT_CACHE_KEY) {
|
||||||
|
this.queryParams.query = source;
|
||||||
|
if (!this.queryParams.schema) {
|
||||||
|
this.queryParams.schema = this.state.initialSchema;
|
||||||
|
}
|
||||||
|
this.changeParams(this.queryParams);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Playground.contextTypes = {
|
||||||
|
router: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Playground;
|
module.exports = Playground;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user