Skip to content

Commit

Permalink
feat(graphiql): GraphiQL customize headers; graphql@14.x support (#892)
Browse files Browse the repository at this point in the history
* GraphQL 0.14 support

* Update introspection snapshot

* Let users adopt new GraphQL errors if they wish

* Move more dependencies to postgraphiql

* Enhanced GraphiQL

* Textarea padding

* Upgrade postgraphile-core

* Upgrade @types/graphql
  • Loading branch information
benjie committed Oct 31, 2018
1 parent 6c349c2 commit 84f00be
Show file tree
Hide file tree
Showing 13 changed files with 8,724 additions and 3,886 deletions.
27 changes: 7 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"prepack": "./scripts/build"
},
"dependencies": {
"@types/graphql": "^0.13.4",
"@types/graphql": "^14.0.3",
"@types/jsonwebtoken": "<7.2.1",
"@types/koa": "^2.0.44",
"@types/pg": "^7.4.10",
Expand All @@ -54,15 +54,15 @@
"css-loader": "1.0.0",
"debug": "^2.3.3",
"finalhandler": "^1.0.6",
"graphql": "^0.6.0 || ^0.7.0 || ^0.8.0-b || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0",
"graphql": "^0.6.0 || ^0.7.0 || ^0.8.0-b || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.2",
"http-errors": "^1.5.1",
"jsonwebtoken": "^8.0.0",
"lru-cache": ">=4 <5",
"parseurl": "^1.3.1",
"pg": ">=6.1.0 <8",
"pg-connection-string": "^0.1.3",
"pg-sql2": "^2.2.1",
"postgraphile-core": "4.1.0-alpha.1",
"postgraphile-core": "4.1.0-rc.0",
"tslib": "^1.5.0"
},
"devDependencies": {
Expand All @@ -85,7 +85,6 @@
"connect": "^3.5.0",
"css-loader": "1.0.0",
"express": "^4.14.0",
"graphiql": "^0.11.11",
"html-webpack-inline-source-plugin": "^0.0.10",
"html-webpack-plugin": "^3.2.0",
"jest": "^18.1.0",
Expand All @@ -94,9 +93,6 @@
"nodemon": "^1.11.0",
"pg-minify": "~0.5.3",
"prettier": "^1.13.7",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-scripts": "^1.1.1",
"source-map-support": "^0.4.6",
"style-loader": "^0.23.0",
"supertest": "^2.0.1",
Expand All @@ -110,23 +106,14 @@
"transform": {
".*": "<rootDir>/resources/jest-preprocessor.js"
},
"moduleFileExtensions": [
"ts",
"js"
],
"setupFiles": [
"<rootDir>/resources/jest-setup.js"
],
"moduleFileExtensions": ["ts", "js"],
"setupFiles": ["<rootDir>/resources/jest-setup.js"],
"browser": false,
"testEnvironment": "node",
"testPathDirs": [
"<rootDir>/src"
],
"testPathDirs": ["<rootDir>/src"],
"testRegex": "/__tests__/[^.]+-test.(t|j)s$"
},
"files": [
"build"
],
"files": ["build"],
"engines": {
"node": ">=8.6"
}
Expand Down
9 changes: 8 additions & 1 deletion postgraphiql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@
"private": true,
"name": "postgraphile-graphiql",
"version": "1.0.0",
"homepage": "https://graphile.org/postgraphile/"
"homepage": "https://graphile.org/postgraphile/",
"dependencies": {
"graphiql": "^0.12.0",
"graphql": "0.13.x",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-scripts": "^1.1.1"
}
}
2 changes: 2 additions & 0 deletions postgraphiql/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>PostGraphile GraphiQL</title>
<meta name="robots" content="noindex"/>
<script src="https://unpkg.com/prettier@1.13.0/standalone.js"></script>
<script src="https://unpkg.com/prettier@1.13.0/parser-graphql.js"></script>
</head>
<body>
<div id="root"></div>
Expand Down
169 changes: 156 additions & 13 deletions postgraphiql/src/components/PostGraphiQL.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import React from 'react';
import GraphiQL from 'graphiql';
import './postgraphiql.css';
import { buildClientSchema, introspectionQuery, isType, GraphQLObjectType } from 'graphql';

const {
POSTGRAPHILE_CONFIG = {
graphqlUrl: 'http://localhost:5000/graphql',
streamUrl: 'http://localhost:5000/_postgraphile/stream',
enhanceGraphiql: true,
},
} = window;

const isValidJSON = json => {
try {
JSON.parse(json);
return true;
} catch (e) {
return false;
}
};

