Skip to content

Commit bda4d0c

Browse files
committed
Revert "GraphQL API playground (#1123)"
This reverts commit d04b7f0.
1 parent 70d49e2 commit bda4d0c

File tree

9 files changed

+1008
-2229
lines changed

9 files changed

+1008
-2229
lines changed

package-lock.json

Lines changed: 823 additions & 1915 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@
4242
"create-react-class": "15.6.3",
4343
"csurf": "1.10.0",
4444
"express": "4.17.1",
45-
"graphql": "^14.3.1",
46-
"graphql-playground-react": "^1.7.20",
4745
"history": "4.9.0",
48-
"immutable": "^4.0.0-rc.9",
46+
"immutable": "3.8.1",
4947
"immutable-devtools": "0.1.3",
5048
"js-beautify": "1.10.0",
5149
"json-file-plus": "3.2.0",
@@ -61,7 +59,6 @@
6159
"react-dnd-html5-backend": "8.0.3",
6260
"react-dom": "16.8.6",
6361
"react-helmet": "5.2.1",
64-
"react-redux": "^5.1.1",
6562
"react-router": "5.0.1",
6663
"react-router-dom": "5.0.1"
6764
},

src/dashboard/Dashboard.js

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import Config from './Data/Config/Config.react';
1818
import Explorer from './Analytics/Explorer/Explorer.react';
1919
import FourOhFour from 'components/FourOhFour/FourOhFour.react';
2020
import GeneralSettings from './Settings/GeneralSettings.react';
21-
import GraphQLConsole from './Data/ApiConsole/GraphQLConsole.react';
2221
import history from 'dashboard/history';
2322
import HostingSettings from './Settings/HostingSettings.react';
2423
import Icon from 'components/Icon/Icon.react';
@@ -36,7 +35,6 @@ import PushIndex from './Push/PushIndex.react';
3635
import PushNew from './Push/PushNew.react';
3736
import PushSettings from './Settings/PushSettings.react';
3837
import React from 'react';
39-
import RestConsole from './Data/ApiConsole/RestConsole.react';
4038
import Retention from './Analytics/Retention/Retention.react';
4139
import SchemaOverview from './Data/Browser/SchemaOverview.react';
4240
import SecuritySettings from './Settings/SecuritySettings.react';
@@ -248,22 +246,6 @@ export default class Dashboard extends React.Component {
248246
return <Browser {...props} params={ props.match.params } />
249247
}
250248

