Skip to content

Commit 03fe106

Browse files
committed
Merge branch 'main' of github.com:devforth/adminforth into update-express-version
AdminForth/1781/image
2 parents 2f021d6 + b6f055c commit 03fe106

15 files changed

Lines changed: 622 additions & 765 deletions

File tree

adminforth/documentation/docs/tutorial/03-Customization/03-virtualColumns.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ columns: [
5353
```
5454

5555
This field will be displayed in show and list views with custom component `CountryFlag.vue`.
56+
57+
:::tip Enriching a virtual column from a hook
58+
If you fill a virtual column from a hook (e.g. [`afterDatasourceResponse`](./04-hooks.md#modify-record-after-it-is-returned-from-database)) instead of a custom component, write the enriched value into a field with **the same name as the virtual column**. This keeps the value addressable by column name everywhere — most importantly, the [Agent plugin](/docs/tutorial/Plugins/agent/) selects records by column name, so a mismatched field name makes it select the (empty) virtual column and miss your enriched data.
59+
:::
5660
Create file `CountryFlag.vue` in `custom` folder of your project:
5761

5862
```html title="./custom/CountryFlag.vue"

adminforth/documentation/docs/tutorial/03-Customization/04-hooks.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ Also you can use this hook to enrich the returned records list with some additio
199199
}
200200
```
201201

202+
:::tip Name enriched fields after the virtual column
203+
When you enrich records with extra fields for display, declare a matching [virtual column](./03-virtualColumns.md) and use **the same name** for the field you add in the hook (e.g. add a `priceWithTax` virtual column and write `r.priceWithTax` in the hook).
204+
205+
Reusing the same name keeps the enriched value tied to a column the rest of AdminForth knows about. In particular, the [Agent plugin](/docs/tutorial/Plugins/agent/) selects records by column name when answering questions — if the hook writes to a different field than the virtual column, the agent selects the (empty) virtual column and never sees your enriched value.
206+
:::
207+
202208
### Dropdown list of foreignResource
203209

204210
By default if there is `foreignResource` like we use for demo on `realtor_id` column, the filter will suggest a

adminforth/documentation/docs/tutorial/06-Adapters/04-storage-adapters.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ If you don't want to use a key/value adapter and you don't need to clean up file
5555

5656
Since the adapter uses a key/value adapter to store keys for deletion, it is important to use persistent storage, so the data will be safe:
5757

58-
- (⛔️) [RAM adapter](07-key-value-adapters.md#ram-adapter) - not recommended, because after a server restart all data will be lost
59-
- (✅) [Redis adapter](07-key-value-adapters.md#redis-adapter) - Redis itself stores data in-memory, but you can set it up to write data to an `.rdb` file so the database is restored on server restart. However, it requires regular database snapshots and persistent Docker storage setup
60-
- (✅✅) [LevelDB adapter](07-key-value-adapters.md#leveldb-adapter) - can be used, but you need to set up persistent storage in your Docker container, so data won't be lost between restarts
61-
- (✅✅✅) [Resource adapter](07-key-value-adapters.md#resource-based-adapter) - uses a database to store key/value pairs, so data will be safe between restarts, but you need to create an extra table for this storage
58+
- (⛔️) [RAM adapter](07-key-value-adapters.md#ram-adapter) - not recommended, because after an admin process restart (e.g. redeployment) all data and orphan file tracking info will be lost (and files will not be cleaned up)
59+
- (✅) [LevelDB adapter](07-key-value-adapters.md#leveldb-adapter) - can be used, but you need to set up persistent storage in your Docker container by monting leveldb data directory into a volume, so data won't be lost between restarts
60+
- (✅✅) [Redis adapter](07-key-value-adapters.md#redis-adapter) - Redis itself stores data in RAM memory but modern versions also able to persist it into disk. If you are running Redis in docker we recommend you to ensure that CI/CD pipeline does not force it to restarts during each redeployment, also ensure that you mount `/data` dir into volume. ()
61+
- (✅✅✅) [Resource adapter](07-key-value-adapters.md#resource-based-adapter) - uses a database to store key/value pairs, so data will be safe between restarts, but you need to create an extra table for this storage.
62+
63+
Please note that one adapter instance can be also reused for any other purposes or plugins, so if your application need KV adapter to multiple purposes, you can instantiate it once in dedicated utility file and reuse this instance in other places. Internally each KV method exposes 'collection' parameter which allows to separate data for different purposes or by different plugins.
6264

6365

6466
### Cloudflare R2 setup example

adminforth/documentation/docs/tutorial/06-Adapters/07-key-value-adapters.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ model key_values {
7878
key String @id
7979
value String
8080
collection String?
81+
expire_at DateTime? //optional column
8182
8283
@@index([key])
8384
@@index([collection])
@@ -117,6 +118,10 @@ export default {
117118
{
118119
name: 'collection',
119120
type: AdminForthDataTypes.STRING,
121+
},
122+
{
123+
name: 'expire_at',
124+
type: AdminForthDataTypes.DATETIME,
120125
}
121126
],
122127
options: {
@@ -157,5 +162,6 @@ const adapter = new ResourceKeyValueAdapter({
157162
keyField: 'key',
158163
valueField: 'value',
159164
collectionField: 'collection',
165+
expireField: 'expire_at'
160166
})
161167
```

