web: integrate filter docs

This commit is contained in:
Maximilian Hils 2014-12-26 03:10:24 +01:00
parent 1f454b577f
commit 3e63107e94
7 changed files with 174 additions and 54 deletions

View File

@ -40,29 +40,7 @@ def example(s):
ns.example = example
filt_help = []
for i in filt.filt_unary:
filt_help.append(
("~%s"%i.code, i.help)
)
for i in filt.filt_rex:
filt_help.append(
("~%s regex"%i.code, i.help)
)
for i in filt.filt_int:
filt_help.append(
("~%s int"%i.code, i.help)
)
filt_help.sort()
filt_help.extend(
[
("!", "unary not"),
("&", "and"),
("|", "or"),
("(...)", "grouping"),
]
)
ns.filt_help = filt_help
ns.filt_help = filt.help
def nav(page, current, state):

View File

@ -351,3 +351,26 @@ def parse(s):
except ValueError:
return None
help = []
for i in filt_unary:
help.append(
("~%s"%i.code, i.help)
)
for i in filt_rex:
help.append(
("~%s regex"%i.code, i.help)
)
for i in filt_int:
help.append(
("~%s int"%i.code, i.help)
)
help.sort()
help.extend(
[
("!", "unary not"),
("&", "and"),
("|", "or"),
("(...)", "grouping"),
]
)

View File

