aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/components/flowview
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2016-02-15 14:58:46 +0100
committerMaximilian Hils <git@maximilianhils.com>2016-02-15 14:58:46 +0100
commit33fa49277a821b9d38e8c9bf0bcf2adcfa2f6f04 (patch)
tree31914a601302579ff817504019296fd7e9e46765 /web/src/js/components/flowview
parent36f34f701991b5d474c005ec45e3b66e20f326a8 (diff)
downloadmitmproxy-33fa49277a821b9d38e8c9bf0bcf2adcfa2f6f04.tar.gz
mitmproxy-33fa49277a821b9d38e8c9bf0bcf2adcfa2f6f04.tar.bz2
mitmproxy-33fa49277a821b9d38e8c9bf0bcf2adcfa2f6f04.zip
move mitmproxy
Diffstat (limited to 'web/src/js/components/flowview')
-rw-r--r--web/src/js/components/flowview/contentview.js237
-rw-r--r--web/src/js/components/flowview/details.js181
-rw-r--r--web/src/js/components/flowview/index.js127
-rw-r--r--web/src/js/components/flowview/messages.js326
-rw-r--r--web/src/js/components/flowview/nav.js61
5 files changed, 0 insertions, 932 deletions
diff --git a/web/src/js/components/flowview/contentview.js b/web/src/js/components/flowview/contentview.js
deleted file mode 100644
index 63d22c1c..00000000
--- a/web/src/js/components/flowview/contentview.js
+++ /dev/null
@@ -1,237 +0,0 @@
-var React = require("react");
-var _ = require("lodash");
-
-var MessageUtils = require("../../flow/utils.js").MessageUtils;
-var utils = require("../../utils.js");
-
-var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i;
-var ViewImage = React.createClass({
- statics: {
- matches: function (message) {
- return image_regex.test(MessageUtils.getContentType(message));
- }
- },
- render: function () {
- var url = MessageUtils.getContentURL(this.props.flow, this.props.message);
- return <div className="flowview-image">
- <img src={url} alt="preview" className="img-thumbnail"/>
- </div>;
- }
-});
-
-var RawMixin = {
- getInitialState: function () {
- return {
- content: undefined,
- request: undefined
- }
- },
- requestContent: function (nextProps) {
- if (this.state.request) {
- this.state.request.abort();
- }
- var request = MessageUtils.getContent(nextProps.flow, nextProps.message);
- this.setState({
- content: undefined,
- request: request
- });
- request.done(function (data) {
- this.setState({content: data});
- }.bind(this)).fail(function (jqXHR, textStatus, errorThrown) {
- if (textStatus === "abort") {
- return;
- }
- this.setState({content: "AJAX Error: " + textStatus + "\r\n" + errorThrown});
- }.bind(this)).always(function () {
- this.setState({request: undefined});
- }.bind(this));
-
- },
- componentWillMount: function () {
- this.requestContent(this.props);
- },
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.message !== this.props.message) {
- this.requestContent(nextProps);
- }
- },
- componentWillUnmount: function () {
- if (this.state.request) {
- this.state.request.abort();
- }
- },
- render: function () {
- if (!this.state.content) {
- return <div className="text-center">
- <i className="fa fa-spinner fa-spin"></i>
- </div>;
- }
- return this.renderContent();
- }
-};
-
-var ViewRaw = React.createClass({
- mixins: [RawMixin],
- statics: {
- matches: function (message) {
- return true;
- }
- },
- renderContent: function () {
- return <pre>{this.state.content}</pre>;
- }
-});
-
-var json_regex = /^application\/json$/i;
-var ViewJSON = React.createClass({
- mixins: [RawMixin],
- statics: {
- matches: function (message) {
- return json_regex.test(MessageUtils.getContentType(message));
- }
- },
- renderContent: function () {
- var json = this.state.content;
- try {
- json = JSON.stringify(JSON.parse(json), null, 2);
- } catch (e) {
- }
- return <pre>{json}</pre>;
- }
-});
-
-var ViewAuto = React.createClass({
- statics: {
- matches: function () {
- return false; // don't match itself
- },
- findView: function (message) {
- for (var i = 0; i < all.length; i++) {
- if (all[i].matches(message)) {
- return all[i];
- }
- }
- return all[all.length - 1];
- }
- },
- render: function () {
- var View = ViewAuto.findView(this.props.message);
- return <View {...this.props}/>;
- }
-});
-
-var all = [ViewAuto, ViewImage, ViewJSON, ViewRaw];
-
-
-var ContentEmpty = React.createClass({
- render: function () {
- var message_name = this.props.flow.request === this.props.message ? "request" : "response";
- return <div className="alert alert-info">No {message_name} content.</div>;
- }
-});
-
-var ContentMissing = React.createClass({
- render: function () {
- var message_name = this.props.flow.request === this.props.message ? "Request" : "Response";
- return <div className="alert alert-info">{message_name} content missing.</div>;
- }
-});
-
-var TooLarge = React.createClass({
- statics: {
- isTooLarge: function (message) {
- var max_mb = ViewImage.matches(message) ? 10 : 0.2;
- return message.contentLength > 1024 * 1024 * max_mb;
- }
- },
- render: function () {
- var size = utils.formatSize(this.props.message.contentLength);
- return <div className="alert alert-warning">
- <button onClick={this.props.onClick} className="btn btn-xs btn-warning pull-right">Display anyway</button>
- {size} content size.
- </div>;
- }
-});
-
-var ViewSelector = React.createClass({
- render: function () {
- var views = [];
- for (var i = 0; i < all.length; i++) {
- var view = all[i];
- var className = "btn btn-default";
- if (view === this.props.active) {
- className += " active";
- }
- var text;
- if (view === ViewAuto) {
- text = "auto: " + ViewAuto.findView(this.props.message).displayName.toLowerCase().replace("view", "");
- } else {
- text = view.displayName.toLowerCase().replace("view", "");
- }
- views.push(
- <button
- key={view.displayName}
- onClick={this.props.selectView.bind(null, view)}
- className={className}>
- {text}
- </button>
- );
- }
-
- return <div className="view-selector btn-group btn-group-xs">{views}</div>;
- }
-});
-
-var ContentView = React.createClass({
- getInitialState: function () {
- return {
- displayLarge: false,
- View: ViewAuto
- };
- },
- propTypes: {
- // It may seem a bit weird at the first glance:
- // Every view takes the flow and the message as props, e.g.
- // <Auto flow={flow} message={flow.request}/>
- flow: React.PropTypes.object.isRequired,
- message: React.PropTypes.object.isRequired,
- },
- selectView: function (view) {
- this.setState({
- View: view
- });
- },
- displayLarge: function () {
- this.setState({displayLarge: true});
- },
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.message !== this.props.message) {
- this.setState(this.getInitialState());
- }
- },
- render: function () {
- var message = this.props.message;
- if (message.contentLength === 0) {
- return <ContentEmpty {...this.props}/>;
- } else if (message.contentLength === null) {
- return <ContentMissing {...this.props}/>;
- } else if (!this.state.displayLarge && TooLarge.isTooLarge(message)) {
- return <TooLarge {...this.props} onClick={this.displayLarge}/>;
- }
-
- var downloadUrl = MessageUtils.getContentURL(this.props.flow, message);
-
- return <div>
- <this.state.View {...this.props} />
- <div className="view-options text-center">
- <ViewSelector selectView={this.selectView} active={this.state.View} message={message}/>
- &nbsp;
- <a className="btn btn-default btn-xs" href={downloadUrl}>
- <i className="fa fa-download"/>
- </a>
- </div>
- </div>;
- }
-});
-
-module.exports = ContentView; \ No newline at end of file
diff --git a/web/src/js/components/flowview/details.js b/web/src/js/components/flowview/details.js
deleted file mode 100644
index 00e0116c..00000000
--- a/web/src/js/components/flowview/details.js
+++ /dev/null
@@ -1,181 +0,0 @@
-var React = require("react");
-var _ = require("lodash");
-
-var utils = require("../../utils.js");
-
-var TimeStamp = React.createClass({
- render: function () {
-
- if (!this.props.t) {
- //should be return null, but that triggers a React bug.
- return <tr></tr>;
- }
-
- var ts = utils.formatTimeStamp(this.props.t);
-
- var delta;
- if (this.props.deltaTo) {
- delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo));
- delta = <span className="text-muted">{"(" + delta + ")"}</span>;
- } else {
- delta = null;
- }
-
- return <tr>
- <td>{this.props.title + ":"}</td>
- <td>{ts} {delta}</td>
- </tr>;
- }
-});
-
-var ConnectionInfo = React.createClass({
-
- render: function () {
- var conn = this.props.conn;
- var address = conn.address.address.join(":");
-
- var sni = <tr key="sni"></tr>; //should be null, but that triggers a React bug.
- if (conn.sni) {
- sni = <tr key="sni">
- <td>
- <abbr title="TLS Server Name Indication">TLS SNI:</abbr>
- </td>
- <td>{conn.sni}</td>
- </tr>;
- }
- return (
- <table className="connection-table">
- <tbody>
- <tr key="address">
- <td>Address:</td>
- <td>{address}</td>
- </tr>
- {sni}
- </tbody>
- </table>
- );
- }
-});
-
-var CertificateInfo = React.createClass({
- render: function () {
- //TODO: We should fetch human-readable certificate representation
- // from the server
- var flow = this.props.flow;
- var client_conn = flow.client_conn;
- var server_conn = flow.server_conn;
-
- var preStyle = {maxHeight: 100};
- return (
- <div>
- {client_conn.cert ? <h4>Client Certificate</h4> : null}
- {client_conn.cert ? <pre style={preStyle}>{client_conn.cert}</pre> : null}
-
- {server_conn.cert ? <h4>Server Certificate</h4> : null}
- {server_conn.cert ? <pre style={preStyle}>{server_conn.cert}</pre> : null}
- </div>
- );
- }
-});
-
-var Timing = React.createClass({
- render: function () {
- var flow = this.props.flow;
- var sc = flow.server_conn;
- var cc = flow.client_conn;
- var req = flow.request;
- var resp = flow.response;
-
- var timestamps = [
- {
- title: "Server conn. initiated",
- t: sc.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Server conn. TCP handshake",
- t: sc.timestamp_tcp_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "Server conn. SSL handshake",
- t: sc.timestamp_ssl_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "Client conn. established",
- t: cc.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Client conn. SSL handshake",
- t: cc.timestamp_ssl_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "First request byte",
- t: req.timestamp_start,
- }, {
- title: "Request complete",
- t: req.timestamp_end,
- deltaTo: req.timestamp_start
- }
- ];
-
- if (flow.response) {
- timestamps.push(
- {
- title: "First response byte",
- t: resp.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Response complete",
- t: resp.timestamp_end,
- deltaTo: req.timestamp_start
- }
- );
- }
-
- //Add unique key for each row.
- timestamps.forEach(function (e) {
- e.key = e.title;
- });
-
- timestamps = _.sortBy(timestamps, 't');
-
- var rows = timestamps.map(function (e) {
- return <TimeStamp {...e}/>;
- });
-
- return (
- <div>
- <h4>Timing</h4>
- <table className="timing-table">
- <tbody>
- {rows}
- </tbody>
- </table>
- </div>
- );
- }
-});
-
-var Details = React.createClass({
- render: function () {
- var flow = this.props.flow;
- var client_conn = flow.client_conn;
- var server_conn = flow.server_conn;
- return (
- <section>
-
- <h4>Client Connection</h4>
- <ConnectionInfo conn={client_conn}/>
-
- <h4>Server Connection</h4>
- <ConnectionInfo conn={server_conn}/>
-
- <CertificateInfo flow={flow}/>
-
- <Timing flow={flow}/>
-
- </section>
- );
- }
-});
-
-module.exports = Details; \ No newline at end of file
diff --git a/web/src/js/components/flowview/index.js b/web/src/js/components/flowview/index.js
deleted file mode 100644
index 739a46dc..00000000
--- a/web/src/js/components/flowview/index.js
+++ /dev/null
@@ -1,127 +0,0 @@
-var React = require("react");
-var _ = require("lodash");
-
-var common = require("../common.js");
-var Nav = require("./nav.js");
-var Messages = require("./messages.js");
-var Details = require("./details.js");
-var Prompt = require("../prompt.js");
-
-
-var allTabs = {
- request: Messages.Request,
- response: Messages.Response,
- error: Messages.Error,
- details: Details
-};
-
-var FlowView = React.createClass({
- mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState],
- getInitialState: function () {
- return {
- prompt: false
- };
- },
- getTabs: function (flow) {
- var tabs = [];
- ["request", "response", "error"].forEach(function (e) {
- if (flow[e]) {
- tabs.push(e);
- }
- });
- tabs.push("details");
- return tabs;
- },
- nextTab: function (i) {
- var tabs = this.getTabs(this.props.flow);
- var currentIndex = tabs.indexOf(this.getActive());
- // JS modulo operator doesn't correct negative numbers, make sure that we are positive.
- var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
- this.selectTab(tabs[nextIndex]);
- },
- selectTab: function (panel) {
- this.replaceWith(
- "flow",
- {
- flowId: this.getParams().flowId,
- detailTab: panel
- }
- );
- },
- getActive: function(){
- return this.getParams().detailTab;
- },
- promptEdit: function () {
- var options;
- switch(this.getActive()){
- case "request":
- options = [
- "method",
- "url",
- {text:"http version", key:"v"},
- "header"
- /*, "content"*/];
- break;
- case "response":
- options = [
- {text:"http version", key:"v"},
- "code",
- "message",
- "header"
- /*, "content"*/];
- break;
- case "details":
- return;
- default:
- throw "Unknown tab for edit: " + this.getActive();
- }
-
- this.setState({
- prompt: {
- done: function (k) {
- this.setState({prompt: false});
- if(k){
- this.refs.tab.edit(k);
- }
- }.bind(this),
- options: options
- }
- });
- },
- render: function () {
- var flow = this.props.flow;
- var tabs = this.getTabs(flow);
- var active = this.getActive();
-
- if (!_.contains(tabs, active)) {
- if (active === "response" && flow.error) {
- active = "error";
- } else if (active === "error" && flow.response) {
- active = "response";
- } else {
- active = tabs[0];
- }
- this.selectTab(active);
- }
-
- var prompt = null;
- if (this.state.prompt) {
- prompt = <Prompt {...this.state.prompt}/>;
- }
-
- var Tab = allTabs[active];
- return (
- <div className="flow-detail" onScroll={this.adjustHead}>
- <Nav ref="head"
- flow={flow}
- tabs={tabs}
- active={active}
- selectTab={this.selectTab}/>
- <Tab ref="tab" flow={flow}/>
- {prompt}
- </div>
- );
- }
-});
-
-module.exports = FlowView; \ No newline at end of file
diff --git a/web/src/js/components/flowview/messages.js b/web/src/js/components/flowview/messages.js
deleted file mode 100644
index 7ac95d85..00000000
--- a/web/src/js/components/flowview/messages.js
+++ /dev/null
@@ -1,326 +0,0 @@
-var React = require("react");
-var _ = require("lodash");
-
-var common = require("../common.js");
-var actions = require("../../actions.js");
-var flowutils = require("../../flow/utils.js");
-var utils = require("../../utils.js");
-var ContentView = require("./contentview.js");
-var ValueEditor = require("../editor.js").ValueEditor;
-
-var Headers = React.createClass({
- propTypes: {
- onChange: React.PropTypes.func.isRequired,
- message: React.PropTypes.object.isRequired
- },
- onChange: function (row, col, val) {
- var nextHeaders = _.cloneDeep(this.props.message.headers);
- nextHeaders[row][col] = val;
- if (!nextHeaders[row][0] && !nextHeaders[row][1]) {
- // do not delete last row
- if (nextHeaders.length === 1) {
- nextHeaders[0][0] = "Name";
- nextHeaders[0][1] = "Value";
- } else {
- nextHeaders.splice(row, 1);
- // manually move selection target if this has been the last row.
- if (row === nextHeaders.length) {
- this._nextSel = (row - 1) + "-value";
- }
- }
- }
- this.props.onChange(nextHeaders);
- },
- edit: function () {
- this.refs["0-key"].focus();
- },
- onTab: function (row, col, e) {
- var headers = this.props.message.headers;
- if (row === headers.length - 1 && col === 1) {
- e.preventDefault();
-
- var nextHeaders = _.cloneDeep(this.props.message.headers);
- nextHeaders.push(["Name", "Value"]);
- this.props.onChange(nextHeaders);
- this._nextSel = (row + 1) + "-key";
- }
- },
- componentDidUpdate: function () {
- if (this._nextSel && this.refs[this._nextSel]) {
- this.refs[this._nextSel].focus();
- this._nextSel = undefined;
- }
- },
- onRemove: function (row, col, e) {
- if (col === 1) {
- e.preventDefault();
- this.refs[row + "-key"].focus();
- } else if (row > 0) {
- e.preventDefault();
- this.refs[(row - 1) + "-value"].focus();
- }
- },
- render: function () {
-
- var rows = this.props.message.headers.map(function (header, i) {
-
- var kEdit = <HeaderEditor
- ref={i + "-key"}
- content={header[0]}
- onDone={this.onChange.bind(null, i, 0)}
- onRemove={this.onRemove.bind(null, i, 0)}
- onTab={this.onTab.bind(null, i, 0)}/>;
- var vEdit = <HeaderEditor
- ref={i + "-value"}
- content={header[1]}
- onDone={this.onChange.bind(null, i, 1)}
- onRemove={this.onRemove.bind(null, i, 1)}
- onTab={this.onTab.bind(null, i, 1)}/>;
- return (
- <tr key={i}>
- <td className="header-name">{kEdit}:</td>
- <td className="header-value">{vEdit}</td>
- </tr>
- );
- }.bind(this));
- return (
- <table className="header-table">
- <tbody>
- {rows}
- </tbody>
- </table>
- );
- }
-});
-
-var HeaderEditor = React.createClass({
- render: function () {
- return <ValueEditor ref="input" {...this.props} onKeyDown={this.onKeyDown} inline/>;
- },
- focus: function () {
- this.getDOMNode().focus();
- },
- onKeyDown: function (e) {
- switch (e.keyCode) {
- case utils.Key.BACKSPACE:
- var s = window.getSelection().getRangeAt(0);
- if (s.startOffset === 0 && s.endOffset === 0) {
- this.props.onRemove(e);
- }
- break;
- case utils.Key.TAB:
- if (!e.shiftKey) {
- this.props.onTab(e);
- }
- break;
- }
- }
-});
-
-var RequestLine = React.createClass({
- render: function () {
- var flow = this.props.flow;
- var url = flowutils.RequestUtils.pretty_url(flow.request);
- var httpver = flow.request.http_version;
-
- return <div className="first-line request-line">
- <ValueEditor
- ref="method"
- content={flow.request.method}
- onDone={this.onMethodChange}
- inline/>
- &nbsp;
- <ValueEditor
- ref="url"
- content={url}
- onDone={this.onUrlChange}
- isValid={this.isValidUrl}
- inline/>
- &nbsp;
- <ValueEditor
- ref="httpVersion"
- content={httpver}
- onDone={this.onHttpVersionChange}
- isValid={flowutils.isValidHttpVersion}
- inline/>
- </div>
- },
- isValidUrl: function (url) {
- var u = flowutils.parseUrl(url);
- return !!u.host;
- },
- onMethodChange: function (nextMethod) {
- actions.FlowActions.update(
- this.props.flow,
- {request: {method: nextMethod}}
- );
- },
- onUrlChange: function (nextUrl) {
- var props = flowutils.parseUrl(nextUrl);
- props.path = props.path || "";
- actions.FlowActions.update(
- this.props.flow,
- {request: props}
- );
- },
- onHttpVersionChange: function (nextVer) {
- var ver = flowutils.parseHttpVersion(nextVer);
- actions.FlowActions.update(
- this.props.flow,
- {request: {http_version: ver}}
- );
- }
-});
-
-var ResponseLine = React.createClass({
- render: function () {
- var flow = this.props.flow;
- var httpver = flow.response.http_version;
- return <div className="first-line response-line">
- <ValueEditor
- ref="httpVersion"
- content={httpver}
- onDone={this.onHttpVersionChange}
- isValid={flowutils.isValidHttpVersion}
- inline/>
- &nbsp;
- <ValueEditor
- ref="code"
- content={flow.response.status_code + ""}
- onDone={this.onCodeChange}
- isValid={this.isValidCode}
- inline/>
- &nbsp;
- <ValueEditor
- ref="msg"
- content={flow.response.msg}
- onDone={this.onMsgChange}
- inline/>
- </div>;
- },
- isValidCode: function (code) {
- return /^\d+$/.test(code);
- },
- onHttpVersionChange: function (nextVer) {
- var ver = flowutils.parseHttpVersion(nextVer);
- actions.FlowActions.update(
- this.props.flow,
- {response: {http_version: ver}}
- );
- },
- onMsgChange: function (nextMsg) {
- actions.FlowActions.update(
- this.props.flow,
- {response: {msg: nextMsg}}
- );
- },
- onCodeChange: function (nextCode) {
- nextCode = parseInt(nextCode);
- actions.FlowActions.update(
- this.props.flow,
- {response: {code: nextCode}}
- );
- }
-});
-
-var Request = React.createClass({
- render: function () {
- var flow = this.props.flow;
- return (
- <section className="request">
- <RequestLine ref="requestLine" flow={flow}/>
- {/*<ResponseLine flow={flow}/>*/}
- <Headers ref="headers" message={flow.request} onChange={this.onHeaderChange}/>
- <hr/>
- <ContentView flow={flow} message={flow.request}/>
- </section>
- );
- },
- edit: function (k) {
- switch (k) {
- case "m":
- this.refs.requestLine.refs.method.focus();
- break;
- case "u":
- this.refs.requestLine.refs.url.focus();
- break;
- case "v":
- this.refs.requestLine.refs.httpVersion.focus();
- break;
- case "h":
- this.refs.headers.edit();
- break;
- default:
- throw "Unimplemented: " + k;
- }
- },
- onHeaderChange: function (nextHeaders) {
- actions.FlowActions.update(this.props.flow, {
- request: {
- headers: nextHeaders
- }
- });
- }
-});
-
-var Response = React.createClass({
- render: function () {
- var flow = this.props.flow;
- return (
- <section className="response">
- {/*<RequestLine flow={flow}/>*/}
- <ResponseLine ref="responseLine" flow={flow}/>
- <Headers ref="headers" message={flow.response} onChange={this.onHeaderChange}/>
- <hr/>
- <ContentView flow={flow} message={flow.response}/>
- </section>
- );
- },
- edit: function (k) {
- switch (k) {
- case "c":
- this.refs.responseLine.refs.status_code.focus();
- break;
- case "m":
- this.refs.responseLine.refs.msg.focus();
- break;
- case "v":
- this.refs.responseLine.refs.httpVersion.focus();
- break;
- case "h":
- this.refs.headers.edit();
- break;
- default:
- throw "Unimplemented: " + k;
- }
- },
- onHeaderChange: function (nextHeaders) {
- actions.FlowActions.update(this.props.flow, {
- response: {
- headers: nextHeaders
- }
- });
- }
-});
-
-var Error = React.createClass({
- render: function () {
- var flow = this.props.flow;
- return (
- <section>
- <div className="alert alert-warning">
- {flow.error.msg}
- <div>
- <small>{ utils.formatTimeStamp(flow.error.timestamp) }</small>
- </div>
- </div>
- </section>
- );
- }
-});
-
-module.exports = {
- Request: Request,
- Response: Response,
- Error: Error
-};
diff --git a/web/src/js/components/flowview/nav.js b/web/src/js/components/flowview/nav.js
deleted file mode 100644
index 46eda707..00000000
--- a/web/src/js/components/flowview/nav.js
+++ /dev/null
@@ -1,61 +0,0 @@
-var React = require("react");
-
-var actions = require("../../actions.js");
-
-var NavAction = React.createClass({
- onClick: function (e) {
- e.preventDefault();
- this.props.onClick();
- },
- render: function () {
- return (
- <a title={this.props.title}
- href="#"
- className="nav-action"
- onClick={this.onClick}>
- <i className={"fa fa-fw " + this.props.icon}></i>
- </a>
- );
- }
-});
-
-var Nav = React.createClass({
- render: function () {
- var flow = this.props.flow;
-
- var tabs = this.props.tabs.map(function (e) {
- var str = e.charAt(0).toUpperCase() + e.slice(1);
- var className = this.props.active === e ? "active" : "";
- var onClick = function (event) {
- this.props.selectTab(e);
- event.preventDefault();
- }.bind(this);
- return <a key={e}
- href="#"
- className={className}
- onClick={onClick}>{str}</a>;
- }.bind(this));
-
- var acceptButton = null;
- if(flow.intercepted){
- acceptButton = <NavAction title="[a]ccept intercepted flow" icon="fa-play" onClick={actions.FlowActions.accept.bind(null, flow)} />;
- }
- var revertButton = null;
- if(flow.modified){
- revertButton = <NavAction title="revert changes to flow [V]" icon="fa-history" onClick={actions.FlowActions.revert.bind(null, flow)} />;
- }
-
- return (
- <nav ref="head" className="nav-tabs nav-tabs-sm">
- {tabs}
- <NavAction title="[d]elete flow" icon="fa-trash" onClick={actions.FlowActions.delete.bind(null, flow)} />
- <NavAction title="[D]uplicate flow" icon="fa-copy" onClick={actions.FlowActions.duplicate.bind(null, flow)} />
- <NavAction disabled title="[r]eplay flow" icon="fa-repeat" onClick={actions.FlowActions.replay.bind(null, flow)} />
- {acceptButton}
- {revertButton}
- </nav>
- );
- }
-});
-
-module.exports = Nav; \ No newline at end of file