diff --git a/fonts/kitematic.eot b/fonts/kitematic.eot index 3bccd0f7fc..5f57382eed 100644 Binary files a/fonts/kitematic.eot and b/fonts/kitematic.eot differ diff --git a/fonts/kitematic.svg b/fonts/kitematic.svg index 717dfdef22..0d577b4207 100644 --- a/fonts/kitematic.svg +++ b/fonts/kitematic.svg @@ -7,25 +7,26 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/kitematic.ttf b/fonts/kitematic.ttf index 72bb395c5a..99254250b0 100644 Binary files a/fonts/kitematic.ttf and b/fonts/kitematic.ttf differ diff --git a/fonts/kitematic.woff b/fonts/kitematic.woff index 121ee6e711..af71b03b6d 100644 Binary files a/fonts/kitematic.woff and b/fonts/kitematic.woff differ diff --git a/package.json b/package.json index e1cf0cdfba..81342308da 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "mixpanel": "kitematic/mixpanel-node", "mkdirp": "^0.5.0", "node-uuid": "^1.4.3", + "numeral": "^1.5.3", "object-assign": "^4.0.1", "osx-release": "^1.1.0", "parseUri": "^1.2.3-2", diff --git a/src/browser.js b/src/browser.js index 0288bb9145..2ad5a38954 100644 --- a/src/browser.js +++ b/src/browser.js @@ -43,7 +43,7 @@ if (process.platform === 'win32') { app.on('ready', function () { var mainWindow = new BrowserWindow({ - width: size.width || 1000, + width: size.width || 1080, height: size.height || 680, 'min-width': os.platform() === 'win32' ? 400 : 700, 'min-height': os.platform() === 'win32' ? 260 : 500, diff --git a/src/components/ContainerHome.react.js b/src/components/ContainerHome.react.js index 51867620d7..dad139c8a8 100644 --- a/src/components/ContainerHome.react.js +++ b/src/components/ContainerHome.react.js @@ -73,10 +73,12 @@ var ContainerHome = React.createClass({ sum = 0; } + let total = (Math.round(sum * 100) / 100).toFixed(2); + body = (
-

Downloading Image

-

{ (Math.round(sum * 100) / 100).toFixed(2) }%

+

{total >= 100 ? 'Creating Container' : 'Downloading Image'}

+

{total}%

diff --git a/src/components/ContainerHomePreview.react.js b/src/components/ContainerHomePreview.react.js index 5358cc41d0..f4dcb3ce16 100644 --- a/src/components/ContainerHomePreview.react.js +++ b/src/components/ContainerHomePreview.react.js @@ -34,7 +34,7 @@ var ContainerHomePreview = React.createClass({ metrics.track('Opened In Browser', { from: 'preview' }); - shell.openExternal(this.props.ports[this.props.defaultPort].url); + shell.openExternal('http://' + this.props.ports[this.props.defaultPort].url); } }, @@ -48,7 +48,7 @@ var ContainerHomePreview = React.createClass({ render: function () { var preview; if (this.props.defaultPort) { - var frame = React.createElement('webview', {className: 'frame', id: 'webview', src: this.props.ports[this.props.defaultPort].url, autosize: 'on'}); + var frame = React.createElement('webview', {className: 'frame', id: 'webview', src: 'http://' + this.props.ports[this.props.defaultPort].url, autosize: 'on'}); preview = (
@@ -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} /> + + + TCP + UDP + + {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;