-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: introduce monaco editor to GraphiQL #17
Changes from 5 commits
4ef8933
af79b24
734d2e2
7003a8d
19a6ea3
85ccd0d
8be3e24
3520332
0ea1a19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
<!-- | ||
* Copyright (c) 2019 GraphQL Contributors | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
--> | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<style> | ||
body { | ||
height: 100%; | ||
margin: 0; | ||
width: 100%; | ||
overflow: hidden; | ||
} | ||
|
||
#graphiql { | ||
height: 100vh; | ||
} | ||
</style> | ||
|
||
<!-- | ||
This GraphiQL example depends on Promise and fetch, which are available in | ||
modern browsers, but can be "polyfilled" for older browsers. | ||
GraphiQL itself depends on React DOM. | ||
If you do not want to rely on a CDN, you can host these files locally or | ||
include them directly in your favored resource bunder. | ||
--> | ||
<script | ||
crossorigin | ||
src="https://unpkg.com/react@16/umd/react.development.js" | ||
></script> | ||
<script | ||
crossorigin | ||
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" | ||
></script> | ||
<script crossorigin src="//unpkg.com/graphql@15.0.0"></script> | ||
<script | ||
crossorigin | ||
src="https://unpkg.com/graphiql/graphiql.min.js" | ||
></script> | ||
|
||
<!-- | ||
These two files can be found in the npm module, however you may wish to | ||
copy them directly into your environment, or perhaps include them in your | ||
favored resource bundler. | ||
--> | ||
<link rel="stylesheet" href="https://unpkg.com/graphiql/graphiql.min.css" /> | ||
</head> | ||
|
||
<body> | ||
<div id="graphiql">Loading...</div> | ||
<script> | ||
const mockSubcriptionClient = { | ||
subscribe: () => {}, | ||
unsubscribe: () => {}, | ||
}; | ||
|
||
const hasSubscriptionOperation = graphQlParams => { | ||
const queryDoc = parse(graphQlParams.query); | ||
|
||
for (let definition of queryDoc.definitions) { | ||
if (definition.kind === 'OperationDefinition') { | ||
const operation = definition.operation; | ||
if (operation === 'subscription') { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
export const graphQLFetcher = (subscriptionsClient, fallbackFetcher) => { | ||
let activeSubscription = null; | ||
|
||
return graphQLParams => { | ||
if (subscriptionsClient && activeSubscription !== null) { | ||
subscriptionsClient.unsubscribe(); | ||
} | ||
|
||
if (subscriptionsClient && hasSubscriptionOperation(graphQLParams)) { | ||
return { | ||
subscribe: observer => { | ||
observer.next( | ||
'Your subscription data will appear here after server publication!', | ||
); | ||
|
||
subscriptionsClient.subscribe( | ||
{ | ||
query: graphQLParams.query, | ||
variables: graphQLParams.variables, | ||
}, | ||
function (error, result) { | ||
if (error) { | ||
observer.error(error); | ||
} else { | ||
observer.next(result); | ||
} | ||
}, | ||
); | ||
activeSubscription = true; | ||
}, | ||
}; | ||
} else { | ||
return fallbackFetcher(graphQLParams); | ||
} | ||
}; | ||
}; | ||
|
||
ReactDOM.render( | ||
React.createElement(GraphiQL, { | ||
fetcher: graphQLFetcher, | ||
defaultVariableEditorOpen: true, | ||
}), | ||
document.getElementById('graphiql'), | ||
); | ||
</script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { SubscriptionClient } from 'subscriptions-transport-ws'; | ||
import { parse } from 'graphql'; | ||
|
||
const hasSubscriptionOperation = (graphQlParams: any) => { | ||
const queryDoc = parse(graphQlParams.query); | ||
|
||
for (const definition of queryDoc.definitions) { | ||
if (definition.kind === 'OperationDefinition') { | ||
const operation = definition.operation; | ||
if (operation === 'subscription') { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
export const graphQLFetcher = ( | ||
subscriptionsClient: SubscriptionClient, | ||
fallbackFetcher: Function, | ||
) => { | ||
let activeSubscriptionId: number | null = null; | ||
|
||
return (graphQLParams: any) => { | ||
if (subscriptionsClient && activeSubscriptionId !== null) { | ||
subscriptionsClient.unsubscribe(activeSubscriptionId); | ||
} | ||
|
||
if (subscriptionsClient && hasSubscriptionOperation(graphQLParams)) { | ||
return { | ||
subscribe: (observer: { error: Function, next: Function }) => { | ||
observer.next( | ||
'Your subscription data will appear here after server publication!', | ||
); | ||
|
||
activeSubscriptionId = subscriptionsClient.subscribe( | ||
{ | ||
query: graphQLParams.query, | ||
variables: graphQLParams.variables, | ||
}, | ||
function (error, result) { | ||
if (error) { | ||
observer.error(error); | ||
} else { | ||
observer.next(result); | ||
} | ||
}, | ||
); | ||
}, | ||
}; | ||
} else { | ||
return fallbackFetcher(graphQLParams); | ||
} | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'; | |
|
||
import 'regenerator-runtime/runtime'; | ||
import 'monaco-graphql/esm/monaco.contribution'; | ||
// / <reference path='monaco-graphql/esm/typings/monaco.d.ts'/> | ||
|
||
// NOTE: using loader syntax becuase Yaml worker imports editor.worker directly and that | ||
// import shouldn't go through loader syntax. | ||
|
@@ -12,7 +13,7 @@ import JSONWorker from 'worker-loader!monaco-editor/esm/vs/language/json/json.wo | |
// @ts-ignore | ||
import GraphQLWorker from 'worker-loader!monaco-graphql/esm/graphql.worker'; | ||
|
||
const SCHEMA_URL = 'https://swapi-graphql.netlify.app/.netlify/functions/index'; | ||
const SCHEMA_URL = 'https://api.spacex.land/graphql/'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't know about this one! :D |
||
|
||
// @ts-ignore | ||
window.MonacoEnvironment = { | ||
|
@@ -51,22 +52,31 @@ const resultsEditor = monaco.editor.create( | |
document.getElementById('results') as HTMLElement, | ||
{ | ||
model: variablesModel, | ||
automaticLayout: true, | ||
}, | ||
); | ||
const variablesEditor = monaco.editor.create( | ||
document.getElementById('variables') as HTMLElement, | ||
{ | ||
value: `{ }`, | ||
language: 'json', | ||
automaticLayout: true, | ||
}, | ||
); | ||
const model = monaco.editor.createModel( | ||
` | ||
query Example { | ||
allFilms { | ||
films { | ||
id | ||
} | ||
launchesPast(limit: 10) { | ||
mission_name | ||
# format me using the right click context menu | ||
launch_date_local | ||
launch_site { | ||
site_name_long | ||
} | ||
links { | ||
article_link | ||
video_link | ||
} | ||
} | ||
} | ||
`, | ||
|
@@ -78,9 +88,13 @@ const operationEditor = monaco.editor.create( | |
document.getElementById('operation') as HTMLElement, | ||
{ | ||
model, | ||
automaticLayout: true, | ||
}, | ||
); | ||
|
||
// @ts-ignore | ||
monaco.languages.graphql.graphqlDefaults.setSchemaUri(SCHEMA_URL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cshaver if we do this inside schema context, then it will reload schema and validations, completion, etc everything!!! |
||
|
||
/** | ||
* Basic Operation Exec Example | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha, nice!