diff --git a/docs/open-api-v3-support.md b/docs/open-api-v3-support.md
index 0410966..955a7e5 100644
--- a/docs/open-api-v3-support.md
+++ b/docs/open-api-v3-support.md
@@ -31,7 +31,7 @@ This document outlines this project's support for visualising the [Open API V3][
- [ ] [components](#components-object)
- [x] [security](#security-requirement-object)
- [x] [tags](#tag-object)
-- [ ] [externalDocs](#external-documentation-object)
+- [x] [externalDocs](#external-documentation-object)
### [Info](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#info-object) object
@@ -104,7 +104,7 @@ This is supported by default as all `$ref` are dereferenced before the definitio
- [x] tags
- [x] summary
- [x] description
-- [ ] [externalDocs](#external-documentation-object)
+- [x] [externalDocs](#external-documentation-object)
- [ ] operationId
- [x] [parameters](#parameter-object)
- [x] [requestBody](#request-body-object)
@@ -116,8 +116,8 @@ This is supported by default as all `$ref` are dereferenced before the definitio
### [External Documentation](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#external-documentation-object) object
-- [ ] description
-- [ ] url
+- [x] description
+- [x] url
### [Parameter](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#parameter-object) object
@@ -209,7 +209,7 @@ See [parameter](#parameter-object) object.
- [x] name
- [x] description
-- [ ] [externalDocs](#external-documentation-object)
+- [x] [externalDocs](#external-documentation-object)
### [Reference](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#reference-object) object
@@ -263,7 +263,7 @@ The OpenAPI specification also supports several additional properties from JSON
- [ ] readOnly
- [ ] writeOnly
- [ ] [xml](#xml-object)
-- [ ] [externalDocs](#external-documentation-object)
+- [x] [externalDocs](#external-documentation-object)
- [ ] example
- [ ] deprecated
diff --git a/src/components/BodyContent/BodyContent.styles.js b/src/components/BodyContent/BodyContent.styles.js
index 6c3467e..3ed1151 100644
--- a/src/components/BodyContent/BodyContent.styles.js
+++ b/src/components/BodyContent/BodyContent.styles.js
@@ -5,14 +5,14 @@ export const styles = createSheet(({ text, backgrounds, sizes }) => ({
'bodyContent': {
display: 'table',
width: '100%',
- padding: '10px',
+ padding: '1rem 0',
boxSizing: 'border-box'
},
'tabs': {
'& > div': {
display: 'inline-block',
- padding: '10px 20px',
+ padding: '1rem 2rem',
cursor: 'pointer',
'&:not($active)': {
@@ -23,12 +23,6 @@ export const styles = createSheet(({ text, backgrounds, sizes }) => ({
'active': {
backgroundColor: `${backgrounds.schema}`,
- borderRadius: '10px 10px 0 0'
- },
-
- [`@media (max-width: ${sizes.breakpoint})`]: {
- 'bodyContent': {
- padding: '10px 0'
- }
+ borderRadius: '1rem 1rem 0 0'
}
}))
diff --git a/src/components/BodySchema/BodySchema.js b/src/components/BodySchema/BodySchema.js
index a3ec6c7..1ce2ab9 100644
--- a/src/components/BodySchema/BodySchema.js
+++ b/src/components/BodySchema/BodySchema.js
@@ -77,6 +77,7 @@ export default class BodySchema extends Component {
defaultValue={property.defaultValue}
constraints={property.constraints}
attributes={property.attributes}
+ docs={property.docs}
onClick={hasSubset ? this.onClick : undefined}
isRequired={property.required}
isOpen={isOpen}
diff --git a/src/components/ContentContainer/ContentContainer.styles.js b/src/components/ContentContainer/ContentContainer.styles.js
index 89c5871..aca4394 100644
--- a/src/components/ContentContainer/ContentContainer.styles.js
+++ b/src/components/ContentContainer/ContentContainer.styles.js
@@ -2,19 +2,15 @@ import { createSheet } from '../../theme'
export const styles = createSheet(({ sizes }) => ({
'contentContainer': {
- padding: '20px 0',
-
- '& h2': {
- paddingLeft: '2rem'
- }
+ padding: '0.5rem 2rem',
+ margin: '1rem 0'
},
[`@media (max-width: ${sizes.breakpoint})`]: {
'contentContainer': {
- padding: '10px 0',
+ padding: '1rem 0',
'& h2': {
- paddingLeft: '1rem',
margin: 0
}
}
diff --git a/src/components/Description/Description.styles.js b/src/components/Description/Description.styles.js
index ec60ff5..6537f6d 100644
--- a/src/components/Description/Description.styles.js
+++ b/src/components/Description/Description.styles.js
@@ -3,10 +3,8 @@ import { createSheet } from '../../theme'
export const styles = createSheet(({ text }) => ({
'description': {
- '&:not($inline)': {
- color: `${c(text.default).lighten(0.3)}`,
- fontSize: '0.9em'
- },
+ color: `${c(text.default).lighten(0.3)}`,
+ fontSize: '1rem',
'&$inline': {
'&, & p': {
@@ -17,5 +15,7 @@ export const styles = createSheet(({ text }) => ({
margin: '.5rem 0'
}
},
- 'inline': {}
+ 'inline': {
+ paddingRight: '.2rem'
+ }
}))
diff --git a/src/components/Docs/Docs.js b/src/components/Docs/Docs.js
new file mode 100644
index 0000000..2b51a38
--- /dev/null
+++ b/src/components/Docs/Docs.js
@@ -0,0 +1,27 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import classNames from 'classnames'
+
+import Description from '../Description/Description'
+import ExternalLink from '../ExternalLink/ExternalLink'
+import { styles } from './Docs.styles'
+
+@styles
+export default class Docs extends PureComponent {
+ render () {
+ const { url, description, classes } = this.props
+
+ return (
+
+ {description && }
+ More information
+
+ )
+ }
+}
+
+Docs.propTypes = {
+ description: PropTypes.string,
+ url: PropTypes.string.isRequired,
+ classes: PropTypes.object
+}
diff --git a/src/components/Docs/Docs.styles.js b/src/components/Docs/Docs.styles.js
new file mode 100644
index 0000000..3c23c93
--- /dev/null
+++ b/src/components/Docs/Docs.styles.js
@@ -0,0 +1,7 @@
+import { createSheet } from '../../theme'
+
+export const styles = createSheet(() => ({
+ 'docs': {
+ margin: '0.5rem 0'
+ }
+}))
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
index 0f8306d..ae608d9 100644
--- a/src/components/Header/Header.js
+++ b/src/components/Header/Header.js
@@ -1,6 +1,7 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
+import Docs from '../Docs/Docs'
import Description from '../Description/Description'
import ExternalLink from '../ExternalLink/ExternalLink'
import { styles } from './Header.styles'
@@ -28,6 +29,8 @@ export default class Header extends PureComponent {
{info && info.termsOfService &&
Terms of Service}
+
+ {info && info.docs && }
)
}
@@ -88,7 +91,11 @@ Header.propTypes = {
info: PropTypes.shape({
contact: PropTypes.object,
license: PropTypes.object,
- termsOfService: PropTypes.string
+ termsOfService: PropTypes.string,
+ docs: PropTypes.shape({
+ description: PropTypes.string,
+ url: PropTypes.string.isRequired
+ })
}),
definitionUrl: PropTypes.string,
classes: PropTypes.object
diff --git a/src/components/Header/Header.styles.js b/src/components/Header/Header.styles.js
index eaacc4d..97a58f4 100644
--- a/src/components/Header/Header.styles.js
+++ b/src/components/Header/Header.styles.js
@@ -2,7 +2,7 @@ import { createSheet } from '../../theme'
export const styles = createSheet(({ borders, sizes }) => ({
'header': {
- padding: '0 20px',
+ padding: '0 2rem',
'& h1': {
marginBottom: '.5rem'
diff --git a/src/components/Method/Method.styles.js b/src/components/Method/Method.styles.js
index 5ae0874..72ab562 100644
--- a/src/components/Method/Method.styles.js
+++ b/src/components/Method/Method.styles.js
@@ -5,7 +5,7 @@ export const styles = createSheet(({ borders, text, sizes }) => ({
method: {
borderBottom: `1px solid ${borders.default}`,
margin: '0 1rem 2rem 0',
- padding: '1rem 2rem',
+ padding: '1rem 0',
'& > h3': {
marginBottom: '15px',
diff --git a/src/components/NavigationTag/NavigationTag.js b/src/components/NavigationTag/NavigationTag.js
index c9510be..996ec73 100644
--- a/src/components/NavigationTag/NavigationTag.js
+++ b/src/components/NavigationTag/NavigationTag.js
@@ -1,6 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
+
import Indicator from '../Indicator/Indicator'
import NavigationMethod from '../NavigationMethod/NavigationMethod'
import Description from '../Description/Description'
@@ -89,11 +90,11 @@ export default class NavigationTag extends Component {
NavigationTag.propTypes = {
title: PropTypes.string.isRequired,
+ hash: PropTypes.string.isRequired,
description: PropTypes.string,
methods: PropTypes.array,
shouldBeExpanded: PropTypes.bool,
onClick: PropTypes.func.isRequired,
- hash: PropTypes.string.isRequired,
- classes: PropTypes.object,
- onClickMethod: PropTypes.func
+ onClickMethod: PropTypes.func,
+ classes: PropTypes.object
}
diff --git a/src/components/Page/Page.js b/src/components/Page/Page.js
index 0755294..175724b 100644
--- a/src/components/Page/Page.js
+++ b/src/components/Page/Page.js
@@ -48,9 +48,17 @@ export default class Page extends Component {
/>
{security && this.renderSecurity(security)}
- {services && services.map(
- (service) =>
- )}
+ {services && services.map((service) => {
+ const serviceWithDocs = Object.assign({}, service, this.findTagDocs(service.title, navigation))
+
+ return (
+
+ )
+ })}
@@ -68,6 +76,21 @@ export default class Page extends Component {
)
}
+ findTagDocs (tagHandle, navigation) {
+ // Find navigation tag that matches given `tagHandle`, and if has docs.
+ // Note: tag.methods is a way to determine if the navigation has tags at all.
+ const navigationTag = navigation.find((tag) => (tag.methods && tag.handle === tagHandle && tag.docs))
+
+ // No tag, no additional docs.
+ if (!navigationTag) {
+ return {}
+ }
+
+ return {
+ docs: navigationTag.docs
+ }
+ }
+
onToggleNavigation () {
const { isNavOpen } = this.state
if (isNavOpen) {
diff --git a/src/components/Property/Property.js b/src/components/Property/Property.js
index 49e36f0..f9333e6 100644
--- a/src/components/Property/Property.js
+++ b/src/components/Property/Property.js
@@ -1,6 +1,8 @@
import React, { PureComponent } from 'react'
import classNames from 'classnames'
import PropTypes from 'prop-types'
+
+import Docs from '../Docs/Docs'
import Description from '../Description/Description'
import Indicator from '../Indicator/Indicator'
import PropertyConstraints from './PropertyConstraints/PropertyConstraints'
@@ -47,9 +49,8 @@ export default class Property extends PureComponent {
render () {
const {
- type, title, description, constraints, isRequired,
- defaultValue, onClick, isOpen, isLast, attributes,
- classes
+ type, title, description, constraints, docs, defaultValue, attributes,
+ isRequired, isOpen, isLast, onClick, classes
} = this.props
const {name, isEnumTrimmed} = this.state
@@ -104,6 +105,7 @@ export default class Property extends PureComponent {
{enumValues && this.renderEnumValues(enumValues, isEnumTrimmed)}
{defaultValue !== undefined && this.renderDefaultValue(defaultValue)}
{description &&
}
+ {docs && }
}
diff --git a/src/components/SecurityContainer/SecurityContainer.styles.js b/src/components/SecurityContainer/SecurityContainer.styles.js
index d16826b..2f49738 100644
--- a/src/components/SecurityContainer/SecurityContainer.styles.js
+++ b/src/components/SecurityContainer/SecurityContainer.styles.js
@@ -2,7 +2,7 @@ import { createSheet } from '../../theme'
export const styles = createSheet(({ backgrounds, borders, sizes }) => ({
'securityContainer': {
- padding: '1rem 2rem',
+ padding: '1rem 0',
borderBottom: `1px solid ${borders.default}`
},
@@ -26,11 +26,5 @@ export const styles = createSheet(({ backgrounds, borders, sizes }) => ({
'& > li > span': {
fontWeight: 600
}
- },
-
- [`@media (max-width: ${sizes.breakpoint})`]: {
- 'securityContainer': {
- padding: '1rem'
- }
}
}))
diff --git a/src/components/ServiceContainer/ServiceContainer.js b/src/components/ServiceContainer/ServiceContainer.js
index 6d093c8..9baa6ac 100644
--- a/src/components/ServiceContainer/ServiceContainer.js
+++ b/src/components/ServiceContainer/ServiceContainer.js
@@ -1,5 +1,7 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
+
+import Docs from '../Docs/Docs'
import Method from '../Method/Method'
import { styles } from './ServiceContainer.styles'
@@ -7,11 +9,12 @@ import { styles } from './ServiceContainer.styles'
export default class ServiceContainer extends PureComponent {
render () {
const { service, classes, initialSchemaTreeDepth } = this.props
- const { title, methods } = service
+ const { title, docs, methods } = service
return (
{title}
+ {docs && }
{methods.map(
(method) =>
)}
diff --git a/src/parser/open-api/schemaParser.js b/src/parser/open-api/schemaParser.js
index e34dad1..4d36949 100644
--- a/src/parser/open-api/schemaParser.js
+++ b/src/parser/open-api/schemaParser.js
@@ -55,6 +55,10 @@ function getPropertyNode (nodeName, propertyNode, required = false) {
outputNode.defaultValue = propertyNode.default
}
+ if (propertyNode.externalDocs) {
+ outputNode.docs = propertyNode.externalDocs
+ }
+
if (propertyNode.additionalProperties === false) {
outputNode.additionalProperties = false
}
diff --git a/src/parser/open-api/v3/navigationParser.js b/src/parser/open-api/v3/navigationParser.js
index e7a960d..f1688fe 100644
--- a/src/parser/open-api/v3/navigationParser.js
+++ b/src/parser/open-api/v3/navigationParser.js
@@ -52,6 +52,10 @@ export function getServicesMethod ({ path, method, request, params, responses })
servicesMethod.description = method.description
}
+ if (method.externalDocs) {
+ servicesMethod.docs = method.externalDocs
+ }
+
if (params) {
servicesMethod.parameters = params
}
diff --git a/src/parser/open-api/v3/open-api-v3-parser.js b/src/parser/open-api/v3/open-api-v3-parser.js
index 5d4ccbc..d3aad7b 100644
--- a/src/parser/open-api/v3/open-api-v3-parser.js
+++ b/src/parser/open-api/v3/open-api-v3-parser.js
@@ -193,10 +193,13 @@ function getUIParametersForLocation (parameters, location) {
const resultArray = parameters.filter(parameter => (parameter.in === location)).map(parameter => {
const uiParameter = {
name: parameter.name,
- description: parameter.description,
required: parameter.required
}
+ if (parameter.description && parameter.description !== '') {
+ uiParameter.description = parameter.description
+ }
+
// TODO: We set the type to be an array because the Property component
// handles this. Property should eventually be split and this won't be
// necessary...
@@ -226,7 +229,7 @@ function getUIParametersForLocation (parameters, location) {
function getUIRequest (description, requestBody = null) {
const uiRequest = {}
- if (description) {
+ if (description && description !== '') {
uiRequest.description = description
}
@@ -252,10 +255,12 @@ function getUIResponses (responses) {
for (const statusCode in responses) {
const response = responses[statusCode]
-
const uiResponse = {
- code: statusCode,
- description: response.description
+ code: statusCode
+ }
+
+ if (response.description && response.description !== '') {
+ uiResponse.description = response.description
}
const mediaType = getMediaType(response.content)
@@ -341,12 +346,12 @@ function addTagDetailsToNavigation (navigation, tagDefinitions) {
navGroup.handle = navGroup.title
navGroup.title = tagDefinition.name
- if (tagDefinition.description) {
+ if (tagDefinition.description && tagDefinition.description !== '') {
navGroup.description = tagDefinition.description
}
if (tagDefinition.externalDocs) {
- navGroup.externalDocs = tagDefinition.externalDocs
+ navGroup.docs = tagDefinition.externalDocs
}
}
}
@@ -390,6 +395,10 @@ export default async function getUIReadyDefinition (openApiV3, sortFunc) {
delete infoObj.version
delete infoObj.description
+ if (derefOpenApiV3.externalDocs) {
+ infoObj.docs = derefOpenApiV3.externalDocs
+ }
+
const definition = {
title: info.title,
version: info.version,
diff --git a/test/parser/open-api/v3/data/inputs/petstore.false.json b/test/parser/open-api/v3/data/inputs/petstore.false.json
index c3f370a..c810158 100644
--- a/test/parser/open-api/v3/data/inputs/petstore.false.json
+++ b/test/parser/open-api/v3/data/inputs/petstore.false.json
@@ -232,6 +232,10 @@
"summary": "Find pet by ID",
"description": "Returns a single pet",
"operationId": "getPetById",
+ "externalDocs": {
+ "description": "Find out more about our store",
+ "url": "http://swagger.io"
+ },
"parameters": [
{
"name": "petId",
@@ -946,7 +950,10 @@
"properties": {
"id": {
"type": "integer",
- "format": "int64"
+ "format": "int64",
+ "externalDocs": {
+ "url": "http://petstore.swagger.io/v2"
+ }
},
"category": {
"$ref": "#/components/schemas/Category"
diff --git a/test/parser/open-api/v3/data/outputs/petstore.false.json b/test/parser/open-api/v3/data/outputs/petstore.false.json
index 9780c20..ca10d0f 100644
--- a/test/parser/open-api/v3/data/outputs/petstore.false.json
+++ b/test/parser/open-api/v3/data/outputs/petstore.false.json
@@ -10,6 +10,10 @@
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ },
+ "docs": {
+ "description": "Find out more about Swagger",
+ "url": "http://swagger.io"
}
},
"navigation": [
@@ -59,7 +63,7 @@
],
"handle": "pet",
"description": "Everything about your Pets",
- "externalDocs": {
+ "docs": {
"description": "Find out more",
"url": "http://swagger.io"
}
@@ -137,7 +141,7 @@
],
"handle": "user",
"description": "Operations about user",
- "externalDocs": {
+ "docs": {
"description": "Find out more about our store",
"url": "http://swagger.io"
}
@@ -161,6 +165,9 @@
"required": false,
"constraints": {
"format": "int64"
+ },
+ "docs": {
+ "url": "http://petstore.swagger.io/v2"
}
},
{
@@ -286,6 +293,9 @@
"required": false,
"constraints": {
"format": "int64"
+ },
+ "docs": {
+ "url": "http://petstore.swagger.io/v2"
}
},
{
@@ -432,6 +442,9 @@
"required": false,
"constraints": {
"format": "int64"
+ },
+ "docs": {
+ "url": "http://petstore.swagger.io/v2"
}
},
{
@@ -583,6 +596,9 @@
"required": false,
"constraints": {
"format": "int64"
+ },
+ "docs": {
+ "url": "http://petstore.swagger.io/v2"
}
},
{
@@ -711,6 +727,10 @@
"type": "get",
"title": "Find pet by ID",
"link": "/pet/{petId}/get",
+ "docs": {
+ "description": "Find out more about our store",
+ "url": "http://swagger.io"
+ },
"request": {
"description": "Returns a single pet"
},
@@ -727,6 +747,9 @@
"required": false,
"constraints": {
"format": "int64"
+ },
+ "docs": {
+ "url": "http://petstore.swagger.io/v2"
}
},
{