mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 03:44:29 +03:00
Added feature to convert and open mobiledoc posts in the lexical editor (#17453)
refs TryGhost/Product#3638 - Added `convert_to_lexical` flag to the posts/pages edit endpoint - Added 'convertToLexical' feature flag so we can enable/disable this feature independently from the main lexical beta flag - Modified admin posts/pages list to point to the lexical editor for _all_ posts, regardless of mobiledoc vs lexical (if the flag is on) - Added call to edit endpoint with `convert_to_lexical` in the lexical editor admin route if the page/post is currently in mobiledoc and the flag is enabled
This commit is contained in:
parent
d8259fb4fe
commit
9ea4fbd7a7
@ -11,6 +11,11 @@ export default class Page extends ApplicationAdapter {
|
||||
parsedUrl.searchParams.append('save_revision', saveRevision);
|
||||
}
|
||||
|
||||
if (snapshot?.adapterOptions?.convertToLexical) {
|
||||
const convertToLexical = snapshot.adapterOptions.convertToLexical;
|
||||
parsedUrl.searchParams.append('convert_to_lexical', convertToLexical);
|
||||
}
|
||||
|
||||
return parsedUrl.toString();
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,12 @@ export default class Post extends ApplicationAdapter {
|
||||
const saveRevision = snapshot.adapterOptions.saveRevision;
|
||||
parsedUrl.searchParams.append('save_revision', saveRevision);
|
||||
}
|
||||
|
||||
if (snapshot?.adapterOptions?.convertToLexical) {
|
||||
const convertToLexical = snapshot.adapterOptions.convertToLexical;
|
||||
parsedUrl.searchParams.append('convert_to_lexical', convertToLexical);
|
||||
}
|
||||
|
||||
return parsedUrl.toString();
|
||||
}
|
||||
|
||||
|
@ -45,12 +45,23 @@
|
||||
{{/unless}}
|
||||
</a>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data gh-post-list-title">
|
||||
<LinkTo @route={{this.editorRoute}} @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data gh-post-list-title">
|
||||
<h3 class="gh-content-entry-title">
|
||||
{{#if @post.featured}}
|
||||
{{svg-jar "star-fill" class="gh-featured-post"}}
|
||||
{{/if}}
|
||||
{{@post.title}}
|
||||
|
||||
{{! Display lexical/mobiledoc indicators for easier testing of the feature --}}
|
||||
{{#if (feature 'convertToLexical')}}
|
||||
{{#if @post.lexical}}
|
||||
<span class="gh-lexical-indicator">L</span>
|
||||
{{/if}}
|
||||
{{#if @post.mobiledoc}}
|
||||
<span class="gh-lexical-indicator">M</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
</h3>
|
||||
{{#unless @hideAuthor }}
|
||||
<p class="gh-content-entry-meta">
|
||||
@ -141,7 +152,7 @@
|
||||
</span>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data">
|
||||
<LinkTo @route={{this.editorRoute}} @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data">
|
||||
{{!-- Empty on purpose --}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
@ -175,7 +186,7 @@
|
||||
</span>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data">
|
||||
<LinkTo @route={{this.editorRoute}} @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data">
|
||||
{{!-- Empty on purpose --}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
@ -196,7 +207,7 @@
|
||||
</span>
|
||||
</a>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data gh-post-list-button" title="">
|
||||
<LinkTo @route={{this.editorRoute}} @models={{array this.post.displayName this.post.id}} class="permalink gh-list-data gh-post-list-button" title="">
|
||||
<span class="gh-post-list-cta edit {{if this.isHovered "is-hovered"}}" title="Go to Editor" data-ignore-select>
|
||||
{{svg-jar "pen" title="Go to Editor"}}
|
||||
</span>
|
||||
|
@ -11,6 +11,8 @@ export default class PostsListItemClicks extends Component {
|
||||
|
||||
@tracked isHovered = false;
|
||||
|
||||
editorRoute = this.feature.get('convertToLexical') ? 'lexical-editor.edit' : 'editor.edit';
|
||||
|
||||
get post() {
|
||||
return this.args.post;
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {pluralize} from 'ember-inflector';
|
||||
|
||||
import {inject as service} from '@ember/service';
|
||||
export default class EditRoute extends AuthenticatedRoute {
|
||||
@service feature;
|
||||
|
||||
beforeModel(transition) {
|
||||
super.beforeModel(...arguments);
|
||||
|
||||
@ -29,10 +31,15 @@ export default class EditRoute extends AuthenticatedRoute {
|
||||
};
|
||||
|
||||
const records = await this.store.query(modelName, query);
|
||||
const post = records.firstObject;
|
||||
|
||||
let post = records.firstObject;
|
||||
|
||||
// CASE: Post is in mobiledoc — convert to lexical or redirect
|
||||
if (post.mobiledoc) {
|
||||
return this.router.transitionTo('editor.edit', post);
|
||||
if (this.feature.get('convertToLexical') && this.feature.get('lexicalEditor')) {
|
||||
post = await post.save({adapterOptions: {convertToLexical: 1}});
|
||||
} else {
|
||||
return this.replaceWith('editor.edit', post);
|
||||
}
|
||||
}
|
||||
|
||||
return post;
|
||||
|
@ -78,6 +78,7 @@ export default class FeatureService extends Service {
|
||||
@feature('headerUpgrade') headerUpgrade;
|
||||
@feature('importMemberTier') importMemberTier;
|
||||
@feature('tipsAndDonations') tipsAndDonations;
|
||||
@feature('convertToLexical') convertToLexical;
|
||||
|
||||
_user = null;
|
||||
|
||||
|
@ -100,7 +100,9 @@
|
||||
<div class="gh-editor-wordcount">
|
||||
{{gh-pluralize this.wordCount "word"}}
|
||||
</div>
|
||||
{{!-- <a href="https://github.com/TryGhost/Koenig/tree/main/packages/koenig-lexical" target="_blank" rel="noopener noreferrer" class="gh-lexical-indicator">Lexical</a> --}}
|
||||
{{#if (feature 'convertToLexical')}}
|
||||
<a href="https://github.com/TryGhost/Koenig/tree/main/packages/koenig-lexical" target="_blank" rel="noopener noreferrer" class="gh-lexical-indicator">Lexical</a>
|
||||
{{/if}}
|
||||
<a href="https://ghost.org/help/using-the-editor/" class="flex" target="_blank" rel="noopener noreferrer">{{svg-jar "help"}}</a>
|
||||
</div>
|
||||
|
||||
|
@ -339,6 +339,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-expandable-block">
|
||||
<div class="gh-expandable-header">
|
||||
<div>
|
||||
<h4 class="gh-expandable-title">Convert to Lexical</h4>
|
||||
<p class="gh-expandable-description">
|
||||
Convert mobiledoc posts to lexical upon opening in the editor.
|
||||
</p>
|
||||
</div>
|
||||
<div class="for-switch">
|
||||
<GhFeatureFlag @flag="convertToLexical" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-expandable-block">
|
||||
<div class="gh-expandable-header">
|
||||
<div>
|
||||
|
@ -141,6 +141,7 @@ module.exports = {
|
||||
'source',
|
||||
'force_rerender',
|
||||
'save_revision',
|
||||
'convert_to_lexical',
|
||||
// NOTE: only for internal context
|
||||
'forUpdate',
|
||||
'transacting'
|
||||
|
@ -192,6 +192,7 @@ module.exports = {
|
||||
'newsletter',
|
||||
'force_rerender',
|
||||
'save_revision',
|
||||
'convert_to_lexical',
|
||||
// NOTE: only for internal context
|
||||
'forUpdate',
|
||||
'transacting'
|
||||
|
@ -19,6 +19,8 @@ const {Tag} = require('./tag');
|
||||
const {Newsletter} = require('./newsletter');
|
||||
const {BadRequestError} = require('@tryghost/errors');
|
||||
const {PostRevisions} = require('@tryghost/post-revisions');
|
||||
const {mobiledocToLexical} = require('@tryghost/kg-converters');
|
||||
const labs = require('../../shared/labs');
|
||||
|
||||
const messages = {
|
||||
isAlreadyPublished: 'Your post is already published, please reload your page.',
|
||||
@ -913,6 +915,16 @@ Post = ghostBookshelf.Model.extend({
|
||||
});
|
||||
}
|
||||
|
||||
// CASE: Convert post to lexical on the fly
|
||||
if (labs.isSet('convertToLexical') && labs.isSet('lexicalEditor') && options.convert_to_lexical) {
|
||||
ops.push(async function convertToLexical() {
|
||||
const mobiledoc = model.get('mobiledoc');
|
||||
const lexical = mobiledocToLexical(mobiledoc);
|
||||
model.set('lexical', lexical);
|
||||
model.set('mobiledoc', null);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get('tiers')) {
|
||||
this.set('tiers', this.get('tiers').map(t => ({
|
||||
id: t.id
|
||||
@ -1154,9 +1166,10 @@ Post = ghostBookshelf.Model.extend({
|
||||
const validOptions = {
|
||||
findOne: ['columns', 'importing', 'withRelated', 'require', 'filter'],
|
||||
findPage: ['status'],
|
||||
|
||||
findAll: ['columns', 'filter'],
|
||||
destroy: ['destroyAll', 'destroyBy'],
|
||||
edit: ['filter', 'email_segment', 'force_rerender', 'newsletter', 'save_revision']
|
||||
edit: ['filter', 'email_segment', 'force_rerender', 'newsletter', 'save_revision', 'convert_to_lexical']
|
||||
};
|
||||
|
||||
// The post model additionally supports having a formats option
|
||||
|
@ -41,8 +41,9 @@ const ALPHA_FEATURES = [
|
||||
'mailEvents',
|
||||
'collectionsCard',
|
||||
'headerUpgrade',
|
||||
'tipsAndDonations',
|
||||
'importMemberTier',
|
||||
'tipsAndDonations'
|
||||
'convertToLexical'
|
||||
];
|
||||
|
||||
module.exports.GA_KEYS = [...GA_FEATURES];
|
||||
|
@ -101,6 +101,7 @@
|
||||
"@tryghost/importer-revue": "0.0.0",
|
||||
"@tryghost/job-manager": "0.0.0",
|
||||
"@tryghost/kg-card-factory": "4.0.9",
|
||||
"@tryghost/kg-converters": "0.0.7",
|
||||
"@tryghost/kg-default-atoms": "4.0.2",
|
||||
"@tryghost/kg-default-cards": "9.1.2",
|
||||
"@tryghost/kg-default-nodes": "0.1.17",
|
||||
|
@ -1,5 +1,112 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Pages API Convert can convert a mobiledoc page to lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"pages": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"negative_feedback": 0,
|
||||
"paid_conversions": 0,
|
||||
"positive_feedback": 0,
|
||||
"signups": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"excerpt": "This is some great content.",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>This is some great content.</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"This is some great content.\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}}",
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"post_revisions": Any<Array>,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"reading_time": 0,
|
||||
"show_title_and_feature_image": Any<Boolean>,
|
||||
"slug": "test-post",
|
||||
"status": "published",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Array [
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": null,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": null,
|
||||
"monthly_price_id": null,
|
||||
"name": "Free",
|
||||
"slug": "free",
|
||||
"trial_days": 0,
|
||||
"type": "free",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": null,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": 500,
|
||||
"monthly_price_id": null,
|
||||
"name": "Default Product",
|
||||
"slug": "default-product",
|
||||
"trial_days": 0,
|
||||
"type": "paid",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": 5000,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
],
|
||||
"title": "Test Post",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Pages API Convert can convert a mobiledoc page to lexical 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "4013",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": "/*",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Pages API Copy Can copy a page 1: [body] 1`] = `
|
||||
Object {
|
||||
"pages": Array [
|
||||
|
@ -790,6 +790,116 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Convert can convert a mobiledoc post to lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"clicks": 0,
|
||||
"negative_feedback": 0,
|
||||
"positive_feedback": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"email": null,
|
||||
"email_only": false,
|
||||
"email_segment": "all",
|
||||
"email_subject": null,
|
||||
"excerpt": "This is some great content.",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>This is some great content.</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"This is some great content.\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}}",
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": null,
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"post_revisions": Any<Array>,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"reading_time": 0,
|
||||
"slug": "test-post-2",
|
||||
"status": "published",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Array [
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": null,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": null,
|
||||
"monthly_price_id": null,
|
||||
"name": "Free",
|
||||
"slug": "free",
|
||||
"trial_days": 0,
|
||||
"type": "free",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": null,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": 500,
|
||||
"monthly_price_id": null,
|
||||
"name": "Default Product",
|
||||
"slug": "default-product",
|
||||
"trial_days": 0,
|
||||
"type": "paid",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": 5000,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
],
|
||||
"title": "Test Post",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Convert can convert a mobiledoc post to lexical 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "4050",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": "/*",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Copy Can copy a post 1: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
|
@ -113,4 +113,79 @@ describe('Pages API', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Convert', function () {
|
||||
it('can convert a mobiledoc page to lexical', async function () {
|
||||
const mobiledoc = JSON.stringify({
|
||||
version: '0.3.1',
|
||||
ghostVersion: '4.0',
|
||||
markups: [],
|
||||
atoms: [],
|
||||
cards: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'This is some great content.']
|
||||
]]
|
||||
]
|
||||
});
|
||||
const expectedLexical = JSON.stringify({
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'This is some great content.',
|
||||
type: 'text',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1
|
||||
}
|
||||
});
|
||||
const pageData = {
|
||||
title: 'Test Post',
|
||||
status: 'published',
|
||||
mobiledoc: mobiledoc,
|
||||
lexical: null
|
||||
};
|
||||
|
||||
const {body: pageBody} = await agent
|
||||
.post('/pages/?formats=mobiledoc,lexical,html', {
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
.body({pages: [pageData]})
|
||||
.expectStatus(201);
|
||||
|
||||
const [pageResponse] = pageBody.pages;
|
||||
|
||||
await agent
|
||||
.put(`/pages/${pageResponse.id}/?formats=mobiledoc,lexical,html&convert_to_lexical=true`)
|
||||
.body({pages: [Object.assign({}, pageResponse)]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
pages: [Object.assign({}, matchPageShallowIncludes, {lexical: expectedLexical, mobiledoc: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -628,4 +628,40 @@ describe('Posts API', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Convert', function () {
|
||||
it('can convert a mobiledoc post to lexical', async function () {
|
||||
const mobiledoc = createMobiledoc('This is some great content.');
|
||||
const expectedLexical = createLexical('This is some great content.');
|
||||
const postData = {
|
||||
title: 'Test Post',
|
||||
status: 'published',
|
||||
mobiledoc: mobiledoc,
|
||||
lexical: null
|
||||
};
|
||||
|
||||
const {body} = await agent
|
||||
.post('/posts/?formats=mobiledoc,lexical,html', {
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
.body({posts: [postData]})
|
||||
.expectStatus(201);
|
||||
|
||||
const [postResponse] = body.posts;
|
||||
|
||||
await agent
|
||||
.put(`/posts/${postResponse.id}/?formats=mobiledoc,lexical,html&convert_to_lexical=true`)
|
||||
.body({posts: [Object.assign({}, postResponse)]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign({}, matchPostShallowIncludes, {lexical: expectedLexical, mobiledoc: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user