import React from "react";
import ReactDOM from "react-dom";
import classNames from "classnames";
import {reverseString} from "../utils.js";
import _ from "lodash";
import shallowEqual from "shallowequal";
import AutoScroll from "./helpers/AutoScroll";
import {calcVScroll} from "./helpers/VirtualScroll";
import flowtable_columns from "./flowtable-columns.js";
FlowRow.propTypes = {
selectFlow: React.PropTypes.func.isRequired,
columns: React.PropTypes.array.isRequired,
flow: React.PropTypes.object.isRequired,
highlighted: React.PropTypes.bool,
selected: React.PropTypes.bool,
};
function FlowRow(props) {
const flow = props.flow;
const className = classNames({
"selected": props.selected,
"highlighted": props.highlighted,
"intercepted": flow.intercepted,
"has-request": flow.request,
"has-response": flow.response,
});
return (
props.selectFlow(flow)}>
{props.columns.map(Column => (
))}
);
}
class FlowTableHead extends React.Component {
static propTypes = {
setSortKeyFun: React.PropTypes.func.isRequired,
columns: React.PropTypes.array.isRequired,
};
constructor(props, context) {
super(props, context);
this.state = { sortColumn: undefined, sortDesc: false };
}
onClick(Column) {
const hasSort = Column.sortKeyFun;
let sortDesc = this.state.sortDesc;
if (Column === this.state.sortColumn) {
sortDesc = !sortDesc;
this.setState({ sortDesc });
} else {
this.setState({ sortColumn: hasSort && Column, sortDesc: false });
}
let sortKeyFun = Column.sortKeyFun;
if (sortDesc) {
sortKeyFun = hasSort && function() {
const k = Column.sortKeyFun.apply(this, arguments);
if (_.isString(k)) {
return reverseString("" + k);
}
return -k;
};
}
this.props.setSortKeyFun(sortKeyFun);
}
render() {
const sortColumn = this.state.sortColumn;
const sortType = this.state.sortDesc ? "sort-desc" : "sort-asc";
return (
{this.props.columns.map(Column => (
this.onClick(Column)}
className={sortColumn === Column && sortType}
/>
))}
);
}
}
class FlowTable extends React.Component {
static contextTypes = {
view: React.PropTypes.object.isRequired,
};
static propTypes = {
rowHeight: React.PropTypes.number,
};
static defaultProps = {
rowHeight: 32,
};
constructor(props, context) {
super(props, context);
this.state = { flows: [], vScroll: calcVScroll() };
this.onChange = this.onChange.bind(this);
this.onViewportUpdate = this.onViewportUpdate.bind(this);
}
componentWillMount() {
window.addEventListener("resize", this.onViewportUpdate);
this.context.view.addListener("add", this.onChange);
this.context.view.addListener("update", this.onChange);
this.context.view.addListener("remove", this.onChange);
this.context.view.addListener("recalculate", this.onChange);
}
componentWillUnmount() {
window.removeEventListener("resize", this.onViewportUpdate);
this.context.view.removeListener("add", this.onChange);
this.context.view.removeListener("update", this.onChange);
this.context.view.removeListener("remove", this.onChange);
this.context.view.removeListener("recalculate", this.onChange);
}
componentDidUpdate() {
this.onViewportUpdate();
}
onViewportUpdate() {
const viewport = ReactDOM.findDOMNode(this);
const viewportTop = viewport.scrollTop;
const vScroll = calcVScroll({
viewportTop,
viewportHeight: viewport.offsetHeight,
itemCount: this.state.flows.length,
rowHeight: this.props.rowHeight,
});
if (!shallowEqual(this.state.vScroll, vScroll) ||
this.state.viewportTop !== viewportTop) {
this.setState({ vScroll, viewportTop });
}
}
onChange() {
this.setState({ flows: this.context.view.list });
}
scrollIntoView(flow) {
const viewport = ReactDOM.findDOMNode(this);
const index = this.context.view.indexOf(flow);
const rowHeight = this.props.rowHeight;
const head = ReactDOM.findDOMNode(this.refs.head);
const headHeight = head ? head.offsetHeight : 0;
const rowTop = (index * rowHeight) + headHeight;
const rowBottom = rowTop + rowHeight;
const viewportTop = viewport.scrollTop;
const viewportHeight = viewport.offsetHeight;
// Account for pinned thead
if (rowTop - headHeight < viewportTop) {
viewport.scrollTop = rowTop - headHeight;
} else if (rowBottom > viewportTop + viewportHeight) {
viewport.scrollTop = rowBottom - viewportHeight;
}
}
render() {
const vScroll = this.state.vScroll;
const highlight = this.context.view._highlight;
const flows = this.state.flows.slice(vScroll.start, vScroll.end);
const transform = `translate(0,${this.state.viewportTop}px)`;
return (
);
}
}
export default AutoScroll(FlowTable);