175 lines
5.7 KiB
JavaScript
175 lines
5.7 KiB
JavaScript
/**
|
|
* График.
|
|
* <code>this.props.datum</code> - данные в формате D3
|
|
*/
|
|
var NvLineChart = React.createClass({
|
|
chart: null,
|
|
d3ChartData: null,
|
|
/*--------------------*/
|
|
render: function(){return(
|
|
ce('div', {id: 'chart'}, ce('svg', {style: {'height': '500px'}}))
|
|
)},
|
|
componentDidMount: function() {
|
|
var _this = this;
|
|
nv.addGraph(function() {
|
|
_this.chart = nv.models.lineChart().useInteractiveGuideline(true);
|
|
_this.chart.xAxis.axisLabel('Time').tickFormat(function(d){ return d3.time.format('%X')(new Date(d)); });
|
|
_this.chart.yAxis.axisLabel('Players').tickFormat(d3.format('d'));
|
|
|
|
_this.d3ChartData = d3.select('#chart svg').datum(_this.props.datum);
|
|
_this.d3ChartData.transition().duration(500).call(_this.chart);
|
|
|
|
nv.utils.windowResize(_this.chart.update);
|
|
return _this.chart;
|
|
});
|
|
},
|
|
componentDidUpdate: function() {
|
|
if (this.d3ChartData === null) return;
|
|
|
|
this.d3ChartData.datum(this.props.datum);
|
|
this.d3ChartData.transition().duration(500).call(this.chart);
|
|
nv.utils.windowResize(this.chart.update);
|
|
},
|
|
componentWillUnmount: function() {
|
|
var nvtooltip = document.querySelector('div[class~="nvtooltip"]');
|
|
if (nvtooltip !== null) {
|
|
nvtooltip.parentElement.removeChild(nvtooltip)
|
|
}
|
|
}
|
|
});
|
|
|
|
var Tabs = React.createClass({
|
|
onTabClick: function(idx){
|
|
this.setState({ activeTab: idx });
|
|
},
|
|
/*--------------------*/
|
|
getInitialState: function(){return{
|
|
activeTab: 0
|
|
}},
|
|
render: function(){
|
|
var _this = this;
|
|
|
|
var tabsElm = [];
|
|
this.props.tabs.forEach(function(title, i){
|
|
tabsElm.push(ce('li', (i === _this.state.activeTab ? {className: 'active'} : null),
|
|
ce('a', {href: '#tab'+(i+1), onClick: _this.onTabClick.bind(_this, i)}, title)));
|
|
});
|
|
|
|
var showElement = this.props.children.map(function(child, i){
|
|
return ce('div', (i !== _this.state.activeTab ? {style: {display: 'none'}} : null), child);
|
|
});
|
|
|
|
return(ce('div', null,
|
|
ce('ul', {className: 'nav nav-tabs', id: 'tabs'}, tabsElm),
|
|
showElement
|
|
))
|
|
},
|
|
componentDidUpdate: function() {
|
|
if (this.props.stateCallback !== null) {
|
|
this.props.stateCallback(this.state.activeTab);
|
|
}
|
|
}
|
|
});
|
|
|
|
var WebConsole = React.createClass({
|
|
ws: null,
|
|
connect: function(){
|
|
if (this.ws !== null) return;
|
|
var _this = this;
|
|
|
|
this.ws = new WebSocket("ws://127.0.0.1:8770"); //FIXME указывать ip:port из настроек
|
|
this.ws.onopen = function(){ console.debug('WS: open...'); };
|
|
this.ws.onclose = function(){ console.debug('WS: close...'); };
|
|
this.ws.onerror = function(e){ console.debug('WS: error'); console.error(e); };
|
|
this.ws.onmessage = function(event){
|
|
_this.setState({ lines: _this.state.lines.concat([event.data]) }); //TODO необходимо ограничить кол-во строк
|
|
};
|
|
},
|
|
disconnect: function() {
|
|
if (this.ws === null) return;
|
|
this.ws.close();
|
|
this.ws = null;
|
|
},
|
|
/*--------------------*/
|
|
getInitialState: function(){return{
|
|
lines: []
|
|
}},
|
|
render: function(){
|
|
var ansi_up = new AnsiUp;
|
|
|
|
return(
|
|
ce('div', {id: 'webconsole'},
|
|
ce('div', {className: 'output'},
|
|
this.state.lines.map(function(line){
|
|
return ce('p', {dangerouslySetInnerHTML: {__html: ansi_up.ansi_to_html(line)}});
|
|
})
|
|
),
|
|
ce('input')
|
|
)
|
|
)
|
|
},
|
|
componentWillUnmount: function(){
|
|
this.disconnect();
|
|
}
|
|
});
|
|
|
|
var ServerInfo = React.createClass({
|
|
tabStateWebConsole: function(state) {
|
|
if (state === 1) {
|
|
this.refs.webconsole.connect();
|
|
}
|
|
},
|
|
/*--------------------*/
|
|
getInitialState: function(){return {
|
|
title: null,
|
|
data: []
|
|
}},
|
|
render: function(){
|
|
if (this.state.title === null) {
|
|
return ce('div', null, 'no data');
|
|
} else {
|
|
return(
|
|
ce('div', null,
|
|
ce('h2', {style: {'margin-top': '0px'}}, this.state.title),
|
|
ce(Tabs, {tabs: ['Онлайн', 'Консоль'], stateCallback: this.tabStateWebConsole},
|
|
ce(NvLineChart, {datum: [{
|
|
key: 'Online players',
|
|
color: '#37d668',
|
|
area: true,
|
|
values: this.state.data
|
|
}]}),
|
|
ce(WebConsole, {ref: 'webconsole'})
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Пункт списка серверов.
|
|
* <code>this.props.title</code> - заголовок / clientId
|
|
* <code>this.props.onClick</code> - callback события клика
|
|
* <code>this.props.active</code> - состояние активности (true/false)
|
|
*/
|
|
var ServerListItem = React.createClass({
|
|
render: function(){
|
|
return(
|
|
ce('a', {className: 'list-group-item clearfix' + (this.props.active ? ' active' : ''), href: '#',
|
|
onClick: this.props.onClick},
|
|
ce('span', {style: {'padding-top': '15px'}},
|
|
ce('span', {className: 'glyphicon glyphicon-tasks'}),
|
|
nbsp,
|
|
this.props.title
|
|
)
|
|
)
|
|
)
|
|
}
|
|
});
|
|
|
|
var ServerList = React.createClass({
|
|
render: function(){return(
|
|
ce('div', {className: 'list-group'}, this.props.children)
|
|
)}
|
|
});
|