diff options
author | Clemens <cle1000.cb@gmail.com> | 2016-08-03 12:08:10 +0200 |
---|---|---|
committer | Clemens <cle1000.cb@gmail.com> | 2016-08-03 12:08:10 +0200 |
commit | 34fe391afbe18f89d774137f82620024f697ab6a (patch) | |
tree | 0a1bcd4b0bccd1e7e51166982f8b4332da94a384 /web | |
parent | bcc496527ebf5faf94025ec7c28992a1ac368140 (diff) | |
download | mitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.tar.gz mitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.tar.bz2 mitmproxy-34fe391afbe18f89d774137f82620024f697ab6a.zip |
add view all button, add dropdown for contentviews
Diffstat (limited to 'web')
-rw-r--r-- | web/src/css/flowdetail.less | 1 | ||||
-rw-r--r-- | web/src/js/components/ContentView.jsx | 10 | ||||
-rw-r--r-- | web/src/js/components/ContentView/ContentViews.jsx | 75 | ||||
-rw-r--r-- | web/src/js/components/ContentView/ShowFullContentButton.jsx | 29 | ||||
-rw-r--r-- | web/src/js/components/ContentView/ViewSelector.jsx | 92 | ||||
-rw-r--r-- | web/src/js/components/common/Button.jsx | 5 | ||||
-rw-r--r-- | web/src/js/ducks/ui/flow.js | 65 |
7 files changed, 213 insertions, 64 deletions
diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index d450bca5..7e65528f 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -65,6 +65,7 @@ } .view-options { + margin-bottom: 10px; margin-top: 10px; } 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}/> <DownloadContentButton flow={flow} message={message}/> <UploadContentButton uploadContent={uploadContent}/> + + <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) |