Skip to content

Commit 6c39365

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-27191-home-amount-pointer
# Conflicts: # packages/spec/src/system/metadata-form-zod-reconciliation.test.ts
2 parents 361f8f2 + 3fd4d6b commit 6c39365

630 files changed

Lines changed: 38486 additions & 3337 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: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/service-automation': minor
4+
'@objectstack/connector-rest': minor
5+
'@objectstack/connector-openapi': minor
6+
---
7+
8+
feat(spec): `signed` joins declarative connector-instance auth, with `aliyun-acs3-hmac-sha256` as its first scheme (ADR-0143 D2.3, #26710)
9+
10+
Clause-②: yes (widening)
11+
Metadata-protocol: added
12+
13+
<!-- adr-0087: not-required (no-migration-prescription) One member is added to the instance-auth union and optional members to the provider context and materialization. Nothing an author or a provider wrote before is refused or re-shaped, so there is nothing for a migration to rewrite. -->
14+
15+
An upstream that authenticates every request by a signature over the request itself, rather than by a token it is sent, had no way to be declared on a connector instance. ADR-0143 D2.3 adds that kind, `signed`, with a closed list of schemes. A scheme joins the list only together with its signer and its vendor test vectors. This release ships one scheme: Alibaba Cloud's OpenAPI V3 signature.
16+
17+
- **`@objectstack/spec`**
18+
- `ConnectorInstanceAuthSchema` gains `{ type: 'signed', scheme, keyId, credentialRef }`, a closed shape for each scheme. `keyId` is the public key identifier. The signing key is only ever a `credentialRef`.
19+
- The publish door refuses an unknown or missing `scheme` at `auth.scheme`, naming the value it got and the schemes that ship. It refuses an inline `secret`, `privateKey`, `secretKey` or `accessKeySecret` by name, with the `credentialRef` prescription, and an authored `signature`. It refuses `signed` on `provider: 'mcp'` at `auth.type`.
20+
- `@objectstack/spec/integration` gains the request-signer seam: `ConnectorRequestSigner` (`sign`, plus an optional `verifyResponse` for schemes that sign their responses), `ConnectorProviderContext.requestSigner`, and `ConnectorMaterialization.requestSignerApplied`.
21+
- `connectorFetchOptions` takes an optional signer and signs every attempt `resilientFetch` makes, retries included. `readConnectorResponse` runs the scheme's response verification before parsing.
22+
- With no signer, both behave exactly as before.
23+
- **`@objectstack/service-automation`**
24+
- A `signed` instance's key resolves through the same credential chain as the static kinds, with the same degrade on an unresolved reference.
25+
- The key is bound to the scheme's signer at materialization, and the provider receives only the signer.
26+
- The service refuses to serve a `signed` instance on a provider that does not acknowledge the signer, so such an instance never calls its upstream unsigned.
27+
- A datasource that borrows a `signed` instance through `external.connector` is refused with `422`.
28+
- **`@objectstack/connector-rest`, `@objectstack/connector-openapi`**
29+
- Both apply a handed request signer to every request and acknowledge it.
30+
- A static credential together with a signer is refused.
31+
- `bearer`, `api-key` and `basic` requests are unchanged.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
'@objectstack/service-automation': patch
5+
'@objectstack/platform-objects': patch
6+
---
7+
8+
feat(console): Setup → Integrations → Connector Credentials, and a credential step after a marketplace install
9+
10+
Clause-②: yes (widening: `@objectstack/service-automation` exports `CONNECTOR_CREDENTIALS_UI_BUNDLE`, `CONNECTOR_CREDENTIALS_COMPONENT_REF` and `CONNECTOR_CREDENTIALS_NAV_CAPABILITY`, and registers a new Setup navigation entry `nav_connector_credentials` resolving component ref `automation:connector-credentials`; no existing key, route or shape changes)
11+
Metadata-protocol: none
12+
13+
An administrator can now set a connector credential without the API or the server environment.
14+
15+
- **Setup → Integrations → Connector Credentials** lists every reference the credential routes list (`GET /api/v1/automation/connectors/credential-refs`): its status (`set`, `missing`, `rejected` with the upstream's reason), the connectors naming it, and when and by whom it last changed. Each writable reference has a masked input that starts empty, whatever is stored; an empty input means "keep the current value", so nothing is sent for it. Saving sends `PUT` and the row takes the entry the server answers after its reconcile. A reference with a value stored here has **Clear**, behind a confirmation, which sends `DELETE`. A reference an environment variable supplies is read-only.
16+
- Where the routes refuse (`403` for a missing capability or a multi-organization tenancy posture, `501`, `503`), the page shows the server's own sentence as a configuration notice, and a server without the routes (`404` / `405`) gets "this server does not manage connector credentials". Neither is drawn as an error.
17+
- **After a marketplace install** into this runtime — install-local, an org package installed here, or a cloud install once its app is served — the install result lists the credentials the package's connectors still need (the same listing, filtered by `connectors[].packageId`), each with the same masked input and **Skip for now**. A skipped reference stays listed with a link to the Setup page. The step comes after the install because the routes refuse a reference no installed package declares (`404`); the connectors materialize as soon as a credential is set, with no restart. Where the listing cannot be read, the install answer's `credentialNote` is shown instead.
18+
- The navigation entry is contributed by `@objectstack/service-automation` at `kernel:ready` through the manifest service, so it appears only where the automation service runs, and only for a viewer holding `manage_metadata`. The label is translated in the four platform locales; the page and the step are translated in all ten Console packs.
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(console): an empty report index points at the apps that have reports
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
An app's report index with nothing to list, such as Setup's All reports, said only "This app has no reports you can open." It now also lists the other apps whose report index has a report for the reader, each linking to that app's index: an app counts when it ships at least one report whose datasets the reader may read, the same served reports and read rule the index uses. The current app, an app that ships no report, and an app whose reports the reader may not read are not listed. The sidebar entry stays static by design. One key is added in all ten locale packs: `console.reportIndex.otherApps`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(setup): metadata lists under Setup take their title from the sidebar, lead with the label, and keep rows short
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A metadata list under Setup (Positions, Permission Sets and the other catalog pages) titled itself with the type's singular label ("Position"), led each row with the API name, and let a long description wrap a row to several lines on a phone. Under Setup the page now takes its title from the app's own navigation entry that opens it, so it reads as the sidebar row that opened it ("Positions", in the served language), and falls back to the type's label when no entry opens exactly that page. Each row leads with the item's label, with its API name beneath it in small monospace type, in place of a separate Label column; an item with no label keeps its API name as the link. A description shows two lines at most, with the whole text on hover. The same page outside Setup is unchanged.
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+
feat(studio): Delete flow in the Automations pillar's ⋯ menu
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
A flow authored in Studio could only be deleted from Setup › Metadata. An open flow of a writable package now has a ⋯ menu in its header with Delete flow. It asks in the console's in-app dialog, naming the flow by its label and `flow/NAME`, then discards the flow's pending draft and deletes the flow through the same `DELETE /meta/flow/:name` door Setup uses, at the package Studio writes the flow's drafts to. The rail is re-read, the pillar returns to its empty state without opening another flow, and a toast names the deleted flow. A refused delete shows the server's sentence and keeps the flow open. A read-only package's flow has no menu. Two keys are added to the studio namespace (en, zh): `engine.studio.auto.deleteFlow` and `engine.studio.auto.flowDeleted`.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@object-ui/i18n': patch
3+
'@object-ui/plugin-form': patch
4+
---
5+
6+
Clause-②: yes (widening: @object-ui/i18n gains the public export recordSaveMessage; no accept set moves)
7+
Metadata-protocol: none
8+
9+
A record saved from an `object-form` block's drawer or modal (`formType: 'drawer' | 'modal'`, including `<ObjectForm formType="drawer">` on a React page) now gets the record-named success toast the console's record dialogs give, such as `Task "Fix login" updated` or `Task "Write release notes" created`. A record with nothing nameable keeps the object-label toast, and a declared `successMessage` is used as written. The toast comes before the author's `onSuccess`, so a page whose `onSuccess` only closes the overlay and reloads its list needs no change. A host that mounts `DrawerForm` / `ModalForm` itself, and a form with a `submitHandler`, keeps owning its feedback and is not toasted twice. `@object-ui/i18n` adds `recordSaveMessage(t, { label, objectDef, saved, mode })`, the one builder of that message, which the console's record dialog and record page now share.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/core': patch
3+
'@object-ui/components': patch
4+
'@object-ui/plugin-grid': patch
5+
'@object-ui/plugin-detail': patch
6+
'@object-ui/data-objectstack': patch
7+
'@object-ui/app-shell': patch
8+
---
9+
10+
fix(console): a packaged action switched off for this deployment is no longer offered as a live button
11+
12+
Clause-②: yes (widening)
13+
Metadata-protocol: none
14+
15+
An administrator can switch a packaged action off in Setup › Packaged automation. The action door then refuses it, but the console kept offering the button on the record header, in action bars and in list rows, so a click could only fail. The object reads now serve the names of the switched-off actions beside the object (#27842), and the console stops offering those actions everywhere it already hides an action whose capability the user lacks: the record header, action bars, record quick actions, list and related-list toolbars, row and bulk actions. Turning the action back on in Setup brings the button back.
16+
17+
`@object-ui/core` adds four exports for this: `isActionSwitchedOff(action)`, `markSwitchedOffActions(schema, served)`, `markSwitchedOffActionsByObject(objects, served)` and `ACTION_SWITCHED_OFF_KEY`. The data layer stamps a switched-off action entry under that symbol key, which survives a spread and never reaches JSON, so an action handed back to a metadata write never carries it.
18+
19+
What to do: nothing. A backend that does not serve the names hides nothing, as before.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@object-ui/core': patch
3+
'@object-ui/plugin-charts': patch
4+
'@object-ui/plugin-dashboard': patch
5+
---
6+
7+
Clause-②: yes (widening: @object-ui/core gains the public export formatMonthBucketLabel; no accept set moves)
8+
Metadata-protocol: none
9+
10+
Dashboard numbers and chart labels stay readable on a phone:
11+
12+
- **KPI value.** A dataset-bound KPI tile's value now shrinks to fit its tile, the way the plain metric tiles already did, instead of being cut with an ellipsis (`$1,090,00...` on a phone). Past the smallest size it keeps the ellipsis and shows the full figure as a tooltip. A short value looks as before.
13+
- **Month axis.** A chart over a month-bucketed date dimension labels its axis `Oct 2025` in the reader's locale, not the raw bucket key `2025-10`. The chart tooltip's header reads the same label. The key itself is unchanged in the data, so drill-through and ordering are unaffected. `@object-ui/core` adds `formatMonthBucketLabel(value, locale)`, which answers that label for a `YYYY-MM` key and `undefined` for anything else.
14+
- **Legend swatches.** A bar or area chart's legend draws a colour swatch for every series; it drew none, because those marks fill from a gradient. A comparison (`compareTo`) series' swatch is drawn hollow, so it reads apart from the solid swatch of the series it overlays in the same colour.
15+
- **Horizontal bar labels.** A horizontal bar chart's category labels are drawn in full on a phone, wrapped to at most two lines inside the axis, instead of cut to eight characters (`In Progr…`). A label still too long ends in an ellipsis and shows the full text as a tooltip.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
'@object-ui/app-shell': patch
4+
'@object-ui/plugin-form': patch
5+
'@object-ui/i18n': patch
6+
'@object-ui/console': patch
7+
---
8+
9+
Clause-②: yes (widening: `@object-ui/app-shell` exports `InvitationLinkHint` and `@object-ui/plugin-form` exports `useInitialFieldFocus`; no accept set moves)
10+
Metadata-protocol: none (platform object metadata only, no authorable key: `sys_invitation.status` options gain display labels, with `rejected` read as "Declined"; the role param of the four `invite_user` actions, `sys_member.add_member` and `sys_member.update_member_role` gains one shared `helpText`; `sys_invitation.resend_invitation` gains a `description` and carries its email and role over from the row; `sys_member.update_member_role` gains a `description` naming the member; the `expired` invitations list projects `role`)
11+
12+
The Invitations screens read more clearly and behave more predictably. Invitation statuses show as labels (Pending, Accepted, Declined, Expired, Canceled) instead of raw values. Every role picker that grants an organization role explains each role on its own line, and Change Role names the member it changes. Resend is a confirmation that names the invitee and keeps the invitation's email and role, instead of an editable form. The workspace's cancel dialog dismisses with "Keep invitation".
13+
14+
The console's action dialogs check an email or URL param before anything runs and mark a malformed value on its field. They open on their first editable field instead of Cancel, and closing one returns focus to the control that opened it: an action button that was disabled while its action ran, a row menu's trigger, or the first opener when a param dialog hands over to a result dialog. This applies to every action that uses the param, confirm and result dialogs.
15+
16+
The sign-in page tells a visitor to open their invitation link where sign-up is by invitation only. After accepting an invitation, the page says the user joined the organization and as which role, and Continue enters it.

‎.changeset/27545-record-pane-v4.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
'@object-ui/plugin-list': patch
4+
'@object-ui/app-shell': patch
5+
'@object-ui/i18n': patch
6+
---
7+
8+
feat(plugin-grid,plugin-list,app-shell,i18n): record pane v4 in the console — a record opens beside the list by default, ⤢ maximizes it in place on the same URL, and the full page opens only from the row's ↗ and the record header's ⋯ (#27545)
9+
10+
Clause-②: yes (widening)
11+
Metadata-protocol: none
12+
13+
No metadata key is added, removed or read differently: every change is in how the console opens a record from a list, and in the reader's own preference. The mechanics (the split face, the non-modal drawer, maximize, the list's narrowed faces) shipped in the change before this one.
14+
15+
- **`@object-ui/app-shell`**
16+
- The object page opens a record beside the list unless the reader prefers the drawer (Display menu); a reader who prefers the full page gets it from a row click. Below a 1000 px content area the pane is a non-modal drawer over the list.
17+
- The list is one element whatever the pane does, so it keeps its scroll. A click on another row swaps the pane's root record. The open row is tinted, follows ↑ ↓ and scrolls into view.
18+
- A `?recordId=` change (a row click, a step) re-renders none of the list: the router's setter and the list's handlers no longer change identity with the URL.
19+
- The bar's ⤢ maximizes the pane in place and no longer routes; nested levels share it. The full page opens from the row's ↗ and from the record header's `⋯`, whose last host item is 「Open as full page」. 「Collapse to drawer」 is drawn only on a page the ↗ opened.
20+
- A step keeps the record on screen until the next one arrives, and ↑ ↓ warm the related counts of both neighbours.
21+
- **`@object-ui/plugin-list`**
22+
- The Display menu's Open records section draws a third segment, Full page, when the host passes the new optional `recordOpen.selectPage`; a host that passes none sees two segments, as before, but now in the order Split | Drawer (it was Drawer | Split), since Split is the default. `recordOpen.preference`, an input the section only reads, also accepts `'page'`. `setPreference` still takes `'split' | 'drawer'`, so a host's setter keeps its type. The note says a record's ↗ always opens the full page.
23+
- Beside a record pane the record-count bar no longer prints the count (the console prints it under the list); the rest of the row stays.
24+
- **`@object-ui/plugin-grid`**: narrowed beside a pane, the row-actions column keeps its header's accessible name but draws no label, so it is only as wide as its ⋮.
25+
- **`@object-ui/i18n`**: `list.recordOpenPage` in all ten packs, and `list.recordOpenNote` reworded in all ten.

0 commit comments

Comments
 (0)