Skip to content

Commit af4162e

Browse files
committed
Merge origin/main (7baede3) into claude/issue-10637-image-alt-translated
2 parents d139941 + 7baede3 commit af4162e

67 files changed

Lines changed: 5086 additions & 562 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.changeset/10475-default-arm-section-builder.md‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ render in the section's order, and every entry override applies: `required`
2222
refuses an empty submit, and `visibleWhen` hides the member until the record
2323
satisfies it. Two things stay as they were. First, a section member that the
2424
top-level `fields` does not list is still dropped, with its console warning,
25-
because the two keys intersect. Second, the form's own field definition
26-
remains the starting point for an override, so an override does not lift a
27-
managed object's field lock, and field-level security still hides or locks
28-
each member. The same fix reaches `object-master-detail-form`, whose parent
29-
form renders through this layout.
25+
because the two keys intersect. Second, at this change the form's own field
26+
definition remains the starting point for an override, so an override does not
27+
lift a managed object's field lock, and field-level security still hides or
28+
locks each member. The same fix reaches `object-master-detail-form`, whose
29+
parent form renders through this layout.
30+
31+
⚠️ **Dated note, 2026-09-25 — the managed-object field lock no longer rides the form's own field definition — objectui#10612.**
32+
Later in this same release the lock moved out of this layout's field generator
33+
into the one field-gate step every layout draws its fields through, after the
34+
section builder and together with field-level security. An override still does
35+
not lift the lock, but the reason is now that the lock is applied after the
36+
override, on every layout, rather than that it rides the definition the
37+
override starts from. The rest of this entry is kept as the reading of this
38+
change.

‎.changeset/10506-named-view-context-tokens.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ schema handed to `ObjectGrid`, and the `list-view` schema handed to a host's `re
1919
The relative-date macros (`{today}`, `{current_quarter_start}`, …) resolve in the same call, in
2020
the browser's local time, as they already did on the surfaces that call the resolver: the
2121
app-shell host, `ObjectChart` and the dashboard widgets. (A directly authored `object-grid` or
22-
`list-view` node still does not call it.) Where they used to reach a backend that resolves them
22+
`list-view` node calls it too, since objectui#10607.) Where they used to reach a backend that resolves them
2323
itself, as the ObjectStack server does in the tenant's configured `localization.timezone` (UTC by
2424
default), a browser whose local day differs from the server's day can now get a different day.
2525

‎.changeset/10516-xaxis-presentation-gate.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ carrying only `field` renders as before.
2020

2121
`position` on `xAxis` now survives normalization too, but at this change no renderer reads
2222
it: the x axis draws along the bottom whatever it says.
23+
24+
⚠️ **Dated note, 2026-09-25 — the renderer now reads `xAxis.position` — objectui#10587.**
25+
Later in this same release the x axis takes the side `position` names where that axis can
26+
run along it, and a side it cannot take draws the default side with a note naming the key.
27+
The sentence above is kept as the reading of this change; the objectui#10587 entry states
28+
what ships.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): three designer inspectors read their words in the designer's locale (objectui#10586)
6+
7+
`DatasetDefaultInspector`, `FlowReferenceField` (with the `ReferenceCombobox` it
8+
wraps) and `ConditionBuilder` rendered their section titles, field labels,
9+
placeholders, hints, option labels and accessible names as English literals, so a
10+
zh-CN author read an English form inside an otherwise Chinese designer.
11+
12+
Those strings now come from the designer's own string catalogue, under
13+
`engine.inspector.dataset.*`, `engine.inspector.reference.*` and
14+
`engine.inspector.condition.*`, plus the existing `engine.form.add` and
15+
`engine.form.searchFields`, each with an en and a zh row. The dataset inspector
16+
reads the `locale` its host already passes; the other two follow the active
17+
language through `useMetadataLocale()`. The en-US text is unchanged. Stored
18+
values, the `≥` / `≤` operator symbols, currency codes and decimal digits are not
19+
words and stay as they were.

