Showcase: Script to save drag-drop sort order in views

UPDATE: You can replace the first part of this example case with the formula mentioned here: Showcase: Script to save drag-drop sort order in views - #2 by Chr1sG


Problem It Solves

In Fibery, manually drag-dropping entities in views updates their hidden Rank values, but these values are inaccessible to users. This script provides a workaround by:

  1. Fetching the hidden Rank values.
  2. Converting them into sequential Weight numbers that users can see and use.

Example use case

You want users to drag-drop a list of entities, but you don’t want them to manually have to update the weight or sorting value. For example in this case a list of AI Steps in a Pipeline.
With this script below, after manually drag-dropping, one button click saves the sort order.

Extended functionality

In addition to assigning Weight values for sort order tracking, in the example video you see two automations follow up with:

  • Use the Weight values to update a Prefix field.
  • Combine the Prefix with a Title to dynamically update the entity’s Name.

What This Script Does

This script organizes StepRun entries in a PipeRun by assigning a simple, sequential Weight based on their Rank. The Rank field in Fibery is a hidden, very large number that users cannot access or edit directly, so this script translates it into a manageable and clear order.


How It Works

  1. Fetch StepRuns:

    • Retrieves all StepRun entries linked to a PipeRun, including their hidden Rank values.
  2. Sort by Rank:

    • Sorts the StepRuns from smallest to largest Rank to determine their order.
  3. Assign Weights:

    • Assigns sequential Weight values (1, 2, 3, etc.) based on the sorted order.
  4. Update Fibery:

    • Saves the updated Weight values back to Fibery for each StepRun.

Example

Before the Script:

  • StepRuns have inaccessible Rank values like 1234567890123456, 1234567890123452, and 1234567890123458. Weight is blank or incorrect.

After the Script:

  • Sorted by Rank:
    • Rank 1234567890123452 → Weight 1
    • Rank 1234567890123456 → Weight 2
    • Rank 1234567890123458 → Weight 3

Additional Functionality:

This script also ensures that StepRun Names reflect their updated Weight:

  1. Weight to Prefix:

    • When a StepRun’s Weight is updated, it triggers an automation to convert the Weight into the Prefix (e.g., 1. for Weight 1).
  2. Prefix to Name:

    • When the Prefix is updated, it triggers another automation to update the Name by combining the Prefix with the Title (e.g., 1. Task Title).

Demonstration Video

https://tinyurl.com/2d988x33

Script (the basic functionality of setting Weight values)

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

// -----------------------------------
// DATABASE CONFIGURATION
// -----------------------------------
const PIPERUN_DB = {
    NAME: 'AI/PipeRun',     // Database name for PipeRun
    STEP_RUNS_FIELD: 'StepRuns' // Field in PipeRun linking to child StepRun entities
};

const STEPRUN_DB = {
    NAME: 'AI/StepRun',       // Database name for StepRun
    RANK_FIELD: 'Rank',       // Numeric Rank field
    WEIGHT_FIELD: 'Weight'    // Numeric field to store sequential numbering
};

// -----------------------------------
// MAIN FUNCTION
// -----------------------------------
async function updateStepRunWeights() {
    try {
        // Get the current PipeRun entity
        const currentEntity = args.currentEntities[0];
        if (!currentEntity) {
            console.error('No current PipeRun entity provided.');
            return;
        }

        // Fetch the PipeRun entity along with its StepRuns
        const pipeRun = await fibery.getEntityById(
            PIPERUN_DB.NAME,
            currentEntity.id,
            [PIPERUN_DB.STEP_RUNS_FIELD] // Retrieve StepRuns relation field
        );

        const stepRuns = pipeRun[PIPERUN_DB.STEP_RUNS_FIELD];
        if (!stepRuns || stepRuns.length === 0) {
            console.log(`No StepRuns found for PipeRun ID ${currentEntity.id}.`);
            return;
        }

        console.log(`Found ${stepRuns.length} StepRuns. Processing...`);

        // Array to store StepRuns for sorting
        const stepRunsData = [];

        // Retrieve Rank for sorting
        for (const stepRunRef of stepRuns) {
            const stepRun = await fibery.getEntityById(
                STEPRUN_DB.NAME,
                stepRunRef.Id,
                [STEPRUN_DB.RANK_FIELD]
            );

            stepRunsData.push({
                id: stepRun.Id,
                rank: stepRun[STEPRUN_DB.RANK_FIELD]
            });
        }

        // Sort StepRuns by Rank (ascending)
        stepRunsData.sort((a, b) => a.rank - b.rank);

        // Assign sequential Weight values
        for (let i = 0; i < stepRunsData.length; i++) {
            const stepRun = stepRunsData[i];
            const weightValue = i + 1; // Start with 1 and increment

            // Update the Weight field
            await fibery.updateEntity(STEPRUN_DB.NAME, stepRun.id, {
                [STEPRUN_DB.WEIGHT_FIELD]: weightValue
            });

            console.log(`Assigned Weight ${weightValue} to StepRun ID ${stepRun.id}`);
        }

        console.log(`All StepRuns for PipeRun ID ${currentEntity.id} have been updated.`);
    } catch (error) {
        console.error('Error in script:', error);
    }
}

// Execute the function
await updateStepRunWeights();

2 Likes

For reference, in some cases, a formula can be used to get the rank order of items (within a collection):

1 Like

That is an amazing solution @Chr1sG thank you! I will link it to the top of the topic.

A minor limitation I have found is that it returns always a float and not an integer, so the values are 1.0 2.0 etc.

The part of the formula responsible is likely this:

(Find(...) + 4) / 5

When you divide by 5, even if the result is mathematically a whole number (e.g., 10 / 5 = 2), the system interprets it as a floating-point number (e.g., 2.0).

I could not find a way to make it an integer, but its not a big deal, since the value will mostly be used for another automation (like populating a Weight field) so it will be hidden anyway.

Just choose zero decimal places when you create the formula

I tried but it does not allow me:

You have to do it at the time of creating the formula

1 Like

That worked, thank you!