Skip to content

Commit 9cb44d0

Browse files
committed
Add possibility to listen on displayOptions changes
1 parent 3c1c382 commit 9cb44d0

File tree

3 files changed

+52
-17
lines changed

3 files changed

+52
-17
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module system it is exported as `GraphQLVoyager` global variable.
3737
+ `displayOptions.sortByAlphabet` [`boolean`, default `false`] - sort fields on graph by alphabet
3838
+ `displayOptions.showLeafFields` [`boolean`, default `true`] - show all scalars and enums
3939
+ `displayOptions.hideRoot` [`boolean`, default `false`] - hide the root type
40+
+ `onDisplayOptionsChange` [function: `(displayOptions) => void`] _(optional)_ - called when user change displayOptions with UI. Can be used to save settings into localstorage or query params
4041
+ `hideDocs` [`boolean`, default `false`] - hide the docs sidebar
4142
+ `hideSettings` [`boolean`, default `false`] - hide settings panel
4243
+ `workerURI` [`string`] _(optional)_ - absolute or relative path to Voyager web worker. By default it will try to load it from `voyager.worker.js`.

demo/index.tsx

+46-17
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,36 @@ export default class Demo extends React.Component {
1919
introspection: defaultPreset,
2020
};
2121

22+
// not part of state because we parse it in constructor and just use in render
23+
displayOptions = {};
24+
2225
constructor(props) {
2326
super(props);
2427

25-
const { url, withCredentials } = getQueryParams();
28+
const { url, withCredentials, ...restQueryParams } = getQueryParams();
29+
// parse rest of query params we expect them to be in JSON format
30+
// we might pick also some options that are not valid displayOptions but they will be ignored
31+
// by Voyager component
32+
for (const [key, value] of Object.entries(restQueryParams)) {
33+
try {
34+
this.displayOptions[key] = JSON.parse(value);
35+
} catch (_) {
36+
console.log(
37+
`Not expected value for key "${key}" or value >${value}< is not in json format so just ignoring it`,
38+
);
39+
}
40+
}
2641
if (url) {
27-
this.state.introspection = introspectionQuery => fetch(url, {
28-
method: 'post',
29-
headers: {
30-
'Accept': 'application/json',
31-
'Content-Type': 'application/json',
32-
},
33-
body: JSON.stringify({ query: introspectionQuery }),
34-
...(
35-
withCredentials === 'true'
36-
? { credentials: 'include', mode: 'cors' }
37-
: {}
38-
),
39-
}).then(response => response.json());
42+
this.state.introspection = introspectionQuery =>
43+
fetch(url, {
44+
method: 'post',
45+
headers: {
46+
Accept: 'application/json',
47+
'Content-Type': 'application/json',
48+
},
49+
body: JSON.stringify({ query: introspectionQuery }),
50+
...(withCredentials === 'true' ? { credentials: 'include', mode: 'cors' } : {}),
51+
}).then(response => response.json());
4052
}
4153
}
4254

@@ -48,13 +60,17 @@ export default class Demo extends React.Component {
4860

4961
return (
5062
<MuiThemeProvider theme={theme}>
51-
<GraphQLVoyager introspection={introspection}>
63+
<GraphQLVoyager
64+
introspection={introspection}
65+
displayOptions={this.displayOptions}
66+
onDisplayOptionsChange={setQueryParamsWithoutRefresh}
67+
>
5268
<GraphQLVoyager.PanelHeader>
5369
<div className="voyager-panel">
5470
<Logo />
5571
<Button
5672
color="primary"
57-
style={{color: 'white'}}
73+
style={{ color: 'white' }}
5874
variant="contained"
5975
className="choosebutton"
6076
onClick={openChangeSchema}
@@ -67,13 +83,26 @@ export default class Demo extends React.Component {
6783
<IntrospectionModal
6884
open={changeSchemaModalOpen}
6985
onClose={closeChangeSchema}
70-
onChange={(introspection) => this.setState({ introspection })}
86+
onChange={introspection => this.setState({ introspection })}
7187
/>
7288
</MuiThemeProvider>
7389
);
7490
}
7591
}
7692

93+
function setQueryParamsWithoutRefresh(displayOptions) {
94+
if ('URLSearchParams' in window) {
95+
const searchParams = new URLSearchParams(window.location.search);
96+
for (const [key, value] of Object.entries(displayOptions)) {
97+
searchParams.set(key, JSON.stringify(value));
98+
}
99+
var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString();
100+
history.pushState(null, '', newRelativePathQuery);
101+
} else {
102+
console.log('Missing URLSearchParams so just printing new displayOptions', displayOptions);
103+
}
104+
}
105+
77106
function getQueryParams(): { [key: string]: string } {
78107
const query = window.location.search.substring(1);
79108
const params = {};

src/components/Voyager.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function normalizeDisplayOptions(options) {
4444
export interface VoyagerProps {
4545
introspection: IntrospectionProvider | Object;
4646
displayOptions?: VoyagerDisplayOptions;
47+
onDisplayOptionsChange?: (displayOptions: VoyagerDisplayOptions) => void;
4748
hideDocs?: boolean;
4849
hideSettings?: boolean;
4950
workerURI?: string;
@@ -64,6 +65,7 @@ export default class Voyager extends React.Component<VoyagerProps> {
6465
hideRoot: PropTypes.bool,
6566
showLeafFields: PropTypes.bool,
6667
}),
68+
onDisplayOptionsChange: PropTypes.func,
6769
hideDocs: PropTypes.bool,
6870
hideSettings: PropTypes.bool,
6971
workerURI: PropTypes.string,
@@ -232,6 +234,9 @@ export default class Voyager extends React.Component<VoyagerProps> {
232234

233235
handleDisplayOptionsChange = delta => {
234236
const displayOptions = { ...this.state.displayOptions, ...delta };
237+
if (this.props.onDisplayOptionsChange) {
238+
this.props.onDisplayOptionsChange(displayOptions);
239+
}
235240
this.updateIntrospection(this.state.introspectionData, displayOptions);
236241
};
237242

0 commit comments

Comments
 (0)