diff --git a/lib/rule_default.js b/lib/rule_default.js index 81515b4..287f3f6 100644 --- a/lib/rule_default.js +++ b/lib/rule_default.js @@ -113,6 +113,16 @@ module.exports = { }); cb(); + }, + + _getCustomMenu : function(){ + return [ + // { + // name:"test", + // icon:"uk-icon-lemon-o", + // url :"http://anyproxy.io" + // } + ]; } }; diff --git a/lib/webInterface.js b/lib/webInterface.js index a1f2002..629953c 100644 --- a/lib/webInterface.js +++ b/lib/webInterface.js @@ -8,6 +8,7 @@ var express = require("express"), util = require("./util"), certMgr = require("./certMgr"), logUtil = require("./log"), + juicer = require("juicer"), compress = require('compression'); @@ -16,10 +17,12 @@ function webInterface(config){ wsPort = config.wsPort, ipAddress = config.ip, userRule = config.userRule, - ruleSummary = ""; + ruleSummary = "", + customMenu = []; try{ ruleSummary = userRule.summary(); + customMenu = userRule._getCustomMenu(); }catch(e){} var self = this, @@ -88,15 +91,16 @@ function webInterface(config){ app.use(function(req,res,next){ var indexTpl = fs.readFileSync(path.join(staticDir,"/index.html"),{encoding:"utf8"}), - indexHTML = util.simpleRender(indexTpl, { - rule : ruleSummary || "", - wsPort : wsPort, - ipAddress : ipAddress || "127.0.0.1" - }); - + opt = { + rule : ruleSummary || "", + customMenu : customMenu || [], + wsPort : wsPort, + ipAddress : ipAddress || "127.0.0.1" + }; + if(req.url == "/"){ res.setHeader("Content-Type", "text/html"); - res.end(indexHTML); + res.end(juicer(indexTpl, opt)); }else{ next(); } diff --git a/web/build/filter.js b/web/build/filter.js index 54eeef1..08372c2 100644 --- a/web/build/filter.js +++ b/web/build/filter.js @@ -21,19 +21,14 @@ function init(React){ return ( React.createElement("div", null, React.createElement("h4", {className: "subTitle"}, "Log Filter"), - React.createElement("div", {className: "filterSection"}, React.createElement("form", {className: "uk-form"}, React.createElement("input", {className: "uk-form-large", ref: "keywordInput", onChange: self.dealChange, type: "text", placeholder: "keywords or /^regExp$/", width: "300"}) ) ), - React.createElement("dl", {className: "uk-description-list-horizontal"}, - React.createElement("dt", null, "wrap your RegExp between two slashes"), - React.createElement("dd", null, - "e.g. ", React.createElement("br", null), - "type ", React.createElement("strong", null, "/id=\\d", 3, "/"), " will give you all the logs containing ", React.createElement("strong", null, "id=123") - ) - ) + React.createElement("p", null, + React.createElement("i", {className: "uk-icon-gift"}), "  type ", React.createElement("strong", null, "/id=\\d", 3, "/"), " will give you all the logs containing ", React.createElement("strong", null, "id=123") + ) ) ); }, diff --git a/web/build/index.js b/web/build/index.js index 744772a..e8d5aca 100644 --- a/web/build/index.js +++ b/web/build/index.js @@ -88,18 +88,10 @@ var showPop; document.getElementById("J_popOuter") ); - showPop = function(tag,props,popArg){ - var tagEl = PopupContent[tag]; - if(!tagEl) throw new Error("element not found, please make sure your panel has been pluged"); - - var contentEl = React.createElement(tagEl, props); - var defaultPopPara = { - show : true, - content : contentEl - }; - - pop.setState(util_merge(defaultPopPara,popArg)); - } + showPop = function(popArg){ + var stateArg = util_merge({show : true },popArg); + pop.setState(stateArg); + }; })(); //init record panel @@ -137,7 +129,7 @@ var recorder; }); function showDetail(data){ - showPop("detail", {data:data}, {left:"35%"}); + showPop({left:"35%",content:React.createElement(PopupContent["detail"], {data:data})}); } //init recorder panel @@ -198,14 +190,29 @@ var recorder; } $(".J_showFilter").on("click",function(){ - showPop("filter", {onChangeKeyword : updateKeyword}, { left : "50%"}); + showPop({ left:"50%", content:React.createElement(PopupContent["filter"], {onChangeKeyword : updateKeyword})}); }); })(); //map local (function(){ $(".J_showMapPanel").on("click",function(){ - showPop("map", {}, {left : "40%"}); + showPop({left:"40%", content:React.createElement(PopupContent["map"],null)}); + }); + })(); + + //other button + (function(){ + $(".J_customButton").on("click",function(){ + var thisEl = $(this), + iframeUrl = thisEl.attr("iframeUrl"); + + if(!iframeUrl){ + throw new Error("cannot find the url assigned for this button"); + } + + var iframeEl = React.createElement("iframe",{src:iframeUrl,frameBorder:0}); + showPop({left:"35%", content: iframeEl }); }); })(); diff --git a/web/css/page.css b/web/css/page.css index 49ecb60..dee8af2 100644 --- a/web/css/page.css +++ b/web/css/page.css @@ -205,7 +205,7 @@ body, html { border-left: 1px solid #CCC; top: 0; padding: 10px 20px 10px 10px; - overflow-y:scroll; + overflow-y:auto; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -225,6 +225,12 @@ body, html { word-wrap: break-word; } +.recordDetailOverlay iframe{ + position: relative; + height: 92vh; + width: 100%; +} + .data_id{ color: #777; } diff --git a/web/index.html b/web/index.html index 001d880..482850f 100644 --- a/web/index.html +++ b/web/index.html @@ -2,6 +2,7 @@ AnyProxy + @@ -35,7 +36,15 @@ | - Rule : {{rule}} + + {@if customMenu.length} + {@each customMenu as item} + ${item.name} + {@/each} + | + {@/if} + + Rule : ${rule}
@@ -43,8 +52,8 @@
- - + + diff --git a/web/page.js b/web/page.js index 82ad8d8..f315915 100644 --- a/web/page.js +++ b/web/page.js @@ -52,11 +52,11 @@ var WsIndicator = __webpack_require__(6).init(React), RecordPanel = __webpack_require__(8).init(React), - Popup = __webpack_require__(9).init(React); + Popup = __webpack_require__(7).init(React); var PopupContent = { - map : __webpack_require__(7).init(React), - detail : __webpack_require__(1).init(React), + map : __webpack_require__(1).init(React), + detail : __webpack_require__(9).init(React), filter : __webpack_require__(10).init(React) }; @@ -134,18 +134,10 @@ document.getElementById("J_popOuter") ); - showPop = function(tag,props,popArg){ - var tagEl = PopupContent[tag]; - if(!tagEl) throw new Error("element not found, please make sure your panel has been pluged"); - - var contentEl = React.createElement(tagEl, props); - var defaultPopPara = { - show : true, - content : contentEl - }; - - pop.setState(util_merge(defaultPopPara,popArg)); - } + showPop = function(popArg){ + var stateArg = util_merge({show : true },popArg); + pop.setState(stateArg); + }; })(); //init record panel @@ -183,7 +175,7 @@ }); function showDetail(data){ - showPop("detail", {data:data}, {left:"35%"}); + showPop({left:"35%",content:React.createElement(PopupContent["detail"], {data:data})}); } //init recorder panel @@ -244,14 +236,29 @@ } $(".J_showFilter").on("click",function(){ - showPop("filter", {onChangeKeyword : updateKeyword}, { left : "50%"}); + showPop({ left:"50%", content:React.createElement(PopupContent["filter"], {onChangeKeyword : updateKeyword})}); }); })(); //map local (function(){ $(".J_showMapPanel").on("click",function(){ - showPop("map", {}, {left : "40%"}); + showPop({left:"40%", content:React.createElement(PopupContent["map"],null)}); + }); + })(); + + //other button + (function(){ + $(".J_customButton").on("click",function(){ + var thisEl = $(this), + iframeUrl = thisEl.attr("iframeUrl"); + + if(!iframeUrl){ + throw new Error("cannot find the url assigned for this button"); + } + + var iframeEl = React.createElement("iframe",{src:iframeUrl,frameBorder:0}); + showPop({left:"35%", content: iframeEl }); }); })(); @@ -261,107 +268,35 @@ /* 1 */ /***/ function(module, exports, __webpack_require__) { + __webpack_require__(12); + function init(React){ + var MapForm = __webpack_require__(13).init(React), + MapList = __webpack_require__(14).init(React); - var DetailPanel = React.createClass({displayName: "DetailPanel", - getInitialState : function(){ - return { - body : {id : -1, content : null}, - left : "35%" - }; + var MapPanel = React.createClass({displayName: "MapPanel", + appendRecord : function(data){ + var self = this, + listComponent = self.refs.list; + + listComponent.appendRecord(data); }, - loadBody:function(){ - var self = this, - id = self.props.data.id; - if(!id) return; - - ws.reqBody(id,function(content){ - if(content.id == self.props.data.id){ - self.setState({ - body : content - }); - } - }); - }, - render : function(){ - var reqHeaderSection = [], - resHeaderSection = [], - summarySection, - detailSection, - bodyContent; - - if(this.props.data.reqHeader){ - for(var key in this.props.data.reqHeader){ - reqHeaderSection.push(React.createElement("li", {key: "reqHeader_" + key}, React.createElement("strong", null, key), " : ", this.props.data.reqHeader[key])) - } - } - - summarySection = ( - React.createElement("div", null, - React.createElement("section", {className: "req"}, - React.createElement("h4", {className: "subTitle"}, "request"), - React.createElement("div", {className: "detail"}, - React.createElement("ul", {className: "uk-list"}, - React.createElement("li", null, this.props.data.method, " ", React.createElement("span", {title: "{this.props.data.path}"}, this.props.data.path), " HTTP/1.1"), - reqHeaderSection - ) - ) - ), - - React.createElement("section", {className: "reqBody"}, - React.createElement("h4", {className: "subTitle"}, "request body"), - React.createElement("div", {className: "detail"}, - React.createElement("p", null, this.props.data.reqBody) - ) - ) - ) - ); - - if(this.props.data.statusCode){ - - if(this.state.body.id == this.props.data.id){ - bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body)); - }else{ - bodyContent = null; - this.loadBody(); - } - - if(this.props.data.resHeader){ - for(var key in this.props.data.resHeader){ - resHeaderSection.push(React.createElement("li", {key: "resHeader_" + key}, React.createElement("strong", null, key), " : ", this.props.data.resHeader[key])) - } - } - - detailSection = ( - React.createElement("div", null, - React.createElement("section", {className: "resHeader"}, - React.createElement("h4", {className: "subTitle"}, "response header"), - React.createElement("div", {className: "detail"}, - React.createElement("ul", {className: "uk-list"}, - React.createElement("li", null, "HTTP/1.1 ", React.createElement("span", {className: "http_status http_status_" + this.props.data.statusCode}, this.props.data.statusCode)), - resHeaderSection - ) - ) - ), - - React.createElement("section", {className: "resBody"}, - React.createElement("h4", {className: "subTitle"}, "response body"), - React.createElement("div", {className: "detail"}, bodyContent) - ) - ) - ); - } - + + render:function(){ + var self = this; return ( - React.createElement("div", null, - summarySection, - detailSection + React.createElement("div", {className: "mapWrapper"}, + React.createElement("h4", {className: "subTitle"}, "Current Config"), + React.createElement(MapList, {ref: "list"}), + + React.createElement("h4", {className: "subTitle"}, "Add Map Rule"), + React.createElement(MapForm, {onSubmit: self.appendRecord}) ) ); } }); - return DetailPanel; + return MapPanel; } module.exports.init = init; @@ -20156,120 +20091,6 @@ /***/ }, /* 7 */ -/***/ function(module, exports, __webpack_require__) { - - __webpack_require__(12); - - function init(React){ - var MapForm = __webpack_require__(13).init(React), - MapList = __webpack_require__(14).init(React); - - var MapPanel = React.createClass({displayName: "MapPanel", - appendRecord : function(data){ - var self = this, - listComponent = self.refs.list; - - listComponent.appendRecord(data); - }, - - render:function(){ - var self = this; - return ( - React.createElement("div", {className: "mapWrapper"}, - React.createElement("h4", {className: "subTitle"}, "Current Config"), - React.createElement(MapList, {ref: "list"}), - - React.createElement("h4", {className: "subTitle"}, "Add Map Rule"), - React.createElement(MapForm, {onSubmit: self.appendRecord}) - ) - ); - } - }); - - return MapPanel; - } - - module.exports.init = init; - -/***/ }, -/* 8 */ -/***/ function(module, exports, __webpack_require__) { - - function init(React){ - var RecordRow = __webpack_require__(11).init(React); - - var RecordPanel = React.createClass({displayName: "RecordPanel", - getInitialState : function(){ - return { - list : [], - filter: "" - }; - }, - render : function(){ - var self = this, - rowCollection = [], - filterStr = self.state.filter, - filter = filterStr; - - //regexp - if(filterStr[0]=="/" && filterStr[filterStr.length-1]=="/"){ - try{ - filter = new RegExp(filterStr.substr(1,filterStr.length-2)); - }catch(e){} - } - - for(var i = self.state.list.length-1 ; i >=0 ; i--){ - var item = self.state.list[i]; - if(item){ - if(filter && item){ - try{ - if(typeof filter == "object" && !filter.test(item.url)){ - continue; - }else if(typeof filter == "string" && item.url.indexOf(filter) < 0){ - continue; - } - }catch(e){} - } - - if(item._justUpdated){ - item._justUpdated = false; - item._needRender = true; - }else{ - item._needRender = false; - } - - rowCollection.push(React.createElement(RecordRow, {key: item.id, data: item, onSelect: self.props.onSelect.bind(self,item)})); - } - } - - return ( - React.createElement("table", {className: "uk-table uk-table-condensed uk-table-hover"}, - React.createElement("thead", null, - React.createElement("tr", null, - React.createElement("th", {className: "col_id"}, "#"), - React.createElement("th", {className: "col_method"}, "method"), - React.createElement("th", {className: "col_code"}, "code"), - React.createElement("th", {className: "col_host"}, "host"), - React.createElement("th", {className: "col_path"}, "path"), - React.createElement("th", {className: "col_mime"}, "mime type"), - React.createElement("th", {className: "col_time"}, "time") - ) - ), - React.createElement("tbody", null, - rowCollection - ) - ) - ); - } - }); - - return RecordPanel; - } - - module.exports.init = init; - -/***/ }, -/* 9 */ /***/ function(module, exports, __webpack_require__) { function init(React){ @@ -20367,6 +20188,192 @@ module.exports.init = init; +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + function init(React){ + var RecordRow = __webpack_require__(11).init(React); + + var RecordPanel = React.createClass({displayName: "RecordPanel", + getInitialState : function(){ + return { + list : [], + filter: "" + }; + }, + render : function(){ + var self = this, + rowCollection = [], + filterStr = self.state.filter, + filter = filterStr; + + //regexp + if(filterStr[0]=="/" && filterStr[filterStr.length-1]=="/"){ + try{ + filter = new RegExp(filterStr.substr(1,filterStr.length-2)); + }catch(e){} + } + + for(var i = self.state.list.length-1 ; i >=0 ; i--){ + var item = self.state.list[i]; + if(item){ + if(filter && item){ + try{ + if(typeof filter == "object" && !filter.test(item.url)){ + continue; + }else if(typeof filter == "string" && item.url.indexOf(filter) < 0){ + continue; + } + }catch(e){} + } + + if(item._justUpdated){ + item._justUpdated = false; + item._needRender = true; + }else{ + item._needRender = false; + } + + rowCollection.push(React.createElement(RecordRow, {key: item.id, data: item, onSelect: self.props.onSelect.bind(self,item)})); + } + } + + return ( + React.createElement("table", {className: "uk-table uk-table-condensed uk-table-hover"}, + React.createElement("thead", null, + React.createElement("tr", null, + React.createElement("th", {className: "col_id"}, "#"), + React.createElement("th", {className: "col_method"}, "method"), + React.createElement("th", {className: "col_code"}, "code"), + React.createElement("th", {className: "col_host"}, "host"), + React.createElement("th", {className: "col_path"}, "path"), + React.createElement("th", {className: "col_mime"}, "mime type"), + React.createElement("th", {className: "col_time"}, "time") + ) + ), + React.createElement("tbody", null, + rowCollection + ) + ) + ); + } + }); + + return RecordPanel; + } + + module.exports.init = init; + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + function init(React){ + + var DetailPanel = React.createClass({displayName: "DetailPanel", + getInitialState : function(){ + return { + body : {id : -1, content : null}, + left : "35%" + }; + }, + loadBody:function(){ + var self = this, + id = self.props.data.id; + if(!id) return; + + ws.reqBody(id,function(content){ + if(content.id == self.props.data.id){ + self.setState({ + body : content + }); + } + }); + }, + render : function(){ + var reqHeaderSection = [], + resHeaderSection = [], + summarySection, + detailSection, + bodyContent; + + if(this.props.data.reqHeader){ + for(var key in this.props.data.reqHeader){ + reqHeaderSection.push(React.createElement("li", {key: "reqHeader_" + key}, React.createElement("strong", null, key), " : ", this.props.data.reqHeader[key])) + } + } + + summarySection = ( + React.createElement("div", null, + React.createElement("section", {className: "req"}, + React.createElement("h4", {className: "subTitle"}, "request"), + React.createElement("div", {className: "detail"}, + React.createElement("ul", {className: "uk-list"}, + React.createElement("li", null, this.props.data.method, " ", React.createElement("span", {title: "{this.props.data.path}"}, this.props.data.path), " HTTP/1.1"), + reqHeaderSection + ) + ) + ), + + React.createElement("section", {className: "reqBody"}, + React.createElement("h4", {className: "subTitle"}, "request body"), + React.createElement("div", {className: "detail"}, + React.createElement("p", null, this.props.data.reqBody) + ) + ) + ) + ); + + if(this.props.data.statusCode){ + + if(this.state.body.id == this.props.data.id){ + bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body)); + }else{ + bodyContent = null; + this.loadBody(); + } + + if(this.props.data.resHeader){ + for(var key in this.props.data.resHeader){ + resHeaderSection.push(React.createElement("li", {key: "resHeader_" + key}, React.createElement("strong", null, key), " : ", this.props.data.resHeader[key])) + } + } + + detailSection = ( + React.createElement("div", null, + React.createElement("section", {className: "resHeader"}, + React.createElement("h4", {className: "subTitle"}, "response header"), + React.createElement("div", {className: "detail"}, + React.createElement("ul", {className: "uk-list"}, + React.createElement("li", null, "HTTP/1.1 ", React.createElement("span", {className: "http_status http_status_" + this.props.data.statusCode}, this.props.data.statusCode)), + resHeaderSection + ) + ) + ), + + React.createElement("section", {className: "resBody"}, + React.createElement("h4", {className: "subTitle"}, "response body"), + React.createElement("div", {className: "detail"}, bodyContent) + ) + ) + ); + } + + return ( + React.createElement("div", null, + summarySection, + detailSection + ) + ); + } + }); + + return DetailPanel; + } + + module.exports.init = init; + /***/ }, /* 10 */ /***/ function(module, exports, __webpack_require__) { @@ -20394,19 +20401,14 @@ return ( React.createElement("div", null, React.createElement("h4", {className: "subTitle"}, "Log Filter"), - React.createElement("div", {className: "filterSection"}, React.createElement("form", {className: "uk-form"}, React.createElement("input", {className: "uk-form-large", ref: "keywordInput", onChange: self.dealChange, type: "text", placeholder: "keywords or /^regExp$/", width: "300"}) ) ), - React.createElement("dl", {className: "uk-description-list-horizontal"}, - React.createElement("dt", null, "wrap your RegExp between two slashes"), - React.createElement("dd", null, - "e.g. ", React.createElement("br", null), - "type ", React.createElement("strong", null, "/id=\\d", 3, "/"), " will give you all the logs containing ", React.createElement("strong", null, "id=123") - ) - ) + React.createElement("p", null, + React.createElement("i", {className: "uk-icon-gift"}), "  type ", React.createElement("strong", null, "/id=\\d", 3, "/"), " will give you all the logs containing ", React.createElement("strong", null, "id=123") + ) ) ); }, diff --git a/web/src/filter.js b/web/src/filter.js index 140bdc1..1ac273c 100644 --- a/web/src/filter.js +++ b/web/src/filter.js @@ -21,19 +21,14 @@ function init(React){ return (

