Commit 53642d4
fix(fields,core,detail): make the sharing-rule dialog usable — i18n, a picker that lists people, and permission-aware CTAs (#2920)
* fix(fields,core,detail): make the sharing-rule dialog usable — i18n, a picker that lists people, and permission-aware CTAs (objectstack#3821)
The Console's "New sharing rule" dialog could not produce a working rule.
**The recipient picker listed nothing, ever.** `QueryParams['$orderby']` was
typed as `Record | string[] | SortObject[]`, so `queryParamsToRecord` fed any
non-array value to `Object.entries`. Handed the clause string `'name asc'` —
which callers do build by hand — it walked the string index by index and emitted
`$orderby=0 n,1 a,2 m,…`. The server sorted by columns that don't exist and every
row was filtered out, so `recipient_id` showed "No matches" for every recipient
type. `ObjectGrid` builds the same shape from a schema-level `sort` in three
places, so grids with a string sort silently showed an empty table. A string
`$orderby` is now passed through verbatim; the type admits `string`, and
`RecipientPickerField` switched to the structured form so it can't regress.
**The three sharing-rule widgets never had translations.** `ObjectRefField`,
`RecipientPickerField` and `FilterConditionField` hardcoded their copy, so a
Chinese Console showed "Select an object", "Select a user", "No matches". They
now go through `useFieldTranslation`, with keys in all ten locales. The
recipient placeholder was the interesting one: it interpolated the enum value
into an English sentence (`Select a ${type.replace(/_/g,' ')}`) — a shape no
locale can translate — and is now a per-type key.
**Editing a rule silently dropped its recipient.** The picker resets the stored
id when `recipient_type` changes; it treated the edit form's `'' → 'user'`
hydration as such a change, so opening a saved rule blanked the recipient and
saving persisted the blank. Only a non-empty predecessor counts now.
**Building a filter submitted the surrounding form.** No `FilterBuilder` control
declared `type="button"`, and a bare <button> in a <form> defaults to submit —
adding a condition fired validation mid-edit and, on a valid form, saved.
**A rejected write showed the user raw server diagnostics.** The form rendered
`error.message` verbatim: `FORBIDDEN: insufficient privileges to update
showcase_private_note pi-TgoJ4_DM55Fqz` — untranslated, leaking the object's
machine name and the record id. Permission failures now render localized copy;
other failures keep the server's message, which is the useful part.
**The detail header offered "Edit" on records the user may only read.** Object
permissions can't say "this one record is read-only" — a read-only sharing grant
is exactly that — so the CTA opened the form and the user only found out at save
time. `RecordDetailView` and `DetailView` now also consult the explain engine's
record-grained verdict (`POST /security/explain` with a `recordId`, ADR-0090 D6
/ ADR-0095 C2 — the same pipeline the middleware runs). One cached request per
record, skipped when the object-level check already says no, and fail-open on
every uncertainty: a courtesy hint must never be why a permitted user can't act.
The server stays the authority (ADR-0057 D10).
Hardens `evaluatePermission` while there: a role config carrying only
`fieldPermissions` (no `actions`) made `check()` throw out of the render.
Browser-verified against the framework showcase Console in Chinese, end to end:
copy is localized, the picker lists real users / business units / positions, a
saved rule reopens intact, editing the filter no longer submits, and a
read-only recipient gets no Edit button while the same recipient at `edit`
level does — and can save.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(components,fields): a long combobox option truncates instead of running past the border (objectstack#3821)
The sharing-rule object picker rendered "成员 (showcase_project_membership)"
straight through the control's right edge and into the field beside it.
Two causes, both mine from the picker work in this branch:
- `Combobox`'s trigger keeps the component's `w-[200px]` default, so the object
picker sat at a third of the form column while `名称` next to it ran full
width — and it is the field holding the longest content on the form.
- The selected label was a bare text child of a flex button. Flex items need
`truncate` AND `min-w-0` to clip; it had neither, so the text simply drew
outside the box instead of ellipsizing.
The label now lives in a truncating span, the trigger may shrink, and the
dropdown takes `--radix-popover-trigger-width` rather than its own hardcoded
200px — a combobox widened by its consumer used to clip its own options. The
two sharing-rule pickers pass `w-full` so they line up with every other input;
`w-[200px]` stays as the component default and consumers keep overriding it,
so no other call site changes.
Pinned by tests that assert the classes, since none of this is visible in an
accessibility tree. Browser-measured both ways: at 1280px the trigger is 362px
and the 247px label fits with room to spare; narrowed to 700px the label clips
at 210px with `text-overflow: ellipsis` and stays inside the button.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent 952b978 commit 53642d4
31 files changed
Lines changed: 1215 additions & 46 deletions
File tree
- .changeset
- packages
- app-shell/src/views
- components/src
- __tests__
- custom
- renderers/form
- core/src/adapters
- __tests__
- fields/src/widgets
- i18n/src/locales
- permissions/src
- plugin-detail/src
- types/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| |||
959 | 959 | | |
960 | 960 | | |
961 | 961 | | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
962 | 982 | | |
963 | 983 | | |
964 | 984 | | |
| |||
1794 | 1814 | | |
1795 | 1815 | | |
1796 | 1816 | | |
1797 | | - | |
| 1817 | + | |
| 1818 | + | |
| 1819 | + | |
| 1820 | + | |
| 1821 | + | |
| 1822 | + | |
1798 | 1823 | | |
1799 | 1824 | | |
1800 | 1825 | | |
| |||
1942 | 1967 | | |
1943 | 1968 | | |
1944 | 1969 | | |
1945 | | - | |
| 1970 | + | |
1946 | 1971 | | |
1947 | 1972 | | |
1948 | 1973 | | |
| |||
Lines changed: 54 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
Lines changed: 77 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
Lines changed: 86 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
0 commit comments