@@ -72,7 +72,7 @@ var ContainerHomePreview = React.createClass({
var val = pair[1];
return (
- | {key} |
+ {key + '/' + val.portType} |
{val.url} |
);
diff --git a/src/components/ContainerSettingsPorts.react.js b/src/components/ContainerSettingsPorts.react.js
index 9234189c98..8739bf67c2 100644
--- a/src/components/ContainerSettingsPorts.react.js
+++ b/src/components/ContainerSettingsPorts.react.js
@@ -6,6 +6,7 @@ import containerActions from '../actions/ContainerActions';
import containerStore from '../stores/ContainerStore';
import metrics from '../utils/MetricsUtil';
import {webPorts} from '../utils/Util';
+import {DropdownButton, MenuItem} from 'react-bootstrap';
var ContainerSettingsPorts = React.createClass({
contextTypes: {
@@ -61,16 +62,29 @@ var ContainerSettingsPorts = React.createClass({
}
this.setState({ports: ports});
},
- handleSave: function() {
+ handleChangePortType: function (key, portType) {
+ let ports = this.state.ports;
+ let port = ports[key].port;
+
+ // save updated port
+ ports[key] = _.extend(ports[key], {
+ url: ports[key].ip + ':' + port,
+ port: port,
+ portType: portType,
+ error: null
+ });
+ this.setState({ports: ports});
+ },
+ handleSave: function () {
+ let bindings = _.reduce(this.state.ports, (res, value, key) => {
+ res[key + '/' + value.portType] = [{
+ HostPort: value.port
+ }];
+ return res;
+ }, {});
containerActions.update(this.props.container.Name, {
NetworkSettings: {
- Ports: _.reduce(this.state.ports, function(res, value, key) {
- res[key + '/tcp'] = [{
- HostIp: value.ip,
- HostPort: value.port,
- }];
- return res;
- }, {})
+ Ports: bindings
}
});
},
@@ -80,9 +94,10 @@ var ContainerSettingsPorts = React.createClass({
}
var isUpdating = (this.props.container.State.Updating);
var isValid = true;
+
var ports = _.map(_.pairs(this.state.ports), pair => {
var key = pair[0];
- var {ip, port, url, error} = pair[1];
+ var {ip, port, url, portType, error} = pair[1];
isValid = (error) ? false : isValid;
let ipLink = (this.props.container.State.Running && !this.props.container.State.Paused && !this.props.container.State.ExitCode && !this.props.container.State.Restarting) ? (
{ip}):({ip});
return (
@@ -96,6 +111,12 @@ var ContainerSettingsPorts = React.createClass({
onChange={this.handleChangePort.bind(this, key)}
defaultValue={port} />
+
+
+
+
+
+ |
{error} |
);
diff --git a/src/components/ImageCard.react.js b/src/components/ImageCard.react.js
index 6d77201f9f..a18420b16c 100644
--- a/src/components/ImageCard.react.js
+++ b/src/components/ImageCard.react.js
@@ -8,6 +8,7 @@ import containerActions from '../actions/ContainerActions';
import containerStore from '../stores/ContainerStore';
import tagStore from '../stores/TagStore';
import tagActions from '../actions/TagActions';
+import numeral from 'numeral';
var ImageCard = React.createClass({
mixins: [Router.Navigation],
@@ -147,6 +148,8 @@ var ImageCard = React.createClass({
);
}
+ let favCount = (this.props.image.star_count < 1000) ? numeral(this.props.image.star_count).value() : numeral(this.props.image.star_count).format('0.0a').toUpperCase();
+ let pullCount = (this.props.image.pull_count < 1000) ? numeral(this.props.image.pull_count).value() : numeral(this.props.image.pull_count).format('0a').toUpperCase();
return (
@@ -185,7 +188,9 @@ var ImageCard = React.createClass({
- {this.props.image.star_count}
+ {favCount}
+
+ {pullCount}
diff --git a/src/utils/ContainerUtil.js b/src/utils/ContainerUtil.js
index b30e5203df..2a9496a6e0 100644
--- a/src/utils/ContainerUtil.js
+++ b/src/utils/ContainerUtil.js
@@ -28,20 +28,22 @@ var ContainerUtil = {
}
var res = {};
var ip = docker.host;
- var ports = (container.NetworkSettings.Ports) ? container.NetworkSettings.Ports : (container.HostConfig.PortBindings) ? container.HostConfig.PortBindings : container.Config.ExposedPorts;
+ var ports = (container.NetworkSettings.Ports) ? container.NetworkSettings.Ports : ((container.HostConfig.PortBindings) ? container.HostConfig.PortBindings : container.Config.ExposedPorts);
_.each(ports, function (value, key) {
- var dockerPort = key.split('/')[0];
+ var [dockerPort, portType] = key.split('/');
var localUrl = null;
- var localUrlDisplay = null;
var port = null;
+
if (value && value.length) {
- var port = value[0].HostPort;
- localUrl = 'http://' + ip + ':' + port;
+ port = value[0].HostPort;
}
+ localUrl = (port) ? ip + ':' + port : ip + ':' + '';
+
res[dockerPort] = {
url: localUrl,
ip: ip,
- port: port
+ port: port,
+ portType: portType
};
});
return res;
diff --git a/src/utils/DockerMachineUtil.js b/src/utils/DockerMachineUtil.js
index 9d2097f8aa..283b4cee85 100644
--- a/src/utils/DockerMachineUtil.js
+++ b/src/utils/DockerMachineUtil.js
@@ -26,7 +26,7 @@ var DockerMachine = {
try {
var matchlist = stdout.match(/(\d+\.\d+\.\d+).*/);
if (!matchlist || matchlist.length < 2) {
- Promise.reject('docker-machine -v output format not recognized.');
+ return Promise.reject('docker-machine -v output format not recognized.');
}
return Promise.resolve(matchlist[1]);
} catch (err) {
diff --git a/src/utils/DockerUtil.js b/src/utils/DockerUtil.js
index df4344976a..7091482feb 100644
--- a/src/utils/DockerUtil.js
+++ b/src/utils/DockerUtil.js
@@ -231,6 +231,19 @@ export default {
existingData.Tty = existingData.Config.Tty;
existingData.OpenStdin = existingData.Config.OpenStdin;
}
+ let networking = _.extend(existingData.NetworkSettings, data.NetworkSettings);
+ if (networking && networking.Ports) {
+ let exposed = _.reduce(networking.Ports, (res, value, key) => {
+ res[key] = {};
+ return res;
+ }, {});
+ data = _.extend(data, {
+ HostConfig: {
+ PortBindings: networking.Ports
+ },
+ ExposedPorts: exposed
+ });
+ }
var fullData = _.extend(existingData, data);
this.createContainer(name, fullData);
diff --git a/styles/container-home.less b/styles/container-home.less
index 3dde3e42be..b8dbc3f20b 100644
--- a/styles/container-home.less
+++ b/styles/container-home.less
@@ -48,6 +48,7 @@
}
}
td {
+ -webkit-user-select: auto;
border-color: @color-divider;
&.right {
text-align: right;
@@ -165,7 +166,7 @@
.text {
margin-top: 0.3rem;
margin-left: 1rem;
- width: 180px;
+ width: 180px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
diff --git a/styles/icons.less b/styles/icons.less
index de69405330..65f7f2e74e 100644
--- a/styles/icons.less
+++ b/styles/icons.less
@@ -35,8 +35,8 @@
text-transform: none !important;
speak: none;
line-height: 1;
- //-webkit-font-smoothing: subpixel-antialiased;
- -webkit-font-smoothing: antialiased;
+ -webkit-font-smoothing: subpixel-antialiased;
+ //-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@@ -103,3 +103,6 @@
.icon-edit:before {
content: "o";
}
+.icon-download:before {
+ content: "p";
+}
diff --git a/styles/new-container.less b/styles/new-container.less
index c84361a26d..7ca9247a3d 100644
--- a/styles/new-container.less
+++ b/styles/new-container.less
@@ -366,16 +366,20 @@
font-size: 11px;
color: @gray-normal;
border-right: 1px solid @color-divider;
- padding: 1.1rem 1.2rem;
+ padding: 1.1rem 1rem;
.icon {
position: relative;
font-size: 11px;
- margin-right: 0.5rem;
+ margin-right: 0.3rem;
color: @gray-normal;
}
+ .icon-download {
+ margin-left: 0.5rem;
+ }
.text {
position: relative;
top: -0.2rem;
+ margin-right: 0.3rem;
}
}
.tags {
@@ -400,10 +404,16 @@
}
.more-menu {
flex: 0 auto;
- width: 39px;
- padding: 0.4rem 1rem;
+ width: 30px;
+ padding: 0.4rem 0.5rem;
font-size: 20px;
.box-button();
+ .box-button {
+ .icon {
+ font-size: 1.5rem;
+ margin-left: 0.2rem;
+ }
+ }
}
.action {
flex: 0 auto;