mirror of https://github.com/docker/docs.git
Displays ports and volumes dropdown.
This commit is contained in:
parent
d80d259f98
commit
b484233d4c
|
@ -11,6 +11,8 @@ var ContainerUtil = require('./ContainerUtil');
|
||||||
var docker = require('./docker');
|
var docker = require('./docker');
|
||||||
var boot2docker = require('./boot2docker');
|
var boot2docker = require('./boot2docker');
|
||||||
var ProgressBar = require('react-bootstrap/ProgressBar');
|
var ProgressBar = require('react-bootstrap/ProgressBar');
|
||||||
|
var Popover = require('react-bootstrap/Popover');
|
||||||
|
var OverlayTrigger = require('react-bootstrap/OverlayTrigger');
|
||||||
|
|
||||||
var Route = Router.Route;
|
var Route = Router.Route;
|
||||||
var NotFoundRoute = Router.NotFoundRoute;
|
var NotFoundRoute = Router.NotFoundRoute;
|
||||||
|
@ -28,7 +30,9 @@ var ContainerDetails = React.createClass({
|
||||||
logs: [],
|
logs: [],
|
||||||
page: this.PAGE_LOGS,
|
page: this.PAGE_LOGS,
|
||||||
env: {},
|
env: {},
|
||||||
pendingEnv: {}
|
pendingEnv: {},
|
||||||
|
ports: {},
|
||||||
|
volumes: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentWillReceiveProps: function () {
|
componentWillReceiveProps: function () {
|
||||||
|
@ -59,8 +63,14 @@ var ContainerDetails = React.createClass({
|
||||||
},
|
},
|
||||||
init: function () {
|
init: function () {
|
||||||
this.setState({
|
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 () {
|
ContainerStore.fetchLogs(this.getParams().name, function () {
|
||||||
this.updateLogs();
|
this.updateLogs();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -115,6 +125,11 @@ var ContainerDetails = React.createClass({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleViewLink: function (url) {
|
||||||
|
exec(['open', url], function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
});
|
||||||
|
},
|
||||||
handleTerminal: function () {
|
handleTerminal: function () {
|
||||||
var container = this.props.container;
|
var container = this.props.container;
|
||||||
var terminal = path.join(process.cwd(), 'resources', 'terminal').replace(/ /g, '\\\\ ');
|
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 () {
|
handleSaveEnvVar: function () {
|
||||||
var $rows = $('.env-vars .keyval-row');
|
var $rows = $('.env-vars .keyval-row');
|
||||||
var envVarList = [];
|
var envVarList = [];
|
||||||
|
@ -259,7 +286,10 @@ var ContainerDetails = React.createClass({
|
||||||
<div className="details-panel">
|
<div className="details-panel">
|
||||||
<div className="settings">
|
<div className="settings">
|
||||||
<h3>Container Name</h3>
|
<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>
|
<h3>Environment Variables</h3>
|
||||||
<div className="env-vars-labels">
|
<div className="env-vars-labels">
|
||||||
<div className="label-key">KEY</div>
|
<div className="label-key">KEY</div>
|
||||||
|
@ -317,6 +347,29 @@ var ContainerDetails = React.createClass({
|
||||||
disabled: this.props.container.State.Downloading
|
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 (
|
return (
|
||||||
<div className="details">
|
<div className="details">
|
||||||
<div className="details-header">
|
<div className="details-header">
|
||||||
|
@ -325,10 +378,35 @@ var ContainerDetails = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
<div className="details-header-actions">
|
<div className="details-header-actions">
|
||||||
<div className="action btn-group">
|
<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>
|
||||||
<div className="action">
|
<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>
|
||||||
<div className="action">
|
<div className="action">
|
||||||
<a className={buttonClass} onClick={this.handleView}><span className="icon icon-refresh"></span> <span className="content">Restart</span></a>
|
<a className={buttonClass} onClick={this.handleView}><span className="icon icon-refresh"></span> <span className="content">Restart</span></a>
|
||||||
|
|
|
@ -227,6 +227,7 @@ var ContainerModal = React.createClass({
|
||||||
<div className={magnifierClasses}></div>
|
<div className={magnifierClasses}></div>
|
||||||
<RetinaImage className={loadingClasses} src="loading.png"/>
|
<RetinaImage className={loadingClasses} src="loading.png"/>
|
||||||
</div>
|
</div>
|
||||||
|
{question}
|
||||||
<div className="results">
|
<div className="results">
|
||||||
<div className="title">{title}</div>
|
<div className="title">{title}</div>
|
||||||
{results}
|
{results}
|
||||||
|
|
|
@ -397,7 +397,10 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
},
|
},
|
||||||
updateContainer: function (name, data, callback) {
|
updateContainer: function (name, data, callback) {
|
||||||
_muted[name] = true;
|
_muted[name] = true;
|
||||||
|
console.log(data);
|
||||||
|
console.log(_containers[name]);
|
||||||
var fullData = assign(_containers[name], data);
|
var fullData = assign(_containers[name], data);
|
||||||
|
console.log(fullData);
|
||||||
this._createContainer(name, fullData, function (err) {
|
this._createContainer(name, fullData, function (err) {
|
||||||
this.emit(this.CLIENT_CONTAINER_EVENT, name);
|
this.emit(this.CLIENT_CONTAINER_EVENT, name);
|
||||||
_muted[name] = false;
|
_muted[name] = false;
|
||||||
|
|
|
@ -10,7 +10,39 @@ var ContainerUtil = {
|
||||||
var splits = [env.slice(0, i), env.slice(i + 1)];
|
var splits = [env.slice(0, i), env.slice(i + 1)];
|
||||||
return splits;
|
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;
|
module.exports = ContainerUtil;
|
||||||
|
|
|
@ -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 {
|
.containers {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -349,6 +374,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-name {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
input {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.env-vars-labels {
|
.env-vars-labels {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
Loading…
Reference in New Issue