mirror of
https://github.com/gravitational/teleport
synced 2024-10-22 10:13:21 +00:00
Merge branch 'alexander/ids' of github.com:gravitational/teleport into alexander/ids
This commit is contained in:
commit
7e70589335
|
@ -244,7 +244,6 @@ func setCmdUser(cmd *exec.Cmd, username string) error {
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
cmd.Env = []string{"HOME=" + osUser.HomeDir}
|
||||
|
||||
// are we already username?
|
||||
curUser, err := user.Current()
|
||||
|
|
1172
web/dist/app/app.js
vendored
1172
web/dist/app/app.js
vendored
File diff suppressed because one or more lines are too long
28
web/dist/app/styles.js
vendored
28
web/dist/app/styles.js
vendored
File diff suppressed because one or more lines are too long
1855
web/dist/app/vendor.js
vendored
1855
web/dist/app/vendor.js
vendored
File diff suppressed because one or more lines are too long
6
web/dist/index.html
vendored
6
web/dist/index.html
vendored
|
@ -11,11 +11,11 @@
|
|||
<script src="/web/app/assets/js/underscore-1.8.3.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.11456968818190"></script>
|
||||
<script src="/web/app/styles.js?ver=0.11456968818190"></script>
|
||||
<script src="/web/app/vendor.js?ver=0.11457083126376"></script>
|
||||
<script src="/web/app/styles.js?ver=0.11457083126376"></script>
|
||||
</head>
|
||||
<body class="grv">
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<script src="/web/app/app.js?ver=0.11456968818190"></script>
|
||||
<script src="/web/app/app.js?ver=0.11457083126376"></script>
|
||||
</html>
|
||||
|
|
|
@ -5,9 +5,9 @@ var {actions} = require('app/modules/activeTerminal/');
|
|||
|
||||
class Tty extends EventEmitter {
|
||||
|
||||
constructor({addr, login, sid, rows, cols }){
|
||||
constructor({serverId, login, sid, rows, cols }){
|
||||
super();
|
||||
this.options = { addr, login, sid, rows, cols };
|
||||
this.options = { serverId, login, sid, rows, cols };
|
||||
this.socket = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ var {getters, actions} = require('app/modules/activeTerminal/');
|
|||
var EventStreamer = require('./eventStreamer.jsx');
|
||||
var Tty = require('app/common/tty');
|
||||
var TtyTerminal = require('./../terminal.jsx');
|
||||
var NotFoundPage = require('app/components/notFoundPage.jsx');
|
||||
|
||||
var ActiveSession = React.createClass({
|
||||
|
||||
var ActiveSessionHost = React.createClass({
|
||||
|
||||
mixins: [reactor.ReactMixin],
|
||||
|
||||
|
@ -14,18 +16,34 @@ var ActiveSession = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
componentDidMount(){
|
||||
var { sid } = this.props.params;
|
||||
if(!this.state.activeSession){
|
||||
actions.openSession(sid);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if(!this.state.activeSession){
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ActiveSession activeSession={this.state.activeSession}/>;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var ActiveSession = React.createClass({
|
||||
render: function() {
|
||||
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>
|
||||
|
@ -34,7 +52,7 @@ var ActiveSession = React.createClass({
|
|||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div className="btn-group">
|
||||
{/*<div className="btn-group">
|
||||
<span className="btn btn-xs btn-primary">128.0.0.1:8888</span>
|
||||
<div className="btn-group">
|
||||
<button data-toggle="dropdown" className="btn btn-default btn-xs dropdown-toggle" aria-expanded="true">
|
||||
|
@ -45,9 +63,9 @@ var ActiveSession = React.createClass({
|
|||
<li><a href="#" target="_blank">Logs</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>*/}
|
||||
</div>
|
||||
<TtyConnection {...this.state.activeSession} />
|
||||
<TtyConnection {...this.props.activeSession} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -66,14 +84,14 @@ var TtyConnection = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
let component = new React.Component();
|
||||
|
||||
return (
|
||||
<component>
|
||||
<div style={{height: '100%'}}>
|
||||
<TtyTerminal tty={this.tty} cols={this.props.cols} rows={this.props.rows} />
|
||||
{ this.state.isConnected ? <EventStreamer sid={this.props.sid}/> : null }
|
||||
</component>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
export {ActiveSession, TtyConnection};
|
||||
module.exports = {ActiveSession, ActiveSessionHost};
|
||||
|
|
|
@ -1,20 +1,37 @@
|
|||
var React = require('react');
|
||||
var NavLeftBar = require('./navLeftBar');
|
||||
var cfg = require('app/config');
|
||||
var actions = require('app/modules/actions');
|
||||
var {ActiveSession} = require('./activeSession/main.jsx');
|
||||
var reactor = require('app/reactor');
|
||||
var {actions, getters} = require('app/modules/app');
|
||||
|
||||
var App = React.createClass({
|
||||
|
||||
componentDidMount(){
|
||||
actions.fetchNodesAndSessions();
|
||||
mixins: [reactor.ReactMixin],
|
||||
|
||||
getDataBindings() {
|
||||
return {
|
||||
app: getters.appState
|
||||
}
|
||||
},
|
||||
|
||||
componentWillMount(){
|
||||
actions.initApp();
|
||||
this.refreshInterval = setInterval(actions.fetchNodesAndSessions, 3000);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if(this.state.app.isInitializing){
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grv-tlpt">
|
||||
<NavLeftBar/>
|
||||
<ActiveSession/>
|
||||
{this.props.activeSessionHost}
|
||||
<div className="row">
|
||||
<nav className="" role="navigation" style={{ marginBottom: 0, float: "right" }}>
|
||||
<ul className="nav navbar-top-links navbar-right">
|
||||
|
|
|
@ -3,4 +3,5 @@ module.exports.Login = require('./login.jsx');
|
|||
module.exports.NewUser = require('./newUser.jsx');
|
||||
module.exports.Nodes = require('./nodes/main.jsx');
|
||||
module.exports.Sessions = require('./sessions/main.jsx');
|
||||
module.exports.ActiveSession = require('./activeSession/main.jsx');
|
||||
module.exports.ActiveSessionHost = require('./activeSession/main.jsx').ActiveSessionHost;
|
||||
module.exports.NotFoundPage = require('./notFoundPage.jsx');
|
||||
|
|
|
@ -3,7 +3,9 @@ var $ = require('jQuery');
|
|||
var reactor = require('app/reactor');
|
||||
var LinkedStateMixin = require('react-addons-linked-state-mixin');
|
||||
var {actions} = require('app/modules/user');
|
||||
var GoogleAuthInfo = require('./googleAuth');
|
||||
var GoogleAuthInfo = require('./googleAuthLogo');
|
||||
var cfg = require('app/config');
|
||||
|
||||
var LoginInputForm = React.createClass({
|
||||
|
||||
mixins: [LinkedStateMixin],
|
||||
|
@ -19,7 +21,7 @@ var LoginInputForm = React.createClass({
|
|||
onClick: function(e) {
|
||||
e.preventDefault();
|
||||
if (this.isValid()) {
|
||||
actions.login({ ...this.state}, '/web');
|
||||
this.props.onClick(this.state);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -55,20 +57,29 @@ var Login = React.createClass({
|
|||
|
||||
getDataBindings() {
|
||||
return {
|
||||
// userRequest: getters.userRequest
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
onClick(inputData){
|
||||
var loc = this.props.location;
|
||||
var redirect = cfg.routes.app;
|
||||
|
||||
if(loc.state && loc.state.redirectTo){
|
||||
redirect = loc.state.redirectTo;
|
||||
}
|
||||
|
||||
actions.login(inputData, redirect);
|
||||
},
|
||||
|
||||
render() {
|
||||
var isProcessing = false;//this.state.userRequest.get('isLoading');
|
||||
var isError = false;//this.state.userRequest.get('isError');
|
||||
|
||||
return (
|
||||
<div className="grv-login text-center">
|
||||
<div className="grv-logo-tprt"></div>
|
||||
<div className="grv-content grv-flex">
|
||||
<div className="grv-flex-column">
|
||||
<LoginInputForm/>
|
||||
<LoginInputForm onClick={this.onClick}/>
|
||||
<GoogleAuthInfo/>
|
||||
<div className="grv-login-info">
|
||||
<i className="fa fa-question"></i>
|
||||
|
|
|
@ -4,7 +4,7 @@ var reactor = require('app/reactor');
|
|||
var {actions, getters} = require('app/modules/invite');
|
||||
var userModule = require('app/modules/user');
|
||||
var LinkedStateMixin = require('react-addons-linked-state-mixin');
|
||||
var GoogleAuthInfo = require('./googleAuth');
|
||||
var GoogleAuthInfo = require('./googleAuthLogo');
|
||||
|
||||
var InviteInputForm = React.createClass({
|
||||
|
||||
|
|
|
@ -3,7 +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 {open} = require('app/modules/activeTerminal/actions');
|
||||
var {createNewSession} = require('app/modules/activeTerminal/actions');
|
||||
|
||||
const TextCell = ({rowIndex, data, columnKey, ...props}) => (
|
||||
<Cell {...props}>
|
||||
|
@ -27,28 +27,33 @@ const LoginCell = ({user, rowIndex, data, ...props}) => {
|
|||
return <Cell {...props} />;
|
||||
}
|
||||
|
||||
var serverId = data[rowIndex].id;
|
||||
var $lis = [];
|
||||
|
||||
function onNewSessionClick(i){
|
||||
var login = user.logins[i];
|
||||
return () => createNewSession(serverId, login);
|
||||
}
|
||||
|
||||
for(var i = 0; i < user.logins.length; i++){
|
||||
$lis.push(<li key={i}><a href="#" target="_blank" onClick={open.bind(null, data[rowIndex].addr, user.logins[i], undefined)}>{user.logins[i]}</a></li>);
|
||||
$lis.push(<li key={i}><a onClick={onNewSessionClick(i)}>{user.logins[i]}</a></li>);
|
||||
}
|
||||
|
||||
return (
|
||||
<Cell {...props}>
|
||||
<div className="btn-group">
|
||||
<button type="button" onClick={open.bind(null, data[rowIndex].addr, user.logins[0], undefined)} className="btn btn-sm btn-primary">{user.logins[0]}</button>
|
||||
<button type="button" onClick={onNewSessionClick(0)} className="btn btn-sm btn-primary">{user.logins[0]}</button>
|
||||
{
|
||||
$lis.length > 1 ? (
|
||||
<div className="btn-group">
|
||||
<button data-toggle="dropdown" className="btn btn-default btn-sm dropdown-toggle" aria-expanded="true">
|
||||
<span className="caret"></span>
|
||||
</button>
|
||||
<ul className="dropdown-menu">
|
||||
<li><a href="#" target="_blank">Logs</a></li>
|
||||
<li><a href="#" target="_blank">Logs</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
): null
|
||||
[
|
||||
<button key={0} data-toggle="dropdown" className="btn btn-default btn-sm dropdown-toggle" aria-expanded="true">
|
||||
<span className="caret"></span>
|
||||
</button>,
|
||||
<ul key={1} className="dropdown-menu">
|
||||
{$lis}
|
||||
</ul>
|
||||
] )
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</Cell>
|
||||
|
@ -65,7 +70,7 @@ var Nodes = React.createClass({
|
|||
user: userGetters.user
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
render: function() {
|
||||
var data = this.state.nodeRecords;
|
||||
return (
|
||||
|
|
19
web/src/app/components/notFoundPage.jsx
Normal file
19
web/src/app/components/notFoundPage.jsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
var React = require('react');
|
||||
|
||||
var NotFoundPage = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div className="grv-page-notfound">
|
||||
<div className="grv-logo-tprt">Teleport</div>
|
||||
<div className="grv-warning"><i className="fa fa-warning"></i> </div>
|
||||
<h1>Whoops, we cannot find that</h1>
|
||||
<div>Looks like the page you are looking for isn't here any longer</div>
|
||||
<div>If you believe this is an error, please contact your organization administrator.</div>
|
||||
<div className="contact-section">If you believe this is an issue with Teleport, please <a href="https://github.com/gravitational/teleport/issues/new">create a GitHub issue.</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = NotFoundPage;
|
|
@ -1,5 +1,6 @@
|
|||
var React = require('react');
|
||||
var reactor = require('app/reactor');
|
||||
var { Link } = require('react-router');
|
||||
var {Table, Column, Cell, TextCell} = require('app/components/table.jsx');
|
||||
var {getters} = require('app/modules/sessions');
|
||||
var {open} = require('app/modules/activeTerminal/actions');
|
||||
|
@ -19,23 +20,15 @@ const UsersCell = ({ rowIndex, data, ...props }) => {
|
|||
};
|
||||
|
||||
const ButtonCell = ({ rowIndex, data, ...props }) => {
|
||||
let onClick = () => {
|
||||
var rowData = data[rowIndex];
|
||||
var {sid, addr} = rowData
|
||||
var login = rowData.login;
|
||||
open(addr, login, sid);
|
||||
}
|
||||
|
||||
var sessionUrl = data[rowIndex].sessionUrl;
|
||||
return (
|
||||
<Cell {...props}>
|
||||
<button onClick={onClick} className="btn btn-info btn-circle" type="button">
|
||||
<Link to={sessionUrl} className="btn btn-info btn-circle" type="button">
|
||||
<i className="fa fa-terminal"></i>
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
<button className="btn btn-info btn-circle" type="button">
|
||||
<i className="fa fa-play-circle"></i>
|
||||
</button>
|
||||
|
||||
</Cell>
|
||||
)
|
||||
}
|
||||
|
@ -71,13 +64,13 @@ var SessionList = React.createClass({
|
|||
}
|
||||
/>
|
||||
<Column
|
||||
columnKey="addr"
|
||||
columnKey="serverIp"
|
||||
header={<Cell> Node </Cell> }
|
||||
cell={<TextCell data={data} /> }
|
||||
/>
|
||||
|
||||
<Column
|
||||
columnKey="addr"
|
||||
columnKey="serverId"
|
||||
header={<Cell> Users </Cell> }
|
||||
cell={<UsersCell data={data} /> }
|
||||
/>
|
||||
|
|
|
@ -34,7 +34,7 @@ var TtyTerminal = React.createClass({
|
|||
this.term.open(this.refs.container);
|
||||
this.term.on('data', (data) => this.tty.send(data));
|
||||
|
||||
this.resize(this.rows, this.cols);
|
||||
this.resize(this.cols, this.rows);
|
||||
|
||||
this.tty.on('open', ()=> this.term.write(CONNECTED_TXT));
|
||||
this.tty.on('close', ()=> this.term.write(DISCONNECT_TXT));
|
||||
|
@ -57,7 +57,7 @@ var TtyTerminal = React.createClass({
|
|||
}
|
||||
|
||||
if(rows !== this.rows || cols !== this.cols){
|
||||
this.resize(rows, cols)
|
||||
this.resize(cols, rows)
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -8,10 +8,15 @@ let cfg = {
|
|||
renewTokenPath:'/v1/webapi/sessions/renew',
|
||||
nodesPath: '/v1/webapi/sites/-current-/nodes',
|
||||
sessionPath: '/v1/webapi/sessions',
|
||||
fetchSessionPath: '/v1/webapi/sites/-current-/sessions/:sid',
|
||||
terminalSessionPath: '/v1/webapi/sites/-current-/sessions/:sid',
|
||||
invitePath: '/v1/webapi/users/invites/:inviteToken',
|
||||
createUserPath: '/v1/webapi/users',
|
||||
|
||||
getFetchSessionUrl: (sid)=>{
|
||||
return formatPattern(cfg.api.fetchSessionPath, {sid});
|
||||
},
|
||||
|
||||
getTerminalSessionUrl: (sid)=> {
|
||||
return formatPattern(cfg.api.terminalSessionPath, {sid});
|
||||
},
|
||||
|
@ -25,9 +30,9 @@ let cfg = {
|
|||
return `${hostname}/v1/webapi/sites/-current-/sessions/${sid}/events/stream?access_token=${token}`;
|
||||
},
|
||||
|
||||
getTtyConnStr: ({token, addr, login, sid, rows, cols}) => {
|
||||
getTtyConnStr: ({token, serverId, login, sid, rows, cols}) => {
|
||||
var params = {
|
||||
addr,
|
||||
server_id: serverId,
|
||||
login,
|
||||
sid,
|
||||
term: {
|
||||
|
@ -48,11 +53,15 @@ let cfg = {
|
|||
logout: '/web/logout',
|
||||
login: '/web/login',
|
||||
nodes: '/web/nodes',
|
||||
activeSession: '/web/active-session/:sid',
|
||||
activeSession: '/web/sessions/:sid',
|
||||
newUser: '/web/newuser/:inviteToken',
|
||||
sessions: '/web/sessions'
|
||||
}
|
||||
sessions: '/web/sessions',
|
||||
pageNotFound: '/web/notfound'
|
||||
},
|
||||
|
||||
getActiveSessionRouteUrl(sid){
|
||||
return formatPattern(cfg.routes.activeSession, {sid});
|
||||
}
|
||||
}
|
||||
|
||||
export default cfg;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
var React = require('react');
|
||||
var render = require('react-dom').render;
|
||||
var { Router, Route, Redirect, IndexRoute, browserHistory } = require('react-router');
|
||||
var { App, Login, Nodes, Sessions, NewUser, ActiveSession } = require('./components');
|
||||
var { App, Login, Nodes, Sessions, NewUser, ActiveSessionHost, NotFoundPage } = require('./components');
|
||||
var {ensureUser} = require('./modules/user/actions');
|
||||
var auth = require('./auth');
|
||||
var session = require('./session');
|
||||
|
@ -21,10 +21,12 @@ render((
|
|||
<Route path={cfg.routes.login} component={Login}/>
|
||||
<Route path={cfg.routes.logout} onEnter={handleLogout}/>
|
||||
<Route path={cfg.routes.newUser} component={NewUser}/>
|
||||
<Redirect from={cfg.routes.app} to={cfg.routes.nodes}/>
|
||||
<Route path={cfg.routes.app} component={App} onEnter={ensureUser} >
|
||||
<IndexRoute component={Nodes}/>
|
||||
<Route path={cfg.routes.nodes} component={Nodes}/>
|
||||
<Route path={cfg.routes.activeSession} components={{activeSessionHost: ActiveSessionHost}}/>
|
||||
<Route path={cfg.routes.sessions} component={Sessions}/>
|
||||
</Route>
|
||||
<Route path="*" component={NotFoundPage} />
|
||||
</Router>
|
||||
), document.getElementById("app"));
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
var reactor = require('app/reactor');
|
||||
var api = require('app/services/api');
|
||||
var cfg = require('app/config');
|
||||
|
||||
var { TLPT_SESSINS_RECEIVE } = require('./sessions/actionTypes');
|
||||
var { TLPT_NODES_RECEIVE } = require('./nodes/actionTypes');
|
||||
|
||||
export default {
|
||||
fetchNodesAndSessions(){
|
||||
api.get(cfg.api.nodesPath).done(json=>{
|
||||
var nodeArray = [];
|
||||
var sessions = {};
|
||||
|
||||
json.nodes.forEach(item=> {
|
||||
nodeArray.push(item.node);
|
||||
if(item.sessions){
|
||||
item.sessions.forEach(item2=>{
|
||||
sessions[item2.id] = item2;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
reactor.batch(() => {
|
||||
reactor.dispatch(TLPT_NODES_RECEIVE, nodeArray);
|
||||
reactor.dispatch(TLPT_SESSINS_RECEIVE, sessions);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
|
@ -2,7 +2,5 @@ import keyMirror from 'keymirror'
|
|||
|
||||
export default keyMirror({
|
||||
TLPT_TERM_OPEN: null,
|
||||
TLPT_TERM_CLOSE: null,
|
||||
TLPT_TERM_CONNECTED: null,
|
||||
TLPT_TERM_RECEIVE_PARTIES: null
|
||||
TLPT_TERM_CLOSE: null
|
||||
})
|
||||
|
|
|
@ -1,51 +1,76 @@
|
|||
var reactor = require('app/reactor');
|
||||
var session = require('app/session');
|
||||
var {uuid} = require('app/utils');
|
||||
var api = require('app/services/api');
|
||||
var cfg = require('app/config');
|
||||
var invariant = require('invariant');
|
||||
var getters = require('./getters');
|
||||
var sessionModule = require('./../sessions');
|
||||
|
||||
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE, TLPT_TERM_CONNECTED, TLPT_TERM_RECEIVE_PARTIES } = require('./actionTypes');
|
||||
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE } = require('./actionTypes');
|
||||
|
||||
export default {
|
||||
var actions = {
|
||||
|
||||
close(){
|
||||
let {isNewSession} = reactor.evaluate(getters.activeSession);
|
||||
|
||||
reactor.dispatch(TLPT_TERM_CLOSE);
|
||||
|
||||
if(isNewSession){
|
||||
session.getHistory().push(cfg.routes.nodes);
|
||||
}else{
|
||||
session.getHistory().push(cfg.routes.sessions);
|
||||
}
|
||||
},
|
||||
|
||||
resize(w, h){
|
||||
invariant(w > 5 || h > 5, 'invalid resize parameters');
|
||||
// some min values
|
||||
w = w < 5 ? 5 : w;
|
||||
h = h < 5 ? 5 : h;
|
||||
|
||||
let reqData = { terminal_params: { w, h } };
|
||||
let {sid} = reactor.evaluate(getters.activeSession);
|
||||
|
||||
api.put(cfg.api.getTerminalSessionUrl(sid), reqData).done(()=>{
|
||||
console.log(`resize with ${w} and ${h} - OK`);
|
||||
}).fail(()=>{
|
||||
console.log(`failed to resize with ${w} and ${h}`);
|
||||
api.put(cfg.api.getTerminalSessionUrl(sid), reqData)
|
||||
.done(()=>{
|
||||
console.log(`resize with w:${w} and h:${h} - OK`);
|
||||
})
|
||||
.fail(()=>{
|
||||
console.log(`failed to resize with w:${w} and h:${h}`);
|
||||
})
|
||||
},
|
||||
|
||||
connected(){
|
||||
reactor.dispatch(TLPT_TERM_CONNECTED);
|
||||
openSession(sid){
|
||||
sessionModule.actions.fetchSession(sid)
|
||||
.done(()=>{
|
||||
let sView = reactor.evaluate(sessionModule.getters.sessionViewById(sid));
|
||||
let { serverId, login } = sView;
|
||||
reactor.dispatch(TLPT_TERM_OPEN, {
|
||||
serverId,
|
||||
login,
|
||||
sid,
|
||||
isNewSession: false
|
||||
});
|
||||
})
|
||||
.fail(()=>{
|
||||
session.getHistory().push(cfg.routes.pageNotFound);
|
||||
})
|
||||
},
|
||||
|
||||
receiveParties(json){
|
||||
var parties = json.map(item=>{
|
||||
return {
|
||||
user: item.user,
|
||||
lastActive: new Date(item.last_active)
|
||||
}
|
||||
})
|
||||
createNewSession(serverId, login){
|
||||
var sid = uuid();
|
||||
var routeUrl = cfg.getActiveSessionRouteUrl(sid);
|
||||
var history = session.getHistory();
|
||||
|
||||
reactor.dispatch(TLPT_TERM_RECEIVE_PARTIES, parties);
|
||||
},
|
||||
reactor.dispatch(TLPT_TERM_OPEN, {
|
||||
serverId,
|
||||
login,
|
||||
sid,
|
||||
isNewSession: true
|
||||
});
|
||||
|
||||
open(addr, login, sid){
|
||||
let isNew = !sid;
|
||||
if(isNew){
|
||||
sid = uuid();
|
||||
}
|
||||
|
||||
reactor.dispatch(TLPT_TERM_OPEN, {addr, login, sid, isNew} );
|
||||
history.push(routeUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default actions;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var { Store, toImmutable } = require('nuclear-js');
|
||||
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE, TLPT_TERM_CONNECTED, TLPT_TERM_RECEIVE_PARTIES } = require('./actionTypes');
|
||||
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE } = require('./actionTypes');
|
||||
|
||||
export default Store({
|
||||
getInitialState() {
|
||||
|
@ -7,30 +7,20 @@ export default Store({
|
|||
},
|
||||
|
||||
initialize() {
|
||||
this.on(TLPT_TERM_CONNECTED, connected);
|
||||
this.on(TLPT_TERM_OPEN, setActiveTerminal);
|
||||
this.on(TLPT_TERM_CLOSE, close);
|
||||
this.on(TLPT_TERM_RECEIVE_PARTIES, receiveParties);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
function close(){
|
||||
return toImmutable(null);
|
||||
}
|
||||
|
||||
function receiveParties(state, parties){
|
||||
return state.set('parties', toImmutable(parties));
|
||||
}
|
||||
|
||||
function setActiveTerminal(state, settings){
|
||||
return toImmutable({
|
||||
isConnecting: true,
|
||||
...settings
|
||||
function setActiveTerminal(state, {serverId, login, sid, isNewSession} ){
|
||||
return toImmutable({
|
||||
serverId,
|
||||
login,
|
||||
sid,
|
||||
isNewSession
|
||||
});
|
||||
}
|
||||
|
||||
function connected(state){
|
||||
return state.set('isConnected', true)
|
||||
.set('isConnecting', false);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,10 @@ const activeSession = [
|
|||
}
|
||||
|
||||
let view = {
|
||||
isNew: activeTerm.get('isNew'),
|
||||
isNewSession: activeTerm.get('isNewSession'),
|
||||
notFound: activeTerm.get('notFound'),
|
||||
addr: activeTerm.get('addr'),
|
||||
serverId: activeTerm.get('serverId'),
|
||||
login: activeTerm.get('login'),
|
||||
sid: activeTerm.get('sid'),
|
||||
cols: undefined,
|
||||
|
@ -15,8 +17,8 @@ const activeSession = [
|
|||
};
|
||||
|
||||
if(sessions.has(view.sid)){
|
||||
view.cols = sessions.getIn([view.sid, 'terminal_params', 'H']);
|
||||
view.rows = sessions.getIn([view.sid, 'terminal_params', 'W']);
|
||||
view.cols = sessions.getIn([view.sid, 'terminal_params', 'w']);
|
||||
view.rows = sessions.getIn([view.sid, 'terminal_params', 'h']);
|
||||
}
|
||||
|
||||
return view;
|
||||
|
|
7
web/src/app/modules/app/actionTypes.js
Normal file
7
web/src/app/modules/app/actionTypes.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import keyMirror from 'keymirror'
|
||||
|
||||
export default keyMirror({
|
||||
TLPT_APP_INIT: null,
|
||||
TLPT_APP_FAILED: null,
|
||||
TLPT_APP_READY: null
|
||||
})
|
43
web/src/app/modules/app/actions.js
Normal file
43
web/src/app/modules/app/actions.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
var reactor = require('app/reactor');
|
||||
var api = require('app/services/api');
|
||||
var cfg = require('app/config');
|
||||
|
||||
var { TLPT_SESSINS_RECEIVE } = require('./../sessions/actionTypes');
|
||||
var { TLPT_NODES_RECEIVE } = require('./../nodes/actionTypes');
|
||||
var { TLPT_APP_INIT, TLPT_APP_FAILED, TLPT_APP_READY } = require('./actionTypes');
|
||||
|
||||
export default {
|
||||
|
||||
initApp() {
|
||||
reactor.dispatch(TLPT_APP_INIT);
|
||||
module.exports.fetchNodesAndSessions()
|
||||
.done(()=>{
|
||||
reactor.dispatch(TLPT_APP_READY);
|
||||
})
|
||||
.fail(()=>{
|
||||
reactor.dispatch(TLPT_APP_FAILED);
|
||||
});
|
||||
},
|
||||
|
||||
fetchNodesAndSessions() {
|
||||
return api.get(cfg.api.nodesPath).done(json => {
|
||||
var nodeArray = [];
|
||||
var sessions = {};
|
||||
|
||||
json.nodes.forEach(item => {
|
||||
nodeArray.push(item.node);
|
||||
if (item.sessions) {
|
||||
item.sessions.forEach(item2 => {
|
||||
sessions[item2.id] = item2;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
reactor.batch(() => {
|
||||
reactor.dispatch(TLPT_NODES_RECEIVE, nodeArray);
|
||||
reactor.dispatch(TLPT_SESSINS_RECEIVE, sessions);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
22
web/src/app/modules/app/appStore.js
Normal file
22
web/src/app/modules/app/appStore.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
var { Store, toImmutable } = require('nuclear-js');
|
||||
|
||||
var { TLPT_APP_INIT, TLPT_APP_FAILED, TLPT_APP_READY } = require('./actionTypes');
|
||||
|
||||
var initState = toImmutable({
|
||||
isReady: false,
|
||||
isInitializing: false,
|
||||
isFailed: false
|
||||
});
|
||||
|
||||
export default Store({
|
||||
|
||||
getInitialState() {
|
||||
return initState.set('isInitializing', true);
|
||||
},
|
||||
|
||||
initialize() {
|
||||
this.on(TLPT_APP_INIT, ()=> initState.set('isInitializing', true));
|
||||
this.on(TLPT_APP_READY,()=> initState.set('isReady', true));
|
||||
this.on(TLPT_APP_FAILED,()=> initState.set('isFailed', true));
|
||||
}
|
||||
})
|
5
web/src/app/modules/app/getters.js
Normal file
5
web/src/app/modules/app/getters.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const appState = [['tlpt'], app=> app.toJS()];
|
||||
|
||||
export default {
|
||||
appState
|
||||
}
|
3
web/src/app/modules/app/index.js
Normal file
3
web/src/app/modules/app/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports.getters = require('./getters');
|
||||
module.exports.actions = require('./actions');
|
||||
module.exports.appStore = require('./appStore');
|
|
@ -1,9 +1,10 @@
|
|||
var reactor = require('app/reactor');
|
||||
reactor.registerStores({
|
||||
'tlpt': require('./app/appStore'),
|
||||
'tlpt_active_terminal': require('./activeTerminal/activeTermStore'),
|
||||
'tlpt_user': require('./user/userStore'),
|
||||
'tlpt_nodes': require('./nodes/nodeStore'),
|
||||
'tlpt_invite': require('./invite/inviteStore'),
|
||||
'tlpt_rest_api': require('./restApi/restApiStore'),
|
||||
'tlpt_sessions': require('./sessions/sessionStore')
|
||||
'tlpt_sessions': require('./sessions/sessionStore')
|
||||
});
|
||||
|
|
|
@ -3,11 +3,13 @@ var {sessionsByServer} = require('./../sessions/getters');
|
|||
|
||||
const nodeListView = [ ['tlpt_nodes'], (nodes) =>{
|
||||
return nodes.map((item)=>{
|
||||
var addr = item.get('addr');
|
||||
var sessions = reactor.evaluate(sessionsByServer(addr));
|
||||
var serverId = item.get('id');
|
||||
var sessions = reactor.evaluate(sessionsByServer(serverId));
|
||||
return {
|
||||
id: serverId,
|
||||
hostname: item.get('hostname'),
|
||||
tags: getTags(item),
|
||||
addr: addr,
|
||||
addr: item.get('addr'),
|
||||
sessionCount: sessions.size
|
||||
}
|
||||
}).toJS();
|
||||
|
@ -44,5 +46,5 @@ function getTags(node){
|
|||
|
||||
|
||||
export default {
|
||||
nodeListView
|
||||
nodeListView
|
||||
}
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
var reactor = require('app/reactor');
|
||||
var api = require('app/services/api');
|
||||
var cfg = require('app/config');
|
||||
|
||||
var { TLPT_SESSINS_RECEIVE, TLPT_SESSINS_UPDATE } = require('./actionTypes');
|
||||
|
||||
export default {
|
||||
|
||||
fetchSession(sid){
|
||||
return api.get(cfg.api.getFetchSessionUrl(sid)).then(json=>{
|
||||
if(json && json.session){
|
||||
reactor.dispatch(TLPT_SESSINS_UPDATE, json.session);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateSession(json){
|
||||
reactor.dispatch(TLPT_SESSINS_UPDATE, json);
|
||||
},
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
var { toImmutable } = require('nuclear-js');
|
||||
var reactor = require('app/reactor');
|
||||
var cfg = require('app/config');
|
||||
|
||||
const sessionsByServer = (addr) => [['tlpt_sessions'], (sessions) =>{
|
||||
const sessionsByServer = (serverId) => [['tlpt_sessions'], (sessions) =>{
|
||||
return sessions.valueSeq().filter(item=>{
|
||||
var parties = item.get('parties') || toImmutable([]);
|
||||
var hasServer = parties.find(item2=> item2.get('server_addr') === addr);
|
||||
var hasServer = parties.find(item2=> item2.get('server_id') === serverId);
|
||||
return hasServer;
|
||||
}).toList();
|
||||
}]
|
||||
|
||||
const sessionsView = [['tlpt_sessions'], (sessions) =>{
|
||||
return sessions.valueSeq().map(item=>{
|
||||
var sid = item.get('id');
|
||||
var parties = reactor.evaluate(partiesBySessionId(sid));
|
||||
return {
|
||||
sid: sid,
|
||||
addr: parties[0].addr,
|
||||
login: item.get('login'),
|
||||
parties: parties
|
||||
}
|
||||
}).toJS();
|
||||
return sessions.valueSeq().map(createView).toJS();
|
||||
}];
|
||||
|
||||
const sessionViewById = (sid)=> [['tlpt_sessions', sid], (session)=>{
|
||||
if(!session){
|
||||
return null;
|
||||
}
|
||||
|
||||
return createView(session);
|
||||
}];
|
||||
|
||||
const partiesBySessionId = (sid) =>
|
||||
|
@ -35,7 +35,8 @@ const partiesBySessionId = (sid) =>
|
|||
var user = item.get('user');
|
||||
return {
|
||||
user: item.get('user'),
|
||||
addr: item.get('server_addr'),
|
||||
serverIp: item.get('remote_addr'),
|
||||
serverId: item.get('server_id'),
|
||||
isActive: lastActiveUsrName === user
|
||||
}
|
||||
}).toJS();
|
||||
|
@ -45,8 +46,29 @@ function getLastActiveUser(parties){
|
|||
return parties.sortBy(item=> new Date(item.get('lastActive'))).first();
|
||||
}
|
||||
|
||||
function createView(session){
|
||||
var sid = session.get('id');
|
||||
var serverIp, serverId;
|
||||
var parties = reactor.evaluate(partiesBySessionId(sid));
|
||||
|
||||
if(parties.length > 0){
|
||||
serverIp = parties[0].serverIp;
|
||||
serverId = parties[0].serverId;
|
||||
}
|
||||
|
||||
return {
|
||||
sid: sid,
|
||||
sessionUrl: cfg.getActiveSessionRouteUrl(sid),
|
||||
serverIp,
|
||||
serverId,
|
||||
login: session.get('login'),
|
||||
parties: parties
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
partiesBySessionId,
|
||||
sessionsByServer,
|
||||
sessionsView
|
||||
sessionsView,
|
||||
sessionViewById
|
||||
}
|
||||
|
|
|
@ -17,5 +17,5 @@ function updateSession(state, json){
|
|||
}
|
||||
|
||||
function receiveSessions(state, json){
|
||||
return state.merge(json);
|
||||
return toImmutable(json);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export default {
|
|||
|
||||
ensureUser(nextState, replace, cb){
|
||||
auth.ensureUser()
|
||||
.done((userData)=> {
|
||||
.done((userData)=> {
|
||||
reactor.dispatch(TLPT_RECEIVE_USER, userData.user );
|
||||
cb();
|
||||
})
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@import "grv-sessions";
|
||||
@import "grv-nav";
|
||||
@import "grv-terminal-host";
|
||||
@import "grv-page-notfound";
|
||||
|
||||
.grv {
|
||||
background-color: white;
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
|
||||
> li.active{
|
||||
border: none;
|
||||
background: #2f4050;
|
||||
background-color: #293846;
|
||||
}
|
||||
|
||||
li:hover{
|
||||
background-color: #2f4050;
|
||||
li:hover{
|
||||
}
|
||||
|
||||
li:first-child{
|
||||
|
|
14
web/src/styles/grv-page-notfound.scss
Normal file
14
web/src/styles/grv-page-notfound.scss
Normal file
|
@ -0,0 +1,14 @@
|
|||
.grv-page-notfound{
|
||||
|
||||
margin: 0 auto;
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
|
||||
.grv-warning{
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.contact-section{
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue