Skip to content

Commit

Permalink
feat: upgrade GraphiQL/GraphiQL Explorer (#1377)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjie authored Nov 13, 2020
1 parent a3cd8b8 commit 0152244
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 189 deletions.
4 changes: 2 additions & 2 deletions postgraphiql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"version": "1.0.0",
"homepage": "https://graphile.org/postgraphile/",
"dependencies": {
"graphiql": "^0.13.2",
"graphiql-explorer": "^0.4.5",
"graphiql": "^1.0.6",
"graphiql-explorer": "^0.6.1",
"graphql": "^14.5.8",
"react": "^16.12.0",
"react-dom": "^16.12.0",
Expand Down
154 changes: 62 additions & 92 deletions postgraphiql/src/components/PostGraphiQL.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@ class PostGraphiQL extends React.PureComponent {
POSTGRAPHILE_CONFIG.enhanceGraphiql && POSTGRAPHILE_CONFIG.subscriptions ? 'pending' : null,
};

_onEditQuery = query => {
this.setState({ query });
};

subscriptionsClient =
POSTGRAPHILE_CONFIG.enhanceGraphiql && POSTGRAPHILE_CONFIG.subscriptions
? new SubscriptionClient(websocketUrl, {
Expand Down Expand Up @@ -201,6 +197,7 @@ class PostGraphiQL extends React.PureComponent {
}
const graphiql = this.graphiql;
this.setState({ query: graphiql._storage.get('query') || defaultQuery });

const editor = graphiql.getQueryEditor();
editor.setOption('extraKeys', {
...(editor.options.extraKeys || {}),
Expand Down Expand Up @@ -280,7 +277,7 @@ class PostGraphiQL extends React.PureComponent {
/**
* Get the user editable headers as an object
*/
getHeaders() {
getHeaders = () => {
const { headersText } = this.state;
let extraHeaders;
try {
Expand All @@ -294,13 +291,13 @@ class PostGraphiQL extends React.PureComponent {
// Do nothing
}
return extraHeaders;
}
};

/**
* 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) {
executeQuery = async graphQLParams => {
const extraHeaders = this.getHeaders();
const response = await fetch(POSTGRAPHILE_CONFIG.graphqlUrl, {
method: 'POST',
Expand All @@ -323,7 +320,7 @@ class PostGraphiQL extends React.PureComponent {
this.setState({ explainResult: result && result.explain ? result.explain : null });

return result;
}
};

/**
* Routes the request either to the subscriptionClient or to executeQuery.
Expand All @@ -333,22 +330,11 @@ class PostGraphiQL extends React.PureComponent {
if (isSubscription(graphQLParams) && this.subscriptionsClient) {
return {
subscribe: observer => {
observer.next('Waiting for subscription to yield data…');

// Hack because GraphiQL logs `[object Object]` on error otherwise
const oldError = observer.error;
observer.error = function (error) {
let stack;
try {
stack = JSON.stringify(error, null, 2);
} catch (e) {
stack = error.message || error;
}
oldError.call(this, {
stack,
...error,
});
};
setTimeout(() => {
// Without this timeout, this message doesn't display on the first
// subscription after the first render of the page.
observer.next('Waiting for subscription to yield data…');
}, 0);

const subscription = this.subscriptionsClient.request(graphQLParams).subscribe(observer);
this.setState({ haveActiveSubscription: true });
Expand Down Expand Up @@ -409,6 +395,10 @@ class PostGraphiQL extends React.PureComponent {
// Get the documentation explorer component from GraphiQL. Unfortunately
// for them this looks like public API. Muwahahahaha.
const { docExplorerComponent } = this.graphiql;
if (!docExplorerComponent) {
console.log('No docExplorerComponent, could not update navStack');
return;
}
const { navStack } = docExplorerComponent.state;

// If one type/field isn’t find this will be set to false and the
Expand Down Expand Up @@ -495,6 +485,28 @@ class PostGraphiQL extends React.PureComponent {
return this.graphiql.getQueryEditor();
};

handleEditQuery = query => {
this.setState({ query });
};

handleEditHeaders = headersText => {
this.setState(
{
headersText,
headersTextValid: isValidJSON(headersText),
},
() => {
if (this.state.headersTextValid && this.state.saveHeadersText) {
this._storage.set(STORAGE_KEYS.HEADERS_TEXT, this.state.headersText);
}
if (this.state.headersTextValid && this.subscriptionsClient) {
// Reconnect to websocket with new headers
this.subscriptionsClient.close(false, true);
}
},
);
};

handlePrettifyQuery = () => {
const editor = this.getQueryEditor();
if (typeof window.prettier !== 'undefined' && typeof window.prettierPlugins !== 'undefined') {
Expand Down Expand Up @@ -654,18 +666,26 @@ class PostGraphiQL extends React.PureComponent {
<GraphiQLExplorer
schema={schema}
query={this.state.query}
onEdit={this._onEditQuery}
onEdit={this.handleEditQuery}
onRunOperation={operationName => this.graphiql.handleRunQuery(operationName)}
explorerIsOpen={this.state.explorerIsOpen}
onToggleExplorer={this.handleToggleExplorer}
//getDefaultScalarArgValue={getDefaultScalarArgValue}
//makeDefaultArg={makeDefaultArg}
/>
<GraphiQL onEditQuery={this._onEditQuery} query={this.state.query} {...sharedProps}>
<GraphiQL
onEditQuery={this.handleEditQuery}
query={this.state.query}
headerEditorEnabled
headers={this.state.headersText}
onEditHeaders={this.handleEditHeaders}
{...sharedProps}
>
<GraphiQL.Logo>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>
<img
alt="PostGraphile logo"
src="https://www.graphile.org/images/postgraphile-tiny.optimized.svg"
width="32"
height="32"
Expand All @@ -691,23 +711,34 @@ class PostGraphiQL extends React.PureComponent {
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="Explorer"
title="Construct a query with the GraphiQL explorer"
onClick={this.handleToggleExplorer}
/>
<GraphiQL.Button
onClick={this.graphiql && this.graphiql.handleMergeQuery}
title="Merge Query (Shift-Ctrl-M)"
label="Merge"
/>
<GraphiQL.Button
onClick={this.graphiql && this.graphiql.handleCopyQuery}
title="Copy Query (Shift-Ctrl-C)"
label="Copy"
/>

{POSTGRAPHILE_CONFIG.allowExplain ? (
<GraphiQL.Button
label={this.state.explain ? 'Explain ON' : 'Explain disabled'}
title="View the SQL statements that this query invokes"
onClick={this.handleToggleExplain}
/>
) : null}
<GraphiQL.Button
label={'Headers ' + (this.state.saveHeadersText ? 'SAVED' : 'unsaved')}
title="Should we persist the headers to localStorage? Header editor is next to variable editor at the bottom."
onClick={this.handleToggleSaveHeaders}
/>
</GraphiQL.Toolbar>
<GraphiQL.Footer>
<div className="postgraphile-footer">
Expand Down Expand Up @@ -775,71 +806,10 @@ class PostGraphiQL extends React.PureComponent {
</div>
</GraphiQL.Footer>
</GraphiQL>
<EditHeaders
open={this.state.showHeaderEditor}
value={this.state.headersText}
valid={this.state.headersTextValid}
toggleSaveHeaders={this.handleToggleSaveHeaders}
saveHeaders={this.state.saveHeadersText}
onChange={e =>
this.setState(
{
headersText: e.target.value,
headersTextValid: isValidJSON(e.target.value),
},
() => {
if (this.state.headersTextValid && this.state.saveHeadersText) {
this._storage.set(STORAGE_KEYS.HEADERS_TEXT, this.state.headersText);
}
if (this.state.headersTextValid && this.subscriptionsClient) {
// Reconnect to websocket with new headers
this.subscriptionsClient.close(false, true);
}
},
)
}
>
<div className="docExplorerHide" onClick={this.handleToggleHeaders}>
{'\u2715'}
</div>
</EditHeaders>
</div>
);
}
}
}

function EditHeaders({ children, open, value, onChange, valid, saveHeaders, toggleSaveHeaders }) {
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">
<label>
<input type="checkbox" checked={saveHeaders} onChange={toggleSaveHeaders} />
Persist headers
</label>
<textarea
value={value}
onChange={onChange}
style={valid ? {} : { backgroundColor: '#fdd' }}
/>
</div>
</div>
</div>
</div>
);
}

export default PostGraphiQL;
10 changes: 9 additions & 1 deletion postgraphiql/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ body,
}

/* Fix weird search alignment issue */
.graphiql-container .search-box:before {
.graphiql-container .search-box-icon {
line-height: 1em;
top: 1px;
}

.graphiql-container .history-contents li button.favorited {
display: inline-block;
}

.graphiql-container button:focus {
outline: none;
}
Loading

0 comments on commit 0152244

Please sign in to comment.