Skip to content

Commit 58950b4

Browse files
authored
Merge pull request #640 from devforth/feature/AdminForth/1671/fix-error-text-i-am-not-deleti
Feature/admin forth/1671/fix error text i am not deleti
2 parents ad1e32f + 268c975 commit 58950b4

5 files changed

Lines changed: 88 additions & 8 deletions

File tree

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,53 @@ If your operation can be expressed more efficiently as a single batched query (e
114114
| `bulkConfirmationMessage` | `string` | Confirmation dialog text shown before the bulk action executes. |
115115
| `bulkSuccessMessage` | `string` | Success message shown after the bulk operation. Defaults to `"N out of M items processed successfully"`. |
116116

117+
## Standalone Bulk Actions
118+
119+
For operations that only apply to multiple selected records, use `options.bulkActions`. The built-in **Delete checked** action is a good reference.
120+
121+
```ts title="./resources/apartments.ts"
122+
{
123+
resourceId: 'aparts',
124+
options: {
125+
bulkActions: [
126+
{
127+
label: 'Send Invitation',
128+
icon: 'flowbite:envelope-solid',
129+
confirm: 'Are you sure you want to send invitation emails?',
130+
allowed: async ({ adminUser }) => adminUser.dbUser.role === 'superadmin',
131+
action: async ({ selectedIds }) => {
132+
await sendBulkInvitations(selectedIds);
133+
return { ok: true, successMessage: `Sent to ${selectedIds.length} users` };
134+
},
135+
},
136+
],
137+
},
138+
}
139+
```
140+
141+
### Confirmation dialog
142+
143+
Pass `confirm` to show a dialog before the action runs.
144+
145+
**String** — shown as the dialog title, no secondary message:
146+
147+
```ts
148+
confirm: 'Are you sure you want to send invitation emails?',
149+
```
150+
151+
**Object** — full control over the dialog. `{count}` in `message` is replaced with the number of selected records; `|` separates singular and plural forms:
152+
153+
```ts
154+
confirm: {
155+
title: 'Are you sure you want to archive the selected items?',
156+
message: 'Archiving {count} item. This process is irreversible. | Archiving {count} items. This process is irreversible.',
157+
yes: 'Archive',
158+
no: 'Cancel',
159+
},
160+
```
161+
162+
Omit `confirm` entirely to skip the dialog and run the action immediately.
163+
117164
### Access Control
118165

119166
You can control who can use an action through the `allowed` function. This function receives:

adminforth/modules/configValidator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ export default class ConfigValidator implements IConfigValidator {
250250
bulkActions.push({
251251
label: `Delete checked`,
252252
icon: 'flowbite:trash-bin-outline',
253-
confirm: 'Are you sure you want to delete selected items?',
253+
confirm: {
254+
title: 'Are you sure you want to delete selected items?',
255+
message: 'Deleting {count} item. This process is irreversible. | Deleting {count} items. This process is irreversible.',
256+
},
254257
allowed: async ({ resource, adminUser, allowedActions }) => { return allowedActions.delete },
255258
action: async ({ selectedIds, adminUser, response }) => {
256259
const connector = this.adminforth.connectors[res.dataSource];

adminforth/modules/restApi.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,15 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
11161116
translateRoutines[`bulkAction${i}`] = tr(action.label, `resource.${resource.resourceId}`);
11171117
}
11181118
if (action.confirm) {
1119-
translateRoutines[`bulkActionConfirm${i}`] = tr(action.confirm, `resource.${resource.resourceId}`);
1119+
if (typeof action.confirm === 'string') {
1120+
translateRoutines[`bulkActionConfirm${i}`] = tr(action.confirm, `resource.${resource.resourceId}`);
1121+
} else {
1122+
Object.entries(action.confirm).forEach(([key, value]: [string, string]) => {
1123+
if (value) {
1124+
translateRoutines[`bulkActionConfirm${i}_${key}`] = tr(value, `resource.${resource.resourceId}`);
1125+
}
1126+
});
1127+
}
11201128
}
11211129
});
11221130

@@ -1217,7 +1225,16 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
12171225
(action, i) => ({
12181226
...action,
12191227
label: action.label ? translated[`bulkAction${i}`] : action.label,
1220-
confirm: action.confirm ? translated[`bulkActionConfirm${i}`] : action.confirm,
1228+
confirm: !action.confirm ? action.confirm : (
1229+
typeof action.confirm === 'string'
1230+
? translated[`bulkActionConfirm${i}`]
1231+
: Object.fromEntries(
1232+
Object.entries(action.confirm).map(([key, value]) => [
1233+
key,
1234+
value ? translated[`bulkActionConfirm${i}_${key}`] : value,
1235+
])
1236+
)
1237+
),
12211238
})
12221239
),
12231240
actions: allowedCustomActions.map(({ bulkHandler, action: actionFn, ...rest }) => ({

adminforth/spa/src/utils/listUtils.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,14 @@ export async function startBulkAction(actionId: string, resource: AdminForthReso
6262
const { confirm, alert } = useAdminforth();
6363

6464
if (action?.confirm) {
65-
const confirmed = await confirm({
66-
title: action.confirm,
67-
message: t('Deleting {count} item. This process is irreversible. | Deleting {count} items. This process is irreversible.', { count: checkboxes.value.length }),
68-
});
65+
const confirmed = await confirm(
66+
typeof action.confirm === 'string'
67+
? { title: action.confirm }
68+
: {
69+
...action.confirm,
70+
message: action.confirm.message && t(action.confirm.message, { count: checkboxes.value.length }),
71+
}
72+
);
6973
if (!confirmed) {
7074
return;
7175
}

adminforth/types/Common.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,17 @@ export interface AdminForthBulkActionCommon {
139139

140140
/**
141141
* Confirmation message which will be displayed to user before action is executed.
142+
* String value is shown as the dialog title without any message under it.
143+
* Use object form to explicitly set a message (e.g. "This process is irreversible.")
144+
* and/or button labels. `{count}` placeholder in message will be replaced with the
145+
* number of selected records, pluralization is supported via `|` separator.
142146
*/
143-
confirm?: string,
147+
confirm?: string | {
148+
title?: string,
149+
message?: string,
150+
yes?: string,
151+
no?: string,
152+
},
144153

145154
/**
146155
* Success message which will be displayed to user after action is executed.

0 commit comments

Comments
 (0)