mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-08-04 21:39:04 +00:00
reconstruct web interface with react.js
This commit is contained in:
174
web/src/detailPanel.js
Normal file
174
web/src/detailPanel.js
Normal file
@@ -0,0 +1,174 @@
|
||||
function init(React){
|
||||
|
||||
function dragableBar(initX,cb){
|
||||
var self = this,
|
||||
dragging = true;
|
||||
|
||||
var ghostbar = $('<div class="ghostbar"></div>').css("left",initX).prependTo('body');
|
||||
|
||||
$(document).mousemove(function(e){
|
||||
e.preventDefault();
|
||||
ghostbar.css("left",e.pageX + "px");
|
||||
});
|
||||
|
||||
$(document).mouseup(function(e){
|
||||
if(!dragging) return;
|
||||
|
||||
dragging = false;
|
||||
|
||||
var deltaPageX = e.pageX - initX;
|
||||
cb && cb.call(null,{
|
||||
delta : deltaPageX,
|
||||
finalX : e.pageX
|
||||
});
|
||||
|
||||
ghostbar.remove();
|
||||
$(document).unbind('mousemove');
|
||||
});
|
||||
}
|
||||
|
||||
var DetailPanel = React.createClass({
|
||||
getInitialState : function(){
|
||||
return {
|
||||
show : false,
|
||||
data : {},
|
||||
body : {id : -1, content : null},
|
||||
left : "35%"
|
||||
};
|
||||
},
|
||||
componentDidMount:function(){
|
||||
var self = this;
|
||||
$(document).on("keyup",function(e){
|
||||
if(e.keyCode == 27){ //ESC
|
||||
self.setState({
|
||||
show : false
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
setHide:function(){
|
||||
this.setState({
|
||||
show : false
|
||||
});
|
||||
},
|
||||
setShow:function(ifShow){
|
||||
this.setState({
|
||||
show : true
|
||||
});
|
||||
},
|
||||
loadBody:function(){
|
||||
var self = this,
|
||||
id = self.state.data.id;
|
||||
if(!id) return;
|
||||
|
||||
ws.reqBody(id,function(content){
|
||||
if(content.id == self.state.data.id){
|
||||
self.setState({
|
||||
body : content
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dealDrag:function(){
|
||||
var self = this,
|
||||
leftVal = $(React.findDOMNode(this.refs.mainOverlay)).css("left");
|
||||
dragableBar(leftVal, function(data){
|
||||
if(data && data.finalX){
|
||||
if(window.innerWidth - data.finalX < 200){
|
||||
data.finalX = window.innerWidth - 200;
|
||||
}
|
||||
self.setState({
|
||||
left : data.finalX + "px"
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
render : function(){
|
||||
var reqHeaderSection = [],
|
||||
resHeaderSection = [],
|
||||
summarySection,
|
||||
detailSection,
|
||||
bodyContent;
|
||||
|
||||
if(this.state.data.reqHeader){
|
||||
for(var key in this.state.data.reqHeader){
|
||||
reqHeaderSection.push(<li key={"reqHeader_" + key}><strong>{key}</strong> : {this.state.data.reqHeader[key]}</li>)
|
||||
}
|
||||
}
|
||||
|
||||
summarySection = (
|
||||
<div>
|
||||
<section className="req">
|
||||
<h4 className="subTitle">request</h4>
|
||||
<div className="detail">
|
||||
<ul className="uk-list">
|
||||
<li>{this.state.data.method} <span title="{this.state.data.path}">{this.state.data.path}</span> HTTP/1.1</li>
|
||||
{reqHeaderSection}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="reqBody">
|
||||
<h4 className="subTitle">request body</h4>
|
||||
<div className="detail">
|
||||
<p>{this.state.data.reqBody}</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
if(this.state.data.statusCode){
|
||||
|
||||
if(this.state.body.id == this.state.data.id){
|
||||
bodyContent = (<pre className="resBodyContent">{this.state.body.body}</pre>);
|
||||
}else{
|
||||
bodyContent = null;
|
||||
this.loadBody();
|
||||
}
|
||||
|
||||
if(this.state.data.resHeader){
|
||||
for(var key in this.state.data.resHeader){
|
||||
resHeaderSection.push(<li key={"resHeader_" + key}><strong>{key}</strong> : {this.state.data.resHeader[key]}</li>)
|
||||
}
|
||||
}
|
||||
|
||||
detailSection = (
|
||||
<div>
|
||||
<section className="resHeader">
|
||||
<h4 className="subTitle">response header</h4>
|
||||
<div className="detail">
|
||||
<ul className="uk-list">
|
||||
<li>HTTP/1.1 <span className={"http_status http_status_" + this.state.data.statusCode}>{this.state.data.statusCode}</span></li>
|
||||
{resHeaderSection}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="resBody">
|
||||
<h4 className="subTitle">response body</h4>
|
||||
<div className="detail">{bodyContent}</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{display:this.state.show ? "block" :"none"}}>
|
||||
<div className="overlay_mask" onClick={this.setHide}></div>
|
||||
<div className="recordDetailOverlay" ref="mainOverlay" style={{left: this.state.left}}>
|
||||
<div className="dragbar" onMouseDown={this.dealDrag}></div>
|
||||
<span className="escBtn" onClick={this.setHide}>Close (ESC)</span>
|
||||
<div>
|
||||
{summarySection}
|
||||
{detailSection}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return DetailPanel;
|
||||
}
|
||||
|
||||
module.exports.init = init;
|
||||
141
web/src/index.js
Normal file
141
web/src/index.js
Normal file
@@ -0,0 +1,141 @@
|
||||
require("../lib/zepto");
|
||||
var EventManager = require('../lib/event'),
|
||||
Anyproxy_wsUtil = require("../lib/anyproxy_wsUtil"),
|
||||
React = require("../lib/react");
|
||||
|
||||
var WsIndicator = require("./wsIndicator").init(React),
|
||||
RecordPanel = require("./recordPanel").init(React);
|
||||
|
||||
var ifPause = false,
|
||||
recordSet = [];
|
||||
|
||||
//Event : wsGetUpdate
|
||||
//Event : recordSetUpdated
|
||||
//Event : wsOpen
|
||||
//Event : wsEnd
|
||||
var eventCenter = new EventManager();
|
||||
|
||||
//invoke AnyProxy web socket util
|
||||
(function(){
|
||||
try{
|
||||
var ws = window.ws = new Anyproxy_wsUtil({
|
||||
baseUrl : document.getElementById("baseUrl").value,
|
||||
port : document.getElementById("socketPort").value,
|
||||
onOpen : function(){
|
||||
eventCenter.dispatchEvent("wsOpen");
|
||||
},
|
||||
onGetUpdate : function(content){
|
||||
eventCenter.dispatchEvent("wsGetUpdate",content);
|
||||
},
|
||||
onError : function(e){
|
||||
eventCenter.dispatchEvent("wsEnd");
|
||||
},
|
||||
onClose : function(e){
|
||||
eventCenter.dispatchEvent("wsEnd");
|
||||
}
|
||||
});
|
||||
window.ws = ws;
|
||||
|
||||
}catch(e){
|
||||
alert("failed to invoking web socket on this browser");
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
//websocket status indicator
|
||||
(function(){
|
||||
var wsIndicator = React.render(
|
||||
<WsIndicator />,
|
||||
document.getElementById("J_indicatorEl")
|
||||
);
|
||||
|
||||
eventCenter.addListener("wsOpen",function(){
|
||||
wsIndicator.setState({
|
||||
isValid : true
|
||||
});
|
||||
});
|
||||
|
||||
eventCenter.addListener("wsEnd",function(){
|
||||
wsIndicator.setState({
|
||||
isValid : false
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
//record panel
|
||||
(function(){
|
||||
//merge : right --> left
|
||||
function util_merge(left,right){
|
||||
for(var key in right){
|
||||
left[key] = right[key];
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
function updateRecordSet(newRecord){
|
||||
if(ifPause) return;
|
||||
|
||||
if(newRecord && newRecord.id){
|
||||
if(!recordSet[newRecord.id]){
|
||||
recordSet[newRecord.id] = newRecord;
|
||||
}else{
|
||||
util_merge(recordSet[newRecord.id],newRecord);
|
||||
}
|
||||
|
||||
recordSet[newRecord.id]._justUpdated = true;
|
||||
// React.addons.Perf.start();
|
||||
eventCenter.dispatchEvent("recordSetUpdated");
|
||||
// React.addons.Perf.stop();
|
||||
}
|
||||
}
|
||||
eventCenter.addListener("wsGetUpdate",updateRecordSet);
|
||||
|
||||
var Panel = React.render(
|
||||
<RecordPanel />,
|
||||
document.getElementById("J_content")
|
||||
);
|
||||
|
||||
eventCenter.addListener('recordSetUpdated',function(){
|
||||
Panel.setState({
|
||||
list : recordSet
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
//action bar
|
||||
(function(){
|
||||
function clearLogs(){
|
||||
recordSet = [];
|
||||
eventCenter.dispatchEvent("recordSetUpdated");
|
||||
}
|
||||
|
||||
$(document).on("keyup",function(e){
|
||||
if(e.keyCode == 88 && e.ctrlKey){ // ctrl + x
|
||||
clearLogs();
|
||||
}
|
||||
});
|
||||
|
||||
var clearLogBtn = $(".J_clearBtn");
|
||||
clearLogBtn.on("click",function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
clearLogs();
|
||||
});
|
||||
|
||||
var statusBtn = $(".J_statusBtn");
|
||||
statusBtn.on("click",function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
$(".J_statusBtn").removeClass("btn_disable");
|
||||
$(this).addClass("btn_disable");
|
||||
|
||||
if(/stop/i.test($(this).html()) ){
|
||||
ifPause = true;
|
||||
}else{
|
||||
ifPause = false;
|
||||
}
|
||||
});
|
||||
})();
|
||||
51
web/src/recordPanel.js
Normal file
51
web/src/recordPanel.js
Normal file
@@ -0,0 +1,51 @@
|
||||
function init(React){
|
||||
var RecordRow = require("./recordRow").init(React);
|
||||
|
||||
var RecordPanel = React.createClass({
|
||||
getInitialState : function(){
|
||||
return {
|
||||
list : []
|
||||
};
|
||||
},
|
||||
render : function(){
|
||||
var rowCollection = [];
|
||||
for(var i = this.state.list.length-1 ; i >=0 ; i--){
|
||||
var item = this.state.list[i];
|
||||
if(item){
|
||||
|
||||
if(item._justUpdated){
|
||||
item._justUpdated = false;
|
||||
item._needRender = true;
|
||||
}else{
|
||||
item._needRender = false;
|
||||
}
|
||||
|
||||
rowCollection.push(<RecordRow key={item.id} data={item}></RecordRow>);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<table className="uk-table uk-table-condensed uk-table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="col_id">id</th>
|
||||
<th className="col_method">method</th>
|
||||
<th className="col_code">code</th>
|
||||
<th className="col_host">host</th>
|
||||
<th className="col_path">path</th>
|
||||
<th className="col_mime">mime type</th>
|
||||
<th className="col_time">time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rowCollection}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return RecordPanel;
|
||||
}
|
||||
|
||||
module.exports.init = init;
|
||||
70
web/src/recordRow.js
Normal file
70
web/src/recordRow.js
Normal file
@@ -0,0 +1,70 @@
|
||||
function init(React){
|
||||
var DetailPanel = require("./detailPanel").init(React);
|
||||
|
||||
$("body").append('<div id="J_detailPanel"></div>');
|
||||
var detail = React.render(
|
||||
<DetailPanel />,
|
||||
document.getElementById("J_detailPanel")
|
||||
);
|
||||
|
||||
function dateFormat(date,fmt) {
|
||||
var o = {
|
||||
"M+": date.getMonth() + 1, //月份
|
||||
"d+": date.getDate(), //日
|
||||
"h+": date.getHours(), //小时
|
||||
"m+": date.getMinutes(), //分
|
||||
"s+": date.getSeconds(), //秒
|
||||
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
|
||||
"S" : date.getMilliseconds() //毫秒
|
||||
};
|
||||
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||||
return fmt;
|
||||
}
|
||||
|
||||
var RecordRow = React.createClass({
|
||||
getInitialState : function(){
|
||||
return null;
|
||||
},
|
||||
handleClick:function(e){
|
||||
detail.setState({
|
||||
data : this.props.data,
|
||||
show : true
|
||||
});
|
||||
},
|
||||
render : function(){
|
||||
var trClassesArr = [],
|
||||
trClasses;
|
||||
if(this.props.data.statusCode){
|
||||
trClassesArr.push("record_status_done");
|
||||
}
|
||||
|
||||
trClassesArr.push( ((Math.floor(this.props.data._id /2) - this.props.data._id /2) == 0)? "row_even" : "row_odd" );
|
||||
trClasses = trClassesArr.join(" ");
|
||||
|
||||
var dateStr = dateFormat(new Date(this.props.data.startTime),"hh:mm:ss");
|
||||
|
||||
return(
|
||||
<tr className={trClasses} onClick={this.handleClick}>
|
||||
<td className="data_id">{this.props.data._id}</td>
|
||||
<td>{this.props.data.method} <span className={"protocol protocol_" + this.props.data.protocol} title="https"><i className="iconfont">󰃉</i></span> </td>
|
||||
<td className={"http_status http_status_" + this.props.data.statusCode}>{this.props.data.statusCode}</td>
|
||||
<td title={this.props.data.host}>{this.props.data.host}</td>
|
||||
<td title={this.props.data.path}>{this.props.data.path}</td>
|
||||
<td>{this.props.data.mime}</td>
|
||||
<td>{dateStr}</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
shouldComponentUpdate:function(nextPros){
|
||||
return nextPros.data._needRender;
|
||||
},
|
||||
componentDidUpdate:function(){},
|
||||
componentWillUnmount:function(){}
|
||||
});
|
||||
|
||||
return RecordRow;
|
||||
|
||||
}
|
||||
|
||||
module.exports.init = init;
|
||||
18
web/src/wsIndicator.js
Normal file
18
web/src/wsIndicator.js
Normal file
@@ -0,0 +1,18 @@
|
||||
function init(React){
|
||||
var WsIndicator = React.createClass({
|
||||
getInitialState:function(){
|
||||
return {
|
||||
isValid: false
|
||||
}
|
||||
},
|
||||
render:function(){
|
||||
return (
|
||||
<img className="logo_bottom anim_rotation" src="https://t.alipayobjects.com/images/rmsweb/T1P_dfXa8oXXXXXXXX.png" width="50" height="50" style={{display: this.state.isValid ?"block" : "none" }} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return WsIndicator;
|
||||
}
|
||||
|
||||
module.exports.init = init;
|
||||
Reference in New Issue
Block a user