fix: stop permission manager from offering permissions Salesforce won't save - #1899
fix: stop permission manager from offering permissions Salesforce won't save#1899paustint wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves the Manage Permissions experience by preventing users from selecting permissions and objects that Salesforce will not persist, primarily by switching the object picker to an org-specific allow-list and by blocking “View All / Modify All” on known-unsupported objects. It also adds an “errors only” filter to help users quickly find failed rows after large saves.
Changes:
- Load an org-specific allow-list for
ObjectPermissions.SobjectTypeand defer object-picker loading until that filter data is ready (with heuristic fallback on failure). - Prevent setting View All / Modify All on objects where Salesforce silently drops those values; add UI affordances and regression tests.
- Add reusable row filtering that combines text filter + “errors only”, and fix
tableLabelfilter/copy behavior with tests.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/ui/src/lib/sobject-list/ConnectedSobjectListMultiSelect.tsx | Adds filterReady gating to avoid populating the list before async filter inputs are loaded. |
| libs/ui/src/index.ts | Re-exports computeFilterSetValues for downstream test/usage. |
| libs/types/src/lib/ui/permission-manager-types.ts | Extends permission table types with ViewAll/ModifyAll support flags and error-filter context fields. |
| libs/features/manage-permissions/src/utils/permission-manager-utils.ts | Adds org allow-list retrieval + filtering helpers, plus shared row filtering and error detection utilities. |
| libs/features/manage-permissions/src/utils/permission-manager-table-utils.tsx | Enforces ViewAll/ModifyAll blocking in all write paths; improves tableLabel handling; adds “errors only” UI toggle. |
| libs/features/manage-permissions/src/utils/object-permission-support.ts | Introduces the curated list of objects that don’t support ViewAll/ModifyAll and a helper to check support. |
| libs/features/manage-permissions/src/utils/tests/permission-manager-view-all-modify-all.spec.ts | Covers ViewAll/ModifyAll enforcement across per-cell, row, and column/bulk actions and row filtering behavior. |
| libs/features/manage-permissions/src/utils/tests/permission-manager-table-label-column.spec.ts | Regression tests to ensure tableLabel is treated as a string and not overridden by a broken getValue. |
| libs/features/manage-permissions/src/utils/tests/permission-manager-sobject-filter.spec.ts | Tests org allow-list loading/fallback behavior and filtering correctness. |
| libs/features/manage-permissions/src/usePermissionableSobjects.ts | New hook to load and refresh permissionable sObject allow-list per org with stale-result avoidance. |
| libs/features/manage-permissions/src/ManagePermissionsSelection.tsx | Wires org allow-list + filterReady into the picker and refresh behavior. |
| libs/features/manage-permissions/src/ManagePermissionsEditorTabVisibilityTable.tsx | Plumbs hasErrors/errorsOnly into the table context for the filter row toggle. |
| libs/features/manage-permissions/src/ManagePermissionsEditorSystemPermissionTable.tsx | Plumbs hasErrors/errorsOnly into the table context for the filter row toggle. |
| libs/features/manage-permissions/src/ManagePermissionsEditorObjectTable.tsx | Plumbs hasErrors/errorsOnly into the table context for the filter row toggle. |
| libs/features/manage-permissions/src/ManagePermissionsEditorFieldTable.tsx | Plumbs hasErrors/errorsOnly into the table context for the filter row toggle. |
| libs/features/manage-permissions/src/ManagePermissionsEditor.tsx | Uses shared row filtering with “errors only” across tables and passes new filter props to table components. |
9a3b2f2 to
b95cdb6
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (1)
libs/features/manage-permissions/src/utils/permission-manager-table-utils.tsx:1901
- The "errors only" toggle is only rendered when
hasErrorsis true. If a user turnserrorsOnlyon, then later clears/fixes all errors (sohasErrorsbecomes false), the toggle disappears whileerrorsOnlycan remain true—leaving the table filtered to zero rows with no UI to switch back to "show all".
{hasErrors && onToggleErrorsOnly && (
…'t save Saving "View All" against every standard object in a real org produced 446 failures out of 580 records, in three distinct classes. Two are fixed here; the third (concurrent save batches breaking cross-object dependencies) is not. The object picker now filters on the org's own allow-list. 423 of those failures were INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST across 291 distinct objects that cannot hold an ObjectPermissions record at all: setup and metadata objects (ApexClass, Profile, RecordType), children whose access rolls up to a parent (Task/Event, OpportunityLineItem, PricebookEntry, Attachment), and platform junctions (Group, FeedItem, User). ObjectPermissions.SobjectType is a restricted picklist whose values are exactly the permissionable objects, so the picker describes it and filters on the result. That is org-specific and accounts for which features are enabled, unlike the previous name/CRUD heuristic which let anything createable through. The describe is async while the existing filter runs synchronously after describeGlobal, so ConnectedSobjectListMultiSelect gained an optional filterReady prop that defers loading until the caller's filter data is ready; it defaults to true, so no other caller changes behavior. If the describe fails the picker falls back to the old heuristic rather than showing an empty list. Permission Analysis shares the picker and benefits for the same reason — non-permissionable objects produce no export rows either.
b95cdb6 to
b537c26
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (1)
libs/features/manage-permissions/src/utils/permission-manager-table-utils.tsx:759
Tooltipis rendered withariaRole="label"around the disabled checkbox. In this codebase,ariaRole="label"changes the ARIA relationship to be a label (not a tooltip/description), which can override the checkbox’s accessible name with the long explanatory message. This is better exposed as a tooltip/description rather than a label.
{unsupportedViewAllModifyAll ? (
<Tooltip ariaRole="label" content={VIEW_ALL_MODIFY_ALL_UNSUPPORTED_MESSAGE}>
{checkbox}
</Tooltip>
Saving "View All" against every standard object in a real org produced 446 failures out of 580 records, in three distinct classes. Two are fixed here; the third (concurrent save batches breaking cross-object dependencies) is not.
The object picker now filters on the org's own allow-list. 423 of those failures were INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST across 291 distinct objects that cannot hold an ObjectPermissions record at all: setup and metadata objects (ApexClass, Profile, RecordType), children whose access rolls up to a parent (Task/Event, OpportunityLineItem, PricebookEntry, Attachment), and platform junctions (Group, FeedItem, User). ObjectPermissions.SobjectType is a restricted picklist whose values are exactly the permissionable objects, so the picker describes it and filters on the result. That is org-specific and accounts for which features are enabled, unlike the previous name/CRUD heuristic which let anything createable through. The describe is async while the existing filter runs synchronously after describeGlobal, so ConnectedSobjectListMultiSelect gained an optional filterReady prop that defers loading until the caller's filter data is ready; it defaults to true, so no other caller changes behavior. If the describe fails the picker falls back to the old heuristic rather than showing an empty list. Permission Analysis shares the picker and benefits for the same reason — non-permissionable objects produce no export rows either.