Displays ports and volumes dropdown.

This commit is contained in:
Sean Li 2015-01-27 13:02:58 -08:00
parent d80d259f98
commit b484233d4c
5 changed files with 152 additions and 6 deletions

View File

@ -11,6 +11,8 @@ var ContainerUtil = require('./ContainerUtil');
var docker = require('./docker');
var boot2docker = require('./boot2docker');
var ProgressBar = require('react-bootstrap/ProgressBar');
var Popover = require('react-bootstrap/Popover');
var OverlayTrigger = require('react-bootstrap/OverlayTrigger');
var Route = Router.Route;
var NotFoundRoute = Router.NotFoundRoute;
@ -28,7 +30,9 @@ var ContainerDetails = React.createClass({
logs: [],
page: this.PAGE_LOGS,
env: {},
pendingEnv: {}
pendingEnv: {},
ports: {},
volumes: {}
};
},
componentWillReceiveProps: function () {
@ -59,8 +63,14 @@ var ContainerDetails = React.createClass({
},
init: function () {
this.setState({
env: ContainerUtil.env(ContainerStore.container(this.getParams().name))
env: ContainerUtil.env(ContainerStore.container(this.getParams().name)),
volumes: ContainerUtil.volumes(ContainerStore.container(this.getParams().name))
});
ContainerUtil.ports(ContainerStore.container(this.getParams().name), function (err, ports) {
this.setState({
ports: ports
});
}.bind(this));
ContainerStore.fetchLogs(this.getParams().name, function () {
this.updateLogs();
}.bind(this));
@ -115,6 +125,11 @@ var ContainerDetails = React.createClass({
});
});
},
handleViewLink: function (url) {
exec(['open', url], function (err) {
if (err) { throw err; }
});
},
handleTerminal: function () {
var container = this.props.container;
var terminal = path.join(process.cwd(), 'resources', 'terminal').replace(/ /g, '\\\\ ');
@ -125,6 +140,18 @@ var ContainerDetails = React.createClass({
}
});
},
handleSaveContainerName: function () {
var newName = $('#input-container-name').val();
var self = this;
console.log(newName);
ContainerStore.updateContainer(self.props.container.Name, {
name: newName
}, function (err) {
if (err) {
console.error(err);
}
});
},
handleSaveEnvVar: function () {
var $rows = $('.env-vars .keyval-row');
var envVarList = [];
@ -259,7 +286,10 @@ var ContainerDetails = React.createClass({
<div className="details-panel">
<div className="settings">
<h3>Container Name</h3>
<input id="input-container-name" type="text" className="line" placeholder="Container Name" defaultValue={this.props.container.Name}></input>
<div className="container-name">
<input id="input-container-name" type="text" className="line" placeholder="Container Name" defaultValue={this.props.container.Name}></input>
</div>
<a className="btn btn-action" onClick={this.handleSaveContainerName}>Save</a>
<h3>Environment Variables</h3>
<div className="env-vars-labels">
<div className="label-key">KEY</div>
@ -317,6 +347,29 @@ var ContainerDetails = React.createClass({
disabled: this.props.container.State.Downloading
});
var viewPopoverClasses = React.addons.classSet({
popover: true,
hidden: false
});
var ports = _.map(self.state.ports, function (val, key) {
return (
<div port={key} className="port-row">
<span>{key}</span>
<a onClick={self.handleViewLink.bind(self, val.url)}>{val.display}</a>
</div>
);
});
var volumes = _.map(self.state.volumes, function (val, key) {
return (
<div port={key} className="port-row">
<span>{key}</span>
<a>{val}</a>
</div>
);
});
return (
<div className="details">
<div className="details-header">
@ -325,10 +378,35 @@ var ContainerDetails = React.createClass({
</div>
<div className="details-header-actions">
<div className="action btn-group">
<a className={buttonClass} onClick={this.handleView}><span className="icon icon-preview-2"></span><span className="content">View</span></a><a className={dropdownButtonClass}><span className="icon-dropdown icon icon-arrow-37"></span></a>
<a className={buttonClass} onClick={this.handleView}><span className="icon icon-preview-2"></span><span className="content">View</span></a>
<OverlayTrigger trigger="click" placement="bottom" overlay={
<Popover className="popover-view">
<div className="port-labels">
<div className="label-docker">DOCKER PORT</div>
<div className="label-local">LOCAL PORT</div>
</div>
<div className="ports">
{ports}
</div>
</Popover>
}>
<a className={dropdownButtonClass}><span className="icon-dropdown icon icon-arrow-37"></span></a>
</OverlayTrigger>
</div>
<div className="action">
<a className={dropdownButtonClass} onClick={this.handleView}><span className="icon icon-folder-1"></span> <span className="content">Volumes</span> <span className="icon-dropdown icon icon-arrow-37"></span></a>
<OverlayTrigger trigger="click" placement="bottom" overlay={
<Popover className="popover-volume">
<div className="port-labels">
<div className="label-docker">DOCKER FOLDER</div>
<div className="label-local">LOCAL FOLDER</div>
</div>
<div className="ports">
{volumes}
</div>
</Popover>
}>
<a className={dropdownButtonClass}><span className="icon icon-folder-1"></span> <span className="content">Volumes</span> <span className="icon-dropdown icon icon-arrow-37"></span></a>
</OverlayTrigger>
</div>
<div className="action">
<a className={buttonClass} onClick={this.handleView}><span className="icon icon-refresh"></span> <span className="content">Restart</span></a>

View File

@ -227,6 +227,7 @@ var ContainerModal = React.createClass({
<div className={magnifierClasses}></div>
<RetinaImage className={loadingClasses} src="loading.png"/>
</div>
{question}
<div className="results">
<div className="title">{title}</div>
{results}

View File

@ -397,7 +397,10 @@ var ContainerStore = assign(EventEmitter.prototype, {
},
updateContainer: function (name, data, callback) {
_muted[name] = true;
console.log(data);
console.log(_containers[name]);
var fullData = assign(_containers[name], data);
console.log(fullData);
this._createContainer(name, fullData, function (err) {
this.emit(this.CLIENT_CONTAINER_EVENT, name);
_muted[name] = false;

View File

@ -10,7 +10,39 @@ var ContainerUtil = {
var splits = [env.slice(0, i), env.slice(i + 1)];
return splits;
}));
}
},
ports: function (container, callback) {
var res = {};
boot2docker.ip(function (err, ip) {
_.each(container.NetworkSettings.Ports, function (value, key) {
var dockerPort = key.split('/')[0];
var localUrl = null;
var localUrlDisplay = null;
if (value && value.length) {
var port = value[0].HostPort;
localUrl = 'http://' + ip + ':' + port;
localUrlDisplay = ip + ':' + port;
}
res[dockerPort] = {
url: localUrl,
display: localUrlDisplay
};
});
callback(err, res);
});
},
volumes: function (container) {
var res = {};
if (container.Volumes) {
res = container.Volumes;
_.each(res, function (value, key) {
if (value && value.indexOf("/mnt/sda1/var/lib/docker/vfs/dir/") > -1) {
res[key] = null;
}
});
}
return res;
},
};
module.exports = ContainerUtil;

View File

@ -1,3 +1,28 @@
.port-labels {
width: 100%;
font-size: 12px;
color: @gray-lightest;
margin-left: 5px;
margin-bottom: 5px;
.label-docker {
display: inline-block;
margin-right: 30px;
width: 20%;
}
.label-local {
display: inline-block;
width: 40%;
}
}
.popover-view {
min-width: 500px;
}
.popover-volume {
min-width: 500px;
}
.containers {
height: 100%;
display: flex;
@ -349,6 +374,13 @@
}
}
.container-name {
margin-bottom: 20px;
input {
width: 20%;
}
}
.env-vars-labels {
width: 100%;
font-size: 12px;