Skip to content

Commit d12ae82

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-ybjm3h
2 parents 0f3c00a + 3346da2 commit d12ae82

77 files changed

Lines changed: 4993 additions & 472 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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/plugin-report': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(plugin-report): a report that declares `dateRange` draws a period chip and runs every query inside the chosen window
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
`ReportSchema.dateRange` (`{ dimension?, defaultRange, allowCustomRange }`) was accepted but read by nothing, so a report showed every period whatever it declared. The report page now reads it:
12+
13+
- **The chip.** A non-joined report that declares `dateRange` draws a date-range chip above its body: All time, the dashboard's presets under the dashboard's labels, and Custom… (two date inputs) unless `allowCustomRange: false`. It opens on `defaultRange`, or `this_month` when that is absent; `custom` opens the custom pick with no window until both ends are named.
14+
- **The window.** The active window rides every dataset query the report makes (the grouped table, the matrix cross-tab and the embedded chart) as one `selection.timeDimensions` entry `{ dimension, dateRange }` with no `granularity`: a preset goes by name, a custom pick as `[start, end]`, and All time sends no entry. The server ANDs it with `runtimeFilter` and the dataset's own filter. A new pick re-queries.
15+
- **The dimension.** A declared `dimension` is sent as written. Omitted, the renderer reads the dataset definition before any query and uses its one `type: 'date'` dimension; a dataset with none or several draws that authoring error in place of the report and queries nothing.
16+
- **Unchanged without it.** A report that does not declare `dateRange` draws no chip, reads no dataset definition and posts exactly the selection it posted before. A `joined` report (where the spec refuses `dateRange`) is not affected.
17+
18+
`@object-ui/i18n` gains `report.dateRange.from`, `report.dateRange.to`, `report.dateRange.datasetUnreadable` and `report.dateRange.noSingleDateDimension` in all ten locale packs; the preset labels reuse `dashboard.filters.*`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/console': patch
4+
---
5+
6+
fix(app-shell): Home, the app switcher and the `app:launcher` block no longer offer an app the user's permission sets hide
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
A permission set's `tabPermissions: { APP: 'hidden' }` hides an app from the member's launcher. The server applies that hide in one place, `GET /api/v1/me/apps`, and the console never read it: Home's tiles, the app switcher's menu and the `app:launcher` page block all listed `GET /api/v1/meta/app`, which still serves the hidden app because a hidden app keeps opening from a direct URL. So the member saw, and could open, the tile their admin had hidden.
12+
13+
What changes:
14+
15+
- The console reads `GET /api/v1/me/apps` once per user, beside its `/auth/me/permissions` read, and every launcher surface narrows its `/meta/app` list by that answer's app names. The tiles keep the labels, icons and publish state `/meta/app` serves.
16+
- An app the answer was not asked about is not hidden by it: an app that is installed or published after the read stays on the launcher, and the console asks again.
17+
- Home waits for the first answer, as it waits for the app list, so a hidden tile is never drawn and then removed.
18+
- A deployment without the security plugin answers `404` there; the launcher then lists every app the user can open, as before. Any other failure does the same and says so once on the browser console.
19+
- A hidden app still opens from its URL, and the switcher still names it while the user is in it. `default_off` is not a hide and changes nothing.
20+
21+
What to do: nothing. A permission set that already hides an app now hides it on Home, in the switcher and in launcher blocks.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/plugin-form': minor
3+
'@object-ui/console': minor
4+
---
5+
6+
fix(console): every console form entry point renders the form view's `buttons`, `layout` and `defaults`, and a tabbed form with subforms opens on its `defaultTab` (#26843)
7+
8+
Clause-②: no
9+
Metadata-protocol: semantic
10+
11+
A form view's `buttons`, `layout` and `defaults` saved and published, but the console set its own values over them, depending on which entry point opened the form:
12+
13+
- **The full-page record form** (`/new`, `/record/:id/edit`) and **the New / Edit dialog** set `showSubmit: true`, their own submit and cancel labels and `layout: 'vertical'`, so an authored `buttons.submit.label`, `buttons.*.show: false` or `layout: 'horizontal'` did nothing. Both now read them from the form view the flow selects. An authored label may be a per-locale map. The New dialog also ignored `defaults`; a create there now opens with them.
14+
- **`defaults` and the host's own opening values merge per field.** A URL prefill, a parent pre-link or a seeded calendar day still wins for the fields it names, and the form view's `defaults` fill the rest. Before, a create carrying any prefill dropped `defaults` entirely. An edit never reads `defaults`.
15+
- **The form page** (`/forms/:name`, and the public `/f/:slug`) never read `buttons` or `defaults`. An authored submit or cancel label now shows, `show: false` removes the button (the public form still draws no Cancel), and a create opens with `defaults`, over the object's own field defaults and under a `?prefill_` param.
16+
- **A tabbed form with subforms** opened on its first tab with the strip on top. `ObjectForm` now hands `defaultTab` / `tabPosition` (and `layout`) through `MasterDetailForm` to the header form. The modal's tabbed layout reads both keys, and its subforms arm now renders the header tabbed instead of stacked.
17+
- **A hidden Cancel on a master-detail form** (`showCancel: false`, or `buttons.cancel.show: false`) is no longer drawn: the action bar draws Cancel only when it is handed `onCancel`, and both form arms now hand none.
18+
19+
`buttons.reset` and the drawer keys (`drawerSide` / `drawerWidth`) are not covered: no console entry point draws a reset button or opens a form view as a drawer.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/plugin-list': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(plugin-list): the list toolbar shows a view's sharing type and lock owner as read-only text instead of a Share button that did nothing
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
A list view declaring `sharing` drew a ghost "Share" button with no click handler: clicking it opened nothing and sent nothing, and `sharing.lockedBy` was never shown anywhere. No view-sharing control or endpoint exists for the button to open, so it is now a non-interactive indicator:
12+
13+
- **The sharing type**, localized: "Personal view" for `type: 'personal'`, "Shared view" for `type: 'collaborative'`.
14+
- **The lock owner**, when `sharing.lockedBy` is set: a lock icon and "Locked by USER", with `lockedBy` rendered as written (the spec declares it a free string naming the user who locked the view configuration).
15+
- The tooltip carries both, so the narrow toolbar, which hides the text, still says them.
16+
17+
New `list.*` keys `sharingPersonal`, `sharingCollaborative` and `sharingLockedBy` ship in all ten `@object-ui/i18n` locale packs and in the plugin's English defaults. The element keeps its `share-button` test id.
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+
---
4+
5+
fix(app-shell): a locked metadata item's designer canvas is read-only
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
In Setup › All Metadata Types, a locked item (for example an object installed by a package, under the banner "This item is locked and cannot be edited or deleted.") still had a live designer canvas. On an object you could add a field, add a field to a section, move a section or remove one: the change showed in the canvas with an "Unsaved" chip, but the page offers no Save on a locked item, so the work was dropped without a word when you left.
11+
12+
What changes: when the page cannot write the item (it is locked, or you lack the capability to author metadata), the designer canvas gets no edit callback, so it renders read-only for every designer type, the way the Studio canvas already does for a read-only package. The Description box was already disabled on a locked item. Writable items are unchanged.
13+
14+
What to do: nothing.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/react': patch
3+
---
4+
5+
fix(react): a create or edit form marks the field a unique-index refusal names
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Saving a record whose value collides with a unique index (a product SKU, an account name that must be unique) used to show "A record with this value already exists" as a banner and a toast, with no field marked. The user had to guess which of the form's unique fields collided.
11+
12+
The server's `409 UNIQUE_VIOLATION` answer names the one field on `field`, with a sentence that names it by its label ("A record with this SKU already exists"). `extractFieldErrors` only read lists of field errors, so it answered nothing for this refusal. It now returns one entry for it: the named field, carrying the server's sentence. The form renderer writes that sentence under the input, as it does for a `required` field, and shows no banner. Inline edit on a record page reads the same helper, so its save bar attributes the refusal to that field too.
13+
14+
When the server cannot tell which column collided (an index name, a composite key), the answer has no `field` and nothing changes: the banner stays.
15+
16+
What to do: nothing.
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 grouped list on a phone draws its group headers and cards instead of the desktop table
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Below the 768px card breakpoint, `ObjectGrid` turned a plain list into one card per row but kept a grouped list (`grouping`) on its desktop table, so on a phone the titles were cut mid-word and every other column sat behind the pinned Actions column. A grouped list now takes the plain list's card layout: each group's header (its toggle, label and count), then that group's rows as the same cards, then, on a server-grouped list, the group's own pager. Collapsing a group hides its cards, and the grouped pager still pages whole groups. At a desktop width the grouped table is unchanged, and so is the plain list's card view, which now draws through the same card renderer.
11+
12+
What to do: nothing.
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 promoted bulk action's field-backed lookup param keeps the field's `lookupFilters`, `lookupColumns`, `lookupPageSize` and `descriptionField`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A view's `bulkActions` can name an object action whose param is backed by a lookup field (`{ field }`). The selection bar's dialog resolved that param through the same resolver as the single-record dialog, but then dropped the field's picker settings. So the selection-toolbar picker offered records the field's `lookupFilters` hides from the row-menu picker, and ignored the field's declared columns, page size and description field. The bulk dialog now hands those four settings to the record picker under the names the single-record dialog uses, so both pickers offer the same records.
11+
12+
What to do: nothing. A lookup field's `lookupFilters` now also narrows the selection-bar picker of any promoted bulk action that takes its param from that field.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@object-ui/plugin-dashboard': patch
3+
---
4+
5+
fix(plugin-dashboard): a dashboard tile whose data the viewer may not read is left out, not drawn as a permission error
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A viewer who may not read the data behind one dataset tile used to see that tile draw "You don't have permission to view the data behind this widget" among tiles that answered. Outside design mode, `DashboardRenderer` now leaves such a tile out of the layout, frame and title included, once the server refuses its query as a read refusal (403 / `PERMISSION_DENIED`), and the remaining tiles reflow. The server's refusal stays the only verdict: every tile is still queried, and nothing is hidden on a guess.
11+
12+
- In design mode the tile stays and draws the no-access state, so an author can still see and select it.
13+
- A failure that is not a read refusal keeps the tile and its error, as before.
14+
- The editable grid layout (`DashboardGridLayout`) keeps the tile and its no-access state, unchanged.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@object-ui/plugin-kanban': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(plugin-kanban): a lane that refuses the dragged card now says why
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
While a card is dragged, a lane the board's drop gate closes was dimmed and `aria-disabled` with nothing saying why. It now carries the reason as its `title` (a pointer user's tooltip) and as the text its `aria-describedby` names (assistive tech). An open lane carries neither, and the reason leaves with the drag. The swimlane layout's cells carry it the same way.
12+
13+
- **`object-kanban`.** The reason is the `message` of each blocking `state_machine` rule on the grouped field that refuses the move, the sentence the server's refusal of the same move carries. A rule the gate ignores (warning-only, inactive, insert-only, or silent on the card's value) is never named; several closing rules join their messages.
14+
- **Hosts of the board.** `KanbanBoardProps` gains an optional `dropBlockedReason(fromColumnId, toColumnId)` beside `canDropCard`. A host that answers nothing, or passes no function, gets the new `kanban.dropBlocked` sentence ("A card in To Do cannot be moved to Done.") with the two column titles, in all ten language packs.

0 commit comments

Comments
 (0)