mirror of https://github.com/docker/docs.git
commit
d82560c313
30
gulpfile.js
30
gulpfile.js
|
|
@ -17,10 +17,18 @@ var packagejson = require('./package.json');
|
|||
|
||||
var dependencies = Object.keys(packagejson.dependencies);
|
||||
var isBeta = process.argv.indexOf('--beta') !== -1;
|
||||
|
||||
var settings;
|
||||
try {
|
||||
settings = JSON.parse(fs.readFileSync('settings.json'), 'utf8');
|
||||
} catch (err) {
|
||||
settings = {};
|
||||
}
|
||||
settings.beta = isBeta;
|
||||
|
||||
var options = {
|
||||
dev: process.argv.indexOf('release') === -1 && process.argv.indexOf('test') === -1,
|
||||
test: process.argv.indexOf('test') !== -1,
|
||||
integration: process.argv.indexOf('--integration') !== -1,
|
||||
beta: isBeta,
|
||||
filename: isBeta ? 'Kitematic (Beta).app' : 'Kitematic.app',
|
||||
name: isBeta ? 'Kitematic (Beta)' : 'Kitematic',
|
||||
|
|
@ -29,6 +37,11 @@ var options = {
|
|||
|
||||
gulp.task('js', function () {
|
||||
return gulp.src('src/**/*.js')
|
||||
.pipe(plumber(function(error) {
|
||||
gutil.log(gutil.colors.red('Error (' + error.plugin + '): ' + error.message));
|
||||
// emit the end event, to properly end the task
|
||||
this.emit('end');
|
||||
}))
|
||||
.pipe(gulpif(options.dev || options.test, sourcemaps.init()))
|
||||
.pipe(react())
|
||||
.pipe(babel({blacklist: ['regenerator']}))
|
||||
|
|
@ -86,7 +99,6 @@ gulp.task('dist', function () {
|
|||
'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app/node_modules',
|
||||
'cp -R browser dist/osx/<%= filename %>/Contents/Resources/app',
|
||||
'cp package.json dist/osx/<%= filename %>/Contents/Resources/app/',
|
||||
'cp settings.json dist/osx/<%= filename %>/Contents/Resources/app/',
|
||||
'mkdir -p dist/osx/<%= filename %>/Contents/Resources/app/resources',
|
||||
'cp -v resources/* dist/osx/<%= filename %>/Contents/Resources/app/resources/ || :',
|
||||
'cp <%= icon %> dist/osx/<%= filename %>/Contents/Resources/atom.icns',
|
||||
|
|
@ -139,8 +151,20 @@ gulp.task('zip', function () {
|
|||
}));
|
||||
});
|
||||
|
||||
gulp.task('settings', function () {
|
||||
var string_src = function (filename, string) {
|
||||
var src = require('stream').Readable({ objectMode: true });
|
||||
src._read = function () {
|
||||
this.push(new gutil.File({ cwd: "", base: "", path: filename, contents: new Buffer(string) }));
|
||||
this.push(null);
|
||||
};
|
||||
return src;
|
||||
};
|
||||
string_src('settings.json', JSON.stringify(settings)).pipe(gulp.dest('dist/osx/' + options.filename.replace(' ', '\ ').replace('(','\(').replace(')','\)') + '/Contents/Resources/app'));
|
||||
});
|
||||
|
||||
gulp.task('release', function () {
|
||||
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
|
||||
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles', 'settings'], 'sign', 'zip');
|
||||
});
|
||||
|
||||
gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
|
||||
|
|
|
|||
18
package.json
18
package.json
|
|
@ -12,7 +12,7 @@
|
|||
"bugs": "https://github.com/kitematic/kitematic/issues",
|
||||
"scripts": {
|
||||
"start": "gulp",
|
||||
"test": "jest",
|
||||
"test": "NODE_PATH=./cache/Atom.app/Contents/Resources/atom/renderer/api/lib:$NODE_PATH jest",
|
||||
"release": "gulp release",
|
||||
"release:beta": "gulp release --beta",
|
||||
"preinstall": "./deps",
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
],
|
||||
"jest": {
|
||||
"scriptPreprocessor": "<rootDir>/preprocessor.js",
|
||||
"setupEnvScriptFile": "<rootDir>/testenv.js",
|
||||
"unmockedModulePathPatterns": [
|
||||
"tty",
|
||||
"net",
|
||||
|
|
@ -41,21 +42,20 @@
|
|||
"docker-version": "1.5.0",
|
||||
"boot2docker-version": "1.5.0",
|
||||
"atom-shell-version": "0.21.1",
|
||||
"virtualbox-version": "4.3.20",
|
||||
"virtualbox-filename": "VirtualBox-4.3.20.pkg",
|
||||
"virtualbox-checksum": "89edac4cc7298c8a04fd4bb646ff2197e7673137c6566c7757f0e9cd6265d0c5",
|
||||
"virtualbox-required-version": "4.3.18",
|
||||
"virtualbox-version": "4.3.22",
|
||||
"virtualbox-filename": "VirtualBox-4.3.22.pkg",
|
||||
"virtualbox-checksum": "4a7dff25bdeef0d112e16ac11bee6d52e856d36bb412aa75576036ba560082eb",
|
||||
"virtualbox-required-version": "4.3.12",
|
||||
"dependencies": {
|
||||
"ansi-to-html": "0.2.0",
|
||||
"async": "^0.9.0",
|
||||
"babel": "^4.0.1",
|
||||
"bluebird": "^2.9.6",
|
||||
"bugsnag-js": "^2.4.7",
|
||||
"dockerode": "^2.0.7",
|
||||
"download": "^4.0.0",
|
||||
"exec": "0.1.2",
|
||||
"jquery": "^2.1.3",
|
||||
"minimist": "^1.1.0",
|
||||
"mixpanel": "0.0.20",
|
||||
"node-uuid": "^1.4.2",
|
||||
"object-assign": "^2.0.0",
|
||||
"react": "^0.12.2",
|
||||
|
|
@ -69,13 +69,13 @@
|
|||
"underscore": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^4.0.1",
|
||||
"browserify": "^6.2.0",
|
||||
"ecstatic": "^0.5.8",
|
||||
"glob": "^4.0.6",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-babel": "^3.0.0",
|
||||
"gulp-atom": "0.0.5",
|
||||
"gulp-babel": "^4.0.0",
|
||||
"gulp-atom": "0.0.5",
|
||||
"gulp-concat": "^2.3.4",
|
||||
"gulp-cssmin": "^0.1.6",
|
||||
"gulp-download-atom-shell": "0.0.4",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ var $ = require('jquery');
|
|||
var React = require('react/addons');
|
||||
var exec = require('exec');
|
||||
var path = require('path');
|
||||
var metrics = require('./Metrics');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var ContainerUtil = require('./ContainerUtil');
|
||||
var boot2docker = require('./Boot2Docker');
|
||||
|
|
@ -65,21 +66,27 @@ var ContainerDetailsSubheader = React.createClass({
|
|||
},
|
||||
showHome: function () {
|
||||
if (!this.disableTab()) {
|
||||
metrics.track('Viewed Home');
|
||||
this.transitionTo('containerHome', {name: this.getParams().name});
|
||||
}
|
||||
},
|
||||
showLogs: function () {
|
||||
if (!this.disableTab()) {
|
||||
metrics.track('Viewed Logs');
|
||||
this.transitionTo('containerLogs', {name: this.getParams().name});
|
||||
}
|
||||
},
|
||||
showSettings: function () {
|
||||
if (!this.disableTab()) {
|
||||
metrics.track('Viewed Settings');
|
||||
this.transitionTo('containerSettings', {name: this.getParams().name});
|
||||
}
|
||||
},
|
||||
handleRun: function () {
|
||||
if (this.state.defaultPort && !this.disableRun()) {
|
||||
metrics.track('Opened In Browser', {
|
||||
from: 'header'
|
||||
});
|
||||
exec(['open', this.state.ports[this.state.defaultPort].url], function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
|
|
@ -87,6 +94,7 @@ var ContainerDetailsSubheader = React.createClass({
|
|||
},
|
||||
handleRestart: function () {
|
||||
if (!this.disableRestart()) {
|
||||
metrics.track('Restarted Container');
|
||||
ContainerStore.restart(this.props.container.Name, function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
|
|
@ -94,12 +102,11 @@ var ContainerDetailsSubheader = React.createClass({
|
|||
},
|
||||
handleTerminal: function () {
|
||||
if (!this.disableTerminal()) {
|
||||
metrics.track('Terminaled Into Container');
|
||||
var container = this.props.container;
|
||||
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
||||
var cmd = [terminal, boot2docker.command().replace(/ /g, '\\\\\\\\ ').replace(/\(/g, '\\\\\\\\(').replace(/\)/g, '\\\\\\\\)'), 'ssh', '-t', 'sudo', 'docker', 'exec', '-i', '-t', container.Name, 'sh'];
|
||||
exec(cmd, function (stderr, stdout, code) {
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
if (code) {
|
||||
console.log(stderr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,23 @@ var React = require('react/addons');
|
|||
var RetinaImage = require('react-retina-image');
|
||||
var path = require('path');
|
||||
var exec = require('exec');
|
||||
var metrics = require('./Metrics');
|
||||
var Router = require('react-router');
|
||||
|
||||
var ContainerHomeFolder = React.createClass({
|
||||
mixins: [Router.State, Router.Navigation],
|
||||
handleClickFolder: function (path) {
|
||||
metrics.track('Opened Volume Directory', {
|
||||
from: 'home'
|
||||
});
|
||||
exec(['open', path], function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
},
|
||||
handleClickChangeFolders: function () {
|
||||
metrics.track('Viewed Volume Settings', {
|
||||
from: 'preview'
|
||||
});
|
||||
this.transitionTo('containerSettingsVolumes', {name: this.getParams().name});
|
||||
},
|
||||
render: function () {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ var $ = require('jquery');
|
|||
var React = require('react/addons');
|
||||
var LogStore = require('./LogStore');
|
||||
var Router = require('react-router');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var _oldScrollTop = 0;
|
||||
|
||||
|
|
@ -42,6 +43,9 @@ var ContainerHomeLogs = React.createClass({
|
|||
});
|
||||
},
|
||||
handleClickLogs: function () {
|
||||
metrics.track('Viewed Logs', {
|
||||
from: 'preview'
|
||||
});
|
||||
this.transitionTo('containerLogs', {name: this.getParams().name});
|
||||
},
|
||||
render: function () {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ var ContainerStore = require('./ContainerStore');
|
|||
var ContainerUtil = require('./ContainerUtil');
|
||||
var Router = require('react-router');
|
||||
var request = require('request');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var ContainerHomePreview = React.createClass({
|
||||
mixins: [Router.State, Router.Navigation],
|
||||
|
|
@ -57,12 +58,18 @@ var ContainerHomePreview = React.createClass({
|
|||
},
|
||||
handleClickPreview: function () {
|
||||
if (this.state.defaultPort) {
|
||||
metrics.track('Opened In Browser', {
|
||||
from: 'preview'
|
||||
});
|
||||
exec(['open', this.state.ports[this.state.defaultPort].url], function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
}
|
||||
},
|
||||
handleClickNotShowingCorrectly: function () {
|
||||
metrics.track('Viewed Port Settings', {
|
||||
from: 'preview'
|
||||
});
|
||||
this.transitionTo('containerSettingsPorts', {name: this.getParams().name});
|
||||
},
|
||||
render: function () {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ var React = require('react/addons');
|
|||
var Router = require('react-router');
|
||||
var remote = require('remote');
|
||||
var dialog = remote.require('dialog');
|
||||
var metrics = require('./Metrics');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var OverlayTrigger = require('react-bootstrap').OverlayTrigger;
|
||||
var Tooltip = require('react-bootstrap').Tooltip;
|
||||
|
|
@ -22,6 +23,10 @@ var ContainerListItem = React.createClass({
|
|||
buttons: ['Delete', 'Cancel']
|
||||
}, function (index) {
|
||||
if (index === 0) {
|
||||
metrics.track('Deleted Container', {
|
||||
from: 'list',
|
||||
type: 'existing'
|
||||
});
|
||||
ContainerStore.remove(this.props.container.Name, function (err) {
|
||||
console.error(err);
|
||||
var containers = ContainerStore.sorted();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ var $ = require('jquery');
|
|||
var React = require('react/addons');
|
||||
var Router = require('react-router');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var ContainerListNewItem = React.createClass({
|
||||
mixins: [Router.State, Router.Navigation],
|
||||
|
|
@ -15,6 +16,10 @@ var ContainerListNewItem = React.createClass({
|
|||
},
|
||||
handleDelete: function () {
|
||||
var self = this;
|
||||
metrics.track('Deleted Container', {
|
||||
from: 'list',
|
||||
type: 'new'
|
||||
});
|
||||
var containers = ContainerStore.sorted();
|
||||
$(self.getDOMNode()).fadeOut(300, function () {
|
||||
if (containers.length > 0) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ var path = require('path');
|
|||
var remote = require('remote');
|
||||
var rimraf = require('rimraf');
|
||||
var fs = require('fs');
|
||||
var metrics = require('./Metrics');
|
||||
var dialog = remote.require('dialog');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var ContainerUtil = require('./ContainerUtil');
|
||||
|
|
@ -91,8 +92,12 @@ var ContainerSettingsGeneral = React.createClass({
|
|||
}
|
||||
ContainerStore.rename(oldName, newName, err => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
this.setState({
|
||||
nameError: err.message
|
||||
});
|
||||
return;
|
||||
}
|
||||
metrics.track('Changed Container Name');
|
||||
this.transitionTo('containerSettingsGeneral', {name: newName});
|
||||
var oldPath = path.join(process.env.HOME, 'Kitematic', oldName);
|
||||
var newPath = path.join(process.env.HOME, 'Kitematic', newName);
|
||||
|
|
@ -127,6 +132,7 @@ var ContainerSettingsGeneral = React.createClass({
|
|||
envVarList.push(key + '=' + val);
|
||||
});
|
||||
var self = this;
|
||||
metrics.track('Saved Environment Variables');
|
||||
ContainerStore.updateContainer(self.props.container.Name, {
|
||||
Env: envVarList
|
||||
}, function (err) {
|
||||
|
|
@ -151,18 +157,21 @@ var ContainerSettingsGeneral = React.createClass({
|
|||
});
|
||||
$('#new-env-key').val('');
|
||||
$('#new-env-val').val('');
|
||||
metrics.track('Added Pending Environment Variable');
|
||||
},
|
||||
handleRemoveEnvVar: function (key) {
|
||||
var newEnv = _.omit(this.state.env, key);
|
||||
this.setState({
|
||||
env: newEnv
|
||||
});
|
||||
metrics.track('Removed Environment Variable');
|
||||
},
|
||||
handleRemovePendingEnvVar: function (key) {
|
||||
var newEnv = _.omit(this.state.pendingEnv, key);
|
||||
this.setState({
|
||||
pendingEnv: newEnv
|
||||
});
|
||||
metrics.track('Removed Pending Environment Variable');
|
||||
},
|
||||
handleDeleteContainer: function () {
|
||||
dialog.showMessageBox({
|
||||
|
|
@ -176,6 +185,10 @@ var ContainerSettingsGeneral = React.createClass({
|
|||
});
|
||||
}
|
||||
if (index === 0) {
|
||||
metrics.track('Deleted Container', {
|
||||
from: 'settings',
|
||||
type: 'existing'
|
||||
});
|
||||
ContainerStore.remove(this.props.container.Name, function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ var Router = require('react-router');
|
|||
var exec = require('exec');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var ContainerUtil = require('./ContainerUtil');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var ContainerSettingsPorts = React.createClass({
|
||||
mixins: [Router.State, Router.Navigation],
|
||||
|
|
@ -34,6 +35,9 @@ var ContainerSettingsPorts = React.createClass({
|
|||
});
|
||||
},
|
||||
handleViewLink: function (url) {
|
||||
metrics.track('Opened In Browser', {
|
||||
from: 'settings'
|
||||
});
|
||||
exec(['open', url], function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ var Router = require('react-router');
|
|||
var remote = require('remote');
|
||||
var exec = require('exec');
|
||||
var dialog = remote.require('dialog');
|
||||
var metrics = require('./Metrics');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
|
||||
var ContainerSettingsVolumes = React.createClass({
|
||||
|
|
@ -16,6 +17,7 @@ var ContainerSettingsVolumes = React.createClass({
|
|||
}
|
||||
var directory = filenames[0];
|
||||
if (directory) {
|
||||
metrics.track('Chose Directory for Volume');
|
||||
var volumes = _.clone(self.props.container.Volumes);
|
||||
volumes[dockerVol] = directory;
|
||||
var binds = _.pairs(volumes).map(function (pair) {
|
||||
|
|
@ -30,6 +32,9 @@ var ContainerSettingsVolumes = React.createClass({
|
|||
});
|
||||
},
|
||||
handleOpenVolumeClick: function (path) {
|
||||
metrics.track('Opened Volume Directory', {
|
||||
from: 'settings'
|
||||
});
|
||||
exec(['open', path], function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
|
|
@ -43,7 +48,7 @@ var ContainerSettingsVolumes = React.createClass({
|
|||
if (!val || val.indexOf(process.env.HOME) === -1) {
|
||||
val = (
|
||||
<span>
|
||||
<a className="value-right">No Folder</a>
|
||||
<a className="value-right">No Folder</a>
|
||||
<a className="btn btn-action small" onClick={self.handleChooseVolumeClick.bind(self, key)}>Change</a>
|
||||
</span>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ var async = require('async');
|
|||
var path = require('path');
|
||||
var assign = require('object-assign');
|
||||
var docker = require('./Docker');
|
||||
var metrics = require('./Metrics');
|
||||
var registry = require('./Registry');
|
||||
var LogStore = require('./LogStore');
|
||||
|
||||
|
|
@ -277,6 +278,7 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
|
|||
_muted[containerName] = true;
|
||||
_progress[containerName] = 0;
|
||||
self._pullImage(repository, tag, function () {
|
||||
metrics.track('Container Finished Creating');
|
||||
delete _placeholders[containerName];
|
||||
localStorage.setItem('store.placeholders', JSON.stringify(_placeholders));
|
||||
self._createContainer(containerName, {Image: imageName}, function () {
|
||||
|
|
@ -372,7 +374,19 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
|
|||
},
|
||||
sorted: function () {
|
||||
return _.values(this.containers()).sort(function (a, b) {
|
||||
return a.Name.localeCompare(b.Name);
|
||||
if (a.State.Downloading && !b.State.Downloading) {
|
||||
return -1;
|
||||
} else if (!a.State.Downloading && b.State.Downloading) {
|
||||
return 1;
|
||||
} else {
|
||||
if (a.State.Running && !b.State.Running) {
|
||||
return -1;
|
||||
} else if (!a.State.Running && b.State.Running) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.Name.localeCompare(b.Name);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
progress: function (name) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ var ContainerList = require('./ContainerList.react');
|
|||
var Header = require('./Header.react');
|
||||
var ipc = require('ipc');
|
||||
var remote = require('remote');
|
||||
var metrics = require('./Metrics');
|
||||
var autoUpdater = remote.require('auto-updater');
|
||||
|
||||
var Containers = React.createClass({
|
||||
|
|
@ -76,9 +77,10 @@ var Containers = React.createClass({
|
|||
handleNewContainer: function () {
|
||||
$(this.getDOMNode()).find('.new-container-item').parent().fadeIn();
|
||||
this.transitionTo('new');
|
||||
metrics.track('Pressed New Container');
|
||||
},
|
||||
handleAutoUpdateClick: function () {
|
||||
console.log('CLICKED UPDATE');
|
||||
metrics.track('Restarted to Update');
|
||||
ipc.send('command', 'application:quit-install');
|
||||
},
|
||||
render: function () {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ var $ = require('jquery');
|
|||
var React = require('react/addons');
|
||||
var RetinaImage = require('react-retina-image');
|
||||
var ContainerStore = require('./ContainerStore');
|
||||
var metrics = require('./Metrics');
|
||||
var OverlayTrigger = require('react-bootstrap').OverlayTrigger;
|
||||
var Tooltip = require('react-bootstrap').Tooltip;
|
||||
|
||||
|
|
@ -18,8 +19,10 @@ var ImageCard = React.createClass({
|
|||
});
|
||||
var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay');
|
||||
$tagOverlay.fadeOut(300);
|
||||
metrics.track('Selected Image Tag');
|
||||
},
|
||||
handleClick: function (name) {
|
||||
metrics.track('Created Container');
|
||||
ContainerStore.create(name, this.state.chosenTag, function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
|
|
@ -35,7 +38,6 @@ var ImageCard = React.createClass({
|
|||
tags: result
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
},
|
||||
handleCloseTagOverlay: function () {
|
||||
var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay');
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ var ContainerStore = require('./ContainerStore');
|
|||
var SetupStore = require('./SetupStore');
|
||||
var MenuTemplate = require('./MenuTemplate');
|
||||
var Menu = remote.require('menu');
|
||||
var metrics = require('./Metrics');
|
||||
var settingsjson;
|
||||
|
||||
try {
|
||||
|
|
@ -37,6 +38,10 @@ bugsnag.appVersion = app.getVersion();
|
|||
var menu = Menu.buildFromTemplate(MenuTemplate);
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
setInterval(function () {
|
||||
metrics.track('app heartbeat');
|
||||
}, 14400000);
|
||||
|
||||
router.run(Handler => React.render(<Handler/>, document.body));
|
||||
SetupStore.run().then(boot2docker.ip).then(ip => {
|
||||
console.log(ip);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ var docker = require('./Docker');
|
|||
var BrowserWindow = remote.require('browser-window');
|
||||
var router = require('./Router');
|
||||
var util = require('./Util');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
// main.js
|
||||
var MenuTemplate = [
|
||||
|
|
@ -71,6 +72,7 @@ var MenuTemplate = [
|
|||
label: 'Open Docker Terminal',
|
||||
accelerator: 'Command+Shift+T',
|
||||
click: function() {
|
||||
metrics.track('Opened Docker Terminal');
|
||||
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
||||
var cmd = [terminal, `DOCKER_HOST=${'tcp://' + docker.host + ':2376'} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm')} DOCKER_TLS_VERIFY=1 $SHELL`];
|
||||
util.exec(cmd).then(() => {});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
var assign = require('object-assign');
|
||||
var Mixpanel = require('mixpanel');
|
||||
var uuid = require('node-uuid');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var util = require('./Util');
|
||||
var settings;
|
||||
|
||||
try {
|
||||
settings = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||
} catch (err) {
|
||||
settings = {};
|
||||
}
|
||||
|
||||
var token = process.env.NODE_ENV === 'development' ? settings['mixpanel-dev'] : settings.mixpanel;
|
||||
if (!token) {
|
||||
token = 'none';
|
||||
}
|
||||
|
||||
var mixpanel = Mixpanel.init(token);
|
||||
|
||||
if (localStorage.getItem('metrics.enabled') === null) {
|
||||
localStorage.setItem('metrics.enabled', true);
|
||||
}
|
||||
|
||||
var Metrics = {
|
||||
enabled: function () {
|
||||
return localStorage.getItem('metrics.enabled') === 'true';
|
||||
},
|
||||
setEnabled: function (enabled) {
|
||||
localStorage.setItem('metrics.enabled', !!enabled);
|
||||
},
|
||||
track: function (name, data) {
|
||||
data = data || {};
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (localStorage.getItem('metrics.enabled') !== 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
var id = localStorage.getItem('metrics.id');
|
||||
if (!id) {
|
||||
localStorage.setItem('metrics.id', uuid.v4());
|
||||
}
|
||||
|
||||
var os = navigator.userAgent.match(/Mac OS X (\d+_\d+_\d+)/)[1].replace(/_/g, '.');
|
||||
mixpanel.track(name, assign({
|
||||
distinct_id: id,
|
||||
version: util.packagejson().version,
|
||||
'Operating System Version': os,
|
||||
beta: !!settings.beta
|
||||
}, data));
|
||||
},
|
||||
|
||||
};
|
||||
module.exports = Metrics;
|
||||
|
|
@ -5,6 +5,7 @@ var RetinaImage = require('react-retina-image');
|
|||
var Radial = require('./Radial.react');
|
||||
var ImageCard = require('./ImageCard.react');
|
||||
var Promise = require('bluebird');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var _recommended = [];
|
||||
var _searchPromise = null;
|
||||
|
|
@ -47,6 +48,7 @@ var NewContainer = React.createClass({
|
|||
});
|
||||
|
||||
_searchPromise = Promise.delay(200).then(() => Promise.resolve($.get('https://registry.hub.docker.com/v1/search?q=' + query))).cancellable().then(data => {
|
||||
metrics.track('Searched for Images');
|
||||
this.setState({
|
||||
results: data.results,
|
||||
query: query,
|
||||
|
|
|
|||
|
|
@ -1,53 +1,58 @@
|
|||
var React = require('react/addons');
|
||||
var assign = require('object-assign');
|
||||
var ipc = require('ipc');
|
||||
var metrics = require('./Metrics');
|
||||
var Router = require('react-router');
|
||||
|
||||
// TODO: move this somewhere else
|
||||
if (localStorage.getItem('options')) {
|
||||
ipc.send('vm', JSON.parse(localStorage.getItem('options')).save_vm_on_quit);
|
||||
if (localStorage.getItem('settings.saveVMOnQuit') === 'true') {
|
||||
ipc.send('vm', true);
|
||||
} else {
|
||||
ipc.send('vm', false);
|
||||
}
|
||||
|
||||
var Preferences = React.createClass({
|
||||
mixins: [Router.Navigation],
|
||||
getInitialState: function () {
|
||||
var data = JSON.parse(localStorage.getItem('options'));
|
||||
return assign({
|
||||
save_vm_on_quit: true,
|
||||
report_analytics: true
|
||||
}, data || {});
|
||||
},
|
||||
handleChange: function (key) {
|
||||
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();
|
||||
return {
|
||||
saveVMOnQuit: localStorage.getItem('settings.saveVMOnQuit') === 'true',
|
||||
metricsEnabled: metrics.enabled()
|
||||
};
|
||||
},
|
||||
handleGoBackClick: function () {
|
||||
this.goBack();
|
||||
metrics.track('Went Back From Preferences');
|
||||
},
|
||||
handleChangeSaveVMOnQuit: function (e) {
|
||||
var checked = e.target.checked;
|
||||
this.setState({
|
||||
saveVMOnQuit: checked
|
||||
});
|
||||
ipc.send('vm', checked);
|
||||
metrics.track('Toggled Save VM On Quit', {
|
||||
save: checked
|
||||
});
|
||||
},
|
||||
handleChangeMetricsEnabled: function (e) {
|
||||
var checked = e.target.checked;
|
||||
this.setState({
|
||||
metricsEnabled: checked
|
||||
});
|
||||
metrics.setEnabled(checked);
|
||||
metrics.track('Toggled Metrics', {
|
||||
enabled: checked
|
||||
});
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div className="preferences">
|
||||
<div className="preferences-content">
|
||||
<a href="#" onClick={this.handleGoBackClick}>Go Back</a>
|
||||
<a onClick={this.handleGoBackClick}>Go Back</a>
|
||||
<div className="title">VM Settings</div>
|
||||
<div className="option">
|
||||
<div className="option-name">
|
||||
Save Linux VM state on closing Kitematic
|
||||
</div>
|
||||
<div className="option-value">
|
||||
<input type="checkbox" checked={this.state.save_vm_on_quit} onChange={this.handleChange.bind(this, 'save_vm_on_quit')}/>
|
||||
<input type="checkbox" checked={this.state.saveVMOnQuit} onChange={this.handleChangeSaveVMOnQuit}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="title">App Settings</div>
|
||||
|
|
@ -56,10 +61,9 @@ var Preferences = React.createClass({
|
|||
Report anonymous usage analytics
|
||||
</div>
|
||||
<div className="option-value">
|
||||
<input type="checkbox" checked={this.state.report_analytics} onChange={this.handleChange.bind(this, 'report_analytics')}/>
|
||||
<input type="checkbox" checked={this.state.metricsEnabled} onChange={this.handleChangeMetricsEnabled}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ var SetupStore = require('./SetupStore');
|
|||
var RetinaImage = require('react-retina-image');
|
||||
var Header = require('./Header.react');
|
||||
var Util = require('./Util');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var Setup = React.createClass({
|
||||
mixins: [ Router.Navigation ],
|
||||
|
|
@ -28,6 +29,7 @@ var Setup = React.createClass({
|
|||
SetupStore.removeListener(SetupStore.ERROR_EVENT, this.update);
|
||||
},
|
||||
handleRetry: function () {
|
||||
metrics.track('Retried Setup');
|
||||
SetupStore.retry();
|
||||
},
|
||||
handleOpenWebsite: function () {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ var virtualBox = require('./VirtualBox');
|
|||
var setupUtil = require('./SetupUtil');
|
||||
var util = require('./Util');
|
||||
var assign = require('object-assign');
|
||||
var metrics = require('./Metrics');
|
||||
|
||||
var _currentStep = null;
|
||||
var _error = null;
|
||||
|
|
@ -167,6 +168,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
|||
return Promise.resolve();
|
||||
},
|
||||
run: Promise.coroutine(function* () {
|
||||
metrics.track('Started Setup');
|
||||
yield this.updateBinaries();
|
||||
var steps = yield this.requiredSteps();
|
||||
for (let step of steps) {
|
||||
|
|
@ -182,9 +184,15 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
|||
this.emit(this.PROGRESS_EVENT);
|
||||
}
|
||||
});
|
||||
metrics.track('Completed Step', {
|
||||
name: step.name
|
||||
});
|
||||
step.percent = 100;
|
||||
break;
|
||||
} catch (err) {
|
||||
metrics.track('Setup Failed', {
|
||||
step: step.name
|
||||
});
|
||||
console.log('Setup encountered an error.');
|
||||
console.log(err);
|
||||
if (err) {
|
||||
|
|
@ -198,6 +206,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
|||
}
|
||||
}
|
||||
}
|
||||
metrics.track('Finished Setup');
|
||||
_currentStep = null;
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
var mock = (function() {
|
||||
var store = {};
|
||||
return {
|
||||
getItem: function(key) {
|
||||
return store[key];
|
||||
},
|
||||
setItem: function(key, value) {
|
||||
store[key] = value.toString();
|
||||
},
|
||||
clear: function() {
|
||||
store = {};
|
||||
}
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(window, 'localStorage', { value: mock });
|
||||
Loading…
Reference in New Issue