Skip to content

Commit f4f49e4

Browse files
authored
Merge pull request #175 from quangkhoa/issue-157-support-servers-functionality
Handle servers functionality. Closes #157
2 parents 01c384c + b9e4e00 commit f4f49e4

16 files changed

+433
-98
lines changed

docs/open-api-v3-support.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ This document outlines this project's support for visualising the [Open API V3][
2626

2727
- [ ] openapi
2828
- [x] [info](#info-object)
29-
- [ ] [servers](#servers-object)
29+
- [x] [servers](#servers-object)
3030
- [x] [paths](#paths-object)
3131
- [ ] [components](#components-object)
3232
- [x] [security](#security-requirement-object)
@@ -55,8 +55,8 @@ This document outlines this project's support for visualising the [Open API V3][
5555

5656
### [Server](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#server-object) object
5757

58-
- [ ] url
59-
- [ ] description
58+
- [x] url
59+
- [x] description
6060
- [ ] [variables](#server-variable-object)
6161

6262
### [Server Variable](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#server-variable-object) object
@@ -251,7 +251,7 @@ The OpenAPI specification also supports several additional properties from JSON
251251
- [ ] not
252252
- [x] items
253253
- [x] properties
254-
- [ ] additionalProperties
254+
- [x] additionalProperties
255255
- [x] description
256256
- [x] format
257257
- [x] default

src/components/Endpoints/Endpoint.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, { PureComponent } from 'react'
2+
import PropTypes from 'prop-types'
3+
import { styles } from './Endpoint.style'
4+
5+
@styles
6+
export default class Endpoint extends PureComponent {
7+
constructor (props) {
8+
super(props)
9+
10+
this.handleFocus = this.handleFocus.bind(this)
11+
}
12+
13+
render () {
14+
const {url, description, classes} = this.props
15+
16+
return (
17+
<div className={classes.endpoint}>
18+
{description && <div><label>{description}</label></div>}
19+
<input className={classes.readonly} defaultValue={url} readOnly onFocus={this.handleFocus} />
20+
</div>
21+
)
22+
}
23+
24+
handleFocus (event) {
25+
event.target.select()
26+
}
27+
}
28+
29+
Endpoint.propTypes = {
30+
url: PropTypes.string,
31+
description: PropTypes.string,
32+
classes: PropTypes.object
33+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { createSheet } from '../../theme'
2+
3+
export const styles = createSheet(({borders, text, sizes}) => ({
4+
endpoint: {
5+
lineHeight: '200%'
6+
},
7+
readonly: {
8+
width: '100%',
9+
'&:focus': {
10+
outline: 'none'
11+
}
12+
}
13+
}))

src/components/Endpoints/Endpoints.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, { PureComponent } from 'react'
2+
import PropTypes from 'prop-types'
3+
import Endpoint from './Endpoint'
4+
import { styles } from './Endpoints.style'
5+
6+
@styles
7+
export default class Endpoints extends PureComponent {
8+
render () {
9+
const {endpoints, classes} = this.props
10+
11+
if (!endpoints || endpoints.length === 0) {
12+
return null
13+
}
14+
15+
return (
16+
<div className={classes.endpoints}>
17+
{endpoints.map(endpoint => <Endpoint key={endpoint.url} url={endpoint.url} description={endpoint.description} />)}
18+
</div>
19+
)
20+
}
21+
}
22+
23+
Endpoints.propTypes = {
24+
endpoints: PropTypes.arrayOf(PropTypes.shape({
25+
url: PropTypes.string.isRequired,
26+
description: PropTypes.string
27+
})),
28+
classes: PropTypes.object
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createSheet } from '../../theme'
2+
import c from 'color'
3+
4+
export const styles = createSheet(({borders, backgrounds, text, sizes}) => ({
5+
endpoints: {
6+
minWidth: '300px',
7+
backgroundColor: `${c(backgrounds.schema).darken(0.1)}`,
8+
padding: '15px'
9+
}
10+
}))

src/components/Method/Method.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import React, { PureComponent } from 'react'
22
import PropTypes from 'prop-types'
3-
import classNames from 'classnames'
43
import ScrollableAnchor from 'react-scrollable-anchor'
54
import BodyContent from '../BodyContent/BodyContent'
65
import Description from '../Description/Description'
76
import Parameters from '../Parameters/Parameters'
87
import Response from '../Response/Response'
8+
import MethodEndpoints from './MethodEndpoints'
99
import { styles } from './Method.styles'
1010

1111
@styles
1212
export default class Method extends PureComponent {
1313
render () {
14-
const { method, classes, initialSchemaTreeDepth } = this.props
15-
const { title, type, description, parameters, request, responses } = method
14+
const {method, classes, initialSchemaTreeDepth} = this.props
15+
const {title, type, path, endpoints, description, parameters, request, responses} = method
1616

1717
return (
1818
<ScrollableAnchor id={method.link}>
1919
<div className={classes.method}>
2020
<h3>
2121
{title}
22-
<span className={classNames(classes.type, `${method.type}`)}>{type}</span>
2322
</h3>
23+
<MethodEndpoints type={type} path={path} endpoints={endpoints} />
2424
<div>
2525
{description && <Description description={description} />}
2626
{parameters && <Parameters parameters={parameters} initialSchemaTreeDepth={initialSchemaTreeDepth} />}
@@ -33,7 +33,7 @@ export default class Method extends PureComponent {
3333
}
3434

3535
renderRequest (request, initialSchemaTreeDepth) {
36-
const { schema, examples } = request
36+
const {schema, examples} = request
3737

3838
if (!schema) {
3939
return null
@@ -65,7 +65,9 @@ Method.propTypes = {
6565
description: PropTypes.string,
6666
parameters: PropTypes.object,
6767
request: PropTypes.object,
68-
responses: PropTypes.array
68+
responses: PropTypes.array,
69+
path: PropTypes.string,
70+
endpoints: PropTypes.array
6971
}),
7072
classes: PropTypes.object,
7173
initialSchemaTreeDepth: PropTypes.number

src/components/Method/Method.styles.js

+2-19
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,8 @@ export const styles = createSheet(({ borders, text, sizes }) => ({
88
padding: '1rem 2rem',
99

1010
'& > h3': {
11-
marginBottom: '15px',
12-
'& > span': {
13-
fontFamily: 'monospace',
14-
textTransform: 'uppercase',
15-
marginLeft: '10px',
16-
17-
'&.get': {
18-
color: `${text.get}`
19-
},
20-
'&.post': {
21-
color: `${text.post}`
22-
},
23-
'&.put': {
24-
color: `${text.put}`
25-
},
26-
'&.delete': {
27-
color: `${text.delete}`
28-
}
29-
}
11+
display: 'inline-block',
12+
marginBottom: '15px'
3013
},
3114

3215
'& h4': {
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React, { PureComponent } from 'react'
2+
import PropTypes from 'prop-types'
3+
import classNames from 'classnames'
4+
import Endpoints from '../Endpoints/Endpoints'
5+
import Indicator from '../Indicator/Indicator'
6+
import { styles } from './MethodEndpoints.styles'
7+
8+
@styles
9+
export default class MethodEndpoints extends PureComponent {
10+
constructor (props) {
11+
super(props)
12+
13+
this.onClickPath = this.onClickPath.bind(this)
14+
15+
this.state = {
16+
isServersExpanded: false
17+
}
18+
}
19+
20+
render () {
21+
const {type, path, endpoints, classes} = this.props
22+
23+
let indicatorDirection = 'downn'
24+
if (this.state.isServersExpanded) {
25+
indicatorDirection = 'up'
26+
}
27+
28+
return (
29+
<div className={classNames(classes.methodPath)}>
30+
<div onClick={this.onClickPath}>
31+
<span className={classNames(type, 'methodType')}>{type}</span>
32+
<span className='path'>{path}</span>
33+
<Indicator direction={indicatorDirection} />
34+
</div>
35+
{endpoints &&
36+
<div className={classNames(classes.methodServers, {
37+
[classes.expanded]: this.state.isServersExpanded
38+
})}>
39+
<Endpoints endpoints={endpoints} />
40+
</div>
41+
}
42+
</div>
43+
)
44+
}
45+
46+
onClickPath () {
47+
this.setState({
48+
isServersExpanded: !this.state.isServersExpanded
49+
})
50+
}
51+
}
52+
53+
MethodEndpoints.propTypes = {
54+
type: PropTypes.string.isRequired,
55+
path: PropTypes.string.isRequired,
56+
endpoints: PropTypes.arrayOf(PropTypes.shape({
57+
url: PropTypes.string.isRequired,
58+
description: PropTypes.string
59+
})),
60+
classes: PropTypes.object
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { createSheet } from '../../theme'
2+
3+
export const styles = createSheet(({borders, text, sizes}) => ({
4+
methodPath: {
5+
display: 'inline-block',
6+
fontFamily: 'monospace',
7+
marginLeft: '30px',
8+
position: 'relative',
9+
10+
'& .methodType': {
11+
textTransform: 'uppercase',
12+
marginRight: '10px',
13+
'&.get': {
14+
color: `${text.get}`
15+
},
16+
'&.post': {
17+
color: `${text.post}`
18+
},
19+
'&.put': {
20+
color: `${text.put}`
21+
},
22+
'&.delete': {
23+
color: `${text.delete}`
24+
},
25+
'&.path': {
26+
textTransform: 'none'
27+
}
28+
}
29+
},
30+
methodServers: {
31+
display: 'none'
32+
},
33+
expanded: {
34+
// outline: '1px solid red',
35+
display: 'block',
36+
position: 'absolute',
37+
backgroundColor: 'white'
38+
}
39+
}))

src/parser/open-api/v3/navigationParser.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@ export function getNavigationMethod (path, method, tag) {
3434
* a response for the given `method`.
3535
*
3636
* @param {string} path
37+
* @param {Array} servers
3738
* @param {object} method
3839
* @param {object} request
3940
* @param {object} params
4041
* @param {object} responses
4142
*/
42-
export function getServicesMethod ({ path, method, request, params, responses }) {
43+
export function getServicesMethod ({path, servers, method, request, params, responses}) {
4344
const servicesMethod = {
4445
type: method.type,
4546
title: method.summary,
4647
link: getPermalink(path, method.type),
48+
path,
4749
request,
4850
responses
4951
}
@@ -56,5 +58,19 @@ export function getServicesMethod ({ path, method, request, params, responses })
5658
servicesMethod.parameters = params
5759
}
5860

61+
if (servers && servers.length > 0) {
62+
servicesMethod.endpoints = servers.map(server => {
63+
const endpoint = {
64+
url: server.url + path
65+
}
66+
67+
if (server.description) {
68+
endpoint.description = server.description
69+
}
70+
71+
return endpoint
72+
})
73+
}
74+
5975
return servicesMethod
6076
}

0 commit comments

Comments
 (0)