fix(request-snippets): prevent scrolling errors from missing function (#7941)

* fix(request-snippets): prevent scrolling errors from missing function

* refactor(request-snippets): migrate to functional component

* fix(curl): remove undefined prop and function

* test(live-response): fix import of RequestSnippets
This commit is contained in:
Tim Lai
2022-03-24 11:23:42 -07:00
committed by GitHub
parent cd2f434438
commit 9250e209d4
4 changed files with 150 additions and 118 deletions

View File

@@ -21,7 +21,6 @@ export default class Curl extends React.Component {
? <SyntaxHighlighter ? <SyntaxHighlighter
language="bash" language="bash"
className="curl microlight" className="curl microlight"
onWheel={this.preventYScrollingBeyondElement}
style={getStyle(get(config, "syntaxHighlight.theme"))} style={getStyle(get(config, "syntaxHighlight.theme"))}
> >
{curl} {curl}

View File

@@ -1,6 +1,6 @@
import * as fn from "./fn" import * as fn from "./fn"
import * as selectors from "./selectors" import * as selectors from "./selectors"
import { RequestSnippets } from "./request-snippets" import RequestSnippets from "./request-snippets"
export default () => { export default () => {
return { return {
components: { components: {

View File

@@ -1,127 +1,160 @@
import React from "react" import React, { useRef, useEffect, useState } from "react"
import { CopyToClipboard } from "react-copy-to-clipboard"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import get from "lodash/get" import get from "lodash/get"
import {SyntaxHighlighter, getStyle} from "core/syntax-highlighting" import isFunction from "lodash/isFunction"
import { CopyToClipboard } from "react-copy-to-clipboard"
import { SyntaxHighlighter, getStyle } from "core/syntax-highlighting"
export class RequestSnippets extends React.Component { const style = {
constructor() { cursor: "pointer",
super() lineHeight: 1,
this.state = { display: "inline-flex",
activeLanguage: this.props?.requestSnippetsSelectors?.getSnippetGenerators()?.keySeq().first(), backgroundColor: "rgb(250, 250, 250)",
expanded: this.props?.requestSnippetsSelectors?.getDefaultExpanded(), paddingBottom: "0",
paddingTop: "0",
border: "1px solid rgb(51, 51, 51)",
borderRadius: "4px 4px 0 0",
boxShadow: "none",
borderBottom: "none"
}
const activeStyle = {
cursor: "pointer",
lineHeight: 1,
display: "inline-flex",
backgroundColor: "rgb(51, 51, 51)",
boxShadow: "none",
border: "1px solid rgb(51, 51, 51)",
paddingBottom: "0",
paddingTop: "0",
borderRadius: "4px 4px 0 0",
marginTop: "-5px",
marginRight: "-5px",
marginLeft: "-5px",
zIndex: "9999",
borderBottom: "none"
}
const RequestSnippets = ({ request, requestSnippetsSelectors, getConfigs }) => {
const config = isFunction(getConfigs) ? getConfigs() : null
const canSyntaxHighlight = get(config, "syntaxHighlight") !== false && get(config, "syntaxHighlight.activated", true)
const rootRef = useRef(null)
const [activeLanguage, setActiveLanguage] = useState(requestSnippetsSelectors.getSnippetGenerators()?.keySeq().first())
const [isExpanded, setIsExpanded] = useState(requestSnippetsSelectors?.getDefaultExpanded())
useEffect(() => {
const doIt = () => {
}
doIt()
}, [])
useEffect(() => {
const childNodes = Array
.from(rootRef.current.childNodes)
.filter(node => !!node.nodeType && node.classList?.contains("curl-command"))
// eslint-disable-next-line no-use-before-define
childNodes.forEach(node => node.addEventListener("mousewheel", handlePreventYScrollingBeyondElement, { passive: false }))
return () => {
// eslint-disable-next-line no-use-before-define
childNodes.forEach(node => node.removeEventListener("mousewheel", handlePreventYScrollingBeyondElement))
}
}, [request])
const snippetGenerators = requestSnippetsSelectors.getSnippetGenerators()
const activeGenerator = snippetGenerators.get(activeLanguage)
const snippet = activeGenerator.get("fn")(request)
const handleGenChange = (key) => {
const needsChange = activeLanguage !== key
if (needsChange) {
setActiveLanguage(key)
} }
} }
static propTypes = { const handleSetIsExpanded = () => {
request: PropTypes.object.isRequired, setIsExpanded(!isExpanded)
requestSnippetsSelectors: PropTypes.object.isRequired,
getConfigs: PropTypes.object.isRequired,
requestSnippetsActions: PropTypes.object.isRequired,
} }
render() {
const {request, getConfigs, requestSnippetsSelectors } = this.props
const snippetGenerators = requestSnippetsSelectors.getSnippetGenerators()
const activeLanguage = this.state.activeLanguage || snippetGenerators.keySeq().first()
const activeGenerator = snippetGenerators.get(activeLanguage)
const snippet = activeGenerator.get("fn")(request)
const onGenChange = (key) => {
const needsChange = activeLanguage !== key
if(needsChange) {
this.setState({
activeLanguage: key
})
}
}
const style = {
cursor: "pointer",
lineHeight: 1,
display: "inline-flex",
backgroundColor: "rgb(250, 250, 250)",
paddingBottom: "0",
paddingTop: "0",
border: "1px solid rgb(51, 51, 51)",
borderRadius: "4px 4px 0 0",
boxShadow: "none",
borderBottom: "none"
}
const activeStyle = {
cursor: "pointer",
lineHeight: 1,
display: "inline-flex",
backgroundColor: "rgb(51, 51, 51)",
boxShadow: "none",
border: "1px solid rgb(51, 51, 51)",
paddingBottom: "0",
paddingTop: "0",
borderRadius: "4px 4px 0 0",
marginTop: "-5px",
marginRight: "-5px",
marginLeft: "-5px",
zIndex: "9999",
borderBottom: "none"
}
const getBtnStyle = (key) => {
if (key === activeLanguage) {
return activeStyle
}
return style
}
const config = getConfigs()
const SnippetComponent = config?.syntaxHighlight?.activated const handleGetBtnStyle = (key) => {
? <SyntaxHighlighter if (key === activeLanguage) {
language={activeGenerator.get("syntax")} return activeStyle
className="curl microlight" }
onWheel={function(e) {return this.preventYScrollingBeyondElement(e)}} return style
style={getStyle(get(config, "syntaxHighlight.theme"))} }
const handlePreventYScrollingBeyondElement = (e) => {
const { target, deltaY } = e
const { scrollHeight: contentHeight, offsetHeight: visibleHeight, scrollTop } = target
const scrollOffset = visibleHeight + scrollTop
const isElementScrollable = contentHeight > visibleHeight
const isScrollingPastTop = scrollTop === 0 && deltaY < 0
const isScrollingPastBottom = scrollOffset >= contentHeight && deltaY > 0
if (isElementScrollable && (isScrollingPastTop || isScrollingPastBottom)) {
e.preventDefault()
}
}
const SnippetComponent = canSyntaxHighlight
? <SyntaxHighlighter
language={activeGenerator.get("syntax")}
className="curl microlight"
style={getStyle(get(config, "syntaxHighlight.theme"))}
>
{snippet}
</SyntaxHighlighter>
:
<textarea readOnly={true} className="curl" value={snippet}></textarea>
return (
<div className="request-snippets" ref={rootRef}>
Just a test
<div style={{ width: "100%", display: "flex", justifyContent: "flex-start", alignItems: "center", marginBottom: "15px" }}>
<h4
onClick={() => handleSetIsExpanded()}
style={{ cursor: "pointer" }}
>Snippets</h4>
<button
onClick={() => handleSetIsExpanded()}
style={{ border: "none", background: "none" }}
title={isExpanded ? "Collapse operation" : "Expand operation"}
> >
{snippet} <svg className="arrow" width="10" height="10">
</SyntaxHighlighter> <use href={isExpanded ? "#large-arrow-down" : "#large-arrow"} xlinkHref={isExpanded ? "#large-arrow-down" : "#large-arrow"} />
: </svg>
<textarea readOnly={true} className="curl" value={snippet}></textarea> </button>
</div>
const expanded = this.state.expanded === undefined ? this.props?.requestSnippetsSelectors?.getDefaultExpanded() : this.state.expanded {
return ( isExpanded && <div className="curl-command">
<div> <div style={{ paddingLeft: "15px", paddingRight: "10px", width: "100%", display: "flex" }}>
<div style={{width: "100%", display: "flex", justifyContent: "flex-start", alignItems: "center", marginBottom: "15px"}}> {
<h4 snippetGenerators.entrySeq().map(([key, gen]) => {
style={{ cursor: "pointer" }} return (<div style={handleGetBtnStyle(key)} className="btn" key={key} onClick={() => handleGenChange(key)}>
onClick={() => this.setState({expanded: !expanded})} <h4 style={key === activeLanguage ? { color: "white", } : {}}>{gen.get("title")}</h4>
>Snippets</h4> </div>)
<button })
onClick={() => this.setState({expanded: !expanded})} }
style={{ border: "none", background: "none" }} </div>
title={expanded ? "Collapse operation": "Expand operation"} <div className="copy-to-clipboard">
> <CopyToClipboard text={snippet}>
<svg className="arrow" width="10" height="10"> <button />
<use href={expanded ? "#large-arrow-down" : "#large-arrow"} xlinkHref={expanded ? "#large-arrow-down" : "#large-arrow"} /> </CopyToClipboard>
</svg> </div>
</button> <div>
{SnippetComponent}
</div> </div>
{
expanded && <div className="curl-command">
<div style={{paddingLeft: "15px", paddingRight: "10px", width: "100%", display: "flex"}}>
{
snippetGenerators.entrySeq().map(([key, gen]) => {
return (<div style={getBtnStyle(key)} className="btn" key={key} onClick={() => onGenChange(key)}>
<h4 style={key === activeLanguage ? {color: "white",} : {}}>{gen.get("title")}</h4>
</div>)
})
}
</div>
<div className="copy-to-clipboard">
<CopyToClipboard text={snippet}>
<button />
</CopyToClipboard>
</div>
<div>
{SnippetComponent}
</div>
</div>
}
</div> </div>
}
) </div>
} )
} }
RequestSnippets.propTypes = {
request: PropTypes.object.isRequired,
requestSnippetsSelectors: PropTypes.object.isRequired,
getConfigs: PropTypes.object.isRequired,
requestSnippetsActions: PropTypes.object,
}
export default RequestSnippets

View File

@@ -6,7 +6,7 @@ import expect from "expect"
import { shallow } from "enzyme" import { shallow } from "enzyme"
import LiveResponse from "components/live-response" import LiveResponse from "components/live-response"
import ResponseBody from "components/response-body" import ResponseBody from "components/response-body"
import { RequestSnippets } from "core/plugins/request-snippets/request-snippets" import RequestSnippets from "core/plugins/request-snippets/request-snippets"
describe("<LiveResponse/>", function () { describe("<LiveResponse/>", function () {
let request = fromJSOrdered({ let request = fromJSOrdered({