diff --git a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx index 5876b9366..78873e399 100644 --- a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx @@ -96,4 +96,19 @@ describe('PermissionMatrixEditPage — B1 first-screen collapse (objectui#2600)' expect(screen.getByTestId('cap-picker')).toBeInTheDocument(); expect(screen.queryByRole('button', { name: /Add capability/i })).toBeNull(); }); + + // objectui#3332 — a large capability chip wall (44+ grants → 20+ rows) is a + // non-shrinking sibling of the flex-1 object matrix; unbounded it squeezed + // the matrix to ~9px with no page scrollbar. The picker must sit inside a + // height-capped, internally-scrolling container so the matrix keeps the rest + // of the viewport. + it('caps the capability area with its own scroll so the matrix stays reachable (objectui#3332)', async () => { + await renderSet({ + systemPermissions: Array.from({ length: 44 }, (_, i) => `navigation.item_${i}`), + }); + const wrap = screen.getByTestId('capability-scroll'); + expect(wrap).toContainElement(screen.getByTestId('cap-picker')); + expect(wrap.className).toContain('overflow-y-auto'); + expect(wrap.className).toMatch(/max-h-/); + }); }); diff --git a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx index c929a15fc..6f2c24b8a 100644 --- a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx +++ b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx @@ -775,15 +775,26 @@ export function PermissionMatrixEditPage({ type, name, packageId, onDraftSaved,

{t('perm.field.systemCapabilitiesHelp')}

- - setDraft((p) => ({ ...p, systemPermissions: parseCapabilityNames(v) })) - } - field={{ name: 'system_permissions' } as any} - dataSource={adapter as any} - readonly={!writable} - /> + {/* objectui#3332 — the capability chip wall grows with the live + sys_capability registry (44+ nav capabilities → 20+ rows). It is + a non-shrinking sibling of the flex-1 matrix, so unbounded it + squeezes the object list to ~0px with no page scrollbar. Cap it + to a viewport share and scroll internally; the matrix keeps the + remaining height (per #2600 B1 the picker itself stays inline). */} +
+ + setDraft((p) => ({ ...p, systemPermissions: parseCapabilityNames(v) })) + } + field={{ name: 'system_permissions' } as any} + dataSource={adapter as any} + readonly={!writable} + /> +
)}