adminforth/documentation/docs/tutorial/09-Plugins/11-oauth.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ Register the same `redirectUri` in BotFather under **Login Widget → Redirect U
373373

374374
If you use `@adminforth/chat-surface-adapter-telegram`, users must connect Telegram from **Settings → Connected Accounts** before the Telegram bot can identify them.
375375

376-
### Kaycloack Adapter
376+
### Keycloak Adapter
377377

378378
Install Adapter:
379379

adminforth/modules/utils.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import crypto from 'crypto';
66
import { AdminForthConfig, AdminForthResource, AdminForthResourceColumnInputCommon,Filters, IAdminForth, Predicate } from '../index.js';
77
import { RateLimiterMemory, RateLimiterAbstract } from "rate-limiter-flexible";
88
import { PERIOD_UNITS, type PeriodString, type PeriodUnit } from '../types/Back.js';
9-
import { z } from "zod";
109

1110
// @ts-ignore-next-line
1211

@@ -646,21 +645,4 @@ export function applyRegexValidation(value, validation) {
646645
${horizontal}
647646
${RESET}
648647
`;
649-
}
650-
651-
652-
export function parseBody<T>(
653-
schema: z.ZodType<T>,
654-
body: unknown,
655-
response: { setStatus: (code: number, message: string) => void },
656-
): { ok: true; data: T } | { ok: false; error: { error: string; details: unknown } } {
657-
const parsed = schema.safeParse(body ?? {});
658-
if (!parsed.success) {
659-
response.setStatus(400, '');
660-
return {
661-
ok: false,
662-
error: { error: 'Request body validation failed', details: parsed.error.issues },
663-
};
664-
}
665-
return { ok: true, data: parsed.data };
666-
}
648+
}

adminforth/servers/express.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ function normalizeExpressRuntimeSchema(schema: unknown): AnySchemaObject | undef
109109
}
110110

111111
if (isZodSchemaLike(schema)) {
112-
return z.toJSONSchema(schema as any, { target: 'openapi-3.0' }) as AnySchemaObject;
112+
return z.toJSONSchema(schema as any, { target: 'draft-07' }) as AnySchemaObject;
113113
}
114114

115115
return schema as AnySchemaObject;
@@ -602,22 +602,22 @@ class ExpressServer implements IExpressHttpServer {
602602
description,
603603
request_schema,
604604
response_schema,
605-
responce_schema,
606605
agent,
607606
target='json'
608607
} = options;
609608
if (!path.startsWith('/')) {
610609
throw new Error(`Path must start with /, got: ${path}`);
611610
}
612611
const fullPath = `${this.adminforth.config.baseUrl}/adminapi/v1${path}`;
613-
const normalizedResponseSchema = response_schema ?? responce_schema;
614-
const registeredApiSchema = (request_schema || normalizedResponseSchema)
612+
const normalizedRequestSchema = normalizeExpressRuntimeSchema(request_schema);
613+
const normalizedResponseSchema = normalizeExpressRuntimeSchema(response_schema);
614+
const registeredApiSchema = (normalizedRequestSchema || normalizedResponseSchema)
615615
? this.adminforth.openApi.registerApiSchema({
616616
method,
617617
noAuth,
618618
path: fullPath,
619619
description,
620-
request_schema,
620+
request_schema: normalizedRequestSchema,
621621
response_schema: normalizedResponseSchema,
622622
agent,
623623
handler,

adminforth/servers/openapi.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ class OpenApiRegistry implements IOpenApiRegistry {
5151
}
5252

5353
registerApiSchema(options: IAdminForthEndpointOptions): IRegisteredApiSchema {
54-
const responseSchema = options.response_schema ?? options.responce_schema;
5554
const route: IRegisteredApiSchema = {
5655
method: options.method.toLowerCase(),
5756
path: options.path,
5857
description: options.description,
5958
agent: options.agent,
6059
request_schema: options.request_schema,
61-
response_schema: responseSchema,
60+
response_schema: options.response_schema,
6261
meta: options.meta,
6362
handler: options.handler,
6463
};

adminforth/types/Back.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export interface IAdminForthEndpointOptionsBase {
7373
description?: string,
7474
request_schema?: AnySchemaObject,
7575
response_schema?: AnySchemaObject,
76-
responce_schema?: AnySchemaObject,
7776
agent?: AgentToolMeta,
7877
meta?: Record<string, unknown>,
7978
target?: 'json' | 'upload',
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "key_values" ADD COLUMN "expire_at" DATETIME;

0 commit comments

Comments
 (0)