Skip to content

Commit 6840f48

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-it3g43
2 parents 6504a2e + a2f434d commit 6840f48

66 files changed

Lines changed: 3396 additions & 184 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: 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(studio): a read-only package's item header offers "Customize with an overlay" only for a type that takes one
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
In Studio, an item of a read-only (code or installed) package showed "Read-only · Customize with an overlay" in its header on every pillar, including objects, flows, pages and permission sets, none of which take an environment overlay, and the link opened the package's whole metadata directory. Now:
11+
12+
- **An overlay-able item.** When the open item's metadata type declares `allowEnvironmentOverlay` in the server's type registry (views, dashboards and reports among them), the header keeps "Read-only · Customize with an overlay", and it opens that item's own page in Setup (`/apps/setup/metadata/TYPE/NAME`), where the overlay is edited.
13+
- **Anything else.** An item whose type takes no overlay, a header with no item open, or a registry not yet read shows a plain "Read-only" with a lock. It is no longer a link. Its tooltip still carries the pillar's read-only sentence.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/service-automation': patch
3+
'@objectstack/service-cluster': patch
4+
---
5+
6+
fix(service-automation): a connector credential written or cleared through the door reaches every replica, not only the one that took the request
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
`PUT` and `DELETE /api/v1/automation/connectors/credential-refs/:ref` reconciled the declarative connector instances of the replica that served the request. On a multi-replica deployment every other replica kept what it had: an instance whose stored value its upstream had refused is held with no retry timer, so a corrected credential took effect there only after a metadata reload or a restart, and requests landing on those replicas kept failing against a degraded connector.
12+
13+
- **A fourth cluster lane.** After the row is written or cleared, the door publishes `{ originNode, ref }` on the `connector-credential.mutated` cluster channel. The payload is an address only: never a value, a fingerprint or a revision.
14+
- **Peers converge from their own read.** A peer drops its own `originNode`, then runs its connector reconcile on its reconcile queue, which re-reads the shared `sys_connector_credential` rows. Exactly the instances naming a changed reference re-materialize, held ones included; a cleared reference degrades them, naming it.
15+
- **Attached where the other lanes are.** `MetadataClusterBridgePlugin` (`@objectstack/service-cluster`) attaches the lane at `kernel:ready` beside `metadata.changed`, `metadata.mutated` and `datasource.mutated`, duck-typed against the automation service's `attachConnectorCredentialPubSub()`. As with lanes 2 and 3, it is skipped on the in-process `memory` cluster driver, so a single replica behaves as before.
16+
- **What it does not promise.** Delivery is at-most-once, as for every lane of the family: a lost message is not retried, and the next metadata reload or restart still reconciles that replica.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): the record highlights strip draws a boolean as one neutral chip, as the details body does
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The `record:highlights` strip drew `true` as a green "✓ Yes" chip and `false` as a warning-toned "× No" chip, whatever the field meant, so a case's "SLA Violated: No" read as a warning. The metadata does not say which value is the good one, and the details body draws the same field as a plain word, so both values now share one neutral chip: the locale's Yes / No word, with no state colour and no glyph.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/rest': patch
3+
---
4+
5+
fix(rest)!: the clone door refuses a body that carries `overrides` beside other top-level keys, instead of cloning with `overrides` alone (#27669)
6+
7+
Clause-②: no (narrowing) — `POST /data/:object/:id/clone` refuses a body that mixes the nested `{ "overrides": {...} }` shape with other top-level keys; it used to answer `201` with those keys ignored. Nothing is widened.
8+
Metadata-protocol: none
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped, and no export or type changes: one REST door now refuses a request shape whose extra keys it used to ignore. There is nothing for a migration to rewrite and no tombstone. -->
11+
12+
**BREAKING** accept-set narrowing at one REST data door (`@objectstack/rest`).
13+
14+
- **Before.** `{ "overrides": { "name": "Copy" }, "status": "draft" }` read `overrides` alone: the clone got the new name, `status` was dropped, and the door answered `201`.
15+
- **Now.** A body that carries `overrides` beside any other top-level key answers `400` with `error.code: 'VALIDATION_ERROR'` before the clone runs, naming the stray keys and the two accepted shapes.
16+
- **Unchanged.** `{ "overrides": {...} }` alone, a bare field map without an `overrides` key, `{}`, and no body at all clone exactly as before. The SDK's `data.clone` sends only the nested shape.
17+
- **Who sees it.** An API caller or script that mixes the two body shapes. Such a request used to succeed while applying only part of what was sent.
18+
19+
**The remedy.** Send either `{ "overrides": {...} }` or a bare field map, not both. A record with a real field named `overrides` sets it through the nested shape: `{ "overrides": { "overrides": ... } }`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/lint': patch
3+
---
4+
5+
fix(lint): a dataset refused at the save door for a base object outside its package's closure prints the dependency declaration as the fix
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
At the runtime save door a dataset written into a package is judged against that package's closure: its own objects, the objects of the packages its manifest declares in `dependencies`, platform objects, and tenant objects that belong to no package. A base object outside it is refused `422` with `object-reference-unknown`, and its fix line used to read "Point it at one of this stack's objects, or at a platform object by its full name", which sends the author away from the fix that works. Under a closure it now reads "Declare a dependency on the package that defines "OBJECT" in the `dependencies` of "PACKAGE"'s manifest, or point it at an object inside that closure", the prescription the flow trigger and list view doors print for the same closure (ADR-0141 D1).
11+
12+
- **One prescription.** The three doors build that line from one helper, so they cannot drift apart again. The list view door's line is unchanged. The flow trigger door's line now quotes the object and package with double quotes and names "PACKAGE's manifest" instead of "the manifest `dependencies` of package 'PACKAGE'"; its second remedy (`set config.objectName …` / `set config.timeRelative.object …`) is unchanged.
13+
- **Only the fix line moves.** The verdict, the severity and the message are the same with or without a closure.
14+
- **Unchanged without a closure.** A write that names no package, and `os validate`, `os build` and `os lint`, print the hint they printed before.
15+
- `os explain object-reference-unknown` describes the closure case.
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+
'@object-ui/console': patch
4+
---
5+
6+
fix(setup): a new metadata item whose name the editor already refuses is not sent, and one mistake is one message
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
- **Before.** On Setup › Permission Sets › New (and every metadata create page), a Name the editor flagged as invalid was sent on Save anyway. The page then showed the server's refusal ("is not a legal metadata item name"), and after the next edit also the summary banner ("does not match the spec — 1 validation error(s)") and the inline error under Name: three messages for one mistake.
12+
- **Now.** While the editor's own check refuses the Name of a new item, Save sends nothing and the error under Name is the message; a Name filled in from the Label, never touched, shows its error there too once Save is pressed. The summary banner no longer repeats an error the form already draws on its field, and a server refusal that names a field the form draws is said on that field only.
13+
- **Unchanged.** Every other check the editor runs while you type stays advisory: Save still sends, and the server has the last word (an existing item is never held by it). Errors the form cannot draw on a field (the whole item, a nested key, a field off screen) are still listed in the banner.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/service-automation': patch
3+
---
4+
5+
fix(service-automation): a refusal met inside a `try_catch` catch region reaches the flow's caller as the structured refusal
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A `try_catch` whose catch region itself fails now carries the refusal that region met (a permission, a validation rule, a duplicate, an app hook's declared refusal) on the run's result as `innerRefusal` (`{ code, message }`) and the producer-marked `userMessage`, the same way a `try_catch` with no catch region already does. Before, the caller got only the node chain as text (`try_catch 'ID': catch region failed — …`), so a runner had no business message to show.
11+
12+
The refusal carried is the catch region's own, never the try region's refusal that it handled. A catch region that failed with no refusal carries neither member, even when the try region was refused, and the `error` text is unchanged.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/plugin-approvals': patch
3+
---
4+
5+
fix(plugin-approvals): an `expression` approver id that names no account no longer opens a slot no one can take
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
#27397 (`user`) and #27752 (`field`, out-of-office delegate) made an approver id that no account carries expand to nobody. The third sibling now follows them: an `expression` approver resolved as users (`resolveAs: 'user'`, the default) keeps a slot for each id its expression yields only when an account carries it. An id no account carries logs the shared "expanded to nobody" warning, naming the id and the expression, and adds no slot, so a slate it leaves empty reaches the node's `onEmptyApprovers`. A failed directory read keeps the slot. A dead out-of-office delegate on an expression id routes back to that id, as it does for `user` and `field`.
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+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(studio): the list-view panel edits a calendar, gallery, timeline, gantt, map or tree view's own settings
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
In Studio › Interfaces, the list-view panel of an object now has a section for the settings of the view's own type, below the type it was created as: a calendar's start date, end date, title, color and all-day fields; a gallery's cover, title and card fields, cover fit and card size; a timeline's dates, title, grouping, color and scale; and the blocks of a gantt, a map and a tree. Before, only a kanban's card could be edited there, so a view made with "Add view" kept the fields it was created with.
12+
13+
The section is drawn from the spec's own schema for that type's block, so every setting the spec declares appears, with its required marks and allowed values, and a setting that names a field is picked from the object's fields by label. The draft it saves is the same view item, under `config.<type>`. Grid and kanban views are unchanged. A chart view's dataset binding is still edited in the Create View dialog only.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
Clause-②: no
7+
Metadata-protocol: none
8+
9+
Studio flow designer, Update Records node: on a record-triggered flow a new node starts on the trigger's object, its Filter offers "Update the triggering record" (writes `id` = the CEL expression `record.id`), and the keys of Filter and Field values are picked from the object's fields by label while the API name is what is stored. Existing nodes keep their stored config; other node types are unchanged.

0 commit comments

Comments
 (0)