rich-text
rich-text copied to clipboard
Unsupported nodes in rich-text-from-markdown
Hi there! I tried following the example from the ReadMe for rich-text-from-markdown to support odd nodes when migrating entries to Contentful. For images, we have a content model called "Image" that contains the asset and extra metadata. I have a feeling this error is locale related, but I'm not sure where that goes:
return await richTextFromMarkdown(replacedText, (node) => {
if (node.type === "image") {
return [
{
nodeType: "embedded-entry-block",
content: [],
data: {
target: {
sys: {
type: "Link",
linkType: "Entry",
id: "56LKuhwunEc9UN5I6MV1Pp", // Real entry ID in my project
},
},
},
},
];
}
return node;
});
The error:
{
"status": 422,
"statusText": "Unprocessable Entity",
"message": "Validation error",
"details": {
"errors": [
{
"name": "in",
"details": "Value must be one of expected values",
"path": [
"fields",
"content",
"en-US",
"content",
3,
"content",
1,
"content",
0,
"nodeType"
],
"value": "embedded-entry-block",
"expected": ["text"]
},
{
"name": "in",
"details": "Value must be one of expected values",
"path": [
"fields",
"content",
"en-US",
"content",
19,
"content",
1,
"content",
0,
"nodeType"
],
"value": "embedded-entry-block",
"expected": ["text"]
}
]
},
"request": {
"url": "entries",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/vnd.contentful.management.v1+json",
"X-Contentful-User-Agent": "sdk contentful-management.js/5.28.0; platform node.js/v14.16.1; os macOS/20.3.0;",
"Authorization": "Bearer ...gjBHA",
"user-agent": "node.js/v14.16.1",
"Accept-Encoding": "gzip",
"X-Contentful-Content-Type": "article",
"Content-Length": 10128
},
"method": "post",
"payloadData": "{\"fields\":{\"title\":{\"en-US\":\"Three Ways to Increase Participation at Your Next Culture Event\"},\"slug\":{\"en-US\":\"three-ways-increase-participation-next-culture-event\"},\"date\":{\"en-US\":\"2014-10-14T22:24:43+00:00\"},\"excerpt\":{\"en-US\":\"I ran into a colleague of mine, Sam, last week who has been working hard to strengthen the culture at his organization. Theyâre working on their core values, aligning their vision throughout the organization, and hiring and promoting based on both of ...\"},\"authors\":{\"en-US\":[{\"sys\":{\"type\":\"Link\",\"linkType\":\"Entry\",\"id\":\"6inaB1C53UihlrUCMsVPkg\"}}]},\"categories\":{\"en-US\":[{\"sys\":{\"type\":\"Link\",\"linkType\":\"Entry\",\"id\":\"303G5Mf28c6EV2PD6mp1DC\"}}]},\"relatedArticles\":{\"en-US\":[]},\"featuredOnHomepage\":{\"en-US\":false},\"pinnedOnHomepage\":{\"en-US\":false},\"featuredImage\":{\"en-US\":{\"sys\":{\"type\":\"Link\",\"linkType\":\"Asset\",\"id\":\"1TvChsZuHgMCQQFBMd4Umt\"}}},\"socialImageVisualDescription\":{\"en-US\":\"Bill and Oren Pingboard\"},\"content\":{\"en-US\":{\"nodeType\":\"document\",\"data\":{},\"content\":[{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"I ran into a colleague of mine, Sam, last week who has been working hard to strengthen the culture at his organization. Theyâre working on their core values, aligning their vision throughout the organization, and hiring and promoting based on both of those initiatives.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"embedded-entry-block\",\"content\":[],\"data\":{\"target\":{\"sys\":{\"type\":\"Link\",\"linkType\":\"Entry\",\"id\":\"56LKuhwunEc9UN5I6MV1Pp\"}}}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"Naturally, theyâve also been ramping up the âfunâ events in an attempt to break down silos and get team members interacting on a more personal level. The challenge is that even though theyâre spending good money on these events the turnout isnât as high as theyâd like it to be. If the events are in the office, employees will show up, get the food, and eat at their desks. What Sam really wants is for people to want to stay at these events but for now heâd settle for getting people there in the first place.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\" \",\"marks\":[],\"data\":{}},{\"nodeType\":\"hyperlink\",\"data\":{\"uri\":\"https://cta-redirect.hubspot.com/cta/redirect/2495271/1a455bba-b03c-4e50-9345-58c147b657da\"},\"content\":[{\"nodeType\":\"embedded-entry-block\",\"content\":[],\"data\":{\"target\":{\"sys\":{\"type\":\"Link\",\"linkType\":\"Entry\",\"id\":\"56LKuhwunEc9UN5I6MV1Pp\"}}}}]},{\"nodeType\":\"text\",\"value\":\" hbspt.cta.load(2495271, '1a455bba-b03c-4e50-9345-58c147b657da', {});\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"heading-2\",\"content\":[{\"nodeType\":\"text\",\"value\":\"1\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\".\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\" Break down organizational silos in a fun way\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"there is strategy behind the âfunâ that, for the most part, goes unnoticed. The strategy is that big events are meant to break down silos between people and teams. They are designed to give people a chance to get to know others within the organization on a more personal level that will, in the long run, make it easier for teams to communicate, interact with, and have empathy for the people they donât know very well.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"The value in the âFunâ events isnât to check a box that youâre trying to be cool. The value happens when you create an environment that encourages people from different offices, teams, and departments to interact and get to know each other.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"This takes strategy. At one company I worked for we designed a Compete to Eat competition that happened before we ate at our monthly events. As employees walked in they drew colored straws and found their âteamâ somewhere around the room. People werenât allowed to select which team they were on because when people get to choose they form teams full of people who know each other. That defeats the point. The point is to get them interacting with \",\"marks\":[],\"data\":{}},{\"nodeType\":\"hyperlink\",\"data\":{\"uri\":\"https://pingboard.com/google-apps-directory\"},\"content\":[{\"nodeType\":\"text\",\"value\":\"people from other groups\",\"marks\":[],\"data\":{}}]},{\"nodeType\":\"text\",\"value\":\".\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"Once the groups were formed and introductions had been made we started the competition. Each one was designed to have some people from the team competing and the rest of the team cheering them on. This allowed newer or more shy employees to play an active role without being forced into the spotlight.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"The team that won was able to get their food first and the team that lost got their food last.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"We knew that breaking people into teams would encourage cross departmental interactions but what we didnât anticipate was that the teams would sit with each other once they had their food. However, thatâs exactly what happened. After the very first competition we realized that all of our new hires had a âgroupâ to sit with which eliminated the awkward experience of being the new kid in the cafeteria. It also allowed employees from varying departments to strengthen their bonds with fellow co-workers.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"heading-2\",\"content\":[{\"nodeType\":\"text\",\"value\":\"2\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\".\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\" Get buy in from senior leadership team\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"âFunâ events only work if people show up. The goal isnât for your HR or Culture department to send out reminders making the events mandatory. That never goes over well. Remember, there is strategy to the âfunâ stuff. That strategy is that it builds relationships, breaks down silos, and increases communication. This is high level, important stuff so the âfunâ events need to be backed and supported by the high level, really important people in the organization. Thatâs the Senior Leadership Team. Once the events are backed by the Senior Leaders then they need to hold their direct reports accountable for getting their people to the events.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"Iâve worked with several organizations who actually have, as part of the leadership job descriptions, measures of accountability that include getting their employees to attend culture events. These events, if executed well, are a huge part of building a strong culture but it requires that leaders and managers are showing up and are strongly encouraging their teams to be there, and stay there, as well. If the leaders donât show up and actively engage in the event why would the rest of the employees?\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"heading-2\",\"content\":[{\"nodeType\":\"text\",\"value\":\"3\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\".\",\"marks\":[],\"data\":{}},{\"nodeType\":\"text\",\"value\":\" Put employees in the driver seat\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"Third, if people arenât showing up you need to ask yourself if the events are hitting the mark. In order for events to hit the mark they have to have high levels of attendance, have support from the Senior Leaders, and support a strategic need the organization has. If youâre having low attendance at your events, are all three of these things happening? Iâm willing to guess they arenât.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"A crucial error that companies make is that someone sitting in an office, slightly removed from the front line employees, decides itâs time to do something fun so they order some pizza and invite people to lunch. Instead, invite employees to give feedback about these events. If youâre hosting a happy hour, ask some of your employees to offer up suggestions for new restaurants theyâd like to try out. If you want to host a competition, ask some of your employees to come up with the next competition. Task them with hosting the event, creating the crazy trophy, and designing the tee-shirts. Youâll be surprised at how much involvement a team of employees excited about the next Oreo Eating Contest can drum up.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"If youâre trying to \",\"marks\":[],\"data\":{}},{\"nodeType\":\"hyperlink\",\"data\":{\"uri\":\"https://pingboard.com/connections\"},\"content\":[{\"nodeType\":\"text\",\"value\":\"build community at work\",\"marks\":[],\"data\":{}}]},{\"nodeType\":\"text\",\"value\":\" by adding some fun, remember that the goal is to do something for your employees to help reinforce behaviors that you want to see more of.\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\"What are some of the fun events you host at your company and how do you get the maximum number of employees to participate?\",\"marks\":[],\"data\":{}}],\"data\":{}},{\"nodeType\":\"paragraph\",\"content\":[{\"nodeType\":\"text\",\"value\":\" \",\"marks\":[],\"data\":{}},{\"nodeType\":\"hyperlink\",\"data\":{\"uri\":\"https://cta-redirect.hubspot.com/cta/redirect/2495271/66db59a1-4d18-4841-a7cb-81ec416fbcc0\"},\"content\":[{\"nodeType\":\"embedded-entry-block\",\"content\":[],\"data\":{\"target\":{\"sys\":{\"type\":\"Link\",\"linkType\":\"Entry\",\"id\":\"56LKuhwunEc9UN5I6MV1Pp\"}}}}]},{\"nodeType\":\"text\",\"value\":\" hbspt.cta.load(2495271, '66db59a1-4d18-4841-a7cb-81ec416fbcc0', {});\",\"marks\":[],\"data\":{}}],\"data\":{}}]}}}}"
},
"requestId": "484b94c8b23d1bff24caf3f0b3c7dd89"
}
I'm also having this issue. Has anyone figured out what it means?
@seejamescode I think your issue is the unnecessary array brackets:
return await richTextFromMarkdown(replacedText, (node) => {
if (node.type === "image") {
- return [
- {
+ return {
nodeType: "embedded-entry-block",
content: [],
data: {
target: {
sys: {
type: "Link",
linkType: "Entry",
id: "56LKuhwunEc9UN5I6MV1Pp", // Real entry ID in my project
},
},
},
},
];
}
return node;
});
I am still having this issue today. Is the documentation outdated?
Iâm having a similar issue. I have an img inside an anchor tag inside a paragraph tag. This is valid html, but breaks the contentful rich text validity for whatâs allowed inside a paragraph nodeType
(apologies for necropost)
Came across this same exact issue posted by barrard (anchor with child image node) and created a workaround so I thought I'd post it here just in case anyone lands here in the future.
I am using Turndown to convert HTML â Markdown then feeding the Markdown into richTextFromMarkdown
.
This gives me an opportunity add a rule to Turndown to filter for anchors, check for nested images and return Markdown that's valid for richTextFromMarkdown
.
Your mileage may vary, but maybe this helps someone out there...
const formatAnchorsRule =
{
filter: ["a"],
replacement: (content, node, options) => {
const href = node.getAttribute("href");
const text = node.innerText;
const extracted = [];
for (const child of node.childNodes) {
if (child.tagName == "IMG") {
const src = child.getAttribute("src");
const alt = child.getAttribute("alt");
extracted.push(``);
}
}
if (href && text) {
return `[${text}](${href})\n\n${extracted.join("\n\n")}`;
} else {
// NOTE: Probably just a link around an image...
return `${extracted.join("\n\n")}`;
}
},
};
Then add the rule to Turndown in the normal way:
const html = "...";
const turndownService = new TurndownService();
turndownService.addRule("formatAnchorsRule", formatAnchorsRule);
const markdown = turndownService.turndown(html)
const richText = await richTextFromMarkdown(markdown)