Skip to content

Commit b39f4aa

Browse files
authored
Merge pull request #645 from devforth/next
Next
2 parents 7ac6637 + 5cc3eba commit b39f4aa

30 files changed

Lines changed: 238 additions & 113 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1+
allowBuilds:
2+
'@prisma/engines': true
3+
adminforth: true
4+
better-sqlite3: true
5+
esbuild: true
6+
prisma: true
17
onlyBuiltDependencies:
28
- better-sqlite3

adminforth/commands/createApp/utils.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -483,17 +483,17 @@ async function installDependenciesPnpm(ctx, cwd) {
483483
const isWindows = process.platform === 'win32';
484484

485485
const nodeBinary = process.execPath;
486-
const npmPath = path.join(path.dirname(nodeBinary), isWindows ? 'pnpm.cmd' : 'pnpm');
486+
const pnpmPath = path.join(path.dirname(nodeBinary), isWindows ? 'pnpm.cmd' : 'pnpm');
487487
const customDir = ctx.customDir;
488488
if (isWindows) {
489489
const res = await Promise.all([
490-
await execAsync(`pnpm install`, { cwd, env: { PATH: process.env.PATH } }),
491-
await execAsync(`pnpm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
490+
execAsync(`pnpm install`, { cwd, env: { PATH: process.env.PATH } }),
491+
execAsync(`pnpm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
492492
]);
493493
} else {
494494
const res = await Promise.all([
495-
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
496-
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
495+
execAsync(`${nodeBinary} ${pnpmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
496+
execAsync(`${nodeBinary} ${pnpmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
497497
]);
498498
}
499499
}
@@ -506,13 +506,13 @@ async function installDependenciesNpm(ctx, cwd) {
506506
const customDir = ctx.customDir;
507507
if (isWindows) {
508508
const res = await Promise.all([
509-
await execAsync(`npm install`, { cwd, env: { PATH: process.env.PATH } }),
510-
await execAsync(`npm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
509+
execAsync(`npm install`, { cwd, env: { PATH: process.env.PATH } }),
510+
execAsync(`npm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
511511
]);
512512
} else {
513513
const res = await Promise.all([
514-
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
515-
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
514+
execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
515+
execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
516516
]);
517517
}
518518
}

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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,11 @@ 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+
},
257+
dangerous: true,
254258
allowed: async ({ resource, adminUser, allowedActions }) => { return allowedActions.delete },
255259
action: async ({ selectedIds, adminUser, response }) => {
256260
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/package-lock.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adminforth/package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22
"name": "adminforth",
33
"version": "1.6.2",
44
"description": "OpenSource Agent-Native forth-generation admin panel",
5-
"pnpm": {
6-
"overrides": {
7-
"shell-quote": "^1.8.4"
8-
}
9-
},
105
"keywords": [
116
"adminforth",
127
"agent",

adminforth/pnpm-lock.yaml

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adminforth/pnpm-workspace.yaml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
packages:
22
- spa
33

4-
ignoredBuiltDependencies:
5-
- '@parcel/watcher'
6-
- esbuild
7-
- vue-demi
8-
9-
onlyBuiltDependencies:
10-
- better-sqlite3
4+
allowBuilds:
5+
'@parcel/watcher': true
6+
better-sqlite3: true
7+
esbuild: true
8+
vue-demi: true

adminforth/spa/package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@
1212
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
1313
"i18n:extract": "echo {} > i18n-empty.json && vue-i18n-extract report --vueFiles \"./src/**/*.{js,vue,ts}\" --output ./i18n-messages.json --languageFiles \"i18n-empty.json\" --add"
1414
},
15-
"pnpm": {
16-
"overrides": {
17-
"shell-quote": "^1.8.4"
18-
}
19-
},
2015
"dependencies": {
2116
"@iconify-prerendered/vue-flag": "^0.28.1748584105",
2217
"@iconify-prerendered/vue-flowbite": "^0.28.1754899090",

0 commit comments

Comments
 (0)