Skip to content

Commit

Permalink
feat: Render external docs links and descriptions (#7559)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim Lai <timothy.lai@smartbear.com>
  • Loading branch information
fabsrc and tim-lai authored Aug 17, 2022
1 parent 7dd167b commit 6ae2693
Show file tree
Hide file tree
Showing 10 changed files with 443 additions and 14 deletions.
12 changes: 11 additions & 1 deletion src/core/components/array-model.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { sanitizeUrl } from "core/utils"

const propClass = "property"

Expand All @@ -25,12 +26,16 @@ export default class ArrayModel extends Component {
let description = schema.get("description")
let items = schema.get("items")
let title = schema.get("title") || displayName || name
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref"].indexOf(key) === -1 )
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref", "externalDocs"].indexOf(key) === -1 )
let externalDocsUrl = schema.getIn(["externalDocs", "url"])
let externalDocsDescription = schema.getIn(["externalDocs", "description"])


const Markdown = getComponent("Markdown", true)
const ModelCollapse = getComponent("ModelCollapse")
const Model = getComponent("Model")
const Property = getComponent("Property")
const Link = getComponent("Link")

const titleEl = title &&
<span className="model-title">
Expand All @@ -52,6 +57,11 @@ export default class ArrayModel extends Component {
!description ? (properties.size ? <div className="markdown"></div> : null) :
<Markdown source={ description } />
}
{ externalDocsUrl &&
<div className="external-docs">
<Link target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
</div>
}
<span>
<Model
{ ...this.props }
Expand Down
16 changes: 15 additions & 1 deletion src/core/components/object-model.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component, } from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
import { sanitizeUrl } from "core/utils"

const braceOpen = "{"
const braceClose = "}"
Expand Down Expand Up @@ -44,12 +45,15 @@ export default class ObjectModel extends Component {
let infoProperties = schema
.filter( ( v, key) => ["maxProperties", "minProperties", "nullable", "example"].indexOf(key) !== -1 )
let deprecated = schema.get("deprecated")
let externalDocsUrl = schema.getIn(["externalDocs", "url"])
let externalDocsDescription = schema.getIn(["externalDocs", "description"])

const JumpToPath = getComponent("JumpToPath", true)
const Markdown = getComponent("Markdown", true)
const Model = getComponent("Model")
const ModelCollapse = getComponent("ModelCollapse")
const Property = getComponent("Property")
const Link = getComponent("Link")

const JumpToPathSection = () => {
return <span className="model-jump-to-path"><JumpToPath specPath={specPath} /></span>
Expand Down Expand Up @@ -93,6 +97,17 @@ export default class ObjectModel extends Component {
</td>
</tr>
}
{
externalDocsUrl &&
<tr className={"external-docs"}>
<td>
externalDocs:
</td>
<td>
<Link target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
</td>
</tr>
}
{
!deprecated ? null :
<tr className={"property"}>
Expand All @@ -103,7 +118,6 @@ export default class ObjectModel extends Component {
true
</td>
</tr>

}
{
!(properties && properties.size) ? null : properties.entrySeq().filter(
Expand Down
10 changes: 3 additions & 7 deletions src/core/components/operation-tag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,14 @@ export default class OperationTag extends React.Component {
</small>
}

{!tagExternalDocsDescription ? null :
{!tagExternalDocsUrl ? null :
<div className="info__externaldocs">
<small>
{tagExternalDocsDescription}
{tagExternalDocsUrl ? ": " : null}
{tagExternalDocsUrl ?
<Link
<Link
href={sanitizeUrl(tagExternalDocsUrl)}
onClick={(e) => e.stopPropagation()}
target="_blank"
>{tagExternalDocsUrl}</Link> : null
}
>{tagExternalDocsDescription || tagExternalDocsUrl}</Link>
</small>
</div>
}
Expand Down
8 changes: 5 additions & 3 deletions src/core/components/operation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ export default class Operation extends PureComponent {
<div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs">
<span className="opblock-external-docs__description">
<Markdown source={ externalDocs.description } />
</span>
{externalDocs.description &&
<span className="opblock-external-docs__description">
<Markdown source={ externalDocs.description } />
</span>
}
<Link target="_blank" className="opblock-external-docs__link" href={sanitizeUrl(externalDocsUrl)}>{externalDocsUrl}</Link>
</div>
</div> : null
Expand Down
15 changes: 13 additions & 2 deletions src/core/components/primitive-model.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import { getExtensions } from "core/utils"
import { getExtensions, sanitizeUrl } from "core/utils"

const propClass = "property primitive"

Expand Down Expand Up @@ -33,12 +33,17 @@ export default class Primitive extends Component {
let description = schema.get("description")
let extensions = getExtensions(schema)
let properties = schema
.filter((_, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1)
.filter((_, key) => ["enum", "type", "format", "description", "$$ref", "externalDocs"].indexOf(key) === -1)
.filterNot((_, key) => extensions.has(key))
let externalDocsUrl = schema.getIn(["externalDocs", "url"])
let externalDocsDescription = schema.getIn(["externalDocs", "description"])

const Markdown = getComponent("Markdown", true)
const EnumModel = getComponent("EnumModel")
const Property = getComponent("Property")
const ModelCollapse = getComponent("ModelCollapse")
const Link = getComponent("Link")

const titleEl = title &&
<span className="model-title">
<span className="model-title__text">{title}</span>
Expand All @@ -60,6 +65,12 @@ export default class Primitive extends Component {
!description ? null :
<Markdown source={description} />
}
{
externalDocsUrl &&
<div className="external-docs">
<Link target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
</div>
}
{
xml && xml.size ? (<span><br /><span className={propClass}>xml:</span>
{
Expand Down
5 changes: 5 additions & 0 deletions src/style/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@
flex: 1;
}
}

.info__externaldocs
{
text-align: right;
}
}

.parameter__type
Expand Down
19 changes: 19 additions & 0 deletions src/style/_models.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@
color: #6b6b6b;
}
}

.external-docs
{
color: #666;
font-weight: normal;
}
}

table.model
Expand Down Expand Up @@ -157,6 +163,19 @@ table.model
vertical-align: top;
}
}

&.external-docs
{
td:first-child
{
font-weight: bold;
}
}

.renderedMarkdown p:first-child
{
margin-top: 0;
}
}
}

Expand Down
148 changes: 148 additions & 0 deletions test/e2e-cypress/static/documents/features/external-docs.openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
openapi: 3.0.2

info:
title: External Docs
version: "1"

externalDocs:
description: Read external docs
url: http://swagger.io

tags:
- name: pet
description: Everything about your Pets
externalDocs:
description: Pet Documentation
url: http://swagger.io
- name: petWithoutDescription
externalDocs:
url: http://swagger.io

paths:
/pet:
put:
externalDocs:
description: More details about putting a pet
url: http://swagger.io
tags:
- pet
summary: Update an existing pet
description: Update an existing pet by Id
operationId: updatePet
requestBody:
description: Update an existent pet in the store
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
required: true
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
"400":
description: Invalid ID supplied
"404":
description: Pet not found
"405":
description: Validation exception
post:
externalDocs:
url: http://swagger.io
tags:
- pet
summary: Add a new pet to the store
description: Add a new pet to the store
operationId: addPet
requestBody:
description: Create a new pet in the store
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
required: true
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
"405":
description: Invalid input

components:
schemas:
Pet:
required:
- name
- photoUrls
type: object
description: This is a Pet
externalDocs:
description: More Docs About Pet
url: http://swagger.io
deprecated: true
properties:
id:
type: integer
format: int64
example: 10
name:
type: string
example: doggie
photoUrls:
type: array
items:
type: string
status:
type: string
description: pet status in the store
enum:
- available
- pending
- sold
Object:
type: object
externalDocs:
description: Object Docs
url: http://swagger.io
properties:
name:
type: string
ObjectWithoutDescription:
type: object
externalDocs:
url: http://swagger.io
properties:
name:
type: string
Primitive:
description: Just a string schema
type: string
externalDocs:
description: Primitive Docs
url: http://swagger.io
PrimitiveWithoutDescription:
description: Just a string schema
type: string
externalDocs:
url: http://swagger.io
Array:
description: Just an array schema
type: array
externalDocs:
description: Array Docs
url: http://swagger.io
items:
type: string
ArrayWithoutDescription:
description: Just an array schema
type: array
externalDocs:
url: http://swagger.io
items:
type: string
Loading

0 comments on commit 6ae2693

Please sign in to comment.