[✔️ DONE] Duplicate a record

Hi - it would be useful if there were a way to easily duplicate a record.

One use case is, if you make a “template” record somewhere, with text you want to re-use frequently, you might want to easily copy-paste that.

Is a button the way to go for this?

4 Likes

Hopefully, since multi-select is a feature, this is not far behind.

1 Like

Would love to see some templating-type functionality alongside this as well!

1 Like

+1 ! We would love to implement “processes made of checklists” in Fibery, to link them to actual tasks & projects, but without the “duplicate” feature this does not really make sense. Any visibility on when this would be implemented ? Thanks !

Hi!
So, do you need to duplicate a record or more smth like a recurring process? Lik Projects with repetitive Tasks and etc.

1 Like

Hi, in our case cloning records will be enough, we will put checklists directly into records, with 1 record = 1 process

Then I can suggest you add a Duplicate a record button :slight_smile:
Here is the code you can use

const fibery = context.getService('fibery');
const schema = await fibery.getSchema();

await Promise.all(args.currentEntities.map(async (template) => {
    const type = template.type;

    const newEntityTemplate = schema.typeObjectsByName[type].fieldObjects
        .reduce((result, fieldObject) => {
            if (fieldObject.type === "fibery/Button" || fieldObject.type === "Collaboration~Documents/Document" || fieldObject.isReadOnly) {
                return result;
            } else if (fieldObject.typeObject.isPrimitive) {
                return { ...result, [fieldObject.title]: template[fieldObject.title] };
            } else if (fieldObject.typeObject.isEnum && fieldObject.cardinality === ":cardinality/many-to-one") {
                // Workaround for issue with setting null to enums
                const enumSetter = template[fieldObject.title].Name ? { [fieldObject.title]: template[fieldObject.title].Name } : {};
                return { ...result, ...enumSetter };
            } else if (fieldObject.typeObject.isPrimitive === false && fieldObject.cardinality === ":cardinality/many-to-one") {
                return { ...result, [fieldObject.title]: template[fieldObject.title].Id };
            } else {
                return result;
            }
        }, {});

    console.log(newEntityTemplate);
    // create new entity with some name
    // see https://api.fibery.io/#script
    const [{ result: newEntity }] = await fibery.createEntity(
        type,
        {
            ...newEntityTemplate,
            Rank: template.Rank + 10000,
            Name: `${template.Name} Copy`
        });

    // Copy multiselect enums
    const multiSelectEnumFields = schema.typeObjectsByName[type].fieldObjects
        .filter((fieldObject) => fieldObject.typeObject.isEnum && fieldObject.cardinality === ":cardinality/many-to-many" && fieldObject.isReadOnly === false);
    for (const multiSelectEnumField of multiSelectEnumFields) {
        if (template[multiSelectEnumField.title]) {
            await Promise.all(template[multiSelectEnumField.title].map((val) => fibery.addCollectionItem(type, newEntity["fibery/id"], multiSelectEnumField.name, val.Id)));
        }
    }

    // copy assignees
    const assigneesField = schema.typeObjectsByName[type].fieldObjects
        .find((fieldObject) => fieldObject.name === "assignments/assignees");
    if (assigneesField && template[assigneesField.title]) {
        await Promise.all(template[assigneesField.title].map((val) => fibery.addCollectionItem(type, newEntity["fibery/id"], assigneesField.name, val.Id)));
    }

    //At the moment we cannot set rich text fields using 'createEntity' api, so we set it using 'setDocumentContent' method
    const richTextFields = schema.typeObjectsByName[type].fieldObjects.filter(f => f.type === "Collaboration~Documents/Document");
    for (const richTextField of richTextFields) {
        const content = await fibery.getDocumentContent(template[richTextField.title].Secret, "json");
        if (!content) {
            continue;
        }
        // take deep details of newly created entity (mainly interested in description Secret)
        // see https://api.fibery.io/#get-entities
        // NOTE: unfortunately #script api doesn't support such deep query at the moment
        //       getEntity(id, ["id", ["Description", "Secret"]]) would make things much simplier
        const newEntityDetails = await fibery.executeSingleCommand(
            {
                "command": "fibery.entity/query",
                "args": {
                    "query": {
                        "q/from": type,
                        "q/select": {
                            "Id": "fibery/id",
                            "RichTextField": {
                                "Id": [richTextField.name, "fibery/id"],
                                "Secret": [richTextField.name, "Collaboration~Documents/secret"]
                            },
                        },
                        "q/where": ["=", ["fibery/id"], "$id"],
                        "q/limit": 1
                    },
                    "params": { "$id": newEntity["fibery/id"] }
                }
            });

        // fail if details object not found
        if (!newEntityDetails) {
            throw new Error(`Request for new entity details is failed`);
        }

        const newSecret = newEntityDetails[0].RichTextField.Secret;
        const result = await fibery.setDocumentContent(newSecret, content, 'json');
    }
}));
2 Likes

Hi @Polina_Zenevich, I have been diving deep since starting with Fibery a few weeks ago specifically into the action buttons requiring me to start using Javascript.

I have been trying to achieve the following by modify the record duplication example:
When the script is executed I want to retrieve the information in the Name field (I think the name field acts as the primary key in the table) and generate a new entity in a different template (another type in another app) using the retrieved Name field information as the name newly created entity.

I found the record duplication script a the best fit to start with and are trying to modify it to achieve the above.

I do not know if you are the correct person to ask.

Hi @NicolSpies,

Is Name the only Field you’d like to copy or are there more?
I’m trying to pick the most relevant example from our library or to write a new one.

Also, it would be great if you share the scenario behind the button: what the Types are and when users trigger the button. This would help us to organize these buttons and code snippets so other creators could find them in the future.

Cheers!

1 Like

Hi Anton,
The reason why I only ask about the Name field is to automate the following:

  1. I create two types in the same or different apps.
  2. I create a relationship between the two types and select to automatically linked records between the two types based on the Name fields being equal between the two records.
  3. When I now manually add a record to the second type with lookup fields to a record in the first type, the fields will stay blank until I enter the first type record name in the second type record name. Then the automatic linking applies and the look up fields in the second record are populated with data from the first type. This is a manual and long process.
  4. If I add a scripted button doing the above, it can add the record to the second type, copy the name of the current record in the first type across so that the automatic linking is activated and the lookup information are updated.
  5. It would also be nice to check in the records of the second type if a record with the specific name already exists. If it does, the script exists on order not to create a duplicate named linked record in the second type.
  6. I would also add a check box field that it set true when the code is executed to show in the first type if the action button script has been executed for the specific record to generate the linked record in the second type already.
  7. From the code I would then be able to see how it is done and modify the script for any other field to be used automatic rule based linking of records.
  8. I suppose this process implies the created by and Creation Date fields also needs to be copied with the name field.
  9. If I extend this script, I can let the action button script create records in multiple related type tables.

I hope this makes sense.

@antoniokov, I assume my explanation was clear :grinning:

Implemented recently

3 Likes