Skip to content

Commit b6fc38b

Browse files
Merge branch 'main' into claude/issue-12079-empty-nav-landing
2 parents 02569f3 + ce991bd commit b6fc38b

33 files changed

Lines changed: 1626 additions & 216 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
The record chatter stores each reaction as the member's own `sys_comment_reaction` record, and stops writing the whole `sys_comment.reactions` column (objectui#12078; ruling A, amended, on objectstack-ai/objectstack#22505).
6+
7+
A reaction click used to write the comment's whole reaction set back with one `sys_comment` update. Two members reacting at the same moment therefore left only the later write stored. A member who could read a record but not edit it could not react to another member's comment either, because that update is the comment author's (or a parent editor's) to make.
8+
9+
- **Read.** After the comment read, the chatter reads the comments' reactions in one `sys_comment_reaction` read, `comment_id` `$in` the comment ids, and groups the rows into the reactions the panel already renders. It never reads per comment. A thread of more than 100 comments is read in pages of 100 ids, in parallel, which keeps each request URL near 4.6 KB.
10+
- **Write.** A click creates the member's own reaction row (`comment_id`, `emoji`; the server stamps `user_id`), and a second click deletes that row. Nothing else is written, so another member's reaction can no longer be overwritten, and both of two simultaneous reactions stay. A refused write puts the reaction back and shows the same "Your reaction was not saved" error as before.
11+
- **Reactions stored only in the column are not shown** where the object exists. The maintainer ruled that the column's reactions need no migration.
12+
- **A deployment without `sys_comment_reaction` keeps the column path, unchanged.** This covers a framework that predates objectstack-ai/objectstack#22566, such as cloud's v17 pin. The chatter asks the object registry it already loads. Only an earned "absent" answer keeps the column path; a registry that lists nothing, or has not answered, is not read as absence. The comment read waits until the registry has answered.
13+
14+
Nothing on the package entry changes: no export, prop, type member or language-pack key. `CommentThread` (`@object-ui/collaboration`) and `Reaction` (`@object-ui/types`) are untouched.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(console): a long flow screen or action parameter list keeps its Submit / Confirm on screen (objectui#12080)
6+
7+
A flow `screen` dialog without an object form, and the action parameter dialog, had no height bound. A screen or a `params` list taller than the window overflowed both edges of the fixed overlay: the heading above the top, the primary action below the bottom. The overlay locks page scrolling, so a mouse wheel moved nothing, and only keyboard focus could reach Submit.
8+
9+
Both dialogs are now at most `90vh` tall. The fields scroll in their own region between the header and a footer that stays on screen. A screen with more than eight declared fields, or a list of more than eight shown params, also gets the wider dialog an object-form step already had, with two columns from the `sm` breakpoint up. Shorter screens and lists keep their previous width and single column.
10+
11+
No new metadata key: the dialog sizes itself by the number of fields.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@object-ui/components': minor
3+
---
4+
5+
`element:repeater` and `element:number` publish the node-level `dataSource` binding as their only query input (objectui#12085). `@objectstack/spec` retires the element layer's flat binding keys as tombstones (objectstack#11509, objectstack PR #22421), and the repeater's registration still required a flat `object`, so the html-page validator refused a repeater bound through `dataSource` alone and accepted the spelling the spec retires.
6+
7+
**Narrowing, no widening.** The `element:repeater` registration drops its `object` (which was `required: true`), `filter`, `sort` and `limit` inputs. The `element:number` registration drops its `object` and `filter` inputs, which the metric has not read since objectui#11880. The injected `dataSource` input is unchanged on both. In the manifest these registrations feed, a repeater bound only through `dataSource` now draws no diagnostic (it drew `missing-required-prop`), and each of those six flat keys now draws `unknown-prop`. No export is added or removed, and no input is added.
8+
9+
**Rendering is unchanged.** The repeater still reads its flat `properties.object` / `filter` / `sort` / `limit` as the binding's fallback, for metadata written before the retirement. That read is not published as an authoring surface. The metric reads its query from `dataSource` only, as before.
10+
11+
objectstack's `sdui.manifest.json` is regenerated from these registrations at objectstack's next console pin bump; this release does not change that file.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
No release. objectui#12093 makes objectui compile against `@objectstack/spec` built from objectstack `main` (the Spec Main Shape Gate) while it keeps compiling, unchanged, against the installed release. The edits are tests, plus two type-only source edits with no runtime effect: `@object-ui/plugin-view`'s `ObjectView` reads the deprecated `table.defaultFilters` through a typed legacy read (the same value, read the same way, now typed by the rule-array shape legacy metadata carries rather than by the row's declaration, a retired-key tombstone on objectstack `main`), and `@object-ui/app-shell`'s zh-CN overlay-scope label table keys `org` beside the spec's union (objectstack `main` narrows that union to `env`).

‎apps/console/src/__tests__/objectname-binding-required-11605.test.ts‎

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,18 @@ const DOC_ROWS = bindingDocRows();
119119
/**
120120
* The key the binding's `object` lands on. The doc: "it lands on the block's
121121
* own object key, which is `objectName` everywhere except `record:line_items`"
122-
* (its row spells that key in the `object` column), and "The two `element:*`
123-
* rows keep their configuration in the node's `properties` bag ...
124-
* `dataSource.object` wins over `properties.object`".
122+
* (its row spells that key in the `object` column).
123+
*
124+
* `undefined` for the `element:*` blocks: each reads `dataSource.object`
125+
* itself, so the binding lands on no key of theirs (objectui#11880), and since
126+
* objectui#12085 neither `element:number` nor `element:repeater` publishes a
127+
* flat `object` for it to land on. Row 3 asserts that exception is exactly the
128+
* `element:*` tags, so it cannot quietly cover an `object-*` block.
125129
*/
126-
function objectKeyOf(tag: string): string {
130+
function objectKeyOf(tag: string): string | undefined {
127131
const named = /\(`([^`]+)`\)/.exec(DOC_ROWS.get(tag)?.object ?? '');
128132
if (named) return named[1];
129-
if (tag.startsWith('element:')) return 'object';
133+
if (tag.startsWith('element:')) return undefined;
130134
return 'objectName';
131135
}
132136

@@ -137,7 +141,8 @@ function objectKeyOf(tag: string): string {
137141
* are supplied too, but no registration requires one, so they are not read.
138142
*/
139143
function bindingSupplies(tag: string): Set<string> {
140-
const supplied = new Set([objectKeyOf(tag)]);
144+
const key = objectKeyOf(tag);
145+
const supplied = new Set<string>(key === undefined ? [] : [key]);
141146
const view = DOC_ROWS.get(tag)?.view ?? '';
142147
if (view === '✅' || view.includes('columns')) supplied.add('columns');
143148
return supplied;
@@ -234,11 +239,21 @@ describe('objectui#11605 — a bound registration requires no input its binding
234239
expect(undocumented, `${BINDING_DOC} must say what the binding supplies on each bound block`).toEqual([]);
235240
for (const tag of BOUND) {
236241
const key = objectKeyOf(tag);
242+
if (key === undefined) continue;
237243
expect(
238244
inputsOf(tag).map((input) => input.name),
239245
`<${tag}>: the binding's object lands on "${key}", which the entry does not declare`,
240246
).toContain(key);
241247
}
248+
// The exception is the `element:*` tags and nothing else, and it is not
249+
// vacuous: the two whose flat `object` objectui#12085 stopped publishing
250+
// are bound entries of the shipped manifest that declare no `object`.
251+
const landsNowhere = BOUND.filter((tag) => objectKeyOf(tag) === undefined);
252+
expect(landsNowhere.every((tag) => tag.startsWith('element:'))).toBe(true);
253+
for (const tag of ['element:number', 'element:repeater']) {
254+
expect(landsNowhere, tag).toContain(tag);
255+
expect(inputsOf(tag).map((input) => input.name), tag).not.toContain('object');
256+
}
242257
// Controls on the doc reading: the exception it names, and a full-view row.
243258
expect(objectKeyOf('record:line_items')).toBe('childObject');
244259
expect(bindingSupplies('object-grid').has('columns')).toBe(true);

0 commit comments

Comments
 (0)