Cloning an entity and re-mapping where it is mentioned

Sometimes, you might want to convert an entity of one type into an entity of another type.

Fibery does have native support for such a conversion
image
but any other entities in your workspace that mention the original item, will continue to point to the original and not the new clone.

To solve this, I have created a script which will re-map all the #mentions in entities so that they point to the newly created one.

The script is designed to work as the second action in an automation, where the first action is to create the clone of the new type.

In order for that to work, the types need to be related.
So for example. if you want to convert an Insight to a Feature, you might have a relation like this:
image
allowing that an Insight can be converted to a Feature (one-to-one).

A button automation then looks like this:

The first action (step 2) creates a new Feature (with the same Name as the Insight) and the second action (step 3) is the script that migrates all existing mentions.

Here’s how the script looks:

const fibery = context.getService('fibery');

// query the schema (so we can determine type ID of newly created entity)
const schema = await fibery.getSchema();
// get the type name for the newly created entity
const newType = schema.typeObjectsByName[args.steps[2].result.entities[0]['type']];
// get the type id for the newly created entity
const newTypeId = newType['id'];

// the automation may be running for a batch of entities, so loop through them
for (const [i, entity] of args.currentEntities.entries()) {
    // find all the places where the triggering entity is #mentioned
    const entityPlus = await fibery.getEntityById(entity.type, entity.id, ['References']);
    const references = entityPlus['References'];

    // for each place where it is mentioned
    for (const ref of references) {
        // get the various parameters of the mention
        const reference = await fibery.getEntityById('Collaboration~Documents/Reference', ref['Id'], ['Collaboration~Documents/FromEntityType', 'Collaboration~Documents/FromEntityId', 'Collaboration~Documents/FromEntityField', 'Collaboration~Documents/ToEntityType']);

        // if the mention is from a document, the field will be null, so ignore
        if (reference['Collaboration~Documents/FromEntityField']['Name'] !== null) {

            // get the rich text field name (of the referring entity)
            const rtfName = reference['Collaboration~Documents/FromEntityField']['Name'].split('/')[1];

            // get the rich text info from the referring entity
            const referringEntity = await fibery.getEntityById(reference['Collaboration~Documents/FromEntityType']['Name'], reference['Collaboration~Documents/FromEntityId'], [rtfName]);
            // get the original content
            const referringText = await fibery.getDocumentContent(referringEntity[rtfName]['Secret'], 'md');

            // create a string representing a mention of the triggering entity in the form [[#^databasseId/entityId]]
            const mentionToReplace = '[[#^' + reference['Collaboration~Documents/ToEntityType']['Id'] + '\/' + entity.id + ']]';

            // create a string representing a mention of the newly created entity
            const newEntityId = args.steps[2].result.entities[i]['Id'];
            const newMention = '[[#^' + newTypeId + '\/' + newEntityId + ']]';

            // use find and replace to update the text, and overwrite the original text in the referring entity
            const modifiedText = referringText.replace(mentionToReplace, newMention);
            await fibery.setDocumentContent(referringEntity[rtfName]['Secret'], modifiedText, 'md');
        }
    }
}

and here’s what this looks like in practice:
firefox_pzjIeBX1jQ

There are a couple of things to note:

  • It transfers only mentions of the original within rich text fields of other entities, i.e. mentions in documents are not transferred.
  • It utilises find and replace via markdown, so if the referring entities have formatting that is not supported by markdown, this will be lost :frowning: (the code could be modified to use getDocumentContent and setDocumentContent with html formatting, but the representation of the mentions would need to be changed accordingly)

Thoughts/feedback gratefully received.

2 Likes