(web) adding SelectNodeDialog

This commit is contained in:
Alexey Kontsevoy 2016-03-08 20:32:38 -05:00
parent d7c2980ddb
commit ce99c40f81
20 changed files with 212 additions and 31 deletions

View file

@ -15,6 +15,11 @@ class Tty extends EventEmitter {
this.socket.close();
}
reconnect(options){
this.socket.close();
this.connect(options);
}
connect(options){
Object.assign(this.options, options);

View file

@ -3,6 +3,7 @@ var NavLeftBar = require('./navLeftBar');
var cfg = require('app/config');
var reactor = require('app/reactor');
var {actions, getters} = require('app/modules/app');
var SelectNodeDialog = require('./selectNodeDialog.jsx');
var App = React.createClass({
@ -16,7 +17,7 @@ var App = React.createClass({
componentWillMount(){
actions.initApp();
this.refreshInterval = setInterval(actions.fetchNodesAndSessions, 3000);
this.refreshInterval = setInterval(actions.fetchNodesAndSessions, 35000);
},
componentWillUnmount: function() {
@ -31,6 +32,7 @@ var App = React.createClass({
return (
<div className="grv-tlpt">
<NavLeftBar/>
<SelectNodeDialog/>
{this.props.CurrentSessionHost}
<div className="row">
<nav className="" role="navigation" style={{ marginBottom: 0, float: "right" }}>

View file

@ -4,25 +4,24 @@ var Tty = require('app/common/tty');
var TtyTerminal = require('./../terminal.jsx');
var EventStreamer = require('./eventStreamer.jsx');
var SessionLeftPanel = require('./sessionLeftPanel');
var {showSelectNodeDialog, closeSelectNodeDialog} = require('app/modules/dialogs/actions');
var ActiveSession = React.createClass({
componentWillUnmount(){
closeSelectNodeDialog();
},
render: function() {
var {serverIp} = this.props.activeSession;
return (
<div className="grv-current-session">
<SessionLeftPanel/>
<div>
{/*<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">
<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>
</div>*/}
<div className="grv-current-session-server-info">
<h3>{serverIp}<span className="btn label label-primary" onClick={showSelectNodeDialog} >Change node</span>
</h3>
</div>
</div>
<TtyConnection {...this.props.activeSession} />
</div>
@ -42,8 +41,14 @@ var TtyConnection = React.createClass({
this.tty.disconnect();
},
render() {
componentWillReceiveProps(nextProps){
if(nextProps.serverId !== this.props.serverId ||
nextProps.login !== this.props.login){
this.tty.reconnect(nextProps);
}
},
render() {
return (
<div style={{height: '100%'}}>
<TtyTerminal tty={this.tty} cols={this.props.cols} rows={this.props.rows} />

View file

@ -22,7 +22,7 @@ const TagCell = ({rowIndex, data, columnKey, ...props}) => (
</Cell>
);
const LoginCell = ({user, rowIndex, data, ...props}) => {
const LoginCell = ({user, onLoginClick, rowIndex, data, ...props}) => {
if(!user || user.logins.length === 0){
return <Cell {...props} />;
}
@ -30,19 +30,23 @@ const LoginCell = ({user, rowIndex, data, ...props}) => {
var serverId = data[rowIndex].id;
var $lis = [];
function onNewSessionClick(i){
function onClick(i){
var login = user.logins[i];
return () => createNewSession(serverId, login);
if(onLoginClick){
return ()=> onLoginClick(serverId, login);
}else{
return () => createNewSession(serverId, login);
}
}
for(var i = 0; i < user.logins.length; i++){
$lis.push(<li key={i}><a onClick={onNewSessionClick(i)}>{user.logins[i]}</a></li>);
$lis.push(<li key={i}><a onClick={onClick(i)}>{user.logins[i]}</a></li>);
}
return (
<Cell {...props}>
<div className="btn-group">
<button type="button" onClick={onNewSessionClick(0)} className="btn btn-sm btn-primary">{user.logins[0]}</button>
<button type="button" onClick={onClick(0)} className="btn btn-sm btn-primary">{user.logins[0]}</button>
{
$lis.length > 1 ? (
[
@ -73,6 +77,7 @@ var Nodes = React.createClass({
render: function() {
var data = this.state.nodeRecords;
var onLoginClick = this.props.onLoginClick;
return (
<div className="grv-nodes">
<h1> Nodes </h1>
@ -97,6 +102,7 @@ var Nodes = React.createClass({
/>
<Column
columnKey="roles"
onLoginClick={onLoginClick}
header={<Cell>Login as</Cell> }
cell={<LoginCell data={data} user={this.state.user}/> }
/>

View file

@ -0,0 +1,60 @@
var React = require('react');
var reactor = require('app/reactor');
var {getters} = require('app/modules/dialogs');
var {closeSelectNodeDialog} = require('app/modules/dialogs/actions');
var {changeServer} = require('app/modules/activeTerminal/actions');
var NodeList = require('./nodes/main.jsx');
var SelectNodeDialog = React.createClass({
mixins: [reactor.ReactMixin],
getDataBindings() {
return {
dialogs: getters.dialogs
}
},
render() {
return this.state.dialogs.isSelectNodeDialogOpen ? <Dialog/> : null;
}
});
var Dialog = React.createClass({
onLoginClick(serverId, login){
changeServer(serverId, login);
closeSelectNodeDialog();
},
componentWillUnmount(callback){
$('.modal').modal('hide');
},
componentDidMount(){
$('.modal').modal('show');
},
render() {
return (
<div className="modal fade grv-dialog-select-node" tabIndex={-1} role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
</div>
<div className="modal-body">
<NodeList onLoginClick={this.onLoginClick}/>
</div>
<div className="modal-footer">
<button onClick={closeSelectNodeDialog} type="button" className="btn btn-primary">
Close
</button>
</div>
</div>
</div>
</div>
);
}
});
module.exports = SelectNodeDialog;

View file

@ -2,5 +2,6 @@ import keyMirror from 'keymirror'
export default keyMirror({
TLPT_TERM_OPEN: null,
TLPT_TERM_CLOSE: null
TLPT_TERM_CLOSE: null,
TLPT_TERM_CHANGE_SERVER: null
})

View file

@ -6,10 +6,17 @@ var cfg = require('app/config');
var getters = require('./getters');
var sessionModule = require('./../sessions');
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE } = require('./actionTypes');
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE, TLPT_TERM_CHANGE_SERVER } = require('./actionTypes');
var actions = {
changeServer(serverId, login){
reactor.dispatch(TLPT_TERM_CHANGE_SERVER, {
serverId,
login
});
},
close(){
let {isNewSession} = reactor.evaluate(getters.activeSession);

View file

@ -1,5 +1,5 @@
var { Store, toImmutable } = require('nuclear-js');
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE } = require('./actionTypes');
var { TLPT_TERM_OPEN, TLPT_TERM_CLOSE, TLPT_TERM_CHANGE_SERVER } = require('./actionTypes');
export default Store({
getInitialState() {
@ -9,9 +9,15 @@ export default Store({
initialize() {
this.on(TLPT_TERM_OPEN, setActiveTerminal);
this.on(TLPT_TERM_CLOSE, close);
this.on(TLPT_TERM_CHANGE_SERVER, changeServer);
}
})
function changeServer(state, {serverId, login}){
return state.set('serverId', serverId)
.set('login', login);
}
function close(){
return toImmutable(null);
}

View file

@ -1,3 +1,5 @@
var {createView} = require('app/modules/sessions/getters');
const activeSession = [
['tlpt_active_terminal'], ['tlpt_sessions'],
(activeTerm, sessions) => {
@ -5,26 +7,37 @@ const activeSession = [
return null;
}
let view = {
/*
* active session needs to have its own view as an actual session might not
* exist at this point. For example, upon creating a new session we need to know
* login and serverId. It will be simplified once server API gets extended.
*/
let asView = {
isNewSession: activeTerm.get('isNewSession'),
notFound: activeTerm.get('notFound'),
addr: activeTerm.get('addr'),
serverId: activeTerm.get('serverId'),
serverIp: undefined,
login: activeTerm.get('login'),
sid: activeTerm.get('sid'),
cols: undefined,
rows: undefined
};
let session = sessions.get(view.sid);
// in case if session already exists, get the data from there
// (for example, when joining an existing session)
if(sessions.has(asView.sid)){
let sView = createView(sessions.get(asView.sid));
if(session){
view.active = session.get('active'),
view.cols = session.getIn(['terminal_params', 'w']);
view.rows = session.getIn(['terminal_params', 'h']);
asView.parties = sView.parties;
asView.serverIp = sView.serverIp;
asView.serverId = sView.serverId;
asView.active = sView.active;
asView.cols = sView.cols;
asView.rows = sView.rows;
}
return view;
return asView;
}
];

View file

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

View file

@ -0,0 +1,14 @@
var reactor = require('app/reactor');
var { TLPT_DIALOG_SHOW_SELECT_NODE, TLPT_DIALOG_CLOSE_SELECT_NODE } = require('./actionTypes');
var actions = {
showSelectNodeDialog(){
reactor.dispatch(TLPT_DIALOG_SHOW_SELECT_NODE);
},
closeSelectNodeDialog(){
reactor.dispatch(TLPT_DIALOG_CLOSE_SELECT_NODE);
}
}
export default actions;

View file

@ -0,0 +1,25 @@
var { Store, toImmutable } = require('nuclear-js');
var { TLPT_DIALOG_SHOW_SELECT_NODE, TLPT_DIALOG_CLOSE_SELECT_NODE } = require('./actionTypes');
export default Store({
getInitialState() {
return toImmutable({
isSelectNodeDialogOpen: false
});
},
initialize() {
this.on(TLPT_DIALOG_SHOW_SELECT_NODE, showSelectNodeDialog);
this.on(TLPT_DIALOG_CLOSE_SELECT_NODE, closeSelectNodeDialog);
}
})
function showSelectNodeDialog(state){
return state.set('isSelectNodeDialogOpen', true);
}
function closeSelectNodeDialog(state){
return state.set('isSelectNodeDialogOpen', false);
}

View file

@ -0,0 +1,5 @@
const dialogs = [['tlpt_dialogs'], state=> state.toJS()];
export default {
dialogs
}

View file

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

View file

@ -1,6 +1,7 @@
var reactor = require('app/reactor');
reactor.registerStores({
'tlpt': require('./app/appStore'),
'tlpt_dialogs': require('./dialogs/dialogStore'),
'tlpt_active_terminal': require('./activeTerminal/activeTermStore'),
'tlpt_user': require('./user/userStore'),
'tlpt_nodes': require('./nodes/nodeStore'),

View file

@ -65,7 +65,9 @@ function createView(session){
created: new Date(session.get('created')),
lastActive: new Date(session.get('last_active')),
login: session.get('login'),
parties: parties
parties: parties,
cols: session.getIn(['terminal_params', 'w']),
rows: session.getIn(['terminal_params', 'h'])
}
}
@ -73,5 +75,6 @@ export default {
partiesBySessionId,
sessionsByServer,
sessionsView,
sessionViewById
sessionViewById,
createView
}

View file

@ -49,6 +49,7 @@ $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
//@import "~bootstrap-sass/assets/stylesheets/bootstrap/wells";
//@import "~bootstrap-sass/assets/stylesheets/bootstrap/close";
//
@import "~bootstrap-sass/assets/stylesheets/bootstrap/modals";
//@import "~bootstrap-sass/assets/stylesheets/bootstrap/tooltip";
//@import "~bootstrap-sass/assets/stylesheets/bootstrap/popovers";
//@import "~bootstrap-sass/assets/stylesheets/bootstrap/carousel";

View file

@ -10,6 +10,7 @@
@import "grv-slider";
@import "grv-session-player";
@import "grv-terminal";
@import "grv-dialog-select-node";
.grv {
background-color: white;

View file

@ -22,3 +22,11 @@
}
}
}
.grv-current-session-server-info{
text-align: center;
span{
margin-left: 5px
}
}

View file

@ -0,0 +1,9 @@
.grv-dialog-select-node{
.modal-header{
border: none;
}
.modal-footer{
border: none;
}
}