feat: web addon can edit flow
parent
2cfc8fcb96
commit
46f9a17509
@ -0,0 +1,208 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Button from 'react-bootstrap/Button'
|
||||||
|
import Modal from 'react-bootstrap/Modal'
|
||||||
|
import Form from 'react-bootstrap/Form'
|
||||||
|
import Alert from 'react-bootstrap/Alert'
|
||||||
|
|
||||||
|
import { sendMessageEnum, buildMessageEdit } from '../message'
|
||||||
|
import { isTextBody } from '../utils'
|
||||||
|
|
||||||
|
|
||||||
|
const stringifyRequest = request => {
|
||||||
|
const firstLine = `${request.method} ${request.url}`
|
||||||
|
const headerLines = Object.keys(request.header).map(key => {
|
||||||
|
const valstr = request.header[key].join(' \t ') // for parse convenience
|
||||||
|
return `${key}: ${valstr}`
|
||||||
|
}).join('\n')
|
||||||
|
|
||||||
|
let bodyLines = ''
|
||||||
|
if (request.body && isTextBody(request)) bodyLines = new TextDecoder().decode(request.body)
|
||||||
|
|
||||||
|
return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseRequest = content => {
|
||||||
|
const sections = content.split('\n\n')
|
||||||
|
if (sections.length !== 3) return
|
||||||
|
|
||||||
|
const [firstLine, headerLines, bodyLines] = sections
|
||||||
|
const [method, url] = firstLine.split(' ')
|
||||||
|
if (!method || !url) return
|
||||||
|
|
||||||
|
const header = {}
|
||||||
|
for (const line of headerLines.split('\n')) {
|
||||||
|
const [key, vals] = line.split(': ')
|
||||||
|
if (!key || !vals) return
|
||||||
|
header[key] = vals.split(' \t ')
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = null
|
||||||
|
if (bodyLines) body = new TextEncoder().encode(bodyLines)
|
||||||
|
|
||||||
|
return {
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stringifyResponse = response => {
|
||||||
|
const firstLine = `${response.statusCode}`
|
||||||
|
const headerLines = Object.keys(response.header).map(key => {
|
||||||
|
const valstr = response.header[key].join(' \t ') // for parse convenience
|
||||||
|
return `${key}: ${valstr}`
|
||||||
|
}).join('\n')
|
||||||
|
|
||||||
|
let bodyLines = ''
|
||||||
|
if (response.body && isTextBody(response)) bodyLines = new TextDecoder().decode(response.body)
|
||||||
|
|
||||||
|
return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseResponse = content => {
|
||||||
|
const sections = content.split('\n\n')
|
||||||
|
if (sections.length !== 3) return
|
||||||
|
|
||||||
|
const [firstLine, headerLines, bodyLines] = sections
|
||||||
|
const statusCode = parseInt(firstLine)
|
||||||
|
if (isNaN(statusCode)) return
|
||||||
|
|
||||||
|
const header = {}
|
||||||
|
for (const line of headerLines.split('\n')) {
|
||||||
|
const [key, vals] = line.split(': ')
|
||||||
|
if (!key || !vals) return
|
||||||
|
header[key] = vals.split(' \t ')
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = null
|
||||||
|
if (bodyLines) body = new TextEncoder().encode(bodyLines)
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode,
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EditFlow extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
show: false,
|
||||||
|
alertMsg: '',
|
||||||
|
content: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleClose = this.handleClose.bind(this)
|
||||||
|
this.handleShow = this.handleShow.bind(this)
|
||||||
|
this.handleSave = this.handleSave.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
showAlert(msg) {
|
||||||
|
this.setState({ alertMsg: msg })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClose() {
|
||||||
|
this.setState({ show: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleShow() {
|
||||||
|
const { flow } = this.props
|
||||||
|
const when = flow.response ? 'response' : 'request'
|
||||||
|
|
||||||
|
let content = ''
|
||||||
|
if (when === 'request') {
|
||||||
|
content = stringifyRequest(flow.request)
|
||||||
|
} else {
|
||||||
|
content = stringifyResponse(flow.response)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ show: true, alertMsg: '', content })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSave() {
|
||||||
|
const { flow } = this.props
|
||||||
|
const when = flow.response ? 'response' : 'request'
|
||||||
|
|
||||||
|
const { content } = this.state
|
||||||
|
|
||||||
|
if (when === 'request') {
|
||||||
|
const request = parseRequest(content)
|
||||||
|
if (!request) {
|
||||||
|
this.showAlert('parse error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onChangeRequest(request)
|
||||||
|
this.handleClose()
|
||||||
|
} else {
|
||||||
|
const response = parseResponse(content)
|
||||||
|
if (!response) {
|
||||||
|
this.showAlert('parse error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onChangeResponse(response)
|
||||||
|
this.handleClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { flow } = this.props
|
||||||
|
if (!flow.waitIntercept) return null
|
||||||
|
|
||||||
|
const { alertMsg } = this.state
|
||||||
|
|
||||||
|
const when = flow.response ? 'response' : 'request'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flow-wait-area">
|
||||||
|
|
||||||
|
<Button size="sm" onClick={this.handleShow}>Edit</Button>
|
||||||
|
|
||||||
|
<Button size="sm" onClick={() => {
|
||||||
|
const msgType = when === 'response' ? sendMessageEnum.changeResponse : sendMessageEnum.changeRequest
|
||||||
|
const msg = buildMessageEdit(msgType, flow)
|
||||||
|
this.props.onMessage(msg)
|
||||||
|
}}>Continue</Button>
|
||||||
|
|
||||||
|
<Button size="sm" onClick={() => {
|
||||||
|
const msgType = when === 'response' ? sendMessageEnum.dropResponse : sendMessageEnum.dropRequest
|
||||||
|
const msg = buildMessageEdit(msgType, flow)
|
||||||
|
this.props.onMessage(msg)
|
||||||
|
}}>Drop</Button>
|
||||||
|
|
||||||
|
|
||||||
|
<Modal size="lg" show={this.state.show} onHide={this.handleClose}>
|
||||||
|
<Modal.Header closeButton>
|
||||||
|
<Modal.Title>Edit {when === 'request' ? 'Request' : 'Response'}</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
|
||||||
|
<Modal.Body>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Control as="textarea" rows={10} value={this.state.content} onChange={e => { this.setState({ content: e.target.value }) }} />
|
||||||
|
</Form.Group>
|
||||||
|
{
|
||||||
|
!alertMsg ? null : <Alert variant="danger">{alertMsg}</Alert>
|
||||||
|
}
|
||||||
|
</Modal.Body>
|
||||||
|
|
||||||
|
<Modal.Footer>
|
||||||
|
<Button variant="secondary" onClick={this.handleClose}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<Button variant="primary" onClick={this.handleSave}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</Modal.Footer>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditFlow
|
Loading…
Reference in New Issue