Skip to content
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

Feature/plugin custom graphql scalars #47

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0e2b43e
add a 'deprecated' class to fields which have been marked as such
TimLehner Jan 10, 2020
9fe6dd3
Merge branch 'master' of https://github.com/OneGraph/graphiql-explorer
TimLehner Jan 29, 2020
025c824
Refactor existing behaviour into seperate method
TimLehner Feb 1, 2020
745e400
Introduce custom scalar input plugin manager
TimLehner Feb 1, 2020
9c3647a
Create example DateInput plugin based on PR #46
TimLehner Feb 1, 2020
014ec5b
Only enable bundled plugins if requested.
TimLehner Feb 1, 2020
77348c4
update readme for custom-graphql-scalars plugin
TimLehner Feb 1, 2020
ce1453f
[bugfix] only disable the bundled plugins
TimLehner Feb 1, 2020
47f6bae
typo
TimLehner Feb 2, 2020
7673dc1
Date -> DateTime
TimLehner Feb 2, 2020
c48ce5f
[bugfix] if manager is null explorer could break
TimLehner Feb 2, 2020
ae727bd
show checkbox if rendered by plugin
TimLehner Feb 2, 2020
0180b44
Add support for complex types
TimLehner Feb 2, 2020
433d702
update example inputs when query text changes
TimLehner Feb 2, 2020
48ae2f0
disable example input plugin if not selected
TimLehner Feb 2, 2020
7d597f7
typo
TimLehner Feb 2, 2020
ead2b1d
update plugin readme
TimLehner Feb 2, 2020
064c579
Merge changes from master
TimLehner Apr 22, 2020
8062b6b
Move everything into Explorer.js following review
TimLehner Apr 22, 2020
7674eba
Merge branch 'master' of https://github.com/OneGraph/graphiql-explore…
TimLehner Apr 22, 2020
f684f5c
fix broken merge
TimLehner May 16, 2020
3e99795
Merge remote-tracking branch 'upstream/master'
dboakes-ag Mar 2, 2022
93cd44b
Merge branch 'master' into feature/plugin-custom-graphql-scalars
dboakes-ag Mar 2, 2022
437b01d
[sc-28504] Bump version and ensure package.json has agrimetrics in na…
dboakes-ag Mar 2, 2022
65c0290
[sc-28504] Fix ScalarInputPluginManager handler and bump version
dboakes-ag Mar 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,161 @@ Example styles map:
}}
/>
```


# Handling Custom GraphQL Scalars

Custom GraphQL Scalars can be supported by using the [GraphQL Scalar Input Plugins](./src/plugins/graphql-scalar-inputs/README.md).

## Plugin Definition

A GraphQL Scalar Input plugin must implement the following:
```js
function canProcess(arg): Boolean!
function render(prop): React.Element!

const name: String!
```

> Please note this interface is not currently finalised. Perhaps it is preferred to use typescript to define an abstract base class. External plugins would then extend this, making the interface concrete.

## Usage

### Enabling bundled plugins

By default, these plugins are disabled to avoid breaking changes to existing users. To enable the bundled plugins, instantiate the explorer with the prop `enableBundledPlugins` set to `true`.

## Example Plugins

### Date Input

See the bundled `DateInput` plugin, which demonstrates a simple implementation for a single GraphQL Scalar.

When instantiating the GraphiQL Explorer, pass the list of desired plugins as the prop `graphqlCustomScalarPlugins`.

### Complex Numbers

This examples shows a plugin that can be used for more complicated input types which should form objects.

For this example, consider the following schema:
```
type ComplexNumber {
real: Float!
imaginary: Float!
}

input ComplexNumberInput {
real: Float!
imaginary: Float!
}

type Query {
complexCalculations(z: ComplexNumberInput): ComplexResponse!
}

type ComplexResponse {
real: Float!
imaginary: Float!
length: Float!
complexConjugate: ComplexNumber!
}
```

The custom object type can be handled with a custom plugin. The file `ComplexNumberHandler.js` shows an example implementation for the `ComplexNumberInput`.

```js
import * as React from "react";

class ComplexNumberHandler extends React.Component {
static canProcess = (arg) => arg && arg.type && arg.type.name === 'ComplexNumberInput';

updateComponent(arg, value, targetName) {
const updatedFields = arg.value.fields.map(childArg => {
if (childArg.name.value !== targetName) {
return childArg;
}
const updatedChild = { ...childArg };
updatedChild.value.value = value;
return updatedChild;
});

const mappedArg = { ...arg };
mappedArg.value.fields = updatedFields;
return mappedArg;
}

handleChangeEvent(event, complexComponent) {
const { arg, selection, modifyArguments, argValue } = this.props;
return modifyArguments(selection.arguments.map(originalArg => {
if (originalArg.name.value !== arg.name) {
return originalArg;
}

return this.updateComponent(originalArg, event.target.value, complexComponent);
}));
}

getValue(complexArg, complexComponent) {
const childNode = complexArg && complexArg.value.fields.find(childArg => childArg.name.value === complexComponent)

if (complexArg && childNode) {
return childNode.value.value;
}

return '';
}

render() {
const { selection, arg } = this.props;
const selectedComplexArg = (selection.arguments || []).find(a => a.name.value === arg.name);
const rePart = this.getValue(selectedComplexArg, 'real');
const imPart = this.getValue(selectedComplexArg, 'imaginary');
return (
<span>
<input
type="number"
value={rePart}
onChange={e => this.handleChangeEvent(e, 'real')}
style={{ maxWidth: '50px', margin: '5px' }}
step='any'
disabled={!selectedComplexArg}
/>
+
<input
type="number"
defaultValue={imPart}
onChange={e => this.handleChangeEvent(e, 'imaginary')}
style={{ maxWidth: '50px', margin: '5px' }}
step='any'
disabled={!selectedComplexArg}
/> i
</span>);
}
}

export default {
canProcess: ComplexNumberHandler.canProcess,
name: 'Complex Number',
render: props => (
<ComplexNumberHandler
{...props}
/>),
}
```
To add the custom plugin, pass it to the GraphiQLExplorer on instantiation.
```js
import ComplexNumberHandler from './ComplexNumberHandler';
const configuredPlugins = [ComplexNumberHandler];

// Then later, in your render method where you create the explorer...
<GraphiQLExplorer
...
enableBundledPlugins={true}
graphqlCustomScalarPlugins={configuredPlugins}
/>
```
> To see examples of instantiating the explorer, see the [example repo](https://github.com/OneGraph/graphiql-explorer-example).

Any number of plugins can be added, and can override existing bundled plugins.

Plugins are checked in the order they are given in the `graphqlCustomScalarPlugins` list. The first plugin with a `canProcess` value that returns `true` will be used. Bundled plugins are always checked last, after all customised plugins.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "graphiql-explorer",
"version": "0.8.0",
"name": "@agrimetrics/graphiql-explorer",
"version": "0.8.2",
"homepage": "https://github.com/onegraph/graphiql-explorer",
"bugs": {
"url": "https://github.com/onegraph/graphiql-explorer/issues"
},
"repository": {
"type": "git",
"url": "http://github.com/onegraph/graphiql-explorer.git"
"url": "http://github.com/agrimetrics/graphiql-explorer.git"
},
"license": "MIT",
"main": "dist/index.js",
Expand Down
Loading