UNPKG

@prisma-cms/front-editor

Version:
429 lines 20.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Editable = void 0; /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable react/forbid-foreign-prop-types */ const react_1 = __importDefault(require("react")); const prop_types_1 = __importDefault(require("prop-types")); const EditorComponent_1 = __importDefault(require("../../../EditorComponent")); const apollo_cms_1 = require("apollo-cms"); const ListView_1 = require("../../Connectors/Connector/ListView"); const context_1 = require("../../../context"); const Query_1 = __importDefault(require("../../Connectors/Query")); // import { graphql } from 'react-apollo'; const graphql_tag_1 = __importDefault(require("graphql-tag")); const graphql_1 = require("graphql"); const path_to_regexp_1 = __importDefault(require("path-to-regexp")); const IconButton_1 = __importDefault(require("material-ui/IconButton")); const CircularProgress_1 = __importDefault(require("material-ui/Progress/CircularProgress")); const Delete_1 = __importDefault(require("material-ui-icons/Delete")); // TODO Fix for new EditableObject class Editable extends apollo_cms_1.EditableObject { constructor(props) { super(props); this.delete = this.delete.bind(this); } updateObject(data) { for (const i in data) { const value = data[i]; if (value === '') { data[i] = null; } } return super.updateObject(data); } mutate(props, method) { const _super = Object.create(null, { mutate: { get: () => super.mutate } }); return __awaiter(this, void 0, void 0, function* () { /** Prepare Mutation */ const { query_components: children, getQueryNameFromQuery, extendQuery, } = this.props; const queries = {}; const { id: objectId } = this.getObject() || {}; children && children.length && children .filter((n) => n) .map((n) => { const { type, props } = n; if (type === Query_1.default) { const { query } = (props && props.props) || {}; if (query) { const queryName = getQueryNameFromQuery(query); if (queryName) { queries[queryName] = query; } } } return null; }); if (!method) { method = objectId ? 'update' : 'create'; } let mutation = queries && method ? queries[method] : null; if (!mutation) { const error = new Error('Can not get mutation'); return this.addError(error); } /** Eof Prepare Mutation */ try { const extendedQuery = extendQuery(mutation); mutation = graphql_tag_1.default(extendedQuery); } catch (error) { console.error(error); } return _super.mutate.call(this, Object.assign(Object.assign({}, props), { mutation })); }); } renderEditableView() { const { children } = this.props; return children; } renderDefaultView() { const { children } = this.props; return children; } renderHeader() { const { show_header } = this.props; return show_header ? super.renderHeader() : null; } getButtons() { const { id: objectId } = this.getObject() || {}; const buttons = super.getButtons() || []; if (this.inEditMode() && objectId) { buttons.push(this.renderDeleteButton()); } return buttons; } renderDeleteButton() { const { DeleteIcon, deletable_object } = this.props; const { loading } = this.state; return deletable_object ? (react_1.default.createElement(IconButton_1.default, { key: "delete", onClick: this.delete, disabled: loading }, loading ? react_1.default.createElement(CircularProgress_1.default, null) : react_1.default.createElement(DeleteIcon, null))) : null; } delete() { const { id: objectId } = this.getObject() || {}; if (objectId) { if (window.confirm('Удалить данный объект?')) { return this.mutate({ variables: { where: { id: objectId, }, }, }, 'delete').then((r) => { const { on_delete_redirect_url } = this.props; if (on_delete_redirect_url) { const { router: { history }, } = this.context; history.push(decodeURIComponent(on_delete_redirect_url)); } return r; }); } } } render() { const _a = this.props, { // eslint-disable-next-line @typescript-eslint/no-unused-vars _dirty: _dirty_null } = _a, other = __rest(_a, ["_dirty"]); const { loading, _dirty, errors, notifications } = this.state; const fieldErrors = {}; if (errors && errors.length) { errors.map(({ key, message }) => { fieldErrors[key] = message; return null; }); } const object = this.getObjectWithMutations(); return (react_1.default.createElement(context_1.EditableObjectContext.Provider, { value: Object.assign({ // getCacheKey: this.getCacheKey, updateObject: this.updateObject, getEditor: this.getEditor, inEditMode: this.inEditMode(), canEdit: this.canEdit(), getObjectWithMutations: this.getObjectWithMutations, getObject: this.getObject, getButtons: this.getButtons, save: this.save, mutate: this.mutate, loading, _dirty, errors, fieldErrors, notifications }, other) }, react_1.default.createElement(ListView_1.ObjectContext.Provider, { value: { object: this.getObjectWithMutations(), } }, super.render()))); } } exports.Editable = Editable; Editable.propTypes = Object.assign(Object.assign({}, apollo_cms_1.EditableObject.propTypes), { show_header: prop_types_1.default.bool.isRequired, extendQuery: prop_types_1.default.func.isRequired, getQueryNameFromQuery: prop_types_1.default.func.isRequired, query_components: prop_types_1.default.array.isRequired, DeleteIcon: prop_types_1.default.func.isRequired, deletable_object: prop_types_1.default.bool.isRequired, on_delete_redirect_url: prop_types_1.default.string, data: prop_types_1.default.object }); Editable.defaultProps = Object.assign(Object.assign({}, apollo_cms_1.EditableObject.defaultProps), { show_header: true, DeleteIcon: Delete_1.default, deletable_object: false }); class EditableObject extends EditorComponent_1.default { constructor(props) { super(props); this.onBeforeDrop = () => { return; }; // onUpdateObject(result) { // return result; // } /** * Расширяем запрос */ this.extendQueryBind = (Query) => this.extendQuery(Query); this.state = Object.assign(Object.assign({}, this.state), { object_key: Math.random() }); this.onCreateObject = this.onCreateObject.bind(this); this.onSaveObject = this.onSaveObject.bind(this); } renderPanelView(content) { return super.renderPanelView(content || react_1.default.createElement("div", { className: 'panelEditableObject' }, "EditableObject")); } getEditableClass() { return Editable; } /** * Позволяет переопределить редактируемый объект, * например, чтобы создавать новый внутри имеющегося */ prepareEditableObject(object) { const { create_as_a_child_of } = this.getComponentProps(this); return create_as_a_child_of ? {} : object; } /** * Этот метод не модифицирует сам редактируемые объект, * а только формирует параметры для класса Editable */ prepareObject(context) { return { _dirty: this.getDirty(context), }; } getDirty(context) { let { _dirty } = context; const { object } = context; const { create_as_a_child_of } = this.getComponentProps(this); const { id: objectId } = object || {}; if (create_as_a_child_of) { _dirty = _dirty ? Object.assign({}, _dirty) : {}; Object.assign(_dirty, { [create_as_a_child_of]: { connect: { id: objectId, }, }, }); } return _dirty; } onCreateObject(result) { const { on_create_redirect_url } = this.getComponentProps(this); if (on_create_redirect_url) { const { response } = result.data || {}; const { data: object } = response || {}; if (object) { const toPath = path_to_regexp_1.default.compile(on_create_redirect_url); try { const url = toPath(object, { noValidate: true }); if (url) { const { router: { history }, } = this.context; history.push(decodeURIComponent(url)); } } catch (error) { console.error(error); } } } return; } onSaveObject(result) { const { random_key } = this.getComponentProps(this); if (random_key) { this.setState({ object_key: Math.random(), }); } return this.onCreateObject(result); } extendQuery(Query) { const { schema } = this.context; if (Query && schema) { /** * Проходим запрос на предмет директив в фрагментах */ const parsedQuery = graphql_1.parse(Query); if (parsedQuery && schema) { const { types } = schema; const { definitions } = parsedQuery; if (definitions && definitions.length) { definitions.reduceRight((current, definition) => { const { kind, directives, selectionSet: { loc: { end }, }, typeCondition, } = definition; if (kind === 'FragmentDefinition' && typeCondition) { const needAutoloadFields = directives && directives.find((n) => n && n.name && n.name.value === 'prismaCmsFragmentAllFields') ? true : false; if (needAutoloadFields) { const { // kind, name: { value: type }, } = typeCondition; if (type) { const field = types.find((n) => { const { kind, name } = n; return kind === 'OBJECT' && name === type; }); if (field) { let { fields } = field; fields = fields.filter((n) => { return n && n.name && this.isScalar(n) ? true : false; }); /** * Если были получены скалярные поля, * добавляем их в запрос */ if (fields.length) { const fieldsList = '\n' + fields.map(({ name }) => name).join('\n') + '\n'; const position = end - 1; Query = [ Query.slice(0, position), fieldsList, Query.slice(position), ].join(''); } } } } } return current; }, []); } } } return Query; } isScalar(field) { const { type: { kind, ofType }, } = field; if (kind === 'SCALAR') { return true; } else if (kind === 'ENUM') { return true; } else if ((kind === 'NON_NULL' || kind === 'LIST') && ofType) { return this.isScalar({ type: ofType, }); } else { return false; } } getQueryNameFromQuery(query) { try { const parsedSchema = graphql_1.parse(query); if (parsedSchema) { const { definitions } = parsedSchema; if (definitions) { const OperationDefinition = definitions.find((n) => n.kind === 'OperationDefinition'); if (OperationDefinition) { const { value } = OperationDefinition.name || {}; return value; } } } } catch (error) { console.error(error); } } renderChildren() { // const { // inEditMode, // } = this.getEditorContext(); const children = super.renderChildren(); const _a = this.getComponentProps(this), { on_create_redirect_url, props, data, components, style, cache_key, cache_key_prefix, new_object_cache_key, object, random_key } = _a, // _dirty, other = __rest(_a, ["on_create_redirect_url", "props", "data", "components", "style", "cache_key", "cache_key_prefix", "new_object_cache_key", "object", "random_key"]); const { object_key } = this.state; const Editable = this.getEditableClass(); return (react_1.default.createElement(ListView_1.ObjectContext.Consumer, { key: "editable_object" }, (context) => { const { object, loading } = context; /** Если объекта нет и еще выполняется загрузка, прерываем рендерер. Иначе объект будет инициализирован как новый, то есть в режиме редактирования со свойством _dirty */ if (!object && loading) { return null; } /** * Здесь есть возможность переопределить объект */ const editableObject = this.prepareEditableObject(object); const { id: objectId } = editableObject || {}; const cacheKey = cache_key !== undefined ? cache_key : new_object_cache_key && !objectId ? new_object_cache_key : undefined; const cacheKeyPrefix = cache_key_prefix; return (react_1.default.createElement(Editable, Object.assign({ key: random_key ? object_key : undefined, // data={{ // object: object || {}, // }} object: editableObject, extendQuery: this.extendQueryBind, // extendQuery={(query) => this.extendQuery(query)} getQueryNameFromQuery: this.getQueryNameFromQuery, query_components: children, onSave: !objectId ? this.onSaveObject : null, cacheKey: cacheKey, cacheKeyPrefix: cacheKeyPrefix }, this.prepareObject(context), other), children)); })); } } EditableObject.propTypes = Object.assign(Object.assign({}, EditorComponent_1.default.propTypes), { deletable_object: prop_types_1.default.bool.isRequired, /** * Если новый объект создается как дочерний от другого объекта, * то можно указать имя родителя, чтобы сформировать конструкцию [parent_name]: {connect: parent_id}. * Важно! Если выставить это свойство, будет создан именно новый объект, * даже если это имеющийся уже объект (объект будет перетерт). */ create_as_a_child_of: prop_types_1.default.string, /** * При рендеринге создает новый ключ для рендеринга Editable. * Это удобно, когда надо обновить данные * при сохранении нового объекта без перезагрузки страницы. * Важно! В режиме редактирования шаблонов передача меняемого key * ломает вывод элементов, поэтому этот параметр следует использовать очень осторожно. */ random_key: prop_types_1.default.bool }); EditableObject.defaultProps = Object.assign(Object.assign({}, EditorComponent_1.default.defaultProps), { style: Object.assign(Object.assign({}, EditorComponent_1.default.defaultProps.style), { flexBasis: '100%' }), /** * УРЛ, куда редиректить при создании нового объекта */ on_create_redirect_url: undefined, /** * Куда редиректить при успешном удалении элемента */ on_delete_redirect_url: undefined, cache_key: undefined, cache_key_prefix: undefined, new_object_cache_key: undefined, show_header: true, hide_wrapper_in_default_mode: true, deletable_object: false, create_as_a_child_of: undefined, random_key: false }); EditableObject.Name = 'EditableObject'; EditableObject.help_url = 'https://front-editor.prisma-cms.com/topics/editableobject.html'; exports.default = EditableObject; //# sourceMappingURL=index.js.map