horizon-devtools
Version:
Devtools for horizon
314 lines (272 loc) • 10.9 kB
JavaScript
;
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; }; }();
exports.createDevTools = createDevTools;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactJsonTree = require('react-json-tree');
var _reactJsonTree2 = _interopRequireDefault(_reactJsonTree);
var _reactDock = require('react-dock');
var _reactDock2 = _interopRequireDefault(_reactDock);
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; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
// This should be replaced with Horizon 2's `query.toString()` method
var ast2string = function ast2string(ast, live) {
// All queries except `find` are an array, so we normalize `find` here to be an array
if (ast.find) ast.find = [ast.find];
return ['find', 'find_all', 'above', 'below', 'order', 'limit'].reduce(function (res, key) {
return res + (!ast[key] ? '' : '.' + key + '(' + JSON.stringify(ast[key][0]).replace(/[\[\]\"\{\}]/g, '') + ')');
}, (live === 'watch' ? '🔄 ' : '') + ast.collection);
};
var positions = ['left', 'top', 'right', 'bottom'];
var nextPosition = function nextPosition(c) {
return positions[(positions.indexOf(c) + 1) % 4];
};
var theme = {
base00: '#1B2B34',
base01: '#EC5F67',
base03: '#99C794',
base06: '#FAC863',
base05: '#6699CC',
base04: '#C594C5',
base02: '#5FB3B3',
base07: '#A7ADBA',
base08: '#4F5B66',
base09: '#EC5F67',
base0A: '#99C794',
base0B: '#FAC863',
base0D: '#6699CC',
base0C: '#C594C5',
base0E: '#5FB3B3',
base0F: '#D8DEE9'
};
function instrument(horizon) {
var observ = {
queries: {},
update: function update() {
return null;
}
};
Object.getPrototypeOf(Object.getPrototypeOf(horizon('users'))).fetch = new Proxy(Object.getPrototypeOf(Object.getPrototypeOf(horizon('users'))).fetch, {
apply: function apply(_fetch, thisArg) {
return _fetch.bind(thisArg)().map(function (c) {
observ.queries[ast2string(thisArg._query, 'fetch')] = c;
observ.update();
return c;
});
}
});
Object.getPrototypeOf(Object.getPrototypeOf(horizon('users'))).watch = new Proxy(Object.getPrototypeOf(Object.getPrototypeOf(horizon('users'))).watch, {
apply: function apply(_watch, thisArg, args) {
return _watch.bind(thisArg).apply(undefined, _toConsumableArray(args)).map(function (c) {
observ.queries[ast2string(thisArg._query, 'watch')] = c;
observ.update();
return c;
});
}
});
return observ;
}
var Button = function Button(_ref) {
var onClick = _ref.onClick;
var children = _ref.children;
return _react2.default.createElement(
'span',
{ onClick: onClick, style: {
flexGrow: '1',
cursor: 'pointer',
textAlign: 'center',
color: theme.base07,
backgroundColor: theme.base08,
borderRadius: '3px',
margin: '5px',
padding: '5px 0',
textDecoration: 'underline'
} },
children
);
};
var ButtonTabs = function ButtonTabs(_ref2) {
var _onClick = _ref2.onClick;
return _react2.default.createElement(
'div',
{ style: { display: 'flex' } },
_react2.default.createElement(
Button,
{ onClick: function onClick() {
return _onClick('query');
} },
'Query'
),
_react2.default.createElement(
Button,
{ onClick: function onClick() {
return _onClick('user');
} },
'User'
)
);
};
var Logo = function Logo() {
return _react2.default.createElement(
'span',
null,
_react2.default.createElement('img', { src: 'http://horizon.io/images/horizon-logo.png', style: { maxWidth: '200px', width: '50%' } }),
_react2.default.createElement(
'span',
{ style: { color: '#5e5e5e' } },
'[DEV TOOLS]'
)
);
};
var QueryView = function QueryView(_ref3) {
var queries = _ref3.queries;
return _react2.default.createElement(_reactJsonTree2.default, {
data: queries,
theme: theme,
invertTheme: false,
hideRoot: true
});
};
var UserView = function UserView(_ref4) {
var user = _ref4.user;
return user === null ? _react2.default.createElement(
'div',
{ style: { color: theme.base01, margin: '.5em' } },
'No user exists'
) : _react2.default.createElement(_reactJsonTree2.default, {
data: user,
theme: theme,
invertTheme: false,
hideRoot: true
});
};
function createDevTools(horizon) {
var devtools = instrument(horizon);
if (typeof window !== 'undefined') window.devtools = devtools;
return function (_Component) {
_inherits(HzDevTools, _Component);
function HzDevTools(props) {
_classCallCheck(this, HzDevTools);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(HzDevTools).call(this, props));
_this.handleKeyDown = _this.handleKeyDown.bind(_this);
_this.handleQueryTextUpdate = _this.handleQueryTextUpdate.bind(_this);
_this.shouldRunQuery = _this.shouldRunQuery.bind(_this);
_this.state = {
visible: props.defaultVisible || true,
position: props.defaultPosition || 'right',
queries: devtools.queries,
user: {},
queryText: '',
queryTextError: false,
currentTab: 'query'
};
return _this;
}
_createClass(HzDevTools, [{
key: 'componentDidMount',
value: function componentDidMount() {
var _this2 = this;
if (typeof window !== 'undefined') window.addEventListener('keydown', this.handleKeyDown);
horizon.currentUser().watch().subscribe(function (user) {
_this2.setState({ user: user });
}, function () {
_this2.setState({ user: null });
});
devtools.update = function () {
_this2.setState({ queries: devtools.queries });
};
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (typeof window !== 'undefined') window.removeEventListener('keydown', this.handleKeyDown);
devtools.update = function () {
return null;
};
}
}, {
key: 'handleKeyDown',
value: function handleKeyDown(e) {
var char = String.fromCharCode(e.keyCode || e.which);
if (char.toUpperCase() === 'Q' && e.ctrlKey) this.setState({ visible: !this.state.visible });
if (char.toUpperCase() === 'W' && e.ctrlKey) this.setState({ position: nextPosition(this.state.position) });
}
}, {
key: 'handleQueryTextUpdate',
value: function handleQueryTextUpdate(e) {
this.setState({ queryText: e.target.value, queryTextError: false });
}
}, {
key: 'shouldRunQuery',
value: function shouldRunQuery(e) {
if (e.keyCode === 13 && e.ctrlKey) {
this.setState({ queryText: '' });
this.runQuery(this.state.queryText);
return false;
}
}
}, {
key: 'runQuery',
value: function runQuery(query) {
try {
var q = eval(query);
if (q.fetch) {
q = q.fetch();
}
if (q.subscribe) {
q = q.subscribe();
}
this.setState({ queries: devtools.queries });
} catch (e) {
this.setState({ queryTextError: true, queryText: e });
}
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
return _react2.default.createElement(
_reactDock2.default,
{ position: this.state.position, isVisible: this.state.visible, dimMode: 'none' },
_react2.default.createElement(
'pre',
{ style: { padding: '10px', width: 'calc(100% - 20px)', height: '90%', margin: 0, backgroundColor: theme.base00 } },
_react2.default.createElement(Logo, null),
_react2.default.createElement('hr', { style: { borderStyle: 'solid', color: '#5e5e5e' } }),
_react2.default.createElement(ButtonTabs, { onClick: function onClick(currentTab) {
return _this3.setState({ currentTab: currentTab });
} }),
_react2.default.createElement(
'div',
{ style: { overflow: 'auto', height: '100%' } },
this.state.currentTab === 'query' ? _react2.default.createElement(QueryView, { queries: this.state.queries }) : this.state.currentTab === 'user' ? _react2.default.createElement(UserView, { user: this.state.user }) : null
)
),
_react2.default.createElement('textarea', {
onChange: this.handleQueryTextUpdate,
value: this.state.queryText,
onKeyUp: this.shouldRunQuery,
placeholder: 'Write a query using `horizon`. Run with ^ + Enter.',
style: { color: this.state.queryTextError ? 'red' : undefined,
padding: '5px',
position: 'absolute',
bottom: '0',
width: '97.2%',
resize: 'none',
height: '10%',
fontSize: '12pt',
fontFamily: 'monospace'
}
})
);
}
}]);
return HzDevTools;
}(_react.Component);
}