minor fixes

This commit is contained in:
Maximilian Hils 2016-06-26 01:45:45 -07:00
parent 1c240d919a
commit 3eb2d04aac
16 changed files with 200 additions and 233 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,8 +9,8 @@ class EventLog extends Component {
static propTypes = {
filters: PropTypes.object.isRequired,
events: PropTypes.array.isRequired,
onToggleFilter: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
toggleFilter: PropTypes.func.isRequired,
close: PropTypes.func.isRequired,
defaultHeight: PropTypes.number,
}
@ -48,7 +48,7 @@ class EventLog extends Component {
render() {
const { height } = this.state
const { filters, events, onToggleFilter, onClose } = this.props
const { filters, events, toggleFilter, close } = this.props
return (
<div className="eventlog" style={{ height }}>
@ -56,9 +56,9 @@ class EventLog extends Component {
Eventlog
<div className="pull-right">
{['debug', 'info', 'web'].map(type => (
<ToggleButton key={type} text={type} checked={filters[type]} onToggle={() => onToggleFilter(type)}/>
<ToggleButton key={type} text={type} checked={filters[type]} onToggle={() => toggleFilter(type)}/>
))}
<i onClick={onClose} className="fa fa-close"></i>
<i onClick={close} className="fa fa-close"></i>
</div>
</div>
<EventList events={events} />
@ -73,7 +73,7 @@ export default connect(
events: state.eventLog.view.data,
}),
{
onClose: toggleVisibility,
onToggleFilter: toggleFilter,
close: toggleVisibility,
toggleFilter: toggleFilter,
}
)(EventLog)

View File

@ -6,7 +6,7 @@ import columns from './FlowColumns'
import { updateSort } from '../../ducks/views/main'
FlowTableHead.propTypes = {
onSort: PropTypes.func.isRequired,
updateSort: PropTypes.func.isRequired,
sortDesc: React.PropTypes.bool.isRequired,
sortColumn: React.PropTypes.string,
}

View File

@ -35,8 +35,8 @@ export default class FlowView extends Component {
closePrompt(edit) {
this.setState({ prompt: false })
if (edit) {
this.refs.tab.edit(edit)
if (edit && this.tabComponent) {
this.tabComponent.edit(edit)
}
}
@ -75,7 +75,7 @@ export default class FlowView extends Component {
render() {
const tabs = this.getTabs()
let { flow, tab: active, onUpdate } = this.props
let { flow, tab: active, updateFlow } = this.props
if (tabs.indexOf(active) < 0) {
if (active === 'response' && flow.error) {
@ -97,7 +97,7 @@ export default class FlowView extends Component {
active={active}
onSelectTab={this.selectTab}
/>
<Tab ref="tab" flow={flow} onUpdate={onUpdate} />
<Tab ref={ tab => this.tabComponent = tab } flow={flow} updateFlow={updateFlow} />
{this.state.prompt && (
<Prompt {...this.state.prompt}/>
)}

View File

@ -10,21 +10,21 @@ import Headers from './Headers'
class RequestLine extends Component {
render() {
const { flow, onUpdate } = this.props
const { flow, updateFlow } = this.props
return (
<div className="first-line request-line">
<ValueEditor
ref="method"
content={flow.request.method}
onDone={method => onUpdate({ request: { method } })}
onDone={method => updateFlow({ request: { method } })}
inline
/>
&nbsp;
<ValueEditor
ref="url"
content={RequestUtils.pretty_url(flow.request)}
onDone={url => onUpdate({ request: Object.assign({ path: '' }, parseUrl(url)) })}
onDone={url => updateFlow({ request: Object.assign({ path: '' }, parseUrl(url)) })}
isValid={url => !!parseUrl(url).host}
inline
/>
@ -32,7 +32,7 @@ class RequestLine extends Component {
<ValueEditor
ref="httpVersion"
content={flow.request.http_version}
onDone={ver => onUpdate({ request: { http_version: parseHttpVersion(ver) } })}
onDone={ver => updateFlow({ request: { http_version: parseHttpVersion(ver) } })}
isValid={isValidHttpVersion}
inline
/>
@ -44,14 +44,14 @@ class RequestLine extends Component {
class ResponseLine extends Component {
render() {
const { flow, onUpdate } = this.props
const { flow, updateFlow } = this.props
return (
<div className="first-line response-line">
<ValueEditor
ref="httpVersion"
content={flow.response.http_version}
onDone={nextVer => onUpdate({ response: { http_version: parseHttpVersion(nextVer) } })}
onDone={nextVer => updateFlow({ response: { http_version: parseHttpVersion(nextVer) } })}
isValid={isValidHttpVersion}
inline
/>
@ -59,7 +59,7 @@ class ResponseLine extends Component {
<ValueEditor
ref="code"
content={flow.response.status_code + ''}
onDone={code => onUpdate({ response: { code: parseInt(code) } })}
onDone={code => updateFlow({ response: { code: parseInt(code) } })}
isValid={code => /^\d+$/.test(code)}
inline
/>
@ -67,7 +67,7 @@ class ResponseLine extends Component {
<ValueEditor
ref="msg"
content={flow.response.reason}
onDone={msg => onUpdate({ response: { msg } })}
onDone={msg => updateFlow({ response: { msg } })}
inline
/>
</div>
@ -78,15 +78,15 @@ class ResponseLine extends Component {
export class Request extends Component {
render() {
const { flow, onUpdate } = this.props
const { flow, updateFlow } = this.props
return (
<section className="request">
<RequestLine ref="requestLine" flow={flow} onUpdate={onUpdate} />
<RequestLine ref="requestLine" flow={flow} updateFlow={updateFlow} />
<Headers
ref="headers"
message={flow.request}
onChange={headers => onUpdate({ request: { headers } })}
onChange={headers => updateFlow({ request: { headers } })}
/>
<hr/>
<ContentView flow={flow} message={flow.request}/>
@ -117,15 +117,15 @@ export class Request extends Component {
export class Response extends Component {
render() {
const { flow, onUpdate } = this.props
const { flow, updateFlow } = this.props
return (
<section className="response">
<ResponseLine ref="responseLine" flow={flow} onUpdate={onUpdate} />
<ResponseLine ref="responseLine" flow={flow} updateFlow={updateFlow} />
<Headers
ref="headers"
message={flow.response}
onChange={headers => onUpdate({ response: { headers } })}
onChange={headers => updateFlow({ response: { headers } })}
/>
<hr/>
<ContentView flow={flow} message={flow.response}/>

View File

@ -1,7 +1,6 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import classnames from 'classnames'
import * as flowsActions from '../../ducks/flows'
NavAction.propTypes = {
icon: PropTypes.string.isRequired,
@ -24,18 +23,12 @@ function NavAction({ icon, title, onClick }) {
}
Nav.propTypes = {
flow: PropTypes.object.isRequired,
active: PropTypes.string.isRequired,
tabs: PropTypes.array.isRequired,
onSelectTab: PropTypes.func.isRequired,
onRemove: PropTypes.func.isRequired,
onDuplicate: PropTypes.func.isRequired,
onReplay: PropTypes.func.isRequired,
onAccept: PropTypes.func.isRequired,
onRevert: PropTypes.func.isRequired,
}
function Nav({ flow, active, tabs, onSelectTab, onRemove, onDuplicate, onReplay, onAccept, onRevert }) {
export default function Nav({ active, tabs, onSelectTab }) {
return (
<nav className="nav-tabs nav-tabs-sm">
{tabs.map(tab => (
@ -49,26 +42,6 @@ function Nav({ flow, active, tabs, onSelectTab, onRemove, onDuplicate, onReplay,
{_.capitalize(tab)}
</a>
))}
<NavAction title="[d]elete flow" icon="fa-trash" onClick={() => onRemove(flow)} />
<NavAction title="[D]uplicate flow" icon="fa-copy" onClick={() => onDuplicate(flow)} />
<NavAction disabled title="[r]eplay flow" icon="fa-repeat" onClick={() => onReplay(flow)} />
{flow.intercepted && (
<NavAction title="[a]ccept intercepted flow" icon="fa-play" onClick={() => onAccept(flow)} />
)}
{flow.modified && (
<NavAction title="revert changes to flow [V]" icon="fa-history" onClick={() => onRevert(flow)} />
)}
</nav>
)
}
export default connect(
null,
{
onRemove: flowsActions.remove,
onDuplicate: flowsActions.duplicate,
onReplay: flowsActions.replay,
onAccept: flowsActions.accept,
onRevert: flowsActions.revert,
}
)(Nav)

View File

@ -36,7 +36,7 @@ class FileMenu extends Component {
onNewClick(e) {
e.preventDefault()
if (confirm('Delete all flows?')) {
this.props.onClear()
this.props.clearFlows()
}
}
@ -48,14 +48,14 @@ class FileMenu extends Component {
onOpenFile(e) {
e.preventDefault()
if (e.target.files.length > 0) {
this.props.onUpload(e.target.files[0])
this.props.loadFlows(e.target.files[0])
this.fileInput.value = ''
}
}
onSaveClick(e) {
e.preventDefault()
this.props.onDownload()
this.props.saveFlows()
}
render() {
@ -103,8 +103,8 @@ class FileMenu extends Component {
export default connect(
null,
{
onClear: flowsActions.clear,
onUpload: flowsActions.upload,
onDownload: flowsActions.download,
clearFlows: flowsActions.clear,
loadFlows: flowsActions.upload,
saveFlows: flowsActions.download,
}
)(FileMenu)

View File

@ -10,16 +10,16 @@ FlowMenu.propTypes = {
flow: PropTypes.object.isRequired,
}
function FlowMenu({ flow, onAccept, onReplay, onDuplicate, onRemove, onRevert }) {
function FlowMenu({ flow, acceptFlow, replayFlow, duplicateFlow, removeFlow, revertFlow }) {
return (
<div>
<div className="menu-row">
<Button disabled={!flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => onAccept(flow)} />
<Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={() => onReplay(flow)} />
<Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={() => onDuplicate(flow)} />
<Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={() => onRemove(flow)}/>
<Button disabled={!flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => onRevert(flow)} />
<Button disabled={!flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => acceptFlow(flow)} />
<Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={() => replayFlow(flow)} />
<Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={() => duplicateFlow(flow)} />
<Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={() => removeFlow(flow)}/>
<Button disabled={!flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => revertFlow(flow)} />
<Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/>
</div>
<div className="clearfix"/>
@ -32,10 +32,10 @@ export default connect(
flow: state.flows.list.byId[state.flows.views.main.selected[0]],
}),
{
onAccept: flowsActions.accept,
onReplay: flowsActions.replay,
onDuplicate: flowsActions.duplicate,
onRemove: flowsActions.remove,
onRevert: flowsActions.revert,
acceptFlow: flowsActions.accept,
replayFlow: flowsActions.replay,
duplicateFlow: flowsActions.duplicate,
removeFlow: flowsActions.remove,
revertFlow: flowsActions.revert,
}
)(FlowMenu)

View File

@ -13,7 +13,7 @@ class MainMenu extends Component {
query: PropTypes.object.isRequired,
settings: PropTypes.object.isRequired,
updateLocation: PropTypes.func.isRequired,
onSettingsChange: PropTypes.func.isRequired,
updateSettings: PropTypes.func.isRequired,
}
constructor(props, context) {
@ -31,7 +31,7 @@ class MainMenu extends Component {
}
render() {
const { query, settings, onSettingsChange } = this.props
const { query, settings, updateSettings } = this.props
return (
<div>
@ -58,7 +58,7 @@ class MainMenu extends Component {
type="pause"
color="hsl(208, 56%, 53%)"
value={settings.intercept || ''}
onChange={intercept => onSettingsChange({ intercept })}
onChange={intercept => updateSettings({ intercept })}
/>
</div>
<div className="clearfix"></div>
@ -72,7 +72,7 @@ export default connect(
settings: state.settings.settings,
}),
{
onSettingsChange: updateSettings,
updateSettings,
},
null,
{

View File

@ -7,15 +7,15 @@ ViewMenu.title = 'View'
ViewMenu.route = 'flows'
ViewMenu.propTypes = {
visible: PropTypes.bool.isRequired,
onToggle: PropTypes.func.isRequired,
eventLogVisible: PropTypes.bool.isRequired,
toggleEventLog: PropTypes.func.isRequired,
}
function ViewMenu({ visible, onToggle }) {
function ViewMenu({ eventLogVisible, toggleEventLog }) {
return (
<div>
<div className="menu-row">
<ToggleButton text="Show Event Log" checked={visible} onToggle={onToggle} />
<ToggleButton text="Show Event Log" checked={eventLogVisible} onToggle={toggleEventLog} />
</div>
<div className="clearfix"></div>
</div>
@ -24,9 +24,9 @@ function ViewMenu({ visible, onToggle }) {
export default connect(
state => ({
visible: state.eventLog.visible,
eventLogVisible: state.eventLog.visible,
}),
{
onToggle: toggleVisibility,
toggleEventLog: toggleVisibility,
}
)(ViewMenu)

View File

@ -110,33 +110,33 @@ class MainView extends Component {
break
case Key.C:
if (e.shiftKey) {
this.props.onClear()
this.props.clearFlows()
}
break
case Key.D:
if (flow) {
if (e.shiftKey) {
this.props.onDuplicate(flow)
this.props.duplicateFlow(flow)
} else {
this.props.onRemove(flow)
this.props.removeFlow(flow)
}
}
break
case Key.A:
if (e.shiftKey) {
this.props.onAcceptAll()
this.props.acceptAllFlows()
} else if (flow && flow.intercepted) {
this.props.onAccept(flow)
this.props.acceptFlow(flow)
}
break
case Key.R:
if (!e.shiftKey && flow) {
this.props.onReplay(flow)
this.props.replayFlow(flow)
}
break
case Key.V:
if (e.shiftKey && flow && flow.modified) {
this.props.onRevert(flow)
this.props.revertFlow(flow)
}
break
case Key.E:
@ -147,6 +147,7 @@ class MainView extends Component {
case Key.SHIFT:
break
default:
console.debug('keydown', e.keyCode)
return
}
e.preventDefault()
@ -171,7 +172,7 @@ class MainView extends Component {
tab={this.props.routeParams.detailTab}
query={this.props.query}
updateLocation={this.props.updateLocation}
onUpdate={attrs => this.props.onUpdate(selectedFlow, attrs)}
updateFlow={data => this.props.updateFlow(selectedFlow, data)}
flow={selectedFlow}
/>
]}
@ -191,14 +192,14 @@ export default connect(
selectFlow,
updateFilter,
updateHighlight,
onUpdate: flowsActions.update,
onClear: flowsActions.clear,
onDuplicate: flowsActions.duplicate,
onRemove: flowsActions.remove,
onAcceptAll: flowsActions.acceptAll,
onAccept: flowsActions.accept,
onReplay: flowsActions.replay,
onRevert: flowsActions.revert,
updateFlow: flowsActions.update,
clearFlows: flowsActions.clear,
duplicateFlow: flowsActions.duplicate,
removeFlow: flowsActions.remove,
acceptAllFlows: flowsActions.acceptAll,
acceptFlow: flowsActions.accept,
replayFlow: flowsActions.replay,
revertFlow: flowsActions.revert,
},
undefined,
{ withRef: true }

View File

@ -17,8 +17,8 @@ const defaultState = {
logId: 0,
visible: false,
filters: { debug: false, info: true, web: true },
list: undefined,
view: undefined,
list: reduceList(undefined, {}),
view: reduceView(undefined, {}),
}
export default function reduce(state = defaultState, action) {
@ -40,7 +40,7 @@ export default function reduce(state = defaultState, action) {
case ADD:
const item = {
id: `log-${state.logId}`,
id: state.logId,
message: action.message,
level: action.level,
}
@ -52,19 +52,14 @@ export default function reduce(state = defaultState, action) {
}
case RECEIVE:
const list = reduceList(state.list, listActions.receive(action.list))
return {
...state,
list,
list: reduceList(state.list, listActions.receive(action.list)),
view: reduceView(state.view, viewActions.receive(list, log => state.filters[log.level])),
}
default:
return {
...state,
list: reduceList(state.list, action),
view: reduceView(state.view, action),
}
return state
}
}

View File

@ -112,8 +112,8 @@ export function revert(flow) {
/**
* @public
*/
export function update(flow, body) {
fetchApi.put(`/flows/${flow.id}`, body)
export function update(flow, data) {
fetchApi.put(`/flows/${flow.id}`, data)
return { type: REQUEST_ACTION }
}
@ -139,7 +139,7 @@ export function download() {
export function upload(file) {
const body = new FormData()
body.append('file', file)
fetchApi('/flows/dump', { method: 'post', body })
fetchApi('/flows/dump', { method: 'post', body })
return { type: REQUEST_ACTION }
}

View File

@ -26,6 +26,7 @@ export default function reduce(state = defaultState, action) {
const data = [...state.data]
const index = state.indexOf[action.id]
// FIXME: We should just swallow this
if (index == null) {
throw new Error('Item not found')
}
@ -35,8 +36,7 @@ export default function reduce(state = defaultState, action) {
return {
...state,
data,
byId: { ...state.byId, [action.id]: null, [action.item.id]: action.item },
indexOf: { ...state.indexOf, [action.id]: null, [action.item.id]: index },
byId: { ...state.byId, [action.item.id]: action.item },
}
}
@ -45,6 +45,7 @@ export default function reduce(state = defaultState, action) {
const indexOf = { ...state.indexOf }
const index = indexOf[action.id]
// FIXME: We should just swallow this
if (index == null) {
throw new Error('Item not found')
}

View File

@ -79,7 +79,7 @@ export function onMessage(msg) {
export function onDisconnect() {
return dispatch => {
dispatch(eventLogActions.addLogEntry('WebSocket connection closed.'))
dispatch(eventLogActions.add('WebSocket connection closed.'))
dispatch({ type: DISCONNECTED })
}
}
@ -87,7 +87,7 @@ export function onDisconnect() {
export function onError(error) {
// @todo let event log subscribe WebSocketActions.ERROR
return dispatch => {
dispatch(eventLogActions.addLogEntry('WebSocket connection error.'))
dispatch(eventLogActions.add('WebSocket connection error.'))
dispatch({ type: ERROR, error })
}
}