Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.

Commit 6e5635d

Browse files
committed
Merge origin/main into claude/issue-7611-setup-catalog-registry (objectui#7611 stage-1 patch round)
Claude-Session: https://claude.ai/code/session_01Rerax7QTjKMPCUZxQUtPFR Co-authored-by: Claude <noreply@anthropic.com>
2 parents 98d46eb + 5330afd commit 6e5635d

111 files changed

Lines changed: 4999 additions & 536 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.
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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
An app that serves the signed-in user no navigation now opens on an app-level empty state, not on the Studio home (objectui#12079).
7+
8+
The server filters an app's navigation per user. When every group is gated on a capability the user does not hold, the app arrives with `navigation: []`. The console's app index route found no landing page and rendered `StudioHomePage`, Studio's metadata overview, inside an app that had nothing to do with Studio. This was measured on HotCLM for its dev admin (objectstack-ai/hotclm#87).
9+
10+
The app root now shows "Nothing in APP is available to you yet", with the app's own label. A user the console treats as a workspace administrator (`useWorkspaceAdminStatus`, the same check the console's no-app screen and Home's administration links use) gets an "Open Setup" link, at the URL the `/setup` deep link resolves. Everyone else is asked to contact an administrator.
11+
12+
Unchanged:
13+
14+
- An app with a landing page still opens on it.
15+
- The Studio app still opens on its own home. Its navigation is full but holds only `component` items, which the landing resolver does not walk, so it reaches the same fallback with a non-empty navigation.
16+
17+
New `@object-ui/i18n` keys, in all ten language packs: `empty.appNothingAvailable`, `empty.appNothingAvailableDescription`, `empty.appNothingAvailableGrantDescription` and `empty.openSetup`.
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
The console asks for recent activity only when the signed-in user may read it, and a failed read no longer shows as "No recent activity" (objectui#12081, item 8).
6+
7+
The header bell's Activity tab, the `global:notifications` page block and Home's activity card share one `sys_activity` read. It went out for every signed-in user on every page. A user whose permission sets grant no read on `sys_activity` (every non-admin on a deployment whose app sets do not name it) got `403` each time, and all three surfaces then said "No recent activity".
8+
9+
- **No read without the grant.** The feed now checks the user's read permission on `sys_activity` from the permissions the console already loads (`/auth/me/permissions`). A user without it gets no request. The bell offers no Activity tab, and Home shows no activity card. When permissions are not loaded (no permission provider is mounted, or the permissions request failed), the read still goes out as before.
10+
- **A failed read says so.** The Activity tab and Home's card now show "An unexpected error occurred." when the read fails, a refusal included, and "Loading…" while it is in flight. "No recent activity" appears only when the read has answered with no rows.
11+
- **The previous user's rows are not reused.** The server returns only the activity on records the reader can open. A sign-out keeps the console running, so the cached rows could be shown to the next user who signed in on the same tab. The cache is now kept per signed-in user.
12+
13+
Clause-②: no. Nothing is added to or removed from the package entry, and no locale key is added. `AppHeader`'s props are unchanged: rows a host passes as `activities` are shown as an answer, as before.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
'@object-ui/core': minor
3+
'@object-ui/plugin-view': patch
4+
'@object-ui/plugin-calendar': patch
5+
'@object-ui/plugin-kanban': patch
6+
'@object-ui/plugin-form': patch
7+
---
8+
9+
Five write affordances that read no grant at all now read the affordance-to-grant
10+
map, so a caller without the grant is no longer offered a write the server then
11+
refuses (objectui#12082, the card's remainder).
12+
13+
- **`object-view`'s New** (the toolbar button of the SDUI `object-view` node)
14+
reads the `listNew` row, as the console's list pages already did: the
15+
object's policy, the effective API operation set and the caller's create
16+
grant, on top of the node's `showCreate` / `operations.create` toggles.
17+
- **The calendar's quick-create** (an empty-day click, or a time-range drag in
18+
the week / day grid) reads the new `calendarQuickCreate` row, and
19+
**drag-to-reschedule** reads the new `calendarReschedule` row. A closed row
20+
withholds the handler the calendar grid draws the affordance from: no dialog
21+
on a day click, no range drag, no draggable event. A host-supplied
22+
`onDateClick` / `onEventDrop` is handed through unchanged.
23+
- **The kanban card move** reads the new `kanbanCardMove` row. A closed row
24+
draws the cards as not movable and hands the board no mover, so no drop
25+
reaches the write.
26+
- **A line-items panel's add and remove** (`record:line_items`) read the
27+
`relatedNew` and `relatedRowDelete` rows on the CHILD object, the same rows a
28+
related list reads for the same two writes. Add covers the Add button, the
29+
entry row and Duplicate; remove covers the per-row Remove.
30+
31+
With no permission provider mounted every one of them reads open, as before.
32+
33+
**Clause-②: yes (widening).** `AFFORDANCE_GRANTS`, exported from
34+
`@object-ui/core`, gains three rows: `calendarQuickCreate` (create),
35+
`calendarReschedule` (update) and `kanbanCardMove` (update), and with them the
36+
`ConsoleAffordance` union that `resolveAffordance` accepts. Nothing is removed or
37+
renamed. The other four packages change behaviour only.
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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@object-ui/plugin-list': minor
3+
'@object-ui/app-shell': minor
4+
---
5+
6+
List views read an absent `userActions.editInline` as on, the v18 protocol default (objectui#12086, the consumer half of objectstack#22605). A list view is editable in place by default, under the permission gate that already exists, and `userActions: { editInline: false }` makes it read-only in place.
7+
8+
**A list view that declares neither key.** The maintainer's v18 ruling flipped the spec's `ListViewSchema.userActions.editInline` from `.default(false)` to `.default(true)`. `ListView` (`@object-ui/plugin-list`) reads an absent `editInline` as on (`!== false`). A grid view that declares neither `userActions.editInline` nor `inlineEdit` offers the inline-edit toggle, on the wide toolbar and in the compact settings popover, and opens out of edit mode. The previous release offered it there too, reading an absent key as "defer to the host"; objectui#5144 read it off on unreleased `main` only, and its entry in this release states the default as on. The fold objectui#5144 added is unchanged.
9+
10+
**Behaviour change: the ADR-0047 interface page (`@object-ui/app-shell`).** The page reads its config's `userActions.editInline` with the same default and hands it to `ListView` as the grid's edit mode, because the page wires no inline-edit toggle. A page that declares nothing now opens its grid editable in place; `editInline: false` keeps it read-only.
11+
12+
**Unchanged.**
13+
14+
- The permission gate. The toggle, the compact entry and the edit mode are offered only where the object is editable in place and the current principal holds `update` on it. A principal without the grant sees no toggle.
15+
- The `inlineEdit` fold (objectui#5144): `inlineEdit: true` reads on and opens the grid in edit mode, `inlineEdit: false` reads off, and an explicit `editInline` wins either way.
16+
- The console toggle stays session-only (objectui#5144, ruling E).
17+
18+
**What to do.** A list whose records are read-only by nature (a log, an audit trail, a history, a roll-up) declares `userActions: { editInline: false }`. A view or overlay where an earlier console stored `inlineEdit: false` still reads off; declaring `userActions.editInline: true` brings the toggle back.
19+
20+
Nothing is added to a package entry: no export, prop, type member or language-pack key. (The bump is `minor` by this repo's release model: objectui's major follows the `@objectstack` family major, and its own behaviour changes ship as `minor` with the semantics stated here.)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': minor
4+
---
5+
6+
After a marketplace install into the environment the console is rendering, the package page waits until that environment serves the installed package's app, and only then refreshes and persists the app list (objectui#12087).
7+
8+
A cloud install answers once the control plane has written the installation. The environment's runtime then rebuilds its kernel and keeps serving the kernel from before the install until the rebuild lands (about 60 s, measured on staging). The page used to refresh the metadata cache the moment the install answered. That refresh read the pre-install app list, and the cache kept it, in memory and in the tab's session seed. The page said "Installed successfully", and the app never appeared in that tab.
9+
10+
- **Wait.** The page reads `GET /meta/app` past the cache, at once and then every 5 s for up to 5 minutes, until an app's `_packageId` is the package's manifest id. Only then does it drop the session seed, refresh the cache and send the metadata-changed signal. No app list read during the wait is persisted. The 5 minutes bound the wait; they do not estimate the rebuild.
11+
- **Say what is happening.** Until the app is served, the dialog, and the page once the dialog is closed, show "Deploying the app…" (「正在部署应用…」). When it is served, they show that the app is ready and offer "Open {name}" (「打开 {name}」).
12+
- **Say what is not known.** When the wait expires, the page says the install was recorded but the app has not appeared yet, names the possible reasons, and offers "Check again". It does not claim success, and it refreshes nothing.
13+
- The install-time suggested audience bindings mount once the app is served, so their one read reaches the rebuilt runtime.
14+
- An install into another environment shows the same success message as before. It no longer refreshes this console's own metadata, which that install did not change.
15+
16+
Five language-pack keys are added under `marketplace.install` (`deploying`, `deployed`, `openApp`, `deployTimeout`, `checkAgain`), in all ten packs. The exported `en` pack, and the `TranslationKeys` type derived from it (`typeof en`, exported from the `@object-ui/i18n` entry), gain these five members under `marketplace.install`, which is why `@object-ui/i18n` is a minor bump. No export, prop or type on the `@object-ui/app-shell` entry changes.
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`).

‎.changeset/5144-editinline-fold.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
'@object-ui/plugin-view': patch
66
---
77

8-
List views read `userActions.editInline` with the spec's default, off. A view's `inlineEdit` folds into it, and the console's inline-edit toggle no longer writes to the view (objectui#5144).
8+
List views read `userActions.editInline` with the spec's default, on since objectstack-ai/objectstack#22605 (`editInline: z.boolean().default(true)`), and `editInline: false` is the opt-out. A view's `inlineEdit` folds into it, and the console's inline-edit toggle no longer writes to the view (objectui#5144).
99

10-
**Breaking for a view that relied on the old default.** The spec declares `userActions.editInline` with `.default(false)`: the list is read-only unless the author opts in. The interface page already read it that way. The object-list toolbar did not: it read an absent `editInline` as "defer to the host", so every console grid offered the inline-edit toggle unless a view said `editInline: false`. The toolbar now reads it as the spec does. A grid view that declares neither `userActions.editInline` nor `inlineEdit` no longer offers the inline-edit toggle, on the wide toolbar or in the compact settings popover, and never opens in edit mode.
10+
**The spec's default, read as declared.** The spec declares `userActions.editInline` with `.default(true)` (objectstack-ai/objectstack#22605): a list view is editable in place by default, under the permission gate, and `editInline: false` is the opt-out. The object-list toolbar used to read an absent `editInline` as "defer to the host", so every console grid offered the inline-edit toggle unless a view said `editInline: false`. The toolbar now reads it as the spec does. A grid view that declares neither `userActions.editInline` nor `inlineEdit` offers the inline-edit toggle, on the wide toolbar and in the compact settings popover, and opens out of edit mode. The flip of the default, and the interface page that reads it, are the objectui#12086 entry of this release.
1111

1212
**The fold.** `normalizeListViewSchema` (`@object-ui/core`) now folds a boolean `inlineEdit` into `userActions.editInline`, the way it already folds the `show*` flags into the other toggles:
1313

1414
- `inlineEdit: true` reads as `editInline: true`: the toggle is offered and the grid opens in edit mode;
1515
- `inlineEdit: false` reads as `editInline: false`: no toggle;
1616
- an explicit `userActions.editInline` wins over `inlineEdit`, in both directions;
17-
- a view with neither key reads off.
17+
- a view with neither key reads on, the spec's default.
1818

1919
`inlineEdit` stays on the folded view, because `ListView` opens the grid in edit mode from it. Nothing migrates stored views.
2020

2121
**The console toggle is session-only (`@object-ui/app-shell`).** Both keys are the author's permission. The console's toolbar toggle used to store a user's edit mode in the view's `inlineEdit`; after the fold, switching it off would have taken the toggle away for good. It now writes nothing. The toggle switches edit mode for the session, and each load starts from the view's own `inlineEdit`. `ListView` still reports the toggle through `onInlineEditChange`.
2222

2323
**A named view's `inlineEdit` keeps its precedence (`@object-ui/plugin-view`).** On a host's `renderListView`, `ObjectView` merges `userActions` from the node, the host's `views` entry and the active named view, the named view last. The named view's `userActions` now go through the same fold as the other two. So a named view's `inlineEdit` decides whether inline editing is offered ahead of a host entry's, as it already decided the edit mode.
2424

25-
**What to do.** A view that should offer inline editing declares `userActions.editInline: true`. The toggle then stays offered whatever the user does with it. Two costs come with the session-only toggle:
25+
**What to do.** A list whose records are read-only by nature declares `userActions.editInline: false`. A view that declares `userActions.editInline: true` keeps the toggle offered whatever the user does with it. Two costs come with the session-only toggle:
2626

2727
- the edit mode is not remembered across loads;
2828
- a view, or a personalization overlay, where the old toggle stored `inlineEdit: false` still reads off. That is existing data, and it is not migrated. Declaring `userActions.editInline: true` on the view brings the toggle back.

0 commit comments

Comments
 (0)