diff --git a/app/ContainerDetails.react.js b/app/ContainerDetails.react.js
index 31e3fcdcee..17c0b392c3 100644
--- a/app/ContainerDetails.react.js
+++ b/app/ContainerDetails.react.js
@@ -12,12 +12,6 @@ var docker = require('./docker');
var boot2docker = require('./boot2docker');
var ProgressBar = require('react-bootstrap/ProgressBar');
-var Route = Router.Route;
-var NotFoundRoute = Router.NotFoundRoute;
-var DefaultRoute = Router.DefaultRoute;
-var Link = Router.Link;
-var RouteHandler = Router.RouteHandler;
-
var ContainerDetails = React.createClass({
mixins: [Router.State],
_oldHeight: 0,
@@ -35,14 +29,13 @@ var ContainerDetails = React.createClass({
this.init();
},
componentWillMount: function () {
- this.init();
},
componentDidMount: function () {
+ this.init();
ContainerStore.on(ContainerStore.SERVER_PROGRESS_EVENT, this.updateProgress);
ContainerStore.on(ContainerStore.SERVER_LOGS_EVENT, this.updateLogs);
},
componentWillUnmount: function () {
- // app close
ContainerStore.removeListener(ContainerStore.SERVER_PROGRESS_EVENT, this.updateProgress);
ContainerStore.removeListener(ContainerStore.SERVER_LOGS_EVENT, this.updateLogs);
},
@@ -74,7 +67,6 @@ var ContainerDetails = React.createClass({
});
},
updateProgress: function (name) {
- console.log('progress', name, ContainerStore.progress(name));
if (name === this.getParams().name) {
this.setState({
progress: ContainerStore.progress(name)
@@ -115,6 +107,11 @@ var ContainerDetails = React.createClass({
});
});
},
+ handleRestart: function () {
+ ContainerStore.restart(this.props.container.Name, function (err) {
+ console.log(err);
+ });
+ },
handleTerminal: function () {
var container = this.props.container;
var terminal = path.join(process.cwd(), 'resources', 'terminal').replace(/ /g, '\\\\ ');
@@ -320,7 +317,7 @@ var ContainerDetails = React.createClass({
Volumes
Terminal
diff --git a/app/ContainerModal.react.js b/app/ContainerModal.react.js
index a8f45c03b9..68558b0896 100644
--- a/app/ContainerModal.react.js
+++ b/app/ContainerModal.react.js
@@ -26,7 +26,7 @@ var ContainerModal = React.createClass({
},
componentDidMount: function () {
this.refs.searchInput.getDOMNode().focus();
- ContainerStore.on(ContainerStore.SERVER_RECOMMENDED_EVENT, this.update);
+ ContainerStore.on(ContainerStore.CLIENT_RECOMMENDED_EVENT, this.update);
},
update: function () {
if (!this.state.query.length) {
diff --git a/app/ContainerStore.js b/app/ContainerStore.js
index 504bd658d7..9099c31e36 100644
--- a/app/ContainerStore.js
+++ b/app/ContainerStore.js
@@ -19,9 +19,9 @@ var _muted = {};
var ContainerStore = assign(EventEmitter.prototype, {
CLIENT_CONTAINER_EVENT: 'client_container',
+ CLIENT_RECOMMENDED_EVENT: 'client_recommended_event',
SERVER_CONTAINER_EVENT: 'server_container',
SERVER_PROGRESS_EVENT: 'server_progress',
- SERVER_RECOMMENDED_EVENT: 'server_recommended_event',
SERVER_LOGS_EVENT: 'server_logs',
_pullScratchImage: function (callback) {
var image = docker.client().getImage('scratch:latest');
@@ -110,7 +110,7 @@ var ContainerStore = assign(EventEmitter.prototype, {
_createContainer: function (name, containerData, callback) {
var existing = docker.client().getContainer(name);
var self = this;
- containerData.name = name;
+ if (!containerData.name) containerData.name = containerData.Name;
if (containerData.Config && containerData.Config.Image) {
containerData.Image = containerData.Config.Image;
}
@@ -232,12 +232,12 @@ var ContainerStore = assign(EventEmitter.prototype, {
this.fetchAllContainers(function (err) {
callback();
this.emit(this.CLIENT_CONTAINER_EVENT);
- this.fetchRecommended(function (err) {
- this.emit(this.SERVER_RECOMMENDED_EVENT);
- }.bind(this));
this._resumePulling();
this._startListeningToEvents();
}.bind(this));
+ this.fetchRecommended(function (err) {
+ this.emit(this.CLIENT_RECOMMENDED_EVENT);
+ }.bind(this));
},
fetchContainer: function (id, callback) {
docker.client().getContainer(id).inspect(function (err, container) {
@@ -403,21 +403,27 @@ var ContainerStore = assign(EventEmitter.prototype, {
_muted[name] = false;
}.bind(this));
},
+ restart: function (name, callback) {
+ var container = docker.client().getContainer(name);
+ container.restart(function (err) {
+ callback(err);
+ });
+ },
remove: function (name, callback) {
var self = this;
- var existing = docker.client().getContainer(name);
+ var container = docker.client().getContainer(name);
if (_containers[name].State.Paused) {
- existing.unpause(function (err) {
+ container.unpause(function (err) {
if (err) {
callback(err);
return;
} else {
- existing.kill(function (err) {
+ container.kill(function (err) {
if (err) {
callback(err);
return;
} else {
- existing.remove(function (err) {
+ container.remove(function (err) {
if (err) {
callback(err);
return;
@@ -428,12 +434,12 @@ var ContainerStore = assign(EventEmitter.prototype, {
}
});
} else {
- existing.kill(function (err) {
+ container.kill(function (err) {
if (err) {
callback(err);
return;
} else {
- existing.remove(function (err) {
+ container.remove(function (err) {
if (err) {
callback(err);
return;
diff --git a/app/Containers.react.js b/app/Containers.react.js
index 45789f8db0..0372475515 100644
--- a/app/Containers.react.js
+++ b/app/Containers.react.js
@@ -72,6 +72,7 @@ var Containers = React.createClass({
sidebarHeaderClass += ' sep';
}
+ var container = this.getParams().name ? this.state.containers[this.getParams().name] : {};
return (
@@ -89,7 +90,7 @@ var Containers = React.createClass({
-
+
);
diff --git a/app/Menu.js b/app/Menu.js
new file mode 100644
index 0000000000..68bcd9cf2a
--- /dev/null
+++ b/app/Menu.js
@@ -0,0 +1,142 @@
+var remote = require('remote');
+var app = remote.require('app');
+var Menu = remote.require('menu');
+var MenuItem = remote.require('menu-item');
+var BrowserWindow = remote.require('browser-window');
+var router = require('./router');
+
+// main.js
+var template = [
+{
+ label: 'Kitematic',
+ submenu: [
+ {
+ label: 'About Kitematic',
+ selector: 'orderFrontStandardAboutPanel:'
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Preferences',
+ accelerator: 'Command+,',
+ click: function () {
+ router.transitionTo('preferences');
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Services',
+ submenu: []
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Hide Kitematic',
+ accelerator: 'Command+H',
+ selector: 'hide:'
+ },
+ {
+ label: 'Hide Others',
+ accelerator: 'Command+Shift+H',
+ selector: 'hideOtherApplications:'
+ },
+ {
+ label: 'Show All',
+ selector: 'unhideAllApplications:'
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Quit',
+ accelerator: 'Command+Q',
+ click: function() {
+ app.quit();
+ }
+ },
+ ]
+},
+{
+ label: 'Edit',
+ submenu: [
+ {
+ label: 'Undo',
+ accelerator: 'Command+Z',
+ selector: 'undo:'
+ },
+ {
+ label: 'Redo',
+ accelerator: 'Shift+Command+Z',
+ selector: 'redo:'
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Cut',
+ accelerator: 'Command+X',
+ selector: 'cut:'
+ },
+ {
+ label: 'Copy',
+ accelerator: 'Command+C',
+ selector: 'copy:'
+ },
+ {
+ label: 'Paste',
+ accelerator: 'Command+V',
+ selector: 'paste:'
+ },
+ {
+ label: 'Select All',
+ accelerator: 'Command+A',
+ selector: 'selectAll:'
+ },
+ ]
+},
+{
+ label: 'View',
+ submenu: [
+ {
+ label: 'Toggle DevTools',
+ accelerator: 'Alt+Command+I',
+ click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
+ },
+ ]
+},
+{
+ label: 'Window',
+ submenu: [
+ {
+ label: 'Minimize',
+ accelerator: 'Command+M',
+ selector: 'performMiniaturize:'
+ },
+ {
+ label: 'Close',
+ accelerator: 'Command+W',
+ selector: 'performClose:'
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Bring All to Front',
+ selector: 'arrangeInFront:'
+ },
+ ]
+},
+{
+ label: 'Help',
+ submenu: []
+},
+];
+
+menu = Menu.buildFromTemplate(template);
+Menu.setApplicationMenu(menu);
+
+module.exports = menu;
diff --git a/app/Preferences.react.js b/app/Preferences.react.js
new file mode 100644
index 0000000000..c18ddc782c
--- /dev/null
+++ b/app/Preferences.react.js
@@ -0,0 +1,64 @@
+var React = require('react/addons');
+var assign = require('object-assign');
+var ipc = require('ipc');
+
+// TODO: move this somewhere else
+if (localStorage.getItem('options')) {
+ ipc.send('vm', JSON.parse(localStorage.getItem('options')).save_vm_on_quit);
+}
+
+var Preferences = React.createClass({
+ getInitialState: function () {
+ var data = JSON.parse(localStorage.getItem('options'));
+ return assign({
+ save_vm_on_quit: true,
+ report_analytics: true
+ }, data || {});
+ },
+ handleChange: function (key, e) {
+ var change = {};
+ change[key] = !this.state[key];
+ console.log(change);
+ this.setState(change);
+ },
+ saveState: function () {
+ ipc.send('vm', this.state.save_vm_on_quit);
+ localStorage.setItem('options', JSON.stringify(this.state));
+ },
+ componentDidMount: function () {
+ this.saveState();
+ },
+ componentDidUpdate: function () {
+ this.saveState();
+ },
+ render: function () {
+ console.log('render');
+ return (
+
+
+
VM Settings
+
+
+ Save Linux VM state on closing Kitematic
+
+
+
+
+
+
App Settings
+
+
+ Report anonymous usage analytics
+
+
+
+
+
+
+
+
+ );
+ }
+});
+
+module.exports = Preferences;
diff --git a/app/Setup.react.js b/app/Setup.react.js
index 16f8928b31..08561310e5 100644
--- a/app/Setup.react.js
+++ b/app/Setup.react.js
@@ -173,7 +173,9 @@ var Setup = React.createClass({
if (!err) {
boot2docker.ip(function (err, ip) {
docker.setHost(ip);
- self.transitionTo('containers');
+ ContainerStore.init(function () {
+ self.transitionTo('containers');
+ });
});
}
});
diff --git a/app/index.html b/app/index.html
index a97ba8b788..699c7186f0 100644
--- a/app/index.html
+++ b/app/index.html
@@ -7,6 +7,5 @@
-