feat: syntax highlighting of code section (#6236)

Co-authored-by: AdrieanKhisbe <adriean.khisbe@live.fr>
This commit is contained in:
Tim Lai
2020-07-17 15:29:15 -07:00
committed by GitHub
parent 9e294fbab5
commit a73783b73d
20 changed files with 340 additions and 228 deletions

View File

@@ -1,26 +1,42 @@
import React from "react"
import PropTypes from "prop-types"
import curlify from "core/curlify"
import { CopyToClipboard } from "react-copy-to-clipboard"
import {SyntaxHighlighter, getStyle} from "core/syntax-highlighting"
import get from "lodash/get"
export default class Curl extends React.Component {
static propTypes = {
getConfigs: PropTypes.func.isRequired,
request: PropTypes.object.isRequired
}
handleFocus(e) {
e.target.select()
document.execCommand("copy")
}
render() {
let { request } = this.props
let { request, getConfigs } = this.props
let curl = curlify(request)
const config = getConfigs()
const curlBlock = get(config, "syntaxHighlight.activated")
? <SyntaxHighlighter
language="bash"
className="curl microlight"
onWheel={this.preventYScrollingBeyondElement}
style={getStyle(get(config, "syntaxHighlight.theme"))}
>
{curl}
</SyntaxHighlighter>
:
<textarea readOnly={true} className="curl" value={curl}></textarea>
return (
<div>
<div className="curl-command">
<h4>Curl</h4>
<div className="copy-paste">
<textarea onFocus={this.handleFocus} readOnly={true} className="curl" value={curl}></textarea>
<div className="copy-to-clipboard">
<CopyToClipboard text={curl}><button/></CopyToClipboard>
</div>
<div>
{curlBlock}
</div>
</div>
)

View File

@@ -1,30 +1,20 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import { highlight } from "core/utils"
import {SyntaxHighlighter, getStyle} from "core/syntax-highlighting"
import get from "lodash/get"
import saveAs from "js-file-download"
import { CopyToClipboard } from "react-copy-to-clipboard"
export default class HighlightCode extends Component {
static propTypes = {
value: PropTypes.string.isRequired,
getConfigs: PropTypes.func.isRequired,
className: PropTypes.string,
downloadable: PropTypes.bool,
fileName: PropTypes.string,
canCopy: PropTypes.bool
}
componentDidMount() {
highlight(this.el)
}
componentDidUpdate() {
highlight(this.el)
}
initializeComponent = (c) => {
this.el = c
}
downloadText = () => {
saveAs(this.props.value, this.props.fileName || "response.txt")
}
@@ -49,9 +39,22 @@ export default class HighlightCode extends Component {
}
render () {
let { value, className, downloadable, canCopy } = this.props
let { value, className, downloadable, getConfigs, canCopy } = this.props
const config = getConfigs ? getConfigs() : {syntaxHighlight: {activated: true, theme: "agate"}}
className = className || ""
const codeBlock = get(config, "syntaxHighlight.activated")
? <SyntaxHighlighter
className={className + " microlight"}
onWheel={this.preventYScrollingBeyondElement}
style={getStyle(get(config, "syntaxHighlight.theme"))}
>
{value}
</SyntaxHighlighter>
: <pre onWheel={this.preventYScrollingBeyondElement} className={className + " microlight"}>{value}</pre>
return (
<div className="highlight-code">
{ !downloadable ? null :
@@ -66,12 +69,7 @@ export default class HighlightCode extends Component {
</div>
}
<pre
ref={this.initializeComponent}
onWheel={this.preventYScrollingBeyondElement}
className={className + " microlight"}>
{value}
</pre>
{ codeBlock }
</div>
)
}

View File

@@ -71,7 +71,7 @@ export default class LiveResponse extends React.Component {
return (
<div>
{ curlRequest && <Curl request={ curlRequest }/> }
{ curlRequest && <Curl request={ curlRequest } getConfigs={ getConfigs } /> }
{ url && <div>
<h4>Request URL</h4>
<div className="request-url">
@@ -110,6 +110,7 @@ export default class LiveResponse extends React.Component {
contentType={ contentType }
url={ url }
headers={ headers }
getConfigs={ getConfigs }
getComponent={ getComponent }/>
: null
}

View File

@@ -14,6 +14,7 @@ export default class ParamBody extends PureComponent {
consumes: PropTypes.object,
consumesValue: PropTypes.string,
fn: PropTypes.object.isRequired,
getConfigs: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,
isExecute: PropTypes.bool,
specSelectors: PropTypes.object.isRequired,
@@ -96,7 +97,7 @@ export default class ParamBody extends PureComponent {
isExecute,
specSelectors,
pathMethod,
getConfigs,
getComponent,
} = this.props
@@ -118,6 +119,7 @@ export default class ParamBody extends PureComponent {
isEditBox && isExecute
? <TextArea className={ "body-param__text" + ( errors.count() ? " invalid" : "")} value={value} onChange={ this.handleOnChange }/>
: (value && <HighlightCode className="body-param__example"
getConfigs={ getConfigs }
value={ value }/>)
}
<div className="body-param-options">

View File

@@ -191,6 +191,7 @@ export default class ParameterRow extends Component {
let inType = param.get("in")
let bodyParam = inType !== "body" ? null
: <ParamBody getComponent={getComponent}
getConfigs={ getConfigs }
fn={fn}
param={param}
consumes={ specSelectors.consumesOptionsFor(pathMethod) }

View File

@@ -13,6 +13,7 @@ export default class ResponseBody extends React.PureComponent {
static propTypes = {
content: PropTypes.any.isRequired,
contentType: PropTypes.string,
getConfigs: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,
headers: PropTypes.object,
url: PropTypes.string
@@ -49,7 +50,7 @@ export default class ResponseBody extends React.PureComponent {
}
render() {
let { content, contentType, url, headers={}, getComponent } = this.props
let { content, contentType, url, headers={}, getConfigs, getComponent } = this.props
const { parsedContent } = this.state
const HighlightCode = getComponent("highlightCode")
const downloadName = "response_" + new Date().getTime()
@@ -99,7 +100,7 @@ export default class ResponseBody extends React.PureComponent {
body = "can't parse JSON. Raw result:\n\n" + content
}
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.json`} value={ body } canCopy />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.json`} value={ body } getConfigs={ getConfigs } canCopy />
// XML
} else if (/xml/i.test(contentType)) {
@@ -107,11 +108,11 @@ export default class ResponseBody extends React.PureComponent {
textNodesOnSameLine: true,
indentor: " "
})
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.xml`} value={ body } canCopy />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.xml`} value={ body } getConfigs={ getConfigs } canCopy />
// HTML or Plain Text
} else if (toLower(contentType) === "text/html" || /text\/plain/.test(contentType)) {
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.html`} value={ content } canCopy />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.html`} value={ content } getConfigs={ getConfigs } canCopy />
// Image
} else if (/^image\//i.test(contentType)) {
@@ -125,7 +126,7 @@ export default class ResponseBody extends React.PureComponent {
} else if (/^audio\//i.test(contentType)) {
bodyEl = <pre className="microlight"><audio controls><source src={ url } type={ contentType } /></audio></pre>
} else if (typeof content === "string") {
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.txt`} value={ content } canCopy />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.txt`} value={ content } getConfigs={ getConfigs } canCopy />
} else if ( content.size > 0 ) {
// We don't know the contentType, but there was some content returned
if(parsedContent) {
@@ -135,7 +136,7 @@ export default class ResponseBody extends React.PureComponent {
<p className="i">
Unrecognized response type; displaying content as text.
</p>
<HighlightCode downloadable fileName={`${downloadName}.txt`} value={ parsedContent } canCopy />
<HighlightCode downloadable fileName={`${downloadName}.txt`} value={ parsedContent } getConfigs={ getConfigs } canCopy />
</div>
} else {

View File

@@ -5,12 +5,12 @@ import cx from "classnames"
import { fromJS, Seq, Iterable, List, Map } from "immutable"
import { getSampleSchema, fromJSOrdered, stringify } from "core/utils"
const getExampleComponent = ( sampleResponse, HighlightCode ) => {
const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => {
if (
sampleResponse !== undefined &&
sampleResponse !== null
) { return <div>
<HighlightCode className="example" value={ stringify(sampleResponse) } />
<HighlightCode className="example" getConfigs={ getConfigs } value={ stringify(sampleResponse) } />
</div>
}
return null
@@ -150,7 +150,7 @@ export default class Response extends React.Component {
}
}
let example = getExampleComponent( sampleResponse, HighlightCode )
let example = getExampleComponent( sampleResponse, HighlightCode, getConfigs )
return (
<tr className={ "response " + ( className || "") } data-code={code}>