change way to edit

This commit is contained in:
Clemens 2016-07-14 23:01:34 +02:00
parent 45349b3597
commit 5f3782dd5f
9 changed files with 130 additions and 89 deletions

View File

@ -201,7 +201,7 @@ class DumpFlows(RequestHandler):
def post(self): def post(self):
self.state.clear() self.state.clear()
content = self.request.files.values()[0][0]["body"] content = self.request.files.values()[0][0].body
bio = BytesIO(content) bio = BytesIO(content)
self.state.load_flows(FlowReader(bio).stream()) self.state.load_flows(FlowReader(bio).stream())
bio.close() bio.close()
@ -297,14 +297,15 @@ class FlowContent(RequestHandler):
flow = self.flow flow = self.flow
flow.backup() flow.backup()
content = 'Can not read file!' content = self.request.files.values()[0][0].body
if (len(self.request.files.values()) > 0): if (message == "response"):
content = self.request.files.values()[0][0]["body"] with models.decoded(flow.response):
flow.response.content = str(content) flow.response.content = content
elif(message == "request"):
with models.decoded(flow.request):
flow.request.content = content
self.state.update_flow(flow) self.state.update_flow(flow)
def get(self, flow_id, message): def get(self, flow_id, message):
message = getattr(self.flow, message) message = getattr(self.flow, message)

View File

@ -109,4 +109,4 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
} }

View File

@ -4,7 +4,7 @@ import { ViewAuto, ViewImage } from './ContentView/ContentViews'
import * as MetaViews from './ContentView/MetaViews' import * as MetaViews from './ContentView/MetaViews'
import ContentLoader from './ContentView/ContentLoader' import ContentLoader from './ContentView/ContentLoader'
import ViewSelector from './ContentView/ViewSelector' import ViewSelector from './ContentView/ViewSelector'
import * as flowsActions from '../ducks/flows' import ContentEditor from './ContentView/ContentEditor'
export default class ContentView extends Component { export default class ContentView extends Component {
@ -14,12 +14,13 @@ export default class ContentView extends Component {
// <Auto flow={flow} message={flow.request}/> // <Auto flow={flow} message={flow.request}/>
flow: React.PropTypes.object.isRequired, flow: React.PropTypes.object.isRequired,
message: React.PropTypes.object.isRequired, message: React.PropTypes.object.isRequired,
onContentChange: React.PropTypes.func.isRequired
} }
constructor(props, context) { constructor(props, context) {
super(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) this.selectView = this.selectView.bind(this)
} }
@ -43,9 +44,7 @@ export default class ContentView extends Component {
onOpenFile(e) { onOpenFile(e) {
if (e.target.files.length > 0) { if (e.target.files.length > 0) {
//alert(e.target.files[0]) this.props.onContentChange(e.target.files[0])
flowsActions.update_content(this.props.flow, e.target.files[0])
//this.fileInput.value = ''
} }
e.preventDefault() e.preventDefault()
} }
@ -68,30 +67,56 @@ export default class ContentView extends Component {
return ( return (
<div> <div>
{View.textView ? ( <div className="row">
<ContentLoader flow={flow} message={message}> <div className="col-sm-12">
<this.state.View update_content={content => flowsActions.update_content(this.props.flow, content)} content="" /> <ContentLoader flow={flow} message={message}>
</ContentLoader> <ContentEditor
) : ( onSave={this.props.onContentChange}
<View flow={flow} update_content={content => flowsActions.update_content(this.props.flow, content)} message={message} /> onClose={() => this.setState({contentEditorClosed : true})}
)} onOpen={() => this.setState({contentEditorClosed : false})}
<div className="view-options text-center"> isClosed={this.state.contentEditorClosed}
<ViewSelector onSelectView={this.selectView} active={View} message={message}/> content=""
&nbsp; />
<a className="btn btn-default btn-xs" href={MessageUtils.getContentURL(flow, message)}> </ContentLoader>
<i className="fa fa-download"/> </div>
</a>
&nbsp;
<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> </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}/>
&nbsp;
<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>
&nbsp;
<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> </div>
) )
} }

View File

@ -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>
)
}
}

View File