Log Filter

-
-
-
wrap your RegExp between two slashes
-
- e.g.
- type /id=\d{3}/ will give you all the logs containing id=123 -
-
+

+   type /id=\d{3}/ will give you all the logs containing id=123 +

); }, diff --git a/web/src/index.js b/web/src/index.js index cbdbb2f..fe21237 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -88,18 +88,10 @@ var showPop; document.getElementById("J_popOuter") ); - showPop = function(tag,props,popArg){ - var tagEl = PopupContent[tag]; - if(!tagEl) throw new Error("element not found, please make sure your panel has been pluged"); - - var contentEl = React.createElement(tagEl, props); - var defaultPopPara = { - show : true, - content : contentEl - }; - - pop.setState(util_merge(defaultPopPara,popArg)); - } + showPop = function(popArg){ + var stateArg = util_merge({show : true },popArg); + pop.setState(stateArg); + }; })(); //init record panel @@ -137,7 +129,7 @@ var recorder; }); function showDetail(data){ - showPop("detail", {data:data}, {left:"35%"}); + showPop({left:"35%",content:React.createElement(PopupContent["detail"], {data:data})}); } //init recorder panel @@ -198,14 +190,29 @@ var recorder; } $(".J_showFilter").on("click",function(){ - showPop("filter", {onChangeKeyword : updateKeyword}, { left : "50%"}); + showPop({ left:"50%", content:React.createElement(PopupContent["filter"], {onChangeKeyword : updateKeyword})}); }); })(); //map local (function(){ $(".J_showMapPanel").on("click",function(){ - showPop("map", {}, {left : "40%"}); + showPop({left:"40%", content:React.createElement(PopupContent["map"],null)}); + }); + })(); + + //other button + (function(){ + $(".J_customButton").on("click",function(){ + var thisEl = $(this), + iframeUrl = thisEl.attr("iframeUrl"); + + if(!iframeUrl){ + throw new Error("cannot find the url assigned for this button"); + } + + var iframeEl = React.createElement("iframe",{src:iframeUrl,frameBorder:0}); + showPop({left:"35%", content: iframeEl }); }); })();