Merge pull request #1155 from FrenchBen/1061-VM-name

Added selector for VM fixes #1061
This commit is contained in:
Michael Chiang 2015-10-29 15:20:20 -07:00
Родитель f15c523080 e137c150da
Коммит 6325b07b5c
7 изменённых файлов: 161 добавлений и 4 удалений

Просмотреть файл

@ -26,7 +26,8 @@ var Header = React.createClass({
document.addEventListener('keyup', this.handleDocumentKeyUp, false); document.addEventListener('keyup', this.handleDocumentKeyUp, false);
accountStore.listen(this.update); accountStore.listen(this.update);
// remove listener if exists
ipc.removeAllListeners('application:update-available');
ipc.on('application:update-available', () => { ipc.on('application:update-available', () => {
this.setState({ this.setState({
updateAvailable: true updateAvailable: true

Просмотреть файл

@ -1,6 +1,8 @@
import React from 'react/addons'; import React from 'react/addons';
import metrics from '../utils/MetricsUtil'; import metrics from '../utils/MetricsUtil';
import Router from 'react-router'; import Router from 'react-router';
import setupUtil from '../utils/SetupUtil';
import docker from '../utils/DockerUtil';
var Preferences = React.createClass({ var Preferences = React.createClass({
mixins: [Router.Navigation], mixins: [Router.Navigation],
@ -14,6 +16,21 @@ var Preferences = React.createClass({
this.goBack(); this.goBack();
metrics.track('Went Back From Preferences'); metrics.track('Went Back From Preferences');
}, },
handleClearVMClick: function () {
localStorage.removeItem('settings.vm');
localStorage.removeItem('placeholders');
setupUtil.resetProgress();
setupUtil.setup().then(() => {
docker.init();
this.transitionTo('search');
}).catch(err => {
metrics.track('Setup Failed', {
step: 'catch',
message: err.message
});
throw err;
});
},
handleChangeCloseVMOnQuit: function (e) { handleChangeCloseVMOnQuit: function (e) {
var checked = e.target.checked; var checked = e.target.checked;
this.setState({ this.setState({
@ -48,6 +65,14 @@ var Preferences = React.createClass({
<input type="checkbox" checked={this.state.closeVMOnQuit} onChange={this.handleChangeCloseVMOnQuit}/> <input type="checkbox" checked={this.state.closeVMOnQuit} onChange={this.handleChangeCloseVMOnQuit}/>
</div> </div>
</div> </div>
<div className="option">
<div className="option-name">
Reset VM preferences
</div>
<div className="option-value">
<button className="btn btn-primary" onClick={this.handleClearVMClick}>Reset</button>
</div>
</div>
<div className="title">App Settings</div> <div className="title">App Settings</div>
<div className="option"> <div className="option">
<div className="option-name"> <div className="option-name">

Просмотреть файл

@ -0,0 +1,85 @@
import _ from 'underscore';
import utils from '../utils/Util';
import React from 'react/addons';
import Router from 'react-router';
import RetinaImage from 'react-retina-image';
import metrics from '../utils/MetricsUtil';
import {DropdownButton, MenuItem} from 'react-bootstrap';
import machine from '../utils/DockerMachineUtil';
import setupActions from '../actions/SetupActions';
var Setup = React.createClass({
mixins: [Router.Navigation],
getInitialState: function () {
return {
currentEngine: localStorage.getItem('settings.vm.name') || 'VM Available',
machines: {}
};
},
componentDidMount: function () {
machine.list().then( machines => {
if (typeof machines.default === 'undefined') {
machines.default = {'driver': 'virtualbox', 'name': 'default', 'create': true};
}
this.setState({
machines: machines
});
});
},
handleChangeDockerEngine: function (machineIndex) {
localStorage.setItem('settings.vm', JSON.stringify(this.state.machines[machineIndex]));
if (this.state.currentEngine !== machineIndex) {
this.setState({
currentEngine: machineIndex
});
}
setupActions.retry(false);
},
render: function () {
let currentDriver = '';
let machineDropdown = (<div className="spinner la-ball-clip-rotate la-dark la-lg" style={{marginLeft: 30 + '%'}}><div></div></div>);
if (!_.isEmpty(this.state.machines)) {
machineDropdown = React.addons.createFragment(_.mapObject(this.state.machines, (machineItem, index) => {
let menu = [];
let machineDriver = utils.camelCase(machineItem.driver);
let machineName = utils.camelCase(machineItem.name);
if (machineItem.create) {
machineName = 'Create ' + machineName;
}
if (currentDriver !== machineItem.driver) {
menu.push(<MenuItem header>{machineDriver}</MenuItem>);
currentDriver = machine.driver;
}
menu.push(<MenuItem onSelect={this.handleChangeDockerEngine.bind(this, index)} key={index}>{machineName}</MenuItem>);
return menu;
}));
}
return (
<div className="setup">
<div className="setup-content">
<div className="image">
<div className="contents">
<RetinaImage src="boot2docker.png" checkIfRetinaImgExists={false}/>
<div className="detail">
</div>
</div>
</div>
<div className="desc">
<div className="content">
<h1>Select Docker VM</h1>
<p>To run Docker containers on your computer, Kitematic needs Linux virtual machine.</p>
<DropdownButton bsStyle="primary" title={this.state.currentEngine}>
{machineDropdown}
</DropdownButton>
</div>
</div>
</div>
</div>
);
}
});
module.exports = Setup;

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react/addons'; import React from 'react/addons';
import Setup from './components/Setup.react'; import Setup from './components/Setup.react';
import SelectMachine from './components/SelectMachine.react';
import Account from './components/Account.react'; import Account from './components/Account.react';
import AccountSignup from './components/AccountSignup.react'; import AccountSignup from './components/AccountSignup.react';
import AccountLogin from './components/AccountLogin.react'; import AccountLogin from './components/AccountLogin.react';
@ -53,6 +54,7 @@ var routes = (
</Route> </Route>
<DefaultRoute name="loading" handler={Loading}/> <DefaultRoute name="loading" handler={Loading}/>
<Route name="setup" handler={Setup}/> <Route name="setup" handler={Setup}/>
<Route name="selectmachine" handler={SelectMachine}/>
</Route> </Route>
); );

Просмотреть файл

@ -13,7 +13,10 @@ var DockerMachine = {
} }
}, },
name: function () { name: function () {
return 'default'; return util.vmsettings().name || 'default';
},
driver: function () {
return util.vmsettings().driver || 'virtualbox';
}, },
installed: function () { installed: function () {
if (util.isWindows() && !process.env.DOCKER_TOOLBOX_INSTALL_PATH) { if (util.isWindows() && !process.env.DOCKER_TOOLBOX_INSTALL_PATH) {
@ -34,6 +37,24 @@ var DockerMachine = {
return null; return null;
} }
}, },
list: function () {
return util.exec([this.command(), 'ls']).then(stdout => {
var lines = stdout.trim().split('\n').filter(line => line.indexOf('time=') === -1);
var machines = {};
lines.slice(1, lines.length).forEach(line => {
var tokens = line.trim().split(/[\s]+/).filter(token => token !== '*');
var machine = {
name: tokens[0],
active: tokens[1],
driver: tokens[2],
state: tokens[3],
url: tokens[4] || ''
};
machines[machine.name] = machine;
});
return Promise.resolve(machines);
});
},
exists: function (machineName = this.name()) { exists: function (machineName = this.name()) {
return this.status(machineName).then(() => { return this.status(machineName).then(() => {
return true; return true;

Просмотреть файл

@ -26,6 +26,10 @@ export default {
}); });
}, },
resetProgress () {
setupServerActions.progress({progress: null});
},
clearTimers () { clearTimers () {
_timers.forEach(t => clearTimeout(t)); _timers.forEach(t => clearTimeout(t));
_timers = []; _timers = [];
@ -62,8 +66,20 @@ export default {
throw new Error('Docker Machine is not installed. Please install it via the Docker Toolbox.'); throw new Error('Docker Machine is not installed. Please install it via the Docker Toolbox.');
} }
// Allow machine selection on initial launch
if (!localStorage.getItem('settings.vm')) {
router.get().transitionTo('selectmachine');
await this.pause();
}
setupServerActions.started({started: true}); setupServerActions.started({started: true});
let exists = await virtualBox.vmExists(machine.name()) && fs.existsSync(path.join(util.home(), '.docker', 'machine', 'machines', machine.name()));
let exists = true;
// Check if we're dealing with a virtualbox machine
if (machine.driver() === 'virtualbox') {
exists = await virtualBox.vmExists(machine.name()) && fs.existsSync(path.join(util.home(), '.docker', 'machine', 'machines', machine.name()));
}
if (!exists) { if (!exists) {
router.get().transitionTo('setup'); router.get().transitionTo('setup');
setupServerActions.started({started: true}); setupServerActions.started({started: true});
@ -90,7 +106,6 @@ export default {
let tries = 80, ip = null; let tries = 80, ip = null;
while (!ip && tries > 0) { while (!ip && tries > 0) {
try { try {
console.log('Trying to fetch machine IP, tries left: ' + tries);
ip = await machine.ip(); ip = await machine.ip();
tries -= 1; tries -= 1;
await Promise.delay(1000); await Promise.delay(1000);

Просмотреть файл

@ -84,6 +84,9 @@ module.exports = {
} catch (err) {} } catch (err) {}
return settingsjson; return settingsjson;
}, },
vmsettings: function () {
return JSON.parse(localStorage.getItem('settings.vm')) || null;
},
isOfficialRepo: function (name) { isOfficialRepo: function (name) {
if (!name || !name.length) { if (!name || !name.length) {
return false; return false;
@ -143,6 +146,11 @@ module.exports = {
return 0; return 0;
}, },
camelCase: function (text) {
return text.toLowerCase().replace( /\b\w/g, function (m) {
return m.toUpperCase();
});
},
randomId: function () { randomId: function () {
return crypto.randomBytes(32).toString('hex'); return crypto.randomBytes(32).toString('hex');
}, },