@ -1,12 +1,9 @@
import React, { PropTypes } from 'react' import React, { PropTypes } from 'react'
import ContentLoader from './ContentLoader' import ContentLoader from './ContentLoader'
import { MessageUtils } from '../../flow/utils.js' import { MessageUtils } from '../../flow/utils.js'
import CodeEditor from '../common/CodeEditor'
import {formatSize} from '../../utils.js'
const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw]
const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw, ViewFile]
ViewImage.regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i ViewImage.regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i
ViewImage.matches = msg => ViewImage.regex.test(MessageUtils.getContentType(msg)) ViewImage.matches = msg => ViewImage.regex.test(MessageUtils.getContentType(msg))
@ -26,16 +23,13 @@ export function ViewImage({ flow, message }) {
ViewRaw.textView = true ViewRaw.textView = true
ViewRaw.matches = () => true ViewRaw.matches = () => true
ViewRaw.input = {}
ViewRaw.propTypes = { ViewRaw.propTypes = {
content: React.PropTypes.string.isRequired, content: React.PropTypes.string.isRequired,
} }
export function ViewRaw({ content, update_content }) { export function ViewRaw({ content }) {
return ( return <pre>{content}</pre>
<CodeEditor value={content} onSave={update_content}/>
)
} }
ViewJSON.textView = true ViewJSON.textView = true
@ -65,26 +59,13 @@ ViewAuto.propTypes = {
flow: React.PropTypes.object.isRequired, flow: React.PropTypes.object.isRequired,
} }
export function ViewAuto({ message, flow, update_content }) { export function ViewAuto({ message, flow }) {
const View = ViewAuto.findView(message) const View = ViewAuto.findView(message)
if (View.textView) { 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 { } else {
return <View message={message} flow={flow} /> 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 export default views

View File

@ -6,6 +6,7 @@ import { Key, formatTimeStamp } from '../../utils.js'
import ContentView from '../ContentView' import ContentView from '../ContentView'
import ValueEditor from '../ValueEditor' import ValueEditor from '../ValueEditor'
import Headers from './Headers' import Headers from './Headers'
import * as flowActions from '../../ducks/flows'
class RequestLine extends Component { class RequestLine extends Component {
@ -89,7 +90,10 @@ export class Request extends Component {
onChange={headers => updateFlow({ request: { headers } })} onChange={headers => updateFlow({ request: { headers } })}
/> />
<hr/> <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> </section>
) )
} }
@ -128,7 +132,10 @@ export class Response extends Component {
onChange={headers => updateFlow({ response: { headers } })} onChange={headers => updateFlow({ response: { headers } })}
/> />
<hr/> <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> </section>
) )
} }

View File

@ -2,7 +2,8 @@ import React, { PropTypes } from 'react'
Button.propTypes = { Button.propTypes = {
onClick: PropTypes.func.isRequired, onClick: PropTypes.func.isRequired,
text: PropTypes.string.isRequired text: PropTypes.string,
icon: PropTypes.string
} }
export default function Button({ onClick, text, icon, disabled }) { 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"} <div className={"btn btn-default"}
onClick={onClick} onClick={onClick}
disabled={disabled}> disabled={disabled}>
<span hidden={!icon}> {icon && (<i className={"fa fa-fw " + icon}/> )}
<i className={"fa fa-fw " + icon}/> {text && text}
&nbsp;
</span>
{text}
</div> </div>
) )
} }

View File

@ -1,40 +1,28 @@
import React, { Component, PropTypes } from 'react' import React, { Component, PropTypes } from 'react'
import { render } from 'react-dom'; import { render } from 'react-dom';
import brace from 'brace';
import AceEditor from 'react-ace'; import AceEditor from 'react-ace';
import Button from './Button'
import 'brace/mode/javascript'; import 'brace/mode/javascript';
import 'brace/mode/json';
import 'brace/theme/kuroir'; import 'brace/theme/kuroir';
export default class CodeEditor extends Component{ export default class CodeEditor extends Component{
constructor( props ) { static propTypes = {
super(props) value: PropTypes.string.isRequired,
this.state = {value: this.props.value} onChange: PropTypes.func.isRequired,
}
onChange(newValue) {
this.setState({value: newValue})
} }
render() { render() {
return ( return (
<div onKeyDown={e => e.stopPropagation()}> <div onKeyDown={e => e.stopPropagation()}>
<AceEditor <AceEditor
onChange={e => this.onChange(e)}
mode="javascript" mode="javascript"
theme="kuroir" theme="kuroir"
value={this.state.value} onChange={this.props.onChange}
name="rea"
value={this.props.value}
width="100%" width="100%"
name="codeEditor"
editorProps={{$blockScrolling: Infinity}} editorProps={{$blockScrolling: Infinity}}
/> />
<Button onClick={(e) => this.props.onSave(this.state.value)} text="Update"/>
</div> </div>
) )
} }

View File

@ -117,13 +117,12 @@ export function update(flow, data) {
return { type: REQUEST_ACTION } return { type: REQUEST_ACTION }
} }
export function update_content(flow, file) { export function updateContent(flow, file, type) {
const body = new FormData() const body = new FormData()
if (typeof file !== File) if (typeof file !== File)
file = new Blob([file], {type: 'plain/text'}) file = new Blob([file], {type: 'plain/text'})
body.append('file', file) body.append('file', file)
fetchApi(`/flows/${flow.id}/response/content`, {method: 'post', body} ) fetchApi(`/flows/${flow.id}/${type}/content`, {method: 'post', body} )
update(flow, {response: {headers: [['Content-Encoding', '']]} } )
return { type: REQUEST_ACTION } return { type: REQUEST_ACTION }
} }