(web) Adding a terminal host

This commit is contained in:
Alexey Kontsevoy 2016-02-26 13:30:54 -05:00
parent 57f8887ba2
commit 0b4565b018
22 changed files with 2139 additions and 1570 deletions

813
web/dist/app/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2602
web/dist/app/vendor.js vendored

File diff suppressed because one or more lines are too long

6
web/dist/index.html vendored
View file

@ -10,11 +10,11 @@
<script src="/web/app/assets/js/jquery-validate-1.14.0.js"></script>
<script src="/web/app/assets/js/bootstrap.js"></script>
<script src="/web/app/assets/js/term.js"></script>
<script src="/web/app/vendor.js?ver=0.11456438265918"></script>
<script src="/web/app/styles.js?ver=0.11456438265918"></script>
<script src="/web/app/vendor.js?ver=0.11456463877805"></script>
<script src="/web/app/styles.js?ver=0.11456463877805"></script>
</head>
<body class="grv">
<div id="app"></div>
</body>
<script src="/web/app/app.js?ver=0.11456438265918"></script>
<script src="/web/app/app.js?ver=0.11456463877805"></script>
</html>

View file

@ -3,7 +3,7 @@ var session = require('./session');
var cfg = require('app/config');
var $ = require('jQuery');
const refreshRate = 60000 * 1; // 1 min
const refreshRate = 60000 * 100; // 1 min
var refreshTokenTimerId = null;

View file

