aboutsummaryrefslogtreecommitdiffstats
path: root/web/src
diff options
context:
space:
mode:
Diffstat (limited to 'web/src')
-rw-r--r--web/src/css/app.less1
-rw-r--r--web/src/css/prompt.less27
-rw-r--r--web/src/js/__tests__/components/FlowTableSpec.js2
-rw-r--r--web/src/js/__tests__/components/Header/FileMenuSpec.js6
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap9
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap6
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap82
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap2
-rw-r--r--web/src/js/__tests__/ducks/flowsSpec.js4
-rw-r--r--web/src/js/__tests__/utilsSpec.js5
-rw-r--r--web/src/js/components/FlowTable.jsx20
-rw-r--r--web/src/js/components/FlowView.jsx101
-rw-r--r--web/src/js/components/FlowView/Messages.jsx46
-rw-r--r--web/src/js/components/Header/FileMenu.jsx9
-rw-r--r--web/src/js/components/Header/OptionMenu.jsx84
-rw-r--r--web/src/js/components/MainView.jsx55
-rw-r--r--web/src/js/components/Modal/OptionModal.jsx2
-rwxr-xr-xweb/src/js/components/Prompt.jsx67
-rw-r--r--web/src/js/components/ProxyApp.jsx2
-rw-r--r--web/src/js/components/common/Button.jsx2
-rw-r--r--web/src/js/utils.js7
21 files changed, 130 insertions, 409 deletions
diff --git a/web/src/css/app.less b/web/src/css/app.less
index b9b5b310..1f246b19 100644
--- a/web/src/css/app.less
+++ b/web/src/css/app.less
@@ -14,7 +14,6 @@ html {
@import (less) "flowtable.less";
@import (less) "flowdetail.less";
@import (less) "flowview.less";
-@import (less) "prompt.less";
@import (less) "eventlog.less";
@import (less) "footer.less";
@import (less) "codemirror.less";
diff --git a/web/src/css/prompt.less b/web/src/css/prompt.less
deleted file mode 100644
index eee0426d..00000000
--- a/web/src/css/prompt.less
+++ /dev/null
@@ -1,27 +0,0 @@
-.prompt-dialog {
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- position: fixed;
- z-index: 100;
- background-color: rgba(0, 0, 0, 0.1);
-}
-
-.prompt-content {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- height: 25px;
- padding: 2px 5px;
- background-color: white;
- box-shadow: 0 -1px 3px lightgray;
-
- .option {
- cursor: pointer;
- &:not(:last-child)::after {
- content: ", ";
- }
- }
-} \ No newline at end of file
diff --git a/web/src/js/__tests__/components/FlowTableSpec.js b/web/src/js/__tests__/components/FlowTableSpec.js
index 4d8de12c..f63b28fc 100644
--- a/web/src/js/__tests__/components/FlowTableSpec.js
+++ b/web/src/js/__tests__/components/FlowTableSpec.js
@@ -1,6 +1,6 @@
import React from 'react'
import renderer from 'react-test-renderer'
-import FlowTable from '../../components/FlowTable'
+import {PureFlowTable as FlowTable} from '../../components/FlowTable'
import TestUtils from 'react-dom/test-utils'
import { TFlow, TStore } from '../ducks/tutils'
import { Provider } from 'react-redux'
diff --git a/web/src/js/__tests__/components/Header/FileMenuSpec.js b/web/src/js/__tests__/components/Header/FileMenuSpec.js
index 0d87530b..2f4e746d 100644
--- a/web/src/js/__tests__/components/Header/FileMenuSpec.js
+++ b/web/src/js/__tests__/components/Header/FileMenuSpec.js
@@ -49,10 +49,4 @@ describe('FileMenu Component', () => {
a.props.onClick(mockEvent)
expect(saveFn).toBeCalled()
})
-
- it('should open optionModal', () => {
- let a = ul.children[3].children[1]
- a.props.onClick(mockEvent)
- expect(openModalFn).toBeCalled()
- })
})
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap
index ef935914..f4018fcd 100644
--- a/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap
@@ -63,15 +63,6 @@ exports[`FileMenu Component should render correctly 1`] = `
</li>
<li>
- <a
- href="#"
- onClick={[Function]}
- >
- <i
- className="fa fa-fw fa-cog"
- />
-  Options
- </a>
<hr
className="divider"
/>
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap
index b0b28f1b..2ed3600e 100644
--- a/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap
@@ -33,7 +33,7 @@ exports[`FlowMenu Component should connect to state 1`] = `
<div
className="btn btn-default"
disabled={true}
- onClick={false}
+ onClick={undefined}
title="revert changes to flow [V]"
>
<i
@@ -92,7 +92,7 @@ exports[`FlowMenu Component should connect to state 1`] = `
<div
className="btn btn-default"
disabled={true}
- onClick={false}
+ onClick={undefined}
title="[a]ccept intercepted flow"
>
<i
@@ -103,7 +103,7 @@ exports[`FlowMenu Component should connect to state 1`] = `
<div
className="btn btn-default"
disabled={true}
- onClick={false}
+ onClick={undefined}
title="kill intercepted flow [x]"
>
<i
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap
index 9299e69f..83d9355c 100644
--- a/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap
+++ b/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap
@@ -9,46 +9,24 @@ exports[`OptionMenu Component should render correctly 1`] = `
className="menu-content"
>
<div
- className="menu-entry"
- >
- <label>
- <input
- checked={false}
- onChange={[Function]}
- type="checkbox"
- />
- HTTP/2.0
- </label>
- </div>
- <div
- className="menu-entry"
- >
- <label>
- <input
- checked={false}
- onChange={[Function]}
- type="checkbox"
- />
- WebSockets
- </label>
- </div>
- <div
- className="menu-entry"
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="Open Options"
>
- <label>
- <input
- checked={false}
- onChange={[Function]}
- type="checkbox"
- />
- Raw TCP
- </label>
+ <i
+ className="fa fa-fw fa-cogs text-primary"
+ />
+ Edit Options
+ <sup>
+ alpha
+ </sup>
</div>
</div>
<div
className="menu-legend"
>
- Protocol Support
+ Options Editor
</div>
</div>
<div
@@ -66,7 +44,7 @@ exports[`OptionMenu Component should render correctly 1`] = `
onChange={[Function]}
type="checkbox"
/>
- Disable Caching
+ Strip cache headers
<a
href="http://docs.mitmproxy.org/en/stable/features/anticache.html"
target="_blank"
@@ -86,18 +64,26 @@ exports[`OptionMenu Component should render correctly 1`] = `
onChange={[Function]}
type="checkbox"
/>
- Disable Compression
- <i
- className="fa fa-question-circle"
- title="Do not forward Accept-Encoding headers to the server to force an uncompressed response."
+ Use host header for display
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
/>
+ Verify server certificates
</label>
</div>
</div>
<div
className="menu-legend"
>
- HTTP Options
+ Quick Options
</div>
</div>
<div
@@ -111,22 +97,6 @@ exports[`OptionMenu Component should render correctly 1`] = `
>
<label>
<input
- checked={false}
- onChange={[Function]}
- type="checkbox"
- />
- Use Host Header
- <i
- className="fa fa-question-circle"
- title="Use the Host header to construct URLs for display."
- />
- </label>
- </div>
- <div
- className="menu-entry"
- >
- <label>
- <input
checked={true}
onChange={[Function]}
type="checkbox"
diff --git a/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap
index 1d403b2d..8b1c9d6d 100644
--- a/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap
+++ b/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap
@@ -4,7 +4,7 @@ exports[`Button Component should be able to be disabled 1`] = `
<div
className="classname btn btn-default"
disabled="true"
- onClick={false}
+ onClick={undefined}
title={undefined}
>
<a>
diff --git a/web/src/js/__tests__/ducks/flowsSpec.js b/web/src/js/__tests__/ducks/flowsSpec.js
index 5bd866f2..d749d9e1 100644
--- a/web/src/js/__tests__/ducks/flowsSpec.js
+++ b/web/src/js/__tests__/ducks/flowsSpec.js
@@ -157,7 +157,9 @@ describe('flows actions', () => {
file = new window.Blob(['foo'], { type: 'plain/text' })
body.append('file', file)
store.dispatch(flowActions.uploadContent(tflow, 'foo', 'foo'))
- expect(fetchApi).toBeCalledWith('/flows/1/foo/content', { method: 'POST', body})
+ // window.Blob's lastModified is always the current time,
+ // which causes flaky tests on comparison.
+ expect(fetchApi).toBeCalledWith('/flows/1/foo/content', { method: 'POST', body: expect.anything()})
})
it('should handle clear action', () => {
diff --git a/web/src/js/__tests__/utilsSpec.js b/web/src/js/__tests__/utilsSpec.js
index 9a1a0750..d0beca14 100644
--- a/web/src/js/__tests__/utilsSpec.js
+++ b/web/src/js/__tests__/utilsSpec.js
@@ -83,11 +83,6 @@ describe('pure', () => {
expect(utils.pure(tFunc).displayName).toEqual('tFunc')
})
- it('should suggest when should component update', () => {
- expect(f.shouldComponentUpdate('foo')).toBeTruthy()
- expect(f.shouldComponentUpdate('bar')).toBeFalsy()
- })
-
it('should render properties', () => {
expect(f.render()).toEqual(tFunc('bar'))
})
diff --git a/web/src/js/components/FlowTable.jsx b/web/src/js/components/FlowTable.jsx
index 24c1f3a1..a6381d0d 100644
--- a/web/src/js/components/FlowTable.jsx
+++ b/web/src/js/components/FlowTable.jsx
@@ -1,17 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
+import { connect } from 'react-redux'
import shallowEqual from 'shallowequal'
import AutoScroll from './helpers/AutoScroll'
import { calcVScroll } from './helpers/VirtualScroll'
import FlowTableHead from './FlowTable/FlowTableHead'
import FlowRow from './FlowTable/FlowRow'
import Filt from "../filt/filt"
+import * as flowsActions from '../ducks/flows'
+
class FlowTable extends React.Component {
static propTypes = {
- onSelect: PropTypes.func.isRequired,
+ selectFlow: PropTypes.func.isRequired,
flows: PropTypes.array.isRequired,
rowHeight: PropTypes.number,
highlight: PropTypes.string,
@@ -107,7 +110,7 @@ class FlowTable extends React.Component {
flow={flow}
selected={flow === selected}
highlighted={isHighlighted(flow)}
- onSelect={this.props.onSelect}
+ onSelect={this.props.selectFlow}
/>
))}
<tr style={{ height: vScroll.paddingBottom }}></tr>
@@ -118,4 +121,15 @@ class FlowTable extends React.Component {
}
}
-export default AutoScroll(FlowTable)
+export const PureFlowTable = AutoScroll(FlowTable)
+
+export default connect(
+ state => ({
+ flows: state.flows.view,
+ highlight: state.flows.highlight,
+ selected: state.flows.byId[state.flows.selected[0]],
+ }),
+ {
+ selectFlow: flowsActions.select,
+ }
+)(PureFlowTable)
diff --git a/web/src/js/components/FlowView.jsx b/web/src/js/components/FlowView.jsx
index d03d681a..25e7bb9f 100644
--- a/web/src/js/components/FlowView.jsx
+++ b/web/src/js/components/FlowView.jsx
@@ -3,94 +3,47 @@ import { connect } from 'react-redux'
import _ from 'lodash'
import Nav from './FlowView/Nav'
-import { Request, Response, ErrorView as Error } from './FlowView/Messages'
+import { ErrorView as Error, Request, Response } from './FlowView/Messages'
import Details from './FlowView/Details'
-import Prompt from './Prompt'
import { selectTab } from '../ducks/ui/flow'
-class FlowView extends Component {
+export const allTabs = { Request, Response, Error, Details }
- static allTabs = { Request, Response, Error, Details }
+function FlowView({ flow, tabName, selectTab }) {
- constructor(props, context) {
- super(props, context)
- this.onPromptFinish = this.onPromptFinish.bind(this)
- }
+ // only display available tab names
+ const tabs = ['request', 'response', 'error'].filter(k => flow[k])
+ tabs.push("details")
- onPromptFinish(edit) {
- this.props.setPrompt(false)
- if (edit && this.tabComponent) {
- this.tabComponent.edit(edit)
+ if (tabs.indexOf(tabName) < 0) {
+ if (tabName === 'response' && flow.error) {
+ tabName = 'error'
+ } else if (tabName === 'error' && flow.response) {
+ tabName = 'response'
+ } else {
+ tabName = tabs[0]
}
}
- getPromptOptions() {
- switch (this.props.tab) {
-
- case 'request':
- return [
- 'method',
- 'url',
- { text: 'http version', key: 'v' },
- 'header'
- ]
- break
-
- case 'response':
- return [
- { text: 'http version', key: 'v' },
- 'code',
- 'message',
- 'header'
- ]
- break
-
- case 'details':
- return
-
- default:
- throw 'Unknown tab for edit: ' + this.props.tab
- }
- }
-
- render() {
- let { flow, tab: active, updateFlow } = this.props
- const tabs = ['request', 'response', 'error'].filter(k => flow[k]).concat(['details'])
-
- if (tabs.indexOf(active) < 0) {
- if (active === 'response' && flow.error) {
- active = 'error'
- } else if (active === 'error' && flow.response) {
- active = 'response'
- } else {
- active = tabs[0]
- }
- }
-
- const Tab = FlowView.allTabs[_.capitalize(active)]
-
- return (
- <div className="flow-detail">
- <Nav
- flow={flow}
- tabs={tabs}
- active={active}
- onSelectTab={this.props.selectTab}
- />
- <Tab ref={ tab => this.tabComponent = tab } flow={flow} updateFlow={updateFlow} />
- {this.props.promptOpen && (
- <Prompt options={this.getPromptOptions()} done={this.onPromptFinish} />
- )}
- </div>
- )
- }
+ const Tab = allTabs[_.capitalize(tabName)]
+
+ return (
+ <div className="flow-detail">
+ <Nav
+ tabs={tabs}
+ active={tabName}
+ onSelectTab={selectTab}
+ />
+ <Tab flow={flow}/>
+ </div>
+ )
}
export default connect(
state => ({
- promptOpen: state.ui.promptOpen,
- tab: state.ui.flow.tab
+ flow: state.flows.byId[state.flows.selected[0]],
+ tabName: state.ui.flow.tab,
}),
{
selectTab,
diff --git a/web/src/js/components/FlowView/Messages.jsx b/web/src/js/components/FlowView/Messages.jsx
index b69dfb69..c1af36c5 100644
--- a/web/src/js/components/FlowView/Messages.jsx
+++ b/web/src/js/components/FlowView/Messages.jsx
@@ -120,30 +120,6 @@ export class Request extends Component {
</section>
)
}
-
-
- edit(k) {
- throw "unimplemented"
- /*
- switch (k) {
- case 'm':
- this.refs.requestLine.refs.method.focus()
- break
- case 'u':
- this.refs.requestLine.refs.url.focus()
- break
- case 'v':
- this.refs.requestLine.refs.httpVersion.focus()
- break
- case 'h':
- this.refs.headers.edit()
- break
- default:
- throw new Error(`Unimplemented: ${k}`)
- }
- */
- }
-
}
Request = Message(Request)
@@ -189,28 +165,6 @@ export class Response extends Component {
</section>
)
}
-
- edit(k) {
- throw "unimplemented"
- /*
- switch (k) {
- case 'c':
- this.refs.responseLine.refs.status_code.focus()
- break
- case 'm':
- this.refs.responseLine.refs.msg.focus()
- break
- case 'v':
- this.refs.responseLine.refs.httpVersion.focus()
- break
- case 'h':
- this.refs.headers.edit()
- break
- default:
- throw new Error(`'Unimplemented: ${k}`)
- }
- */
- }
}
Response = Message(Response)
diff --git a/web/src/js/components/Header/FileMenu.jsx b/web/src/js/components/Header/FileMenu.jsx
index 5cb8e507..c88efcd8 100644
--- a/web/src/js/components/Header/FileMenu.jsx
+++ b/web/src/js/components/Header/FileMenu.jsx
@@ -11,7 +11,6 @@ FileMenu.propTypes = {
clearFlows: PropTypes.func.isRequired,
loadFlows: PropTypes.func.isRequired,
saveFlows: PropTypes.func.isRequired,
- openModal: PropTypes.func.isRequired,
}
FileMenu.onNewClick = (e, clearFlows) => {
@@ -20,7 +19,7 @@ FileMenu.onNewClick = (e, clearFlows) => {
clearFlows()
}
-export function FileMenu ({clearFlows, loadFlows, saveFlows, openModal}) {
+export function FileMenu ({clearFlows, loadFlows, saveFlows}) {
return (
<Dropdown className="pull-left" btnClass="special" text="mitmproxy">
<a href="#" onClick={e => FileMenu.onNewClick(e, clearFlows)}>
@@ -38,12 +37,7 @@ export function FileMenu ({clearFlows, loadFlows, saveFlows, openModal}) {
</a>
<HideInStatic>
- <a href="#" onClick={e => { e.preventDefault(); openModal(); }}>
- <i className="fa fa-fw fa-cog"></i>
- &nbsp;Options
- </a>
<Divider/>
-
<a href="http://mitm.it/" target="_blank">
<i className="fa fa-fw fa-external-link"></i>
&nbsp;Install Certificates...
@@ -59,6 +53,5 @@ export default connect(
clearFlows: flowsActions.clear,
loadFlows: flowsActions.upload,
saveFlows: flowsActions.download,
- openModal: () => modalActions.setActiveModal('OptionModal'),
}
)(FileMenu)
diff --git a/web/src/js/components/Header/OptionMenu.jsx b/web/src/js/components/Header/OptionMenu.jsx
index c41c9d99..765129ed 100644
--- a/web/src/js/components/Header/OptionMenu.jsx
+++ b/web/src/js/components/Header/OptionMenu.jsx
@@ -1,74 +1,56 @@
-import React from "react"
-import PropTypes from 'prop-types'
+import React from "react"
import { connect } from "react-redux"
-import { SettingsToggle, EventlogToggle } from "./MenuToggle"
+import { EventlogToggle, SettingsToggle } from "./MenuToggle"
+import Button from "../common/Button"
import DocsLink from "../common/DocsLink"
import HideInStatic from "../common/HideInStatic";
+import * as modalActions from "../../ducks/ui/modal"
OptionMenu.title = 'Options'
-export default function OptionMenu() {
+function OptionMenu({ openOptions }) {
return (
<div>
<HideInStatic>
- <div className="menu-group">
- <div className="menu-content">
- <SettingsToggle setting="http2">HTTP/2.0</SettingsToggle>
- <SettingsToggle setting="websocket">WebSockets</SettingsToggle>
- <SettingsToggle setting="rawtcp">Raw TCP</SettingsToggle>
+ <div className="menu-group">
+ <div className="menu-content">
+ <Button title="Open Options" icon="fa-cogs text-primary"
+ onClick={openOptions}>
+ Edit Options <sup>alpha</sup>
+ </Button>
+ </div>
+ <div className="menu-legend">Options Editor</div>
</div>
- <div className="menu-legend">Protocol Support</div>
- </div>
- <div className="menu-group">
- <div className="menu-content">
- <SettingsToggle setting="anticache">
- Disable Caching <DocsLink resource="features/anticache.html"/>
- </SettingsToggle>
- <SettingsToggle setting="anticomp">
- Disable Compression <i className="fa fa-question-circle"
- title="Do not forward Accept-Encoding headers to the server to force an uncompressed response."></i>
- </SettingsToggle>
+ <div className="menu-group">
+ <div className="menu-content">
+ <SettingsToggle setting="anticache">
+ Strip cache headers <DocsLink resource="features/anticache.html"/>
+ </SettingsToggle>
+ <SettingsToggle setting="showhost">
+ Use host header for display
+ </SettingsToggle>
+ <SettingsToggle setting="ssl_insecure">
+ Verify server certificates
+ </SettingsToggle>
+ </div>
+ <div className="menu-legend">Quick Options</div>
</div>
- <div className="menu-legend">HTTP Options</div>
- </div>
</HideInStatic>
<div className="menu-group">
<div className="menu-content">
- <HideInStatic>
- <SettingsToggle setting="showhost">
- Use Host Header <i className="fa fa-question-circle"
- title="Use the Host header to construct URLs for display."></i>
- </SettingsToggle>
- </HideInStatic>
-
<EventlogToggle/>
</div>
<div className="menu-legend">View Options</div>
</div>
- { /*
- <ToggleButton text="no_upstream_cert"
- checked={settings.no_upstream_cert}
- onToggle={() => updateSettings({ no_upstream_cert: !settings.no_upstream_cert })}
- />
- <ToggleInputButton name="stickyauth" placeholder="Sticky auth filter"
- checked={!!settings.stickyauth}
- txt={settings.stickyauth}
- onToggleChanged={txt => updateSettings({ stickyauth: !settings.stickyauth ? txt : null })}
- />
- <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter"
- checked={!!settings.stickycookie}
- txt={settings.stickycookie}
- onToggleChanged={txt => updateSettings({ stickycookie: !settings.stickycookie ? txt : null })}
- />
- <ToggleInputButton name="stream_large_bodies" placeholder="stream..."
- checked={!!settings.stream_large_bodies}
- txt={settings.stream_large_bodies}
- inputType="number"
- onToggleChanged={txt => updateSettings({ stream_large_bodies: !settings.stream_large_bodies ? txt : null })}
- />
- */}
</div>
)
}
+
+export default connect(
+ null,
+ {
+ openOptions: () => modalActions.setActiveModal('OptionModal')
+ }
+)(OptionMenu)
diff --git a/web/src/js/components/MainView.jsx b/web/src/js/components/MainView.jsx
index e2bedc88..03bfce7f 100644
--- a/web/src/js/components/MainView.jsx
+++ b/web/src/js/components/MainView.jsx
@@ -1,54 +1,27 @@
-import React, { Component } from 'react'
+import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Splitter from './common/Splitter'
import FlowTable from './FlowTable'
import FlowView from './FlowView'
-import * as flowsActions from '../ducks/flows'
-class MainView extends Component {
-
- static propTypes = {
- highlight: PropTypes.string,
- sort: PropTypes.object,
- }
+MainView.propTypes = {
+ hasSelection: PropTypes.bool.isRequired,
+}
- render() {
- const { flows, selectedFlow, highlight } = this.props
- return (
- <div className="main-view">
- <FlowTable
- ref="flowTable"
- flows={flows}
- selected={selectedFlow}
- highlight={highlight}
- onSelect={this.props.selectFlow}
- />
- {selectedFlow && [
- <Splitter key="splitter"/>,
- <FlowView
- key="flowDetails"
- ref="flowDetails"
- tab={this.props.tab}
- updateFlow={data => this.props.updateFlow(selectedFlow, data)}
- flow={selectedFlow}
- />
- ]}
- </div>
- )
- }
+function MainView({ hasSelection }) {
+ return (
+ <div className="main-view">
+ <FlowTable/>
+ {hasSelection && <Splitter key="splitter"/>}
+ {hasSelection && <FlowView key="flowDetails"/>}
+ </div>
+ )
}
export default connect(
state => ({
- flows: state.flows.view,
- filter: state.flows.filter,
- highlight: state.flows.highlight,
- selectedFlow: state.flows.byId[state.flows.selected[0]],
- tab: state.ui.flow.tab,
+ hasSelection: !!state.flows.byId[state.flows.selected[0]]
}),
- {
- selectFlow: flowsActions.select,
- updateFlow: flowsActions.update,
- }
+ {}
)(MainView)
diff --git a/web/src/js/components/Modal/OptionModal.jsx b/web/src/js/components/Modal/OptionModal.jsx
index 82ef8350..fed0048d 100644
--- a/web/src/js/components/Modal/OptionModal.jsx
+++ b/web/src/js/components/Modal/OptionModal.jsx
@@ -53,7 +53,7 @@ class PureOptionModal extends Component {
}
componentWillUnmount(){
- this.props.save()
+ // this.props.save()
}
render() {
diff --git a/web/src/js/components/Prompt.jsx b/web/src/js/components/Prompt.jsx
deleted file mode 100755
index 77b07027..00000000
--- a/web/src/js/components/Prompt.jsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import ReactDOM from 'react-dom'
-import _ from 'lodash'
-
-import {Key} from '../utils.js'
-
-Prompt.propTypes = {
- options: PropTypes.array.isRequired,
- done: PropTypes.func.isRequired,
- prompt: PropTypes.string,
-}
-
-export default function Prompt({ prompt, done, options }) {
- const opts = []
-
- for (let i = 0; i < options.length; i++) {
- let opt = options[i]
- if (_.isString(opt)) {
- let str = opt
- while (str.length > 0 && keyTaken(str[0])) {
- str = str.substr(1)
- }
- opt = { text: opt, key: str[0] }
- }
- if (!opt.text || !opt.key || keyTaken(opt.key)) {
- throw 'invalid options'
- }
- opts.push(opt)
- }
-
- function keyTaken(k) {
- return _.map(opts, 'key').includes(k)
- }
-
- function onKeyDown(event) {
- event.stopPropagation()
- event.preventDefault()
- const key = opts.find(opt => Key[opt.key.toUpperCase()] === event.keyCode)
- if (!key && event.keyCode !== Key.ESC && event.keyCode !== Key.ENTER) {
- return
- }
- done(key.key || false)
- }
-
- return (
- <div tabIndex="0" onKeyDown={onKeyDown} className="prompt-dialog">
- <div className="prompt-content">
- {prompt || <strong>Select: </strong> }
- {opts.map(opt => {
- const idx = opt.text.indexOf(opt.key)
- function onClick(event) {
- done(opt.key)
- event.stopPropagation()
- }
- return (
- <span key={opt.key} className="option" onClick={onClick}>
- {idx !== -1 ? opt.text.substring(0, idx) : opt.text + '('}
- <strong className="text-primary">{opt.key}</strong>
- {idx !== -1 ? opt.text.substring(idx + 1) : ')'}
- </span>
- )
- })}
- </div>
- </div>
- )
-}
diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx
index 8c3970bc..15384e02 100644
--- a/web/src/js/components/ProxyApp.jsx
+++ b/web/src/js/components/ProxyApp.jsx
@@ -20,7 +20,7 @@ class ProxyAppMain extends Component {
}
render() {
- const { showEventLog, location, filter, highlight } = this.props
+ const { showEventLog } = this.props
return (
<div id="container" tabIndex="0">
<Header/>
diff --git a/web/src/js/components/common/Button.jsx b/web/src/js/components/common/Button.jsx
index e02ae010..02dab305 100644
--- a/web/src/js/components/common/Button.jsx
+++ b/web/src/js/components/common/Button.jsx
@@ -12,7 +12,7 @@ Button.propTypes = {
export default function Button({ onClick, children, icon, disabled, className, title }) {
return (
<div className={classnames(className, 'btn btn-default')}
- onClick={!disabled && onClick}
+ onClick={disabled ? undefined : onClick}
disabled={disabled}
title={title}>
{icon && (<i className={"fa fa-fw " + icon}/> )}
diff --git a/web/src/js/utils.js b/web/src/js/utils.js
index 7c1719ae..80f0c42a 100644
--- a/web/src/js/utils.js
+++ b/web/src/js/utils.js
@@ -1,6 +1,5 @@
import _ from 'lodash'
import React from 'react'
-import shallowEqual from 'shallowequal'
window._ = _;
window.React = React;
@@ -126,13 +125,9 @@ export function getDiff(obj1, obj2) {
return result
}
-export const pure = renderFn => class extends React.Component {
+export const pure = renderFn => class extends React.PureComponent {
static displayName = renderFn.name
- shouldComponentUpdate(nextProps) {
- return !shallowEqual(this.props, nextProps)
- }
-
render() {
return renderFn(this.props)
}