Skip to content

Commit a0485c7

Browse files
committed
Merge branch 'main' of github.com:devforth/adminforth into next
AdminForth/1774/find-a-way-to-run-dev-demo-in-
2 parents 975b313 + bf45404 commit a0485c7

13 files changed

Lines changed: 233 additions & 83 deletions

File tree

adminforth/commands/cli.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,61 @@ export function getVersion() {
4242
return ADMINFORTH_VERSION;
4343
}
4444

45+
/**
46+
* Resolves the adminforth version range to write into a scaffolded package.json.
47+
*
48+
* Returns a caret range pinned to the latest published release of the dist-tag
49+
* matching the running CLI, e.g. "^3.6.12" (installs the latest 3.x.x, never a
50+
* major upgrade). For "next" builds the moving "next" tag is kept, since
51+
* prerelease versions do not caret cleanly. Falls back to a major-only range
52+
* (e.g. "^3.0.0"), and finally to "latest", when the registry is unreachable.
53+
*/
54+
export async function resolveAdminforthVersionRange() {
55+
// Determine which dist-tag matches the CLI currently running, and derive an
56+
// offline fallback range from the CLI's own major version.
57+
let tag = 'latest';
58+
let offlineFallback = 'latest';
59+
try {
60+
const version = getVersion();
61+
if (typeof version === 'string') {
62+
if (version.includes('next')) {
63+
tag = 'next';
64+
}
65+
const major = version.split('.')[0];
66+
if (/^\d+$/.test(major)) {
67+
offlineFallback = `^${major}.0.0`;
68+
}
69+
}
70+
} catch {
71+
// Ignore; fall back to "latest" below.
72+
}
73+
74+
// "next" builds keep the moving tag — prerelease versions don't caret cleanly.
75+
if (tag === 'next') {
76+
return 'next';
77+
}
78+
79+
try {
80+
const res = await fetch('https://registry.npmjs.org/-/package/adminforth/dist-tags', {
81+
signal: AbortSignal.timeout(5000),
82+
});
83+
if (!res.ok) {
84+
throw new Error(`registry responded with ${res.status}`);
85+
}
86+
const distTags = await res.json();
87+
const latest = distTags[tag];
88+
if (typeof latest !== 'string' || !/^\d+\.\d+\.\d+/.test(latest)) {
89+
throw new Error('invalid version received from registry');
90+
}
91+
return `^${latest}`;
92+
} catch (err) {
93+
console.warn(
94+
`⚠️ Could not resolve AdminForth version from npm registry (${err.message}); defaulting to "${offlineFallback}".`
95+
);
96+
return offlineFallback;
97+
}
98+
}
99+
45100
function showVersion() {
46101
const ADMINFORTH_VERSION = getVersion();
47102

adminforth/commands/createApp/utils.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,14 @@ import { exec } from 'child_process';
1111

1212
import Handlebars from 'handlebars';
1313
import { promisify } from 'util';
14-
import { getVersion } from '../cli.js';
14+
import { resolveAdminforthVersionRange } from '../cli.js';
1515

1616
import { URL } from 'url'
1717
import net from 'net'
1818

1919
const execAsync = promisify(exec);
2020

21-
function detectAdminforthVersion() {
22-
try {
23-
const version = getVersion();
24-
25-
if (typeof version !== 'string') {
26-
throw new Error('Invalid version format');
27-
}
28-
29-
if (version.includes('next')) {
30-
return 'next';
31-
}
32-
return 'latest';
33-
} catch (err) {
34-
console.warn('⚠️ Could not detect AdminForth version, defaulting to "latest".');
35-
return 'latest';
36-
}
37-
}
38-
39-
const adminforthVersion = detectAdminforthVersion();
40-
const SUPPORTED_DB_URL_SCHEMES = ['sqlite://', 'postgresql://', 'mongodb://', 'mysql://', 'clickhouse://'];
21+
const SUPPORTED_DB_URL_SCHEMES =['sqlite://', 'postgresql://', 'mongodb://', 'mysql://', 'clickhouse://'];
4122
const PRISMA_MIGRATION_DB_PROTOCOLS = ['sqlite', 'postgres', 'postgresql', 'mysql'];
4223

4324

@@ -314,6 +295,7 @@ async function writeTemplateFiles(dirname, cwd, useNpm, includePrismaMigrations,
314295
dbUrlProd, prismaDbUrlProd, sqliteFile
315296
} = options;
316297
const packageManagerTemplateData = getPackageManagerTemplateData(useNpm, nodeMajor);
298+
const adminforthVersion = await resolveAdminforthVersionRange();
317299
const resolvedPrismaDbUrl = includePrismaMigrations ? prismaDbUrl : null;
318300
const resolvedPrismaDbUrlProd = includePrismaMigrations ? prismaDbUrlProd : null;
319301
const connectorProvider = provider === 'postgresql' ? 'postgres' :

adminforth/commands/createPlugin/templates/package.json.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
"typescript": "^5.7.3"
1717
},
1818
"dependencies": {
19-
"adminforth": "latest"
19+
"adminforth": "{{adminforthVersion}}"
2020
}
2121
}