@ -1,20 +1,17 @@
var React = require('react');
var NavLeftBar = require('./navLeftBar');
var cfg = require('app/config');
var {TerminalHost} = require('./terminalHost.jsx');
var App = React.createClass({
render: function() {
return (
<div className="grv-tlpt">
<TerminalHost/>
<NavLeftBar/>
<div className="row">
<nav className="" role="navigation" style={{ marginBottom: 0 }}>
<ul className="nav navbar-top-links navbar-right">
<li>
<span className="m-r-sm text-muted welcome-message">
Welcome to Gravitational Portal
</span>
</li>
<ul className="nav navbar-top-links navbar-right">
<li>
<a href={cfg.routes.logout}>
<i className="fa fa-sign-out"></i>

View file

@ -3,8 +3,9 @@ var { Router, IndexLink, History } = require('react-router');
var cfg = require('app/config');
var menuItems = [
{icon: 'fa fa fa-sitemap', to: cfg.routes.nodes, title: 'Nodes'},
{icon: 'fa fa-hdd-o', to: cfg.routes.sessions, title: 'Sessions'}
{icon: 'fa fa-cogs', to: cfg.routes.nodes, title: 'Nodes'},
{icon: 'fa fa-sitemap', to: cfg.routes.sessions, title: 'Sessions'},
{icon: 'fa fa-question', to: cfg.routes.sessions, title: 'Sessions'},
];
var NavLeftBar = React.createClass({

View file

@ -3,6 +3,7 @@ var reactor = require('app/reactor');
var {getters, actions} = require('app/modules/nodes');
var userGetters = require('app/modules/user/getters');
var {Table, Column, Cell} = require('app/components/table.jsx');
var {connect} = require('app/modules/activeTerminal/actions');
const TextCell = ({rowIndex, data, columnKey, ...props}) => (
<Cell {...props}>
@ -21,7 +22,7 @@ const TagCell = ({rowIndex, data, columnKey, ...props}) => (
</Cell>
);
const LoginCell = ({user, ...props}) => {
const LoginCell = ({user, rowIndex, data, ...props}) => {
if(!user || user.logins.length === 0){
return <Cell {...props} />;
}
@ -29,13 +30,13 @@ const LoginCell = ({user, ...props}) => {
var $lis = [];
for(var i = 0; i < user.logins.length; i++){
$lis.push(<li key={i}><a href="#" target="_blank">{user.logins[i]}</a></li>);
$lis.push(<li key={i}><a href="#" target="_blank" onClick={connect.bind(null, data[rowIndex].addr, user.logins[i])}>{user.logins[i]}</a></li>);
}
return (
<Cell {...props}>
<div className="btn-group">
<button type="button" className="btn btn-sm btn-primary">{user.logins[0]}</button>
<button type="button" onClick={connect.bind(null, data[rowIndex].addr, user.logins[0])} className="btn btn-sm btn-primary">{user.logins[0]}</button>
{
$lis.length > 1 ? (
<div className="btn-group">
@ -80,14 +81,14 @@ var Nodes = React.createClass({
<div className="">
<div className="">
<div className="">
<Table rowCount={data.length} className="grv-nodes-table">
<Table rowCount={data.length} className="table-stripped grv-nodes-table">
<Column
columnKey="count"
columnKey="sessionCount"
header={<Cell> Sessions </Cell> }
cell={<TextCell data={data}/> }
/>
<Column
columnKey="ip"
columnKey="addr"
header={<Cell> Node </Cell> }
cell={<TextCell data={data}/> }
/>
@ -99,7 +100,7 @@ var Nodes = React.createClass({
<Column
columnKey="roles"
header={<Cell>Login as</Cell> }
cell={<LoginCell user={this.state.user}/> }
cell={<LoginCell data={data} user={this.state.user}/> }
/>
</Table>
</div>

View file

@ -56,7 +56,7 @@ var GrvTable = React.createClass({
children.push(child);
});
var tableClass = 'table table-bordered ' + this.props.className;
var tableClass = 'table ' + this.props.className;
return (
<table className={tableClass}>

View file

@ -0,0 +1,107 @@
var session = require('app/session');
var cfg = require('app/config');
var React = require('react');
var {getters, actions} = require('app/modules/activeTerminal/');
var TerminalHost = React.createClass({
mixins: [reactor.ReactMixin],
getDataBindings() {
return {
terminal: getters.terminal
}
},
render: function() {
if(!this.state.terminal){
return null;
}
return (
<div className="grv-terminal-host">
<div className="grv-terminal-participans">
<ul className="nav">
<li><button className="btn btn-primary btn-circle" type="button"> <strong>A</strong></button></li>
<li><button className="btn btn-primary btn-circle" type="button"> B </button></li>
<li><button className="btn btn-primary btn-circle" type="button"> C </button></li>
<li>
<button onClick={actions.close} className="btn btn-danger btn-circle" type="button">
<i className="fa fa-times"></i>
</button>
</li>
</ul>
</div>
<TerminalBox settings={this.state.terminal} />
</div>
);
}
});
var TerminalBox = React.createClass({
renderTerminal: function() {
var {token} = session.getUserData();
var parent = document.getElementById("terminal-box");
var settings = this.props.settings;
//settings.sid = 5555;
settings.term = {
h: 120,
w: 100
};
var connectionStr = cfg.api.getTermConnString(token, settings);
this.term = new Terminal({
cols: 180,
rows: 50,
useStyle: true,
screenKeys: true,
cursorBlink: false
});
this.term.open(parent);
this.socket = new WebSocket(connectionStr, "proto");
this.term.write('\x1b[94mconnecting to "pod"\x1b[m\r\n');
this.socket.onopen = () => {
this.term.on('data', (data) => {
this.socket.send(data);
});
this.socket.onmessage = (e) => {
this.term.write(e.data);
}
this.socket.onclose = () => {
this.term.write('\x1b[31mdisconnected\x1b[m\r\n');
}
}
},
componentDidMount: function() {
this.renderTerminal();
},
componentWillUnmount: function() {
this.socket.close();
this.term.destroy();
},
shouldComponentUpdate: function() {
return false;
},
componentWillReceiveProps: function(props) {
},
render: function() {
return (
<div className="grv-wiz-terminal" id="terminal-box">
</div>
);
}
});
export default TerminalHost;
export {TerminalBox, TerminalHost};

View file

@ -11,6 +11,13 @@ let cfg = {
createUserPath: '/v1/webapi/users',
getInviteUrl: (inviteToken) => {
return formatPattern(cfg.api.invitePath, {inviteToken});
},
getTermConnString: (token, params) => {
var json = JSON.stringify(params);
var jsonEncoded = window.encodeURI(json);
var prefix = location.protocol == "https:"?"wss://":"ws://";
return `${prefix}${params.addr}/v1/webapi/sites/-current-/connect?access_token=${token}&params=${jsonEncoded}`;
}
},

View file

@ -0,0 +1,6 @@
import keyMirror from 'keymirror'
export default keyMirror({
TLPT_TERM_CONNECT: null,
TLPT_TERM_CLOSE: null
})

View file

@ -0,0 +1,21 @@
var reactor = require('app/reactor');
var { TLPT_TERM_CONNECT, TLPT_TERM_CLOSE } = require('./actionTypes');
export default {
close(){
reactor.dispatch(TLPT_TERM_CLOSE);
},
connect(addr, login){
/*
* {
* "addr": "127.0.0.1:5000",
* "login": "admin",
* "term": {"h": 120, "w": 100},
* "sid": "123"
* }
*/
reactor.dispatch(TLPT_TERM_CONNECT, {addr, login});
}
}

View file

@ -0,0 +1,22 @@
var { Store, toImmutable } = require('nuclear-js');
var { TLPT_TERM_CONNECT, TLPT_TERM_CLOSE } = require('./actionTypes');
export default Store({
getInitialState() {
return toImmutable(null);
},
initialize() {
this.on(TLPT_TERM_CONNECT, connect);
this.on(TLPT_TERM_CLOSE, close);
}
})
function close(){
return toImmutable(null);
}
function connect(state, term){
return toImmutable(term);
}

View file

@ -0,0 +1,13 @@
const terminal = [ ['tlpt_active_terminal'], (settings) => {
if(!settings){
return null;
}
var {addr, login } = settings.toJS();
return {addr, login }
}
];
export default {
terminal
}

View file

@ -0,0 +1,3 @@
module.exports.getters = require('./getters');
module.exports.actions = require('./actions');
module.exports.activeTermStore = require('./activeTermStore');

View file

@ -1,5 +1,6 @@
var reactor = require('app/reactor');
reactor.registerStores({
'tlpt_active_terminal': require('./activeTerminal/activeTermStore'),
'tlpt_user': require('./user/userStore'),
'tlpt_nodes': require('./nodes/nodeStore'),
'tlpt_invite': require('./invite/inviteStore'),

View file

@ -1,10 +1,13 @@
//var sort = require('app/common/sort');
var { toImmutable } = require('nuclear-js');
const nodeListView = [ ['tlpt_nodes'], (nodes) =>{
return nodes.map((item)=>{
var sessions = item.get('sessions') || toImmutable([]);
return {
tags: getTags(item),
ip: item.get('addr')
tags: getTags(item.get('node')),
addr: item.getIn(['node', 'addr']),
sessionCount: sessions.size
}
}).toJS();
}

View file

@ -9,11 +9,11 @@ var cfg = require('app/config');
export default {
ensureUser(nextState, replace, cb){
/*var userData = session.getUserData();
var userData = session.getUserData();
reactor.dispatch(TLPT_RECEIVE_USER, userData.user);
cb();*/
cb();
auth.ensureUser()
/*auth.ensureUser()
.done((userData)=> {
reactor.dispatch(TLPT_RECEIVE_USER, userData.user);
cb();
@ -21,7 +21,7 @@ export default {
.fail(()=>{
replace({redirectTo: nextState.location.pathname }, cfg.routes.login);
cb();
});
});*/
},
signUp({name, psw, token, inviteToken}){

View file

@ -2,7 +2,7 @@
@import "grv-login";
@import "grv-logo";
@import "grv-nodes";
@import "grv-terminal-host";
.grv {

View file

@ -1,5 +1,12 @@
.grv-nodes{
h1{
margin-top: -30px;
padding-bottom: 30px;
text-align: center;
}
.grv-nodes-table{
.label {
margin-right: 5px;

View file

@ -0,0 +1,25 @@
.grv-terminal-host{
padding: 50px 60px;
padding-left: 130px;
position: fixed;
height: 100%;
width: 100%;
display: block;
background-color: black;
z-index: 1;
}
.grv-terminal-participans{
margin-left: -100px;
width: 50px;
position: absolute;
.nav {
text-align: center;
> li{
margin: 15px 0;
}
}
}