@antelopejs/dms 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +11 -1
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +1 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +1 -0
- package/frontend-vue/layers/dms-ui/app/components/grid/Grid.vue +10 -1
- package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +16 -6
- package/frontend-vue/layers/dms-ui/app/components/grid/columns.ts +29 -0
- package/frontend-vue/layers/dms-ui/app/components/grid/constants.ts +1 -0
- package/frontend-vue/package.json +4 -3
- package/frontend-vue/pnpm-lock.yaml +1158 -20
- package/frontend-vue/tests/grid-responsive-columns.test.ts +105 -0
- package/package.json +3 -3
- package/skills/dms/REFERENCE.md +1 -1
- package/skills/dms/SKILL.md +2 -2
- package/skills/dms-dev/SKILL.md +5 -5
- package/skills/dms-dev/scripts/dms-dev.sh +5 -5
- package/skills/dms-project/SKILL.md +3 -3
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { gridColumnsTemplate } from "../layers/dms-ui/app/components/grid/columns";
|
|
4
|
+
|
|
5
|
+
const GAP = "1rem";
|
|
6
|
+
const MIN = "240px";
|
|
7
|
+
|
|
8
|
+
const sourceOf = (file: string) =>
|
|
9
|
+
readFileSync(
|
|
10
|
+
new URL(`../layers/dms-ui/app/components/grid/${file}`, import.meta.url),
|
|
11
|
+
"utf8",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// Guards the exact-fit case: at the width where the track floor is precisely
|
|
15
|
+
// one Nth of the container, binary floats land a hair under the integer.
|
|
16
|
+
const FIT_EPSILON = 1e-6;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the template the way a browser would, in pixels, and reports how
|
|
20
|
+
* many tracks `auto-fill` ends up with for a given container width.
|
|
21
|
+
*/
|
|
22
|
+
function resolveColumnCount(
|
|
23
|
+
template: string,
|
|
24
|
+
containerWidth: number,
|
|
25
|
+
gapPx: number,
|
|
26
|
+
): number {
|
|
27
|
+
const match = template.match(
|
|
28
|
+
/repeat\(auto-fill, minmax\(min\(100%, max\((\d+)px, \(100% - (\d+) \* [^)]+\) \/ (\d+)\)\), 1fr\)\)/,
|
|
29
|
+
);
|
|
30
|
+
if (!match) throw new Error(`unexpected template: ${template}`);
|
|
31
|
+
const [, min, gapCount, maxColumns] = match;
|
|
32
|
+
const share =
|
|
33
|
+
(containerWidth - Number(gapCount) * gapPx) / Number(maxColumns);
|
|
34
|
+
const floor = Math.min(containerWidth, Math.max(Number(min), share));
|
|
35
|
+
if (floor <= 0) return Number(maxColumns);
|
|
36
|
+
return Math.max(
|
|
37
|
+
1,
|
|
38
|
+
Math.floor((containerWidth + gapPx) / (floor + gapPx) + FIT_EPSILON),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("grid column template", () => {
|
|
43
|
+
it("keeps every column at the widest row's count once the container is wide", () => {
|
|
44
|
+
const template = gridColumnsTemplate(6, GAP, MIN);
|
|
45
|
+
expect(resolveColumnCount(template, 1600, 16)).toBe(6);
|
|
46
|
+
expect(resolveColumnCount(template, 2400, 16)).toBe(6);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("drops columns rather than shrinking them below the minimum", () => {
|
|
50
|
+
const template = gridColumnsTemplate(6, GAP, MIN);
|
|
51
|
+
expect(resolveColumnCount(template, 976, 16)).toBe(3);
|
|
52
|
+
expect(resolveColumnCount(template, 657, 16)).toBe(2);
|
|
53
|
+
expect(resolveColumnCount(template, 328, 16)).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("never asks for a track wider than the container", () => {
|
|
57
|
+
const template = gridColumnsTemplate(4, GAP, MIN);
|
|
58
|
+
expect(template).toContain("min(100%,");
|
|
59
|
+
expect(resolveColumnCount(template, 200, 16)).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("gives rows of the same grid one shared template, so they stay aligned", () => {
|
|
63
|
+
expect(gridColumnsTemplate(4, GAP, MIN)).toBe(
|
|
64
|
+
gridColumnsTemplate(4, GAP, MIN),
|
|
65
|
+
);
|
|
66
|
+
expect(gridColumnsTemplate(4, GAP, MIN)).not.toBe(
|
|
67
|
+
gridColumnsTemplate(3, GAP, MIN),
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("treats a row-less grid as a single column", () => {
|
|
72
|
+
expect(gridColumnsTemplate(0, GAP, MIN)).toBe(
|
|
73
|
+
gridColumnsTemplate(1, GAP, MIN),
|
|
74
|
+
);
|
|
75
|
+
expect(resolveColumnCount(gridColumnsTemplate(1, GAP, MIN), 976, 16)).toBe(
|
|
76
|
+
1,
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("subtracts the gaps the row actually renders", () => {
|
|
81
|
+
expect(gridColumnsTemplate(3, "2rem", MIN)).toContain("(100% - 2 * 2rem)");
|
|
82
|
+
expect(gridColumnsTemplate(1, GAP, MIN)).toContain("(100% - 0 * 1rem)");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("honours a caller-supplied minimum", () => {
|
|
86
|
+
expect(gridColumnsTemplate(4, GAP, "120px")).toContain("120px");
|
|
87
|
+
expect(
|
|
88
|
+
resolveColumnCount(gridColumnsTemplate(4, GAP, "120px"), 657, 16),
|
|
89
|
+
).toBe(4);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("grid components", () => {
|
|
94
|
+
it("drive both the container and its rows from the shared template", () => {
|
|
95
|
+
for (const file of ["Grid.vue", "GridRow.vue"]) {
|
|
96
|
+
const source = sourceOf(file);
|
|
97
|
+
expect(source).toContain("gridColumnsTemplate(");
|
|
98
|
+
expect(source).not.toMatch(/repeat\(\$\{/);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("keeps rows spanning the full grid width", () => {
|
|
103
|
+
expect(sourceOf("GridRow.vue")).toContain('gridColumn: "1 / -1"');
|
|
104
|
+
});
|
|
105
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/AntelopeJS/dms.git"
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"zod": "~3.24.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@antelopejs/core": ">=1.
|
|
54
|
+
"@antelopejs/core": ">=1.8.0 <2",
|
|
55
55
|
"@antelopejs/tooling-configs": ">=0.0.6 <1.0.0",
|
|
56
56
|
"@types/archiver": "^6.0.4",
|
|
57
57
|
"@types/chai": "^4.3.20",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"@antelopejs/interface-redis": ">=0.0.8 <1.0.0"
|
|
101
101
|
},
|
|
102
102
|
"peerDependencies": {
|
|
103
|
-
"@antelopejs/core": ">=1.
|
|
103
|
+
"@antelopejs/core": ">=1.8.0 <2"
|
|
104
104
|
},
|
|
105
105
|
"peerDependenciesMeta": {
|
|
106
106
|
"@antelopejs/core": {
|
package/skills/dms/REFERENCE.md
CHANGED
|
@@ -10,7 +10,7 @@ List a section to see its files:
|
|
|
10
10
|
| Doc | Covers |
|
|
11
11
|
| --- | --- |
|
|
12
12
|
| `docs/01.getting-started/` | Intro, installation, quickstart, tutorial, **architecture**, the built-in dashboard |
|
|
13
|
-
| `docs/02.building/` | Project setup (**the common case**), every config key, pages & components, navigation, actions, backend services (hooks, notifications, realtime, replayable jobs, HTML/email rendering, export jobs), localization, frontend layer & `ajs
|
|
13
|
+
| `docs/02.building/` | Project setup (**the common case**), every config key, pages & components, navigation, actions, backend services (hooks, notifications, realtime, replayable jobs, HTML/email rendering, export jobs), localization, frontend layer & `ajs dms` CLI, distributable modules, deployment, troubleshooting |
|
|
14
14
|
| `docs/03.auth-and-tenancy/` | Auth flows (JWT, 2FA, invites), decorators & RBAC, multi-tenant data, SaaS mode |
|
|
15
15
|
| `docs/04.components/` | Component catalog: charts/widgets, layout, forms, tables, tree, DataTypes, DataController, file storage |
|
|
16
16
|
| `docs/05.extending-the-dashboard/` | Dashboard chrome, theming, custom DataTypes (frontend side), table-view displays, component events, period filtering |
|
package/skills/dms/SKILL.md
CHANGED
|
@@ -20,9 +20,9 @@ For the framework underneath (the core, `ajs` CLI, interfaces as versioned contr
|
|
|
20
20
|
- **Two coupled packages.** **`@antelopejs/dms`** is the backend: an AntelopeJS module
|
|
21
21
|
providing the page system, component builders, DataTypes, auth, and platform services,
|
|
22
22
|
auto-registering its **base Vue dashboard frontend** (`frontend-vue/`). **`@antelopejs/dms-frontend`**
|
|
23
|
-
is the frontend loader (the `ajs
|
|
23
|
+
is the frontend loader (the `ajs dms` CLI): an Inertia SSR app whose single catch-all
|
|
24
24
|
route renders the component tree the backend describes. In dev: two processes, `ajs project dev -w`
|
|
25
|
-
(legacy alias: `ajs project run`) and `ajs
|
|
25
|
+
(legacy alias: `ajs project run`) and `ajs dms dev` (auto-discovers a backend; `-b <url>` optional) —
|
|
26
26
|
see **Running**.
|
|
27
27
|
- **Two ways to build — usually a project.** Most commonly you build a **project**: your own app
|
|
28
28
|
loading the DMS via `antelope.config.ts`, registering *its own* pages and data — **dms-project**.
|
package/skills/dms-dev/SKILL.md
CHANGED
|
@@ -26,9 +26,9 @@ script is for local shells, not managed orbs: its processes do not survive orb u
|
|
|
26
26
|
The DMS has two coupled processes, both started from the DMS backend package directory:
|
|
27
27
|
|
|
28
28
|
- **Backend**: the AntelopeJS project — `ajs project dev -w` (`ajs project run` is the legacy alias). Listens on `http://localhost:5010`. Ready when the log emits `Server started, listening on http://localhost:5010`.
|
|
29
|
-
- **Frontend**: the `@antelopejs/dms-frontend` loader — `ajs
|
|
29
|
+
- **Frontend**: the `@antelopejs/dms-frontend` loader — `ajs dms dev`. It auto-discovers the running backend via `.antelope/dev.json`, so `-b <backend-url>` is optional. Listens on `http://localhost:3001`. Ready when the log emits `Local: http://localhost:3001/`.
|
|
30
30
|
|
|
31
|
-
By default the script runs each via the project's `pnpm dev` / `pnpm frontend:dev` scripts — a convention our playground projects adopt that expands to the two commands above. Those script names aren't shipped by the DMS, so if a project starts its servers differently, override the actual commands with the `DMS_BACK_CMD` / `DMS_FRONT_CMD` env vars (the script reads them; readiness detection and process cleanup already cover `ajs`, `ajs
|
|
31
|
+
By default the script runs each via the project's `pnpm dev` / `pnpm frontend:dev` scripts — a convention our playground projects adopt that expands to the two commands above. Those script names aren't shipped by the DMS, so if a project starts its servers differently, override the actual commands with the `DMS_BACK_CMD` / `DMS_FRONT_CMD` env vars (the script reads them; readiness detection and process cleanup already cover `ajs`, `ajs dms`, and the loader's Node entry point directly).
|
|
32
32
|
|
|
33
33
|
Order matters: start the backend first and wait for ready, **then** start the frontend. The frontend materializes the backend's layers into a `~/.antelopejs/dms-frontend/` workspace at startup; starting it before the backend is up produces stale or empty layer copies.
|
|
34
34
|
|
|
@@ -96,12 +96,12 @@ The script writes the long-running server logs to `/tmp/dms-back.log` and `/tmp/
|
|
|
96
96
|
- **Frontend's "auth redirect" 302** on `/modules/...` URLs is **normal** — it's the auth-protected admin routes. The frontend layer is loaded correctly even when curl returns 302. Don't restart on this alone; have the user log in.
|
|
97
97
|
- **Don't run `start` or `restart` more than once concurrently** in a single session — the second invocation will hit a port/lock conflict. If multiple background Bash tasks are queued, use the foreground `restart`.
|
|
98
98
|
- **Stale `dms-back-path` memory.** If the saved path no longer exists or the user has switched projects, the script will fail fast with a clear error. Re-prompt the user and overwrite the memory entry.
|
|
99
|
-
- **Stubbornly stale frontend after restarts.** The loader serves layers from physical copies under `~/.antelopejs/dms-frontend/<hash>/`. If a layer edit still doesn't show after a full restart, reset the workspaces with `ajs
|
|
100
|
-
- **`ajs
|
|
99
|
+
- **Stubbornly stale frontend after restarts.** The loader serves layers from physical copies under `~/.antelopejs/dms-frontend/<hash>/`. If a layer edit still doesn't show after a full restart, reset the workspaces with `ajs dms clean --all` (run in the backend package dir — bare `ajs dms clean` exits with an error asking for `-b` or `--all`, and `-b <url>` misses autodiscovered workspaces, which are keyed by project path), then `restart`.
|
|
100
|
+
- **`ajs dms` reports a refused credential (401), or the backend logs "no valid bootstrap credential".** The frontend authenticates to the layer endpoints with the ephemeral secret a dev backend publishes to `<project>/.antelope/dms-dev.json`. A 401 means that file is absent (backend not in dev mode), or stale — it outlives the backend that wrote it, exactly like `dev.json`, so a stopped instance leaves one behind whose pid no longer resolves. `restart` rewrites it. If the frontend runs outside the project tree, give it `DMS_BOOTSTRAP_SECRET` explicitly.
|
|
101
101
|
|
|
102
102
|
## Don't
|
|
103
103
|
|
|
104
104
|
- Don't try to hot-reload by editing files and refreshing the browser without `restart`. It will work intermittently and waste debugging cycles on phantom issues.
|
|
105
|
-
- Don't `pkill -9 node` — it kills unrelated processes. The script targets specific patterns (`antelope-runner`, `ajs project run|dev`, `ajs
|
|
105
|
+
- Don't `pkill -9 node` — it kills unrelated processes. The script targets specific patterns (`antelope-runner`, `ajs project run|dev`, `ajs dms dev`, and paths ending in `dms-frontend/dist/index.js dev`).
|
|
106
106
|
- Don't hardcode a backend path into a session. Always resolve via memory-or-prompt so the skill works across projects.
|
|
107
107
|
- Don't ask the user to start or restart the servers themselves before manual testing. You have the script — run it, wait for ready, then hand off. Asking the user to do it defeats the point of the skill and breaks the testing loop.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Run from the DMS backend package dir (DMS_BACK_DIR). By default it invokes that project's
|
|
4
4
|
# `pnpm dev` / `pnpm frontend:dev` scripts — a convention our playground projects adopt, which
|
|
5
5
|
# expand to `ajs project dev …` (the AntelopeJS backend; `ajs project run` is the legacy
|
|
6
|
-
# alias) and `ajs
|
|
6
|
+
# alias) and `ajs dms dev` (the Inertia frontend loader — it auto-discovers the backend, -b optional).
|
|
7
7
|
# Those script names aren't shipped by the DMS, so override the actual commands with
|
|
8
8
|
# DMS_BACK_CMD / DMS_FRONT_CMD when a project starts its servers differently.
|
|
9
9
|
# Dev watchers cover many edits, but the deterministic recipe when verifying a change is:
|
|
@@ -24,7 +24,7 @@ BACK_ERROR_PATTERN='Failed to load module|Module load failed|Error loading modul
|
|
|
24
24
|
FRONT_ERROR_PATTERN='Cannot find module|Failed to compile|Vite error|ENOENT.*package\.json|EADDRINUSE'
|
|
25
25
|
WAIT_TIMEOUT="${DMS_DEV_TIMEOUT:-180}"
|
|
26
26
|
|
|
27
|
-
PROC_PATTERN='antelope-runner|ajs project (run|dev)|(^|[[:space:]/])ajs-dms dev|dms-frontend/dist/index\.js dev'
|
|
27
|
+
PROC_PATTERN='antelope-runner|ajs project (run|dev)|(^|[[:space:]/])(ajs dms|ajs-dms) dev|dms-frontend/dist/index\.js dev'
|
|
28
28
|
|
|
29
29
|
log() { printf '[dms-dev] %s\n' "$*"; }
|
|
30
30
|
|
|
@@ -48,7 +48,7 @@ stop_servers() {
|
|
|
48
48
|
log "stopping dev servers…"
|
|
49
49
|
pkill -9 -f "antelope-runner" 2>/dev/null || true
|
|
50
50
|
pkill -9 -f "ajs project (run|dev)" 2>/dev/null || true
|
|
51
|
-
pkill -9 -f "(^|[[:space:]/])ajs-dms dev" 2>/dev/null || true
|
|
51
|
+
pkill -9 -f "(^|[[:space:]/])(ajs dms|ajs-dms) dev" 2>/dev/null || true
|
|
52
52
|
pkill -9 -f "dms-frontend/dist/index\.js dev" 2>/dev/null || true
|
|
53
53
|
sleep 2
|
|
54
54
|
if pgrep -af "$PROC_PATTERN" >/dev/null 2>&1; then
|
|
@@ -112,7 +112,7 @@ start_frontend() {
|
|
|
112
112
|
# shellcheck disable=SC2086 # word-splitting of the command is intentional
|
|
113
113
|
( cd "$DMS_BACK_DIR" && setsid nohup $FRONT_CMD >> "$FRONT_LOG" 2>&1 < /dev/null & )
|
|
114
114
|
wait_for "$FRONT_LOG" "$FRONT_READY_PATTERN" "frontend (http://localhost:3001)" \
|
|
115
|
-
"$FRONT_ERROR_PATTERN" 'pnpm.*frontend:dev|(^|[[:space:]/])ajs-dms dev|dms-frontend/dist/index\.js dev'
|
|
115
|
+
"$FRONT_ERROR_PATTERN" 'pnpm.*frontend:dev|(^|[[:space:]/])(ajs dms|ajs-dms) dev|dms-frontend/dist/index\.js dev'
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
status() {
|
|
@@ -141,7 +141,7 @@ Environment:
|
|
|
141
141
|
DMS_BACK_CMD Command to start the backend, run in DMS_BACK_DIR (default: "pnpm dev",
|
|
142
142
|
the playground convention for "ajs project dev -w" / legacy "run -w").
|
|
143
143
|
DMS_FRONT_CMD Command to start the frontend, run in DMS_BACK_DIR (default:
|
|
144
|
-
"pnpm frontend:dev", the playground convention for "ajs
|
|
144
|
+
"pnpm frontend:dev", the playground convention for "ajs dms dev").
|
|
145
145
|
DMS_BACK_LOG (default: /tmp/dms-back.log)
|
|
146
146
|
DMS_FRONT_LOG (default: /tmp/dms-front.log)
|
|
147
147
|
DMS_DEV_TIMEOUT (default: 180 seconds per server)
|
|
@@ -29,7 +29,7 @@ An AntelopeJS app whose `antelope.config.ts` loads **`@antelopejs/dms`** (+ the
|
|
|
29
29
|
infrastructure it needs) and whose own `src/` is the `local` module. It provides no interfaces, so
|
|
30
30
|
its `package.json` has **no `antelopeJs.implements`** (that field marks a distributable module);
|
|
31
31
|
deps are `@antelopejs/dms` + the interface libs, plus `@antelopejs/dms-frontend` (the
|
|
32
|
-
`ajs
|
|
32
|
+
`ajs dms` CLI) as a dependency — the template keeps it in `dependencies`; a devDependency also works
|
|
33
33
|
since it is only a CLI. The frontend attaches at runtime with `AddFrontendModule`, and the DMS
|
|
34
34
|
**auto-registers its base dashboard layer** (shell, login, component vocabulary) — a pages-only
|
|
35
35
|
project needs no `frontend-vue/` of its own.
|
|
@@ -114,9 +114,9 @@ under the built-in `pagesCategory` (`RegisterModule` is for distributable module
|
|
|
114
114
|
|
|
115
115
|
- Backend: `ajs project dev -w` (`ajs project run` is the legacy alias; `-e STAGING` picks an
|
|
116
116
|
environment). Projects often start Mongo/Redis in Docker first (`docker-compose up -d`).
|
|
117
|
-
- Frontend: the `@antelopejs/dms-frontend` loader, `ajs
|
|
117
|
+
- Frontend: the `@antelopejs/dms-frontend` loader, `ajs dms dev` — auto-discovers the running
|
|
118
118
|
backend via `.antelope/dev.json`, so `-b <apiBaseUrl>` is optional.
|
|
119
119
|
|
|
120
120
|
The `pnpm dev` / `frontend:dev` script names are **your project's conventions** — they expand to
|
|
121
|
-
`ajs project dev` and `ajs
|
|
121
|
+
`ajs project dev` and `ajs dms dev`. Whenever a change doesn't show (or you're about to verify one),
|
|
122
122
|
full-restart both, backend first — see **dms-dev**. Production: `docs/02.building/11.deployment.md`.
|