@antelopejs/interface-dms-builder 0.3.0 → 0.4.0
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/README.md +17 -17
- package/dist/catalog.d.ts +7 -7
- package/dist/drafts.d.ts +10 -9
- package/dist/drafts.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mapping.d.ts +5 -0
- package/dist/mapping.js +2 -1
- package/dist/mapping.js.map +1 -1
- package/dist/operation-map.d.ts +66 -0
- package/dist/operation-map.js +57 -0
- package/dist/operation-map.js.map +1 -0
- package/dist/operations.d.ts +6 -5
- package/dist/operations.js.map +1 -1
- package/dist/project.d.ts +3 -2
- package/dist/project.js.map +1 -1
- package/dist/queries.d.ts +12 -11
- package/dist/resources.d.ts +3 -3
- package/dist/results.d.ts +4 -4
- package/dist/structure.d.ts +5 -4
- package/dist/values.d.ts +14 -10
- package/docs/1.introduction.md +28 -22
- package/docs/10.a-chart-without-code.md +47 -71
- package/docs/11.external-databases.md +94 -70
- package/docs/2.addressing-and-structure.md +48 -40
- package/docs/3.catalog.md +105 -49
- package/docs/4.page-operations.md +74 -60
- package/docs/5.resources.md +97 -71
- package/docs/6.queries.md +94 -95
- package/docs/7.values.md +38 -32
- package/docs/8.results-and-errors.md +62 -45
- package/docs/9.drafts-and-preview.md +84 -48
- package/docs/images/captures/editor-selected.webp +0 -0
- package/docs/tsconfig.json +4 -0
- package/package.json +2 -2
- package/docs/images/editor-selected.png +0 -0
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: "Results and errors"
|
|
3
|
+
description: "The OpResult envelope every builder operation returns: the staged file changes, the warnings, the BuilderError codes with their payloads, and the expectedVersion check."
|
|
4
|
+
mode: reference
|
|
5
|
+
---
|
|
2
6
|
|
|
3
7
|
## Overview
|
|
4
8
|
|
|
5
|
-
Every operation that can fail returns an `OpResult`. It is a discriminated union
|
|
9
|
+
Every operation that can fail returns an `OpResult`. It is a discriminated union. `ok: true` carries the operation's data and the file changes it staged, and `ok: false` carries a single `BuilderError`. An expected failure comes back as a value and does not throw. An unknown ref, a duplicate name and a configuration the engine cannot validate are examples. The one known exception is an unknown block type inside a `$block` value passed to `AddBlock` or `ConfigureBlock`, which rejects the call, as [Value encodings](./7.values.md) describes.
|
|
6
10
|
|
|
7
|
-
Mutations are transactional. The engine applies the edit in memory, typechecks the project, and only
|
|
11
|
+
Mutations of source files are transactional. The engine applies the edit in memory, typechecks the project, and writes only when the typecheck passes. A failure rolls the transaction back and returns `typecheck_failed`, so a rejected operation leaves no partial edit on disk.
|
|
8
12
|
|
|
9
|
-
## Branch on a
|
|
13
|
+
## Branch on a result
|
|
10
14
|
|
|
11
|
-
```typescript
|
|
15
|
+
```typescript fragment
|
|
12
16
|
import { GetPageStructure } from "@antelopejs/interface-dms-builder";
|
|
13
17
|
|
|
14
18
|
const result = await GetPageStructure("/dashboard");
|
|
@@ -20,28 +24,28 @@ if (!result.ok) {
|
|
|
20
24
|
const { blocks, version } = result.data;
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
`OpResult<T>`
|
|
27
|
+
`OpResult<T>` has two variants:
|
|
24
28
|
|
|
25
29
|
| Variant | Fields |
|
|
26
30
|
| --- | --- |
|
|
27
|
-
|
|
|
28
|
-
|
|
|
31
|
+
| Success | `ok: true`, `data: T`, `changes: FileChange[]`, `warnings?: OpWarning[]` |
|
|
32
|
+
| Failure | `ok: false`, `error: BuilderError` |
|
|
29
33
|
|
|
30
|
-
`OpResult` defaults to `OpResult<void
|
|
34
|
+
`OpResult` defaults to `OpResult<void>`. The operations that return only a status use it, such as `ConfigureCategory`, `RemoveBlock` and `RemoveField`.
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
The reads that use the envelope, such as `GetPageStructure` and `GetResourceStructure`, return an empty `changes` array on success. The listing operations (`ListPages`, `ListCategories`, `ListResources`, `ListQueryTemplates`, `ListDataSources` and `GetCatalog`) do not use the envelope. They return their value directly, and `RefreshSourceIndex` returns `void`.
|
|
33
37
|
|
|
34
|
-
## Read the
|
|
38
|
+
## Read the staged changes
|
|
35
39
|
|
|
36
|
-
`changes`
|
|
40
|
+
`changes` lists what the operation wrote, one entry per file.
|
|
37
41
|
|
|
38
42
|
| Field | Type | Description |
|
|
39
43
|
| --- | --- | --- |
|
|
40
44
|
| `path` | `string` | The file's absolute path. |
|
|
41
45
|
| `kind` | `"create" \| "modify" \| "delete"` | What happened to the file. |
|
|
42
|
-
| `diff` | `string` | The change as unified diff hunks (`@@ -a,b +c,d @@`, then lines
|
|
46
|
+
| `diff` | `string` | The change as unified diff hunks (`@@ -a,b +c,d @@`, then lines that start with a space, `-` or `+`), with no file headers. Empty for a deleted file or folder. |
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
One operation often changes more than one file. Creating a page writes the page file and rewrites the barrel that exports it. Creating a resource writes three files and rewrites a barrel.
|
|
45
49
|
|
|
46
50
|
```typescript
|
|
47
51
|
import { CreateResource } from "@antelopejs/interface-dms-builder";
|
|
@@ -57,16 +61,28 @@ if (result.ok) {
|
|
|
57
61
|
}
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
## Handle
|
|
64
|
+
## Handle warnings
|
|
61
65
|
|
|
62
|
-
`warnings` is present only when
|
|
66
|
+
`warnings` is present only when a successful operation has something non-fatal to report. The field is optional, so it can be absent instead of an empty array.
|
|
63
67
|
|
|
64
68
|
| Code | Raised when |
|
|
65
69
|
| --- | --- |
|
|
66
|
-
| `index_clamped` | An `AddBlock` or `MoveBlock` index fell outside the sibling range and
|
|
67
|
-
| `datatype_fallback` | A field's DataType is not one the builder maps, so it
|
|
68
|
-
| `data_not_dropped` | `DeleteResource` removed the source but could not
|
|
69
|
-
| `
|
|
70
|
+
| `index_clamped` | An `AddBlock` or `MoveBlock` index fell outside the sibling range, and the engine moved it to the nearest end. |
|
|
71
|
+
| `datatype_fallback` | A field's DataType is not one the builder maps, so a resource stores it as a string, or a query filter compares it as a string. |
|
|
72
|
+
| `data_not_dropped` | `DeleteResource` removed the source files but could not delete the rows of the resource's table. |
|
|
73
|
+
| `data_kept` | `DeleteResource` deleted a resource that mirrors an external database. Its rows belong to that database and stay in place. |
|
|
74
|
+
| `route_changed` | `ConfigurePage` moved a page to another category, so its route changed and links to the old route break. |
|
|
75
|
+
| `query_opaque` | `SetPageBlocks` left alone a query on the page that a person took over by hand. |
|
|
76
|
+
| `query_kept` | `SetPageBlocks` kept a query that the draft dropped, because a block still reads it. |
|
|
77
|
+
| `page_not_written` | `MapResources` wrote a mapped relation's tables, but not its table view page. |
|
|
78
|
+
| `relation_missing` | `GetMapping` found a relation that the module maps but the database no longer has, or that the role can no longer see. |
|
|
79
|
+
| `module_not_loaded` | `MapResources` wrote the mapping, but the module it wrote into did not load again. The module was unloaded and did not start within the wait, or the runtime does not report it active. The message names the module, and the backend log holds the error. |
|
|
80
|
+
| `setting_dropped` | `ConfigureTableView` or `MapResources` dropped a TableView setting that no longer holds, such as a default display the table no longer offers. |
|
|
81
|
+
| `relation_skipped` | `MapResources` left out a relation of the batch because one of its choices was refused, and wrote the others. |
|
|
82
|
+
| `display_dropped` | `MapResources` wrote a column plain because the display sent for it, or the tabs sent from it, do not suit the column. |
|
|
83
|
+
| `field_flag_set` | `MapResources` or `ConfigureTableView` marked a column filterable or sortable, because a view, footer figure, tab or grouping needs it. |
|
|
84
|
+
| `label_changed` | `MapResources` changed a relation's label to one the generated code can read, or dropped it when no column offers it. |
|
|
85
|
+
| `display_not_proposed` | `MapResources` mapped a relation whose columns left `display` out, and no profile or analysis could propose a badge, so its text columns were written plain. |
|
|
70
86
|
|
|
71
87
|
```typescript
|
|
72
88
|
import { AddBlock } from "@antelopejs/interface-dms-builder";
|
|
@@ -85,20 +101,20 @@ if (result.ok) {
|
|
|
85
101
|
}
|
|
86
102
|
```
|
|
87
103
|
|
|
88
|
-
## Handle
|
|
104
|
+
## Handle errors
|
|
89
105
|
|
|
90
|
-
`BuilderError` is a union discriminated by `code`. Each variant carries
|
|
106
|
+
`BuilderError` is a union discriminated by `code`. Each variant carries the data needed to act on it.
|
|
91
107
|
|
|
92
108
|
| Code | Payload | Meaning |
|
|
93
109
|
| --- | --- | --- |
|
|
94
110
|
| `not_found` | `ref: string` | The page, category, block, resource, field or query does not exist. |
|
|
95
111
|
| `duplicate_name` | `name: string`, `scope: DuplicateScope` | The name is already taken within that scope. |
|
|
96
112
|
| `invalid_config` | `issues: ValidationIssue[]` | The request's configuration did not validate. |
|
|
97
|
-
| `opaque_target` | `path: BlockPath` | The target exists but the builder cannot rewrite it. |
|
|
98
|
-
| `unsupported` | `detail: string` | The
|
|
113
|
+
| `opaque_target` | `path: BlockPath` | The target exists, but the builder cannot rewrite it. For a field or a query, `path` holds the `FieldPath` or the `QueryRef`. |
|
|
114
|
+
| `unsupported` | `detail: string` | The engine does not handle the request, and `detail` says why. |
|
|
99
115
|
| `referential_integrity` | `blockedBy: string[]` | Something still depends on what you asked to delete. |
|
|
100
116
|
| `stale` | `ref: string`, `currentVersion: string` | The file changed since the version you passed as `expectedVersion`. |
|
|
101
|
-
| `typecheck_failed` | `diagnostics: TypecheckError[]` | The edit would not compile, and
|
|
117
|
+
| `typecheck_failed` | `diagnostics: TypecheckError[]` | The edit would not compile, and the engine rolled it back. |
|
|
102
118
|
|
|
103
119
|
```typescript
|
|
104
120
|
import { AddBlock } from "@antelopejs/interface-dms-builder";
|
|
@@ -130,9 +146,9 @@ if (!result.ok) {
|
|
|
130
146
|
}
|
|
131
147
|
```
|
|
132
148
|
|
|
133
|
-
### Duplicate
|
|
149
|
+
### Duplicate scopes
|
|
134
150
|
|
|
135
|
-
`DuplicateScope` names the namespace the collision happened in, which tells you what to rename
|
|
151
|
+
`DuplicateScope` names the namespace the collision happened in, which tells you what to rename.
|
|
136
152
|
|
|
137
153
|
| Scope | The name collided with |
|
|
138
154
|
| --- | --- |
|
|
@@ -140,20 +156,21 @@ if (!result.ok) {
|
|
|
140
156
|
| `siblings` | Another child of the same container block. |
|
|
141
157
|
| `category` | Another category. |
|
|
142
158
|
| `resource` | Another resource, or another field on the same resource. |
|
|
143
|
-
| `query` | A member of the page controller, a route path
|
|
159
|
+
| `query` | A member of the page controller, a route path the page already serves, or a member of the resource's model. For a route path, `name` holds the endpoint. |
|
|
160
|
+
| `module` | A module. The type declares this scope, and no operation returns it now. |
|
|
144
161
|
|
|
145
|
-
### Validation
|
|
162
|
+
### Validation issues
|
|
146
163
|
|
|
147
|
-
`ValidationIssue` addresses a failure by JSON pointer into the request
|
|
164
|
+
`ValidationIssue` addresses a failure by a JSON pointer into the request.
|
|
148
165
|
|
|
149
166
|
| Field | Type | Description |
|
|
150
167
|
| --- | --- | --- |
|
|
151
|
-
| `pointer` | `string` | A JSON pointer into the
|
|
152
|
-
| `message` | `string` | What is wrong
|
|
168
|
+
| `pointer` | `string` | A JSON pointer into the input that failed, such as `/where/0/op`. Empty when the failure is not tied to one key. |
|
|
169
|
+
| `message` | `string` | What is wrong. It often names the operation that lists the valid values. |
|
|
153
170
|
|
|
154
|
-
### Typecheck
|
|
171
|
+
### Typecheck errors
|
|
155
172
|
|
|
156
|
-
`TypecheckError` is one TypeScript diagnostic from the in-memory typecheck
|
|
173
|
+
`TypecheckError` is one TypeScript diagnostic from the in-memory typecheck.
|
|
157
174
|
|
|
158
175
|
| Field | Type | Description |
|
|
159
176
|
| --- | --- | --- |
|
|
@@ -161,21 +178,21 @@ if (!result.ok) {
|
|
|
161
178
|
| `line` | `number` | The line number. |
|
|
162
179
|
| `message` | `string` | The diagnostic message. |
|
|
163
180
|
|
|
164
|
-
|
|
181
|
+
The engine collects diagnostics across the whole project, outside `node_modules`, and not only in the file the operation edited. A change that breaks code elsewhere fails before anything is written.
|
|
165
182
|
|
|
166
|
-
## Make a
|
|
183
|
+
## Make a write conditional
|
|
167
184
|
|
|
168
|
-
`MutationOpts` is the trailing options argument of
|
|
185
|
+
`MutationOpts` is the trailing options argument of the mutations that check a version. Not every mutation takes it.
|
|
169
186
|
|
|
170
187
|
| Option | Type | Description |
|
|
171
188
|
| --- | --- | --- |
|
|
172
|
-
| `expectedVersion` | `string` | The version the
|
|
189
|
+
| `expectedVersion` | `string` | The version the caller last read. A mismatch fails with `stale`. |
|
|
173
190
|
|
|
174
|
-
The operations that edit something that already exists take it: `ConfigurePage`, `DeletePage`, `AddBlock`, `ConfigureBlock`, `MoveBlock`, `RemoveBlock`, `DeleteResource`, `AddField`, `ConfigureField`, `RemoveField`, `AddQuery`, `ConfigureQuery` and `
|
|
191
|
+
The operations that edit something that already exists take it: `ConfigurePage`, `DeletePage`, `AddBlock`, `ConfigureBlock`, `MoveBlock`, `RemoveBlock`, `SetPageBlocks`, `ConfigureResource`, `DeleteResource`, `AddField`, `ConfigureField`, `RemoveField`, `AddQuery`, `ConfigureQuery`, `RemoveQuery`, `ConfigureTableView` and `ComposePage`. The three creations, `CreatePage`, `CreateCategory` and `CreateResource`, take no options argument. Neither do `ConfigureCategory` and `DeleteCategory`.
|
|
175
192
|
|
|
176
|
-
The version comes from the structure you read
|
|
193
|
+
The version comes from the structure you read. A page operation takes `PageStructure.version`, and a resource operation takes `ResourceStructure.version`. Both are content hashes, of the page file and of the resource's two generated files.
|
|
177
194
|
|
|
178
|
-
```typescript
|
|
195
|
+
```typescript fragment
|
|
179
196
|
import {
|
|
180
197
|
ConfigureBlock,
|
|
181
198
|
GetPageStructure,
|
|
@@ -192,11 +209,11 @@ const write = await ConfigureBlock(
|
|
|
192
209
|
{ expectedVersion: read.data.version },
|
|
193
210
|
);
|
|
194
211
|
if (!write.ok && write.error.code === "stale") {
|
|
195
|
-
// `write.error.currentVersion` is
|
|
196
|
-
//
|
|
212
|
+
// `write.error.currentVersion` is the file's hash now.
|
|
213
|
+
// Read the structure again, decide again, and retry.
|
|
197
214
|
}
|
|
198
215
|
```
|
|
199
216
|
|
|
200
|
-
|
|
217
|
+
Without `expectedVersion`, the write is unconditional. Pass it when a person or another process can change the file between your read and your write.
|
|
201
218
|
|
|
202
|
-
Two operations extend `MutationOpts` with options of their own
|
|
219
|
+
Two operations extend `MutationOpts` with options of their own. `ConfigureBlockOpts` adds `replace` and `meta`, described in [Page operations](./4.page-operations.md). `DeleteResourceOpts` adds `keepData`, described in [Resources](./5.resources.md).
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: "Drafts and preview"
|
|
3
|
+
description: "SetPageBlocks writes a page's whole block tree and its queries in one transaction, PreviewLayout serializes a draft without writing it, and PreviewQuery runs an unsaved query against the real table."
|
|
4
|
+
mode: reference
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
`PreviewLayout` serializes a page draft without writing files. `SetPageBlocks` saves the draft's complete block tree in one transaction. A successful preview does not mean that the draft compiles, because only the write runs the typecheck.
|
|
4
8
|
|
|
5
9
|
> **Warning:** `SetPageBlocks` replaces the whole block tree. Blocks you omit are removed. For one small change to an existing page, use `ConfigureBlock` instead.
|
|
6
10
|
|
|
7
11
|
## Preview one card
|
|
8
12
|
|
|
9
|
-
With an existing `/dashboard` page, this read-only example returns a serialized KPI card. An editor can render `preview.data.components.total
|
|
13
|
+
With an existing `/dashboard` page, this read-only example returns a serialized KPI card. An editor can render `preview.data.components.total`. No source file changes.
|
|
10
14
|
|
|
11
15
|
```typescript
|
|
12
16
|
import { PreviewLayout } from "@antelopejs/interface-dms-builder";
|
|
@@ -22,26 +26,26 @@ if (preview.ok) {
|
|
|
22
26
|
}
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
Each per-block operation saves at once. A visual editor usually holds its edits locally and calls `SetPageBlocks` once. The block tree and its queries then pass one typecheck together, or the page stays unchanged.
|
|
26
30
|
|
|
27
|
-
## Describe a
|
|
31
|
+
## Describe a draft
|
|
28
32
|
|
|
29
33
|
`PageDraft` is a page as you want it written.
|
|
30
34
|
|
|
31
35
|
| Field | Type | Description |
|
|
32
36
|
| --- | --- | --- |
|
|
33
|
-
| `page` | `Partial<EditablePageMeta>` | Metadata to patch alongside the blocks. Omit to leave
|
|
34
|
-
| `blocks` | `BlockDraft[]` | The top-level blocks, in
|
|
35
|
-
| `queries` | `AddQueryInput[]` | The queries the page
|
|
37
|
+
| `page` | `Partial<EditablePageMeta>` | Metadata to patch alongside the blocks. Omit it to leave the metadata alone. |
|
|
38
|
+
| `blocks` | `BlockDraft[]` | The top-level blocks, in page order. |
|
|
39
|
+
| `queries` | `AddQueryInput[]` | The queries the page serves, written with the blocks. Omit it to leave the page's queries alone. |
|
|
36
40
|
|
|
37
|
-
A block and the data it reads are one edit, so they are one write
|
|
41
|
+
A block and the data it reads are one edit, so they are one write. The blocks, the model methods and the routes land in a single transaction with a single typecheck, or none of them land.
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
An omitted `queries` and an empty array differ. An omitted `queries` leaves the queries the page already serves untouched. An empty array says that the page serves none, and removes the generated ones. Two queries in a draft with the same name fail with `invalid_config`.
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
A draft never removes or rewrites these two kinds of query:
|
|
42
46
|
|
|
43
|
-
- **A query edited past the grammar
|
|
44
|
-
- **A query the draft
|
|
47
|
+
- **A query edited past the grammar.** The write leaves it exactly as it is, whether the draft still lists it or not, and reports a `query_opaque` warning. The builder cannot read the chain, so a person owns it.
|
|
48
|
+
- **A query the draft left out while a block still reads it.** The write keeps the query when a block on the page still names its URL, and reports a `query_kept` warning. Removing the query would break that block.
|
|
45
49
|
|
|
46
50
|
```typescript
|
|
47
51
|
import { SetPageBlocks } from "@antelopejs/interface-dms-builder";
|
|
@@ -74,20 +78,21 @@ await SetPageBlocks("/shop/board", {
|
|
|
74
78
|
|
|
75
79
|
| Field | Type | Description |
|
|
76
80
|
| --- | --- | --- |
|
|
77
|
-
| `name` | `string` |
|
|
78
|
-
| `type` | `string` | A `BlockTypeDescriptor.type` from the catalog.
|
|
79
|
-
| `config` | `
|
|
81
|
+
| `name` | `string` | The static key (top level) or the `.child()` id (nested). Must be a valid identifier. |
|
|
82
|
+
| `type` | `string` | A `BlockTypeDescriptor.type` from the catalog. Required unless `preserve` is set. On a preserved block, a `type` that differs from the one on disk is refused. |
|
|
83
|
+
| `config` | `ConfigObject` | The factory's options. Leave out locked options, because the server keeps their source. A preserved block takes no `config`. |
|
|
84
|
+
| `lockedOptions` | `Record<string, string>` | Read-only UI hints copied from `GetPageStructure`. The server derives option locks from its own source. |
|
|
80
85
|
| `slot` | `string` | The slot the block sits in. |
|
|
81
|
-
| `meta` | `
|
|
86
|
+
| `meta` | `ConfigObject` | Child metadata emitted with `slot`, such as `{ colSpan: 2 }` on a grid child. |
|
|
82
87
|
| `controller` | `ResourceRef` | Required for a controller-leading type such as `TableView`. |
|
|
83
88
|
| `children` | `BlockDraft[]` | Nested blocks, in `.child()` order. |
|
|
84
89
|
| `preserve` | `boolean` | Write the block back exactly as it stands on disk. |
|
|
85
90
|
|
|
86
|
-
## Carry an
|
|
91
|
+
## Carry an opaque block through a write
|
|
87
92
|
|
|
88
|
-
A whole-tree write has to
|
|
93
|
+
A whole-tree write has to keep the blocks that the builder can read but not rewrite. These include a `CustomComponent`, a block behind a computed expression, and any block that `GetPageStructure` reported with `editable: false`. Set `preserve` on such a block. The write matches the block by name among its siblings and writes its source text back untouched. A locked block without `preserve` is refused.
|
|
89
94
|
|
|
90
|
-
To change only the page title, preserve every top-level block
|
|
95
|
+
To change only the page title, preserve every top-level block. A preserved block keeps its children, so you do not rebuild editable blocks from part of their configuration:
|
|
91
96
|
|
|
92
97
|
```typescript
|
|
93
98
|
import {
|
|
@@ -111,11 +116,13 @@ if (structure.ok) {
|
|
|
111
116
|
}
|
|
112
117
|
```
|
|
113
118
|
|
|
114
|
-
When you
|
|
119
|
+
When you edit a block, supply its full draft, including its `children`, `slot`, `meta` and `controller` where they apply. Do not reduce a block tree to names and configuration objects, because the write deletes omitted children.
|
|
120
|
+
|
|
121
|
+
The children of a preserved block are read-only. If a preserved block lists `children`, each child must also be preserved, with the names, slots and metadata it has on disk. A block with locked options keeps its type, its controller and the placement of its children, and the draft cannot copy it to another path.
|
|
115
122
|
|
|
116
123
|
A `preserve` block whose name matches nothing on disk is rejected with `invalid_config`.
|
|
117
124
|
|
|
118
|
-
## Write a
|
|
125
|
+
## Write a whole page
|
|
119
126
|
|
|
120
127
|
```typescript
|
|
121
128
|
import { GetPageStructure, SetPageBlocks } from "@antelopejs/interface-dms-builder";
|
|
@@ -154,32 +161,35 @@ const result = await SetPageBlocks(
|
|
|
154
161
|
if (!result.ok) throw new Error(result.error.code);
|
|
155
162
|
```
|
|
156
163
|
|
|
157
|
-
Read the version immediately before
|
|
164
|
+
Read the version immediately before you prepare the draft. If the write returns `stale`, read the page again and review the other editor's changes before you retry.
|
|
158
165
|
|
|
159
|
-
On success the result carries the staged `changes` and the page's new `version
|
|
166
|
+
On success, the result carries the staged `changes` and the page's new `version`. Pass that `version` as the next `expectedVersion`.
|
|
160
167
|
|
|
161
|
-
|
|
168
|
+
The write removes the blocks that the draft leaves out. It leaves static members that are not blocks where they are. It drops a named import that the file used before the write and no longer uses. An import that was already unused before the write stays.
|
|
162
169
|
|
|
163
|
-
`$expr` is refused anywhere in a draft
|
|
170
|
+
`$expr` is refused anywhere in a draft, including `page` and a block's `meta`. A whole-tree write stays structured, and arbitrary code would break that guarantee. `$dataType`, `$ref` and `$block` are accepted. See [Value encodings](./7.values.md).
|
|
164
171
|
|
|
165
|
-
## Read the
|
|
172
|
+
## Read the failures
|
|
166
173
|
|
|
167
|
-
`SetPageBlocks` validates the whole draft before
|
|
174
|
+
`SetPageBlocks` validates the whole draft before it touches anything. One call reports every problem at once as an `invalid_config` issue, each addressed by a JSON pointer into the draft:
|
|
168
175
|
|
|
169
176
|
| Pointer | Cause |
|
|
170
177
|
| --- | --- |
|
|
171
178
|
| `/blocks/1/name` | Not a valid identifier, or a duplicate among its siblings. |
|
|
172
|
-
| `/blocks/2/type` |
|
|
173
|
-
| `/blocks/
|
|
179
|
+
| `/blocks/2/type` | An unknown block type. |
|
|
180
|
+
| `/blocks/2/children` | Children on a block type that takes none. |
|
|
181
|
+
| `/blocks/2/children/0/type` | A child type that the container does not accept. |
|
|
182
|
+
| `/blocks/0/controller` | A controller-leading type without a controller, or a controller on a type that takes none. |
|
|
174
183
|
| `/blocks/3/config/title` | `$expr` inside a config value. |
|
|
184
|
+
| `/blocks/4` | A `preserve` block with no match on disk, a locked block without `preserve`, or a change to a preserved block. |
|
|
175
185
|
|
|
176
|
-
Beyond `invalid_config`, the write fails the same way the per-block operations
|
|
186
|
+
Beyond `invalid_config`, the write fails the same way as the per-block operations. It returns `stale` when `expectedVersion` no longer matches, and `typecheck_failed` when the emitted source does not compile. In both cases nothing is written. See [Results and errors](./8.results-and-errors.md).
|
|
177
187
|
|
|
178
|
-
## Preview a
|
|
188
|
+
## Preview a draft
|
|
179
189
|
|
|
180
|
-
`PreviewLayout` serializes a draft the way the runtime would,
|
|
190
|
+
`PreviewLayout` serializes a draft the way the runtime would, through the block factories of `@antelopejs/interface-dms/base` that the emitted source calls. It runs no typecheck and writes nothing to disk, so an editor can run it on every edit.
|
|
181
191
|
|
|
182
|
-
```typescript
|
|
192
|
+
```typescript fragment
|
|
183
193
|
const preview = await PreviewLayout("/dashboard", draft);
|
|
184
194
|
if (preview.ok) {
|
|
185
195
|
const grid = preview.data.components.kpis; // ComponentPreview
|
|
@@ -190,14 +200,22 @@ if (preview.ok) {
|
|
|
190
200
|
|
|
191
201
|
| Field | Type | Description |
|
|
192
202
|
| --- | --- | --- |
|
|
193
|
-
| `components` | `Record<string, ComponentPreview>` | The serialized tree, keyed by top-level block name
|
|
194
|
-
| `degraded` | `BlockPath[]` | Blocks the preview could not build faithfully. |
|
|
203
|
+
| `components` | `Record<string, ComponentPreview>` | The serialized tree, keyed by top-level block name. The DMS frontend renders this shape. |
|
|
204
|
+
| `degraded` | `BlockPath[]` | Blocks that the preview could not build faithfully. |
|
|
205
|
+
|
|
206
|
+
A degraded block appears in `components` as a placeholder that names the reason. A block lands in `degraded` in these cases:
|
|
195
207
|
|
|
196
|
-
|
|
208
|
+
- It is a `preserve` block, or a block with locked options, which the draft does not describe.
|
|
209
|
+
- Its type is unknown.
|
|
210
|
+
- It is a controller-leading block, such as `TableView`, with no `controller`, or with a resource whose DataAPI class the running app has not loaded. A table created a moment ago is not loaded until the app reloads.
|
|
211
|
+
- Its config holds an `$expr`, or a `$ref` to a resource whose DataAPI class the running app has not loaded.
|
|
212
|
+
- Its factory threw.
|
|
197
213
|
|
|
198
|
-
|
|
214
|
+
For a degraded block, render the last known-good layout rather than trust the preview.
|
|
199
215
|
|
|
200
|
-
|
|
216
|
+
## Preview a query
|
|
217
|
+
|
|
218
|
+
`PreviewLayout` shows what the page looks like. `PreviewQuery` shows the data its blocks display. It runs a query that is not saved and answers what its route would, so an editor can configure a source against real data before anything is written.
|
|
201
219
|
|
|
202
220
|
```typescript
|
|
203
221
|
import { PreviewQuery } from "@antelopejs/interface-dms-builder";
|
|
@@ -225,17 +243,35 @@ if (result.ok) {
|
|
|
225
243
|
|
|
226
244
|
| Field | Type | Description |
|
|
227
245
|
| --- | --- | --- |
|
|
228
|
-
| `query` | `AddQueryInput` |
|
|
229
|
-
| `args` | `
|
|
230
|
-
| `tenant` | `string` | Whose rows to read, for a resource in a per-tenant schema. |
|
|
246
|
+
| `query` | `AddQueryInput` | The query to run. The template validates its parameters as it does for `AddQuery`. |
|
|
247
|
+
| `args` | `ConfigObject` | The values the route would receive, under the names the route exposes. |
|
|
248
|
+
| `tenant` | `string` | Whose rows to read, for a resource in a per-tenant schema. A resource in any other schema ignores it. |
|
|
249
|
+
|
|
250
|
+
`QueryPreview` holds the route's own response body and how it is arranged:
|
|
251
|
+
|
|
252
|
+
| Field | Type | Description |
|
|
253
|
+
| --- | --- | --- |
|
|
254
|
+
| `output` | `QueryOutputKind` | `"scalar"` or `"series"`, as `GetPageStructure` reports the saved query. |
|
|
255
|
+
| `response` | `QueryArrangement` | Set only when a DMS helper arranged the body, the same condition under which read-back reports it. |
|
|
256
|
+
| `body` | `QueryResponseBody` | What the route would return. |
|
|
257
|
+
| `truncated` | `boolean` | `true` when the preview stopped at 500 points. |
|
|
258
|
+
|
|
259
|
+
The body depends on the calculation and on `response`:
|
|
260
|
+
|
|
261
|
+
- A scalar calculation answers `{ value }`, whatever `response` asks for.
|
|
262
|
+
- A grouped calculation with no `response`, or with `response: "series"`, answers `{ series }` and leaves `response` unset.
|
|
263
|
+
- `response: "card"`, `"value"` and `"items"` answer the body that `chartCardData`, `kpiCardData` and `topListData` from `@antelopejs/interface-dms/base/query-response` build. The generated route calls the same helper, so `"card"` answers a `ChartCardData`, headline figure included, and a block can take it directly.
|
|
231
264
|
|
|
232
|
-
|
|
265
|
+
A query is filters, a grouping and a measure. It has no way to express a write, so a preview only reads. It stops at 500 points and sets `truncated`, so a chart that lost its tail says so.
|
|
233
266
|
|
|
234
|
-
|
|
267
|
+
`PreviewQuery` answers every failure as a failed `OpResult`, never as a rejected promise:
|
|
235
268
|
|
|
236
|
-
|
|
269
|
+
- `not_found` for an unknown resource.
|
|
270
|
+
- `invalid_config` for an unknown template or invalid parameters.
|
|
271
|
+
- `unsupported` when the resource's schema is not registered, when a bound value has no argument in `args`, or when the database refuses the query.
|
|
237
272
|
|
|
238
|
-
|
|
273
|
+
## Next steps
|
|
239
274
|
|
|
240
|
-
- [
|
|
241
|
-
- [
|
|
275
|
+
- [A chart without code](./10.a-chart-without-code.md) follows these calls from the choice of a measure to the reopened page.
|
|
276
|
+
- [Results and errors](./8.results-and-errors.md) shows how to branch on `OpResult` and handle `stale`.
|
|
277
|
+
- [Catalog](./3.catalog.md) lists the block types, their schemas and their defaults.
|
|
Binary file
|
package/docs/tsconfig.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-dms-builder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "AntelopeJS interface for the DMS builder: create and edit pages, blocks, resources and queries in a DMS project from another module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"prepack": "pnpm run build"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@antelopejs/interface-core": ">=0.
|
|
53
|
+
"@antelopejs/interface-core": ">=0.4.0 <1.0.0",
|
|
54
54
|
"release-it": "^19.2.4",
|
|
55
55
|
"release-it-changelogen": "^0.1.0",
|
|
56
56
|
"rimraf": "^6.1.3",
|
|
Binary file
|