‎.changeset/10587-xaxis-position.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
'@object-ui/plugin-charts': patch
3+
---
4+
5+
A chart's `xAxis.position` now places the x axis, and a side that axis cannot take is
6+
refused with a note that names the key (objectui#10587).
7+
8+
`position` is declared on `@objectstack/spec`'s `ChartAxisSchema`, which `xAxis` takes by
9+
reference, and since objectui#10516 the normalizer keeps it on the x-axis object. No axis
10+
read it, so `xAxis: { field: 'month', position: 'top' }` validated and still drew the axis
11+
along the bottom.
12+
13+
- **bar, line, area and scatter** (and a combo derived from its series' families): the x
14+
axis runs across the plot. `top` draws it along the top; `bottom` draws it along the
15+
bottom, the default.
16+
- **horizontal-bar**: the `xAxis` object configures the category axis, which runs down the
17+
plot there (its `format` already applied to that axis). `left` or `right` puts the
18+
category axis on that side; the default stays the left.
19+
- **A side the axis cannot take** (`left` / `right` across the plot, `top` / `bottom` on
20+
horizontal-bar) draws the axis at its default side, and the chart shows a note under the
21+
plot (`data-chart-note="x-axis-position"`) naming `xAxis.position`, the value, and the
22+
side the axis was drawn on. The value still validates: `ChartAxisSchema` is shared by the
23+
x and y axes, and this change does not narrow it.
24+
25+
A top axis also mirrors its title and its rotated tick labels, so both stay on the far side
26+
of the axis from the plot.
27+
28+
**User-visible render change** only for a chart whose `xAxis` declares `position`. The
29+
bottom / no-position controls in `ChartRenderer.xAxisPosition-10587.test.tsx` pin that a
30+
chart declaring none still draws its x axis along the bottom with no note.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
'@object-ui/plugin-list': patch
4+
---
5+
6+
A directly authored `object-grid` or `list-view` node resolves the spec's context tokens in its own filter (objectui#10607).
7+
8+
`filter: [['owner', '=', '{current_user_id}']]` on an `object-grid` or `list-view` node authored
9+
straight into a page, not reached through `object-view`, went out on `$filter` as the literal
10+
token: neither package called `@object-ui/core`'s `resolveFilterPlaceholders`. Each now resolves
11+
the node's own filter once through that shared resolver, with the session scope the host provides
12+
through `useFilterScope` (the console shell mounts `FilterScopeProvider` from the signed-in user
13+
and the active organization). On `object-grid` that is `filter` and its deprecated alias
14+
`defaultFilters`: the resolved `filter` feeds the grid's query and its server-side export, and the
15+
resolved alias feeds the query when `filter` is absent. On
16+
`list-view` it is `filter`, and the resolved value feeds the list's query, the child view it
17+
renders, the self-querying views (gantt, tree, chart), the export and the empty-state copy.
18+
`object-view` has done this since objectui#10506; these two nodes, authored directly, had not.
19+
20+
The relative-date macros (`{today}`, `{current_quarter_start}`, …) resolve in the same call, in
21+
the browser's local time, as on the other surfaces that call the resolver. Where they used to
22+
reach a backend that resolves them itself, as the ObjectStack server does in the tenant's
23+
configured `localization.timezone` (UTC by default), a browser whose local day differs from the
24+
server's day can now get a different day.
25+
26+
A token the scope cannot resolve is left as written and the resolver warns once, which is the
27+
resolver's own rule, so the filter is never widened.
28+
29+
The resolved value is held against its inputs: the authored filter, compared by structure, and the
30+
scope's three members (`currentUserId`, `currentOrgId`, `onUnresolved`), each compared on its own.
31+
A re-render that changes none of them does not refetch, including one that rebuilds an equal
32+
filter inline; a new signed-in user refetches with the new id. Date macros are therefore resolved
33+
once and held until the scope or the authored filter changes, and a refetch for another reason
34+
reuses the held value. `object-view` already hands these nodes a filter it has resolved
35+
(objectui#10506); resolving that value again changes nothing, because a resolved id or date no
36+
longer matches the placeholder pattern.
37+
38+
On `object-grid`, the load effect now also refetches when the resolved `defaultFilters` changes (a
39+
new signed-in user, or an in-place edit of the alias). It read that alias without keying on it
40+
before.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/plugin-form': patch
3+
---
4+
5+
Every `object-form` layout now locks a managed object's fields, as the simple form does (objectui#10612).
6+
7+
**Clause-②: no.** No exported symbol, type or prop changes. The shared step lives in `fieldWriteGate.ts`, an internal module that `index.tsx` does not re-export. What changes is which inputs the `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts draw enabled.
8+
9+
**Before.** ADR-0092 D4 locks a form on a managed object: when the object's CRUD affordance for the form's mode is closed, every field is disabled. The affordance comes from the object's `managedBy` bucket, its `userActions` opt-in (`create` on a create form, `edit` on an edit form) and the server's effective API operations. Only the simple form applied this lock, inside its own field generator. The `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts drew live inputs on, for example, a `managedBy: 'better-auth'` object with no `userActions.create`, and the server then refused the save. The layouts disagreed with each other on the same object for the same user.
10+
11+
**What changed, in observable terms.**
12+
13+
- The `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts, flat or sectioned, now disable every field of an object whose affordance for the form's mode is closed. This covers a managed bucket that does not open the mode, and any object whose `create` or `update` the server's effective API operations deny. The simple form did this already.
14+
- The lock and field-level security now run as one step that every layout calls on the fields it has resolved. A field the caller may not read is dropped, and a field they may read but not edit is locked, on every layout, as before.
15+
- ⚠️ On the simple form, an inline `customFields` member, and a section entry already written as a full field definition, are now locked with the rest of a managed object's fields. The lock used to be set only on the fields the simple form generated from the object, so those two escaped it.
16+
- The lock sets `disabled` only, as it did on the simple form. No message is added, and the submit button stays on screen on every layout. The server's write guard is still what refuses the write.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@object-ui/plugin-timeline': patch
3+
'@object-ui/plugin-list': patch
4+
'@object-ui/plugin-map': patch
5+
'@object-ui/components': patch
6+
---
7+
8+
Five more page blocks re-read when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a write to the object they read (objectui#10623). These blocks read neither `onMutation` nor the bus, so any write — through the data source or past it (a page action over raw HTTP, a flow, a server action) — showed only when something remounted them. Each fetch effect now names the `useDataInvalidation` nonce for its object; an unscoped change (`'*'`) matches too, and a change to another object does not.
9+
10+
- `@object-ui/plugin-timeline`: `object-timeline` re-reads its rows; a canvas that already shows rows stays mounted while the re-read runs.
11+
- `@object-ui/plugin-list`: `object-gallery` re-reads its cards; collapsed groups stay collapsed.
12+
- `@object-ui/plugin-map`: `object-map` re-reads the markers it is showing without its loading placeholder, so the map stays mounted and the camera stays where the user left it. If that re-read fails, the last markers stay on the map and the failure is logged to the console, as `ObjectGantt`'s background refresh does. A changed query still shows the placeholder and re-fits the camera, even when a bus event arrives with it. Two older faults in the same fetch are fixed as well: a slow earlier answer can no longer overwrite a newer one, and a load that succeeds now takes the map off an earlier error screen.
13+
- `@object-ui/components`: `element:number` re-reads its aggregate and `element:repeater` its rows.
14+
15+
Rows a host hands these blocks (`data`, `bind`, authored `items`, an inline `value` set) are still the host's to refresh; only the blocks' own queries follow the bus.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@object-ui/core": patch
3+
---
4+
5+
`@object-ui/core` now exports the native date/time control adapters `toDateInputValue`, `toDateTimeInputValue`, `fromDateTimeInputValue` and `isImpossibleStoredDay` (objectui#10625). They moved down from `@object-ui/fields` unchanged, next to `isRealCalendarDate`, so the data table in `@object-ui/components` can use the same set instead of private copies. Their behaviour is unchanged: a stored day that does not exist (such as `2026-02-30`) is never rolled to a real one.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@object-ui/components": patch
3+
---
4+
5+
The data table's inline date editors no longer roll or silently blank a stored day that does not exist (objectui#10625). A `datetime` column holding `2026-02-30T10:00:00Z` used to open on 2 March, so an edit of only the minutes saved that day; a `date` column holding `2026-02-30` opened empty with no marker. Both editors now use the shared adapters from `@object-ui/core`, the same ones the form's date widgets use. For such a value the control is empty, marked `aria-invalid`, and described by a notice that names the stored value (the existing `fields.date.impossibleDay` and `fields.dateTime.impossibleDay` messages). Pressing Enter without an edit keeps the stored value as it was. Real dates open and save as before.

0 commit comments

Comments
 (0)