UNPKG

canner

Version:

Build CMS in few lines of code for different data sources

434 lines (356 loc) 13.7 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.findNode = findNode; exports.isToList = isToList; exports.default = void 0; require("antd/lib/alert/style"); var _alert = _interopRequireDefault(require("antd/lib/alert")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var React = _interopRequireWildcard(require("react")); var _reactLoadable = _interopRequireDefault(require("react-loadable")); var _lodash = require("lodash"); var _cannerRefId = _interopRequireDefault(require("canner-ref-id")); var _cannerLayouts = _interopRequireDefault(require("canner-layouts")); var _antd = require("antd"); var _cannerHelpers = require("canner-helpers"); var _hocs = _interopRequireDefault(require("../hocs")); var _reactContentLoader = require("react-content-loader"); /** * Genertaor is a Component that renders the components, layouts * with the a given componentTree which is created by qa-compiler * * First Step, prerender the tree in constructor, this action will add a * React Component with all hocs it needs in every node * * Second Step, take the node.component to render it, and give the component * some props it maybe needs such as renderChildren */ var Generator = /*#__PURE__*/ function (_React$Component) { (0, _inherits2.default)(Generator, _React$Component); function Generator(_props) { var _this; (0, _classCallCheck2.default)(this, Generator); _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Generator).call(this, _props)); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "idNodeMap", {}); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "renderNode", function (node, props, index) { // take the node.component to render it, and give the component // some props it maybe needs such as renderChildren // eslint-disable-next-line no-unused-vars if (!node) { throw new Error("Unexpected Error: Want to render a undefined node with refId '".concat(props.refId.toString(), "'")); } var component = node.component, restNodeData = (0, _objectWithoutProperties2.default)(node, ["component"]); var _this$props = _this.props, _this$props$routerPar = _this$props.routerParams, routerParams = _this$props$routerPar === void 0 ? {} : _this$props$routerPar, goTo = _this$props.goTo, routes = _this$props.routes, imageStorages = _this$props.imageStorages, fileStorages = _this$props.fileStorages, onDeploy = _this$props.onDeploy, removeOnDeploy = _this$props.removeOnDeploy, hideButtons = _this$props.hideButtons, schema = _this$props.schema; var renderChildren = function renderChildren(props) { return _this.renderChildren(node, props); }; if (node.hidden || props.hidden) { return null; } if (component) { var contextValue = { renderChildren: renderChildren, routes: routes, refId: props.refId }; return React.createElement("div", { "data-testid": node.path }, React.createElement(_cannerHelpers.Context.Provider, { key: restNodeData.keyName ? "".concat(props.refId.toString(), "/").concat(restNodeData.keyName) : index, value: contextValue }, React.createElement(node.component, (0, _extends2.default)({ hideButtons: hideButtons, routes: routes, imageStorage: (imageStorages || {})[routes[0]], fileStorage: (fileStorages || {})[routes[0]], renderChildren: function renderChildren(props) { return _this.renderChildren(node, props); }, renderComponent: _this.renderComponent, routerParams: routerParams, onDeploy: onDeploy, removeOnDeploy: removeOnDeploy, schema: schema, goTo: goTo }, restNodeData, props)))); } return null; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "renderComponent", function (refId, props) { var cacheTree = _this.state.cacheTree; var componentPathArr = refId.getPathArr().filter(function (path) { return isNaN(Number(path)); }); var componentPath = componentPathArr.join('/'); var node = _this.idNodeMap[componentPath]; var entryKey = componentPathArr[0]; if (!node) { var lastPath = componentPathArr.slice(1); if (lastPath.length === 0) { node = cacheTree[entryKey]; } else { node = findNode(componentPathArr.slice(), cacheTree[entryKey]); } _this.idNodeMap[componentPath] = node; } if (!node) { throw new Error("Can't find the node at refId ".concat(refId.toString())); } return _this.renderNode(node, (0, _objectSpread2.default)({ refId: refId.remove(1), keyName: refId.getPathArr().slice(-1)[0] }, props), 0); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "renderChildren", function (node, props) { // just get the props and call renderNode // this method is called by components themselves var children = node.children; if (children) { return children.map(function (child, index) { var childProps = typeof props === 'function' ? props(child) : props; var refId = childProps.refId; if ((0, _lodash.isUndefined)(refId)) { throw new Error("refId is required for renderChildren, please check node '".concat(node.keyName || '', "'")); } if (childProps.hidden) { return null; } if (childProps.mergeNode) { // mutate node childProps.mergeNode(node); } return _this.renderNode(child, childProps, index); }); } return null; }); var componentTree = _props.componentTree; _this.state = { cacheTree: genCacheTree(componentTree), error: null, errorInfo: {} }; return _this; } (0, _createClass2.default)(Generator, [{ key: "componentDidMount", value: function componentDidMount() { var _this$props2 = this.props, componentTree = _this$props2.componentTree, routes = _this$props2.routes, goTo = _this$props2.goTo, defaultKey = _this$props2.defaultKey; var activeKey = routes[0]; if (!activeKey) { activeKey = Object.keys(componentTree)[0]; goTo({ pathname: defaultKey || activeKey }); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (this.props.refresh && !(0, _lodash.isEqual)(prevProps.componentTree, this.props.componentTree)) { this.setState({ cacheTree: genCacheTree(this.props.componentTree) }); } if (isToList(prevProps, this.props)) { this.props.reset && this.props.reset(); } } }, { key: "componentDidCatch", value: function componentDidCatch(error, errorInfo) { // Catch errors in any components below and re-render with error message this.setState({ error: error, errorInfo: errorInfo }); } }, { key: "render", value: function render() { var _this$state = this.state, cacheTree = _this$state.cacheTree, error = _this$state.error, errorInfo = _this$state.errorInfo; var _this$props3 = this.props, routes = _this$props3.routes, routerParams = _this$props3.routerParams; if (error) { return errorInfo; } if (!routes[0] || !cacheTree[routes[0]]) { return null; } return React.createElement("div", null, this.renderNode(cacheTree[routes[0]], { refId: new _cannerRefId.default(''), routes: routes, routerParams: routerParams }, 0)); } }]); return Generator; }(React.Component); exports.default = Generator; (0, _defineProperty2.default)(Generator, "defaultProps", { componentTree: {}, layouts: {} }); function defaultHoc(Component) { return Component; } function isComponent(node) { return node.nodeType && node.nodeType.startsWith('component'); } function isLayout(node) { return node.nodeType && node.nodeType.startsWith('layout'); } function isFieldset(node) { return node.packageName === '@canner/antd-object-fieldset'; } function isPage(node) { return node.nodeType && node.nodeType.startsWith('page'); } function isPageRoot(node) { return node.nodeType === 'page.page.default'; } function inPage(node) { return node.pattern.startsWith('page'); } function Loading(props) { if (props.error) { return React.createElement(_alert.default, { message: "Something went wrong.", description: props.error, type: "error", closable: true }); } else { return React.createElement(_reactContentLoader.List, { style: { maxWidth: '600px' } }); } } function createLoadableComponnet(node) { return (0, _reactLoadable.default)({ loader: function loader() { return node.loader || Promise.reject("There is no loader in ".concat(node.path)); }, loading: Loading }); } function generateComponent(node) { var component = node.component; if (isLayout(node)) { if (!node.component) { component = _cannerLayouts.default[node.ui]; } return wrapByHOC(component, node.ui === 'condition' ? ['containerQuery', 'context'] : ['context']); } if (isComponent(node)) { if (isFieldset(node)) { component = function component() { return React.createElement(_cannerHelpers.Item, null); }; } else { component = createLoadableComponnet(node); } return wrapByHOC(component, ['title', 'onDeploy', 'validation', 'deploy', 'request', 'relation', 'query', 'cache', 'route', 'id', 'context', 'errorCatch']); } else if (isPage(node)) { if (isPageRoot(node)) { component = function component() { return React.createElement(_cannerHelpers.Item, null); }; } else if (inPage(node)) { component = createLoadableComponnet(node); return wrapByHOC(component, ['graphqlQuery']); } else { component = createLoadableComponnet(node); component = wrapByHOC(component, ['title', 'onDeploy', 'validation', 'deploy', 'request', 'relation', 'query', 'cache', 'route', 'id', 'context', 'errorCatch']); } } return component; } function wrapByHOC(component, hocNames) { // find hocs and wrap the component while (hocNames.length) { var hocName = hocNames.shift(); var hoc = (0, _lodash.get)(_hocs.default, hocName, defaultHoc); component = hoc(component); } return component; } // wrap the plugin with hoc if it has function prerender(node) { // add a field `component` in every node. // it's a React Component with all hocs it needs in every node var copyNode = (0, _objectSpread2.default)({}, node); var component = generateComponent(node); if (!component) { throw new Error("invalid node, name: ".concat(copyNode.keyName, ", nodeType: ").concat(copyNode.nodeType)); } copyNode.component = component; if (copyNode.children) { copyNode.children = copyNode.children.map(function (child) { return prerender(child); }); } return copyNode; } function genCacheTree(tree) { return (0, _lodash.mapValues)(tree, function (branch) { return prerender(branch); }); } function findNode(pathArr, node) { if (isComponent(node) && node.keyName === pathArr[0]) { pathArr = pathArr.slice(1); if (!pathArr.length) { return node; } } if (node.children) { return node.children.map(function (child) { return findNode(pathArr, child); }).find(function (node) { return !!node; }); } } function isToList(preProps, props) { var preRoutes = JSON.stringify(preProps.routes); var routes = JSON.stringify(props.routes); var preOperator = preProps.routerParams.operator; var operator = props.routerParams.operator; return preRoutes === routes && preOperator === 'create' && operator === 'update'; }