Skip to content

Commit db7ab29

Browse files
committed
feat: add request page to each project, complete the layout of it
1 parent 389abb7 commit db7ab29

5 files changed

Lines changed: 422 additions & 0 deletions

File tree

src/models/app.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,19 @@ export default {
243243
route: `/project/${p.project}/db`,
244244
}
245245
routesToAppend.push(dbRoute)
246+
247+
let reqRoute = {
248+
id: `10${p.id}2`,
249+
breadcrumbParentId: `10${p.id}`,
250+
menuParentId: `10${p.id}`,
251+
name: 'Request',
252+
zh: {
253+
name: 'Request',
254+
},
255+
icon: 'api',
256+
route: `/project/${p.project}/request`,
257+
}
258+
routesToAppend.push(reqRoute)
246259
})
247260

248261
yield put({ type: 'updateRoutes', payload: { append: routesToAppend } })

src/pages/project/$db/request.js

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
import React from 'react'
2+
import { request } from 'utils'
3+
import { connect } from 'dva'
4+
import _get from 'lodash/get'
5+
import {
6+
Row,
7+
Col,
8+
Select,
9+
Input,
10+
Button,
11+
List,
12+
Tag,
13+
Form,
14+
Icon,
15+
Checkbox,
16+
} from 'antd'
17+
import classnames from 'classnames'
18+
import CodeMirror from 'react-codemirror'
19+
import { Trans } from '@lingui/react'
20+
import { CLIENT_API } from 'utils/constant'
21+
import api from '@/services/api'
22+
import { Page } from 'components'
23+
24+
import 'codemirror/mode/javascript/javascript'
25+
import 'codemirror/lib/codemirror.css'
26+
import 'codemirror/theme/monokai.css'
27+
28+
import styles from './request.less'
29+
30+
const { Option } = Select
31+
const InputGroup = Input.Group
32+
const methods = ['POST', 'GET', 'PUT', 'PATCH', 'DELETE']
33+
34+
const methodTagColor = {
35+
GET: 'green',
36+
POST: 'orange',
37+
DELETE: 'red',
38+
PUT: 'geekblue',
39+
}
40+
41+
// for local test
42+
const apiPrefix = '/v3'
43+
44+
const requests = Object.values(CLIENT_API).map(item => {
45+
let url = apiPrefix + item
46+
let method = 'GET'
47+
const paramsArray = item.split(' ')
48+
if (paramsArray.length === 2) {
49+
method = paramsArray[0]
50+
url = apiPrefix + paramsArray[1]
51+
}
52+
return {
53+
method,
54+
url,
55+
}
56+
})
57+
58+
let uuid = 2
59+
@Form.create()
60+
@connect(({ projectDetail }) => ({ config: projectDetail.config }))
61+
class RequestPage extends React.Component {
62+
constructor(props) {
63+
super(props)
64+
this.state = {
65+
method: 'GET',
66+
url: apiPrefix + CLIENT_API.find,
67+
keys: [1],
68+
result: null,
69+
visible: true,
70+
}
71+
}
72+
73+
constructAPIDomain = () => {
74+
const alias = _get(this.props.config, ['misc', 'alias'], '')
75+
console.log('...l..', this.props.config)
76+
return '//' + alias + '.stg-api.covenantsql.io:15153'
77+
}
78+
79+
constructTableSelection = () => {
80+
const tables = _get(this.props.config, ['misc', 'tables'], [])
81+
return tables.map(t => ({}))
82+
return (
83+
<Select placeholder="Please select a country">
84+
{tables.map(t => {
85+
if (!t.config.is_deleted) {
86+
return (
87+
<Select.Option key={t.table} value={t.table}>
88+
{t.table}
89+
</Select.Option>
90+
)
91+
}
92+
})}
93+
</Select>
94+
)
95+
}
96+
97+
handleRequest = () => {
98+
const { method } = this.state
99+
100+
// prefix the this.constructAPIDomain()
101+
let url = this.constructAPIDomain() + this.state.url
102+
103+
this.props.form.validateFields((err, values) => {
104+
if (!err) {
105+
const params = {}
106+
console.log('.///', values)
107+
if (values.key) {
108+
values.key.forEach((item, index) => {
109+
if (item && values.check[index]) {
110+
params[item] = values.value[index]
111+
}
112+
})
113+
114+
if (values.value.data) {
115+
console.log('parsing, ', values.value.data)
116+
params.data = JSON.parse(values.value.data)
117+
}
118+
}
119+
120+
console.log(params)
121+
122+
request({ method, url, data: params }).then(data => {
123+
this.setState({
124+
result: JSON.stringify(data),
125+
})
126+
})
127+
}
128+
})
129+
}
130+
131+
handleClickListItem = ({ method, url }) => {
132+
this.setState({
133+
method,
134+
url,
135+
keys: [uuid++],
136+
result: null,
137+
})
138+
}
139+
140+
handleInputChange = e => {
141+
this.setState({
142+
url: e.target.value,
143+
})
144+
}
145+
146+
handleSelectChange = method => {
147+
this.setState({
148+
method,
149+
})
150+
}
151+
152+
handleAddField = () => {
153+
const { keys } = this.state
154+
const nextKeys = keys.concat(uuid)
155+
uuid++
156+
this.setState({
157+
keys: nextKeys,
158+
})
159+
}
160+
161+
handleRemoveField = key => {
162+
const { keys } = this.state
163+
this.setState({
164+
keys: keys.filter(item => item !== key),
165+
})
166+
}
167+
168+
handleVisible = () => {
169+
this.setState({
170+
visible: !this.state.visible,
171+
})
172+
}
173+
174+
render() {
175+
const { result, url, method, keys, visible } = this.state
176+
const { getFieldDecorator } = this.props.form
177+
console.log('///////////', this.state)
178+
179+
return (
180+
<Page inner>
181+
<div style={{ padding: '10px 10px 20px' }}>
182+
Client API domain:{' '}
183+
<Tag color="geekblue">{this.constructAPIDomain()}</Tag>
184+
</div>
185+
<Row>
186+
<Col lg={8} md={24}>
187+
<List
188+
className={styles.requestList}
189+
dataSource={requests}
190+
renderItem={item => (
191+
<List.Item
192+
className={classnames(styles.listItem, {
193+
[styles.lstItemActive]:
194+
item.method === method && item.url === url,
195+
})}
196+
onClick={this.handleClickListItem.bind(this, item)}
197+
>
198+
<span style={{ width: 72 }}>
199+
<Tag
200+
style={{ marginRight: 8 }}
201+
color={methodTagColor[item.method]}
202+
>
203+
{item.method}
204+
</Tag>
205+
</span>
206+
{item.url}
207+
</List.Item>
208+
)}
209+
/>
210+
</Col>
211+
<Col lg={16} md={24}>
212+
<Row type="flex" justify="space-between">
213+
<InputGroup compact size="large" style={{ flex: 1 }}>
214+
<Select
215+
size="large"
216+
value={method}
217+
style={{ width: 100 }}
218+
onChange={this.handleSelectChange}
219+
>
220+
{methods.map(item => (
221+
<Option value={item} key={item}>
222+
{item}
223+
</Option>
224+
))}
225+
</Select>
226+
<Input
227+
value={url}
228+
onChange={this.handleInputChange}
229+
style={{ width: 'calc(100% - 200px)' }}
230+
/>
231+
<Button
232+
ghost={visible}
233+
type={visible ? 'primary' : ''}
234+
onClick={this.handleVisible}
235+
size="large"
236+
>
237+
<Trans>Params</Trans>
238+
</Button>
239+
</InputGroup>
240+
241+
<Button
242+
size="large"
243+
type="primary"
244+
style={{ width: 100 }}
245+
onClick={this.handleRequest}
246+
>
247+
<Trans>Send</Trans>
248+
</Button>
249+
</Row>
250+
251+
<div
252+
className={classnames(styles.paramsBlock, {
253+
[styles.hideParams]: !visible || url.indexOf(':table') > -1,
254+
})}
255+
>
256+
{keys.map((key, index) => (
257+
<Row
258+
gutter={8}
259+
type="flex"
260+
justify="start"
261+
align="middle"
262+
key={key}
263+
>
264+
<Col style={{ marginTop: 8 }}>
265+
{getFieldDecorator(`check[${key}]`, {
266+
initialValue: true,
267+
})(<Checkbox defaultChecked />)}
268+
</Col>
269+
<Col style={{ marginTop: 8 }}>
270+
{getFieldDecorator(`key[${key}]`)(
271+
<Input placeholder="Key" />
272+
)}
273+
</Col>
274+
<Col style={{ marginTop: 8 }}>
275+
{getFieldDecorator(`value[${key}]`)(
276+
<Input placeholder="Value" />
277+
)}
278+
</Col>
279+
<Col style={{ marginTop: 8 }}>
280+
<Icon
281+
onClick={this.handleRemoveField.bind(this, key)}
282+
style={{ cursor: 'pointer' }}
283+
type="close"
284+
theme="outlined"
285+
/>
286+
</Col>
287+
</Row>
288+
))}
289+
290+
<Row style={{ marginTop: 8 }}>
291+
<Button onClick={this.handleAddField}>
292+
<Trans>Add Param</Trans>
293+
</Button>
294+
</Row>
295+
</div>
296+
297+
{url.indexOf(':table') > -1 && (
298+
<div>
299+
<Row gutter={8} type="flex" justify="start" align="middle">
300+
<Col style={{ marginTop: 8 }}>
301+
{getFieldDecorator(`check[table]`, {
302+
initialValue: true,
303+
})(<Checkbox defaultChecked disabled />)}
304+
</Col>
305+
<Col style={{ marginTop: 8 }}>
306+
{getFieldDecorator(`key[table]`)(
307+
<Input placeholder="table" value={'table'} disabled />
308+
)}
309+
</Col>
310+
<Col style={{ marginTop: 8 }}>
311+
{getFieldDecorator(`value[table]`)(
312+
<Input placeholder="Value" />
313+
)}
314+
</Col>
315+
</Row>
316+
<Row gutter={8}>
317+
<div style={{ padding: '15px 10px 5px', fontWeight: '600' }}>
318+
Data:
319+
</div>
320+
{getFieldDecorator('value[data]', {
321+
rules: [
322+
{
323+
required: true,
324+
message: 'Please input table data',
325+
type: 'json',
326+
},
327+
],
328+
})(
329+
<div style={{ margin: '10px 0' }}>
330+
<CodeMirror
331+
value={this.state.rules}
332+
onChange={this.onCodeMirrorChange}
333+
options={{
334+
lineNumbers: true,
335+
matchBrackets: true,
336+
autoCloseBrackets: true,
337+
mode: 'application/ld+json',
338+
lineWrapping: true,
339+
theme: 'monokai',
340+
}}
341+
/>
342+
</div>
343+
)}
344+
</Row>
345+
</div>
346+
)}
347+
348+
<div className={styles.result}>
349+
<pre>{JSON.stringify(JSON.parse(result), null, 2)}</pre>
350+
</div>
351+
</Col>
352+
</Row>
353+
</Page>
354+
)
355+
}
356+
}
357+
358+
export default RequestPage

0 commit comments

Comments
 (0)