aboutsummaryrefslogtreecommitdiffstats
path: root/web/src
diff options
context:
space:
mode:
Diffstat (limited to 'web/src')
-rw-r--r--web/src/css/flowtable.less153
-rw-r--r--web/src/css/tabs.less6
-rw-r--r--web/src/js/components/flowdetail.jsx.js79
-rw-r--r--web/src/js/components/flowtable-columns.jsx.js6
-rw-r--r--web/src/js/components/header.jsx.js103
-rw-r--r--web/src/js/components/mainview.jsx.js13
6 files changed, 235 insertions, 125 deletions
diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less
index 38f5e0e8..9988f1a8 100644
--- a/web/src/css/flowtable.less
+++ b/web/src/css/flowtable.less
@@ -1,78 +1,95 @@
.flow-table {
- width: 100%;
- overflow: auto;
+ width: 100%;
+ overflow: auto;
- table {
- width: 100%;
- table-layout: fixed;
- }
+ table {
+ width: 100%;
+ table-layout: fixed;
+ }
- thead {
- background-color: #F2F2F2;
- line-height: 23px;
- }
+ thead {
+ background-color: #F2F2F2;
+ line-height: 23px;
+ }
- th {
- font-weight: normal;
- box-shadow: 0 1px 0 #a6a6a6;
- }
+ th {
+ font-weight: normal;
+ box-shadow: 0 1px 0 #a6a6a6;
+ }
- tr {
- cursor: pointer;
+ tr {
+ cursor: pointer;
- &:nth-child(even) {
- background-color : rgba(0,0,0,0.05);
- }
- &.selected {
- background-color: hsla(209, 52%, 84%, 0.5) !important;
- }
- &.highlighted {
- background-color: hsla(48, 100%, 50%, 0.4);
- }
- &.highlighted:nth-child(even) {
- background-color: hsla(48, 100%, 50%, 0.5);
- }
- }
+ &:nth-child(even) {
+ background-color: rgba(0, 0, 0, 0.05);
+ }
+ &.selected {
+ background-color: hsla(209, 52%, 84%, 0.5) !important;
+ }
+ &.highlighted {
+ background-color: hsla(48, 100%, 50%, 0.4);
+ }
+ &.highlighted:nth-child(even) {
+ background-color: hsla(48, 100%, 50%, 0.5);
+ }
+ }
- td {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
+ td {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
- tr.intercepted:not(.has-response) {
- .col-path, .col-method {
- color: hsl(30, 100%, 50%);
- }
- }
- tr.intercepted.has-response {
- .col-status, .col-size, .col-time {
- color: hsl(30, 100%, 50%);
- }
- }
+ @interceptorange: hsl(30, 100%, 50%);
- .col-tls {
- width: 10px;
- }
- .col-tls-https {
- background-color: rgba(0, 185, 0, 0.5);
- }
- .col-icon {
- width: 32px;
- }
- .col-method {
- width: 60px;
- }
- .col-status {
- width: 50px;
- }
- .col-size {
- width: 70px;
- }
- .col-time {
- width: 50px;
- }
- td.col-time, td.col-size {
- text-align: right;
- }
+ tr.intercepted:not(.has-response) {
+ .col-path, .col-method {
+ color: @interceptorange;
+ }
+ }
+ tr.intercepted.has-response {
+ .col-status, .col-size, .col-time {
+ color: @interceptorange;
+ }
+ }
+
+ .fa {
+ line-height: inherit;
+ &.pull-right {
+ margin-left: 0;
+ }
+ }
+
+ .col-tls {
+ width: 10px;
+ }
+ .col-tls-https {
+ background-color: rgba(0, 185, 0, 0.5);
+ }
+ .col-icon {
+ width: 32px;
+ }
+ .col-path {
+ .fa-repeat {
+ color: green;
+ }
+ .fa-pause {
+ color: @interceptorange;
+ }
+ }
+ .col-method {
+ width: 60px;
+ }
+ .col-status {
+ width: 50px;
+ }
+ .col-size {
+ width: 70px;
+ }
+ .col-time {
+ width: 50px;
+ }
+ td.col-time, td.col-size {
+ text-align: right;
+ }
} \ No newline at end of file
diff --git a/web/src/css/tabs.less b/web/src/css/tabs.less
index 36bc5b68..43f7264e 100644
--- a/web/src/css/tabs.less
+++ b/web/src/css/tabs.less
@@ -40,6 +40,10 @@
a {
padding: 0px 7px;
margin: 2px 2px -1px;
-
+ }
+ a.nav-action {
+ float: right;
+ padding: 0;
+ margin: 1px 0 0px;
}
} \ No newline at end of file
diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js
index 5727ec75..dfc0099e 100644
--- a/web/src/js/components/flowdetail.jsx.js
+++ b/web/src/js/components/flowdetail.jsx.js
@@ -1,7 +1,72 @@
+var DeleteButton = React.createClass({
+ onClick: function (e) {
+ e.preventDefault();
+ FlowActions.delete(this.props.flow);
+ },
+ render: function () {
+ return (
+ <a title="[d]elete Flow"
+ href="#"
+ className="nav-action"
+ onClick={this.onClick}>
+ <i className="fa fa-fw fa-trash"></i>
+ </a>
+ );
+ }
+});
+var DuplicateButton = React.createClass({
+ onClick: function (e) {
+ e.preventDefault();
+ FlowActions.duplicate(this.props.flow);
+ },
+ render: function () {
+ return (
+ <a title="[D]uplicate Flow"
+ href="#"
+ className="nav-action"
+ onClick={this.onClick}>
+ <i className="fa fa-fw fa-edit"></i>
+ </a>
+ );
+ }
+});
+var ReplayButton = React.createClass({
+ onClick: function (e) {
+ e.preventDefault();
+ FlowActions.replay(this.props.flow);
+ },
+ render: function () {
+ return (
+ <a title="[r]eplay Flow"
+ href="#"
+ className="nav-action"
+ onClick={this.onClick}>
+ <i className="fa fa-fw fa-close"></i>
+ </a>
+ );
+ }
+});
+var AcceptButton = React.createClass({
+ onClick: function (e) {
+ e.preventDefault();
+ FlowActions.accept(this.props.flow);
+ },
+ render: function () {
+ return (
+ <a title="[a]ccept (resume) Flow"
+ href="#"
+ className="nav-action"
+ onClick={this.onClick}>
+ <i className="fa fa-fw fa-play"></i>
+ </a>
+ );
+ }
+});
var FlowDetailNav = React.createClass({
render: function () {
+ var flow = this.props.flow;
- var items = this.props.tabs.map(function (e) {
+ var tabs = this.props.tabs.map(function (e) {
var str = e.charAt(0).toUpperCase() + e.slice(1);
var className = this.props.active === e ? "active" : "";
var onClick = function (event) {
@@ -13,9 +78,14 @@ var FlowDetailNav = React.createClass({
className={className}
onClick={onClick}>{str}</a>;
}.bind(this));
+
return (
<nav ref="head" className="nav-tabs nav-tabs-sm">
- {items}
+ {tabs}
+ <DeleteButton flow={flow}/>
+ <DuplicateButton flow={flow}/>
+ <ReplayButton flow={flow}/>
+ { flow.intercepted ? <AcceptButton flow={this.props.flow}/> : null }
</nav>
);
}
@@ -104,7 +174,9 @@ var FlowDetailError = React.createClass({
<section>
<div className="alert alert-warning">
{flow.error.msg}
- <div><small>{ formatTimeStamp(flow.error.timestamp) }</small></div>
+ <div>
+ <small>{ formatTimeStamp(flow.error.timestamp) }</small>
+ </div>
</div>
</section>
);
@@ -341,6 +413,7 @@ var FlowDetail = React.createClass({
return (
<div className="flow-detail" onScroll={this.adjustHead}>
<FlowDetailNav ref="head"
+ flow={flow}
tabs={tabs}
active={active}
selectTab={this.selectTab}/>
diff --git a/web/src/js/components/flowtable-columns.jsx.js b/web/src/js/components/flowtable-columns.jsx.js
index 1aa256c4..9162e077 100644
--- a/web/src/js/components/flowtable-columns.jsx.js
+++ b/web/src/js/components/flowtable-columns.jsx.js
@@ -66,7 +66,11 @@ var PathColumn = React.createClass({
},
render: function () {
var flow = this.props.flow;
- return <td className="col-path">{flow.request.scheme + "://" + flow.request.host + flow.request.path}</td>;
+ return <td className="col-path">
+ {flow.request.is_replay ? <i className="fa fa-fw fa-repeat pull-right"></i> : null}
+ {flow.intercepted ? <i className="fa fa-fw fa-pause pull-right"></i> : null}
+ {flow.request.scheme + "://" + flow.request.host + flow.request.path}
+ </td>;
}
});
diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js
index 9e6b8f2f..e1016950 100644
--- a/web/src/js/components/header.jsx.js
+++ b/web/src/js/components/header.jsx.js
@@ -111,23 +111,9 @@ var FilterInput = React.createClass({
var MainMenu = React.createClass({
mixins: [Navigation, State],
statics: {
- title: "Traffic",
+ title: "Start",
route: "flows"
},
- toggleEventLog: function () {
- var d = {};
-
- if(this.getQuery()[Query.SHOW_EVENTLOG]){
- d[Query.SHOW_EVENTLOG] = undefined;
- } else {
- d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
- }
-
- this.setQuery(d);
- },
- clearFlows: function () {
- FlowActions.clear();
- },
onFilterChange: function (val) {
var d = {};
d[Query.FILTER] = val;
@@ -145,22 +131,9 @@ var MainMenu = React.createClass({
var filter = this.getQuery()[Query.FILTER] || "";
var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
var intercept = this.props.settings.intercept || "";
- var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
return (
<div>
- <button
- className={"btn " + (showEventLog ? "btn-primary" : "btn-default")}
- onClick={this.toggleEventLog}>
- <i className="fa fa-database"></i>
- &nbsp;Display Event Log
- </button>
- <span> </span>
- <button className="btn btn-default" onClick={this.clearFlows}>
- <i className="fa fa-eraser"></i>
- &nbsp;Clear Flows
- </button>
- <span> </span>
<form className="form-inline" style={{display: "inline"}}>
<FilterInput
placeholder="Filter"
@@ -189,13 +162,36 @@ var MainMenu = React.createClass({
});
-var ToolsMenu = React.createClass({
+var ViewMenu = React.createClass({
statics: {
- title: "Tools",
+ title: "View",
route: "flows"
},
+ mixins: [Navigation, State],
+ toggleEventLog: function () {
+ var d = {};
+
+ if (this.getQuery()[Query.SHOW_EVENTLOG]) {
+ d[Query.SHOW_EVENTLOG] = undefined;
+ } else {
+ d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
+ }
+
+ this.setQuery(d);
+ },
render: function () {
- return <div>Tools Menu</div>;
+ var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
+ return (
+ <div>
+ <button
+ className={"btn " + (showEventLog ? "btn-primary" : "btn-default")}
+ onClick={this.toggleEventLog}>
+ <i className="fa fa-database"></i>
+ &nbsp;Show Eventlog
+ </button>
+ <span> </span>
+ </div>
+ );
}
});
@@ -232,7 +228,9 @@ var FileMenu = React.createClass({
},
handleNewClick: function (e) {
e.preventDefault();
- console.error("unimplemented: handleNewClick");
+ if (confirm("Delete all flows?")) {
+ FlowActions.clear();
+ }
},
handleOpenClick: function (e) {
e.preventDefault();
@@ -259,25 +257,34 @@ var FileMenu = React.createClass({
New
</a>
</li>
- <li>
- <a href="#" onClick={this.handleOpenClick}>
- <i className="fa fa-fw fa-folder-open"></i>
- Open
- </a>
- </li>
- <li>
- <a href="#" onClick={this.handleSaveClick}>
- <i className="fa fa-fw fa-save"></i>
- Save
- </a>
- </li>
<li role="presentation" className="divider"></li>
<li>
- <a href="#" onClick={this.handleShutdownClick}>
- <i className="fa fa-fw fa-plug"></i>
- Shutdown
+ <a href="http://mitm.it/" target="_blank">
+ <i className="fa fa-fw fa-lock"></i>
+ Install Certificates...
</a>
</li>
+ {/*
+ <li>
+ <a href="#" onClick={this.handleOpenClick}>
+ <i className="fa fa-fw fa-folder-open"></i>
+ Open
+ </a>
+ </li>
+ <li>
+ <a href="#" onClick={this.handleSaveClick}>
+ <i className="fa fa-fw fa-save"></i>
+ Save
+ </a>
+ </li>
+ <li role="presentation" className="divider"></li>
+ <li>
+ <a href="#" onClick={this.handleShutdownClick}>
+ <i className="fa fa-fw fa-plug"></i>
+ Shutdown
+ </a>
+ </li>
+ */}
</ul>
</div>
);
@@ -285,7 +292,7 @@ var FileMenu = React.createClass({
});
-var header_entries = [MainMenu, ToolsMenu, ReportsMenu];
+var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
var Header = React.createClass({
diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js
index 78415ad0..41f22a95 100644
--- a/web/src/js/components/mainview.jsx.js
+++ b/web/src/js/components/mainview.jsx.js
@@ -44,6 +44,7 @@ var MainView = React.createClass({
view.addListener("recalculate", this.onRecalculate);
view.addListener("add update remove", this.onUpdate);
+ view.addListener("remove", this.onRemove);
},
onRecalculate: function () {
this.forceUpdate();
@@ -57,6 +58,12 @@ var MainView = React.createClass({
this.forceUpdate();
}
},
+ onRemove: function (flow_id, index) {
+ if (flow_id === this.getParams().flowId) {
+ var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length -1)];
+ this.selectFlow(flow_to_select);
+ }
+ },
closeView: function () {
this.state.view.close();
},
@@ -106,7 +113,7 @@ var MainView = React.createClass({
},
onKeyDown: function (e) {
var flow = this.getSelected();
- if(e.ctrlKey){
+ if (e.ctrlKey) {
return;
}
switch (e.keyCode) {
@@ -157,8 +164,6 @@ var MainView = React.createClass({
if (e.shiftKey) {
FlowActions.duplicate(flow);
} else {
- var last_flow = this.state.view.index(flow) === this.state.view.list.length - 1;
- this.selectFlowRelative(last_flow ? -1 : +1);
FlowActions.delete(flow);
}
}
@@ -171,7 +176,7 @@ var MainView = React.createClass({
}
break;
case Key.R:
- if(!e.shiftKey && flow){
+ if (!e.shiftKey && flow) {
FlowActions.replay(flow);
}
break;