adminforth/commands/createPlugin/utils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Listr } from 'listr2';
88
import { fileURLToPath } from 'url';
99
import { execa } from 'execa';
1010
import Handlebars from 'handlebars';
11+
import { resolveAdminforthVersionRange } from '../cli.js';
1112

1213
export function parseArgumentsIntoOptions(rawArgs) {
1314
const args = arg(
@@ -102,6 +103,7 @@ async function scaffoldProject(ctx, options, cwd) {
102103

103104
async function writeTemplateFiles(dirname, cwd, options) {
104105
const { pluginName } = options;
106+
const adminforthVersion = await resolveAdminforthVersionRange();
105107

106108
// Build a list of files to generate
107109
const templateTasks = [
@@ -113,7 +115,7 @@ async function writeTemplateFiles(dirname, cwd, options) {
113115
{
114116
src: "package.json.hbs",
115117
dest: "package.json",
116-
data: { pluginName },
118+
data: { pluginName, adminforthVersion },
117119
},
118120
{
119121
src: "index.ts.hbs",

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ When user opens edit page, AdminForth makes a request to the backend to get the
4242

4343
![Initial data for edit page flow](get_resource_data.png)
4444

45-
Practically you can use `show.afterDatasourceResponse` to modify or add some data before it is displayed on the edit page.
45+
Practically you can use `show.afterDatasourceResponse` to modify or add some data before it is displayed on the edit page. In other words, at this stage you can enrich the data with some additional metadata which might be handy on edit page for custom Vue fields.
4646

47-
For example [upload plugin](/docs/tutorial/Plugins/upload/) uses this hook to generate signed preview URL so user can see existing uploaded file preview in form, and at the same time database stores only original file path which might be not accessible without presigned URL.
47+
For example [upload plugin](/docs/tutorial/Plugins/upload/) uses this hook to generate signed preview URL so user can see existing uploaded file preview in form, and at the same time database stores only original file path which might be not accessible without presigned URL.
4848

4949
## Saving data on edit page
5050

@@ -177,6 +177,28 @@ For example, you can change the way columns value is displayed by changing the v
177177
}
178178
```
179179

180+
Also you can use this hook to enrich the returned records list with some additional data fields which might be handy for custom Vue components defined in `components.list` or `components.show` for this resource. For example you can use [key-value adapter](/docs/tutorial/Adapters/key-value-adapters/) to get some global configuration values and add them to each record in the list:
181+
182+
```ts title='./resources/apartments.ts'
183+
184+
{
185+
...
186+
hooks: {
187+
list: {
188+
//diff-add
189+
afterDatasourceResponse: async ({ response }: { response: any }) => {
190+
//diff-add
191+
response.forEach((r: any) => {
192+
const taxRate = await kvAdapter.getValue('taxRate');
193+
r.priceWithTax = r.price * (1 + taxRate);
194+
});
195+
return { ok: true, error: "" };
196+
},
197+
},
198+
},
199+
}
200+
```
201+
180202
### Dropdown list of foreignResource
181203

182204
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/07-key-value-adapters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
description: "Reference page for AdminForth key-value adapters, including RAM, Redis, and LevelDB backends for temporary state, caching, and plugin storage."
2+
description: "Reference page for prebuilt key-value adapters created by AdminForth team, including simplest RAM Adapter (in-memory, no dependencies but ephemeral), Redis-based adapter, LevelDB - based (requires a mounted volume DevOps), Resource-based (Works on top of a resource persistable with your native SQL/NoSQL database)"
33
---
44

55
# Key-value Adapters

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,26 @@ export default {
106106
} satisfies AdminForthResourceInput;
107107
```
108108

109+
Then register the resource in `index.ts`:
110+
111+
```ts title="./index.ts"
112+
//diff-add
113+
import adminUserExternalIdentitiesResource from "./resources/adminUserExternalIdentities";
114+
115+
116+
... new AdminForth({
117+
dataSources: [...],
118+
...
119+
resources: [
120+
apartmentsResource,
121+
usersResource,
122+
//diff-add
123+
adminUserExternalIdentitiesResource,
124+
],
125+
...
126+
})
127+
```
128+
109129
## Configuration
110130

111131
This example configures Google OAuth. See [OAuth2 Providers](#oauth2-providers) for provider setup details.

adminforth/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
"@inquirer/prompts": "^7.4.1",
9090
"@scalar/express-api-reference": "^0.9.7",
9191
"@types/express": "^4.17.21",
92-
"adminforth": "link:.",
9392
"ajv": "^8.18.0",
9493
"arg": "^5.0.2",
9594
"ast-types": "^0.14.2",

0 commit comments

Comments
 (0)