@fieldia/core 0.24.0 → 0.26.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 +133 -1
- package/package.json +1 -1
- package/schema/page.schema.json +983 -329
- package/src/index.d.mts +6 -2
- package/src/index.d.ts +6 -2
- package/src/index.js +16 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +7 -2
- package/src/index.mjs.map +1 -1
- package/src/lib/format/actions.d.mts +31 -1
- package/src/lib/format/actions.d.ts +31 -1
- package/src/lib/format/actions.js +1 -0
- package/src/lib/format/actions.js.map +1 -1
- package/src/lib/format/actions.mjs +1 -0
- package/src/lib/format/actions.mjs.map +1 -1
- package/src/lib/format/duplicate-kinds.d.mts +10 -0
- package/src/lib/format/duplicate-kinds.d.ts +10 -0
- package/src/lib/format/duplicate-kinds.js +14 -0
- package/src/lib/format/duplicate-kinds.js.map +1 -0
- package/src/lib/format/duplicate-kinds.mjs +10 -0
- package/src/lib/format/duplicate-kinds.mjs.map +1 -0
- package/src/lib/format/duplicates.d.mts +22 -0
- package/src/lib/format/duplicates.d.ts +22 -0
- package/src/lib/format/duplicates.js +24 -0
- package/src/lib/format/duplicates.js.map +1 -0
- package/src/lib/format/duplicates.mjs +21 -0
- package/src/lib/format/duplicates.mjs.map +1 -0
- package/src/lib/format/field.d.mts +236 -0
- package/src/lib/format/field.d.ts +236 -0
- package/src/lib/format/field.js +4 -3
- package/src/lib/format/field.js.map +1 -1
- package/src/lib/format/field.mjs +2 -1
- package/src/lib/format/field.mjs.map +1 -1
- package/src/lib/format/head-checks.d.mts +3 -1
- package/src/lib/format/head-checks.d.ts +3 -1
- package/src/lib/format/head-checks.js +25 -4
- package/src/lib/format/head-checks.js.map +1 -1
- package/src/lib/format/head-checks.mjs +24 -4
- package/src/lib/format/head-checks.mjs.map +1 -1
- package/src/lib/format/import-fields.d.mts +18 -0
- package/src/lib/format/import-fields.d.ts +18 -0
- package/src/lib/format/import-fields.js +26 -0
- package/src/lib/format/import-fields.js.map +1 -0
- package/src/lib/format/import-fields.mjs +21 -0
- package/src/lib/format/import-fields.mjs.map +1 -0
- package/src/lib/format/layout.d.mts +7391 -3264
- package/src/lib/format/layout.d.ts +7391 -3264
- package/src/lib/format/layout.js +100 -37
- package/src/lib/format/layout.js.map +1 -1
- package/src/lib/format/layout.mjs +99 -36
- package/src/lib/format/layout.mjs.map +1 -1
- package/src/lib/format/layout.types.d.mts +5 -2
- package/src/lib/format/layout.types.d.ts +5 -2
- package/src/lib/format/page.d.mts +1018 -118
- package/src/lib/format/page.d.ts +1018 -118
- package/src/lib/format/page.js +17 -0
- package/src/lib/format/page.js.map +1 -1
- package/src/lib/format/page.mjs +17 -0
- package/src/lib/format/page.mjs.map +1 -1
- package/src/lib/format/records.d.mts +23 -0
- package/src/lib/format/records.d.ts +23 -0
- package/src/lib/format/records.js +28 -0
- package/src/lib/format/records.js.map +1 -0
- package/src/lib/format/records.mjs +25 -0
- package/src/lib/format/records.mjs.map +1 -0
- package/src/lib/format/references.d.mts +31 -0
- package/src/lib/format/references.d.ts +31 -0
- package/src/lib/format/references.js +185 -24
- package/src/lib/format/references.js.map +1 -1
- package/src/lib/format/references.mjs +185 -24
- package/src/lib/format/references.mjs.map +1 -1
- package/src/lib/format/translate.js +12 -6
- package/src/lib/format/translate.js.map +1 -1
- package/src/lib/format/translate.mjs +12 -6
- package/src/lib/format/translate.mjs.map +1 -1
- package/src/lib/format/upgrade.d.mts +8 -3
- package/src/lib/format/upgrade.d.ts +8 -3
- package/src/lib/format/upgrade.js +8 -3
- package/src/lib/format/upgrade.js.map +1 -1
- package/src/lib/format/upgrade.mjs +8 -3
- package/src/lib/format/upgrade.mjs.map +1 -1
- package/src/lib/format/version.d.mts +2 -2
- package/src/lib/format/version.d.ts +2 -2
- package/src/lib/format/version.js +2 -2
- package/src/lib/format/version.js.map +1 -1
- package/src/lib/format/version.mjs +2 -2
- package/src/lib/format/version.mjs.map +1 -1
- package/src/lib/record/check.js +2 -2
- package/src/lib/record/check.js.map +1 -1
- package/src/lib/record/check.mjs +3 -3
- package/src/lib/record/check.mjs.map +1 -1
- package/src/lib/record/data-source.d.mts +121 -0
- package/src/lib/record/data-source.d.ts +121 -0
- package/src/lib/record/data-source.js +16 -0
- package/src/lib/record/data-source.js.map +1 -1
- package/src/lib/record/data-source.mjs +15 -0
- package/src/lib/record/data-source.mjs.map +1 -1
- package/src/lib/record/form.d.mts +51 -3
- package/src/lib/record/form.d.ts +51 -3
- package/src/lib/record/form.js +78 -17
- package/src/lib/record/form.js.map +1 -1
- package/src/lib/record/form.mjs +79 -18
- package/src/lib/record/form.mjs.map +1 -1
- package/src/lib/record/inputs.js +8 -8
- package/src/lib/record/inputs.js.map +1 -1
- package/src/lib/record/inputs.mjs +9 -9
- package/src/lib/record/inputs.mjs.map +1 -1
- package/src/lib/record/limits.js +1 -1
- package/src/lib/record/limits.js.map +1 -1
- package/src/lib/record/limits.mjs +2 -2
- package/src/lib/record/limits.mjs.map +1 -1
- package/src/lib/record/locales/de.js +2 -0
- package/src/lib/record/locales/de.js.map +1 -1
- package/src/lib/record/locales/de.mjs +2 -0
- package/src/lib/record/locales/de.mjs.map +1 -1
- package/src/lib/record/memory-data-source.d.mts +12 -5
- package/src/lib/record/memory-data-source.d.ts +12 -5
- package/src/lib/record/memory-data-source.js +85 -1
- package/src/lib/record/memory-data-source.js.map +1 -1
- package/src/lib/record/memory-data-source.mjs +86 -2
- package/src/lib/record/memory-data-source.mjs.map +1 -1
- package/src/lib/record/memory-duplicates.d.mts +19 -0
- package/src/lib/record/memory-duplicates.d.ts +19 -0
- package/src/lib/record/memory-duplicates.js +78 -0
- package/src/lib/record/memory-duplicates.js.map +1 -0
- package/src/lib/record/memory-duplicates.mjs +74 -0
- package/src/lib/record/memory-duplicates.mjs.map +1 -0
- package/src/lib/record/messages.d.mts +24 -0
- package/src/lib/record/messages.d.ts +24 -0
- package/src/lib/record/messages.js +25 -0
- package/src/lib/record/messages.js.map +1 -1
- package/src/lib/record/messages.mjs +24 -0
- package/src/lib/record/messages.mjs.map +1 -1
- package/src/lib/record/record-words.d.mts +19 -0
- package/src/lib/record/record-words.d.ts +19 -0
- package/src/lib/record/record-words.js +60 -0
- package/src/lib/record/record-words.js.map +1 -0
- package/src/lib/record/record-words.mjs +56 -0
- package/src/lib/record/record-words.mjs.map +1 -0
- package/src/lib/record/rules.js +1 -1
- package/src/lib/record/rules.js.map +1 -1
- package/src/lib/record/rules.mjs +2 -2
- package/src/lib/record/rules.mjs.map +1 -1
- package/src/lib/record/run.d.mts +39 -1
- package/src/lib/record/run.d.ts +39 -1
- package/src/lib/record/run.js +15 -1
- package/src/lib/record/run.js.map +1 -1
- package/src/lib/record/run.mjs +15 -1
- package/src/lib/record/run.mjs.map +1 -1
- package/src/lib/record/search.js +2 -1
- package/src/lib/record/search.js.map +1 -1
- package/src/lib/record/search.mjs +2 -1
- package/src/lib/record/search.mjs.map +1 -1
- package/src/lib/record/structures.js +3 -3
- package/src/lib/record/structures.js.map +1 -1
- package/src/lib/record/structures.mjs +4 -4
- package/src/lib/record/structures.mjs.map +1 -1
- package/src/lib/record/waits.d.mts +32 -0
- package/src/lib/record/waits.d.ts +32 -0
- package/src/lib/record/waits.js +89 -0
- package/src/lib/record/waits.js.map +1 -0
- package/src/lib/record/waits.mjs +85 -0
- package/src/lib/record/waits.mjs.map +1 -0
- package/src/runtime.d.mts +13 -7
- package/src/runtime.d.ts +13 -7
- package/src/runtime.js +13 -3
- package/src/runtime.js.map +1 -1
- package/src/runtime.mjs +4 -1
- package/src/runtime.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ list of records — that your app implements;
|
|
|
28
28
|
The page format is also a JSON Schema, for editors and other languages:
|
|
29
29
|
`@fieldia/core/page.schema.json`.
|
|
30
30
|
|
|
31
|
-
A page says which format it is written in (`"fieldia": "0.
|
|
31
|
+
A page says which format it is written in (`"fieldia": "0.5"`, `FORMAT_VERSION`; a page in 0.1, 0.2, 0.3 or 0.4 is read as it is).
|
|
32
32
|
One in an older format is brought up to date as it is read — by `checkPage`,
|
|
33
33
|
`validatePage` and `createForm`, so by the viewer and the designer too — and
|
|
34
34
|
`upgradePage` does it for the pages your app keeps. One newer than this Fieldia
|
|
@@ -63,6 +63,21 @@ settings each kind has are `PART_LOOKS`:
|
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
## Values that wait for a line
|
|
67
|
+
|
|
68
|
+
A value worked out from others waits while one of them holds text that does
|
|
69
|
+
not read — "abc" in a line's Quantity — as the table's own total does, so it is
|
|
70
|
+
never shown counting the value that text replaced. Who works it out does not
|
|
71
|
+
matter: the page (a `compute`, such as `sum(lines, 'subtotal')`, and what is
|
|
72
|
+
worked out from that in turn) or your app (an amount or totals kept whole, read
|
|
73
|
+
only, which a source with an `onchange` works out as the lines change — a sales
|
|
74
|
+
order's Untaxed, Taxes and Total, Flectra's `tax_totals`). `form.waitsFor(field)`
|
|
75
|
+
says what it waits for — `{ field: 'line_ids', line: 1, column: 'qty' }`, the line
|
|
76
|
+
as people count lines, or `{ field: 'rate' }` for a field of the record's own —
|
|
77
|
+
and null when it shows its value; the viewer draws it as a dash, said in words
|
|
78
|
+
("Fix line 1 of Order lines to see Untaxed amount"). An answer your onchange
|
|
79
|
+
gives meanwhile is kept, and shown once the line reads.
|
|
80
|
+
|
|
66
81
|
## A public form's bot check
|
|
67
82
|
|
|
68
83
|
A page of responses anyone may send — a sign-up, a contact form — can check that
|
|
@@ -202,6 +217,94 @@ const dataSource = createMemoryDataSource({
|
|
|
202
217
|
});
|
|
203
218
|
```
|
|
204
219
|
|
|
220
|
+
## Possible duplicates and Merge
|
|
221
|
+
|
|
222
|
+
A record's page may name the fields records like the one typed are found by —
|
|
223
|
+
the same phone, email or tax id, a name close enough:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{ "duplicates": { "fields": ["name", "phone", "email", "vat"], "on": "type" } }
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The data source's `duplicates({ model, recordId, values, fields })` is asked
|
|
230
|
+
with the fields named that hold a value (none: nothing is asked), every value of
|
|
231
|
+
the form and the record typed (null while new), and answers with the records
|
|
232
|
+
like it — `{ matches: [{ id, name, why: ['phone'], score? }] }`, `why` naming
|
|
233
|
+
the fields each matched on. `on: "type"` (the default) asks as those fields are
|
|
234
|
+
typed in, as a saved record opens and as it is saved; `"save"` only as it is
|
|
235
|
+
saved. Nothing is in the way of a save. `merge({ model, keepId, mergeIds,
|
|
236
|
+
values, fields })` keeps `keepId` with the value picked for each field and takes
|
|
237
|
+
`mergeIds` away; moving what was theirs (messages, activities, links) is the
|
|
238
|
+
source's work, and `saveRefused({ kind: 'rule', message })` refuses it.
|
|
239
|
+
`form.findDuplicates()`, `form.readRecord(id)` and `form.merge(…)` ask the
|
|
240
|
+
source for a screen of your own, `form.canFindDuplicates()` and
|
|
241
|
+
`form.canMerge()` say whether it can; the viewer says each match under the field
|
|
242
|
+
it matched on, with Open it, "It's someone new" and Merge (`@fieldia/viewer`).
|
|
243
|
+
`checkPage` and `validatePage` refuse a field the page has not, one named twice,
|
|
244
|
+
and one of a kind records are not compared by (`DUPLICATE_KINDS`). Without
|
|
245
|
+
`duplicates` in the source, nothing is asked. For demos and tests,
|
|
246
|
+
`alikeRecords()` answers from the memory source's records — the same value as
|
|
247
|
+
people write them apart (a phone's spaces, an email's case, a link's record) or,
|
|
248
|
+
in the name field, a name close enough (`nameLikeness`) — and its `merge`
|
|
249
|
+
merges as a backend would:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import { alikeRecords, createMemoryDataSource } from '@fieldia/core';
|
|
253
|
+
|
|
254
|
+
const dataSource = createMemoryDataSource({ records, duplicates: alikeRecords() });
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## What a page's records are called
|
|
258
|
+
|
|
259
|
+
A page may say what its records are, so Fieldia's own sentences name them as
|
|
260
|
+
the business does — "A customer with this phone already exists", "17 customers
|
|
261
|
+
imported", "Are you sure you want to delete this customer?", "New customer" —
|
|
262
|
+
where they said "record", or no noun at all:
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{ "records": { "one": "customer", "other": "customers", "a": "a customer" }, "lowerLabels": true }
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`one` and `other` are the words for one record and for more, as they stand
|
|
269
|
+
inside a sentence; a sentence that counts picks one of them as its language does
|
|
270
|
+
for the number. `a` is one with its article, where the language puts one before
|
|
271
|
+
it ("an invoice", "une facture"): Fieldia never guesses an article, so a
|
|
272
|
+
sentence that needs one says "A record …" until it is given.
|
|
273
|
+
|
|
274
|
+
The page's own `lowerLabels`, beside `records` (label casing is no part of what
|
|
275
|
+
records are called), writes a field's label with a small first letter wherever one of
|
|
276
|
+
Fieldia's sentences puts it after a word of it — the form's messages ("Choose at
|
|
277
|
+
least 2 for interests", "End date can’t be before start date"), a refused save's
|
|
278
|
+
"Not saved. Check: email", a value that waits ("Fix tax rate to see total"), a
|
|
279
|
+
help's, a lock's and a link's × names, a possible duplicate ("A customer with
|
|
280
|
+
this phone already exists"), a conflict ("They changed: phone."), a column's
|
|
281
|
+
grip, a filter's menu, a search's suggestion, a history's "changed status to …"
|
|
282
|
+
— while a label that begins its sentence keeps its capital: "Phone is
|
|
283
|
+
required", and a heading's place, "Status: nothing is called …" (an import's
|
|
284
|
+
refusals, an input's). Off unless said, since only the page knows whether that
|
|
285
|
+
is right: a label whose first word is a name ("IBAN", "VAT number", "WhatsApp",
|
|
286
|
+
"E-mail") stays as written, its first letter alone ever changes ("found in
|
|
287
|
+
Build"), and every label stays as written in a language that writes its nouns
|
|
288
|
+
with a capital (German) or has none (Arabic). One rule says it, `labelAt(template,
|
|
289
|
+
key, lower, locale)`; the form's messages carry the page's ask as
|
|
290
|
+
`messages.lowerLabels` (`fillMessage`). A page asks it with its records named or
|
|
291
|
+
not, a survey too. A line's own dialog says its labels as its record's page asks — a part
|
|
292
|
+
of the same record — unless the line's own page (`lineOpens: "record"`) says
|
|
293
|
+
otherwise; a list's Edit dialog as the list's page asks. Other languages come through the
|
|
294
|
+
page's `translations`, as its other words do (`"customer": "عميل"`), and
|
|
295
|
+
`pageWords` lists them for a translator.
|
|
296
|
+
|
|
297
|
+
The form's own sentences say them — what it asks before the gear menu's Archive
|
|
298
|
+
and Delete, why a person may not change, archive, copy or delete one, why a run
|
|
299
|
+
of steps stopped, what letting changes go asks — and the viewer's (a list's, a
|
|
300
|
+
record's, possible duplicates', a related list's in its model page's words: see
|
|
301
|
+
`@fieldia/viewer`). Each such sentence is a message of its own beside the plain
|
|
302
|
+
one (`deleteConfirmNoun`: "Are you sure you want to delete this {record}?",
|
|
303
|
+
with `{record}`, `{records}` and `{aRecord}`); `recordSentence(records, named,
|
|
304
|
+
plain, locale)` says one. A language, or an app's own `messages`, that has no
|
|
305
|
+
such sentence says its plain one: a page that names no records reads as before.
|
|
306
|
+
`checkPage` and `validatePage` refuse a word for one or for more left out.
|
|
307
|
+
|
|
205
308
|
## Two people, one record
|
|
206
309
|
|
|
207
310
|
A source that keeps versions returns each record with its version, and what this
|
|
@@ -289,6 +392,35 @@ says which fields Edit offers. `createMemoryDataSource` gives `allIds` and
|
|
|
289
392
|
`writeMany` (each record refused as its save would be), and no `exportRecords`.
|
|
290
393
|
See [many records at once](https://fieldia.dev/data/#many).
|
|
291
394
|
|
|
395
|
+
## Records that point at this one
|
|
396
|
+
|
|
397
|
+
A page's `related` part lists another model's records whose link is this
|
|
398
|
+
record — a customer's invoices — inside it (the viewer draws it). Its
|
|
399
|
+
`model`, `field` (their many2one to this page's model), `fields` and `columns`
|
|
400
|
+
say what it lists; `filter`, `sort`, `limit`, `cells`, `searchFields`,
|
|
401
|
+
`viewAll` and `create` the rest. `form.relatedFilter(id)` gives what it asks
|
|
402
|
+
the data source's `list` for, as the source gets it: the link to the record
|
|
403
|
+
shown, then its own filter with each `valueFrom` read from that record — or null
|
|
404
|
+
before the record's first save. No new data source member: `list` answers it.
|
|
405
|
+
The page check holds its columns, order, search and cells to its own `fields`,
|
|
406
|
+
its link to a many2one of theirs to this model, and it to a record's page. A
|
|
407
|
+
tab holding one may count its records (`"count": { "related": "<its id>" }`,
|
|
408
|
+
`TabCount`); the check holds that id to a related list inside the tab, and
|
|
409
|
+
`relatedInTab(tab, id)` finds it there. `"open": "app"` sends its rows and New
|
|
410
|
+
the app's own way first (the viewer's `onOpen`), a dialog where it does not take
|
|
411
|
+
them.
|
|
412
|
+
|
|
413
|
+
A list's Import makes records from a file's rows. `createMany({ model, records,
|
|
414
|
+
fields })` makes many at once and answers each in order: `{ id }`, or `{ message,
|
|
415
|
+
problem? }` for one it refused; without it the list saves each as a new record,
|
|
416
|
+
`save(newRecordSave(model, fields, values))`. `importRecords({ model, file,
|
|
417
|
+
columns, rows, fields, locale, dateOrder })` takes the file on the server once
|
|
418
|
+
its columns are matched: answer `{ message }`, or `false` to let the browser
|
|
419
|
+
import it. A page offers Import with its list's `import` (`true`, or the
|
|
420
|
+
fields); `importFields(page, list)` says which fields a file's columns may fill.
|
|
421
|
+
`createMemoryDataSource` gives `createMany`. See [many records made at
|
|
422
|
+
once](https://fieldia.dev/data/#import).
|
|
423
|
+
|
|
292
424
|
## A saved form placed in another
|
|
293
425
|
|
|
294
426
|
A block made once — an address, a contact person, a consent — is a page of its
|
package/package.json
CHANGED