Skip to content

Commit 707b44e

Browse files
committed
fix: update docs for actions
1 parent 3e5d1a2 commit 707b44e

File tree

2 files changed

+38
-175
lines changed

2 files changed

+38
-175
lines changed

adminforth/documentation/docs/tutorial/03-Customization/09-Actions.md

Lines changed: 17 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ Here's how to add a custom action:
3535
listThreeDotsMenu: true, // Show in three dots menu in list view
3636
showButton: true, // Show as a button
3737
showThreeDotsMenu: true, // Show in three-dots menu
38-
bulkButton: true
3938
}
4039
}
4140
]
@@ -51,11 +50,11 @@ Here's how to add a custom action:
5150
- `action`: Handler function that executes when action is triggered for a **single** record
5251
- `bulkHandler`: Handler function that executes when the action is triggered for **multiple** records at once (see [Bulk button with bulkHandler](#bulk-button-with-bulkhandler))
5352
- `showIn`: Controls where the action appears
54-
- `list`: whether to show in list view
55-
- `listThreeDotsMenu`: whether to show in three dots menu in the list view
56-
- `showButton`: whether to show as a button on show view
57-
- `showThreeDotsMenu`: when to show in the three-dots menu of show view
58-
- `bulkButton`: whether to show as a bulk-selection button in the list view
53+
- `list`: whether to show as an icon button per row in the list view
54+
- `listThreeDotsMenu`: whether to show in the three-dots menu per row in the list view
55+
- `showButton`: whether to show as a button on the show view
56+
- `showThreeDotsMenu`: whether to show in the three-dots menu of the show view
57+
- `bulkButton`: whether to show as a bulk action button when rows are selected
5958

6059
### Bulk button with `action`
6160

@@ -100,6 +99,15 @@ If your operation can be expressed more efficiently as a single batched query (e
10099

101100
> ☝️ When both `action` and `bulkHandler` are defined, AdminForth uses `bulkHandler` for bulk operations and `action` for single-record operations. When only `action` is defined and `bulkButton` is enabled, AdminForth falls back to `Promise.all` over individual `action` calls.
102101
102+
### Bulk-specific options
103+
104+
| Option | Type | Description |
105+
|---|---|---|
106+
| `showIn.bulkButton` | `boolean` | Show as a bulk action button in the list toolbar. |
107+
| `bulkHandler` | `async ({ recordIds, adminUser, adminforth, resource, response, tr }) => { ok, error?, message? }` | Called with all selected IDs at once. Falls back to calling `action` per record in parallel if omitted. |
108+
| `bulkConfirmationMessage` | `string` | Confirmation dialog text shown before the bulk action executes. |
109+
| `bulkSuccessMessage` | `string` | Success message shown after the bulk operation. Defaults to `"N out of M items processed successfully"`. |
110+
103111
### Access Control
104112

105113
You can control who can use an action through the `allowed` function. This function receives:
@@ -130,46 +138,11 @@ The `allowed` function receives:
130138
Return:
131139
- `true` to allow access
132140
- `false` to deny access
133-
- A string with an error message to explain why access was denied
141+
- A string with an error message to explain why access was denied — e.g. `return 'Only superadmins can perform this action'`
134142

135143
Here is how it looks:
136144
![alt text](<Single record actions.png>)
137145

138-
139-
You might want to allow only certain users to perform your custom bulk action.
140-
141-
To implement this limitation use `allowed`:
142-
143-
If you want to prohibit the use of bulk action for user, you can do it this way:
144-
145-
```ts title="./resources/apartments.ts"
146-
import { admin } from '../index';
147-
148-
....
149-
150-
bulkActions: [
151-
{
152-
label: 'Mark as listed',
153-
icon: 'flowbite:eye-solid',
154-
allowed: async ({ resource, adminUser, selectedIds }) => {
155-
if (adminUser.dbUser.role !== 'superadmin') {
156-
return false;
157-
}
158-
return true;
159-
},
160-
confirm: 'Are you sure you want to mark all selected apartments as listed?',
161-
action: async ({ resource, selectedIds, adminUser, tr }) => {
162-
const stmt = admin.resource('aparts').dataConnector.client.prepare(
163-
`UPDATE apartments SET listed = 1 WHERE id IN (${selectedIds.map(() => '?').join(',')})`
164-
);
165-
await stmt.run(...selectedIds);
166-
167-
return { ok: true, message: tr(`Marked ${selectedIds.length} apartments as listed`) };
168-
},
169-
}
170-
],
171-
```
172-
173146
### Action URL
174147

175148
Instead of defining an `action` handler, you can specify a `url` that the user will be redirected to when clicking the action button:
@@ -192,7 +165,7 @@ The URL can be:
192165
- A relative path within your admin panel (starting with '/')
193166
- An absolute URL (starting with 'http://' or 'https://')
194167

195-
To open the URL in a new tab, add `?target=_blank` to the URL:
168+
To open the URL in a new tab, append `target=_blank` as a query parameter. If the URL already has query parameters, use `&target=_blank`; otherwise use `?target=_blank`:
196169

197170
```ts
198171
{
@@ -208,118 +181,12 @@ To open the URL in a new tab, add `?target=_blank` to the URL:
208181

209182
> ☝️ Note: You cannot specify both `action` and `url` for the same action - only one should be used.
210183
211-
212-
213-
## Custom bulk actions
214-
215-
You might need to give admin users a feature to perform same action on multiple records at once.
216-
217-
For example you might want allow setting `listed` field to `false` for multiple apartment records at once.
218-
219-
AdminForth by default provides a checkbox in first column of the list view for this purposes.
220-
221-
By default AdminForth provides only one bulk action `delete` which allows to delete multiple records at once
222-
(if deletion for records available by [resource.options.allowedActions](/docs/api/Back/interfaces/ResourceOptions/#allowedactions))
223-
224-
To add custom bulk action quickly:
225-
226-
```ts title="./resources/apartments.ts"
227-
//diff-add
228-
import { AdminUser } from 'adminforth';
229-
//diff-add
230-
import { admin } from '../index';
231-
232-
{
233-
...
234-
resourceId: 'aparts',
235-
...
236-
options: {
237-
//diff-add
238-
bulkActions: [
239-
//diff-add
240-
{
241-
//diff-add
242-
label: 'Mark as listed',
243-
//diff-add
244-
icon: 'flowbite:eye-solid',
245-
//diff-add
246-
// if optional `confirm` is provided, user will be asked to confirm action
247-
//diff-add
248-
confirm: 'Are you sure you want to mark all selected apartments as listed?',
249-
//diff-add
250-
action: async function ({selectedIds, adminUser }: {selectedIds: any[], adminUser: AdminUser }) {
251-
//diff-add
252-
const stmt = admin.resource('aparts').dataConnector.client.prepare(`UPDATE apartments SET listed = 1 WHERE id IN (${selectedIds.map(() => '?').join(',')})`);
253-
//diff-add
254-
await stmt.run(...selectedIds);
255-
//diff-add
256-
return { ok: true, successMessage: `Marked ${selectedIds.length} apartments as listed` };
257-
//diff-add
258-
},
259-
//diff-add
260-
}
261-
//diff-add
262-
],
263-
}
264-
}
265-
```
266-
267-
Action code is called on the server side only and allowed to only authorized users.
268-
269-
> ☝️ AdminForth provides no way to update the data, it is your responsibility to manage the data by selectedIds. You can use any ORM system
270-
> or write raw queries to update the data.
271-
272-
> ☝️ You can use `adminUser` object to check whether user is allowed to perform bulk action
273-
274-
275-
> Action response can return optional `successMessage` property which will be shown to user after action is performed. If this property is not provided, no messages will be shown to user.
276-
277-
Here is how it looks:
278-
![alt text](<Custom bulk actions.png>)
279-
280-
281-
## Limiting access to bulk actions
282-
283-
You might want to allow only certain users to perform your custom bulk action.
284-
285-
To implement this limitation use `allowed`:
286-
287-
If you want to prohibit the use of bulk action for user, you can do it this way:
288-
289-
```ts title="./resources/apartments.ts"
290-
bulkActions: [
291-
{
292-
label: 'Mark as listed',
293-
icon: 'flowbite:eye-solid',
294-
//diff-add
295-
allowed: async ({ resource, adminUser, selectedIds }) => {
296-
//diff-add
297-
if (adminUser.dbUser.role !== 'superadmin') {
298-
//diff-add
299-
return false;
300-
//diff-add
301-
}
302-
//diff-add
303-
return true;
304-
//diff-add
305-
},
306-
// if optional `confirm` is provided, user will be asked to confirm action
307-
confirm: 'Are you sure you want to mark all selected apartments as listed?',
308-
action: async function ({selectedIds, adminUser }: {selectedIds: any[], adminUser: AdminUser }, allow) {
309-
const stmt = admin.resource('aparts').dataConnector.client.prepare(`UPDATE apartments SET listed = 1 WHERE id IN (${selectedIds.map(() => '?').join(',')}`);
310-
await stmt.run(...selectedIds);
311-
return { ok: true, error: false, successMessage: `Marked ${selectedIds.length} apartments as listed` };
312-
},
313-
}
314-
],
315-
```
316-
317184
## Custom Component
318185

319186
If you want to style an action's button/icon without changing its behavior, attach a custom UI wrapper via `customComponent`.
320187
The file points to your SFC in the custom folder (alias `@@/`), and `meta` lets you pass lightweight styling options (e.g., border color, radius).
321188

322-
Below we wrap a Mark as listed action (see the original example in [Custom bulk actions](#custom-bulk-actions)).
189+
Below we wrap a "Mark as listed" action.
323190

324191
```ts title="./resources/apartments.ts"
325192
{

adminforth/documentation/docs/tutorial/08-Plugins/10-i18n.md

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -542,37 +542,33 @@ Pluralisation rules are the same as in frontend
542542
543543
## Translating messages within bulk action
544544
545-
Label and confirm strings of bulk actions are already translated by AdminForth, but
546-
`succesMessage` returned by action function should be translated manually because of the dynamic nature of the message.
545+
The `label`, `bulkConfirmationMessage`, and `bulkSuccessMessage` fields of bulk actions are static strings and are translated automatically by AdminForth. However, a **dynamic** success message returned from inside `bulkHandler` must be translated manually using the `tr` helper that is injected into the handler.
547546
548-
Let's rework the bulk action from [bulkActions example](/docs/tutorial/Customization/Actions/#custom-bulk-actions) to use translations:
547+
Let's rework the bulk action from the [Actions example](/docs/tutorial/Customization/Actions/#dedicated-bulk-handler) to use translations:
549548
550549
```ts title="./resources/apartments.ts"
551-
import { AdminUser } from 'adminforth';
552-
import { admin } from '../index';
553-
554550
{
555-
...
556-
resourceId: 'aparts',
557-
...
558-
options: {
559-
bulkActions: [
560-
{
561-
label: 'Mark as listed',
562-
icon: 'flowbite:eye-solid',
563-
// if optional `confirm` is provided, user will be asked to confirm action
564-
confirm: 'Are you sure you want to mark all selected apartments as listed?',
565-
action: function ({selectedIds, adminUser }: {selectedIds: any[], adminUser: AdminUser }) {
566-
const stmt = admin.resource('aparts').dataConnector.client.prepare(`UPDATE apartments SET listed = 1 WHERE id IN (${selectedIds.map(() => '?').join(',')})`);
567-
stmt.run(...selectedIds);
551+
name: 'Mark as listed',
552+
icon: 'flowbite:eye-solid',
553+
showIn: {
554+
showThreeDotsMenu: true,
555+
bulkButton: true,
556+
},
557+
action: async ({ recordId, adminforth }) => {
558+
await adminforth.resource('aparts').update(recordId, { listed: true });
559+
return { ok: true, successMessage: 'Marked as listed' };
560+
},
561+
bulkHandler: async ({ recordIds, tr }) => {
562+
const db = adminforth.resource('aparts').dataConnector.client;
563+
db.prepare(
564+
`UPDATE aparts SET listed = 1 WHERE id IN (${recordIds.map(() => '?').join(',')})`
565+
).run(...recordIds);
568566
//diff-remove
569-
return { ok: true, error: false, successMessage: `Marked ${selectedIds.length} apartments as listed` };
567+
return { ok: true, successMessage: `Marked ${recordIds.length} apartments as listed` };
570568
//diff-add
571-
return { ok: true, error: false, successMessage: await tr('Marked {count} apartments as listed', 'apartments', { count: selectedIds.length }) };
572-
},
573-
}
574-
],
575-
}
569+
return { ok: true, successMessage: await tr('Marked {count} apartments as listed', 'apartments', { count: recordIds.length }) };
570+
},
571+
bulkConfirmationMessage: 'Are you sure you want to mark selected apartments as listed?',
576572
}
577573
```
578574

0 commit comments

Comments
 (0)