251-
const ApiConsoleRoute = (props) => (
252-
<Switch>
253-
<Route path={ props.match.path + '/rest' } render={props => (
254-
<ApiConsole {...props}>
255-
<RestConsole />
256-
</ApiConsole>
257-
)} />
258-
<Route path={ props.match.path + '/graphql' } render={props => (
259-
<ApiConsole {...props}>
260-
<GraphQLConsole />
261-
</ApiConsole>
262-
)} />
263-
<Redirect from={ props.match.path } to='/apps/:appId/api_console/rest' />
264-
</Switch>
265-
)
266-
267249
const AppRoute = ({ match }) => (
268250
<AppData params={ match.params }>
269251
<Switch>
@@ -283,8 +265,8 @@ export default class Dashboard extends React.Component {
283265
<Redirect from={ match.path + '/logs' } to='/apps/:appId/logs/info' />
284266

285267
<Route path={ match.path + '/config' } component={Config} />
286-
<Route path={ match.path + '/api_console' } component={ApiConsoleRoute} />
287-
<Route path={ match.path + '/migration' } component={Migration} />
268+
<Route path={ match.path + '/api_console' } component={ApiConsole} />
269+
<Route path={ match.path + '/migration' } component={Migration} />/>
288270

289271

290272
<Redirect exact from={ match.path + '/push' } to='/apps/:appId/push/new' />

src/dashboard/Data/ApiConsole/ApiConsole.react.js

Lines changed: 181 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,198 @@
55
* This source code is licensed under the license found in the LICENSE file in
66
* the root directory of this source tree.
77
*/
8-
import React from 'react'
9-
import CategoryList from 'components/CategoryList/CategoryList.react'
10-
import DashboardView from 'dashboard/DashboardView.react'
8+
import PropTypes from 'lib/PropTypes';
9+
import Button from 'components/Button/Button.react';
10+
import DashboardView from 'dashboard/DashboardView.react';
11+
import Dropdown from 'components/Dropdown/Dropdown.react';
12+
import Field from 'components/Field/Field.react';
13+
import Fieldset from 'components/Fieldset/Fieldset.react';
14+
import fieldStyle from 'components/Field/Field.scss';
15+
import FlowFooter from 'components/FlowFooter/FlowFooter.react';
16+
import FormNote from 'components/FormNote/FormNote.react';
17+
import generateCurl from 'dashboard/Data/ApiConsole/generateCurl';
18+
import JsonPrinter from 'components/JsonPrinter/JsonPrinter.react';
19+
import Label from 'components/Label/Label.react';
20+
import Modal from 'components/Modal/Modal.react';
21+
import Option from 'components/Dropdown/Option.react';
22+
import Parse from 'parse';
23+
import ParseApp from 'lib/ParseApp';
24+
import React from 'react';
25+
import request from 'dashboard/Data/ApiConsole/request';
26+
import styles from 'dashboard/Data/ApiConsole/ApiConsole.scss';
27+
import TextInput from 'components/TextInput/TextInput.react';
28+
import Toggle from 'components/Toggle/Toggle.react';
29+
import Toolbar from 'components/Toolbar/Toolbar.react';
1130

1231
export default class ApiConsole extends DashboardView {
1332

1433
constructor() {
1534
super();
1635
this.section = 'Core';
1736
this.subsection = 'API Console';
37+
38+
this.state = {
39+
method: 'GET',
40+
endpoint: '',
41+
useMasterKey: false,
42+
runAsIdentifier: '',
43+
sessionToken: null,
44+
parameters: '',
45+
response: {results:[]},
46+
fetchingUser: false,
47+
inProgress: false,
48+
error: false,
49+
curlModal: false,
50+
};
1851
}
1952

20-
renderSidebar() {
21-
const { path } = this.props.match
22-
const current = path.substr(path.lastIndexOf('/') + 1, path.length - 1)
23-
return (
24-
<CategoryList current={current} linkPrefix={'api_console/'} categories={[
25-
{ name: 'REST Console', id: 'rest' },
26-
{ name: 'GraphQL Console', id: 'graphql' }
27-
]} />
28-
)
53+
fetchUser() {
54+
if (this.state.runAsIdentifier.length === 0) {
55+
this.setState({ error: false, sessionToken: null });
56+
return;
57+
}
58+
Parse.Query.or(
59+
new Parse.Query(Parse.User).equalTo('username', this.state.runAsIdentifier ),
60+
new Parse.Query(Parse.User).equalTo('objectId', this.state.runAsIdentifier )
61+
).first({ useMasterKey: true }).then((found) => {
62+
if (found) {
63+
if (found.getSessionToken()) {
64+
this.setState({ sessionToken: found.getSessionToken(), error: false, fetchingUser: false });
65+
} else {
66+
// Check the Sessions table
67+
new Parse.Query(Parse.Session).equalTo('user', found).first({ useMasterKey: true }).then((session) => {
68+
if (session) {
69+
this.setState({ sessionToken: session.getSessionToken(), error: false, fetchingUser: false });
70+
} else {
71+
this.setState({ error: 'Unable to find any active sessions for that user.', fetchingUser: false });
72+
}
73+
}, () => {
74+
this.setState({ error: 'Unable to find any active sessions for that user.', fetchingUser: false });
75+
});
76+
}
77+
} else {
78+
this.setState({ error: 'Unable to find that user.', fetchingUser: false });
79+
}
80+
}, () => {
81+
this.setState({ error: 'Unable to find that user.', fetchingUser: false });
82+
});
83+
this.setState({ fetchingUser: true });
84+
}
85+
86+
makeRequest() {
87+
let endpoint = this.state.endpoint + (this.state.method === 'GET' ? `?${this.state.parameters}` : '');
88+
let payload = (this.state.method === 'DELETE' || this.state.method === 'GET') ? null : this.state.parameters;
89+
let options = {};
90+
if (this.state.useMasterKey) {
91+
options.useMasterKey = true;
92+
}
93+
if (this.state.sessionToken) {
94+
options.sessionToken = this.state.sessionToken;
95+
}
96+
request(
97+
this.context.currentApp,
98+
this.state.method,
99+
endpoint,
100+
payload,
101+
options
102+
).then((response) => {
103+
this.setState({ response });
104+
document.body.scrollTop = 540;
105+
});
106+
}
107+
108+
showCurl() {
109+
this.setState({ curlModal: true });
29110
}
30111

31112
renderContent() {
32-
const child = React.Children.only(this.props.children);
33-
return React.cloneElement(
34-
child,
35-
{ ...child.props }
36-
)
113+
const methodDropdown =
114+
<Dropdown onChange={(method) => this.setState({method})} value={this.state.method}>
115+
<Option value='GET'>GET</Option>
116+
<Option value='POST'>POST</Option>
117+
<Option value='PUT'>PUT</Option>
118+
<Option value='DELETE'>DELETE</Option>
119+
</Dropdown>
120+
121+
let hasError = this.state.fetchingUser ||
122+
this.state.endpoint.length === 0 ||
123+
(this.state.runAsIdentifier.length > 0 && !this.state.sessionToken);
124+
let parameterPlaceholder = 'where={"username":"johndoe"}';
125+
if (this.state.method === 'POST' || this.state.method === 'PUT') {
126+
parameterPlaceholder = '{"name":"John"}';
127+
}
128+
129+
let modal = null;
130+
if (this.state.curlModal) {
131+
let payload = this.state.method === 'DELETE' ? null : this.state.parameters;
132+
let options = {};
133+
if (this.state.useMasterKey) {
134+
options.useMasterKey = true;
135+
}
136+
if (this.state.sessionToken) {
137+
options.sessionToken = this.state.sessionToken;
138+
}
139+
let content = generateCurl(
140+
this.context.currentApp,
141+
this.state.method,
142+
this.state.endpoint,
143+
payload,
144+
options
145+
);
146+
modal = (
147+
<Modal
148+
title='cURL Request'
149+
subtitle='Use this to replicate the request'
150+
icon='laptop-outline'
151+
customFooter={
152+
<div className={styles.footer}>
153+
<Button primary={true} value='Close' onClick={() => this.setState({ curlModal: false })} />
154+
</div>
155+
}>
156+
<div className={styles.curl}>{content}</div>
157+
</Modal>
158+
);
159+
}
160+
161+
return (
162+
<div style={{ padding: '120px 0 60px 0' }}>
163+
<Fieldset
164+
legend='Send a test query'
165+
description='Try out some queries, and take a look at what they return.'>
166+
<Field
167+
label={<Label text='What type of request?' />}
168+
input={methodDropdown} />
169+
<Field
170+
label={<Label text='Which endpoint?' description={<span>Not sure what endpoint you need?<br />Take a look at our <a href="http://docs.parseplatform.org/rest/guide/">REST API guide</a>.</span>} />}
171+
input={<TextInput value={this.state.endpoint} monospace={true} placeholder={'classes/_User'} onChange={(endpoint) => this.setState({endpoint})} />} />
172+
<Field
173+
label={<Label text='Use Master Key?' description={'This will bypass any ACL/CLPs.'} />}
174+
input={<Toggle value={this.state.useMasterKey} onChange={(useMasterKey) => this.setState({ useMasterKey })} />} />
175+
<Field
176+
label={<Label text='Run as...' description={'Send your query as a specific user. You can use their username or Object ID.'} />}
177+
input={<TextInput value={this.state.runAsIdentifier} monospace={true} placeholder={'Username or ID'} onChange={(runAsIdentifier) => this.setState({runAsIdentifier})} onBlur={this.fetchUser.bind(this)} />} />
178+
<FormNote color='red' show={!!this.state.error}>{this.state.error}</FormNote>
179+
<Field
180+
label={<Label text='Query parameters' description={<span>Learn more about query parameters in our <a href="http://docs.parseplatform.org/rest/guide/#queries">REST API guide</a>.</span>} />}
181+
input={<TextInput value={this.state.parameters} monospace={true} multiline={true} placeholder={parameterPlaceholder} onChange={(parameters) => this.setState({parameters})} />} />
182+
</Fieldset>
183+
<Fieldset
184+
legend='Results'
185+
description=''>
186+
<div className={fieldStyle.field}>
187+
<JsonPrinter object={this.state.response} />
188+
</div>
189+
</Fieldset>
190+
<Toolbar section='Core' subsection='API Console' />
191+
<FlowFooter
192+
primary={<Button primary={true} disabled={hasError} value='Send Query' progress={this.state.inProgress} onClick={this.makeRequest.bind(this)} />}
193+
secondary={<Button disabled={hasError} value='Export to cURL' onClick={this.showCurl.bind(this)} />} />
194+
{modal}
195+
</div>
196+
);
37197
}
38198
}
199+
200+
ApiConsole.contextTypes = {
201+
currentApp: PropTypes.instanceOf(ParseApp)
202+
};

src/dashboard/Data/ApiConsole/ApiConsole.scss

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,3 @@
2020
padding: 10px 0;
2121
text-align: center;
2222
}
23-
24-
.content {
25-
position: relative;
26-
min-height: 100vh;
27-
padding-top: 96px;
28-
}
29-
30-
.empty {
31-
position: absolute;
32-
top: 96px;
33-
left: 0;
34-
right: 0;
35-
bottom: 0;
36-
}

src/dashboard/Data/ApiConsole/GraphQLConsole.react.js

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)