mirror of https://github.com/docker/docs.git
Removing active event from ContainerStore
This commit is contained in:
parent
5d291b6cd8
commit
b28c27455f
|
@ -1,15 +1,19 @@
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
|
var Convert = require('ansi-to-html');
|
||||||
|
var convert = new Convert();
|
||||||
|
var ContainerStore = require('./ContainerStore');
|
||||||
|
var docker = require('./docker');
|
||||||
|
var exec = require('exec');
|
||||||
|
var boot2docker = require('./boot2docker');
|
||||||
|
var ProgressBar = require('react-bootstrap/ProgressBar');
|
||||||
|
|
||||||
var Route = Router.Route;
|
var Route = Router.Route;
|
||||||
var NotFoundRoute = Router.NotFoundRoute;
|
var NotFoundRoute = Router.NotFoundRoute;
|
||||||
var DefaultRoute = Router.DefaultRoute;
|
var DefaultRoute = Router.DefaultRoute;
|
||||||
var Link = Router.Link;
|
var Link = Router.Link;
|
||||||
var RouteHandler = Router.RouteHandler;
|
var RouteHandler = Router.RouteHandler;
|
||||||
var Convert = require('ansi-to-html');
|
|
||||||
var convert = new Convert();
|
|
||||||
var ContainerStore = require('./ContainerStore');
|
|
||||||
var docker = require('./docker');
|
|
||||||
|
|
||||||
var ContainerDetails = React.createClass({
|
var ContainerDetails = React.createClass({
|
||||||
mixins: [Router.State],
|
mixins: [Router.State],
|
||||||
|
@ -19,14 +23,17 @@ var ContainerDetails = React.createClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentWillReceiveProps: function () {
|
componentWillReceiveProps: function () {
|
||||||
console.log('props');
|
|
||||||
this.update();
|
this.update();
|
||||||
|
this.setState({
|
||||||
|
logs: []
|
||||||
|
});
|
||||||
var self = this;
|
var self = this;
|
||||||
var logs = [];
|
var logs = [];
|
||||||
var index = 0;
|
var index = 0;
|
||||||
docker.client().getContainer(this.getParams().name).logs({
|
docker.client().getContainer(this.getParams().name).logs({
|
||||||
follow: false,
|
follow: false,
|
||||||
stdout: true,
|
stdout: true,
|
||||||
|
stderr: true,
|
||||||
timestamps: true
|
timestamps: true
|
||||||
}, function (err, stream) {
|
}, function (err, stream) {
|
||||||
stream.setEncoding('utf8');
|
stream.setEncoding('utf8');
|
||||||
|
@ -44,6 +51,7 @@ var ContainerDetails = React.createClass({
|
||||||
docker.client().getContainer(self.getParams().name).logs({
|
docker.client().getContainer(self.getParams().name).logs({
|
||||||
follow: true,
|
follow: true,
|
||||||
stdout: true,
|
stdout: true,
|
||||||
|
stderr: true,
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
tail: 0
|
tail: 0
|
||||||
}, function (err, stream) {
|
}, function (err, stream) {
|
||||||
|
@ -75,11 +83,9 @@ var ContainerDetails = React.createClass({
|
||||||
},
|
},
|
||||||
update: function () {
|
update: function () {
|
||||||
var name = this.getParams().name;
|
var name = this.getParams().name;
|
||||||
var container = ContainerStore.container(name);
|
|
||||||
var progress = ContainerStore.progress(name);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
progress: progress,
|
container: ContainerStore.container(name),
|
||||||
container: container
|
progress: ContainerStore.progress(name)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_escapeHTML: function (html) {
|
_escapeHTML: function (html) {
|
||||||
|
@ -88,8 +94,32 @@ var ContainerDetails = React.createClass({
|
||||||
div.appendChild(text);
|
div.appendChild(text);
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
},
|
},
|
||||||
|
handleClick: function (name) {
|
||||||
|
var container = this.state.container;
|
||||||
|
boot2docker.ip(function (err, ip) {
|
||||||
|
var ports = _.map(container.NetworkSettings.Ports, function (value, key) {
|
||||||
|
var portProtocolPair = key.split('/');
|
||||||
|
var res = {
|
||||||
|
'port': portProtocolPair[0],
|
||||||
|
'protocol': portProtocolPair[1]
|
||||||
|
};
|
||||||
|
if (value && value.length) {
|
||||||
|
var port = value[0].HostPort;
|
||||||
|
res.host = ip;
|
||||||
|
res.port = port;
|
||||||
|
res.url = 'http://' + ip + ':' + port;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
console.log(ports);
|
||||||
|
exec(['open', ports[0].url], function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
console.log('render details');
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!this.state) {
|
if (!this.state) {
|
||||||
|
@ -111,12 +141,32 @@ var ContainerDetails = React.createClass({
|
||||||
state = <h2 className="status">restarting</h2>;
|
state = <h2 className="status">restarting</h2>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var progress;
|
||||||
|
if (this.state.progress > 0 && this.state.progress != 1) {
|
||||||
|
progress = (
|
||||||
|
<div className="details-progress">
|
||||||
|
<ProgressBar now={this.state.progress * 100} label="%(percent)s%" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
progress = <div></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
var button;
|
||||||
|
if (this.state.progress === 1) {
|
||||||
|
button = <a className="btn btn-primary" onClick={this.handleClick}>View</a>;
|
||||||
|
} else {
|
||||||
|
button = <a className="btn btn-primary disabled" onClick={this.handleClick}>View</a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = this.state.container.Name.replace('/', '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="details">
|
<div className="details">
|
||||||
<div className="details-header">
|
<div className="details-header">
|
||||||
<h1>{this.state.container.Name.replace('/', '')}</h1>
|
<h1>{name}</h1> <a className="btn btn-primary" onClick={this.handleClick}>View</a>
|
||||||
<h2>{this.state.progress}</h2>
|
|
||||||
</div>
|
</div>
|
||||||
|
{progress}
|
||||||
<div className="details-logs">
|
<div className="details-logs">
|
||||||
<div className="logs">
|
<div className="logs">
|
||||||
{logs}
|
{logs}
|
||||||
|
|
|
@ -16,16 +16,13 @@ var RouteHandler = Router.RouteHandler;
|
||||||
var Navigation= Router.Navigation;
|
var Navigation= Router.Navigation;
|
||||||
|
|
||||||
var ContainerList = React.createClass({
|
var ContainerList = React.createClass({
|
||||||
mixins: [Navigation],
|
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
return {
|
return {
|
||||||
active: null,
|
|
||||||
containers: []
|
containers: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
this.updateContainers();
|
this.updateContainers();
|
||||||
ContainerStore.addChangeListener(ContainerStore.ACTIVE, this.updateActive);
|
|
||||||
ContainerStore.addChangeListener(ContainerStore.CONTAINERS, this.updateContainers);
|
ContainerStore.addChangeListener(ContainerStore.CONTAINERS, this.updateContainers);
|
||||||
},
|
},
|
||||||
componentWillMount: function () {
|
componentWillMount: function () {
|
||||||
|
@ -33,29 +30,13 @@ var ContainerList = React.createClass({
|
||||||
},
|
},
|
||||||
componentWillUnmount: function () {
|
componentWillUnmount: function () {
|
||||||
ContainerStore.removeChangeListener(ContainerStore.CONTAINERS, this.updateContainers);
|
ContainerStore.removeChangeListener(ContainerStore.CONTAINERS, this.updateContainers);
|
||||||
ContainerStore.removeChangeListener(ContainerStore.ACTIVE, updateActive.update);
|
|
||||||
},
|
|
||||||
updateActive: function () {
|
|
||||||
if (ContainerStore.active()) {
|
|
||||||
this.transitionTo('container', {name: ContainerStore.active()});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
updateContainers: function () {
|
updateContainers: function () {
|
||||||
// Sort by name
|
// Sort by name
|
||||||
var containers = _.values(ContainerStore.containers()).sort(function (a, b) {
|
var containers = _.values(ContainerStore.containers()).sort(function (a, b) {
|
||||||
return a.Name.localeCompare(b.Name);
|
return a.Name.localeCompare(b.Name);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({containers: containers});
|
this.setState({containers: containers});
|
||||||
|
|
||||||
// Transition to the active container or set one
|
|
||||||
var active = ContainerStore.active();
|
|
||||||
if (!ContainerStore.container(active) && containers.length > 0) {
|
|
||||||
ContainerStore.setActive(containers[0].Name.replace('/', ''));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleClick: function (containerId) {
|
|
||||||
ContainerStore.setActive(name);
|
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -95,13 +76,15 @@ var ContainerList = React.createClass({
|
||||||
state = <div className="state state-stopped"></div>;
|
state = <div className="state state-stopped"></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var name = container.Name.replace('/', '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link key={container.Name.replace('/', '')} to="container" params={{name: container.Name.replace('/', '')}} onClick={self.handleClick.bind(self, container.Id)}>
|
<Link key={name} data-container={name} to="container" params={{name: name}}>
|
||||||
<li>
|
<li>
|
||||||
{state}
|
{state}
|
||||||
<div className="info">
|
<div className="info">
|
||||||
<div className="name">
|
<div className="name">
|
||||||
{container.Name.replace('/', '')}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
<div className="image">
|
<div className="image">
|
||||||
{imageName}
|
{imageName}
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
|
var async = require('async');
|
||||||
|
var $ = require('jquery');
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
var Modal = require('react-bootstrap/Modal');
|
var Modal = require('react-bootstrap/Modal');
|
||||||
var RetinaImage = require('react-retina-image');
|
var RetinaImage = require('react-retina-image');
|
||||||
var $ = require('jquery');
|
|
||||||
var ContainerStore = require('./ContainerStore');
|
var ContainerStore = require('./ContainerStore');
|
||||||
|
|
||||||
var Navigation = Router.Navigation;
|
var Navigation = Router.Navigation;
|
||||||
|
|
||||||
var ContainerModal = React.createClass({
|
var ContainerModal = React.createClass({
|
||||||
|
mixins: [Navigation],
|
||||||
_searchRequest: null,
|
_searchRequest: null,
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
return {
|
return {
|
||||||
query: '',
|
query: '',
|
||||||
results: []
|
results: [],
|
||||||
|
recommended: ContainerStore.recommended()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
|
@ -21,6 +24,8 @@ var ContainerModal = React.createClass({
|
||||||
search: function (query) {
|
search: function (query) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this._searchRequest = $.get('https://registry.hub.docker.com/v1/search?q=' + query, function (result) {
|
this._searchRequest = $.get('https://registry.hub.docker.com/v1/search?q=' + query, function (result) {
|
||||||
|
self._searchRequest.abort();
|
||||||
|
self._searchRequest = null;
|
||||||
if (self.isMounted()) {
|
if (self.isMounted()) {
|
||||||
self.setState(result);
|
self.setState(result);
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
@ -35,6 +40,7 @@ var ContainerModal = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._searchRequest) {
|
if (this._searchRequest) {
|
||||||
|
console.log('Cancel');
|
||||||
this._searchRequest.abort();
|
this._searchRequest.abort();
|
||||||
this._searchRequest = null;
|
this._searchRequest = null;
|
||||||
}
|
}
|
||||||
|
@ -48,14 +54,20 @@ var ContainerModal = React.createClass({
|
||||||
var name = event.target.getAttribute('name');
|
var name = event.target.getAttribute('name');
|
||||||
var self = this;
|
var self = this;
|
||||||
ContainerStore.create(name, 'latest', function (err, containerName) {
|
ContainerStore.create(name, 'latest', function (err, containerName) {
|
||||||
ContainerStore.setActive(containerName);
|
// this.transitionTo('containers', {container: containerName});
|
||||||
self.props.onRequestHide();
|
self.props.onRequestHide();
|
||||||
});
|
}.bind(this));
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var top = this.state.results.splice(0, 7);
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var results = top.map(function (r) {
|
|
||||||
|
var data;
|
||||||
|
if (this.state.query) {
|
||||||
|
data = this.state.results.splice(0, 7);
|
||||||
|
} else {
|
||||||
|
data = this.state.recommended;
|
||||||
|
}
|
||||||
|
var results = data.map(function (r) {
|
||||||
var name;
|
var name;
|
||||||
if (r.is_official) {
|
if (r.is_official) {
|
||||||
name = <span><RetinaImage src="official.png"/>{r.name}</span>;
|
name = <span><RetinaImage src="official.png"/>{r.name}</span>;
|
||||||
|
@ -79,6 +91,14 @@ var ContainerModal = React.createClass({
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var title;
|
||||||
|
if (this.state.query) {
|
||||||
|
title = <div className="title">Results</div>;
|
||||||
|
} else {
|
||||||
|
title = <div className="title">Recommended</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal {...this.props} animation={false} className="create-modal">
|
<Modal {...this.props} animation={false} className="create-modal">
|
||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
|
@ -88,7 +108,7 @@ var ContainerModal = React.createClass({
|
||||||
<a href="#"><span>What's an image?</span></a>
|
<a href="#"><span>What's an image?</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div className="results">
|
<div className="results">
|
||||||
<div className="title">Results</div>
|
{title}
|
||||||
<ul>
|
<ul>
|
||||||
{results}
|
{results}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -11,11 +11,11 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
CONTAINERS: 'containers',
|
CONTAINERS: 'containers',
|
||||||
PROGRESS: 'progress',
|
PROGRESS: 'progress',
|
||||||
LOGS: 'logs',
|
LOGS: 'logs',
|
||||||
ACTIVE: 'active',
|
RECOMMENDED: 'recommended',
|
||||||
|
_recommended: [],
|
||||||
_containers: {},
|
_containers: {},
|
||||||
_progress: {},
|
_progress: {},
|
||||||
_logs: {},
|
_logs: {},
|
||||||
_active: null,
|
|
||||||
_pullScratchImage: function (callback) {
|
_pullScratchImage: function (callback) {
|
||||||
var image = docker.client().getImage('scratch:latest');
|
var image = docker.client().getImage('scratch:latest');
|
||||||
image.inspect(function (err, data) {
|
image.inspect(function (err, data) {
|
||||||
|
@ -101,7 +101,9 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
// Refresh with docker & hook into events
|
// Refresh with docker & hook into events
|
||||||
var self = this;
|
var self = this;
|
||||||
this.update(function (err) {
|
this.update(function (err) {
|
||||||
|
self.updateRecommended(function (err) {
|
||||||
callback();
|
callback();
|
||||||
|
});
|
||||||
var downloading = _.filter(_.values(self._containers), function (container) {
|
var downloading = _.filter(_.values(self._containers), function (container) {
|
||||||
var env = container.Config.Env;
|
var env = container.Config.Env;
|
||||||
return _.indexOf(env, 'KITEMATIC_DOWNLOADING=true') !== -1;
|
return _.indexOf(env, 'KITEMATIC_DOWNLOADING=true') !== -1;
|
||||||
|
@ -168,6 +170,30 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateRecommended: function (callback) {
|
||||||
|
var self = this;
|
||||||
|
$.ajax({
|
||||||
|
url: 'https://kitematic.com/recommended.json',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function (res, status) {
|
||||||
|
var recommended = res.recommended;
|
||||||
|
async.map(recommended, function (repository, callback) {
|
||||||
|
$.get('https://registry.hub.docker.com/v1/search?q=' + repository, function (data) {
|
||||||
|
var results = data.results;
|
||||||
|
callback(null, _.find(results, function (r) {
|
||||||
|
return r.name === repository;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}, function (err, results) {
|
||||||
|
self._recommended = results;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
create: function (repository, tag, callback) {
|
create: function (repository, tag, callback) {
|
||||||
tag = tag || 'latest';
|
tag = tag || 'latest';
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -213,7 +239,6 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
self._progress[containerName] = 0;
|
self._progress[containerName] = 0;
|
||||||
self.emit(containerName);
|
|
||||||
|
|
||||||
stream.on('data', function (str) {
|
stream.on('data', function (str) {
|
||||||
console.log(str);
|
console.log(str);
|
||||||
|
@ -253,26 +278,19 @@ var ContainerStore = assign(EventEmitter.prototype, {
|
||||||
// If not then directly create the container
|
// If not then directly create the container
|
||||||
self._createContainer(imageName, containerName, function () {
|
self._createContainer(imageName, containerName, function () {
|
||||||
callback(null, containerName);
|
callback(null, containerName);
|
||||||
console.log('done');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setActive: function (name) {
|
|
||||||
console.log('set active');
|
|
||||||
this._active = name;
|
|
||||||
this.emit(this.ACTIVE);
|
|
||||||
},
|
|
||||||
active: function () {
|
|
||||||
return this._active;
|
|
||||||
},
|
|
||||||
// Returns all containers
|
|
||||||
containers: function() {
|
containers: function() {
|
||||||
return this._containers;
|
return this._containers;
|
||||||
},
|
},
|
||||||
container: function (name) {
|
container: function (name) {
|
||||||
return this._containers[name];
|
return this._containers[name];
|
||||||
},
|
},
|
||||||
|
recommended: function () {
|
||||||
|
return this._recommended;
|
||||||
|
},
|
||||||
progress: function (name) {
|
progress: function (name) {
|
||||||
return this._progress[name];
|
return this._progress[name];
|
||||||
},
|
},
|
||||||
|
|
|
@ -233,7 +233,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0px 45px 14px;
|
padding: 0px 45px 14px;
|
||||||
background: white;
|
position: relative;
|
||||||
|
a {
|
||||||
|
position: absolute;
|
||||||
|
right: 30px;
|
||||||
|
top: -4px;
|
||||||
|
}
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -253,6 +258,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.details-progress {
|
||||||
|
margin: 26% auto 0;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
.details-logs {
|
.details-logs {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
Loading…
Reference in New Issue