Skip to content

Actions

Actions run your own business logic on one or several records, from the back-office: validate a KYC, refund an order, resend an email, generate an invoice… They are declared in the actions array of a model.

Out of the box, every model has a Delete action and an Export CSV action on selections. Your actions are added next to them.

{
slug: 'users',
model: models.users,
actions: [
{
label: 'Validate KYC',
code: 'validate_kyc',
target: ['item', 'bulk'],
filter: user => user.kyc_status === 'pending',
handler: async ({ ids }, success, error) => {
const users = await models.users.find({ _id: { $in: ids } });
if (users.some(user => !user.id_document)) {
return error({ message: 'Some users did not upload their ID document' });
}
await models.users.updateMany({ _id: { $in: ids } }, { kyc_status: 'validated' });
success({ message: `${ids.length} user(s) validated`, reload: true });
}
}
]
}
Property Required Description
label Yes The name of the action in the back-office.
code Yes A unique identifier. It is used in the activity log and in team permissions: avoid changing it once in use.
target Yes Where the action is available: 'item' (on the item page), 'bulk' (on a selection in the list), or ['item', 'bulk'].
filter No A function receiving a record and returning false to hide the action for it. On a selection, the action is shown only if all the selected records pass the filter.
handler Yes The function executed when the action is triggered.
handler: async (attrs, success, error) => { ... }

attrs contains:

Property Description
ids The IDs of the selected records.
data The values of the form filled by the user, if you asked for one (see below).
whereClause A ready-to-use query matching the selected records: Model.update(values, { where: whereClause }) with Sequelize, Model.updateMany(whereClause, values) with Mongoose. Handy with composite primary keys.

Call success() when the action succeeded, or error() when it failed. Exactly one of them must be called.

// Show a message
success({ message: 'The user has been updated' });
// Reload the data of the page
success({ reload: true });
// Open a link in a new tab
success({ action: 'open_tab', link: 'https://dashboard.stripe.com/payments/py_123' });
// Download a generated file (text content, such as CSV)
success({ action: 'download', data: csvContent, filename: 'report.csv' });
// Show an error message
error({ message: 'This user cannot be updated' });

When an action needs input from the user, call error() with a form. The back-office displays it, and runs the action again with the values in attrs.data:

handler: async ({ ids, data }, success, error) => {
if (!data || !data.amount) {
return error({
form: {
title: 'Refund the order',
submitLabel: 'Refund',
fields: [
{ label: 'Amount', name: 'amount', type: 'number', isFloat: true, required: true },
{
label: 'Reason',
name: 'reason',
type: 'select',
options: [
{ label: 'Damaged product', value: 'damaged' },
{ label: 'Late delivery', value: 'late' }
]
},
{ label: 'Refund date', name: 'refund_date', type: 'date' }
]
}
});
}
await refundOrder(ids[0], data.amount, data.reason);
success({ message: 'Refund done', reload: true });
}

Available field types: text, number (add isFloat: true for decimals), date and select (with options). Each field accepts label, name, required and defaultValue.

Admins and developers can use every action. For users, choose which actions each team can use in its permissions. Every execution is recorded in the activity log.