aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js
diff options
context:
space:
mode:
authorClemens <cle1000.cb@gmail.com>2016-08-03 12:08:10 +0200
committerClemens <cle1000.cb@gmail.com>2016-08-03 12:08:10 +0200
commit34fe391afbe18f89d774137f82620024f697ab6a (patch)
tree0a1bcd4b0bccd1e7e51166982f8b4332da94a384 /web/src/js
parentbcc496527ebf5faf94025ec7c28992a1ac368140 (diff)
downloadmitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.tar.gz
mitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.tar.bz2
mitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.zip
add view all button, add dropdown for contentviews
Diffstat (limited to 'web/src/js')
-rw-r--r--web/src/js/components/ContentView.jsx10
-rw-r--r--web/src/js/components/ContentView/ContentViews.jsx75
-rw-r--r--web/src/js/components/ContentView/ShowFullContentButton.jsx29
-rw-r--r--web/src/js/components/ContentView/ViewSelector.jsx92
-rw-r--r--web/src/js/components/common/Button.jsx5
-rw-r--r--web/src/js/ducks/ui/flow.js65
6 files changed, 212 insertions, 64 deletions
diff --git a/web/src/js/components/ContentView.jsx b/web/src/js/components/ContentView.jsx
index de4ffd06..9ec283ca 100644
--- a/web/src/js/components/ContentView.jsx
+++ b/web/src/js/components/ContentView.jsx
@@ -5,6 +5,7 @@ import * as MetaViews from './ContentView/MetaViews'
import ViewSelector from './ContentView/ViewSelector'
import UploadContentButton from './ContentView/UploadContentButton'
import DownloadContentButton from './ContentView/DownloadContentButton'
+import ShowFullContentButton from './ContentView/ShowFullContentButton'
import { setContentView, displayLarge, updateEdit } from '../ducks/ui/flow'
@@ -19,7 +20,7 @@ ContentView.propTypes = {
ContentView.isContentTooLarge = msg => msg.contentLength > 1024 * 1024 * (ContentViews.ViewImage.matches(msg) ? 10 : 0.2)
function ContentView(props) {
- const { flow, message, contentView, isDisplayLarge, displayLarge, uploadContent, onContentChange, readonly } = props
+ const { flow, message, contentView, isDisplayLarge, displayLarge, uploadContent, onContentChange, readonly, contentViewDescription } = props
if (message.contentLength === 0 && readonly) {
return <MetaViews.ContentEmpty {...props}/>
@@ -37,13 +38,15 @@ function ContentView(props) {
return (
<div className="contentview">
<View flow={flow} message={message} contentView={contentView} readonly={readonly} onChange={onContentChange}/>
-
- <div className="view-options text-center">
+ <ShowFullContentButton/>
+ <div className="view-options">
<ViewSelector message={message}/>
&nbsp;
<DownloadContentButton flow={flow} message={message}/>
&nbsp;
<UploadContentButton uploadContent={uploadContent}/>
+ &nbsp;
+ <span>{contentViewDescription}</span>
</div>
</div>
)
@@ -53,6 +56,7 @@ export default connect(
state => ({
contentView: state.ui.flow.contentView,
isDisplayLarge: state.ui.flow.displayLarge,
+ contentViewDescription: state.ui.flow.viewDescription
}),
{
displayLarge,
diff --git a/web/src/js/components/ContentView/ContentViews.jsx b/web/src/js/components/ContentView/ContentViews.jsx
index 3b2af0a9..43aece46 100644
--- a/web/src/js/components/ContentView/ContentViews.jsx
+++ b/web/src/js/components/ContentView/ContentViews.jsx
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React, { PropTypes, Component } from 'react'
+import { connect } from 'react-redux'
+import { setContentViewDescription, setShowFullContent } from '../../ducks/ui/flow'
import ContentLoader from './ContentLoader'
import { MessageUtils } from '../../flow/utils'
import CodeEditor from './CodeEditor'
@@ -27,32 +29,63 @@ function Edit({ content, onChange }) {
}
Edit = ContentLoader(Edit)
+class ViewServer extends Component {
+ constructor(props){
+ super(props)
+ this.maxLines = 80
+ }
-function ViewServer(props){
- const {content, contentView, message} = props
- let data = JSON.parse(content)
+ componentWillMount(){
+ this.setContentView(this.props)
+ }
+ componentWillReceiveProps(nextProps){
+ this.setContentView(nextProps)
+ }
+ setContentView(props){
+ try {
+ this.data = JSON.parse(props.content)
+ }catch(err) {
+ this.data= {lines: [], description: err.message}
+ }
- return <div>
- {contentView != data.description &&
- <div className="alert alert-warning">{data.description}</div>
- }
- <pre>
- {data.lines.map((line, i) =>
- <div key={`line${i}`}>
- {line.map((tuple, j) =>
- <span key={`tuple${j}`} className={tuple[0]}>
- {tuple[1]}
- </span>
- )}
- </div>
- )}
- </pre>
+ props.setContentViewDescription(props.contentView != this.data.description ? this.data.description : '')
+
+ let isFullContentShown = this.data.lines.length < this.maxLines
+ if (isFullContentShown) props.setShowFullContent(true)
+ }
+ render() {
+ const {content, contentView, message} = this.props
+
+ let lines = this.props.showFullContent ? this.data.lines : this.data.lines.slice(0, this.maxLines)
+
+ return <div>
+ <pre>
+ {lines.map((line, i) =>
+ <div key={`line${i}`}>
+ {line.map((tuple, j) =>
+ <span key={`tuple${j}`} className={tuple[0]}>
+ {tuple[1]}
+ </span>
+ )}
+ </div>
+ )}
+ </pre>
{ViewImage.matches(message) &&
- <ViewImage {...props} />
+ <ViewImage {...this.props} />
}
</div>
+ }
+
}
-ViewServer = ContentLoader(ViewServer)
+ViewServer = connect(
+ state => ({
+ showFullContent: state.ui.flow.showFullContent
+ }),
+ {
+ setContentViewDescription,
+ setShowFullContent
+ }
+)(ContentLoader(ViewServer))
export { Edit, ViewServer, ViewImage }
diff --git a/web/src/js/components/ContentView/ShowFullContentButton.jsx b/web/src/js/components/ContentView/ShowFullContentButton.jsx
new file mode 100644
index 00000000..a0217d32
--- /dev/null
+++ b/web/src/js/components/ContentView/ShowFullContentButton.jsx
@@ -0,0 +1,29 @@
+import React, { Component, PropTypes } from 'react'
+import { connect } from 'react-redux'
+import { render } from 'react-dom';
+import Button from '../common/Button';
+import { setShowFullContent } from '../../ducks/ui/flow'
+
+
+
+ShowFullContentButton.propTypes = {
+ setShowFullContent: PropTypes.func.isRequired,
+ showFullContent: PropTypes.bool.isRequired
+}
+
+function ShowFullContentButton ( {setShowFullContent, showFullContent} ){
+
+ return (
+ !showFullContent && <Button isXs={true} onClick={() => setShowFullContent(true)} text="Show full content"/>
+ )
+}
+
+export default connect(
+ state => ({
+ showFullContent: state.ui.flow.showFullContent
+ }),
+ {
+ setShowFullContent
+ }
+)(ShowFullContentButton)
+
diff --git a/web/src/js/components/ContentView/ViewSelector.jsx b/web/src/js/components/ContentView/ViewSelector.jsx
index c5670328..1959ec1e 100644
--- a/web/src/js/components/ContentView/ViewSelector.jsx
+++ b/web/src/js/components/ContentView/ViewSelector.jsx
@@ -1,48 +1,82 @@
-import React, { PropTypes } from 'react'
+import React, { PropTypes, Component } from 'react'
import classnames from 'classnames'
import { connect } from 'react-redux'
import * as ContentViews from './ContentViews'
-import { setContentView } from "../../ducks/ui/flow";
+import { setContentView, setContentViewSelectorOpen } from "../../ducks/ui/flow";
-function ViewButton({ name, setContentView, children, activeView }) {
+function ViewItem({ name, setContentView, children }) {
return (
- <button
- onClick={() => setContentView(name)}
- className={classnames('btn btn-default', { active: name === activeView })}>
- {children}
- </button>
+ <li>
+ <a href="#" onClick={() => setContentView(name)}>
+ {children}
+ </a>
+ </li>
)
}
-ViewButton = connect(state => ({
- activeView: state.ui.flow.contentView
-}), {
- setContentView
-})(ViewButton)
-ViewSelector.propTypes = {
- message: PropTypes.object.isRequired,
-}
-function ViewSelector({contentViews, isEdit }) {
- let edit = ContentViews.Edit.displayName
- return (
- <div className="view-selector btn-group btn-group-xs">
+/*ViewSelector.propTypes = {
+ contentViews: PropTypes.array.isRequired,
+ activeView: PropTypes.string.isRequired,
+ isEdit: PropTypes.bool.isRequired,
+ isContentViewSelectorOpen: PropTypes.bool.isRequired,
+ setContentViewSelectorOpen: PropTypes.func.isRequired
+}*/
- {contentViews.map(name =>
- <ViewButton key={name} name={name}>{name.toLowerCase().replace('_', ' ')}</ViewButton>
- )}
- {isEdit &&
- <ViewButton key={edit} name={edit}>{edit.toLowerCase()}</ViewButton>
- }
+class ViewSelector extends Component {
+ constructor(props, context) {
+ super(props, context)
+ this.close = this.close.bind(this)
+ }
+ close() {
+ this.props.setContentViewSelectorOpen(false)
+ document.removeEventListener('click', this.close)
+ }
- </div>
- )
+ onDropdown(e){
+ e.preventDefault()
+ this.props.setContentViewSelectorOpen(!this.props.isContentViewSelectorOpen)
+ document.addEventListener('click', this.close)
+ }
+
+ render() {
+ const {contentViews, activeView, isEdit, isContentViewSelectorOpen, setContentViewSelectorOpen, setContentView} = this.props
+ let edit = ContentViews.Edit.displayName
+
+ return (
+ <div className={classnames('dropup pull-left', { open: isContentViewSelectorOpen })}>
+ <a className="btn btn-default btn-xs"
+ onClick={ e => this.onDropdown(e) }
+ href="#">
+ <b>View:</b> {activeView}<span className="caret"></span>
+ </a>
+ <ul className="dropdown-menu" role="menu">
+ {contentViews.map(name =>
+ <ViewItem key={name} setContentView={setContentView} name={name}>
+ {name.toLowerCase().replace('_', ' ')}
+ </ViewItem>
+ )}
+ {isEdit &&
+ <ViewItem key={edit} setContentView={setContentView} name={edit}>
+ {edit.toLowerCase()}
+ </ViewItem>
+ }
+ </ul>
+ </div>
+ )
+ }
}
export default connect (
state => ({
contentViews: state.settings.contentViews,
+ activeView: state.ui.flow.contentView,
isEdit: !!state.ui.flow.modifiedFlow,
- }))(ViewSelector)
+ isContentViewSelectorOpen: state.ui.flow.isContentViewSelectorOpen
+ }), {
+ setContentView,
+ setContentViewSelectorOpen
+ }
+)(ViewSelector)
diff --git a/web/src/js/components/common/Button.jsx b/web/src/js/components/common/Button.jsx
index cd01af22..0ac80782 100644
--- a/web/src/js/components/common/Button.jsx
+++ b/web/src/js/components/common/Button.jsx
@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react'
+import classnames from 'classnames'
Button.propTypes = {
onClick: PropTypes.func.isRequired,
@@ -6,9 +7,9 @@ Button.propTypes = {
icon: PropTypes.string
}
-export default function Button({ onClick, text, icon, disabled }) {
+export default function Button({ onClick, text, icon, disabled, isXs }) {
return (
- <div className={"btn btn-default"}
+ <div className={classnames('btn btn-default', { 'btn-xs': isXs})}
onClick={onClick}
disabled={disabled}>
{icon && (<i className={"fa fa-fw " + icon}/> )}
diff --git a/web/src/js/ducks/ui/flow.js b/web/src/js/ducks/ui/flow.js
index d9811a33..9c1d6dea 100644
--- a/web/src/js/ducks/ui/flow.js
+++ b/web/src/js/ducks/ui/flow.js
@@ -3,16 +3,22 @@ import { getDiff } from "../../utils"
import _ from 'lodash'
-export const SET_CONTENT_VIEW = 'UI_FLOWVIEW_SET_CONTENT_VIEW',
- DISPLAY_LARGE = 'UI_FLOWVIEW_DISPLAY_LARGE',
- SET_TAB = "UI_FLOWVIEW_SET_TAB",
- START_EDIT = 'UI_FLOWVIEW_START_EDIT',
- UPDATE_EDIT = 'UI_FLOWVIEW_UPDATE_EDIT',
- UPLOAD_CONTENT = 'UI_FLOWVIEW_UPLOAD_CONTENT'
+export const SET_CONTENT_VIEW = 'UI_FLOWVIEW_SET_CONTENT_VIEW',
+ DISPLAY_LARGE = 'UI_FLOWVIEW_DISPLAY_LARGE',
+ SET_TAB = "UI_FLOWVIEW_SET_TAB",
+ START_EDIT = 'UI_FLOWVIEW_START_EDIT',
+ UPDATE_EDIT = 'UI_FLOWVIEW_UPDATE_EDIT',
+ UPLOAD_CONTENT = 'UI_FLOWVIEW_UPLOAD_CONTENT',
+ SET_SHOW_FULL_CONTENT = 'UI_SET_SHOW_FULL_CONTENT',
+ SET_CONTENT_VIEW_DESCRIPTION = "UI_SET_CONTENT_VIEW_DESCRIPTION",
+ SET_CONTENT_VIEW_SELECTOR = "UI_SET_CONTENT_VIEW_SELECTOR"
const defaultState = {
displayLarge: false,
+ contentViewDescription: '',
+ showFullContent: false,
+ isContentViewSelectorOpen: false,
modifiedFlow: false,
contentView: 'Auto',
tab: 'request',
@@ -26,7 +32,8 @@ export default function reducer(state = defaultState, action) {
return {
...state,
modifiedFlow: action.flow,
- contentView: 'Edit'
+ contentView: 'Edit',
+ showFullContent: true
}
case UPDATE_EDIT:
@@ -40,7 +47,9 @@ export default function reducer(state = defaultState, action) {
...state,
modifiedFlow: false,
displayLarge: false,
- contentView: (wasInEditMode ? 'Auto' : state.contentView)
+ contentView: (wasInEditMode ? 'Auto' : state.contentView),
+ viewDescription: '',
+ showFullContent: false,
}
case flowsActions.UPDATE:
@@ -52,24 +61,46 @@ export default function reducer(state = defaultState, action) {
...state,
modifiedFlow: false,
displayLarge: false,
- contentView: (wasInEditMode ? 'Auto' : state.contentView)
+ contentView: (wasInEditMode ? 'Auto' : state.contentView),
+ viewDescription: '',
+ showFullContent: false
}
} else {
return state
}
+ case SET_CONTENT_VIEW_DESCRIPTION:
+ return {
+ ...state,
+ viewDescription: action.description
+ }
+
+ case SET_SHOW_FULL_CONTENT:
+ return {
+ ...state,
+ showFullContent: action.show
+ }
+
+
+ case SET_CONTENT_VIEW_SELECTOR:
+ return {
+ ...state,
+ isContentViewSelectorOpen: action.contentViewSelector
+ }
case SET_TAB:
return {
...state,
tab: action.tab,
displayLarge: false,
+ showFullContent: false
}
case SET_CONTENT_VIEW:
return {
...state,
contentView: action.contentView,
+ showFullContent: action.contentView == 'Edit'
}
case DISPLAY_LARGE:
@@ -102,6 +133,22 @@ export function updateEdit(update) {
return { type: UPDATE_EDIT, update }
}
+export function setContentViewDescription(description) {
+ return { type: SET_CONTENT_VIEW_DESCRIPTION, description }
+}
+
+export function setShowFullContent(show) {
+ return { type: SET_SHOW_FULL_CONTENT, show }
+}
+
+export function setContentViewSelectorOpen(open){
+ return {type: SET_CONTENT_VIEW_SELECTOR, contentViewSelector: open}
+}
+
+export function updateEdit(update) {
+ return { type: UPDATE_EDIT, update }
+}
+
export function stopEdit(flow, modifiedFlow) {
let diff = getDiff(flow, modifiedFlow)
return flowsActions.update(flow, diff)