|
5 | 5 | * This source code is licensed under the license found in the LICENSE file in |
6 | 6 | * the root directory of this source tree. |
7 | 7 | */ |
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'; |
| 8 | +import React from 'react' |
| 9 | +import CategoryList from 'components/CategoryList/CategoryList.react' |
| 10 | +import DashboardView from 'dashboard/DashboardView.react' |
30 | 11 |
|
31 | 12 | export default class ApiConsole extends DashboardView { |
32 | 13 |
|
33 | 14 | constructor() { |
34 | 15 | super(); |
35 | 16 | this.section = 'Core'; |
36 | 17 | 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 | | - }; |
51 | | - } |
52 | | - |
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 | 18 | } |
85 | 19 |
|
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 }); |
| 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 | + ) |
110 | 29 | } |
111 | 30 |
|
112 | 31 | renderContent() { |
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 | | - ); |
| 32 | + const child = React.Children.only(this.props.children); |
| 33 | + return React.cloneElement( |
| 34 | + child, |
| 35 | + { ...child.props } |
| 36 | + ) |
197 | 37 | } |
198 | 38 | } |
199 | | - |
200 | | -ApiConsole.contextTypes = { |
201 | | - currentApp: PropTypes.instanceOf(ParseApp) |
202 | | -}; |
0 commit comments