mirror of
https://github.com/gravitational/teleport
synced 2024-10-22 10:13:21 +00:00
(web) adding SelectNodeDialog
This commit is contained in:
parent
d7c2980ddb
commit
ce99c40f81
|
@ -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);
|
||||
|
||||
|
|
|
@ -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" }}>
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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}/> }
|
||||
/>
|
||||
|
|
60
web/src/app/components/selectNodeDialog.jsx
Normal file
60
web/src/app/components/selectNodeDialog.jsx
Normal 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;
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
];
|
||||
|
|
6
web/src/app/modules/dialogs/actionTypes.js
Normal file
6
web/src/app/modules/dialogs/actionTypes.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import keyMirror from 'keymirror'
|
||||
|
||||
export default keyMirror({
|
||||
TLPT_DIALOG_SHOW_SELECT_NODE: null,
|
||||
TLPT_DIALOG_CLOSE_SELECT_NODE: null
|
||||
})
|
14
web/src/app/modules/dialogs/actions.js
Normal file
14
web/src/app/modules/dialogs/actions.js
Normal 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;
|
25
web/src/app/modules/dialogs/dialogStore.js
Normal file
25
web/src/app/modules/dialogs/dialogStore.js
Normal 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);
|
||||
}
|
5
web/src/app/modules/dialogs/getters.js
Normal file
5
web/src/app/modules/dialogs/getters.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const dialogs = [['tlpt_dialogs'], state=> state.toJS()];
|
||||
|
||||
export default {
|
||||
dialogs
|
||||
}
|
3
web/src/app/modules/dialogs/index.js
Normal file
3
web/src/app/modules/dialogs/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports.getters = require('./getters');
|
||||
module.exports.actions = require('./actions');
|
||||
module.exports.dialogStore = require('./dialogStore');
|
|
@ -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'),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
1
web/src/styles/bootstrap.scss
vendored
1
web/src/styles/bootstrap.scss
vendored
|
@ -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";
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
@import "grv-slider";
|
||||
@import "grv-session-player";
|
||||
@import "grv-terminal";
|
||||
@import "grv-dialog-select-node";
|
||||
|
||||
.grv {
|
||||
background-color: white;
|
||||
|
|
|
@ -22,3 +22,11 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.grv-current-session-server-info{
|
||||
text-align: center;
|
||||
span{
|
||||
margin-left: 5px
|
||||
}
|
||||
}
|
||||
|
|
9
web/src/styles/grv-dialog-select-node.scss
Normal file
9
web/src/styles/grv-dialog-select-node.scss
Normal file
|
@ -0,0 +1,9 @@
|
|||
.grv-dialog-select-node{
|
||||
.modal-header{
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-footer{
|
||||
border: none;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue