Code examples
Ready-to-adapt recipes for the most common needs. In these examples, models is the object exported by your database.js file.
Actions
Section titled “Actions”Update several records at once (Sequelize)
Section titled “Update several records at once (Sequelize)”whereClause matches the selected records, even with composite primary keys.
{ label: 'Mark as shipped', code: 'mark_as_shipped', target: ['item', 'bulk'], filter: order => order.status === 'paid', handler: async ({ whereClause }, success, error) => { try { await models.orders.update({ status: 'shipped', shipped_at: new Date() }, { where: whereClause }); success({ message: 'Orders marked as shipped', reload: true }); } catch (e) { error({ message: e.message }); } }}Call your own business logic (Mongoose)
Section titled “Call your own business logic (Mongoose)”Reuse the functions of your app, so that the back-office follows the same rules as your product.
const { sendWelcomeEmail } = require('../services/emails');
{ label: 'Resend the welcome email', code: 'resend_welcome_email', target: ['item', 'bulk'], handler: async ({ ids }, success, error) => { const users = await models.users.find({ _id: { $in: ids } }); await Promise.all(users.map(user => sendWelcomeEmail(user))); success({ message: `${users.length} email(s) sent` }); }}Open an external page
Section titled “Open an external page”{ label: 'Open in Stripe', code: 'open_in_stripe', target: 'item', filter: customer => !!customer.stripe_id, handler: async ({ ids }, success) => { const customer = await models.customers.findById(ids[0]); success({ action: 'open_tab', link: `https://dashboard.stripe.com/customers/${customer.stripe_id}` }); }}Generate a file
Section titled “Generate a file”{ label: 'Export the order lines', code: 'export_order_lines', target: 'bulk', handler: async ({ ids }, success) => { const lines = await models.order_lines.find({ order_id: { $in: ids } }).lean(); const csv = ['order_id,product,quantity,price'] .concat(lines.map(l => [l.order_id, l.product, l.quantity, l.price].join(','))) .join('\n');
success({ action: 'download', data: csv, filename: 'order-lines.csv' }); }}Ask for a confirmation value
Section titled “Ask for a confirmation value”{ label: 'Ban the user', code: 'ban_user', target: 'item', handler: async ({ ids, data }, success, error) => { if (!data || !data.reason) { return error({ form: { title: 'Why do you ban this user?', submitLabel: 'Ban', fields: [{ label: 'Reason', name: 'reason', type: 'text', required: true }] } }); }
await models.users.updateOne({ _id: ids[0] }, { banned: true, ban_reason: data.reason }); success({ message: 'User banned', reload: true }); }}Custom charts
Section titled “Custom charts”Single value: revenue of the current month (Sequelize)
Section titled “Single value: revenue of the current month (Sequelize)”const { Op } = require('sequelize');
{ code: 'revenue_this_month', label: 'Revenue this month', handler: async (data, success) => { const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1); const revenue = await models.orders.sum('amount', { where: { status: 'paid', created_at: { [Op.gte]: startOfMonth } } }); success({ data: revenue || 0 }); }}Line: signups per month (Mongoose)
Section titled “Line: signups per month (Mongoose)”{ code: 'signups_per_month', label: 'Signups per month', handler: async (data, success) => { const rows = await models.users.aggregate([ { $match: { createdAt: { $gte: new Date(Date.now() - 365 * 24 * 3600 * 1000) } } }, { $group: { _id: { $dateToString: { format: '%Y-%m', date: '$createdAt' } }, count: { $sum: 1 } } }, { $sort: { _id: 1 } } ]);
success({ config: { xaxis: [{ dataKey: 'month' }], yaxis: [{ dataKey: 'signups', name: 'Signups' }] }, data: rows.map(row => ({ month: row._id, signups: row.count })) }); }}Ranking: best customers (Sequelize)
Section titled “Ranking: best customers (Sequelize)”{ code: 'best_customers', label: 'Best customers', handler: async (data, success) => { const rows = await models.orders.findAll({ attributes: ['customer_email', [models.orders.sequelize.fn('SUM', models.orders.sequelize.col('amount')), 'total']], where: { status: 'paid' }, group: ['customer_email'], order: [[models.orders.sequelize.literal('total'), 'DESC']], limit: 10, raw: true });
success({ data: rows.map(row => ({ key: row.customer_email, value: Number(row.total) })) }); }}Segments
Section titled “Segments”Records of the last 7 days
Section titled “Records of the last 7 days”{ label: 'Last 7 days', code: 'last_7_days', get query() { return { createdAt: { $gte: new Date(Date.now() - 7 * 24 * 3600 * 1000) } }; }}Records matching several conditions (Sequelize)
Section titled “Records matching several conditions (Sequelize)”const { Op } = require('sequelize');
{ label: 'Trials ending soon', code: 'trials_ending_soon', get query() { const in3Days = new Date(Date.now() + 3 * 24 * 3600 * 1000); return { plan: 'trial', trial_ends_at: { [Op.between]: [new Date(), in3Days] } }; }}