@bigfishtv/cockpit
Version:
422 lines (355 loc) • 14.2 kB
JavaScript
'use strict';
exports.__esModule = true;
exports.default = undefined;
var _dec, _class, _class2, _temp;
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _immutable = require('immutable');
var _immutable2 = _interopRequireDefault(_immutable);
var _reactRedux = require('react-redux');
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _isEqual = require('lodash/isEqual');
var _isEqual2 = _interopRequireDefault(_isEqual);
var _MainContent = require('../container/MainContent');
var _MainContent2 = _interopRequireDefault(_MainContent);
var _Icon = require('../Icon');
var _Icon2 = _interopRequireDefault(_Icon);
var _Tree = require('../tree/Tree');
var _Tree2 = _interopRequireDefault(_Tree);
var _Bulkhead = require('../page/Bulkhead');
var _Bulkhead2 = _interopRequireDefault(_Bulkhead);
var _Button = require('../button/Button');
var _Button2 = _interopRequireDefault(_Button);
var _xhrUtils = require('../../api/xhrUtils');
var _promptUtils = require('../../utils/promptUtils');
var _roleUtils = require('../../utils/roleUtils');
var _treeUtils = require('../../utils/treeUtils');
var _notifications = require('../../actions/notifications');
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 HeaderToolbar = function HeaderToolbar(props) {
var _props$headerToolbarP = props.headerToolbarProps,
allCollapsed = _props$headerToolbarP.allCollapsed,
collapsedIds = _props$headerToolbarP.collapsedIds,
selectedIds = _props$headerToolbarP.selectedIds,
onCollapseAll = _props$headerToolbarP.onCollapseAll,
onExpandAll = _props$headerToolbarP.onExpandAll,
onDelete = _props$headerToolbarP.onDelete;
return _react2.default.createElement(
'div',
null,
_react2.default.createElement(_Button2.default, { text: 'Collapse All', onClick: onCollapseAll, disabled: allCollapsed }),
_react2.default.createElement(_Button2.default, { text: 'Expand All', onClick: onExpandAll, disabled: !collapsedIds.length }),
_react2.default.createElement(_Button2.default, { text: 'Delete', style: 'error', onClick: onDelete, disabled: !selectedIds.length })
);
};
var PageTreeCell = function PageTreeCell(props) {
var id = props.id,
title = props.title,
status = props.status,
path = props.path,
userCanAccess = props.userCanAccess,
isCollapsed = props.isCollapsed,
selectedDrag = props.selectedDrag,
showIndicator = props.showIndicator,
onIndicatorClick = props.onIndicatorClick,
onIndicatorDoubleClick = props.onIndicatorDoubleClick,
isOver = props.isOver,
position = props.position,
onClick = props.onClick,
onDoubleClick = props.onDoubleClick,
selected = props.selected;
return _react2.default.createElement(
'div',
{ className: (0, _classnames2.default)('tree-item', isOver && 'drag-' + position) },
_react2.default.createElement(
'div',
{
className: (0, _classnames2.default)('tree-cell', { dragging: selectedDrag, selected: selected, disabled: !userCanAccess }),
onClick: userCanAccess ? onClick : null,
onDoubleClick: userCanAccess ? onDoubleClick : null },
_react2.default.createElement(
'div',
{ className: 'tree-cell-icon' },
showIndicator && _react2.default.createElement(
'div',
{
className: (0, _classnames2.default)('tree-cell-control', isCollapsed && 'collapsed'),
onClick: onIndicatorClick,
onDoubleClick: onIndicatorDoubleClick },
_react2.default.createElement(_Icon2.default, { name: 'chevron-' + (isCollapsed ? 'right' : 'down'), size: '18' })
)
),
_react2.default.createElement(
'div',
{ className: 'tree-cell-status' },
_react2.default.createElement('div', { className: (0, _classnames2.default)('status', status) })
),
!userCanAccess && _react2.default.createElement(
'div',
{ className: 'tree-cell-icon' },
_react2.default.createElement(_Icon2.default, { name: 'lock', size: 12 })
),
userCanAccess ? _react2.default.createElement(
'div',
{ className: 'tree-cell-title' },
_react2.default.createElement(
'a',
{ href: '/admin/pages/edit/' + id, onClick: function onClick(event) {
return event.stopPropagation();
} },
title
)
) : _react2.default.createElement(
'div',
{ className: 'tree-cell-title disabled' },
title
),
_react2.default.createElement(
'div',
{ className: 'tree-cell-text' },
_react2.default.createElement(
'a',
{ href: path, target: '_blank', onClick: function onClick(event) {
return event.stopPropagation();
} },
path
)
)
)
);
};
function filterPages(data, user) {
return data.map(function (page) {
page.userCanAccess = (0, _roleUtils.userCanAccess)([{ model: 'Pages', foreign_key: page.id }], user);
if (page.userCanAccess) {
markRecursive(page.children);
} else {
page.children = filterPages(page.children, user);
}
return page;
});
}
function markRecursive(children) {
children.map(function (page) {
page.userCanAccess = true;
markRecursive(page.children);
});
}
/**
* Pages tree view page template
*/
var Pages = (_dec = (0, _reactRedux.connect)(function (_ref) {
var viewer = _ref.viewer;
return { viewer: viewer };
}), _dec(_class = (_temp = _class2 = function (_Component) {
_inherits(Pages, _Component);
function Pages(props) {
_classCallCheck(this, Pages);
var _this = _possibleConstructorReturn(this, _Component.call(this));
_this.handleChange = function (newTree, delta) {
if (_this.props.moveUrl) {
_this.setState({ data: newTree });
(0, _xhrUtils.post)({
url: _this.props.moveUrl,
data: delta,
quietSuccess: true,
errorMessage: 'Failed to update tree',
callback: function callback(data) {
return _this.setState({ data: _immutable2.default.fromJS(filterPages(data, _this.props.viewer)) });
}
});
} else {
_this.props.dispatch((0, _notifications.notifyFailure)('Failed to update tree'));
console.warn('[Pages] moveUrl not supplied, not saving tree');
}
};
_this.handleDelete = function () {
var _this$state = _this.state,
selectedIds = _this$state.selectedIds,
data = _this$state.data;
var itemsToDelete = (0, _treeUtils.collectValuesImmutable)(data, 'title', function (item) {
return selectedIds.indexOf(item.get('id')) >= 0;
}).map(function (value) {
return { title: value };
});
(0, _promptUtils.showDeletePrompt)({
subject: 'page',
style: 'error',
selectedIds: selectedIds,
data: itemsToDelete,
callback: function callback() {
_this.setState({
data: (0, _treeUtils.pruneTreeImmutable)(data, 'id', selectedIds, 'children'),
selectedIds: []
});
}
});
};
_this.handleSelectionChange = function (selectedIds) {
_this.setState({ selectedIds: selectedIds });
};
_this.handleCollapseChange = function (collapsedIds) {
var collapsableIds = (0, _treeUtils.collectValuesImmutable)(_this.state.data, 'id', function (item) {
return item.get('children') && item.get('children').size > 0;
});
var allCollapsed = (0, _isEqual2.default)(collapsableIds.sort(), collapsedIds.sort());
_this.setState({ collapsedIds: collapsedIds, allCollapsed: allCollapsed });
};
_this.handleCombinationChange = function (mixed) {
var newState = {};
Object.keys(mixed).map(function (key) {
if (key in _this.state) newState[key] = mixed[key];
});
_this.setState(newState);
};
_this.handleCollapseAll = function () {
var collapsedIds = (0, _treeUtils.collectValuesImmutable)(_this.state.data, 'id', function (item) {
return item.get('children') && item.get('children').size > 0;
});
_this.setState({ collapsedIds: collapsedIds, allCollapsed: true });
};
_this.handleExpandAll = function () {
_this.setState({ collapsedIds: [], allCollapsed: false });
};
_this.handleSelectedItem = function (item) {
window.location = '/admin/pages/edit/' + item.get('id');
};
var pages = filterPages(props.treeData, props.viewer);
_this.state = {
data: _immutable2.default.fromJS(pages),
selectedIds: [],
collapsedIds: localStorage.pagesCollapsedIds ? JSON.parse(localStorage.pagesCollapsedIds) : [], //getInitialCollapsed(pages),
allCollapsed: false
};
return _this;
}
Pages.prototype.componentDidUpdate = function componentDidUpdate() {
localStorage.pagesCollapsedIds = JSON.stringify(this.state.collapsedIds);
};
Pages.prototype.render = function render() {
var _state = this.state,
data = _state.data,
selectedIds = _state.selectedIds,
collapsedIds = _state.collapsedIds,
allCollapsed = _state.allCollapsed;
var headerToolbarProps = {
selectedIds: selectedIds,
allCollapsed: allCollapsed,
collapsedIds: collapsedIds,
onCollapseAll: this.handleCollapseAll,
onExpandAll: this.handleExpandAll,
onDelete: this.handleDelete
};
return _react2.default.createElement(
_MainContent2.default,
null,
_react2.default.createElement(_Bulkhead2.default, { title: 'Pages', Toolbar: HeaderToolbar, headerToolbarProps: headerToolbarProps }),
_react2.default.createElement(
'div',
{ className: 'panel margin-medium' },
_react2.default.createElement(_Tree2.default, {
value: data,
immutable: true,
TreeCell: PageTreeCell,
treeItemSource: treeItemSource,
treeItemTarget: treeItemTarget,
selectedIds: selectedIds,
collapsedIds: collapsedIds,
onChange: this.handleChange,
onSelectItem: this.handleSelectedItem,
onSelectionChange: this.handleSelectionChange,
onCollapseChange: this.handleCollapseChange,
onCombinationChange: this.handleCombinationChange
})
)
);
};
return Pages;
}(_react.Component), _class2.propTypes = {
/** update url to hit on page reorder */
moveUrl: _propTypes2.default.string,
/** threaded array of objects - tree data */
treeData: _propTypes2.default.array
}, _class2.defaultProps = {
treeData: []
}, _temp)) || _class);
// this is referenced in TreeItem -- it needs to be provided as a prop for react-dnd decorator in order for it to be optionally replaced by tree props
exports.default = Pages;
var treeItemSource = {
canDrag: function canDrag(props) {
return props.userCanAccess;
},
beginDrag: function beginDrag(props) {
props.beginDrag(props.id);
return { id: props.id, index: props.index };
},
endDrag: function endDrag(props, monitor) {
if (!monitor.didDrop()) {
props.endDrag();
}
}
};
// this is referenced in TreeItem -- it needs to be provided as a prop for react-dnd decorator in order for it to be optionally replaced by tree props
var expandTimeout = null;
var EDGE_SIZE = 10;
var PARENT_BELOW_EDGE_SIZE = 50;
var treeItemTarget = {
drop: function drop(props, monitor, component) {
if (!component.decoratedComponentInstance.props.userCanAccess) return;
if (!props.reorderable) return;
// goes through all drop targets and resets their forceExpand state so they don't randomly open upon drag if hover expanded
for (var key in monitor.internalMonitor.registry.handlers) {
if (key.charAt(0) == 'T') {
var item = monitor.internalMonitor.registry.handlers[key].component;
if (item.state && item.state.forceExpand) {
item.props.onCollapse();
item.setState({ forceExpand: false });
}
}
}
if (monitor.isOver({ shallow: true })) {
var draggedId = monitor.getItem().id;
var targetId = props.id;
var position = component.state.position;
props.endDrag(draggedId, targetId, position);
}
},
hover: function hover(props, monitor, component) {
if (!component.decoratedComponentInstance.props.userCanAccess) return;
if (!props.reorderable) return;
var isOverCurrent = monitor.isOver({ shallow: true });
if (isOverCurrent) {
var ownId = props.id;
var draggedId = monitor.getItem().id;
if (draggedId === ownId || component.props.selected) return;
var boundingRect = _reactDom2.default.findDOMNode(component).getBoundingClientRect();
var clientOffset = monitor.getClientOffset();
var offsetY = clientOffset.y - boundingRect.top;
var rowHeight = boundingRect.bottom - boundingRect.top;
var bottomEdgeSize = !props.collapsed && props.children && props.children.size > 0 ? PARENT_BELOW_EDGE_SIZE : EDGE_SIZE;
if (clientOffset.y > boundingRect.top && clientOffset.y < boundingRect.bottom) {
if (clientOffset.y > boundingRect.top + EDGE_SIZE && clientOffset.y < boundingRect.top + rowHeight - bottomEdgeSize) {
if (component.props.collapsed && component.state.position != 'into') {
if (expandTimeout !== null) clearTimeout(expandTimeout);
expandTimeout = setTimeout(function () {
component.setState({ forceExpand: true });
}, 1000);
}
component.setState({ position: 'into' });
} else if (offsetY < EDGE_SIZE) {
component.setState({ position: 'above' });
} else {
component.setState({ position: 'below' });
}
}
}
}
};