Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy response to clipboard #4300 #5278

Merged
334 changes: 178 additions & 156 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"prop-types": "^15.7.2",
"randombytes": "^2.1.0",
"react": "^15.6.2",
"react-copy-to-clipboard": "5.0.1",
"react-debounce-input": "^3.2.0",
"react-dom": "^15.6.2",
"react-immutable-proptypes": "2.1.0",
Expand Down
13 changes: 11 additions & 2 deletions src/core/components/highlight-code.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import React, { Component } from "react"
import PropTypes from "prop-types"
import { highlight } from "core/utils"
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,
className: PropTypes.string,
downloadable: PropTypes.bool,
fileName: PropTypes.string
fileName: PropTypes.string,
canCopy: PropTypes.bool
}

componentDidMount() {
Expand Down Expand Up @@ -47,7 +49,7 @@ export default class HighlightCode extends Component {
}

render () {
let { value, className, downloadable } = this.props
let { value, className, downloadable, canCopy } = this.props
className = className || ""

return (
Expand All @@ -57,6 +59,13 @@ export default class HighlightCode extends Component {
Download
</div>
}

{ !canCopy ? null :
<div className="copy-to-clipboard">
<CopyToClipboard text={value}><button/></CopyToClipboard>
</div>
}

<pre
ref={this.initializeComponent}
onWheel={this.preventYScrollingBeyondElement}
Expand Down
10 changes: 5 additions & 5 deletions src/core/components/response-body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ 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 } />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.json`} value={ body } canCopy />

// XML
} else if (/xml/i.test(contentType)) {
body = formatXml(content, {
textNodesOnSameLine: true,
indentor: " "
})
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.xml`} value={ body } />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.xml`} value={ body } canCopy />

// HTML or Plain Text
} else if (toLower(contentType) === "text/html" || /text\/plain/.test(contentType)) {
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.html`} value={ content } />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.html`} value={ content } canCopy />

// Image
} else if (/^image\//i.test(contentType)) {
Expand All @@ -125,7 +125,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 } />
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.txt`} value={ content } canCopy />
} else if ( content.size > 0 ) {
// We don't know the contentType, but there was some content returned
if(parsedContent) {
Expand All @@ -135,7 +135,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 } />
<HighlightCode downloadable fileName={`${downloadName}.txt`} value={ parsedContent } canCopy />
</div>

} else {
Expand Down
1 change: 1 addition & 0 deletions src/img/clipboard.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions src/style/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,23 @@ button
@include invalidFormElement();
}
}

.copy-to-clipboard
{
position: absolute;
bottom: 10px;
right: 100px;
width: 30px;
height: 30px;
background: #7d8293;
border-radius: 4px;
border: none;

button
{
padding-left: 25px;
border: none;
height: 25px;
background: url("../img/clipboard.svg") center center no-repeat;
}
}
28 changes: 28 additions & 0 deletions test/components/highlight-code.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react"
import expect from "expect"
import { shallow } from "enzyme"
import HighlightCode from "components/highlight-code"

describe("<HighlightCode />", () => {
it("should render a Download button if downloadable", () => {
const props = {downloadable: true}
const wrapper = shallow(<HighlightCode {...props} />)
expect(wrapper.find(".download-contents").length).toEqual(1)
})

it("should render a Copy To Clipboard button if copyable", () => {
const props = {canCopy: true}
const wrapper = shallow(<HighlightCode {...props} />)
expect(wrapper.find("CopyToClipboard").length).toEqual(1)
})

it("should render values in a preformatted element", () => {
const value = "test text"
const props = {value: value}
const wrapper = shallow(<HighlightCode {...props} />)
const preTag = wrapper.find("pre")

expect(preTag.length).toEqual(1)
expect(preTag.contains(value)).toEqual(true)
})
})
43 changes: 43 additions & 0 deletions test/components/response-body.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react"
import expect from "expect"
import { shallow } from "enzyme"
import ResponseBody from "components/response-body"

describe("<ResponseBody />", function() {
const highlightCodeComponent = () => null
const components = {
highlightCode: highlightCodeComponent
}
const props = {
getComponent: c => components[c],
}

it("renders ResponseBody as 'application/json'", function() {
props.contentType = "application/json"
props.content = "{\"key\": \"a test value\"}"
const wrapper = shallow(<ResponseBody {...props}/>)
expect(wrapper.find("highlightCodeComponent").length).toEqual(1)
})

it("renders ResponseBody as 'text/html'", function() {
props.contentType = "application/json"
props.content = "<b>Result</b>"
const wrapper = shallow(<ResponseBody {...props}/>)
expect(wrapper.find("highlightCodeComponent").length).toEqual(1)
})

it("renders ResponseBody as 'image/svg'", function() {
props.contentType = "image/svg"
const wrapper = shallow(<ResponseBody {...props}/>)
console.warn(wrapper.debug())
expect(wrapper.find("highlightCodeComponent").length).toEqual(0)
})

it("should render a copyable highlightCodeComponent for text types", function() {
props.contentType = "text/plain"
props.content = "test text"
const wrapper = shallow(<ResponseBody {...props}/>)
console.warn(wrapper.debug())
expect(wrapper.find("highlightCodeComponent[canCopy]").length).toEqual(1)
})
})
9 changes: 8 additions & 1 deletion test/mocha/components/response-body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from "react"
import expect from "expect"
import { shallow } from "enzyme"
import ResponseBody from "components/response-body"
import { inferSchema } from "corePlugins/samples/fn"

describe("<ResponseBody />", function() {
const highlightCodeComponent = () => null
Expand Down Expand Up @@ -33,4 +32,12 @@ describe("<ResponseBody />", function() {
console.warn(wrapper.debug())
expect(wrapper.find("highlightCodeComponent").length).toEqual(0)
})

it("should render a copyable highlightCodeComponent for text types", function() {
props.contentType = "text/plain"
props.content = "test text"
const wrapper = shallow(<ResponseBody {...props}/>)
console.warn(wrapper.debug())
expect(wrapper.find("highlightCodeComponent[canCopy]").length).toEqual(1)
})
})