1import React, { Component } from 'react' 2import PropTypes from 'prop-types' 3import { connect } from 'react-redux' 4 5 6import { RequestUtils, isValidHttpVersion, parseUrl } from '../../flow/utils.js' 7import { formatTimeStamp } from '../../utils.js' 8import ContentView from '../ContentView' 9import ContentViewOptions from '../ContentView/ContentViewOptions' 10import ValidateEditor from '../ValueEditor/ValidateEditor' 11import ValueEditor from '../ValueEditor/ValueEditor' 12import HideInStatic from '../common/HideInStatic' 13 14import Headers from './Headers' 15import { startEdit, updateEdit } from '../../ducks/ui/flow' 16import * as FlowActions from '../../ducks/flows' 17import ToggleEdit from './ToggleEdit' 18 19function RequestLine({ flow, readonly, updateFlow }) { 20 return ( 21 <div className="first-line request-line"> 22 <div> 23 <ValueEditor 24 content={flow.request.method} 25 readonly={readonly} 26 onDone={method => updateFlow({ request: { method } })} 27 /> 28 29 <ValidateEditor 30 content={RequestUtils.pretty_url(flow.request)} 31 readonly={readonly} 32 onDone={url => updateFlow({ request: {path: '', ...parseUrl(url)}})} 33 isValid={url => !!parseUrl(url).host} 34 /> 35 36 <ValidateEditor 37 content={flow.request.http_version} 38 readonly={readonly} 39 onDone={http_version => updateFlow({ request: { http_version } })} 40 isValid={isValidHttpVersion} 41 /> 42 </div> 43 </div> 44 ) 45} 46 47function ResponseLine({ flow, readonly, updateFlow }) { 48 return ( 49 <div className="first-line response-line"> 50 <ValidateEditor 51 content={flow.response.http_version} 52 readonly={readonly} 53 onDone={nextVer => updateFlow({ response: { http_version: nextVer } })} 54 isValid={isValidHttpVersion} 55 /> 56 57 <ValidateEditor 58 content={flow.response.status_code + ''} 59 readonly={readonly} 60 onDone={code => updateFlow({ response: { code: parseInt(code) } })} 61 isValid={code => /^\d+$/.test(code)} 62 /> 63 64 <ValueEditor 65 content={flow.response.reason} 66 readonly={readonly} 67 onDone={msg => updateFlow({ response: { msg } })} 68 /> 69 </div> 70 ) 71} 72 73const Message = connect( 74 state => ({ 75 flow: state.ui.flow.modifiedFlow || state.flows.byId[state.flows.selected[0]], 76 isEdit: !!state.ui.flow.modifiedFlow, 77 }), 78 { 79 updateFlow: updateEdit, 80 uploadContent: FlowActions.uploadContent 81 } 82) 83 84export class Request extends Component { 85 render() { 86 const { flow, isEdit, updateFlow, uploadContent } = this.props 87 let noContent = !isEdit && (flow.request.contentLength == 0 || flow.request.contentLength == null) 88 return ( 89 <section className="request"> 90 <article> 91 <ToggleEdit/> 92 <RequestLine 93 flow={flow} 94 readonly={!isEdit} 95 updateFlow={updateFlow}/> 96 <Headers 97 message={flow.request} 98 readonly={!isEdit} 99 onChange={headers => updateFlow({ request: { headers } })} 100 /> 101 102 <hr/> 103 <ContentView 104 readonly={!isEdit} 105 flow={flow} 106 onContentChange={content => updateFlow({ request: {content}})} 107 message={flow.request}/> 108 109 <hr/> 110 <Headers 111 message={flow.request} 112 readonly={!isEdit} 113 onChange={trailers => updateFlow({ request: { trailers } })} 114 type='trailers' 115 /> 116 </article> 117 <HideInStatic> 118 {!noContent && 119 <footer> 120 <ContentViewOptions 121 flow={flow} 122 readonly={!isEdit} 123 message={flow.request} 124 uploadContent={content => uploadContent(flow, content, "request")}/> 125 </footer> 126 } 127 </HideInStatic> 128 </section> 129 ) 130 } 131} 132 133Request = Message(Request) 134 135 136export class Response extends Component { 137 render() { 138 const { flow, isEdit, updateFlow, uploadContent } = this.props 139 let noContent = !isEdit && (flow.response.contentLength == 0 || flow.response.contentLength == null) 140 141 return ( 142 <section className="response"> 143 <article> 144 <ToggleEdit/> 145 <ResponseLine 146 flow={flow} 147 readonly={!isEdit} 148 updateFlow={updateFlow}/> 149 <Headers 150 message={flow.response} 151 readonly={!isEdit} 152 onChange={headers => updateFlow({ response: { headers } })} 153 /> 154 <hr/> 155 <ContentView 156 readonly={!isEdit} 157 flow={flow} 158 onContentChange={content => updateFlow({ response: {content}})} 159 message={flow.response} 160 /> 161 <hr/> 162 <Headers 163 message={flow.response} 164 readonly={!isEdit} 165 onChange={trailers => updateFlow({ response: { trailers } })} 166 type='trailers' 167 /> 168 </article> 169 <HideInStatic> 170 {!noContent && 171 <footer > 172 <ContentViewOptions 173 flow={flow} 174 message={flow.response} 175 uploadContent={content => uploadContent(flow, content, "response")} 176 readonly={!isEdit}/> 177 </footer> 178 } 179 </HideInStatic> 180 </section> 181 ) 182 } 183} 184 185Response = Message(Response) 186 187 188ErrorView.propTypes = { 189 flow: PropTypes.object.isRequired, 190} 191 192export function ErrorView({ flow }) { 193 return ( 194 <section className="error"> 195 <div className="alert alert-warning"> 196 {flow.error.msg} 197 <div> 198 <small>{formatTimeStamp(flow.error.timestamp)}</small> 199 </div> 200 </div> 201 </section> 202 ) 203} 204