@ -4,7 +4,7 @@ import tornado.web
import tornado.websocket
import logging
import json
from .. import version
from .. import version, filt
class APIError(tornado.web.HTTPError):
@ -52,6 +52,12 @@ class IndexHandler(RequestHandler):
self.render("index.html")
class FiltHelp(RequestHandler):
def get(self):
self.write(dict(
commands=filt.help
))
class WebSocketEventBroadcaster(tornado.websocket.WebSocketHandler):
connections = None # raise an error if inherited class doesn't specify its own instance.
@ -194,6 +200,7 @@ class Application(tornado.web.Application):
self.master = master
handlers = [
(r"/", IndexHandler),
(r"/filter-help", FiltHelp),
(r"/updates", ClientConnection),
(r"/events", Events),
(r"/flows", Flows),

View File

@ -138,10 +138,30 @@ header .menu {
padding: 10px;
border-bottom: solid #a6a6a6 1px;
}
.menu-row {
margin-left: -2.5px;
margin-right: -2.5px;
}
.filter-input {
position: relative;
min-height: 1px;
padding-left: 2.5px;
padding-right: 2.5px;
}
@media (min-width: 992px) {
.filter-input {
float: left;
width: 25%;
}
}
.filter-input .popover {
top: 27px;
display: block;
width: 100%;
max-width: none;
}
.filter-input .popover .popover-content {
max-height: 500px;
overflow-y: auto;
}
.flow-table {
width: 100%;

View File

@ -2632,6 +2632,48 @@ var VirtualScrollMixin = {
}
},
};
var FilterDocs = React.createClass({displayName: 'FilterDocs',
statics: {
xhr: false,
doc: false
},
componentWillMount: function () {
if (!FilterDocs.doc) {
FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
FilterDocs.doc = doc;
FilterDocs.xhr = false;
});
}
if (FilterDocs.xhr) {
FilterDocs.xhr.done(function () {
this.forceUpdate();
}.bind(this));
}
},
render: function () {
if (!FilterDocs.doc) {
return React.createElement("i", {className: "fa fa-spinner fa-spin"});
} else {
var commands = FilterDocs.doc.commands.map(function (c) {
return React.createElement("tr", null,
React.createElement("td", null, c[0].replace(" ", '\u00a0')),
React.createElement("td", null, c[1])
);
});
commands.push(React.createElement("tr", null,
React.createElement("td", {colSpan: "2"},
React.createElement("a", {href: "https://mitmproxy.org/doc/features/filters.html",
target: "_blank"},
React.createElement("i", {className: "fa fa-external-link"}),
"  mitmproxy docs")
)
));
return React.createElement("table", {className: "table table-condensed"},
React.createElement("tbody", null, commands)
);
}
}
});
var FilterInput = React.createClass({displayName: 'FilterInput',
getInitialState: function () {
// Consider both focus and mouseover for showing/hiding the tooltip,
@ -2675,10 +2717,7 @@ var FilterInput = React.createClass({displayName: 'FilterInput',
return desc;
} else {
return (
React.createElement("a", {href: "https://mitmproxy.org/doc/features/filters.html", target: "_blank"},
React.createElement("i", {className: "fa fa-external-link"}),
"Filter Documentation"
)
React.createElement(FilterDocs, null)
);
}
},
@ -2768,28 +2807,27 @@ var MainMenu = React.createClass({displayName: 'MainMenu',
return (
React.createElement("div", null,
React.createElement("form", {className: "form-inline", style: {display: "inline"}},
React.createElement("div", {className: "menu-row"},
React.createElement(FilterInput, {
placeholder: "Filter",
type: "filter",
color: "black",
value: filter,
onChange: this.onFilterChange}),
React.createElement("span", null, " "),
React.createElement(FilterInput, {
placeholder: "Highlight",
type: "tag",
color: "hsl(48, 100%, 50%)",
value: highlight,
onChange: this.onHighlightChange}),
React.createElement("span", null, " "),
React.createElement(FilterInput, {
placeholder: "Intercept",
type: "pause",
color: "hsl(208, 56%, 53%)",
value: intercept,
onChange: this.onInterceptChange})
)
),
React.createElement("div", {className: "clearfix"})
)
);
}

View File

@ -1,21 +1,37 @@
@import (reference) '../../bower_components/bootstrap/less/variables.less';
@import (reference) '../../bower_components/bootstrap/less/mixins/grid.less';
header {
background-color: white;
background-color: white;
.title-bar {
line-height: 25px;
text-align: center;
}
.title-bar {
line-height: 25px;
text-align: center;
}
@separator-color: lighten(grey, 15%);
@separator-color: lighten(grey, 15%);
.menu {
padding: 10px;
border-bottom: solid @separator-color 1px;
}
.menu {
padding: 10px;
border-bottom: solid @separator-color 1px;
}
}
@menu-row-gutter-width: 5px;
.menu-row {
.make-row(@menu-row-gutter-width);
}
.filter-input {
.make-md-column(3, @menu-row-gutter-width);
}
.filter-input .popover {
top: 27px;
display: block;
width: 100%;
top: 27px;
display: block;
max-width: none;
.popover-content {
max-height: 500px;
overflow-y: auto;
}
}

View File

@ -1,3 +1,45 @@
var FilterDocs = React.createClass({
statics: {
xhr: false,
doc: false
},
componentWillMount: function () {
if (!FilterDocs.doc) {
FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
FilterDocs.doc = doc;
FilterDocs.xhr = false;
});
}
if (FilterDocs.xhr) {
FilterDocs.xhr.done(function () {
this.forceUpdate();
}.bind(this));
}
},
render: function () {
if (!FilterDocs.doc) {
return <i className="fa fa-spinner fa-spin"></i>;
} else {
var commands = FilterDocs.doc.commands.map(function (c) {
return <tr>
<td>{c[0].replace(" ", '\u00a0')}</td>
<td>{c[1]}</td>
</tr>;
});
commands.push(<tr>
<td colSpan="2">
<a href="https://mitmproxy.org/doc/features/filters.html"
target="_blank">
<i className="fa fa-external-link"></i>
&nbsp; mitmproxy docs</a>
</td>
</tr>);
return <table className="table table-condensed">
<tbody>{commands}</tbody>
</table>;
}
}
});
var FilterInput = React.createClass({
getInitialState: function () {
// Consider both focus and mouseover for showing/hiding the tooltip,
@ -41,10 +83,7 @@ var FilterInput = React.createClass({
return desc;
} else {
return (
<a href="https://mitmproxy.org/doc/features/filters.html" target="_blank">
<i className="fa fa-external-link"></i>
Filter Documentation
</a>
<FilterDocs/>
);
}
},
@ -134,28 +173,27 @@ var MainMenu = React.createClass({
return (
<div>
<form className="form-inline" style={{display: "inline"}}>
<div className="menu-row">
<FilterInput
placeholder="Filter"
type="filter"
color="black"
value={filter}
onChange={this.onFilterChange} />
<span> </span>
<FilterInput
placeholder="Highlight"
type="tag"
color="hsl(48, 100%, 50%)"
value={highlight}
onChange={this.onHighlightChange}/>
<span> </span>
<FilterInput
placeholder="Intercept"
type="pause"
color="hsl(208, 56%, 53%)"
value={intercept}
onChange={this.onInterceptChange}/>
</form>
</div>
<div className="clearfix"></div>
</div>
);
}