Embedding entities - teasers and full size

Here is a working script that turns Mention links into embedded teaser displays or embedded ful size entity displays. Note: these are snapshots, not live mirrored embeds. But they can be included and updated with buttons.

chrome_jGYvThrVCM

Explanation

  1. nitialization: Sets up the Fibery service, defines constants for the type of page (yoPageType), a mapping of database IDs to their corresponding types, character limits for text truncation, and a base URL for constructing “Read more” links.
  2. Main Function - enrichDescriptionWithEntityDataV2_2:
  • Retrieves the current entity’s description.
  • If a description exists, it fetches the document content and processes it for specific patterns ([[#^databaseId/entityId]]).
  • Updates the document content with the enriched description.
  1. Pattern Processing - processTextPatternsV2_2:
  • Searches the document content for patterns that represent links to other entities within the same Fibery workspace.
  • For each pattern found, it fetches the corresponding entity’s description and public ID.
  • Adjusts header levels within the teaser text from #, ##, or ### to #### to maintain consistency and avoid hierarchy conflicts.
  • Truncates the fetched description to a specified character limit if necessary and removes any leading empty lines.
  • Constructs a “Read more” link if the description is truncated.
  • Embeds the modified content into the original document, replacing the pattern with a blockquote containing the teaser (the entity’s adjusted description and optionally the “Read more” link).
  1. Description Truncation - truncateDescriptionV2_2:
  • Truncates the entity description to a predefined character limit, ensuring the text ends on a full word and appending an ellipsis to indicate truncation.
  1. Execution:
  • The script executes the main function enrichDescriptionWithEntityDataV2_2 to start the process of enriching document descriptions based on the specified patterns.

Script - Only the teasers button

(Replace SpaceName/DatabaseName with your ones, as well as the const databaseIdMap Database UUID)

const fibery = context.getService('fibery');
const yoPageType = 'SpaceName/DatabaseName'; 
const databaseIdMap = { '8ff09230-0883-11ee-a2e3-dd72e97a05a2': 'SpaceName/DatabaseName' };
const characterLimit = 400;
const baseUrl = 'https://cce.fibery.io/SpaceName/DatabaseName/';

async function enrichDescriptionWithEntityDataV2_2() {
    try {
        const currentEntity = args.currentEntities[0];
        const yoPageEntity = await fibery.getEntityById(yoPageType, currentEntity.id, ['Description']);
        if (yoPageEntity.Description && yoPageEntity.Description.Secret) {
            let descriptionContent = await fibery.getDocumentContent(yoPageEntity.Description.Secret, 'md');
            descriptionContent = await processTextPatternsV2_2(descriptionContent);
            await fibery.setDocumentContent(yoPageEntity.Description.Secret, descriptionContent, 'md');
        }
    } catch (error) {
        console.error('Error in script:', error);
    }
}

async function processTextPatternsV2_2(descriptionContent) {
    const regex = /(?:^|\n)\[\[#\^(.*?)\/(.*?)\]\](?=\n|$)/g;
    let match;
    let modifiedContent = descriptionContent;
    let offsetAdjustment = 0;

    while ((match = regex.exec(descriptionContent)) !== null) {
        const fullMatch = match[0].trim(); // Trim to remove any leading newline from the match
        const databaseId = match[1].trim(), entityId = match[2].trim();

        // Calculate the actual index of the match considering previous adjustments
        const actualMatchIndex = match.index + offsetAdjustment + (match[0].startsWith('\n') ? 1 : 0); // Adjust index if match started with a newline

        if (!databaseIdMap[databaseId]) {
            console.error(`Database ID mapping not found for ${databaseId}.`);
            continue;
        }

        try {
            const fiberyTypeName = databaseIdMap[databaseId];
            const entity = await fibery.getEntityById(fiberyTypeName, entityId, ['Description', 'Public Id']);
            if (entity.Description && entity.Description.Secret) {
                let entityDescriptionContent = await fibery.getDocumentContent(entity.Description.Secret, 'md');

                // Convert headers #, ##, ### to #### in the teaser text
                entityDescriptionContent = entityDescriptionContent.replace(/^(>?\s*)(#{1,3})\s/gm, '$1#### ');

                const { text: truncatedText, isTruncated } = truncateDescriptionV2_2(entityDescriptionContent, characterLimit);
                entityDescriptionContent = truncatedText.replace(/^\s*[\r\n]/gm, ''); // Remove empty lines
                const readMoreLink = isTruncated && entity['Public Id'] ? ` [Read more](${baseUrl}${entity['Public Id']})` : '';
                const headerText = `## ${fullMatch}`;
                const contentToBeQuoted = `${headerText}\n${entityDescriptionContent}${readMoreLink}\n`.trim();
                const quotedBlock = contentToBeQuoted.split('\n').map(line => `> ${line}`).join('\n');

                modifiedContent = modifiedContent.slice(0, actualMatchIndex) + quotedBlock + modifiedContent.slice(actualMatchIndex + fullMatch.length);
                offsetAdjustment += quotedBlock.length - fullMatch.length;
            }
        } catch (error) {
            console.error(`Error fetching entity or entity Description for ID ${entityId}:`, error);
        }
    }
    return modifiedContent;
}

function truncateDescriptionV2_2(description, maxLength) {
    if (description.length <= maxLength) return { text: description, isTruncated: false };
    const truncated = description.substr(0, description.lastIndexOf(' ', maxLength)) + ' ...';
    return { text: truncated, isTruncated: true };
}

await enrichDescriptionWithEntityDataV2_2();

5 Likes

Hi,

Tx for sharing this.

1 Like

Wow, this is pretty cool! I have definitely wanted the option to embed individual entities in another entity or page, either as a full embed, or as a “card” or something more expansive/visual than the existing (but great) Reference capability. I’m not sure I’ll use this workaround, but I like that it points the way to this kind of functionality, which will hopefully become native one day. I envision something similar to how URL embeds are treated currently, with the option to have the current in-line behavior, a “Card” view, perhaps an “Excerpt” view as you have created here, and the “full” embed as well.

3 Likes