UNPKG

@metacell/geppetto-meta-ui

Version:

React components from geppetto-meta to create neuroscience applications and visualize data.

585 lines (578 loc) 23.7 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var _excluded = ["events"]; function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } import React from 'react'; import { plugins, ColumnDefinition, RowDefinition } from 'griddle-react'; import Griddle from './utils/Griddle'; import BaseIconComponent from './BaseIconComponent'; import { PropTypes } from 'prop-types'; import PopupColorPicker from './PopupColorPicker'; import './listviewer.less'; import { mapToObject, mapSourceToRow, extractGriddleData, isString } from './utils'; /** * Allows to group multiple components in a single column * @param {*} conf */ export var GroupComponent = function GroupComponent(conf) { return function (_ref) { var value = _ref.value; return conf.map(function (_ref2) { var id = _ref2.id, customComponent = _ref2.customComponent, configuration = _ref2.configuration, source = _ref2.source, visible = _ref2.visible; if (value.get) { // is a map coming from griddle. instanceof Map does not work here value = mapToObject(value); } if (visible !== undefined) { var isVisible = visible instanceof Function ? visible(value) : visible; if (!isVisible) { return ''; } } if (!customComponent) { customComponent = WrapperComponent; } if (configuration) { customComponent = customComponent(configuration); } var componentValue = source ? mapSourceToRow(source, value) : value; return /*#__PURE__*/React.createElement(customComponent, { key: id, value: componentValue }); }); }; }; /** * Shows a fontAwesome icon. Allows an action to be specified * @param { icon, action, color, tooltip } */ export var IconComponent = function IconComponent(_ref3) { var icon = _ref3.icon, _action = _ref3.action, color = _ref3.color, tooltip = _ref3.tooltip; return function (_ref4) { var value = _ref4.value; return /*#__PURE__*/React.createElement(BaseIconComponent, { color: color, title: tooltip, action: function action() { return _action(value); }, icon: icon }); }; }; export var MultiStatusComponent = function MultiStatusComponent(availableStatuses) { return /*#__PURE__*/function (_React$Component) { function Comp(props) { var _this; _classCallCheck(this, Comp); _this = _callSuper(this, Comp, [props]); // State contains the index of a circular list _this.state = { statusIdx: 0 }; _this.value = props.value; return _this; } _inherits(Comp, _React$Component); return _createClass(Comp, [{ key: "render", value: function render() { var _this2 = this; var statusIdx = this.state.statusIdx; var _availableStatuses$th = availableStatuses[this.state.statusIdx], tooltip = _availableStatuses$th.tooltip, icon = _availableStatuses$th.icon, _action2 = _availableStatuses$th.action, color = _availableStatuses$th.color; return /*#__PURE__*/React.createElement(BaseIconComponent, { color: color, title: tooltip, action: function action() { _this2.setState({ statusIdx: statusIdx + 1 < availableStatuses.length ? statusIdx + 1 : 0 }); _action2(_this2.value); }, icon: icon }); } }]); }(React.Component); }; /** * Wraps a component implementing a click action on it. * @param {*} action * @param {*} customComponent */ export var WrapperComponent = function WrapperComponent(action, customComponent) { return function (_ref5) { var value = _ref5.value; return /*#__PURE__*/React.createElement("span", { onClick: function onClick() { return action(value); } }, customComponent ? /*#__PURE__*/React.createElement(customComponent, { value: value }) : value); }; }; /** * Shows an image from the data field. If the data field has no value, a default image is shown instead. * * @param { title, alt, defaultImg, action } configuration */ export var ImageComponent = function ImageComponent(_ref6) { var title = _ref6.title, alt = _ref6.alt, defaultImg = _ref6.defaultImg, action = _ref6.action; return function (_ref7) { var value = _ref7.value; return /*#__PURE__*/React.createElement("img", { src: value ? value : defaultImg, title: title, alt: alt ? alt : title, onClick: function onClick() { return action(value); }, className: "thumbnail-img" }); }; }; /** * Allows to specify an input field. * * The value can be processed on the onBlur action * * @param { placeholder, onBlur, onKeyPress, readOnly, classString, unit, defaultValue } configuration */ export var ParameterInputComponent = function ParameterInputComponent(_ref8) { var placeholder = _ref8.placeholder, _onBlur = _ref8.onBlur, _onKeyPress = _ref8.onKeyPress, readOnly = _ref8.readOnly, classString = _ref8.classString, unit = _ref8.unit, defaultValue = _ref8.defaultValue; return function (_ref9) { var value = _ref9.value; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("input", { placeholder: placeholder, defaultValue: defaultValue instanceof Function ? defaultValue(value) : defaultValue, onBlur: function onBlur(evt) { return _onBlur(value, evt.target.value); }, onKeyPress: function onKeyPress(evt) { return _onKeyPress(value, evt.target.value); }, className: classString, title: "", readOnly: readOnly }), /*#__PURE__*/React.createElement("span", { className: "control-panel-parameter-unit" }, unit)); }; }; export var ColorComponent = function ColorComponent(_ref10) { var _action3 = _ref10.action, defaultColor = _ref10.defaultColor, icon = _ref10.icon; return function (_ref11) { var value = _ref11.value; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(PopupColorPicker, { color: isString(defaultColor) ? defaultColor : defaultColor(value), action: function action(hex) { return _action3(_objectSpread(_objectSpread({}, isString(value) ? { path: value } : value), {}, { color: hex })); }, icon: icon })); }; }; /** * Shows the data value as a link */ export var LinkComponent = function LinkComponent(_ref12) { var text = _ref12.text; return function (_ref13) { var value = _ref13.value; return /*#__PURE__*/React.createElement("a", { href: value, target: "_blank", rel: "noopener noreferrer" }, text ? text : value); }; }; export var defaultColumnConfiguration = [{ id: 'path', title: 'Path', source: 'path' }, { id: 'metaType', title: 'Meta Type', source: 'metaType' }, { id: 'type', title: 'Type', source: 'type' }]; var ListViewer = /*#__PURE__*/function (_React$Component2) { function ListViewer(props, context) { var _this3; _classCallCheck(this, ListViewer); _this3 = _callSuper(this, ListViewer, [props, context]); _defineProperty(_this3, "builtInComponents", { GroupComponent: GroupComponent, IconComponent: IconComponent, WrapperComponent: WrapperComponent, LinkComponent: LinkComponent, ImageComponent: ImageComponent }); _this3.preprocessColumnConfiguration = _this3.preprocessColumnConfiguration.bind(_this3); _this3.handlerObject = _this3.props.handler; return _this3; } _inherits(ListViewer, _React$Component2); return _createClass(ListViewer, [{ key: "getColumnConfiguration", value: function getColumnConfiguration() { return this.preprocessColumnConfiguration(this.props.columnConfiguration !== undefined ? this.props.columnConfiguration : defaultColumnConfiguration); } }, { key: "getData", value: function getData() { return extractGriddleData(this.props.filter ? this.props.instances.filter(this.props.filter) : this.props.instances, this.getColumnConfiguration()); } /** * Parses the configuration for further processing, inserting defaults and adjusting types * @param {id, action, customComponent, configuration} colConf */ }, { key: "preprocessColumnConfiguration", value: function preprocessColumnConfiguration(conf) { if (this.incrementalId === undefined) { this.incrementalId = 0; } if (conf instanceof Array) { return conf.map(this.preprocessColumnConfiguration); } if (conf.configuration && !conf.customComponent) { console.warn('Configuration was specified for column', conf.id, 'but no customComponent was specified.'); } return _objectSpread(_objectSpread({}, conf), {}, { id: conf.id ? conf.id : this.incrementalId++, action: conf.action === undefined ? undefined : this.preprocessAction(conf.action), onBlur: conf.onBlur === undefined ? undefined : this.preprocessAction(conf.onBlur), onChange: conf.onChange === undefined ? undefined : this.preprocessAction(conf.onChange), onKeyPress: conf.onKeyPress === undefined ? undefined : this.preprocessAction(conf.onKeyPress), customComponent: conf.customComponent === undefined ? undefined : this.preprocessComponent(conf.customComponent), configuration: conf.configuration === undefined ? undefined : this.preprocessColumnConfiguration(conf.configuration) }); } }, { key: "preprocessAction", value: function preprocessAction(action) { var _this4 = this; if (isString(action)) { if (!this.handlerObject[action]) { throw new Error('Bad ListViewer configuration: the function ' + action + ' is not defined in the specified handler ' + this.handlerObject); } return function (entity) { return _this4.handlerObject[action](entity); }; } else { return action.bind(this.handlerObject); } } }, { key: "preprocessComponent", value: function preprocessComponent(customComponent) { if (isString(customComponent)) { if (this.builtInComponents[customComponent]) { return this.builtInComponents[customComponent]; } else if (window[customComponent]) { return window[customComponent]; } else { throw new Error('ListViewer configuration error: ' + customComponent + ' not defined. Try attach to the global (window) context or pass the imported object instead.'); } } return customComponent; } }, { key: "getFilterFn", value: function getFilterFn() { return this.props.filterFn ? this.props.filterFn : function () { return true; }; } /** * <ColumnDefinition key="path" id="path" customComponent={CustomColumn} />, * <ColumnDefinition key="controls" id="actions" customHeadingComponent={CustomHeading} customComponent={CustomActions(buttonsConf)} /> * @param {*} param0 */ }, { key: "getColumnDefinition", value: function getColumnDefinition(conf) { var id = conf.id, customComponent = conf.customComponent, configuration = conf.configuration, action = conf.action; if (configuration && customComponent) { customComponent = customComponent(configuration); } if (action && !customComponent) { customComponent = WrapperComponent(action, customComponent); } return /*#__PURE__*/React.createElement(ColumnDefinition, _objectSpread(_objectSpread({}, conf), {}, { key: id, configuration: undefined, customComponent: customComponent, source: undefined })); } }, { key: "getColumnDefinitions", value: function getColumnDefinitions() { var _this5 = this; return this.getColumnConfiguration().map(function (colConf) { return _this5.getColumnDefinition(colConf); }); } }, { key: "getLayout", value: function getLayout() { var _this6 = this; if (this.props.layout) { return this.props.layout; } return function (_ref14) { var Table = _ref14.Table, Pagination = _ref14.Pagination, Filter = _ref14.Filter, SettingsWrapper = _ref14.SettingsWrapper; return /*#__PURE__*/React.createElement("div", { className: "listviewer-container" }, /*#__PURE__*/React.createElement(Filter, null), /*#__PURE__*/React.createElement(Table, null), _this6.props.showPagination === false ? null : /*#__PURE__*/React.createElement(Pagination, null)); }; } }, { key: "getPlugins", value: function getPlugins() { var _this$props = this.props, _this$props$remoteInf = _this$props.remoteInfiniteScroll, remoteInfiniteScroll = _this$props$remoteInf === void 0 ? false : _this$props$remoteInf, _this$props$plugins = _this$props.plugins, extraPlugins = _this$props$plugins === void 0 ? [] : _this$props$plugins; if (remoteInfiniteScroll) { return [plugins.PositionPlugin({ disablePointerEvents: true })].concat(_toConsumableArray(extraPlugins)); } return this.props.infiniteScroll ? [plugins.LocalPlugin, plugins.PositionPlugin({ disablePointerEvents: true })].concat(_toConsumableArray(extraPlugins)) : [plugins.LocalPlugin].concat(_toConsumableArray(extraPlugins)); } }, { key: "render", value: function render() { var customComponents = this.props.customComponents ? this.props.customComponents : {}; var _this$props2 = this.props, events = _this$props2.events, others = _objectWithoutProperties(_this$props2, _excluded); return /*#__PURE__*/React.createElement("section", { className: this.props.className ? this.props.className : "listviewer" }, /*#__PURE__*/React.createElement(Griddle, { data: this.getData(), plugins: this.getPlugins(), components: _objectSpread({ Layout: this.getLayout() }, customComponents), events: _objectSpread({}, events) }, /*#__PURE__*/React.createElement(RowDefinition, null, this.getColumnDefinitions()))); } }]); }(React.Component); export { ListViewer as default }; ListViewer.defaultProps = { handler: {} }; ListViewer.propTypes = { /** * Instances object */ instances: PropTypes.array.isRequired, /** * Specifies a handler context to which the callbacks specified are bound */ handler: PropTypes.object, /** * Bool that defines the presence or not of infiniteScroll */ infiniteScroll: PropTypes.bool, /** * Specifies custom column definitions */ columnConfiguration: PropTypes.arrayOf(PropTypes.shape({ /** * Column identifier */ id: PropTypes.string, /** * Title of the column */ title: PropTypes.string, /** * Source of the column */ source: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** * Custom css classname */ cssClassName: PropTypes.string, /** * Action associated with the column */ action: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.func]), /** * Custom component */ customComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.func]), /** * Custom heading component */ customHeadingComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]), /** * Display name of the column */ displayName: PropTypes.string, /** * Boolean value for determining column visibility */ visible: PropTypes.bool, /** * Configuration details of the column */ configuration: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]) })), /** * Function to filter data given a custom criterion */ filter: PropTypes.func, /** * Components passed in with a matching name will override the default in Griddle */ customComponents: PropTypes.shape({ /** * Custom components' cell type */ Cell: PropTypes.elementType, /** * Filter for searching custom components */ Filter: PropTypes.elementType, /** * Loading element */ Loading: PropTypes.elementType, /** * ElementType for the next button in the custom components */ NextButton: PropTypes.elementType, /** * ElementType for when there are no results returned from a search */ NoResults: PropTypes.elementType, /** * Page dropdown for the custom components */ PageDropdown: PropTypes.elementType, /** * Pagination for the custom components */ Pagination: PropTypes.elementType, /** * ElementType for the previous button in the custom components */ PreviousButton: PropTypes.elementType, /** * Row elementType for the custom components */ Row: PropTypes.elementType, /** * Definition of rows in the custom components */ RowDefinition: PropTypes.elementType, /** * Settings for the custom components */ Settings: PropTypes.elementType, /** * Settings for the List Viewer's custom component's toggle */ SettingsToggle: PropTypes.elementType, /** * Table for custom components */ Table: PropTypes.elementType, /** * Table body for custom components */ TableBody: PropTypes.elementType, /** * Table heading for custom components */ TableHeading: PropTypes.elementType, /** * Table heading for cells for custom components */ TableHeadingCell: PropTypes.elementType, /** * Table heading for cells in ascending order for custom components */ TableHeadingCellAscending: PropTypes.elementType, /** * Table heading for cells in descending order for custom components */ TableHeadingCellDescending: PropTypes.elementType, /** * Layout of the custom components */ Layout: PropTypes.elementType }), /** * Booleam to determine showing the Pagination button that is used for changing pages */ showPagination: PropTypes.bool };