Files
docker-docs/src/components/ContainerSettingsPorts.react.js
French Ben 73f29a2b49 Added port type support - fixes #344
Signed-off-by: French Ben <me+git@frenchben.com>
2015-11-10 14:08:49 -08:00

152 lines
5.0 KiB
JavaScript

import _ from 'underscore';
import React from 'react/addons';
import shell from 'shell';
import ContainerUtil from '../utils/ContainerUtil';
import containerActions from '../actions/ContainerActions';
import containerStore from '../stores/ContainerStore';
import metrics from '../utils/MetricsUtil';
import {webPorts} from '../utils/Util';
import {DropdownButton, MenuItem} from 'react-bootstrap';
var ContainerSettingsPorts = React.createClass({
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function () {
return {
ports: ContainerUtil.ports(this.props.container)
};
},
handleViewLink: function (url) {
metrics.track('Opened In Browser', {
from: 'settings'
});
shell.openExternal(url);
},
handleChangePort: function(key, e) {
let ports = this.state.ports;
let port = e.target.value;
// save updated port
ports[key] = _.extend(ports[key], {
url: 'http://' + ports[key]['ip'] + ':' + port,
port: port,
error: null
});
// basic validation, if number is integer, if its in range, if there
// is no collision with ports of other containers and also if there is no
// collision with ports for current container
const otherContainers = _.filter(_.values(containerStore.getState().containers), c => c.Name !== this.props.container.Name);
const otherPorts = _.flatten(otherContainers.map(container => {
return _.values(container.NetworkSettings.Ports).map(hosts => hosts.map(host => {return {port: host.HostPort, name: container.Name}}));
})).reduce((prev, pair) => {
prev[pair.port] = pair.name;
return prev;
}, {});
const duplicates = _.filter(ports, (v, i) => {
return (i != key && _.isEqual(v.port, port));
});
if (!port.match(/^[0-9]+$/g)) {
ports[key].error = 'Needs to be an integer.';
} else if (port <= 0 || port > 65535) {
ports[key].error = 'Needs to be in range <1,65535>.';
} else if (otherPorts[port]) {
ports[key].error = 'Collision with container "'+ otherPorts[port] +'"';
} else if (duplicates.length > 0) {
ports[key].error = 'Collision with another port in this container.';
} else if (port == 22 || port == 2376) {
ports[key].error = 'Ports 22 and 2376 are reserved ports for Kitematic/Docker.';
}
this.setState({ports: ports});
},
handleChangePortType: function (key, portType) {
let ports = this.state.ports;
let port = ports[key].port;
// save updated port
ports[key] = _.extend(ports[key], {
url: ports[key].ip + ':' + port,
port: port,
portType: portType,
error: null
});
this.setState({ports: ports});
},
handleSave: function () {
let bindings = _.reduce(this.state.ports, (res, value, key) => {
res[key + '/' + value.portType] = [{
HostPort: value.port
}];
return res;
}, {});
containerActions.update(this.props.container.Name, {
NetworkSettings: {
Ports: bindings
}
});
},
render: function () {
if (!this.props.container) {
return false;
}
var isUpdating = (this.props.container.State.Updating);
var isValid = true;
var ports = _.map(_.pairs(this.state.ports), pair => {
var key = pair[0];
var {ip, port, url, portType, error} = pair[1];
isValid = (error) ? false : isValid;
let ipLink = (this.props.container.State.Running && !this.props.container.State.Paused && !this.props.container.State.ExitCode && !this.props.container.State.Restarting) ? (<a onClick={this.handleViewLink.bind(this, url)}>{ip}</a>):({ip});
return (
<tr key={key}>
<td>{key}</td>
<td className="bind">
{ipLink}:
<input
type="text"
disabled={isUpdating}
onChange={this.handleChangePort.bind(this, key)}
defaultValue={port} />
</td>
<td>
<DropdownButton bsStyle="primary" title={portType}>
<MenuItem onSelect={this.handleChangePortType.bind(this, key, 'tcp')} key={key + '-tcp'}>TCP</MenuItem>
<MenuItem onSelect={this.handleChangePortType.bind(this, key, 'udp')} key={key + '-udp'}>UDP</MenuItem>
</DropdownButton>
</td>
<td className="error">{error}</td>
</tr>
);
});
return (
<div className="settings-panel">
<div className="settings-section">
<h3>Configure Ports</h3>
<table className="table ports">
<thead>
<tr>
<th>DOCKER PORT</th>
<th>MAC IP:PORT</th>
<th></th>
</tr>
</thead>
<tbody>
{ports}
</tbody>
</table>
<a className="btn btn-action"
disabled={isUpdating || !isValid}
onClick={this.handleSave}>
Save
</a>
</div>
</div>
);
}
});
module.exports = ContainerSettingsPorts;