Merging master

Signed-off-by: Jeffrey Morgan <jmorganca@gmail.com>
This commit is contained in:
Jeffrey Morgan 2015-04-17 13:00:55 -04:00
commit 8ccb7b05cb
22 changed files with 107 additions and 77 deletions

View File

@ -27,5 +27,5 @@
"jest": true, "jest": true,
"pit": true "pit": true
}, },
"predef": [ "Promise" ] "predef": [ "-Promise" ]
} }

View File

@ -36,7 +36,7 @@ To run the app in development:
**Note: This architecture is work in progress and doesn't reflect the current state of the app, yet!** **Note: This architecture is work in progress and doesn't reflect the current state of the app, yet!**
Kitematic is an application built using [atom-shell](https://github.com/atom/atom-shell) and is powered by the [Docker Engine](https://github.com/docker/docker). While it's work in progress, the goal is to make Kitematic a high-performance, portable Javascript ES6 application built with React and Reflux. It adopts a single data flow pattern: Kitematic is an application built using [electron](https://github.com/atom/electron) and is powered by the [Docker Engine](https://github.com/docker/docker). While it's work in progress, the goal is to make Kitematic a high-performance, portable Javascript ES6 application built with React and Reflux. It adopts a single data flow pattern:
``` ```
╔═════════╗ ╔════════╗ ╔═════════════════╗ ╔═════════╗ ╔════════╗ ╔═════════════════╗

View File

@ -2,7 +2,7 @@ var babel = require('gulp-babel');
var changed = require('gulp-changed'); var changed = require('gulp-changed');
var concat = require('gulp-concat'); var concat = require('gulp-concat');
var cssmin = require('gulp-cssmin'); var cssmin = require('gulp-cssmin');
var downloadatomshell = require('gulp-download-atom-shell'); var downloadelectron = require('gulp-download-electron');
var fs = require('fs'); var fs = require('fs');
var gulp = require('gulp'); var gulp = require('gulp');
var gulpif = require('gulp-if'); var gulpif = require('gulp-if');
@ -76,8 +76,8 @@ gulp.task('styles', function () {
}); });
gulp.task('download', function (cb) { gulp.task('download', function (cb) {
downloadatomshell({ downloadelectron({
version: packagejson['atom-shell-version'], version: packagejson['electron-version'],
outputDir: 'cache' outputDir: 'cache'
}, cb); }, cb);
}); });
@ -97,8 +97,8 @@ gulp.task('dist', function () {
var stream = gulp.src('').pipe(shell([ var stream = gulp.src('').pipe(shell([
'rm -Rf dist', 'rm -Rf dist',
'mkdir -p ./dist/osx', 'mkdir -p ./dist/osx',
'cp -R ./cache/Atom.app ./dist/osx/<%= filename %>', 'cp -R ./cache/Electron.app ./dist/osx/<%= filename %>',
'mv ./dist/osx/<%= filename %>/Contents/MacOS/Atom ./dist/osx/<%= filename %>/Contents/MacOS/<%= name %>', 'mv ./dist/osx/<%= filename %>/Contents/MacOS/Electron ./dist/osx/<%= filename %>/Contents/MacOS/<%= name %>',
'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app', 'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app',
'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app/node_modules', 'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app/node_modules',
'cp package.json dist/osx/<%= filename %>/Contents/Resources/app/', 'cp package.json dist/osx/<%= filename %>/Contents/Resources/app/',
@ -138,9 +138,19 @@ gulp.task('sign', function () {
try { try {
var signing_identity = fs.readFileSync('./identity', 'utf8').trim(); var signing_identity = fs.readFileSync('./identity', 'utf8').trim();
return gulp.src('').pipe(shell([ return gulp.src('').pipe(shell([
'codesign --deep --force --verbose --sign "' + signing_identity + '" ' + options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)') 'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Electron\\ Framework.framework',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Electron\\ Helper\\ EH.app',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Electron\\ Helper\\ NP.app',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Electron\\ Helper.app',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/ReactiveCocoa.framework',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Squirrel.framework',
'codesign --deep --force --verbose --sign <%= identity %> <%= filename %>/Contents/Frameworks/Mantle.framework',
'codesign --force --verbose --sign <%= identity %> <%= filename %>',
], { ], {
cwd: './dist/osx/' templateData: {
filename: 'dist/osx/' + options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
identity: '\"' + signing_identity + '\"'
}
})); }));
} catch (error) { } catch (error) {
gutil.log(gutil.colors.red('Error: ' + error.message)); gutil.log(gutil.colors.red('Error: ' + error.message));
@ -207,11 +217,11 @@ gulp.task('default', ['download-deps', 'download', 'copy', 'js', 'images', 'styl
env.NODE_ENV = 'development'; env.NODE_ENV = 'development';
if(process.platform === 'win32') { if(process.platform === 'win32') {
gulp.src('').pipe(shell(['cache\\atom.exe .'], { gulp.src('').pipe(shell(['cache\\electron.exe .'], {
env: env env: env
})); }));
} else { } else {
gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom .'], { gulp.src('').pipe(shell(['./cache/Electron.app/Contents/MacOS/Electron .'], {
env: env env: env
})); }));
} }

View File

@ -38,6 +38,7 @@
"tty", "tty",
"net", "net",
"crypto", "crypto",
"babel",
"<rootDir>/node_modules/.*JSONStream", "<rootDir>/node_modules/.*JSONStream",
"<rootDir>/node_modules/object-assign", "<rootDir>/node_modules/object-assign",
"<rootDir>/node_modules/underscore", "<rootDir>/node_modules/underscore",
@ -46,7 +47,7 @@
}, },
"docker-version": "1.6.0", "docker-version": "1.6.0",
"docker-machine-version": "0.2.0", "docker-machine-version": "0.2.0",
"atom-shell-version": "0.23.0", "electron-version": "0.24.0",
"virtualbox-version": "4.3.26", "virtualbox-version": "4.3.26",
"virtualbox-filename": "VirtualBox-4.3.26.pkg", "virtualbox-filename": "VirtualBox-4.3.26.pkg",
"virtualbox-filename-win": "VirtualBox-4.3.26.exe", "virtualbox-filename-win": "VirtualBox-4.3.26.exe",
@ -58,6 +59,7 @@
"async": "^0.9.0", "async": "^0.9.0",
"bluebird": "^2.9.24", "bluebird": "^2.9.24",
"bugsnag-js": "^2.4.7", "bugsnag-js": "^2.4.7",
"classnames": "^1.2.0",
"coveralls": "^2.11.2", "coveralls": "^2.11.2",
"dockerode": "^2.1.1", "dockerode": "^2.1.1",
"exec": "0.2.0", "exec": "0.2.0",
@ -83,7 +85,7 @@
"gulp-changed": "^1.2.1", "gulp-changed": "^1.2.1",
"gulp-concat": "^2.5.2", "gulp-concat": "^2.5.2",
"gulp-cssmin": "^0.1.6", "gulp-cssmin": "^0.1.6",
"gulp-download-atom-shell": "0.0.4", "gulp-download-electron": "^0.0.5",
"gulp-if": "^1.2.5", "gulp-if": "^1.2.5",
"gulp-insert": "^0.4.0", "gulp-insert": "^0.4.0",
"gulp-less": "^3.0.2", "gulp-less": "^3.0.2",
@ -93,7 +95,6 @@
"gulp-shell": "^0.4.1", "gulp-shell": "^0.4.1",
"gulp-sourcemaps": "^1.5.2", "gulp-sourcemaps": "^1.5.2",
"gulp-util": "^3.0.4", "gulp-util": "^3.0.4",
"gulp": "^3.8.11",
"jest-cli": "kitematic/jest", "jest-cli": "kitematic/jest",
"jsxhint": "^0.14.0", "jsxhint": "^0.14.0",
"minimist": "^1.1.1", "minimist": "^1.1.1",

View File

@ -5,7 +5,9 @@ var ContainerDetailsSubheader = require('./ContainerDetailsSubheader.react');
var Router = require('react-router'); var Router = require('react-router');
var ContainerDetail = React.createClass({ var ContainerDetail = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
currentRoute: null currentRoute: null
@ -18,9 +20,9 @@ var ContainerDetail = React.createClass({
this.init(); this.init();
}, },
init: function () { init: function () {
var currentRoute = _.last(this.getRoutes()).name; var currentRoute = _.last(this.context.router.getCurrentRoutes()).name;
if (currentRoute === 'containerDetails') { if (currentRoute === 'containerDetails') {
this.transitionTo('containerHome', {name: this.getParams().name}); this.context.router.transitionTo('containerHome', {name: this.context.router.getCurrentParams().name});
} }
}, },
render: function () { render: function () {

View File

@ -1,19 +1,21 @@
var _ = require('underscore'); var _ = require('underscore');
var $ = require('jquery'); var $ = require('jquery');
var React = require('react/addons'); var React = require('react');
var exec = require('exec'); var exec = require('exec');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var machine = require('./DockerMachine'); var machine = require('./DockerMachine');
var RetinaImage = require('react-retina-image'); var RetinaImage = require('react-retina-image');
var Router = require('react-router');
var webPorts = require('./Util').webPorts; var webPorts = require('./Util').webPorts;
var shell = require('shell'); var shell = require('shell');
var resources = require('./Resources'); var resources = require('./Resources');
var classNames = require('classNames');
var ContainerDetailsSubheader = React.createClass({ var ContainerDetailsSubheader = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
defaultPort: null defaultPort: null
@ -27,9 +29,9 @@ var ContainerDetailsSubheader = React.createClass({
}, },
init: function () { init: function () {
this.setState({ this.setState({
currentRoute: _.last(this.getRoutes()).name currentRoute: _.last(this.context.router.getCurrentRoutes()).name
}); });
var container = ContainerStore.container(this.getParams().name); var container = ContainerStore.container(this.context.router.getCurrentParams().name);
if (!container) { if (!container) {
return; return;
} }
@ -70,19 +72,19 @@ var ContainerDetailsSubheader = React.createClass({
metrics.track('Viewed Home', { metrics.track('Viewed Home', {
from: 'header' from: 'header'
}); });
this.transitionTo('containerHome', {name: this.getParams().name}); this.context.router.transitionTo('containerHome', {name: this.context.router.getCurrentParams().name});
} }
}, },
showLogs: function () { showLogs: function () {
if (!this.disableTab()) { if (!this.disableTab()) {
metrics.track('Viewed Logs'); metrics.track('Viewed Logs');
this.transitionTo('containerLogs', {name: this.getParams().name}); this.context.router.transitionTo('containerLogs', {name: this.context.router.getCurrentParams().name});
} }
}, },
showSettings: function () { showSettings: function () {
if (!this.disableTab()) { if (!this.disableTab()) {
metrics.track('Viewed Settings'); metrics.track('Viewed Settings');
this.transitionTo('containerSettings', {name: this.getParams().name}); this.context.router.transitionTo('containerSettings', {name: this.context.router.getCurrentParams().name});
} }
}, },
handleRun: function () { handleRun: function () {
@ -139,29 +141,29 @@ var ContainerDetailsSubheader = React.createClass({
$action.css("visibility", "hidden"); $action.css("visibility", "hidden");
}, },
render: function () { render: function () {
var runActionClass = React.addons.classSet({ var runActionClass = classNames({
action: true, action: true,
disabled: this.disableRun() disabled: this.disableRun()
}); });
var restartActionClass = React.addons.classSet({ var restartActionClass = classNames({
action: true, action: true,
disabled: this.disableRestart() disabled: this.disableRestart()
}); });
var terminalActionClass = React.addons.classSet({ var terminalActionClass = classNames({
action: true, action: true,
disabled: this.disableTerminal() disabled: this.disableTerminal()
}); });
var tabHomeClasses = React.addons.classSet({ var tabHomeClasses = classNames({
'tab': true, 'tab': true,
'active': this.state.currentRoute === 'containerHome', 'active': this.state.currentRoute === 'containerHome',
disabled: this.disableTab() disabled: this.disableTab()
}); });
var tabLogsClasses = React.addons.classSet({ var tabLogsClasses = classNames({
'tab': true, 'tab': true,
'active': this.state.currentRoute === 'containerLogs', 'active': this.state.currentRoute === 'containerLogs',
disabled: this.disableTab() disabled: this.disableTab()
}); });
var tabSettingsClasses = React.addons.classSet({ var tabSettingsClasses = classNames({
'tab': true, 'tab': true,
'active': this.state.currentRoute && (this.state.currentRoute.indexOf('containerSettings') >= 0), 'active': this.state.currentRoute && (this.state.currentRoute.indexOf('containerSettings') >= 0),
disabled: this.disableTab() disabled: this.disableTab()

View File

@ -2,7 +2,6 @@ var _ = require('underscore');
var $ = require('jquery'); var $ = require('jquery');
var React = require('react/addons'); var React = require('react/addons');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var Router = require('react-router');
var Radial = require('./Radial.react'); var Radial = require('./Radial.react');
var ContainerHomePreview = require('./ContainerHomePreview.react'); var ContainerHomePreview = require('./ContainerHomePreview.react');
var ContainerHomeLogs = require('./ContainerHomeLogs.react'); var ContainerHomeLogs = require('./ContainerHomeLogs.react');
@ -17,7 +16,9 @@ var resizeWindow = function () {
}; };
var ContainerHome = React.createClass({ var ContainerHome = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
ports: {}, ports: {},
@ -48,7 +49,7 @@ var ContainerHome = React.createClass({
resizeWindow(); resizeWindow();
}, },
init: function () { init: function () {
var container = ContainerStore.container(this.getParams().name); var container = ContainerStore.container(this.context.router.getCurrentParams().name);
if (!container) { if (!container) {
return; return;
} }
@ -58,12 +59,12 @@ var ContainerHome = React.createClass({
defaultPort: _.find(_.keys(ports), function (port) { defaultPort: _.find(_.keys(ports), function (port) {
return util.webPorts.indexOf(port) !== -1; return util.webPorts.indexOf(port) !== -1;
}), }),
progress: ContainerStore.progress(this.getParams().name), progress: ContainerStore.progress(this.context.router.getCurrentParams().name),
blocked: ContainerStore.blocked(this.getParams().name) blocked: ContainerStore.blocked(this.context.router.getCurrentParams().name)
}); });
}, },
updateProgress: function (name) { updateProgress: function (name) {
if (name === this.getParams().name) { if (name === this.context.router.getCurrentParams().name) {
this.setState({ this.setState({
blocked: ContainerStore.blocked(name), blocked: ContainerStore.blocked(name),
progress: ContainerStore.progress(name) progress: ContainerStore.progress(name)

View File

@ -5,11 +5,12 @@ var path = require('path');
var shell = require('shell'); var shell = require('shell');
var util = require('./Util'); var util = require('./Util');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var Router = require('react-router');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerHomeFolder = React.createClass({ var ContainerHomeFolder = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
handleClickFolder: function (hostVolume, containerVolume) { handleClickFolder: function (hostVolume, containerVolume) {
metrics.track('Opened Volume Directory', { metrics.track('Opened Volume Directory', {
from: 'home' from: 'home'
@ -47,7 +48,7 @@ var ContainerHomeFolder = React.createClass({
metrics.track('Viewed Volume Settings', { metrics.track('Viewed Volume Settings', {
from: 'preview' from: 'preview'
}); });
this.transitionTo('containerSettingsVolumes', {name: this.getParams().name}); this.context.router.transitionTo('containerSettingsVolumes', {name: this.context.router.getCurrentParams().name});
}, },
render: function () { render: function () {
if (!this.props.container) { if (!this.props.container) {

View File

@ -44,9 +44,12 @@ module.exports = React.createClass({
metrics.track('Viewed Logs', { metrics.track('Viewed Logs', {
from: 'preview' from: 'preview'
}); });
this.transitionTo('containerLogs', {name: this.props.container.Name}); this.context.router.transitionTo('containerLogs', {name: this.props.container.Name});
}, },
update: function () { update: function () {
if (!this.props.container) {
return;
}
this.setState({ this.setState({
logs: LogStore.logs(this.props.container.Name) logs: LogStore.logs(this.props.container.Name)
}); });

View File

@ -3,14 +3,15 @@ var React = require('react/addons');
var exec = require('exec'); var exec = require('exec');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var Router = require('react-router');
var request = require('request'); var request = require('request');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var webPorts = require('./Util').webPorts; var webPorts = require('./Util').webPorts;
var util = require('./Util'); var util = require('./Util');
var ContainerHomePreview = React.createClass({ var ContainerHomePreview = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
ports: {}, ports: {},
@ -42,7 +43,7 @@ var ContainerHomePreview = React.createClass({
clearInterval(this.timer); clearInterval(this.timer);
}, },
init: function () { init: function () {
var container = ContainerStore.container(this.getParams().name); var container = ContainerStore.container(this.context.router.getCurrentParams().name);
if (!container) { if (!container) {
return; return;
} }
@ -66,7 +67,7 @@ var ContainerHomePreview = React.createClass({
metrics.track('Viewed Port Settings', { metrics.track('Viewed Port Settings', {
from: 'preview' from: 'preview'
}); });
this.transitionTo('containerSettingsPorts', {name: this.getParams().name}); this.context.router.transitionTo('containerSettingsPorts', {name: this.context.router.getCurrentParams().name});
}, },
render: function () { render: function () {
var preview; var preview;

View File

@ -5,7 +5,6 @@ var ContainerStore = require('./ContainerStore');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var ContainerListNewItem = React.createClass({ var ContainerListNewItem = React.createClass({
mixins: [Router.State, Router.Navigation],
handleItemMouseEnter: function () { handleItemMouseEnter: function () {
var $action = $(this.getDOMNode()).find('.action'); var $action = $(this.getDOMNode()).find('.action');
$action.show(); $action.show();

View File

@ -20,6 +20,10 @@ module.exports = React.createClass({
LogStore.fetch(this.props.container.Name); LogStore.fetch(this.props.container.Name);
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
if (!this.props.container) {
return;
}
LogStore.detach(this.props.container.Name); LogStore.detach(this.props.container.Name);
LogStore.removeListener(LogStore.SERVER_LOGS_EVENT, this.update); LogStore.removeListener(LogStore.SERVER_LOGS_EVENT, this.update);
}, },
@ -34,6 +38,9 @@ module.exports = React.createClass({
_prevBottom = parent[0].scrollHeight - parent.height(); _prevBottom = parent[0].scrollHeight - parent.height();
}, },
update: function () { update: function () {
if (!this.props.container) {
return;
}
this.setState({ this.setState({
logs: LogStore.logs(this.props.container.Name) logs: LogStore.logs(this.props.container.Name)
}); });

View File

@ -3,7 +3,9 @@ var React = require('react/addons');
var Router = require('react-router'); var Router = require('react-router');
var ContainerSettings = React.createClass({ var ContainerSettings = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
componentWillReceiveProps: function () { componentWillReceiveProps: function () {
this.init(); this.init();
}, },
@ -11,9 +13,9 @@ var ContainerSettings = React.createClass({
this.init(); this.init();
}, },
init: function () { init: function () {
var currentRoute = _.last(this.getRoutes()).name; var currentRoute = _.last(this.context.router.getCurrentRoutes()).name;
if (currentRoute === 'containerSettings') { if (currentRoute === 'containerSettings') {
this.transitionTo('containerSettingsGeneral', {name: this.getParams().name}); this.context.router.transitionTo('containerSettingsGeneral', {name: this.context.router.getCurrentParams().name});
} }
}, },
render: function () { render: function () {

View File

@ -28,7 +28,9 @@ var containerNameSlugify = function (text) {
}; };
var ContainerSettingsGeneral = React.createClass({ var ContainerSettingsGeneral = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
slugName: null, slugName: null,
@ -44,7 +46,7 @@ var ContainerSettingsGeneral = React.createClass({
this.init(); this.init();
}, },
init: function () { init: function () {
var container = ContainerStore.container(this.getParams().name); var container = ContainerStore.container(this.context.router.getCurrentParams().name);
if (!container) { if (!container) {
return; return;
} }
@ -98,7 +100,7 @@ var ContainerSettingsGeneral = React.createClass({
return; return;
} }
metrics.track('Changed Container Name'); metrics.track('Changed Container Name');
this.transitionTo('containerSettingsGeneral', {name: newName}); this.context.router.transitionTo('containerSettingsGeneral', {name: newName});
var oldPath = path.join(process.env.HOME, 'Kitematic', oldName); var oldPath = path.join(process.env.HOME, 'Kitematic', oldName);
var newPath = path.join(process.env.HOME, 'Kitematic', newName); var newPath = path.join(process.env.HOME, 'Kitematic', newName);
rimraf(newPath, () => { rimraf(newPath, () => {

View File

@ -1,6 +1,5 @@
var _ = require('underscore'); var _ = require('underscore');
var React = require('react/addons'); var React = require('react/addons');
var Router = require('react-router');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
@ -8,7 +7,9 @@ var webPorts = require('./Util').webPorts;
var shell = require('shell'); var shell = require('shell');
var ContainerSettingsPorts = React.createClass({ var ContainerSettingsPorts = React.createClass({
mixins: [Router.State, Router.Navigation], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
ports: {}, ports: {},
@ -22,7 +23,7 @@ var ContainerSettingsPorts = React.createClass({
this.init(); this.init();
}, },
init: function () { init: function () {
var container = ContainerStore.container(this.getParams().name); var container = ContainerStore.container(this.context.router.getCurrentParams().name);
if (!container) { if (!container) {
return; return;
} }
@ -41,7 +42,6 @@ var ContainerSettingsPorts = React.createClass({
shell.openExternal(url); shell.openExternal(url);
}, },
handleChangeDefaultPort: function (port, e) { handleChangeDefaultPort: function (port, e) {
console.log(e.target.checked);
if (e.target.checked) { if (e.target.checked) {
this.setState({ this.setState({
defaultPort: port defaultPort: port

View File

@ -1,6 +1,5 @@
var _ = require('underscore'); var _ = require('underscore');
var React = require('react/addons'); var React = require('react/addons');
var Router = require('react-router');
var remote = require('remote'); var remote = require('remote');
var dialog = remote.require('dialog'); var dialog = remote.require('dialog');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
@ -8,7 +7,6 @@ var ContainerStore = require('./ContainerStore');
var util = require('./Util'); var util = require('./Util');
var ContainerSettingsVolumes = React.createClass({ var ContainerSettingsVolumes = React.createClass({
mixins: [Router.State, Router.Navigation],
handleChooseVolumeClick: function (dockerVol) { handleChooseVolumeClick: function (dockerVol) {
var self = this; var self = this;
dialog.showOpenDialog({properties: ['openDirectory', 'createDirectory']}, function (filenames) { dialog.showOpenDialog({properties: ['openDirectory', 'createDirectory']}, function (filenames) {

View File

@ -15,7 +15,9 @@ var Tooltip = require('react-bootstrap').Tooltip;
var shell = require('shell'); var shell = require('shell');
var Containers = React.createClass({ var Containers = React.createClass({
mixins: [Router.Navigation, Router.State], contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () { getInitialState: function () {
return { return {
sidebarOffset: 0, sidebarOffset: 0,
@ -34,7 +36,7 @@ var Containers = React.createClass({
ContainerStore.on(ContainerStore.CLIENT_CONTAINER_EVENT, this.updateFromClient); ContainerStore.on(ContainerStore.CLIENT_CONTAINER_EVENT, this.updateFromClient);
if (this.state.sorted.length) { if (this.state.sorted.length) {
this.transitionTo('containerHome', {name: this.state.sorted[0].Name}); this.context.router.transitionTo('containerHome', {name: this.state.sorted[0].Name});
} }
ipc.on('application:update-available', () => { ipc.on('application:update-available', () => {
@ -50,9 +52,9 @@ var Containers = React.createClass({
}, },
onDestroy: function () { onDestroy: function () {
if (this.state.sorted.length) { if (this.state.sorted.length) {
this.transitionTo('containerHome', {name: this.state.sorted[0].Name}); this.context.router.transitionTo('containerHome', {name: this.state.sorted[0].Name});
} else { } else {
this.transitionTo('containers'); this.context.router.transitionTo('containers');
} }
}, },
updateError: function (err) { updateError: function (err) {
@ -77,7 +79,7 @@ var Containers = React.createClass({
downloading: ContainerStore.downloading() downloading: ContainerStore.downloading()
}); });
if (status === 'create') { if (status === 'create') {
this.transitionTo('containerHome', {name: name}); this.context.router.transitionTo('containerHome', {name: name});
} else if (status === 'destroy') { } else if (status === 'destroy') {
this.onDestroy(); this.onDestroy();
} }
@ -95,7 +97,7 @@ var Containers = React.createClass({
}, },
handleNewContainer: function () { handleNewContainer: function () {
$(this.getDOMNode()).find('.new-container-item').parent().fadeIn(); $(this.getDOMNode()).find('.new-container-item').parent().fadeIn();
this.transitionTo('new'); this.context.router.transitionTo('new');
metrics.track('Pressed New Container'); metrics.track('Pressed New Container');
}, },
handleAutoUpdateClick: function () { handleAutoUpdateClick: function () {
@ -106,7 +108,7 @@ var Containers = React.createClass({
metrics.track('Opened Preferences', { metrics.track('Opened Preferences', {
from: 'app' from: 'app'
}); });
this.transitionTo('preferences'); this.context.router.transitionTo('preferences');
}, },
handleClickDockerTerminal: function () { handleClickDockerTerminal: function () {
metrics.track('Opened Docker Terminal', { metrics.track('Opened Docker Terminal', {
@ -173,7 +175,7 @@ var Containers = React.createClass({
button = <a className="btn-new icon icon-add-3" onClick={this.handleNewContainer}></a>; button = <a className="btn-new icon icon-add-3" onClick={this.handleNewContainer}></a>;
} }
var container = this.getParams().name ? this.state.containers[this.getParams().name] : {}; var container = this.context.router.getCurrentParams().name ? this.state.containers[this.context.router.getCurrentParams().name] : {};
return ( return (
<div className="containers"> <div className="containers">
<Header /> <Header />

View File

@ -33,7 +33,6 @@ var Docker = {
delay = delay || 1000; delay = delay || 1000;
var tryCount = 1; var tryCount = 1;
while (true) { while (true) {
console.log('Connecting: ' + tryCount + ' tries...');
try { try {
yield new Promise((resolve, reject) => { yield new Promise((resolve, reject) => {
this._client.listContainers((err) => { this._client.listContainers((err) => {

View File

@ -30,7 +30,7 @@ module.exports = assign(Object.create(EventEmitter.prototype), {
follow: false follow: false
}, (err, logStream) => { }, (err, logStream) => {
if (err) { if (err) {
throw err; return;
} }
var logs = []; var logs = [];
var outstream = new stream.PassThrough(); var outstream = new stream.PassThrough();
@ -56,8 +56,9 @@ module.exports = assign(Object.create(EventEmitter.prototype), {
stream: true stream: true
}, (err, logStream) => { }, (err, logStream) => {
if (err) { if (err) {
throw err; return;
} }
_streams[name] = logStream;
var outstream = new stream.PassThrough(); var outstream = new stream.PassThrough();
docker.client().modem.demuxStream(logStream, outstream, outstream); docker.client().modem.demuxStream(logStream, outstream, outstream);
outstream.on('data', (chunk) => { outstream.on('data', (chunk) => {

View File

@ -1,11 +1,12 @@
var _ = require('underscore'); var _ = require('underscore');
var $ = require('jquery'); var $ = require('jquery');
var React = require('react/addons'); var React = require('react');
var RetinaImage = require('react-retina-image'); var RetinaImage = require('react-retina-image');
var Radial = require('./Radial.react'); var Radial = require('./Radial.react');
var ImageCard = require('./ImageCard.react'); var ImageCard = require('./ImageCard.react');
var Promise = require('bluebird'); var Promise = require('bluebird');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var classNames = require('classnames');
var _recommended = []; var _recommended = [];
var _searchPromise = null; var _searchPromise = null;
@ -132,11 +133,11 @@ var NewContainer = React.createClass({
); );
} }
} }
var loadingClasses = React.addons.classSet({ var loadingClasses = classNames({
hidden: !this.state.loading, hidden: !this.state.loading,
loading: true loading: true
}); });
var magnifierClasses = React.addons.classSet({ var magnifierClasses = classNames({
hidden: this.state.loading, hidden: this.state.loading,
icon: true, icon: true,
'icon-magnifier': true, 'icon-magnifier': true,

View File

@ -1,4 +1,5 @@
var React = require('react/addons'); var React = require('react');
var classNames = require('classnames');
var Radial = React.createClass({ var Radial = React.createClass({
render: function () { render: function () {
@ -10,7 +11,7 @@ var Radial = React.createClass({
} else { } else {
percentage = <div></div>; percentage = <div></div>;
} }
var classes = React.addons.classSet({ var classes = classNames({
'radial-progress': true, 'radial-progress': true,
'radial-spinner': this.props.spin, 'radial-spinner': this.props.spin,
'radial-negative': this.props.error, 'radial-negative': this.props.error,

View File

@ -245,7 +245,6 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
setup: Promise.coroutine(function * () { setup: Promise.coroutine(function * () {
while (true) { while (true) {
try { try {
console.log('Starting Steps');
var ip = yield this.run(); var ip = yield this.run();
if (!ip || !ip.length) { if (!ip || !ip.length) {
throw { throw {
@ -254,8 +253,6 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
ip: ip ip: ip
}; };
} }
console.log('Finished Steps');
console.log(ip);
docker.setup(ip, machine.name()); docker.setup(ip, machine.name());
yield docker.waitForConnection(); yield docker.waitForConnection();
metrics.track('Setup Finished'); metrics.track('Setup Finished');