Skip to content

Commit 31ad53b

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-dvfr9q
Resolves the administrator guide's offboarding row: main's wording (the ban also blocks the user's API keys) with this branch's hand-over link. Claude-Session: https://claude.ai/code/session_01Utp6CZavYYLh5k5r6jhgCF Co-authored-by: Claude <noreply@anthropic.com>
2 parents 6e44006 + c045c34 commit 31ad53b

314 files changed

Lines changed: 15937 additions & 1373 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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the automation skill's OAuth recipe names a stdio MCP server's credential route as `transport.credentialEnv`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Recipe 6 of `objectstack-automation/references/integration-recipes.md` said a `stdio` server's credentials ride `transport.env` — the literal-in-metadata route the `connector-credential-literal` advisory warns against. It now says what the `mcp` provider does: the grant-bearing kinds stay `http` only; a `stdio` server takes a static `auth: { type: 'bearer', credentialRef }`, handed to the child process in the variable `transport.credentialEnv` names, never a literal in `transport.env`. Paid inside the file's token ceiling by dropping the opening paragraph's restatement of two facts that keep their homes: the packaged spec (SKILL.md § Integrations are declared, not coded) and where an `api` hook's secret goes (SKILL.md's `secretRef` row and recipe 4). No eval asserted the old route; none changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): an empty body table of the record page keeps its header (title, 0, New) with the empty sentence under it, instead of folding into one line that read the empty sentence before the table's title
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
**Visible behaviour change on a released page.** The default record page draws a body table (a related list drawn full width in the details column, or the Details tab) beside its sibling sections. Because the tables share that container, the related-list empty fold took them for a Related tab stack: once one table had rows, an empty one left its place and reappeared as a single line after the last table, reading 「暂无相关记录 · 偏离 · + 新建」 (no related records · Deviations · New). A body table now never folds. An empty one keeps the header row its non-empty siblings draw (title, count 0, ⤢, New), and the empty sentence moves out of that row to the table's place under it.
11+
12+
The fold of a record's Related tab, and the empty-panels line of the related column, are unchanged: only a list whose relationship is one of the page's body tables opts out.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): the record page's activity feed names the record as the reader reads it, as the record's heading does, when the object is named by a formula
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
An activity summary quotes the record's name as its writer read it: `sys_activity.record_label`, and the same text inside `summary`, are stored when the write happens. The server composes the rest of the summary in the reader's language on read, but not the name. For an object whose name field is a formula over `label(record.FIELD)`, that name is in the writer's language, so an en-US reader of a review a zh-CN user created read `Created Review "法务 · Legal Counsel 1"` while the heading above it read `Legal · Legal Counsel 1`.
11+
12+
Each activity row of the page's own record now names the record by the value of the object's name field on the record the page read, which is the heading's name. The change is made where the feed is drawn (`RecordActivityTimeline`), so the activity panel, the 动态 stream and the 动态 panel all read it. Only the name the summary quotes (`"…"`, or `「…」` in Japanese) is replaced.
13+
14+
What stays as stored:
15+
16+
- an object whose name field is a stored field (text and the like): the name a row stored is the name the record had then, and a rename does not rewrite older rows;
17+
- a row about another record, a row that carries no `record_label`, and a summary that does not quote the stored name;
18+
- a page with no record around the feed, or whose record has no name to show.
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+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(app-shell): Studio Interfaces opens a list view from 不在导航中 on its object's page; the 视图 group lists only what no header dropdown reaches, and names a form view and its own type
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
- **A list view opens on its object's page from every door.** A list view picked under 不在导航中 → 视图, and a link to the view itself (`?surface=view:OBJECT.KEY`, the All metadata door), now land on the object's page with its header dropdown (object / view ▾), on that view: the object's nav entry when it has one, else the object itself, with no entry (`?surface=object:OBJECT`, which a reload or a shared link opens again, `?view=` included). The panel there now also carries what only the view's own page offered: its conditional formatting (条件格式化), whose CEL verdicts hold the view's autosave as they held the view page's Save, and the sections of the spec's authoring form for a view, without the keys the panel already edits. A form view, and a view a read-only base's pair adds, still open as themselves.
12+
- **The 视图 group lists what the dropdowns do not reach.** A list view whose object has a nav entry is no longer listed there, a view only drafted in the package included; the list views of an object with no entry stay listed.
13+
- **Form views read as forms.** A form view is listed by its label, else as the object's name and the word for a form ("Lead form", 「线索表单」), never its item name (`crm_lead.form`); the group's heading says what it holds (表单视图, 视图, or 表单视图与列表视图). In the view inspector, a form view's 视图类型 offers the form layouts of the spec's `FormViewSchema.type` (simple, tabbed, wizard) and reads its own, where it read 「simple(未找到)」; a list view's picker is unchanged.
14+
- **`@object-ui/i18n`: three Studio keys,** `engine.studio.if.offNav.viewForms`, `engine.studio.if.offNav.viewMixed` and `engine.studio.if.offNav.formName`, in en and zh.
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+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(app-shell): Studio's rails mark a customized row with the word 定制 / Custom and an added row with 新增 / Added, no fill, instead of a filled square with a glyph that read as an add button (#30070)
7+
8+
Clause-②: yes (widening) — new studio i18n key `engine.customizationMark.customizedShort` (en, zh)
9+
Metadata-protocol: none
10+
11+
The compact customization mark the pillar rails draw (and the Interfaces rail's navigation-override mark, which wraps it) now prints one short coloured word with no background. Its tooltip and accessible name are unchanged: the full text ("已定制(HotCRM)") followed by the sentence naming the customization package. It is not a control: a click on it is a click on its row.
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': patch
4+
---
5+
6+
feat(app-shell): the Studio list-view panel configures the selection bar's actions (#30089)
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
The list-view panel of an object's grid view gains a "Selection actions" section. It edits two keys the list view already declares, and no other:
12+
13+
- `bulkActions`: pick the object's actions by label, plus the built-in Delete (`delete`). Each runs once per selected record, promoted with the action's own label and params.
14+
- `bulkActionDefs`: add, edit or remove a field update (`operation: 'update'`): a button label, the fields the dialog asks for (one required param per field, carrying a select's options and a lookup's object) and an optional confirmation. A def is written only once it has a label and a field and `BulkActionDefSchema` accepts it.
15+
16+
The section says what happens to the built-in Delete: shown while the view declares neither key, and kept once either is declared only when `bulkActions` names `delete`. A def of another kind (`delete`, an aggregate `custom` dispatch) is listed and can be removed; it is edited in metadata. An emptied key is removed, so a view that declares neither key saves as it was read. On an installed app's read-only view, the first edit goes through the same customization copy as every other setting of the panel. Strings are added in English and Chinese to the `studio` namespace of `@object-ui/i18n`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/lint': minor
3+
---
4+
5+
fix(lint)!: a stored page sort naming a field its object lacks is refused by `os validate` and at the page publish door (`page-field-unknown`, error), on every page sort slot (#30093)
6+
7+
Clause-②: no (narrowing) — an unknown sort field on a page slot moves from silent or warning to error: `os validate` / `os build` / `os lint` and the `page` publish door refuse a page sort they accepted before.
8+
Metadata-protocol: narrowed
9+
Skills-docs: updated here — content/docs/deployment/validating-metadata.mdx
10+
11+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed or renamed: every page sort slot keeps its shape and meaning, and the build and the page publish door now give an unknown field there the verdict a list view sort already gets. A refused name never sorted anything (the list door answered every read 400 INVALID_SORT), so there is no rewrite that keeps what the author meant; the author names a real field, and the refusal says which. -->
12+
13+
**BREAKING** accept-set narrowing at the page publish door (`PUT /api/v1/meta/page/NAME`; Studio, REST and MCP authors) and in `os validate` / `os build` / `os lint`.
14+
15+
- **Before.** A page sort naming a field the object does not have saved green, and its first read, and every read after it, answered `400 INVALID_SORT` at the list door. A list page's `interfaceConfig.sort` and a `record:related_list` block's `sort` drew a `page-field-unknown` warning on the CLI alone; an element `dataSource.sort`, a related list's `parentDataSource.sort`, an app page's `record.sort` and the own `sort` of a `record:line_items`, `list-view` or `object-*` block were read by nothing.
16+
- **Now.** Every one of those slots is judged by `validateSortableFields`, the reference-integrity member the page publish door already runs, and an unknown name is `page-field-unknown` at `error`, at the slot's path, bound to the object the slot's renderer reads (`dataSource.object`, else the block's object prop; `interfaceConfig.source`, else the page's `object`; `parentDataSource.object`; `record.object`). The page door refuses it `422 INVALID_METADATA`. A registry-injected column on an `external` object is `page-field-unprovisioned` at `warning`, as before. `validatePageFieldBindings` no longer reads a page sort, so each slot has one reader.
17+
- **Not judged.** A dotted relationship path (the list door refuses it as its own verdict), a system column such as `created_at`, an object the stack (or the publish snapshot) does not carry, and an object with no field map.
18+
- **Not changed.** A stored page already carrying such a sort keeps loading; only its next save is judged, and its read answers 400 as it did before.
19+
20+
**What an author does.** Name a field the object declares, or add the field to the object. A refused name never sorted the page, so there is nothing to keep.
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+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(app-shell): Studio's publish review sheet says a customization lives in this environment's database and moves only by `os package export` (#30119)
7+
8+
Clause-②: yes (widening) — new `@object-ui/i18n` key `preview.changes.customizationEnvironment` in every pack; `preview/savedToCustomization` gains `customizationEnvironmentText` and `PACKAGE_EXPORT_COMMAND`
9+
Metadata-protocol: none
10+
11+
Reviewing a read-only package's customizations, the sheet adds one line under "Saved to BASE's customizations": the changes are kept in this environment's database as items of the `.custom` package it names (the id the server answered for the base), not in the project's source, and they reach another environment only through `os package export`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/auth': patch
3+
'@object-ui/console': patch
4+
---
5+
6+
fix(console,auth): after an explicit sign-out, whoever signs in next lands on their own home, not on the page the previous person had open
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
- **`@object-ui/auth`: `AuthContextValue.sessionEndedBySignOut`**, `true` from a `signOut()` until a session is established again in the tab, whoever it belongs to; `false` on load, while signed in, and after a session that ended any other way (expired, revoked, signed out in another tab). It is a new required member of the exported `AuthContextValue` type: code that builds its own value of that type (a test double, a custom provider) must add `sessionEndedBySignOut: false` (or its own reading) to type-check.
12+
- **`@object-ui/console`: `LoginRedirect`** sends the visitor to `/login` with no `?redirect=` after an explicit sign-out. A new member signing in after the administrator signed out of a Setup page used to land on that page and read "you do not have access to this app". A session that expires or is revoked under the person still keeps the path (list state stripped as before), so that person signs back in where they were.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/i18n': patch
3+
'@object-ui/core': patch
4+
'@object-ui/app-shell': patch
5+
'@object-ui/plugin-dashboard': patch
6+
---
7+
8+
fix(console): four copy and display details from a real-user walkthrough: Latin object names spaced in zh form titles, a title on the lookup's create dialog, a success toast that names the action, and money metrics at the currency's decimals
9+
10+
Clause-②: yes (widening)
11+
Metadata-protocol: none
12+
13+
- **zh form titles space a Latin object name.** `新建{{object}}`, `编辑{{object}}` and `查看{{object}}` (and the AI chat's record-write card titles) read `新建 Repair Ticket` when the object has no Chinese label, and still `新建联系人` when it has one. `createI18n` applies the spacing to those keys only, through an i18next post-processor; the packs keep the plain `{{object}}` spelling.
14+
- **The lookup's "create the referenced record" dialog has a title.** A `{ objectName, mode: 'create' }` modal descriptor with no `title` now reads `form.createTitle` with the object's label, the title of the console's own New dialog. An authored title still wins.
15+
- **The default success toast names the action.** An action with a `label` and no `successMessage` (and no matching `outcomeMessages` entry) toasts the new pack key `actions.completedNamed` (`Resolve completed`, zh `“解决”已完成`) instead of the generic `Action completed successfully`. An action with no label keeps the generic text.
16+
- **Money metrics keep the currency's decimals.** A dataset metric over a currency measure with no `format`, and a static metric card with a `currency` and no `format`, show the currency's own minor-unit width (CNY `¥1,293.00`, JPY `¥1,293`), the width the list cell shows. Before, the dataset metric printed the shortest form (`¥1,293`, `¥1,280.5`) and the static card rounded to whole units. An authored `format` pattern still states its width.

0 commit comments

Comments
 (0)