@bigfishtv/cockpit
Version:
488 lines (439 loc) • 17.5 kB
JavaScript
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _class, _class2, _temp2, _class3, _temp3;
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; }
import React, { Component } from 'react';
import { Fieldset } from '@bigfishtv/react-forms';
import deepEqual from 'deep-equal';
import classnames from 'classnames';
import _get from 'lodash/get';
import _truncate from 'lodash/truncate';
import * as xhrUtils from '../../api/xhrUtils';
import { showDeletePrompt } from '../../utils/promptUtils';
import { titleCase } from '../../utils/stringUtils';
import { modalHandler } from '../modal/ModalHost';
import { flatten, getParentByChildId, sortByKey, pruneTree, appendChildToParent, replaceChild } from '../../utils/treeUtils';
import modalFormValueContext from '../../decorators/modalFormValueContext';
import { AutoTableIndexContainer, AutoTableIndexBase } from './AutoTableIndex';
import MainContent from '../container/MainContent';
import Bulkhead from '../page/Bulkhead';
import Panel from '../container/panel/Panel';
import Tree from '../tree/Tree';
import Field from '../form/Field';
import Modal from '../modal/Modal';
import TreeSelectModal from '../modal/TreeSelectModal';
import Button from '../button/Button';
import DropdownItem from '../button/dropdown/DropdownItem';
import DropdownItemDivider from '../button/dropdown/DropdownItemDivider';
import DropdownButton from '../button/dropdown/DropdownButton';
import Icon from '../Icon';
import TreeModal from '../modal/TreeModal';
var DefaultBulkheadToolbar = function DefaultBulkheadToolbar(_ref) {
var modelLabel = _ref.modelLabel,
model = _ref.model,
addUrl = _ref.addUrl;
return React.createElement(Button, {
text: 'New ' + titleCase(modelLabel || model),
onClick: function onClick() {
return window.location.href = addUrl;
},
style: 'primary',
size: 'large'
});
};
// used in sidebar
var DefaultTreeCell = function DefaultTreeCell(props) {
var id = props.id,
title = props.title,
locked = props.locked,
isCollapsed = props.isCollapsed,
showIndicator = props.showIndicator,
onIndicatorClick = props.onIndicatorClick,
onIndicatorDoubleClick = props.onIndicatorDoubleClick,
isOver = props.isOver,
position = props.position,
onClick = props.onClick,
onDoubleClick = props.onDoubleClick,
selected = props.selected,
data = props.data;
var items = id === null ? data : data.filter(function (_ref2) {
var folder_id = _ref2.folder_id;
return id === '_unsorted' ? folder_id === null : folder_id === id;
});
return React.createElement(
'div',
{ className: classnames('tree-item', isOver && 'drag-' + position) },
React.createElement(
'div',
{
className: classnames('tree-cell tree-cell-small', { selected: selected }),
onClick: onClick,
onDoubleClick: onDoubleClick },
showIndicator ? React.createElement(
'div',
{
className: classnames('tree-cell-icon', isCollapsed && 'collapsed'),
onClick: onIndicatorClick,
onDoubleClick: onIndicatorDoubleClick },
React.createElement(Icon, { name: 'chevron-' + (isCollapsed ? 'right' : 'down'), size: 18 })
) : React.createElement('div', { className: 'tree-cell-icon' }),
locked && React.createElement(
'div',
{ className: 'tree-cell-icon' },
React.createElement(Icon, { name: 'lock', size: 12 })
),
React.createElement(
'div',
{ className: 'tree-cell-title' },
_truncate(title, { length: 45 }),
' (',
items.length,
')'
)
)
);
};
// used in sidebar
var DefaultTray = function DefaultTray(props) {
var onFolderAdd = props.onFolderAdd,
onFolderDelete = props.onFolderDelete,
onEdit = props.onEdit,
currentFolderId = props.currentFolderId;
return React.createElement(
'div',
{ className: 'finder-menu-footer' },
React.createElement(Button, { size: 'small', text: 'Add Folder', onClick: onFolderAdd }),
React.createElement(Button, { size: 'small', text: 'Delete', onClick: onFolderDelete }),
React.createElement(Button, { size: 'small', text: 'Edit', onClick: onEdit, disabled: currentFolderId === null })
);
};
export var DefaultFolderSidebarToolbar = function DefaultFolderSidebarToolbar(props) {
return React.createElement(
DropdownButton,
{ style: 'icon', caret: false, pullRight: true, text: React.createElement(Icon, { name: 'hamburger' }) },
React.createElement(DropdownItem, { text: 'New Folder', icon: 'folder-new', onClick: props.handleFolderAdd }),
React.createElement(DropdownItem, { text: 'Edit', icon: 'edit', onClick: props.handleFolderEdit, disabled: !props.currentFolderId }),
React.createElement(DropdownItemDivider, null),
React.createElement(DropdownItem, { text: 'Remove', icon: 'remove', onClick: props.handleFolderDelete, disabled: !props.currentFolderId })
);
};
export var DefaultFolderEditModal = modalFormValueContext(_class = (_temp2 = _class2 = function (_Component) {
_inherits(DefaultFolderEditModal, _Component);
function DefaultFolderEditModal() {
var _temp, _this, _ret;
_classCallCheck(this, DefaultFolderEditModal);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.handleSave = function () {
_this.props.onSave(_this.props.formValue, _this.props.isNew);
}, _this.handleClose = function () {
var didSave = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
_this.props.onClose(_this.props.formValue, didSave, _this.props.isNew);
}, _temp), _possibleConstructorReturn(_this, _ret);
}
DefaultFolderEditModal.prototype.render = function render() {
var foldersUrl = this.props.foldersUrl;
var title = this.props.formValue.value.title;
return React.createElement(
Modal,
_extends({}, this.props, {
title: title || 'New Folder',
size: 'small',
onClose: this.handleClose,
onSave: this.handleSave }),
React.createElement(
Fieldset,
{ formValue: this.props.formValue },
React.createElement(Field, { select: 'title', label: 'Title', placeholder: 'Title', autoFocus: true }),
React.createElement(
Field,
{ select: 'parent', label: 'Parent Folder' },
React.createElement(TreeSelectModal, {
buttonText: 'Select Folder',
modalProps: {
url: foldersUrl,
title: 'Select Parent Folder',
primaryActionText: 'Select Parent Folder',
filterData: function filterData(data, user) {
return sortByKey(data, 'title');
}
}
})
)
)
);
};
return DefaultFolderEditModal;
}(Component), _class2.defaultProps = {
isNew: false
}, _temp2)) || _class;
var AutoFolderTableIndex = (_temp3 = _class3 = function (_Component2) {
_inherits(AutoFolderTableIndex, _Component2);
function AutoFolderTableIndex(props) {
_classCallCheck(this, AutoFolderTableIndex);
var _this2 = _possibleConstructorReturn(this, _Component2.call(this, props));
_this2.handleFolderSelection = function (ids, handleFilterChange) {
var currentFolderId = ids[0];
_this2.setState({ currentFolderId: currentFolderId }, function () {
return handleFilterChange && handleFilterChange('folder_id', currentFolderId == '_unsorted' ? function (val) {
return val === null;
} : currentFolderId);
});
};
_this2.handleFolderCollapse = function (collapsedIds) {
_this2.setState({ collapsedIds: collapsedIds });
};
_this2.handleFolderAdd = function () {
console.log('opening folder add modal');
modalHandler.add({
Component: _this2.props.FolderEditModal,
props: {
isNew: true,
defaultValue: _this2.props.newFolderDefaultValue,
foldersUrl: _this2.props.foldersUrl,
onSave: _this2.handleFolderEditSave.bind(_this2, {}),
onClose: _this2.handleFolderEditClose.bind(_this2, {})
}
});
};
_this2.handleFolderEdit = function () {
var _this2$state = _this2.state,
foldersData = _this2$state.foldersData,
currentFolderId = _this2$state.currentFolderId;
if (!currentFolderId) return;
// because folder data is threaded we gotta flatten it to find current selection and set its parent
var folder = flatten(foldersData).filter(function (item) {
return item.id === currentFolderId;
})[0];
folder.parent = getParentByChildId(currentFolderId, foldersData);
modalHandler.add({
Component: _this2.props.FolderEditModal,
props: {
defaultValue: folder,
foldersUrl: _this2.props.foldersUrl,
onSave: _this2.handleFolderEditSave.bind(_this2, folder),
onClose: _this2.handleFolderEditClose.bind(_this2, folder)
}
});
};
_this2.handleFolderEditSave = function (oldRowValue, newRowValue, isNew) {
newRowValue = newRowValue.value;
if (!deepEqual(oldRowValue, newRowValue)) {
var postUrl = _this2.props.getFolderSubmitUrl({ id: isNew ? false : newRowValue.id });
var hasNewParent = _get(newRowValue, 'parent.id', null) != _get(oldRowValue, 'parent.id');
if (hasNewParent) newRowValue.parent_id = _get(newRowValue, 'parent.id', null);
xhrUtils.post({
url: postUrl,
data: newRowValue,
callback: function callback(folder) {
var foldersData = _this2.state.foldersData;
if (isNew) {
foldersData = appendChildToParent(foldersData, folder.parent_id, folder);
foldersData = sortByKey(foldersData, 'title');
} else {
if (hasNewParent) {
foldersData = pruneTree(foldersData, 'id', folder.id);
foldersData = appendChildToParent(foldersData, folder.parent_id, folder);
foldersData = sortByKey(foldersData, 'title');
} else {
foldersData = replaceChild(_this2.state.foldersData, folder);
}
}
_this2.setState({ foldersData: foldersData });
_this2.handleFolderSelection([folder.id]);
}
});
} else {
console.log('Nothing edited, not saving.');
}
};
_this2.handleFolderEditClose = function (oldRowValue, newFormValue, isNew) {
console.log('MODAL CLOSED, W/E');
};
_this2.handleFolderDelete = function () {
var _this2$state2 = _this2.state,
foldersData = _this2$state2.foldersData,
currentFolderId = _this2$state2.currentFolderId;
showDeletePrompt({
subject: 'email template folder',
queryUrl: _this2.props.folderDeleteUrl,
style: 'error',
selectedIds: [currentFolderId],
data: flatten(foldersData).filter(function (item) {
return item.id === currentFolderId;
}),
callback: function callback(response) {
_this2.setState({
foldersData: pruneTree(foldersData, 'id', [currentFolderId]),
currentFolderId: null
});
}
});
};
_this2.handleMove = function (selectedItems, updateCallback) {
modalHandler.add({
Component: TreeModal,
props: {
title: 'Select Folder',
primaryActionText: 'Confirm',
url: _this2.props.foldersUrl,
onClose: function onClose() {},
onSave: function onSave(folder) {
if (folder) {
var selectedIds = selectedItems.map(function (_ref3) {
var id = _ref3.id;
return id;
});
xhrUtils.post({
url: _this2.props.moveUrl + '?folder_id=' + folder.id,
data: { id: selectedIds },
successMessage: selectedItems.length + ' item' + (selectedItems.length > 1 ? 's' : '') + ' moved to ' + folder.title,
failureMessage: 'There was an error moving items',
callback: function callback() {
var updateDataFunc = function updateDataFunc(data) {
return data.map(function (item) {
return ~selectedIds.indexOf(item.id) ? _extends({}, item, { folder_id: folder.id }) : item;
});
};
updateCallback(updateDataFunc);
}
});
}
}
}
});
};
_this2.state = {
foldersData: props.folders || [],
currentFolderId: null,
collapsedFolderIds: []
};
return _this2;
}
AutoFolderTableIndex.prototype.render = function render() {
var _this3 = this;
var _props = this.props,
SidebarToolbar = _props.SidebarToolbar,
BulkheadToolbar = _props.BulkheadToolbar,
_TreeCell = _props.TreeCell,
sidebarTitle = _props.sidebarTitle;
var _state = this.state,
collapsedFolderIds = _state.collapsedFolderIds,
currentFolderId = _state.currentFolderId,
foldersData = _state.foldersData;
var sidebarProps = {
currentFolderId: currentFolderId,
handleFolderAdd: this.handleFolderAdd,
handleFolderEdit: this.handleFolderEdit,
handleFolderDelete: this.handleFolderDelete
};
var _foldersData = [{ id: null, title: '[All]' }, { id: '_unsorted', title: '[Unsorted]' }].concat(foldersData);
return React.createElement(
AutoTableIndexContainer,
_extends({}, this.props, {
defaultValue: this.props.data,
movable: !!this.props.moveUrl,
onMove: this.handleMove }),
function (props) {
var model = props.model,
panelProps = props.panelProps,
handleFilterChange = props.handleFilterChange,
originalData = props.originalData;
return React.createElement(
MainContent,
null,
React.createElement(Bulkhead, { title: titleCase(model), Toolbar: function Toolbar() {
return React.createElement(BulkheadToolbar, _extends({}, props, panelProps));
} }),
React.createElement(
'div',
{ className: 'finder' },
React.createElement(
'div',
{ className: 'finder-menu' },
React.createElement(
Panel,
{ title: sidebarTitle || 'Folders', PanelToolbar: function PanelToolbar() {
return React.createElement(SidebarToolbar, sidebarProps);
} },
React.createElement(Tree, {
value: _foldersData,
TreeCell: function TreeCell(props) {
return React.createElement(_TreeCell, _extends({}, props, { data: originalData }));
},
dropTargetType: 'TANK_FOLDER',
treeItemTarget: treeItemTarget(_this3),
treeItemSource: treeItemSource(_this3),
onSelectItem: _this3.handleFolderEdit,
selectedIds: [currentFolderId],
collapsedIds: collapsedFolderIds,
onSelectionChange: function onSelectionChange(ids) {
return _this3.handleFolderSelection(ids, handleFilterChange);
},
onCollapseChange: _this3.handleFolderCollapse,
onCombinationChange: function onCombinationChange() {
return console.log('HANDLE COMBINATION CHANGE');
}
})
)
),
React.createElement(
'div',
{ className: 'finder-content', ref: 'finderContent' },
React.createElement(AutoTableIndexBase, props)
)
)
);
}
);
};
return AutoFolderTableIndex;
}(Component), _class3.defaultProps = {
Tray: DefaultTray,
TreeCell: DefaultTreeCell,
BulkheadToolbar: DefaultBulkheadToolbar,
SidebarToolbar: DefaultFolderSidebarToolbar,
FolderEditModal: DefaultFolderEditModal,
foldersUrl: '/tank/folders.json',
folderDeleteUrl: '/tank/folders/delete.json',
getFolderSubmitUrl: function getFolderSubmitUrl(data) {
return '/tank/folders/' + (data.id ? 'edit/' + data.id : 'add') + '.json';
},
componentResolver: function componentResolver() {},
attributeModified: function attributeModified() {},
newFolderDefaultValue: {}
}, _temp3);
// drag source & target configs for allowing projects to be dropped into sector folders
export { AutoFolderTableIndex as default };
var treeItemSource = function treeItemSource(parent) {
return {
beginDrag: function beginDrag(props, monitor, component) {
return { id: props.id };
}
};
};
var treeItemTarget = function treeItemTarget(parent) {
return {
drop: function drop(props, monitor, component) {
if (monitor.isOver({ shallow: true })) {
if (!props.selected) {
var sectorId = monitor.getItem().id;
var parentId = props.id;
parent.onMoveSector(parentId, sectorId);
} else {
console.log('no need to move asset into already opened folder');
}
}
},
hover: function hover(props, monitor, component) {
if (monitor.isOver({ shallow: true })) {
var ownId = props.id;
var draggedId = monitor.getItem().id;
if (draggedId === ownId) return;
component.setState({ position: 'into' });
}
}
};
};