/**
* The standard GraphiQL interface wrapped with some PostGraphile extensions.
* Including a JWT setter and live schema udpate capabilities.
Expand All @@ -18,6 +29,9 @@ class PostGraphiQL extends React.Component {
// Our GraphQL schema which GraphiQL will use to do its intelligence
// stuffs.
schema: null,
showHeaderEditor: true, // REMOVE ME
headersText: '{\n"Authorization": null\n}\n',
headersTextValid: true,
};

componentDidMount() {
Expand Down Expand Up @@ -73,19 +87,27 @@ class PostGraphiQL extends React.Component {
* Executes a GraphQL query with some extra information then the standard
* parameters. Namely a JWT which may be added as an `Authorization` header.
*/
async executeQuery(graphQLParams, { jwtToken } = {}) {
async executeQuery(graphQLParams) {
const { headersText } = this.state;
let extraHeaders;
try {
extraHeaders = JSON.parse(headersText);
for (const k in extraHeaders) {
if (extraHeaders[k] == null) {
delete extraHeaders[k];
}
}
} catch (e) {
// Do nothing
}
const response = await fetch(POSTGRAPHILE_CONFIG.graphqlUrl, {
method: 'POST',
headers: Object.assign(
{
Accept: 'application/json',
'Content-Type': 'application/json',
},
jwtToken
? {
Authorization: `Bearer ${jwtToken}`,
}
: {},
extraHeaders,
),
credentials: 'same-origin',
body: JSON.stringify(graphQLParams),
Expand Down Expand Up @@ -221,16 +243,137 @@ class PostGraphiQL extends React.Component {
}
}

getQueryEditor = () => {
return this.graphiql.getQueryEditor();
};

handlePrettifyQuery = () => {
const editor = this.getQueryEditor();
if (typeof window.prettier !== 'undefined' && typeof window.prettierPlugins !== 'undefined') {
// TODO: window.prettier.formatWithCursor
editor.setValue(
window.prettier.format(editor.getValue(), {
parser: 'graphql',
plugins: window.prettierPlugins,
}),
);
} else {
return this.graphiql.handlePrettifyQuery();
}
};

handleToggleHistory = e => {
this.graphiql.handleToggleHistory(e);
};

handlePostGraphile = () => {
window.open('https://graphile.org/postgraphile/', 'postgraphile');
};

handleDonate = () => {
window.open('https://graphile.org/donate', 'postgraphile');
};

handleToggleHeaders = () => {
this.setState({ showHeaderEditor: !this.state.showHeaderEditor });
};

render() {
const { schema } = this.state;
return (
<GraphiQL
ref={ref => (this.graphiql = ref)}
schema={schema}
fetcher={params => this.executeQuery(params)}
/>
);
const sharedProps = {
ref: ref => {
this.graphiql = ref;
},
schema: schema,
fetcher: params => this.executeQuery(params),
};
if (!POSTGRAPHILE_CONFIG.enhanceGraphiql) {
return <GraphiQL {...sharedProps} />;
} else {
return (
<div className="postgraphiql-container">
<GraphiQL {...sharedProps}>
<GraphiQL.Logo>
PostGraph
<em>i</em>
QL
</GraphiQL.Logo>
<GraphiQL.Toolbar>
<GraphiQL.Button
onClick={this.handlePrettifyQuery}
title="Prettify Query (Shift-Ctrl-P)"
label="Prettify"
/>
<GraphiQL.Button
onClick={this.handleToggleHistory}
title="Show History"
label="History"
/>
<GraphiQL.Button
label="Headers"
title="Modify the headers to be sent with the requests"
onClick={this.handleToggleHeaders}
/>
<GraphiQL.Button
label="PostGraphile"
title="Open PostGraphile documentation"
onClick={this.handlePostGraphile}
/>
<GraphiQL.Button
label="Donate"
title="PostGraphile is supported by the community, please donate to fund ongoing development"
onClick={this.handleDonate}
/>
</GraphiQL.Toolbar>
</GraphiQL>
<EditHeaders
open={this.state.showHeaderEditor}
value={this.state.headersText}
valid={this.state.headersTextValid}
onChange={e =>
this.setState({
headersText: e.target.value,
headersTextValid: isValidJSON(e.target.value),
})
}
>
<div className="docExplorerHide" onClick={this.handleToggleHeaders}>
{'\u2715'}
</div>
</EditHeaders>
</div>
);
}
}
}

function EditHeaders({ children, open, value, onChange, valid }) {
return (
<div
className="graphiql-container not-really"
style={{
display: open ? 'block' : 'none',
width: '300px',
flexBasis: '300px',
}}
>
<div className="docExplorerWrap">
<div className="doc-explorer">
<div className="doc-explorer-title-bar">
<div className="doc-explorer-title">Edit Headers</div>
<div className="doc-explorer-rhs">{children}</div>
</div>
<div className="doc-explorer-contents">
<textarea
value={value}
onChange={onChange}
style={valid ? {} : { backgroundColor: '#fdd' }}
/>
</div>
</div>
</div>
</div>
);
}

export default PostGraphiQL;
38 changes: 38 additions & 0 deletions postgraphiql/src/components/postgraphiql.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.graphiql-container.not-really {
display: block;
width: auto;
height: auto;
border-left: 1px solid rgb(0, 0, 0, 0.2);
}

.not-really .docExplorerWrap {
height: 100%;
}

.postgraphiql-container .graphiql-container {
flex-grow: 1;
}

.not-really .doc-explorer-contents {
margin: 0;
padding: 0;
}
.not-really textarea {
height: 100%;
width: 100%;
border: none;
outline: none;
box-sizing: border-box;
overflow: auto;
font-size: 1rem;
padding: 0.5rem;
}

.postgraphiql-container {
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
overflow: hidden;
margin: 0;
}

0 comments on commit 84f00be

Please sign in to comment.