Skip to content

Commit 24072cb

Browse files
committed
feat(graphql-playground-react): added spinner for schema fetching
1 parent f675517 commit 24072cb

File tree

4 files changed

+81
-12
lines changed

4 files changed

+81
-12
lines changed

packages/graphql-playground-react/src/components/Playground/GraphQLEditor.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export interface State {
122122
nextQueryStartTime?: Date
123123
tracingSupported?: boolean
124124
queryVariablesActive: boolean
125+
endpointUnreachable: boolean
125126
}
126127

127128
export interface SimpleProps {
@@ -251,6 +252,7 @@ export class GraphQLEditor extends React.PureComponent<
251252
subscription: null,
252253
selectedVariableNames: [],
253254
queryVariablesActive,
255+
endpointUnreachable: false,
254256
...queryFacts,
255257
}
256258

@@ -502,6 +504,7 @@ export class GraphQLEditor extends React.PureComponent<
502504
sharing={this.props.sharing}
503505
onReloadSchema={this.reloadSchema}
504506
fixedEndpoint={this.props.fixedEndpoint}
507+
endpointUnreachable={this.state.endpointUnreachable}
505508
/>
506509
<div
507510
ref={this.setEditorBarComponent}
@@ -805,15 +808,25 @@ export class GraphQLEditor extends React.PureComponent<
805808
this.renewStacks(schema)
806809
this.setState({
807810
schema,
811+
endpointUnreachable: false,
808812
tracingSupported,
809813
})
810814
}
811815
})
812-
.catch(error => {
813-
this.setState({
814-
schema: null,
815-
responses: [{ date: error.message, time: new Date() }],
816-
})
816+
.catch(async error => {
817+
if (error.message === 'Failed to fetch') {
818+
setTimeout(() => {
819+
this.setState({
820+
endpointUnreachable: true,
821+
})
822+
this.ensureOfSchema()
823+
}, 1000)
824+
} else {
825+
this.setState({
826+
schema: null,
827+
responses: [{ date: error.message, time: new Date() }],
828+
})
829+
}
817830
})
818831
}
819832

packages/graphql-playground-react/src/components/Playground/SchemaFetcher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class SchemaFetcher {
3636
},
3737
body: JSON.stringify({ query: introspectionQuery }),
3838
})
39+
3940
const schemaData = await response.json()
4041

4142
if (schemaData && (schemaData.errors || !schemaData.data)) {

packages/graphql-playground-react/src/components/Playground/TopBar/TopBar.tsx

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ export interface Props {
1919
onReloadSchema?: () => void
2020
sharing?: SharingProps
2121
fixedEndpoint?: boolean
22+
endpointUnreachable: boolean
2223
}
2324

2425
export default class TopBar extends React.Component<Props, {}> {
2526
render() {
27+
const { endpointUnreachable } = this.props
2628
return (
2729
<TopBarWrapper>
2830
<Button onClick={this.props.onClickPrettify}>Prettify</Button>
@@ -36,12 +38,19 @@ export default class TopBar extends React.Component<Props, {}> {
3638
disabled={this.props.fixedEndpoint}
3739
className={cx({ active: !this.props.fixedEndpoint })}
3840
/>
39-
<ReloadIcon
40-
src={require('graphcool-styles/icons/fill/reload.svg')}
41-
width={20}
42-
height={20}
43-
onClick={this.props.onReloadSchema}
44-
/>
41+
{endpointUnreachable ? (
42+
<ReachError>
43+
<span>Server cannot be reached</span>
44+
<Spinner />
45+
</ReachError>
46+
) : (
47+
<ReloadIcon
48+
src={require('graphcool-styles/icons/fill/reload.svg')}
49+
width={20}
50+
height={20}
51+
onClick={this.props.onReloadSchema}
52+
/>
53+
)}
4554
</UrlBarWrapper>
4655
<CopyToClipboard text={this.props.curl}>
4756
<Button>Copy CURL</Button>
@@ -155,6 +164,14 @@ const UrlBarWrapper = styled.div`
155164
align-items: center;
156165
`
157166

167+
const ReachError = styled.div`
168+
position: absolute;
169+
right: 5px;
170+
display: flex;
171+
align-items: center;
172+
color: #f25c54;
173+
`
174+
158175
const ReloadIcon = styled(Icon)`
159176
position: absolute;
160177
right: 5px;
@@ -167,3 +184,39 @@ const ReloadIcon = styled(Icon)`
167184
}
168185
}
169186
` as any // TODO remove this once typings are fixed
187+
188+
const Spinner = styled.div`
189+
& {
190+
width: 40px;
191+
height: 40px;
192+
margin: 40px auto;
193+
background-color: #333;
194+
border-radius: 100%;
195+
-webkit-animation: sk-pulseScaleOut 1s infinite ease-in-out;
196+
animation: sk-pulseScaleOut 1s infinite ease-in-out;
197+
}
198+
199+
@-webkit-keyframes sk-pulseScaleOut {
200+
0% {
201+
-webkit-transform: scale(0);
202+
transform: scale(0);
203+
}
204+
100% {
205+
-webkit-transform: scale(1);
206+
transform: scale(1);
207+
opacity: 0;
208+
}
209+
}
210+
211+
@keyframes sk-pulseScaleOut {
212+
0% {
213+
-webkit-transform: scale(0);
214+
transform: scale(0);
215+
}
216+
100% {
217+
-webkit-transform: scale(1);
218+
transform: scale(1);
219+
opacity: 0;
220+
}
221+
}
222+
`

packages/graphql-playground-react/src/components/PlaygroundStorage.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ export default class PlaygroundStorage {
200200
private getProject() {
201201
let result: any = null
202202
try {
203-
result = JSON.parse(localStorage.getItem(this.endpoint) || '{}')
203+
const data = localStorage.getItem(this.endpoint) || '{}'
204+
result = JSON.parse(data)
204205
} catch (e) {
205206
/* tslint:disable-next-line */
206207
console.info(e)
@@ -212,6 +213,7 @@ export default class PlaygroundStorage {
212213
date: new Date(item.date),
213214
}))
214215
}
216+
215217
return PlaygroundStorage.runMigration(result, this.endpoint)
216218
}
217219

0 commit comments

Comments
 (0)