UNPKG

singularityui-tailer

Version:
379 lines (314 loc) 13.3 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _reactRedux = require('react-redux'); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _immutable = require('immutable'); var _immutable2 = _interopRequireDefault(_immutable); var _connectToTailer = require('./connectToTailer'); var _connectToTailer2 = _interopRequireDefault(_connectToTailer); var _selectors = require('../selectors'); var Selectors = _interopRequireWildcard(_selectors); var _LogLines = require('./LogLines'); var _LogLines2 = _interopRequireDefault(_LogLines); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var SCROLL_LOAD_THRESHOLD = 300; var Log = function (_Component) { _inherits(Log, _Component); function Log() { _classCallCheck(this, Log); var _this = _possibleConstructorReturn(this, (Log.__proto__ || Object.getPrototypeOf(Log)).call(this)); _this.isLineLoaded = _this.isLineLoaded.bind(_this); _this.loadLine = _this.loadLine.bind(_this); _this.tailLog = _this.tailLog.bind(_this); _this.pollScroll = _this.pollScroll.bind(_this); _this.handleTail = _this.handleTail.bind(_this); _this.getTailDelayMs = _this.getTailDelayMs.bind(_this); _this.scheduleNextHandleTail = _this.scheduleNextHandleTail.bind(_this); _this.scrollTop = undefined; _this.scrollHeight = undefined; _this.invalidate = false; _this.fakeLineCount = 0; _this.scrollDelta = 0; _this.tailAttempt = 0; return _this; } _createClass(Log, [{ key: 'componentWillMount', value: function componentWillMount() { if (this.props.goToOffset === -1 && !this.props.tailing) { this.props.startTailing(); } } }, { key: 'componentDidMount', value: function componentDidMount() { if (!this.props.isLoaded) { this.props.initializeFile(this.props.goToOffset); } else { this.tailLog(); } this.rafRequestId = window.requestAnimationFrame(this.pollScroll); } }, { key: 'componentWillUpdate', value: function componentWillUpdate(nextProps, nextState) { if (nextProps.lines !== this.props.lines) { this.invalidate = true; if (this.props.tailing) { this.scrollDelta = -1; } } if (nextProps.lines.size > 1 && this.props.lines.size > 1) { var oldLines = this.props.lines; var newLines = nextProps.lines; var addedToBeginning = newLines.findIndex(function (l) { return l.start >= oldLines.get(0).end; }) - 1; var removedFromBeginning = oldLines.findIndex(function (l) { return l.end >= newLines.get(0).end; }); if (removedFromBeginning) { this.fakeLineCount += removedFromBeginning - 1; } if (addedToBeginning) { if (this.fakeLineCount - addedToBeginning >= 0) { this.fakeLineCount -= addedToBeginning; } else { this.scrollDelta += _LogLines.LOG_LINE_HEIGHT * (addedToBeginning - this.fakeLineCount); this.fakeLineCount = 0; } } } if (nextProps.tailing && this.tailTimeoutId == null) { this.handleTail(); } else if (!nextProps.tailing && this.tailTimeoutId != null) { clearTimeout(this.tailTimeoutId); this.tailTimeoutId = null; } } }, { key: 'getTailDelayMs', value: function getTailDelayMs() { return Math.min(this.props.maxTailDelayMs, Math.max(this.props.minTailDelayMs, this.props.calculateTailDelayMs(this.tailAttempt))); } }, { key: 'scheduleNextHandleTail', value: function scheduleNextHandleTail() { if (this.props.tailing) { this.tailTimeoutId = setTimeout(this.handleTail, this.getTailDelayMs()); } } }, { key: 'handleTail', value: function handleTail() { var _this2 = this; if (this.props.lines.size > 1) { this.loadLine(this.props.lines.size - 1, false).then(function (data) { if (data && data.hasOwnProperty('chunk')) { if (data.chunk.start === data.chunk.end) { _this2.tailAttempt++; } else { _this2.tailAttempt = 0; } } _this2.scheduleNextHandleTail(); }); } else { this.scheduleNextHandleTail(); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps) { var idMatches = this.props.tailerId === prevProps.tailerId; var offsetMatches = this.props.goToOffset === prevProps.goToOffset; if (!idMatches || !offsetMatches) { this.props.initializeFile(this.props.goToOffset); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { window.cancelAnimationFrame(this.rafRequestId); clearInterval(this.tailTimeoutId); } }, { key: 'isLineLoaded', value: function isLineLoaded(index) { return index < this.props.lines.size && !this.props.lines.get(index).isMissingMarker && !this.props.requests.has(this.props.lines.get(index).start); } // detect when dom has changed underneath us- either scrollTop or scrollHeight (layout reflow) // may have changed. }, { key: 'pollScroll', value: function pollScroll() { var _this3 = this; var domNode = _reactDom2.default.findDOMNode(this); // let's update the scroll now, in a raf. if (this.scrollDelta > 0) { domNode.scrollTop += this.scrollDelta; this.scrollDelta = 0; } else if (this.scrollDelta === -1) { domNode.scrollTop = domNode.scrollHeight; this.scrollDelta = 0; } var scrollTop = domNode.scrollTop, scrollHeight = domNode.scrollHeight, clientHeight = domNode.clientHeight; if (scrollTop !== this.scrollTop || this.invalidate) { this.invalidate = false; var scrollLoadThreshold = _LogLines.LOG_LINE_HEIGHT * SCROLL_LOAD_THRESHOLD; var nearTop = scrollTop - this.fakeLineCount * _LogLines.LOG_LINE_HEIGHT <= scrollLoadThreshold; var nearBottom = scrollTop >= scrollHeight - clientHeight - scrollLoadThreshold; var atBottom = scrollTop >= scrollHeight - clientHeight - 1; var lines = this.props.lines; if (nearTop && nearBottom && lines.size === 1) { // wait until the first chunk is loaded. } else { // we are at the top/bottom, load some stuff. if (nearTop && !this.isLineLoaded(0)) { // don't dispatch in the raf, do it later setTimeout(function () { return _this3.loadLine(0, true); }, 0); } if (nearBottom && lines.size) { // if we haven't reached the end of the file yet if (lines.last().isMissingMarker) { // don't dispatch in the raf, do it later setTimeout(function () { return _this3.loadLine(lines.size - 1, false); }, 0); } else if (atBottom) { // we're tailing here. if (!this.props.tailing) { this.props.startTailing(); } } } } if (!atBottom && this.props.tailing) { this.props.stopTailing(); } // update the scroll position. this.scrollTop = domNode.scrollTop; this.scrollHeight = domNode.scrollHeight; } // do another raf. this.rafRequestId = window.requestAnimationFrame(this.pollScroll); } }, { key: 'loadLine', value: function loadLine(index, loadUp) { return this.props.loadLine(index, loadUp, this.props.lines, this.props.chunks); } }, { key: 'tailLog', value: function tailLog() { return this.props.tailLog(this.props.lines); } }, { key: 'render', value: function render() { var props = this.props; var hrefFunc = props.hrefFunc ? function (offset) { return props.hrefFunc(props.tailerId, offset); } : undefined; var logPaneClasses = (0, _classnames2.default)({ 'log-pane': true, tailing: this.props.tailing }); return _react2.default.createElement( 'section', { className: logPaneClasses }, _react2.default.createElement( 'div', { className: 'log-line-wrapper' }, _react2.default.createElement(_LogLines2.default, { isLoaded: props.isLoaded, lines: props.lines, fakeLineCount: this.fakeLineCount, isLineLoaded: this.isLineLoaded, hrefFunc: hrefFunc, lineLinkRenderer: props.lineLinkRenderer, highlightedOffset: props.goToOffset }) ) ); } }]); return Log; }(_react.Component); Log.propTypes = { tailerId: _react.PropTypes.string.isRequired, goToOffset: _react.PropTypes.number, hrefFunc: _react.PropTypes.func, minTailDelayMs: _react.PropTypes.number.isRequired, maxTailDelayMs: _react.PropTypes.number.isRequired, calculateTailDelayMs: _react.PropTypes.func.isRequired, // from connectToTailer HOC getTailerState: _react.PropTypes.func.isRequired, // from tailer implementation // actions initializeFile: _react.PropTypes.func.isRequired, loadLine: _react.PropTypes.func.isRequired, tailLog: _react.PropTypes.func.isRequired, // from connect isLoaded: _react.PropTypes.bool.isRequired, fileSize: _react.PropTypes.number, lines: _react.PropTypes.instanceOf(_immutable2.default.List), chunks: _react.PropTypes.instanceOf(_immutable2.default.List), requests: _react.PropTypes.instanceOf(_immutable2.default.Map), config: _react.PropTypes.object.isRequired, lineLinkRenderer: _react.PropTypes.func, startTailing: _react.PropTypes.func.isRequired, stopTailing: _react.PropTypes.func.isRequired, tailing: _react.PropTypes.bool }; Log.defaultProps = { minTailDelayMs: 100, maxTailDelayMs: 5000, calculateTailDelayMs: function calculateTailDelayMs(attempt) { return 100 * attempt; } }; var makeMapStateToProps = function makeMapStateToProps() { var getEnhancedLines = Selectors.makeGetEnhancedLines(); var mapStateToProps = function mapStateToProps(state, ownProps) { return { isLoaded: Selectors.getIsLoaded(state, ownProps), fileSize: Selectors.getFileSize(state, ownProps), lines: getEnhancedLines(state, ownProps), chunks: Selectors.getChunks(state, ownProps), requests: Selectors.getRequests(state, ownProps), config: Selectors.getConfig(state, ownProps), tailing: Selectors.isTailing(state, ownProps) }; }; return mapStateToProps; }; var _default = (0, _connectToTailer2.default)((0, _reactRedux.connect)(makeMapStateToProps)(Log)); exports.default = _default; ; var _temp = function () { if (typeof __REACT_HOT_LOADER__ === 'undefined') { return; } __REACT_HOT_LOADER__.register(SCROLL_LOAD_THRESHOLD, 'SCROLL_LOAD_THRESHOLD', 'src/components/Log.js'); __REACT_HOT_LOADER__.register(Log, 'Log', 'src/components/Log.js'); __REACT_HOT_LOADER__.register(makeMapStateToProps, 'makeMapStateToProps', 'src/components/Log.js'); __REACT_HOT_LOADER__.register(_default, 'default', 'src/components/Log.js'); }(); ;