Skip to content

Commit 1778135

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-isr622
2 parents 1b8e2b8 + 6390fe5 commit 1778135

117 files changed

Lines changed: 4762 additions & 1411 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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
refactor(app-shell)!: retire the 54 root-entry exports that nothing outside the package names
6+
7+
`@object-ui/app-shell`'s root entry published 261 names. 57 of them appear in no file of this repository outside `ui/packages/app-shell/` (the measure covers `ui/`, `packages/` and `apps/`); three of those are taken by the package's own README examples and stay (`SignUpOffer`, `RuntimeBranding`, `studioOrgScopePath`). The other 54 leave the entry. Every module that defines them stays, and code inside the package keeps importing them from there; only the package entry stops publishing them. The entry now publishes 209 names (207, plus `InvitationSignUpPrompt` and `isDefaultProductName`, which main added meanwhile).
8+
9+
Clause-②: yes (narrowing)
10+
Metadata-protocol: none
11+
12+
<!-- adr-0087: not-required (runtime-export-retired @object-ui/app-shell#useExpressionContext, @object-ui/app-shell#UseUrlOverlayOptions, @object-ui/app-shell#UrlOverlayControls, @object-ui/app-shell#SettleSignalState, @object-ui/app-shell#isIdle, @object-ui/app-shell#ObjectUiGlobal, @object-ui/app-shell#ExpressionContextValue, @object-ui/app-shell#RecentItemInput, @object-ui/app-shell#RecentTextItem, @object-ui/app-shell#RecentItemLabelResolver, @object-ui/app-shell#isOverrideOnlyViewer, @object-ui/app-shell#actionAdmittedByOverride, @object-ui/app-shell#bypassedApproverNames, @object-ui/app-shell#DeclaredHomeApp, @object-ui/app-shell#AiSurfaceState, @object-ui/app-shell#PreviewBadgeProps, @object-ui/app-shell#RedirectWithSplashProps, @object-ui/app-shell#toastWithUndo, @object-ui/app-shell#ToastWithUndoOptions, @object-ui/app-shell#getCloudBase, @object-ui/app-shell#getBrandColor, @object-ui/app-shell#isRuntimeConfigInitialised, @object-ui/app-shell#RuntimeFeatures, @object-ui/app-shell#RecordFormPageProps, @object-ui/app-shell#DeclaredActionsBarProps, @object-ui/app-shell#addNavigationItem, @object-ui/app-shell#removeNavigationItems, @object-ui/app-shell#renameNavigationItems, @object-ui/app-shell#navigationEqual, @object-ui/app-shell#generateNavId, @object-ui/app-shell#CommandPaletteContextValue, @object-ui/app-shell#SignUpOfferContext, @object-ui/app-shell#HydratedUIMessage, @object-ui/app-shell#listAppComponents, @object-ui/app-shell#urlSegmentsToComponentRef, @object-ui/app-shell#AppComponentRegistryEntry, @object-ui/app-shell#MetadataPageShell, @object-ui/app-shell#listMetadataResources, @object-ui/app-shell#useMetadataTypes, @object-ui/app-shell#useTypesIndex, @object-ui/app-shell#matchesQuery, @object-ui/app-shell#MetadataPreviewProps, @object-ui/app-shell#MetadataInspectorProps, @object-ui/app-shell#StudioDesignSurfaceProps, @object-ui/app-shell#getStudioCanvasPreview, @object-ui/app-shell#listStudioCanvasPreviewTypes, @object-ui/app-shell#StudioObjectRecordsCanvas, @object-ui/app-shell#StudioCanvasPreview, @object-ui/app-shell#StudioCanvasPreviewProps, @object-ui/app-shell#useAssistant, @object-ui/app-shell#useRegisterAssistantEditor, @object-ui/app-shell#requestAssistantOpen, @object-ui/app-shell#AssistantEditorContext, @object-ui/app-shell#AssistantEditorField) No metadata moves: no spec key, authorable spelling, object definition or stored shape is added, removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What retires is 54 names of `@object-ui/app-shell`'s published entry that no file in this repository outside the package names. The affected party is a TypeScript importer, and the compiler at that import delivers the break. -->
13+
14+
**BREAKING** (an export retirement), shipped as `patch`: no metadata protocol kind moves. An importer of a retired name gets `TS2305` ("has no exported member") at its import line.
15+
16+
Migration. A retired type that describes a name the entry still exports is derived from that name; everything else has no replacement on the entry.
17+
18+
- FROM `UseUrlOverlayOptions` TO `Parameters<typeof useUrlOverlay>[1]`.
19+
- FROM `UrlOverlayControls` TO `ReturnType<typeof useUrlOverlay>`.
20+
- FROM `SettleSignalState` TO `ReturnType<typeof useSettleSignal>`.
21+
- FROM `AiSurfaceState` TO `ReturnType<typeof useAiSurfaceEnabled>`.
22+
- FROM `CommandPaletteContextValue` TO `ReturnType<typeof useCommandPalette>`.
23+
- FROM `RecentItemInput` TO `Parameters<ReturnType<typeof useRecentItems>['addRecentItem']>[0]`.
24+
- FROM `RecentTextItem` TO `Extract<RecentItem, { label: string }>`.
25+
- FROM `RecentItemLabelResolver` TO `ReturnType<typeof useRecentItemLabel>`.
26+
- FROM `DeclaredHomeApp` TO `NonNullable<Parameters<typeof resolveDeclaredHomePath>[0]>[number]`.
27+
- FROM `RuntimeFeatures` TO `AppShellRuntimeConfig['features']`.
28+
- FROM `SignUpOfferContext` TO `Parameters<typeof decideSignUpOffer>[1]`.
29+
- FROM `HydratedUIMessage` TO `ReturnType<typeof toUIMessages>[number]`.
30+
- FROM `AppComponentRegistryEntry` TO `Parameters<typeof registerAppComponent>[0]`.
31+
- FROM `MetadataPreviewProps` TO `ComponentProps<MetadataPreview>` (`ComponentProps` from `react`).
32+
- FROM `MetadataInspectorProps` TO `ComponentProps<MetadataInspector>`.
33+
- FROM `StudioCanvasPreview` TO `Parameters<typeof registerStudioCanvasPreview>[1]`.
34+
- FROM `StudioCanvasPreviewProps` TO `ComponentProps<Parameters<typeof registerStudioCanvasPreview>[1]>`.
35+
- FROM `StudioDesignSurfaceProps` TO `ComponentProps<typeof StudioDesignSurface>`.
36+
- FROM `PreviewBadgeProps` TO `ComponentProps<typeof PreviewBadge>`.
37+
- FROM `RedirectWithSplashProps` TO `ComponentProps<typeof RedirectWithSplash>`.
38+
- FROM `RecordFormPageProps` TO `ComponentProps<typeof RecordFormPage>`.
39+
- FROM `DeclaredActionsBarProps` TO `ComponentProps<typeof DeclaredActionsBar>`.
40+
- FROM `useExpressionContext`, `ExpressionContextValue`, `isIdle`, `ObjectUiGlobal`, `isOverrideOnlyViewer`, `actionAdmittedByOverride`, `bypassedApproverNames`, `toastWithUndo`, `ToastWithUndoOptions`, `getCloudBase`, `getBrandColor`, `isRuntimeConfigInitialised` TO nothing (no replacement on the entry).
41+
- FROM `addNavigationItem`, `removeNavigationItems`, `renameNavigationItems`, `navigationEqual`, `generateNavId` TO nothing (no replacement on the entry).
42+
- FROM `listAppComponents`, `urlSegmentsToComponentRef` TO nothing (no replacement on the entry): `getAppComponent` and `componentRefToUrlSegments` stay.
43+
- FROM `MetadataPageShell`, `listMetadataResources`, `useMetadataTypes`, `useTypesIndex`, `matchesQuery` TO nothing (no replacement on the entry): `getMetadataResource`, `useMetadataClient` and `useGlobalDiagnostics` stay.
44+
- FROM `getStudioCanvasPreview`, `listStudioCanvasPreviewTypes`, `StudioObjectRecordsCanvas` TO nothing (no replacement on the entry): `registerStudioCanvasPreview` stays.
45+
- FROM `useAssistant`, `useRegisterAssistantEditor`, `requestAssistantOpen`, `AssistantEditorContext`, `AssistantEditorField` TO nothing (no replacement on the entry): `assistantBus` stays.
46+
47+
`ui/docs/app-shell-extraction-guide.md`, the package's architecture guide, is rewritten to describe the package that ships: what each directory holds, the groups of names the entry publishes, its load-time registrations, its dependencies, and its three consumers in this repository.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
'@object-ui/types': minor
3+
'@object-ui/react': minor
4+
'@object-ui/sdui-parser': minor
5+
'@object-ui/app-shell': patch
6+
---
7+
8+
feat(types,react,sdui-parser,app-shell)!: the node-level `visibleOn` / `hiddenOn` / `disabledOn` spellings are retired; `visibleWhen` / `hidden` / `disabled` are the one predicate each
9+
10+
Clause-②: no (narrowing)
11+
Metadata-protocol: narrowed
12+
13+
<!-- adr-0087: not-required (no-migration-prescription) The three keys are `@object-ui/types` schema members on objectui's own node face, not an `@objectstack/spec` key, object definition, stored row or stored shape: the spec declares `visibleWhen` as the one conditional-visibility predicate at every layer (ADR-0089) and never declared a `*On` suffix on a page component, so the ADR-0087 registries in `packages/spec` have no entry to write and `objectstack migrate meta` has nothing to rewrite. Each old spelling is refused by name on both faces (the TypeScript compiler, the Zod mirror behind `objectui validate`), and the refusal names the surviving key; that is the same disposition the objectui retirements took when the package merged into this repository (maintainer ruling 28 = B on objectstack#25831). The guidance below is for the author of a page, not for a metadata upgrader. The other categories are closed on facts: the four packages publish (not unpublished); no ADR-0087 id is named or touched (not registered or already-registered); and what narrows is a declared schema key on a published metadata face, not a runtime-only interface, a type annotation or a runtime export (not runtime-interface-only, type-surface-only or runtime-export-retired). -->
14+
15+
`@objectstack/spec` declares exactly one conditional-visibility predicate at every layer, `visibleWhen`, and objectui carried three spellings of its own beside it: `visibleOn` beside `visibleWhen`, `hiddenOn` beside `hidden`, `disabledOn` beside `disabled`. Each pair was evaluated by the same code with the same polarity, so the second spelling added a dialect and nothing else. The three are retired, with no alias window.
16+
17+
- **`@object-ui/types`**: `BaseSchema.visibleOn`, `hiddenOn` and `disabledOn` are `never` on the TypeScript face and alias refusals on the Zod mirror. A document that writes one is refused at that key, and the message names the key that survives (`visibleWhen`, `hidden`, `disabled`), says the polarity is the same, and says the value is unchanged. `objectui validate` reads the same mirror, so it prints the same refusal. The `object-view` table slot's refusal of the same three keys now names the surviving node key too (write `visibleWhen` / `hidden` / `disabled` on the object-view node itself) instead of sending the author to a retired spelling. Boolean `visible` stays: the spec declares it on actions, navigation entries, tabs, alerts and settings, and the renderer keeps evaluating it.
18+
- **`@object-ui/react`**: `SchemaRenderer`'s visibility chain has three legs, `visibleWhen` and `visible` (shown when truthy) and `hidden` (hidden when truthy), and the enablement gate has one, `disabled`. A stale retired key that reaches the renderer unvalidated is not consulted and is held out of the component's props, so it neither gates the node nor lands in the DOM.
19+
- **`@object-ui/sdui-parser`**: the three keys are no longer base props. `validateTree` reports each as an `unknown-prop` diagnostic that names the surviving key, so a TSX tree is told the same thing a JSON document is. `checkRetiredVisibilityDialect` and `RETIRED_VISIBILITY_DIALECTS` are exported for that reading.
20+
- **`@object-ui/app-shell`**: the command palette reads a navigation entry's `visible` only; the `visibleOn` fallback it carried read a key `NavigationItem` never declared.
21+
22+
**BREAKING** (an accept-set narrowing) for any page, view or component document that writes `visibleOn`, `hiddenOn` or `disabledOn` on a node. No shipped example, fixture or skill example in this repository wrote one; the ones in the documentation and the `objectui` skill are rewritten in this change.
23+
24+
- **Before.** The three keys parsed, were evaluated beside their canonical twin, and the docs taught both spellings.
25+
- **Now.** Each is refused by name on `objectui validate`, on the Zod mirror, by the TypeScript compiler and by the SDUI parser, and the renderer does not read it.
26+
- **Fix.** Rename the key and keep the value: `visibleOn` becomes `visibleWhen`, `hiddenOn` becomes `hidden`, `disabledOn` becomes `disabled`. A form field's `fields[].visibleOn` is a different, view-level slot and is unchanged.
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+
refactor(app-shell): the Console `ObjectView`'s identity import and record navigation move into sibling hooks
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Two concerns move verbatim out of `ObjectViewInner` in `views/ObjectView.tsx`. The identity-import gate, its password-policy state and data source, and the managed-environment Users marker move into `useObjectViewIdentity` in `objectViewIdentity.tsx`. The record navigation overlay (how a row opens its record, the drawer's `?recordId=` URL state, "expand to full page" and the list's record links) moves into `useObjectViewRecordNavigation` in `objectViewRecordNavigation.ts`. The component passes every input in and reads the returned values. No logic, name or rendered output changes, and the package entry is unchanged.
11+
12+
What to do: nothing.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): the Setup position page shows, read-only, what each permission set the position names grants
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A position grants access only through the permission sets its definition names in `permissionSets`. The position page in Setup → Positions listed those names but showed nothing of what they grant, so an admin had to open every set to see its objects, capabilities and record scopes.
11+
12+
- **One preview per named set.** Under the position's definition, beside its holders, the page now shows each named set's permission preview: the object × capability grid with each object's read and write scope, field-level overrides, row-level policies, system permissions and tabs. The previews follow the order the position names the sets. Each is headed by the set's name, which links to the set's own page.
13+
- **No merge, no editing.** Each preview shows one set as stored. The page does not compute what the sets add up to, and nothing in the previews is editable. A set is changed on its own page.
14+
- **A set that does not load.** A named set the server does not serve shows one line, `Permission set "NAME" was not found.`, for that set only; the other previews still show. A read the server refuses says that, with the server's sentence, instead of "not found".
15+
- **No sets.** A position that names no permission sets says so.
16+
17+
The permission-set page itself is unchanged: its matrix already shows each object's read and write scope.
18+
19+
What to do: nothing. No spec key, stored shape or API changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/service-automation': minor
4+
'@object-ui/app-shell': minor
5+
---
6+
7+
feat(spec,automation,app-shell): a read-only `record_link` screen field shows a record the run created, by its display name, as a link to its record page
8+
9+
Clause-②: yes (widening)
10+
Metadata-protocol: added
11+
12+
A screen flow can now end on a result screen that links the records it created, instead of a toast that points at nothing.
13+
14+
```ts
15+
{ id: 'done', type: 'screen', config: { title: 'Lead converted', fields: [
16+
{ name: 'account_link', label: 'Account', type: 'record_link',
17+
reference: 'crm_account', defaultValue: { dialect: 'cel', source: 'account.id' } },
18+
] } },
19+
```
20+
21+
- **`@objectstack/spec`**: `ScreenFieldConfigSchema` gains the `type` member `'record_link'` (`SCREEN_FIELD_RECORD_LINK_TYPE`). On it, `reference` (the record's object) and `defaultValue` (a value slot that evaluates to the record's id) are required, and `required`, `options`, `placeholder`, `min` and `max` are refused, each at its own key with the exported refusal text (`SCREEN_FIELD_RECORD_LINK_REFERENCE_REQUIRED`, `SCREEN_FIELD_RECORD_LINK_DEFAULT_VALUE_REQUIRED`, `screenFieldRecordLinkRefusedKey`). The name is `record_link`, not `record`, because `record` is already an object field type (a name-keyed map of sub-objects) and a screen field's `type` uses the same vocabulary. Every other `type` value parses as before.
22+
- **`@objectstack/service-automation`**: the resume refuses any value sent under a `record_link` field's name, `null` included and visible or not, with `400 INVALID_SCREEN_INPUT` and the field code `invalid_value` ("shows a record and takes no value"). The value is never bound to a flow variable, the refusal keeps the pause, and a resume that leaves the field out still lands. A caller's param that shares the field's name never counts as answering the screen, so a result screen always pauses.
23+
- **`@object-ui/app-shell`**: the flow screen dialog shows a `record_link` field as the record's display name (the object's `nameField`, through the lookup widget's read-only branch) inside a link to `/apps/APP/OBJECT/record/ID`. An empty id shows "—" with no link, and an object the console cannot route to shows the name without a link. `visibleWhen` works as on any field. The dialog never seeds or posts a value for the field.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
---
4+
5+
fix(plugin-grid): a bulk action's confirm sentence formats its numbers and dates in the viewer's display locale
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A bulk `confirmText` such as `Set the amount to {{ amount | currency:EUR }} on {{ count }} records?` formatted its numbers and dates in `en-US` for every viewer, while the same action's single-record confirm formats them in the viewer's language. `BulkActionDialog` now reads `useDisplayLocale()`, the locale every date, number and currency renderer and the console's action runners read, and `bulkConfirmText` takes it as an optional third argument, handed to `fillTemplateHoles`'s locale channel apart from the template roots. A German viewer reads `1.234.567,50 €`; with no locale handed, the sentence formats in `en-US` as before.
11+
12+
What to do: nothing.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/spec': patch
3+
'@objectstack/plugin-approvals': patch
4+
'@objectstack/rest': patch
5+
'@objectstack/client': patch
6+
---
7+
8+
feat(plugin-approvals,rest,client): a record-anchored approval lock read, `{ locked }` for every caller who can read the record
9+
10+
Clause-②: yes (widening)
11+
Metadata-protocol: none
12+
13+
A member who could read and edit a record but was not on its approval was offered an edit the server then refused with `409 RECORD_LOCKED`. The lock's only carrier was the request row's `lock_record`, and that row is rightly not served to a non-participant unless the object turns on `approvalsVisibleToReaders`. The lock now has a carrier of its own.
14+
15+
- **`@objectstack/spec`.** `IApprovalService` gains the optional member `getRecordLock(object, recordId, context)`, which answers `{ locked: boolean }`, or `null` when the caller cannot read the record. No exported schema or type is added.
16+
- **`@objectstack/plugin-approvals`.** `ApprovalService.getRecordLock` reads the record as the caller. A record the caller cannot read answers `null`, the same answer as an id that does not exist. A caller with no read on the object is refused for every id, whether it exists or not. `locked` is `true` while a pending request's node has `lockRecord` other than `false`. The lock judgement is now one function, `nodeConfigLocksRecord` (not exported from the package), and the record-lock hook, the request row's `lock_record` and the new read all call it. Request content stays behind `approvalsVisibleToReaders`: the answer carries no request id, node, approvers or `pending` flag.
17+
- **`@objectstack/rest`.** New route `GET /api/v1/approvals/records/:object/:recordId/lock`. It answers `{ success: true, data: { locked } }`. A `null` answers `404 RECORD_NOT_FOUND` with one body, whether the record is unreadable or missing. A service without the member answers `501`. The route's closed query-parameter set is empty, so any query parameter is refused with a `400`. The route is ledgered as `sdk`.
18+
- **`@objectstack/client`.** `client.approvals.getRecordLock(object, recordId)` calls that route.

0 commit comments

Comments
 (0)