Skip to content

Commit d508400

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-7tu0bz
# Conflicts: # scripts/sdui-manifest.record.json
2 parents a811401 + 6d15aca commit d508400

95 files changed

Lines changed: 2372 additions & 1995 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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@objectstack/core': patch
3+
'@objectstack/mcp': patch
4+
'@objectstack/plugin-audit': patch
5+
'@objectstack/plugin-hono-server': patch
6+
---
7+
8+
refactor(core)!: `resolveLocalizationContext` takes the organization as `organizationId`; the `tenantId` key is retired
9+
10+
Clause-②: no (narrowing)
11+
Metadata-protocol: none
12+
13+
<!-- adr-0087: not-required (runtime-export-retired @objectstack/core#ResolveLocalizationInput.tenantId) the retired member is a key of a published runtime TypeScript input with no Zod schema, no spec declaration and no stored shape; the compiler reports it at every object-literal call that still spells it, and nothing exists for `objectstack migrate meta` to rewrite -->
14+
15+
**BREAKING** for a TypeScript caller of `resolveLocalizationContext` from `@objectstack/core`. The key that names the organization to localize for is renamed. There is no alias and no deprecation window.
16+
17+
`ResolveLocalizationInput.tenantId` always meant the **organization** id: the settings service stores and reads `localization` under the organization (ADR-0131 D8), and the direct `sys_setting` fallback reads that organization's rows. The name did not say so, and an environment id passed there type-checked. It matched no organization's settings, so every non-UTC organization silently resolved its timezone as `UTC`, and the date boundaries cut from it moved with it. The key is now `organizationId`, and the resolver reads no other spelling at run time.
18+
19+
- FROM `ResolveLocalizationInput.tenantId` TO `ResolveLocalizationInput.organizationId`: pass the caller's organization id under the new key, `resolveLocalizationContext({ ql, settings, organizationId, userId })`. Never pass an environment id.
20+
21+
**Who moves.** A caller that builds the input as an object literal with `tenantId` gets a compile error (excess property) and makes the one-key fix above. A caller that builds it some other way, such as spreading an object that holds `tenantId` or passing a variable typed wider than the input, does not get that error: its `tenantId` is ignored and the resolver localizes as for a caller with no organization, so grep for `tenantId` beside `resolveLocalizationContext`. In this repository the four callers (`@objectstack/core`'s request execution context, `@objectstack/mcp`, `@objectstack/plugin-audit` and `@objectstack/plugin-hono-server`) are migrated here and behave as before.
22+
23+
**Not moved.** The settings service's own scope argument, `{ tenantId, userId }` on `get` / `getMany`, keeps its spelling. It is a separate surface with its own callers. The resolver passes the organization id there as before.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
---
4+
5+
fix(platform-objects): the zh-CN label for an organization's logo reads 「徽标」, no longer 「标识」, which read as the slug (「标识符」) on the same record page and in the Rename Organization dialog
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`sys_organization.fields.logo.label` in the zh-CN bundle was 「标识」 ("identifier"), directly beside the slug's 「标识符」. The Rename Organization and Edit Organization dialogs take their `logo` param label from this field label, so a zh-CN admin read the logo URL input as the organization's identifier. ja-JP (「ロゴ」 / 「スラッグ」) and es-ES (「Logotipo」 / 「Slug」) had no such collision and are unchanged.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
"@object-ui/app-shell": minor
3+
"@object-ui/auth": minor
4+
"@object-ui/cli": minor
5+
"@object-ui/collaboration": minor
6+
"@object-ui/components": minor
7+
"@object-ui/console": minor
8+
"@object-ui/core": minor
9+
"@object-ui/create-plugin": minor
10+
"@object-ui/data-objectstack": minor
11+
"@object-ui/fields": minor
12+
"@object-ui/i18n": minor
13+
"@object-ui/layout": minor
14+
"@object-ui/mobile": minor
15+
"@object-ui/permissions": minor
16+
"@object-ui/plugin-ai": minor
17+
"@object-ui/plugin-calendar": minor
18+
"@object-ui/plugin-charts": minor
19+
"@object-ui/plugin-chatbot": minor
20+
"@object-ui/plugin-dashboard": minor
21+
"@object-ui/plugin-designer": minor
22+
"@object-ui/plugin-detail": minor
23+
"@object-ui/plugin-editor": minor
24+
"@object-ui/plugin-form": minor
25+
"@object-ui/plugin-gantt": minor
26+
"@object-ui/plugin-grid": minor
27+
"@object-ui/plugin-kanban": minor
28+
"@object-ui/plugin-list": minor
29+
"@object-ui/plugin-map": minor
30+
"@object-ui/plugin-markdown": minor
31+
"@object-ui/plugin-report": minor
32+
"@object-ui/plugin-timeline": minor
33+
"@object-ui/plugin-tree": minor
34+
"@object-ui/plugin-view": minor
35+
"@object-ui/providers": minor
36+
"@object-ui/react": minor
37+
"@object-ui/react-runtime": minor
38+
"@object-ui/sdui-parser": minor
39+
"@object-ui/types": minor
40+
---
41+
42+
**BREAKING** Object UI's changes from its 18.1.0 release to the day it moved into this repository, released here as one entry. They are objectui commits `a3c0da9`..`9e1fe03`, the release commit to the freeze. Their 65 changesets came across with the code under `ui/.changeset/`, which `changeset version` does not read, so this entry carries them into the release. Each of those 65 files stays in `ui/.changeset/` unchanged, as the full record of its change. Five of the changes are breaking retirements; each has a paragraph below and points at the file that holds its migration table.
43+
44+
<!-- adr-0087: not-required (no-migration-prescription) The five retirements below shipped in objectui before it merged into this repository, and each one is an `@object-ui/*` surface: a renderer node type and its schema (`html`), a widget source member (`module`), exports nothing read, three providers that duplicated `@object-ui/react` and `@object-ui/app-shell` names, and nine `@object-ui/types` schema keys. None is an `@objectstack/spec` key, object definition or stored shape, so the ADR-0087 registries in `packages/spec` have no entry to write and `objectstack migrate meta` has nothing to rewrite. objectui had no conversion registry; each old spelling is refused by name, at validation or by the compiler, and each change ships its own migration in the original changeset this entry points to, which is why this entry does not restate them (maintainer ruling 28 = B on objectstack#25831). -->
45+
46+
### The raw-HTML `html` node type is retired (objectui#13449, PR #13475)
47+
48+
`@object-ui/components` no longer registers `html` or `ui:html`, `@object-ui/core` drops it from the public blocks, and `@object-ui/types` no longer exports `HtmlSchema`. Its renderer wrote the authored string into the page with no sanitiser. A page that still names the node draws the unknown-component panel, and `objectui validate` refuses `type: "html"` by name. The `html` field type is a different layer and stays. Migration: `ui/.changeset/13449-retire-html-renderer.md`.
49+
50+
### The `module` widget source is retired (objectui#13450, PR #13473)
51+
52+
`WidgetRegistry` no longer loads a widget's code from a URL at runtime, and `@object-ui/types` no longer exports `WidgetSourceModule`. That loader was a runtime dynamic import and needed `unsafe-eval` under a strict content security policy. A manifest that still declares the `module` source is refused before anything is fetched, with a message that names both replacement sources. Migration: `ui/.changeset/13450-retire-widget-module-source.md`.
53+
54+
### Nine zero-consumer modules are retired and the runner is private (objectui#13453 part 1, PR #13506)
55+
56+
`@object-ui/core` drops the fluent schema builders and the drag-and-drop, keyboard and sharing protocol bridges. `@object-ui/react` drops `useFocusTrap`, `useFocusReturn`, `useRovingFocus`, `usePageTransition`, `useSchemaPersistence` and `createLocalStorageAdapter`. `@object-ui/collaboration` drops `LiveCursors`. The test-only reset helpers are no longer on the package roots of `@object-ui/core`, `@object-ui/app-shell`, `@object-ui/types` and `@object-ui/plugin-detail`. Nothing in ObjectUI read any of them. `@object-ui/runner` is now private. Details: `ui/.changeset/13453-core-retire-dead-modules.md`, `13453-react-retire-dead-hooks.md`, `13453-collaboration-retire-live-cursors.md` and `13453-test-helpers-off-barrels.md`.
57+
58+
### The providers trio is retired (objectui#13453 part 2, PR #13507)
59+
60+
`@object-ui/providers` no longer exports `DataSourceProvider` / `useDataSource`, `MetadataProvider` / `useMetadata` or `ThemeProvider` / `useTheme`. They duplicated names that `@object-ui/react` and `@object-ui/app-shell` publish with different implementations. `UploadProvider` and the upload adapters are unchanged. Migration: `ui/.changeset/13453-providers-retire-trio.md`.
61+
62+
### Nine duration keys carry their unit in their name (objectstack#25762, PR #13515)
63+
64+
Nine keys on `carousel`, the three chatbot nodes, `ActionSchema`, `ActionSchema.retry`, `toast`, `tooltip`, `hover-card` and `report` now end in `Ms` or `Seconds`. The value and its unit do not change. An old key is refused at its own path with a message that names the new key, and its TypeScript member is `never`. Migration table: `ui/.changeset/25762-duration-keys-carry-unit.md`.
65+
66+
### Also in this range
67+
68+
- Every package's `react` / `react-dom` peer range is `^19.0.0` (was `^18.0.0 || ^19.0.0`): a React 18 host is no longer supported (objectui#13465, PR #13481).
69+
- The `react-pages` capability (`kind: 'react'` pages) now defaults to off in `@object-ui/core`; a host turns it on. The Console sets zod's `jitless` before any module runs, so zod no longer probes for `eval` (PR #13526).
70+
- An invalid `gantt` block is refused with each schema issue named, instead of drawn (objectui#13459, PR #13490). An action's `confirmText` or `successMessage` with no template hole is shown exactly as written (objectui#13476, PR #13482).
71+
- A record section whose fields are all empty folds into one "Show N empty fields" row (objectui#13386, PR #13483). The list, gallery, map and timeline record preview mounts `RecordDetailPanel` (PR #13486).
72+
- Bulk actions keep each failed record's id and reason, and refresh the bound list once per run (objectui#13442, PR #13474). The AI build chat's plan card says how the build will land (objectui#12724, PR #13508). Assistant answers render text and charts in stream order (objectui#13492, PR #13500).
73+
- Inline locale-map labels and descriptions on reports and pages show in the viewer's language (objectui#13470, #13488; PRs #13487, #13501). Positions show by label in a permission set's assigned users (objectui#13477, PR #13493). The translation preview draws the `positions` and `permissions` groups (objectui#13478, PR #13485). Calendar events with a lookup `titleField` show the record's display name (PR #13480). Unlabeled datasource enum selects get readable option labels (objectui#13353, PR #13499).
74+
- More console pages are translated (objectui#13460, PRs #13489, #13503). Icon-only buttons have accessible names and clickable controls are keyboard-reachable (objectui#13461, PR #13494).
75+
- Every published package declares `sideEffects` (objectui#13464, PR #13495). One `react` 19.3.0 line and one `zod` `^4.6.5` range across the packages, and single-copy pins for `@ai-sdk/react`, `ai` and `better-auth` (objectstack#25685, #25727; PRs #13472, #13496, #13512).
76+
- Tooling and test-only changes for the merge, which publish nothing: workspace-root readers and test assumptions (objectstack#25723, #25733; PRs #13484, #13498) and warm test imports (objectstack#25763, PR #13513).
77+
78+
Clause-②: yes (narrowing)
79+
Metadata-protocol: narrowed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/console': patch
3+
---
4+
5+
fix(console): the audit log's From and To filters use the platform date picker the record forms use
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Setup → Audit Log drew the browser's native date input for its From and To filters, with the operating system's `mm/dd/yyyy` face and picker whatever the console's language. Both filters now draw the same date picker as a record form's `date` field: a text box in the display locale's format, a calendar popover, a clear button and today / tomorrow shortcuts. A typed day commits on blur or Enter. The filters send the same `created_at` bounds as before (`YYYY-MM-DD`, the To day through 23:59:59), and each filter label still names its text box.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@object-ui/layout': patch
3+
---
4+
5+
feat(layout): a collapsed sidebar navigation group shows how many entries it holds
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Before.** A closed navigation group drew its label and a chevron and nothing else, so a closed group holding one entry looked exactly like one holding ten, and users did not open it to find what was inside.
11+
- **Now.** While a group is collapsed, `NavigationRenderer` draws a small count badge between its label and its chevron. The count is what opening the group would reveal: the entries that pass the same per-item guards the renderer applies (the `visible` expression, `requiredPermissions`, the `requiresObject` / `requiresService` capability gates, a `doc` entry's readability check, and an `action` entry only when the host wires `onAction`), counted through nested groups. Separators and the groups themselves are not entries. It is the same walk that decides whether a group renders at all (`hasVisibleNavigationItems`), so the count cannot disagree with the opened group.
12+
- **When it does not show.** An open group shows no count, because its entries are in view. A group that holds the current route is forced open, so it never shows one. In the icon rail the badge is hidden under the same classes as the group label.
13+
- **Accessibility.** The badge is `aria-hidden`: the disclosure's accessible name stays the group label, and the disclosure already announces collapsed or expanded.
14+
15+
What to do: nothing. No navigation key or value changes, and no translation key is added.
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+
fix(app-shell): the Console no longer sends two requests it knows will be refused, the drafts ledger for a member and the published body of a new draft
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Home's drafts row** read `GET /api/v1/meta/_drafts` for whoever opened Home. A member holding none of the capabilities the ledger admits (`studio.access`, `setup.access` or `manage_metadata`) got a 403, and the console logged it as a failed request on every visit. The row now reads the ledger only for a session that holds one of them, through the new `useCanReadPendingDrafts()`. An unreported capability set still reads it, and the server still enforces the gate.
11+
- **The pending-changes sheet** (Studio's Publish and Changes, and the draft-preview bar's Changes) read each draft's published body beside its draft. Under Publish, where every row opens expanded, that read was sent before the sheet knew which drafts are new, so a draft-only object such as one just saved from New object got `GET /api/v1/meta/object/NAME?package=PKG` → 404. A row now waits for its new-or-update classification, and a new draft is not asked for a published body. A row whose classification read failed is read both ways, as before.
12+
13+
What to do: nothing. The pages render exactly as before.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@object-ui/plugin-list': patch
3+
'@object-ui/plugin-grid': patch
4+
'@object-ui/i18n': patch
5+
---
6+
7+
fix(plugin-list,plugin-grid): an empty list tells "no records you can see" and "nothing of yours yet" apart from "no records"
8+
9+
Clause-②: no
10+
Metadata-protocol: none
11+
12+
An empty list chose its copy from the user's query and the view's filter alone. A member who may read none of an object's records and may not create one was told "Nothing here yet / Create your first record to get started." beside no Create button, and every "my …" view (`owner` equals the current user) told someone who owns nothing "No records match this view's filter."
13+
14+
- **No filter, no create grant.** When the permission answer has loaded and the caller does not hold the create grant (the `listNew` row of the affordance-to-grant map, the verdict the page's own New reads), the empty state reads "No records you can see" and asks the reader to contact an administrator. The add-record action is not drawn for that caller, even on a view that enables `addRecord`.
15+
- **A filter naming the signed-in user.** When the view's declared filter compares a field to the caller's own id (or still carries the `{current_user_id}` placeholder), the empty state reads "Nothing of yours yet", with the add-record action only under the create grant.
16+
- **Unchanged.** The first-run copy and action for a caller who may create, the user-query and view-filter copy, an authored `emptyState`, the 403 error panel, and every surface with no permission provider mounted.
17+
18+
`ListView` (grid and gallery), the standalone `ObjectGallery` and `ObjectGrid`'s default empty state decide the same way. `@object-ui/i18n` gains `list.ownedNoneTitle`, `list.ownedNoneMessage`, `list.noneVisibleTitle` and `list.noneVisibleMessage` in all ten locale packs.
19+
20+
What to do: nothing. A view that authors its own `emptyState` keeps it.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): the Setup → Positions list shows each position's description
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The position list in Setup declared only Name, Label, Holders and Permission sets, so a position's `description`, which `GET /meta/position` already serves, was never shown. The list now has a Description column right after Label, the same column the permission-set list next to it has. A position without a description shows the empty cell. The text is the served one, so a description the translation bundle's `positions` namespace translates shows translated, like the label.
11+
12+
What to do: nothing.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/plugin-security': patch
3+
---
4+
5+
Every built-in permission set says who holds it, in English, Chinese, Japanese and Spanish
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Setup → Permission Sets lists the platform's own permission sets beside every app's. Five of them (*Administrator — Full Access*, *Organization Administrator*, *Member — Standard Access*, *Viewer — Read-Only* and *External Member — Own Records*) had no description, and the no-bypass organization administrator set and the three MCP agent sets had descriptions written for platform engineers. An administrator picking a set for a new user could not tell an administrator set from a member set.
11+
12+
Each built-in set now has one plain sentence saying who holds it and what it opens or withholds. For example, *Organization Administrator* reads "Owners and admins of an organization: full control of its records and members in Setup, but no app authoring or platform-wide settings." The sentences are translated into zh-CN, ja-JP and es-ES through the permission-set group of the translation bundle (`permissions.<name>.description`), so the page shows them in the user's language. The engineering detail that used to be in the no-bypass and MCP descriptions is now in code comments.
13+
14+
No set's grants, name or label changed. This changes only the text shown about each set, not its permissions.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
fix(cli): the Console drift warning and refusal name `pnpm console:build` instead of the retired `pnpm objectui:build`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
When the Console build being served was stamped from a different objectui commit than the `.objectui-sha` pin above it, `os serve` printed a warning and `os dev` refused to mount the Console (and answered `503` at `/_console/`). Both told you to run `pnpm objectui:build`, and the refusal also mentioned `pnpm objectui:refresh`. Neither script exists any more: the objectui pin and its scripts were retired when the Console moved into this workspace, and the Console is now built with `pnpm console:build`.
11+
12+
- **Now.** The warning ends with `rebuild it with 'pnpm console:build'.`, and the refusal (terminal and `503` body) says `Rebuild the console:` followed by `pnpm console:build`. The `objectui:refresh` line is gone. The SHAs, the `OS_ALLOW_CONSOLE_DRIFT=1` escape hatch and the status codes are unchanged.
13+
- **Who sees it.** Only a tree that still carries its own `.objectui-sha` above a stamped Console build. The framework repository carries no pin, and `pnpm console:build` writes no stamp, so a framework checkout never reaches this message. A published install carries no pin either.

0 commit comments

Comments
 (0)