@ghentcdh/crouton-core 0.0.1-alpha.87 → 0.0.1-alpha.89
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/agent-docs/1.getting-started/index.md +45 -41
- package/agent-docs/2.resources/actions.md +40 -0
- package/agent-docs/2.resources/columns.md +126 -50
- package/agent-docs/2.resources/field-inputs/autocomplete.md +26 -0
- package/agent-docs/2.resources/layout.md +329 -119
- package/agent-docs/2.resources/operations.md +1 -5
- package/agent-docs/2.resources/relations.md +14 -11
- package/agent-docs/3.backend/authentication.md +156 -0
- package/agent-docs/3.backend/data-sources.md +3 -3
- package/agent-docs/4.frontend/croutonform.md +8 -8
- package/agent-docs/4.frontend/translations.md +78 -0
- package/agent-docs/5.tooling/migrate.md +1 -100
- package/agent-docs/6.recipes/config-only-resource.md +1 -1
- package/agent-docs/README.md +1 -0
- package/agent-docs/reference/parse-schema.md +0 -2
- package/dist/crouton.schema.json +5 -0
- package/dist/field-input-schemas/array.field-input.schema.json +44 -0
- package/dist/field-input-schemas/array.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/autocomplete.field-input.schema.json +296 -0
- package/dist/field-input-schemas/autocomplete.field-input.schema.v1.json +296 -0
- package/dist/field-input-schemas/boolean.field-input.schema.json +44 -0
- package/dist/field-input-schemas/boolean.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/custom.field-input.schema.json +44 -0
- package/dist/field-input-schemas/custom.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/date-range.field-input.schema.json +44 -0
- package/dist/field-input-schemas/date-range.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/date.field-input.schema.json +44 -0
- package/dist/field-input-schemas/date.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/markdown.field-input.schema.json +44 -0
- package/dist/field-input-schemas/markdown.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/number.field-input.schema.json +44 -0
- package/dist/field-input-schemas/number.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/relation.field-input.schema.json +44 -0
- package/dist/field-input-schemas/relation.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/select.field-input.schema.json +44 -0
- package/dist/field-input-schemas/select.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/string.field-input.schema.json +44 -0
- package/dist/field-input-schemas/string.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/textarea.field-input.schema.json +44 -0
- package/dist/field-input-schemas/textarea.field-input.schema.v1.json +44 -0
- package/dist/field-input-schemas/toggle.field-input.schema.json +44 -0
- package/dist/field-input-schemas/toggle.field-input.schema.v1.json +44 -0
- package/dist/index.cjs +4223 -3090
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8638 -6993
- package/dist/index.d.ts +8638 -6993
- package/dist/index.js +4082 -2935
- package/dist/index.js.map +1 -1
- package/dist/resource.schema.json +177 -45
- package/dist/resource.schema.v1.json +177 -45
- package/dist/testing/index.cjs +38 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +20 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +9 -1
|
@@ -10,7 +10,8 @@ Two ways to start with crouton: **create a new project** from scratch, or **add
|
|
|
10
10
|
|
|
11
11
|
## @ghentcdh/create-crouton
|
|
12
12
|
|
|
13
|
-
Scaffold a complete crouton project — a NestJS backend with Prisma, pre-configured datasource, Docker Compose, and
|
|
13
|
+
Scaffold a complete crouton project — a NestJS backend with Prisma, pre-configured datasource, Docker Compose, and
|
|
14
|
+
optionally an Nx monorepo layout with a Vue frontend.
|
|
14
15
|
|
|
15
16
|
```sh
|
|
16
17
|
npm create @ghentcdh/crouton my-app
|
|
@@ -40,21 +41,21 @@ node packages/create-crouton/dist/index.js my-test-app
|
|
|
40
41
|
|
|
41
42
|
### Flags
|
|
42
43
|
|
|
43
|
-
| Flag
|
|
44
|
-
|
|
45
|
-
| `--nx`
|
|
46
|
-
| `--no-nx`
|
|
47
|
-
| `--no-frontend`
|
|
48
|
-
| `--no-postgres`
|
|
49
|
-
| `--sample`
|
|
50
|
-
| `--pm <manager>`
|
|
51
|
-
| `--no-install`
|
|
52
|
-
| `--no-git`
|
|
53
|
-
| `--no-docker`
|
|
54
|
-
| `--prefix <name>` | prompt
|
|
55
|
-
| `--db-url <url>`
|
|
56
|
-
| `-y, --yes`
|
|
57
|
-
| `--force`
|
|
44
|
+
| Flag | Default | Description |
|
|
45
|
+
|-------------------|---------|---------------------------------------------------------------------|
|
|
46
|
+
| `--nx` | prompt | Use Nx monorepo layout (backend + frontend + shared libs). |
|
|
47
|
+
| `--no-nx` | — | Skip Nx layout (scaffold a regular single-app project). |
|
|
48
|
+
| `--no-frontend` | — | Skip Vue frontend generation (Nx layout only). |
|
|
49
|
+
| `--no-postgres` | — | Skip PostgreSQL setup (Prisma schema, adapter, Docker). |
|
|
50
|
+
| `--sample` | — | Include a sample resource. |
|
|
51
|
+
| `--pm <manager>` | prompt | Package manager: `pnpm`, `npm`, `yarn`, or `bun`. |
|
|
52
|
+
| `--no-install` | — | Skip dependency installation. |
|
|
53
|
+
| `--no-git` | — | Skip `git init`. |
|
|
54
|
+
| `--no-docker` | — | Skip Docker files (Dockerfile, compose.yml). |
|
|
55
|
+
| `--prefix <name>` | prompt | Subfolder prefix for apps/config (e.g. `split`). Implies Nx layout. |
|
|
56
|
+
| `--db-url <url>` | prompt | Database connection URL. |
|
|
57
|
+
| `-y, --yes` | — | Accept all defaults (non-interactive). |
|
|
58
|
+
| `--force` | — | Overwrite existing files. |
|
|
58
59
|
|
|
59
60
|
### Layouts
|
|
60
61
|
|
|
@@ -113,7 +114,8 @@ my-app/
|
|
|
113
114
|
|
|
114
115
|
#### Nx monorepo with prefix
|
|
115
116
|
|
|
116
|
-
When using `--prefix split`, apps and generated code live under a subfolder. This is useful when the Nx workspace also
|
|
117
|
+
When using `--prefix split`, apps and generated code live under a subfolder. This is useful when the Nx workspace also
|
|
118
|
+
contains non-crouton projects.
|
|
117
119
|
|
|
118
120
|
```
|
|
119
121
|
my-app/
|
|
@@ -138,7 +140,8 @@ The CLI runs these steps automatically (unless skipped via flags):
|
|
|
138
140
|
|
|
139
141
|
1. **`git init`** — initialises a repository with an initial commit.
|
|
140
142
|
2. **`<pm> install`** — installs all dependencies.
|
|
141
|
-
3. **`crouton update resources`** — introspects the database and generates resource CRUD (best-effort; warns on failure
|
|
143
|
+
3. **`crouton update resources`** — introspects the database and generates resource CRUD (best-effort; warns on failure
|
|
144
|
+
if DB is not running).
|
|
142
145
|
|
|
143
146
|
Then follow the printed next-steps:
|
|
144
147
|
|
|
@@ -157,7 +160,8 @@ crouton update resources --prefix split
|
|
|
157
160
|
|
|
158
161
|
## @ghentcdh/add-crouton
|
|
159
162
|
|
|
160
|
-
Add crouton to an **existing** NestJS project — regular or Nx. This command is additive: it never overwrites existing
|
|
163
|
+
Add crouton to an **existing** NestJS project — regular or Nx. This command is additive: it never overwrites existing
|
|
164
|
+
files.
|
|
161
165
|
|
|
162
166
|
```sh
|
|
163
167
|
npx @ghentcdh/add-crouton
|
|
@@ -167,32 +171,32 @@ npx @ghentcdh/add-crouton --cwd /path/to/project
|
|
|
167
171
|
|
|
168
172
|
### Flags
|
|
169
173
|
|
|
170
|
-
| Flag
|
|
171
|
-
|
|
172
|
-
| `--cwd <dir>`
|
|
173
|
-
| `--backend <app>`
|
|
174
|
-
| `--frontend <app>` | auto-detect | Frontend app name (Nx only).
|
|
175
|
-
| `--no-frontend`
|
|
176
|
-
| `--pm <manager>`
|
|
177
|
-
| `--no-install`
|
|
178
|
-
| `--no-docker`
|
|
179
|
-
| `-y, --yes`
|
|
174
|
+
| Flag | Default | Description |
|
|
175
|
+
|--------------------|-------------|----------------------------------------|
|
|
176
|
+
| `--cwd <dir>` | `.` | Project directory. |
|
|
177
|
+
| `--backend <app>` | auto-detect | Backend app name (Nx only). |
|
|
178
|
+
| `--frontend <app>` | auto-detect | Frontend app name (Nx only). |
|
|
179
|
+
| `--no-frontend` | — | Skip frontend detection. |
|
|
180
|
+
| `--pm <manager>` | auto-detect | Package manager. |
|
|
181
|
+
| `--no-install` | — | Skip dependency installation. |
|
|
182
|
+
| `--no-docker` | — | Skip Docker file generation. |
|
|
183
|
+
| `-y, --yes` | — | Accept all defaults (non-interactive). |
|
|
180
184
|
|
|
181
185
|
### What it does
|
|
182
186
|
|
|
183
|
-
1. **Detects project type** — checks for `nx.json` at or above the current directory to distinguish Nx workspaces from
|
|
184
|
-
|
|
187
|
+
1. **Detects project type** — checks for `nx.json` at or above the current directory to distinguish Nx workspaces from
|
|
188
|
+
regular projects.
|
|
189
|
+
2. **Discovers apps** (Nx only) — scans `apps/` subdirs, classifies them as backend (`@nestjs/core` in deps) or frontend
|
|
190
|
+
(`vue`/`vite` in deps), and prompts which to use.
|
|
185
191
|
3. **Detects package manager** — from lockfile presence (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb).
|
|
186
|
-
4. **Scans dependencies** — reports missing backend deps (`@ghentcdh/crouton-api`, `@ghentcdh/crouton-core`, `prisma`,
|
|
192
|
+
4. **Scans dependencies** — reports missing backend deps (`@ghentcdh/crouton-api`, `@ghentcdh/crouton-core`, `prisma`,
|
|
193
|
+
etc.).
|
|
187
194
|
5. **Writes config files** (if absent):
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
195
|
+
- `crouton.json` — with detected `resourcesDir` and `dataSourcesDir`
|
|
196
|
+
- `crouton.enums.json` — empty enum registry
|
|
197
|
+
- `data-sources/default/` — default datasource with Prisma schema and config
|
|
198
|
+
- `.env.example` — with `DATABASE_URL` placeholder
|
|
192
199
|
6. **Installs dependencies** — runs `<pm> install` if missing deps were detected.
|
|
193
200
|
|
|
194
|
-
After running `@ghentcdh/add-crouton`, wire `CroutonApiModule` into your NestJS app module —
|
|
195
|
-
|
|
196
|
-
## Keeping agent files current
|
|
197
|
-
|
|
198
|
-
After upgrading crouton, run `crouton migrate` to update your `resource.json` files **and** refresh the Claude skill, Cursor rule, and `AGENTS.md` block to the new version. See [Migrations](../5.tooling/migrate.md#agent-files) for details.
|
|
201
|
+
After running `@ghentcdh/add-crouton`, wire `CroutonApiModule` into your NestJS app module —
|
|
202
|
+
see [Backend setup](backend.md).
|
|
@@ -141,3 +141,43 @@ The `condition` object takes a `field`, an operator, and (except for the existen
|
|
|
141
141
|
## Display options
|
|
142
142
|
|
|
143
143
|
Table actions support `icon`, `label`, and `tooltip`; row actions support `label`. The HTTP `method` of a procedure action defaults to `post`.
|
|
144
|
+
|
|
145
|
+
## Toolbar status feedback
|
|
146
|
+
|
|
147
|
+
When a procedure action runs, the CRUD toolbar shows an inline status message. No toasts are shown — feedback stays next to the table.
|
|
148
|
+
|
|
149
|
+
| State | Icon | Default text |
|
|
150
|
+
|-------|------|--------------|
|
|
151
|
+
| In progress | ⏳ | *Processing…* |
|
|
152
|
+
| Success | ✓ | Server `message`, or *Done* |
|
|
153
|
+
| Error | ✗ | Server `message`, or *Action failed* |
|
|
154
|
+
| Network error | ✗ | *Something went wrong, please try again* |
|
|
155
|
+
|
|
156
|
+
Override the default messages per action with optional fields on a procedure action:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"layout": {
|
|
161
|
+
"table": {
|
|
162
|
+
"rowActions": [
|
|
163
|
+
{
|
|
164
|
+
"id": "publish",
|
|
165
|
+
"label": "Publish",
|
|
166
|
+
"procedure": "publish",
|
|
167
|
+
"pendingMessage": "Publishing…",
|
|
168
|
+
"successMessage": "Published successfully",
|
|
169
|
+
"errorMessage": "Could not publish"
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
| Field | Purpose |
|
|
178
|
+
|-------|---------|
|
|
179
|
+
| `pendingMessage` | Shown immediately when the button is clicked. |
|
|
180
|
+
| `successMessage` | Shown on success. Falls back to the server `message`, then *Done*. |
|
|
181
|
+
| `errorMessage` | Shown when the server returns `success: false`. Falls back to the server `message`, then *Action failed*. |
|
|
182
|
+
|
|
183
|
+
Success messages auto-clear after 3 s; error messages stay for 5 s.
|
|
@@ -16,21 +16,21 @@
|
|
|
16
16
|
|
|
17
17
|
Both forms support the same options:
|
|
18
18
|
|
|
19
|
-
| Option | Description
|
|
20
|
-
|
|
21
|
-
| `idField` | Marks the id column
|
|
22
|
-
| `type` | Data type — a shorthand (`"string"`, `"integer"`, `"boolean"`, `"date"`, …) or a JSON Schema fragment for nested shapes. Optional on a prisma resource (derived from the Zod model); **required on every column of a `kind: "custom"` resource**, see [Custom resources](custom-resource.md#column-types)
|
|
23
|
-
| `label` / `hideLabel` | Display label, or hide it
|
|
24
|
-
| `hiddenInTable` / `hiddenInForm` / `hiddenInView` | Visibility per context when
|
|
25
|
-
| `createable` / `updateable` | Whether the field is written on create/update
|
|
26
|
-
| `required` | Whether the **form** demands a value. Overrides the Zod model in either direction on a prisma resource (`true` adds, `false` removes, omitted defers to the model); the only way to mark a field required on a `kind: "custom"` resource. Ignored on the id column and on fields that are neither createable nor updateable
|
|
27
|
-
| `displayKey` | Nested field to display (e.g. `author.name`)
|
|
28
|
-
| `showInLookup` *(deprecated)* | **Use `lookup.labels` at the resource root instead
|
|
29
|
-
| `unique` | Validate the value is unique: `true`, or `{ scope, caseInsensitive, message }`. Checks as-you-type and maps a DB unique violation to this field. Needs a matching `@unique` constraint. See [Unique fields](unique.md)
|
|
30
|
-
| `column` | Source column name when it differs from the key/`id` (defaults to `id`)
|
|
31
|
-
| `enum` | Name of a shared enum in `crouton.enums.json`; its `{ value, label }[]` is injected into `fieldInput.options.values`
|
|
32
|
-
| `extend` | Path to another `resource.json` whose columns are expanded as virtual sub-columns under this key (with a per-sub-column `columns` override map)
|
|
33
|
-
| `fieldInput` | Form control configuration, see below
|
|
19
|
+
| Option | Description |
|
|
20
|
+
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
21
|
+
| `idField` | Marks the id column |
|
|
22
|
+
| `type` | Data type — a shorthand (`"string"`, `"integer"`, `"boolean"`, `"date"`, …) or a JSON Schema fragment for nested shapes. Optional on a prisma resource (derived from the Zod model); **required on every column of a `kind: "custom"` resource**, see [Custom resources](custom-resource.md#column-types) |
|
|
23
|
+
| `label` / `hideLabel` | Display label, or hide it |
|
|
24
|
+
| `hiddenInTable` / `hiddenInForm` / `hiddenInView` | Visibility per context, used **only when that context has no `layout.<ctx>.items`** — they are the fallback that builds the layout. As soon as `layout.<ctx>` lists field items, those items are the full list: only listed columns render and these flags are ignored. On a `oneToMany` relation column, `hiddenInTable` (when acting as the table fallback) also drops it from the `_count` subquery `findAll` issues |
|
|
25
|
+
| `createable` / `updateable` | Whether the field is written on create/update |
|
|
26
|
+
| `required` | Whether the **form** demands a value. Overrides the Zod model in either direction on a prisma resource (`true` adds, `false` removes, omitted defers to the model); the only way to mark a field required on a `kind: "custom"` resource. Ignored on the id column and on fields that are neither createable nor updateable |
|
|
27
|
+
| `displayKey` | Nested field to display (e.g. `author.name`) |
|
|
28
|
+
| `showInLookup` *(deprecated)* | **Use `lookup.labels` at the resource root instead**. Sets the display label when this resource appears as an autocomplete option in another resource. Does **not** affect `?q=` search. |
|
|
29
|
+
| `unique` | Validate the value is unique: `true`, or `{ scope, caseInsensitive, message }`. Checks as-you-type and maps a DB unique violation to this field. Needs a matching `@unique` constraint. See [Unique fields](unique.md) |
|
|
30
|
+
| `column` | Source column name when it differs from the key/`id` (defaults to `id`) |
|
|
31
|
+
| `enum` | Name of a shared enum in `crouton.enums.json`; its `{ value, label }[]` is injected into `fieldInput.options.values` |
|
|
32
|
+
| `extend` | Path to another `resource.json` whose columns are expanded as virtual sub-columns under this key (with a per-sub-column `columns` override map) |
|
|
33
|
+
| `fieldInput` | Form control configuration, see below |
|
|
34
34
|
|
|
35
35
|
::: warning Moved to `layout.table`
|
|
36
36
|
The following column-level options are **deprecated** and will be removed. Use `layout.table` instead:
|
|
@@ -42,7 +42,8 @@ The following column-level options are **deprecated** and will be removed. Use `
|
|
|
42
42
|
- `showWhen` / `hideWhen` / `disabledWhen` → `layout.table.items[{ id, showWhen, ... }]`
|
|
43
43
|
- `fieldTable` → `layout.table.items[{ id, type, options }]`
|
|
44
44
|
|
|
45
|
-
See [Layout — Table layout](layout.md#table-layout-layouttable) and [migrate-to-next-alpha.md](/migrate-to-next-alpha)
|
|
45
|
+
See [Layout — Table layout](layout.md#table-layout-layouttable) and [migrate-to-next-alpha.md](/migrate-to-next-alpha)
|
|
46
|
+
for migration details.
|
|
46
47
|
:::
|
|
47
48
|
|
|
48
49
|
## Free-text search (`?q=`)
|
|
@@ -53,16 +54,23 @@ Declare which columns are included in free-text search via `operations.findAll.s
|
|
|
53
54
|
{
|
|
54
55
|
"operations": {
|
|
55
56
|
"findAll": {
|
|
56
|
-
"search": [
|
|
57
|
+
"search": [
|
|
58
|
+
"title",
|
|
59
|
+
"authorId"
|
|
60
|
+
]
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
```
|
|
61
65
|
|
|
62
|
-
- **Multiple entries** are ORed together: `?q=tolkien` matches books whose `title` contains "tolkien" OR whose author
|
|
63
|
-
|
|
64
|
-
- **`
|
|
65
|
-
|
|
66
|
+
- **Multiple entries** are ORed together: `?q=tolkien` matches books whose `title` contains "tolkien" OR whose author
|
|
67
|
+
name contains "tolkien".
|
|
68
|
+
- **`manyToOne` relation columns** (e.g. `authorId`) automatically resolve to the related resource's first visible
|
|
69
|
+
display field (e.g. `author.name`), so you never search against a raw foreign key string.
|
|
70
|
+
- **`showInLookup`** is a separate concern — it controls the label shown when this resource appears as an autocomplete
|
|
71
|
+
option somewhere else. Do not use it to drive `?q=` search; use `operations.findAll.search` instead.
|
|
72
|
+
- **Default**: when `findAll: true` and no explicit `search` is declared, all simple (non-id, non-relation, non-date)
|
|
73
|
+
columns are searched.
|
|
66
74
|
|
|
67
75
|
## Nested object and array columns
|
|
68
76
|
|
|
@@ -75,15 +83,21 @@ A column's `type` may be a full JSON Schema fragment, which is how you describe
|
|
|
75
83
|
"type": {
|
|
76
84
|
"type": "object",
|
|
77
85
|
"properties": {
|
|
78
|
-
"id": {
|
|
79
|
-
|
|
86
|
+
"id": {
|
|
87
|
+
"type": "string"
|
|
88
|
+
},
|
|
89
|
+
"name": {
|
|
90
|
+
"type": "string"
|
|
91
|
+
}
|
|
80
92
|
}
|
|
81
93
|
}
|
|
82
94
|
},
|
|
83
95
|
"tags": {
|
|
84
96
|
"type": {
|
|
85
97
|
"type": "array",
|
|
86
|
-
"items": {
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "string"
|
|
100
|
+
}
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
}
|
|
@@ -129,10 +143,10 @@ form-open time, not persisted until the user saves.
|
|
|
129
143
|
|
|
130
144
|
#### Dynamic default tokens
|
|
131
145
|
|
|
132
|
-
| Token | Resolves to
|
|
133
|
-
|
|
134
|
-
| `"$now"` | Current datetime as an ISO 8601 string
|
|
135
|
-
| `"$today"` | Current date as an ISO 8601 date string (`"2025-03-14"`)
|
|
146
|
+
| Token | Resolves to |
|
|
147
|
+
|------------|---------------------------------------------------------------------|
|
|
148
|
+
| `"$now"` | Current datetime as an ISO 8601 string |
|
|
149
|
+
| `"$today"` | Current date as an ISO 8601 date string (`"2025-03-14"`) |
|
|
136
150
|
| `"$user"` | Current user object (requires `defaults` in `CroutonPlugin` config) |
|
|
137
151
|
|
|
138
152
|
**Using `$user`** requires passing the current user when setting up the plugin:
|
|
@@ -163,7 +177,8 @@ onMounted(async () => {
|
|
|
163
177
|
|
|
164
178
|
## Field variants — per-context overrides
|
|
165
179
|
|
|
166
|
-
A single `fieldInput` drives the form, the read-only view, and the table cell. To render differently in a specific
|
|
180
|
+
A single `fieldInput` drives the form, the read-only view, and the table cell. To render differently in a specific
|
|
181
|
+
context, use layout item overrides:
|
|
167
182
|
|
|
168
183
|
- **form** ← `fieldInput`
|
|
169
184
|
- **view** ← `fieldInput` (override per-column via `layout.view.items[{ id, type, options }]`)
|
|
@@ -178,19 +193,32 @@ A single `fieldInput` drives the form, the read-only view, and the table cell. T
|
|
|
178
193
|
"fieldInput": {
|
|
179
194
|
"format": "relation",
|
|
180
195
|
"resource": "./author/resource.json",
|
|
181
|
-
"options": {
|
|
196
|
+
"options": {
|
|
197
|
+
"display": "autocomplete",
|
|
198
|
+
"displayKey": "name"
|
|
199
|
+
}
|
|
182
200
|
}
|
|
183
201
|
}
|
|
184
202
|
},
|
|
185
203
|
"layout": {
|
|
186
204
|
"view": {
|
|
187
205
|
"items": [
|
|
188
|
-
{
|
|
206
|
+
{
|
|
207
|
+
"id": "author",
|
|
208
|
+
"options": {
|
|
209
|
+
"display": "link"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
189
212
|
]
|
|
190
213
|
},
|
|
191
214
|
"table": {
|
|
192
215
|
"items": [
|
|
193
|
-
{
|
|
216
|
+
{
|
|
217
|
+
"id": "author",
|
|
218
|
+
"options": {
|
|
219
|
+
"displayKey": "shortName"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
194
222
|
]
|
|
195
223
|
}
|
|
196
224
|
}
|
|
@@ -208,7 +236,12 @@ Add `customComponent` to the table layout item's `options` to override the cell
|
|
|
208
236
|
"layout": {
|
|
209
237
|
"table": {
|
|
210
238
|
"items": [
|
|
211
|
-
{
|
|
239
|
+
{
|
|
240
|
+
"id": "section_number",
|
|
241
|
+
"options": {
|
|
242
|
+
"customComponent": "moveUpDown"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
212
245
|
]
|
|
213
246
|
}
|
|
214
247
|
}
|
|
@@ -236,12 +269,15 @@ Read-only columns derived from a raw SQL subquery at query time. Add a `computed
|
|
|
236
269
|
}
|
|
237
270
|
```
|
|
238
271
|
|
|
239
|
-
| Field
|
|
240
|
-
|
|
241
|
-
| `sql`
|
|
242
|
-
| `type`
|
|
272
|
+
| Field | Type | Description |
|
|
273
|
+
|--------|----------|-----------------------------------------------------------------------------|
|
|
274
|
+
| `sql` | `string` | Raw SQL subquery. Use `main` as the alias for the parent table row. |
|
|
275
|
+
| `type` | `string` | Cast type for the result: `"number"` (default), `"string"`, or `"boolean"`. |
|
|
243
276
|
|
|
244
|
-
All standard column fields (`label`, `hiddenInTable`, `hiddenInView`, `position`, `fieldInput`, …) are valid alongside
|
|
277
|
+
All standard column fields (`label`, `hiddenInTable`, `hiddenInView`, `position`, `fieldInput`, …) are valid alongside
|
|
278
|
+
`computed`. When a context declares a layout, list the computed column's id in `layout.table.items` /
|
|
279
|
+
`layout.view.items` to place it there (it is hidden otherwise); with no layout it follows `hiddenInTable` /
|
|
280
|
+
`hiddenInView` as before.
|
|
245
281
|
|
|
246
282
|
::: warning
|
|
247
283
|
Computed columns are not available on `kind: "custom"` resources — they run raw SQL against a real table.
|
|
@@ -249,12 +285,18 @@ Compute the value in `findAll` instead.
|
|
|
249
285
|
:::
|
|
250
286
|
|
|
251
287
|
::: warning Deprecated: `calculatedColumns`
|
|
252
|
-
The top-level `calculatedColumns` array is removed
|
|
288
|
+
The top-level `calculatedColumns` array is removed — computed columns live on
|
|
289
|
+
`columns[id].computed`. Legacy top-level entries no longer accept `hiddenInTable` /
|
|
290
|
+
`hiddenInView`; without an explicit layout such a column is always rendered.
|
|
253
291
|
:::
|
|
254
292
|
|
|
255
293
|
## Includes
|
|
256
294
|
|
|
257
|
-
Eagerly load relations with the list/detail queries. Declare them per operation so `findAll` and `findOne` can differ
|
|
295
|
+
Eagerly load relations with the list/detail queries. Declare them per operation so `findAll` and `findOne` can differ.
|
|
296
|
+
|
|
297
|
+
### Dot-path strings (recommended for simple nesting)
|
|
298
|
+
|
|
299
|
+
Use `"a.b"` shorthand instead of the verbose object form when you don't need `orderBy`:
|
|
258
300
|
|
|
259
301
|
```json
|
|
260
302
|
{
|
|
@@ -262,13 +304,43 @@ Eagerly load relations with the list/detail queries. Declare them per operation
|
|
|
262
304
|
"findAll": {
|
|
263
305
|
"include": [
|
|
264
306
|
"author",
|
|
265
|
-
|
|
307
|
+
"chapters.sections"
|
|
266
308
|
]
|
|
267
|
-
}
|
|
268
|
-
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Multiple dot-path entries for the same top-level relation are **deep-merged**:
|
|
315
|
+
|
|
316
|
+
```json
|
|
317
|
+
"include": ["a.b", "a.c"]
|
|
318
|
+
// → { a: { include: { b: true, c: true } } }
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Mix dot paths and object form freely — they merge on the same relation:
|
|
322
|
+
|
|
323
|
+
```json
|
|
324
|
+
"include": [
|
|
325
|
+
"chapters.sections",
|
|
326
|
+
{ "relation": "chapters", "orderBy": { "position": "asc" } }
|
|
327
|
+
]
|
|
328
|
+
// → chapters included with sections nested + orderBy applied
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Object form (when you need options)
|
|
332
|
+
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"operations": {
|
|
336
|
+
"findAll": {
|
|
269
337
|
"include": [
|
|
270
338
|
"author",
|
|
271
|
-
{
|
|
339
|
+
{
|
|
340
|
+
"relation": "chapters",
|
|
341
|
+
"orderBy": { "position": "asc" },
|
|
342
|
+
"include": ["sections"]
|
|
343
|
+
}
|
|
272
344
|
]
|
|
273
345
|
}
|
|
274
346
|
}
|
|
@@ -277,15 +349,19 @@ Eagerly load relations with the list/detail queries. Declare them per operation
|
|
|
277
349
|
|
|
278
350
|
When `findOne.include` is absent, crouton falls back to `findAll.include`.
|
|
279
351
|
|
|
280
|
-
| Field | Type
|
|
281
|
-
|
|
282
|
-
| `relation` | `string`
|
|
283
|
-
| `orderBy` | `object`
|
|
284
|
-
| `include` | `array`
|
|
352
|
+
| Field | Type | Description |
|
|
353
|
+
|------------|----------|-------------------------------------------------------------------|
|
|
354
|
+
| `relation` | `string` | Prisma relation field name |
|
|
355
|
+
| `orderBy` | `object` | Optional sort: `{ field: 'asc' \| 'desc' }` for included records |
|
|
356
|
+
| `include` | `array` | Nested includes (string, dot-path, or object) |
|
|
285
357
|
|
|
286
358
|
When a relation column has a `sort` option (see [Relations](relations.md#sorting-related-records)), the loader
|
|
287
359
|
automatically injects the corresponding `orderBy` into the include clause — no manual configuration needed.
|
|
288
360
|
|
|
361
|
+
`?include=` is limited to relation columns the **table layout** renders (via `layout.table.items`); without a
|
|
362
|
+
table layout it falls back to the `hiddenInTable` column flag. A relation the table never shows cannot be included.
|
|
363
|
+
|
|
289
364
|
::: warning Deprecated: root `include`
|
|
290
|
-
The top-level `include` field is removed.
|
|
365
|
+
The top-level `include` field is removed. Move it to `operations.findAll.include` /
|
|
366
|
+
`operations.findOne.include`.
|
|
291
367
|
:::
|
|
@@ -39,4 +39,30 @@ Autocomplete with optional free-text and create. Three option shapes are support
|
|
|
39
39
|
}
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## Excluding already-selected values
|
|
43
|
+
|
|
44
|
+
Use `exclude` to hide values the user already chose — useful for many-to-many chip lists or sibling field constraints.
|
|
45
|
+
|
|
46
|
+
```jsonc
|
|
47
|
+
"fieldInput": {
|
|
48
|
+
"type": "autocomplete",
|
|
49
|
+
"options": {
|
|
50
|
+
"resource": "./author.resource",
|
|
51
|
+
"labelKey": "name",
|
|
52
|
+
"valueKey": "id",
|
|
53
|
+
"exclude": {
|
|
54
|
+
"values": "{form.coAuthors}", // {form.path} placeholder or a literal array
|
|
55
|
+
"key": "id", // filter field — defaults to valueKey
|
|
56
|
+
"selected": true // also exclude this field's own current value
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **`values`** — a `{form.path}` placeholder (resolved at fetch time) or a literal `unknown[]`. Objects in the array are mapped through `valueKey` to extract the scalar.
|
|
63
|
+
- **`key`** — the server-side field used for the `not_in` filter. Defaults to `valueKey` (or `"id"`).
|
|
64
|
+
- **`selected`** — when `true`, the control's own current value is also excluded. Automatically applied by `RelationInline` for many-to-many chips.
|
|
65
|
+
|
|
66
|
+
For resource-backed autocomplete the exclude list is sent as a `filter=<key>:[…]:not_in` query param (skipped above 200 values). For remote URIs, add `{exclude}` to the URI template. Client-side filtering always runs as a fallback.
|
|
67
|
+
|
|
42
68
|
<!-- @include: ./_generated/autocomplete.md -->
|