2015-11-27 10:50:37 +03:00
|
|
|
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';
|
2015-11-28 10:48:48 +03:00
|
|
|
import pypyjs_vm from 'pypyjs';
|
2015-11-27 10:50:37 +03:00
|
|
|
|
|
|
|
import 'codemirror/mode/python/python';
|
|
|
|
import '../css/playground.styl';
|
|
|
|
|
2015-11-28 10:48:48 +03:00
|
|
|
if (typeof PUBLIC_PATH === "undefined") {
|
|
|
|
var PUBLIC_PATH = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
pypyjs_vm.rootURL = `${PUBLIC_PATH}/playground/lib/`;
|
|
|
|
pypyjs_vm.cacheKey = 'graphene';
|
|
|
|
|
2015-11-27 10:50:37 +03:00
|
|
|
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)
|
|
|
|
`;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2015-11-28 10:48:48 +03:00
|
|
|
function syntaxError() {
|
|
|
|
var marker = document.createElement("div");
|
|
|
|
marker.style.color = "#822";
|
|
|
|
marker.innerHTML = "●";
|
|
|
|
return marker;
|
|
|
|
}
|
|
|
|
|
|
|
|
var default_interpreter;
|
2015-11-27 10:50:37 +03:00
|
|
|
class Playground extends React.Component {
|
2015-11-28 10:48:48 +03:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.state = {pypyjs: false, stdout: '', response:''};
|
|
|
|
}
|
|
|
|
stdout() {
|
|
|
|
console.log('stdout', arguments);
|
|
|
|
}
|
2015-11-27 10:50:37 +03:00
|
|
|
componentDidMount() {
|
2015-11-28 10:48:48 +03:00
|
|
|
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(() => {
|
2015-11-29 00:05:34 +03:00
|
|
|
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)
|
|
|
|
`);
|
2015-11-28 10:48:48 +03:00
|
|
|
}).then(() => {
|
|
|
|
this.createSchema(baseCode);
|
|
|
|
}).then(() => {
|
|
|
|
this.setState({pypyjs: true, response:'"Execute the query for see the results"'});
|
|
|
|
});
|
|
|
|
|
|
|
|
window.markLine = (lineNo) => {
|
|
|
|
this.markLine(lineNo);
|
|
|
|
}
|
|
|
|
|
2015-11-27 10:50:37 +03:00
|
|
|
this.editor = CodeMirror(ReactDOM.findDOMNode(this.refs.schemaCode), {
|
|
|
|
value: baseCode,
|
|
|
|
mode: "python",
|
2015-11-28 10:48:48 +03:00
|
|
|
theme: "graphene",
|
|
|
|
// lineNumbers: true,
|
2015-11-27 10:50:37 +03:00
|
|
|
tabSize: 4,
|
2015-11-28 10:48:48 +03:00
|
|
|
indentUnit: 4,
|
|
|
|
gutters: ["CodeMirror-linenumbers", "breakpoints"]
|
|
|
|
});
|
|
|
|
this.editor.on("change", this.onEditorChange.bind(this));
|
|
|
|
}
|
|
|
|
onEditorChange() {
|
|
|
|
if (this.changeTimeout) {
|
|
|
|
clearTimeout(this.changeTimeout);
|
|
|
|
}
|
|
|
|
this.changeTimeout = setTimeout(() =>
|
|
|
|
this.updateSchema()
|
|
|
|
, 300);
|
|
|
|
}
|
|
|
|
updateSchema() {
|
|
|
|
this.createSchema(this.editor.getValue());
|
|
|
|
}
|
|
|
|
createSchema(code) {
|
2015-11-29 00:05:34 +03:00
|
|
|
console.log('createSchema');
|
2015-11-28 10:48:48 +03:00
|
|
|
this.validSchema = null;
|
|
|
|
this.pypyjs.then(() => {
|
|
|
|
return this.pypy_interpreter.exec(`
|
|
|
|
schema = None
|
|
|
|
${code}
|
|
|
|
assert schema, 'You have to define a schema'
|
|
|
|
`)
|
2015-11-29 00:05:34 +03:00
|
|
|
}).then(() => {
|
|
|
|
console.log('NO ERRORS');
|
|
|
|
this.validSchema = true;
|
2015-11-28 10:48:48 +03:00
|
|
|
}, (err) => {
|
2015-11-29 00:05:34 +03:00
|
|
|
console.log('ERROR', err);
|
2015-11-28 10:48:48 +03:00
|
|
|
this.validSchema = false;
|
|
|
|
// this.editor.setGutterMarker(5, "breakpoints", syntaxError());
|
|
|
|
}).then(this.updateGraphiQL.bind(this));
|
|
|
|
}
|
|
|
|
updateGraphiQL() {
|
|
|
|
if (this.validSchema) {
|
|
|
|
this.refs.graphiql.state.schema = null;
|
|
|
|
this.refs.graphiql.componentDidMount();
|
|
|
|
this.refs.graphiql.forceUpdate();
|
|
|
|
this.refs.graphiql.refs.docExplorer.forceUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2015-11-29 00:05:34 +03:00
|
|
|
result = __graphene_executor.execute(schema.schema, '''${query}''')
|
2015-11-28 10:48:48 +03:00
|
|
|
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;
|
2015-11-27 10:50:37 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
markLine(lineNo) {
|
2015-11-28 10:48:48 +03:00
|
|
|
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"});
|
2015-11-27 10:50:37 +03:00
|
|
|
setTimeout(() => {
|
2015-11-28 10:48:48 +03:00
|
|
|
this.editor.removeLineClass(lineNo, "text", "activeline");
|
|
|
|
}, 1200);
|
2015-11-27 10:50:37 +03:00
|
|
|
}
|
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div className="playground">
|
2015-11-28 10:48:48 +03:00
|
|
|
{!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>
|
2015-11-27 10:50:37 +03:00
|
|
|
<div className="playground-graphiql">
|
2015-11-28 10:48:48 +03:00
|
|
|
<GraphiQL ref="graphiql" fetcher={this.fetcher.bind(this)} response={this.state.response} />
|
2015-11-27 10:50:37 +03:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Playground;
|