Skip to content

Commit aac8f32

Browse files
committed
Merge branch 'main' of github.com:devforth/adminforth
2 parents e0d41de + 7219e11 commit aac8f32

40 files changed

Lines changed: 1269 additions & 1277 deletions

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ For impossible states, prefer failing loudly in development rather than hiding t
183183

184184
---
185185

186-
## Code review rules for agents
186+
## Code rules for agents
187187

188188
Before writing extra guards, ask:
189189

adminforth/basePlugin.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default class AdminForthPlugin implements IAdminForthPlugin {
2020
resourceConfig: AdminForthResource;
2121
className: string;
2222
activationOrder: number = 0;
23+
pluginsScope: 'resource' | 'global' = 'resource';
2324
shouldHaveSingleInstancePerWholeApp?: () => boolean;
2425

2526
constructor(pluginOptions: any, metaUrl: string) {
@@ -41,14 +42,27 @@ export default class AdminForthPlugin implements IAdminForthPlugin {
4142
}
4243

4344

45+
initializePluginInstanceId = (resourceConfig?: AdminForthResource) => {
46+
const uniqueness = this.instanceUniqueRepresentation(this.pluginOptions);
47+
let seed = '';
48+
if (resourceConfig) {
49+
seed = `af_pl_${this.constructor.name}_${resourceConfig?.resourceId || '_'}_${uniqueness}`;
50+
} else {
51+
seed = `af_pl_${this.constructor.name}_global_${uniqueness}`;
52+
}
53+
this.pluginInstanceId = md5hash(seed);
54+
afLogger.trace({seed, pluginInstanceId: this.pluginInstanceId}, `🪲 AdminForthPlugin.initializePluginInstanceId`);
55+
}
56+
4457
modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource, allPluginInstances?: {pi: AdminForthPlugin, resource: AdminForthResource}[]) {
4558
this.resourceConfig = resourceConfig;
46-
const uniqueness = this.instanceUniqueRepresentation(this.pluginOptions);
59+
this.initializePluginInstanceId(resourceConfig);
60+
this.adminforth = adminforth;
61+
}
4762

48-
const seed = `af_pl_${this.constructor.name}_${resourceConfig.resourceId}_${uniqueness}`;
49-
this.pluginInstanceId = md5hash(seed);
50-
afLogger.trace({seed, pluginInstanceId: this.pluginInstanceId}, `🪲 AdminForthPlugin.modifyResourceConfig`);
63+
modifyGlobalConfig(adminforth: IAdminForth) {
5164
this.adminforth = adminforth;
65+
this.initializePluginInstanceId();
5266
}
5367

5468
/**
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const globalPlugins = []

adminforth/commands/createApp/templates/index.ts.hbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import path from 'path';
66
import { Filters } from 'adminforth';
77
import { initApi } from './api.js';
88
import { logger } from 'adminforth';
9+
import { globalPlugins } from './globalPlugins.js';
910

1011
const ADMIN_BASE_URL = '';
1112

@@ -66,6 +67,7 @@ export const admin = new AdminForth({
6667
resourceId: 'adminuser'
6768
},
6869
],
70+
globalPlugins: globalPlugins,
6971
});
7072

7173
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {

adminforth/commands/createApp/utils.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ async function writeTemplateFiles(dirname, cwd, useNpm, includePrismaMigrations,
428428
src: 'custom/package.json.hbs',
429429
dest: 'custom/package.json',
430430
data: {}
431+
},
432+
{
433+
src: 'globalPlugins.ts.hbs',
434+
dest: 'globalPlugins.ts',
435+
data: {},
431436
}
432437
];
433438

adminforth/documentation/docs/tutorial/03-Customization/12-security.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ new AdminForth({
5353
5454
The format is `requests/period`, where period can use `s`, `m`, `h`, or `d`.
5555
Because rate limits are keyed by client IP, configure `auth.clientIpHeader` when AdminForth runs behind a trusted CDN or reverse proxy. See [Trusting client IP addresses](#trusting-client-ip-addresses).
56+
> It is important to provide '`auth.clientIpHeader`, because otherwise adminforth will automatically detect client IP in headers and if you don't use proxy, hacker can change IP like `x-forwarded-for: 1.1.1.1` in request headers and skip rate limit
5657
5758
5859
## Password strength

adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,26 @@ And `edit` action will be available as quick action:
542542
543543

544544

545+
## Show
546+
547+
### Next record button
548+
549+
By default, when a user opens a record from the list view, a **Next** button appears on the show page. It allows navigating through records one by one, respecting the current filters and sorting applied in the list. When the user reaches the last record on the current page, AdminForth automatically fetches the next page and continues navigation seamlessly.
550+
551+
To disable the Next button for a resource, set `showNextButton` to `false`:
552+
553+
```typescript title="./resources/apartments.ts"
554+
export default {
555+
resourceId: 'aparts',
556+
options: {
557+
//diff-add
558+
showNextButton: false,
559+
}
560+
}
561+
```
562+
563+
> ☝️ The Next button is only shown when the user navigates to the show page from the list view. Opening a record directly via URL will not display the button.
564+
545565
## Creating
546566

547567
### Fill with default values

adminforth/documentation/docs/tutorial/05-deploy.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ You can use it to build your AdminForth application in Docker container.
1919
> at build time. If you will remove it, your AdminForth application will still work, but will cause some downtime during app restart/redeploy because bundling will happen at runtime after you start the `index.ts` file. When `npx adminforth bundle` command is executed at build time, the call do `bundleNow()` inside of `index.ts` file will actually do nothing.
2020
2121

22+
2223
## Building the image
2324

2425
Now you can build your image:
@@ -41,6 +42,33 @@ docker run -p 3500:3500 \
4142
4243
Now open your browser and go to `http://localhost:3500` to see your AdminForth application running in Docker container.
4344

45+
46+
## Reducing docker image build time
47+
48+
By default `Dockerfile` created by adminforth CLI is configured in a way to rebuild adminforth SPA from scratch on every build:
49+
50+
```
51+
RUN pnpm/npm adminforth bundle
52+
```
53+
54+
If you want to speed up your build, you can use Docker cache for /tmp folder and change this line to:
55+
56+
```
57+
RUN --mount=type=cache,target=/tmp pnpm/npm adminforth bundle
58+
```
59+
60+
This will cache all /tmp folder between builds and speed up the build process significantly. However you need to ensure that your build daemon persists cache from `--mount=type=cache` mounts. Most of vendor CI build daemons like Github actions Default runner will not persist cache between builds so adding `--mount=type=cache` will not help in such case and you need to use dedicated caching solutions.
61+
62+
To verify build performance locally you can do next:
63+
1) Modify any custom vue file
64+
2) Run `docker build -t myadminapp .`. This populates docker cache with bundled SPA
65+
3) Modify same cusom vue file again
66+
4) Run `time docker build -t myadminapp .` and check resulting time.
67+
68+
First we recommend repeat steps 1-4 without `--mount=type=cache` on your docker daemon to see how much time it takes to build without cache and then add `--mount=type=cache` and repeat steps 1-4 again to see the difference in build times. Then experiment with your CI caching solution to achieve similar build times.
69+
70+
71+
4472
## Automating deployments with CI
4573

4674
If you are looking for a professional way to deploy your AdminForth application, you can follow our blog post [how to deploy your AdminForth application with Terraform From GitHub actions](https://adminforth.dev/blog/compose-aws-ec2-ecr-terraform-github-actions/)

adminforth/documentation/docs/tutorial/06-Adapters/02-oauth2-adapters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Adds support for Twitch authentication, useful for streaming or creator-oriented
5959
## Clerk OAuth Adapter
6060

6161
```bash
62-
pnpm i @adminforth/clerk-oauth-adapter
62+
pnpm i @adminforth/oauth-adapter-clerk
6363
```
6464

6565
Enables sign-in via [Clerk](https://clerk.com/) — a hosted authentication platform with built-in user management, MFA, and social logins.

adminforth/documentation/docs/tutorial/09-Plugins/01-agent.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ It stores session history in your own resources and generates responses using on
1717
## Installation
1818

1919
```bash
20-
pnpm i @adminforth/agent --save
21-
pnpm i @adminforth/completion-adapter-openai-responses --save
20+
pnpm add @adminforth/agent --save
21+
pnpm add @adminforth/completion-adapter-openai-responses --save
2222
```
2323

2424
Add your LLM credentials to `.env`:
@@ -197,17 +197,17 @@ export const admin = new AdminForth({
197197
});
198198
```
199199

200-
Then attach the plugin once, usually to your `adminuser` resource:
200+
Then attach the plugin once in `index.ts` as global plugin:
201201

202202
Configure the plugin with `modes`. The legacy top-level `completionAdapter` setup is no longer used.
203203

204-
```ts title="./resources/adminuser.ts"
204+
```ts title="./index.ts"
205205
import AdminForthAgent from '@adminforth/agent';
206206
import CompletionAdapterOpenAIResponses from '@adminforth/completion-adapter-openai-responses';
207207

208208
...
209209

210-
plugins: [
210+
globalPlugins: [
211211
...
212212
new AdminForthAgent({
213213
// optional, can be used to suggest example prompts in the UI
@@ -462,7 +462,7 @@ pnpm makemigration --name add-adminforth-agent-turn-debug ; pnpm migrate:local
462462

463463
Tell the plugin where to store debug data:
464464

465-
```ts title="./resources/adminuser.ts"
465+
```ts title="index.ts"
466466
new AdminForthAgent({
467467
modes: [
468468
...
@@ -604,7 +604,7 @@ pnpm add @adminforth/audio-adapter-openai
604604

605605
2) Import it in your users resource and add to the plugin config
606606

607-
```ts title="./resources/adminuser.ts"
607+
```ts title="index.ts"
608608
//diff-add
609609
import OpenAIAudioAdapter from '@adminforth/audio-adapter-openai'
610610

@@ -1010,7 +1010,7 @@ export const admin = new AdminForth({
10101010

10111011
Then connect it to the plugin:
10121012

1013-
```ts title="./resources/adminuser.ts"
1013+
```ts title="index.ts"
10141014
new AdminForthAgent({
10151015
modes: [
10161016
...

0 commit comments

Comments
 (0)