@ai-matrx/records 0.83.1 → 0.84.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/CHANGELOG.md +18 -1
- package/dist/data/index.cjs +9 -1
- package/dist/data/index.cjs.map +1 -1
- package/dist/data/index.js +9 -1
- package/dist/data/index.js.map +1 -1
- package/dist/react/index.cjs +9 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +9 -1
- package/dist/react/index.js.map +1 -1
- package/dist/templates/index.cjs +4 -1
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.js +4 -1
- package/dist/templates/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
+
## 0.84.0 — an empty box is no value; a link is never sorted by its ids
|
|
4
|
+
|
|
5
|
+
- **`createTableDataPort` writes "" as null for every column that is not words** (`blankToNull`, exported from
|
|
6
|
+
`./data/table-port`): a cleared date input sent `post_date: ""` and `record_write` refused it ("Post Date
|
|
7
|
+
takes a date") with nothing on screen (Applets live test, 2026-10-08). Text columns keep "".
|
|
8
|
+
- **A sort by a link (relation) column is refused by name** ("\"Brand\" is a link, so the store cannot sort
|
|
9
|
+
by it."): the store would order by the ids in the cell, a sort that looks like it did nothing.
|
|
10
|
+
- Tests red→green in `src/__tests__/an-empty-box-is-no-value-and-a-link-is-never-sorted-by-id.test.ts`.
|
|
11
|
+
- **Consumer action:** a page that sorted a table source by a link field sorts its rows on the page by the
|
|
12
|
+
links' labels (`@ai-matrx/applets` `sortRows`).
|
|
13
|
+
|
|
14
|
+
## 0.83.2
|
|
15
|
+
|
|
16
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
17
|
+
`git diff npm/records/v0.83.1..npm/records/v0.83.2 -- apps/shared/records`).
|
|
18
|
+
No source changes intended and no consumer action required.
|
|
19
|
+
|
|
3
20
|
## 0.83.1
|
|
4
21
|
|
|
5
22
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
@@ -20,7 +37,7 @@ Consumer action: `parseFormula` / `FORMULA_FUNCTIONS` from `@ai-matrx/records`
|
|
|
20
37
|
## 0.82.1
|
|
21
38
|
### lane DESCRIBE-BENCH2 (sweep): the mechanical wrong shapes are read, not refused
|
|
22
39
|
|
|
23
|
-
- `autofixDescribeSpec` also rewrites, each with an auto-fix note and only when unambiguous: view `filters` written as a list of `{field, op, value}` (→ the store's map; several values → `anyOf`; a condition the store cannot express is dropped and SAID), `sort`/`orderBy` → `sorts`, `group_by`/`date_field`/… → `groupBy`/`dateField`/…, an exact duplicate view dropped; a field typed with `kind`/`type` (or by a plain label) → `parityType`; a formula over bare field names → `{Label}`; a relationship `inverseKey` that is already a field of the target (the store then read the rollup's link as a plain formula) renamed; a rollup named for a status with no filter → the filter when exactly one far-side choice/tick box is that word; a real-looking phone → a fictional one; a copy of the shared team_member block → an ordinary table (name, role, notes) — never a table whose fields are exactly one the person already has (a link-only reuse is not changed).
|
|
40
|
+
- `autofixDescribeSpec` also rewrites, each with an auto-fix note and only when unambiguous: view `filters` written as a list of `{field, op, value}` (→ the store's map; several values → `anyOf`; a condition the store cannot express is dropped and SAID), `sort`/`orderBy` → `sorts`, `group_by`/`date_field`/… → `groupBy`/`dateField`/…, an exact duplicate view dropped; a field typed with `kind`/`type` (or by a plain label) → `parityType`; a formula over bare field names → `{Label}`; a relationship `inverseKey` that is already a field of the target (the store then read the rollup's link as a plain formula) renamed; a rollup named for a status with no filter → the filter when exactly one far-side choice/tick box is that word; a real-looking phone → a fictional one; a copy of the shared team_member block → an ordinary table (name, role, notes) — never a table whose fields are exactly one the person already has (a link-only reuse is not changed, and `describeCheck` no longer calls it a copy of the shared block).
|
|
24
41
|
- `describeVocabulary()` gains `view_filters_shape`, `field_shape`, `formula_shape`, `relationship_shape`, `phone_rule`, `team_rule`.
|
|
25
42
|
|
|
26
43
|
## Earlier in this release — a rollup or lookup in the wrong shape is read, not refused
|
package/dist/data/index.cjs
CHANGED
|
@@ -214,6 +214,9 @@ function compileSort(sort, shape) {
|
|
|
214
214
|
for (const s of sort ?? []) {
|
|
215
215
|
const column = shape.columns.find((c) => c.key === s.column);
|
|
216
216
|
if (!column) return { ok: false, error: noSuchColumn(s.column) };
|
|
217
|
+
if (column.type === "relation") {
|
|
218
|
+
return { ok: false, error: refusal(`"${column.label}" is a link, so the store cannot sort by it.`, "Sort the rows on the page by each link's label. Nothing was read.") };
|
|
219
|
+
}
|
|
217
220
|
const as = isNumberColumn(column.type) ? "number" : isDateColumn(column.type) ? "date" : "text";
|
|
218
221
|
out.push({ field: column.key, direction: s.direction === "desc" ? "desc" : "asc", as });
|
|
219
222
|
}
|
|
@@ -6072,6 +6075,11 @@ function relationIdsOf(value) {
|
|
|
6072
6075
|
}
|
|
6073
6076
|
return out;
|
|
6074
6077
|
}
|
|
6078
|
+
var WORD_TYPES = /* @__PURE__ */ new Set(["text", "long_text", "rich_text", "email", "url", "phone", "markdown"]);
|
|
6079
|
+
function blankToNull(type, value) {
|
|
6080
|
+
if (typeof value === "string" && value.trim() === "" && !WORD_TYPES.has(type)) return null;
|
|
6081
|
+
return value;
|
|
6082
|
+
}
|
|
6075
6083
|
function createTableDataPort({ client, aliases }) {
|
|
6076
6084
|
const shapes = /* @__PURE__ */ new Map();
|
|
6077
6085
|
let warnedNotLive = false;
|
|
@@ -6145,7 +6153,7 @@ function createTableDataPort({ client, aliases }) {
|
|
|
6145
6153
|
if (!column) return refuse2("invalid_argument", `This table has no column "${key}".`, "Ask columns() for the keys this table has now. Nothing was saved.");
|
|
6146
6154
|
if (column.readOnly) return refuse2("invalid_argument", `"${column.label}" is worked out by the table, so it cannot be written.`, "Nothing was saved.");
|
|
6147
6155
|
const kinds = column.type === "relation" ? entityKindsOf(shape.fields.get(key)) : [];
|
|
6148
|
-
out[key] = kinds.length ? entityRefsOf2(value, kinds) : column.type === "relation" ? relationIdsOf(value) : value;
|
|
6156
|
+
out[key] = kinds.length ? entityRefsOf2(value, kinds) : column.type === "relation" ? relationIdsOf(value) : blankToNull(column.type, value);
|
|
6149
6157
|
}
|
|
6150
6158
|
return { ok: true, data: out };
|
|
6151
6159
|
}
|