diff options
author | Clemens <cle1000.cb@gmail.com> | 2016-07-14 23:01:34 +0200 |
---|---|---|
committer | Clemens <cle1000.cb@gmail.com> | 2016-07-14 23:01:34 +0200 |
commit | 5f3782dd5fb8be4c196f57cb07fd1cc2fd6b2f56 (patch) | |
tree | 8858b5b6ccbfe15236eb99de7d2bd731f1717a22 /web | |
parent | 45349b3597f53ee08207b20eb8bff9dfc9166aa8 (diff) | |
download | mitmproxy-5f3782dd5fb8be4c196f57cb07fd1cc2fd6b2f56.tar.gz mitmproxy-5f3782dd5fb8be4c196f57cb07fd1cc2fd6b2f56.tar.bz2 mitmproxy-5f3782dd5fb8be4c196f57cb07fd1cc2fd6b2f56.zip |
change way to edit
Diffstat (limited to 'web')
-rw-r--r-- | web/src/css/flowdetail.less | 2 | ||||
-rw-r--r-- | web/src/js/components/ContentView.jsx | 81 | ||||
-rw-r--r-- | web/src/js/components/ContentView/ContentEditor.jsx | 42 | ||||
-rw-r--r-- | web/src/js/components/ContentView/ContentViews.jsx | 29 | ||||
-rw-r--r-- | web/src/js/components/FlowView/Messages.jsx | 11 | ||||
-rw-r--r-- | web/src/js/components/common/Button.jsx | 10 | ||||
-rw-r--r-- | web/src/js/components/common/CodeEditor.jsx | 24 | ||||
-rw-r--r-- | web/src/js/ducks/flows.js | 5 |
8 files changed, 122 insertions, 82 deletions
diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index edf97566..43078eff 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -109,4 +109,4 @@ text-overflow: ellipsis; white-space: nowrap; } -}
\ No newline at end of file +} diff --git a/web/src/js/components/ContentView.jsx b/web/src/js/components/ContentView.jsx index 6c9d9b26..fa26a057 100644 --- a/web/src/js/components/ContentView.jsx +++ b/web/src/js/components/ContentView.jsx @@ -4,7 +4,7 @@ import { ViewAuto, ViewImage } from './ContentView/ContentViews' import * as MetaViews from './ContentView/MetaViews' import ContentLoader from './ContentView/ContentLoader' import ViewSelector from './ContentView/ViewSelector' -import * as flowsActions from '../ducks/flows' +import ContentEditor from './ContentView/ContentEditor' export default class ContentView extends Component { @@ -14,12 +14,13 @@ export default class ContentView extends Component { // <Auto flow={flow} message={flow.request}/> flow: React.PropTypes.object.isRequired, message: React.PropTypes.object.isRequired, + onContentChange: React.PropTypes.func.isRequired } constructor(props, context) { super(props, context) - this.state = { displayLarge: false, View: ViewAuto } + this.state = { displayLarge: false, View: ViewAuto, contentEditorClosed: true } this.selectView = this.selectView.bind(this) } @@ -43,9 +44,7 @@ export default class ContentView extends Component { onOpenFile(e) { if (e.target.files.length > 0) { - //alert(e.target.files[0]) - flowsActions.update_content(this.props.flow, e.target.files[0]) - //this.fileInput.value = '' + this.props.onContentChange(e.target.files[0]) } e.preventDefault() } @@ -68,30 +67,56 @@ export default class ContentView extends Component { return ( <div> - {View.textView ? ( - <ContentLoader flow={flow} message={message}> - <this.state.View update_content={content => flowsActions.update_content(this.props.flow, content)} content="" /> - </ContentLoader> - ) : ( - <View flow={flow} update_content={content => flowsActions.update_content(this.props.flow, content)} message={message} /> - )} - <div className="view-options text-center"> - <ViewSelector onSelectView={this.selectView} active={View} message={message}/> - - <a className="btn btn-default btn-xs" href={MessageUtils.getContentURL(flow, message)}> - <i className="fa fa-download"/> - </a> - - <a className="btn btn-default btn-xs" href="#" onClick={e => {this.fileInput.click(); e.preventDefault();}}> - <i className="fa fa-upload"/> - </a> - <input - ref={ref => this.fileInput = ref} - className="hidden" - type="file" - onChange={e => this.onOpenFile(e)} - /> + <div className="row"> + <div className="col-sm-12"> + <ContentLoader flow={flow} message={message}> + <ContentEditor + onSave={this.props.onContentChange} + onClose={() => this.setState({contentEditorClosed : true})} + onOpen={() => this.setState({contentEditorClosed : false})} + isClosed={this.state.contentEditorClosed} + content="" + /> + </ContentLoader> + </div> </div> + + {this.state.contentEditorClosed && (<div> + {View.textView ? ( + <ContentLoader flow={flow} message={message}> + <this.state.View content="" /> + </ContentLoader> + ) : ( + <View flow={flow} message={message} /> + )} + + + + <div className="view-options text-center"> + <ViewSelector onSelectView={this.selectView} active={View} message={message}/> + + <a className="btn btn-default btn-xs" + href={MessageUtils.getContentURL(flow, message)} + title="Download the content of the flow." + > + <i className="fa fa-download"/> + </a> + + <a className="btn btn-default btn-xs" + href="#" + onClick={e => {this.fileInput.click(); e.preventDefault();}} + title="Upload a file to replace the content." + > + <i className="fa fa-upload"/> + </a> + <input + ref={ref => this.fileInput = ref} + className="hidden" + type="file" + onChange={e => this.onOpenFile(e)} + /> + </div> + </div>)} </div> ) } diff --git a/web/src/js/components/ContentView/ContentEditor.jsx b/web/src/js/components/ContentView/ContentEditor.jsx new file mode 100644 index 00000000..a38e4d6f --- /dev/null +++ b/web/src/js/components/ContentView/ContentEditor.jsx @@ -0,0 +1,42 @@ +import React, { Component, PropTypes } from 'react' +import CodeEditor from '../common/CodeEditor' + +export default class ContentEditor extends Component { + + static propTypes = { + content: PropTypes.string.isRequired, + onSave: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, + onOpen: PropTypes.func.isRequired, + isClosed: PropTypes.bool.isRequired + } + + constructor(props){ + super(props) + this.state = {content: this.props.content} + } + + render() { + return ( + <div> + {this.props.isClosed ? + <a className="btn btn-default btn-xs pull-right" onClick={this.props.onOpen}> + <i className="fa fa-pencil-square-o"/> + </a> : + <span> + <a className="btn btn-default btn-xs pull-right" onClick={this.props.onClose}> + <i className="fa fa-times"/> + </a> + <a className="btn btn-default btn-xs pull-right" onClick={() => this.props.onSave(this.state.content)}> + <i className="fa fa-floppy-o"/> + </a> + </span> + } + {!this.props.isClosed && + <CodeEditor value={this.state.content} onChange={content => this.setState({content: content})}/> + } + </div> + + ) + } +} diff --git a/web/src/js/components/ContentView/ContentViews.jsx b/web/src/js/components/ContentView/ContentViews.jsx index 617ed242..82ee0adc 100644 --- a/web/src/js/components/ContentView/ContentViews.jsx +++ b/web/src/js/components/ContentView/ContentViews.jsx @@ -1,12 +1,9 @@ import React, { PropTypes } from 'react' import ContentLoader from './ContentLoader' import { MessageUtils } from '../../flow/utils.js' -import CodeEditor from '../common/CodeEditor' -import {formatSize} from '../../utils.js' - -const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw, ViewFile] +const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw] ViewImage.regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i ViewImage.matches = msg => ViewImage.regex.test(MessageUtils.getContentType(msg)) @@ -26,16 +23,13 @@ export function ViewImage({ flow, message }) { ViewRaw.textView = true ViewRaw.matches = () => true -ViewRaw.input = {} ViewRaw.propTypes = { content: React.PropTypes.string.isRequired, } -export function ViewRaw({ content, update_content }) { - return ( - <CodeEditor value={content} onSave={update_content}/> - ) +export function ViewRaw({ content }) { + return <pre>{content}</pre> } ViewJSON.textView = true @@ -65,26 +59,13 @@ ViewAuto.propTypes = { flow: React.PropTypes.object.isRequired, } -export function ViewAuto({ message, flow, update_content }) { +export function ViewAuto({ message, flow }) { const View = ViewAuto.findView(message) if (View.textView) { - return <ContentLoader message={message} flow={flow}><View update_content={update_content} content="" /></ContentLoader> + return <ContentLoader message={message} flow={flow}><View content="" /></ContentLoader> } else { return <View message={message} flow={flow} /> } } -ViewFile.matches = () => false - -ViewFile.propTypes = { - message: React.PropTypes.object.isRequired, - flow: React.PropTypes.object.isRequired, -} - -export function ViewFile({ message, flow }) { - return <div className="alert alert-info"> - {formatSize(message.contentLength)} content size. - </div> -} - export default views diff --git a/web/src/js/components/FlowView/Messages.jsx b/web/src/js/components/FlowView/Messages.jsx index d2c42a54..27e18c05 100644 --- a/web/src/js/components/FlowView/Messages.jsx +++ b/web/src/js/components/FlowView/Messages.jsx @@ -6,6 +6,7 @@ import { Key, formatTimeStamp } from '../../utils.js' import ContentView from '../ContentView' import ValueEditor from '../ValueEditor' import Headers from './Headers' +import * as flowActions from '../../ducks/flows' class RequestLine extends Component { @@ -89,7 +90,10 @@ export class Request extends Component { onChange={headers => updateFlow({ request: { headers } })} /> <hr/> - <ContentView flow={flow} message={flow.request} onChange={content => updateFlow({request: {content} })}/> + <ContentView flow={flow} + onContentChange={content => flowActions.updateContent(this.props.flow, content, "request") } + message={flow.request} + /> </section> ) } @@ -128,7 +132,10 @@ export class Response extends Component { onChange={headers => updateFlow({ response: { headers } })} /> <hr/> - <ContentView flow={flow} message={flow.response} onChange={content => updateFlow({response: {content} }) }/> + <ContentView flow={flow} + onContentChange={content => flowActions.updateContent(this.props.flow, content, "response") } + message={flow.response} + /> </section> ) } diff --git a/web/src/js/components/common/Button.jsx b/web/src/js/components/common/Button.jsx index 221c6ace..cd01af22 100644 --- a/web/src/js/components/common/Button.jsx +++ b/web/src/js/components/common/Button.jsx @@ -2,7 +2,8 @@ import React, { PropTypes } from 'react' Button.propTypes = { onClick: PropTypes.func.isRequired, - text: PropTypes.string.isRequired + text: PropTypes.string, + icon: PropTypes.string } export default function Button({ onClick, text, icon, disabled }) { @@ -10,11 +11,8 @@ export default function Button({ onClick, text, icon, disabled }) { <div className={"btn btn-default"} onClick={onClick} disabled={disabled}> - <span hidden={!icon}> - <i className={"fa fa-fw " + icon}/> - - </span> - {text} + {icon && (<i className={"fa fa-fw " + icon}/> )} + {text && text} </div> ) } diff --git a/web/src/js/components/common/CodeEditor.jsx b/web/src/js/components/common/CodeEditor.jsx index 85da0507..b10b13ed 100644 --- a/web/src/js/components/common/CodeEditor.jsx +++ b/web/src/js/components/common/CodeEditor.jsx @@ -1,40 +1,28 @@ import React, { Component, PropTypes } from 'react' import { render } from 'react-dom'; -import brace from 'brace'; import AceEditor from 'react-ace'; -import Button from './Button' - import 'brace/mode/javascript'; -import 'brace/mode/json'; import 'brace/theme/kuroir'; - - - export default class CodeEditor extends Component{ - constructor( props ) { - super(props) - this.state = {value: this.props.value} - } - - onChange(newValue) { - this.setState({value: newValue}) + static propTypes = { + value: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, } render() { return ( <div onKeyDown={e => e.stopPropagation()}> <AceEditor - onChange={e => this.onChange(e)} mode="javascript" theme="kuroir" - value={this.state.value} + onChange={this.props.onChange} + name="rea" + value={this.props.value} width="100%" - name="codeEditor" editorProps={{$blockScrolling: Infinity}} /> - <Button onClick={(e) => this.props.onSave(this.state.value)} text="Update"/> </div> ) } diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js index 1dc88c67..3dd21016 100644 --- a/web/src/js/ducks/flows.js +++ b/web/src/js/ducks/flows.js @@ -117,13 +117,12 @@ export function update(flow, data) { return { type: REQUEST_ACTION } } -export function update_content(flow, file) { +export function updateContent(flow, file, type) { const body = new FormData() if (typeof file !== File) file = new Blob([file], {type: 'plain/text'}) body.append('file', file) - fetchApi(`/flows/${flow.id}/response/content`, {method: 'post', body} ) - update(flow, {response: {headers: [['Content-Encoding', '']]} } ) + fetchApi(`/flows/${flow.id}/${type}/content`, {method: 'post', body} ) return { type: REQUEST_ACTION } } |