feat(sub-org): sub-organization menu selector UI/UX improvements#5599
feat(sub-org): sub-organization menu selector UI/UX improvements#5599
Conversation
Adds direct membership support for sub-organizations: new TJoinSubOrgDTO type, joinSubOrg service method, POST /:subOrgId/memberships route, and JOIN_SUB_ORGANIZATION audit event. Made-with: Cursor
Adds TJoinSubOrganizationDTO type and useJoinSubOrganization mutation hook calling POST /api/v1/sub-organizations/:subOrgId/memberships. Made-with: Cursor
Introduces a vertical tab layout in ProjectsPage with Projects and Sub Orgs tabs (root orgs only). SubOrgsView supports listing, searching, sorting, creating, editing, deleting, and joining sub-organizations with proper permission and license checks. Made-with: Cursor
Adds Mintlify endpoint pages for delete and join sub-organization operations, and registers the Sub Organizations group in docs.json. Made-with: Cursor
Adds a magnifying glass search input with thin-scrollbar list and divider to both the org dropdown flyout and breadcrumb sub-org switcher, matching the ProjectSelect pattern. Made-with: Cursor
- Row click logs into sub-org; removed dedicated login icon button - cursor-pointer on member rows; role/keyboard handlers follow a11y - Hide My/All toggle when user lacks DirectAccess permission - When DirectAccess is missing show only accessible sub-orgs (no badge) - Joined badge only shown in All Sub Orgs view with DirectAccess Made-with: Cursor
Match existing patterns (OrgRoleTable, AuditLogStreamRow) by using colorSchema="secondary" and className="w-6" on the options IconButton. Made-with: Cursor
Made-with: Cursor
Adds Edit and Delete actions to the SubOrganization permission subject, replacing the incorrect Settings subject fallback. Updates backend service, permission schema, default admin role, frontend types, role modify utils, and SubOrgsView to use the dedicated sub-org actions. Made-with: Cursor
Adds Edit and Delete checkboxes to OrgPermissionSubOrgRow so the new actions appear in the Access Control role editor, alongside Full Access and No Access presets. Made-with: Cursor
Adds validateSearch to the ProjectsPage route and replaces useState with useSearch/useNavigate so the active tab (Projects vs Sub Orgs) is reflected in the URL and survives page refreshes. Made-with: Cursor
Made-with: Cursor
…pdown search blocks Made-with: Cursor
…this option in the dropdown menu
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Greptile SummaryThis PR delivers a solid set of UI/UX improvements to the sub-organization experience: a searchable/paginated Sub-Orgs table in the Settings page, client-side search filters in both navbar dropdowns, new Delete and Join API endpoints (with audit logging), permission-gated Edit/Delete actions in the role UI, and an MFA flow for switching into sub-orgs. The overall structure is well-organized and consistent with existing patterns. Key concerns identified during review:
Confidence Score: 2/5
Important Files Changed
|
| Feature | Before | After |
|---|---|---|
rbac |
false |
true |
subOrganization |
false |
true |
samlSSO |
false |
true |
enforceGoogleSSO |
false |
true |
oidcSSO |
false |
true |
groups |
false |
true |
enforceMfa |
false |
true |
Only subOrganization: true is plausibly needed for the sub-org features in this PR. Enabling SAML SSO, OIDC SSO, Google SSO enforcement, RBAC, groups, and MFA enforcement for all self-hosted instances as a side-effect of a UI/UX PR is a very broad and potentially breaking product/licensing change. Any self-hosted deployment that relies on feature-gating these capabilities (e.g., restricting SSO to paid tiers) will silently have those gates removed.
Please confirm each change is intentional, and if so, call it out explicitly in the PR description and changelog so customers and the licensing team are aware.
frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx, line 1182 (link)
Navbar sub-org query regressed from 500 to default 25
The previous code fetched up to 500 accessible sub-orgs for the navbar dropdown:
subOrganizationsQuery.list({ limit: 500, isAccessible: true })The new code omits limit, so the backend falls back to its default of 25 (the Zod schema in sub-org-router.ts has .default(25)). For any user who is a member of more than 25 sub-orgs, the overflow entries will never appear in the navbar dropdown, regardless of whether they use the filter.
Consider passing an explicit higher limit (e.g., limit: 500) or, if the real goal is to use server-side search, remove the client-side SubOrgFilterList filtering and instead pass the search value to the API call so the server handles filtering across all records.
const subOrgQuery = subOrganizationsQuery.list({ limit: 500, isAccessible: true });frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx, line 1241-1246 (link)
subOrgMenuSearch not cleared when the org-picker sub-menu closes
The breadcrumb dropdown correctly resets its search state when closed:
onOpenChange={(open) => {
if (!open) setSubOrgBreadcrumbSearch("");
}}The DropdownSubMenu that wraps the org-picker sub-menu has no equivalent handler for subOrgMenuSearch. After a user searches in the org-picker, closes the dropdown, and reopens it, the previous search term is still visible — inconsistent with the breadcrumb behavior.
Consider adding an onOpenChange handler to the DropdownSubMenu (if the component exposes one) to clear subOrgMenuSearch on close, matching the breadcrumb pattern.
Last reviewed commit: 11e5ada
frontend/src/pages/organization/ProjectsPage/components/SubOrgsView.tsx
Outdated
Show resolved
Hide resolved
…, add join loading state and mutation error handling
|
@greptile review this again plz |
Move the OrgPermissionCan + "New Sub-Organization" button into SubOrgFilterList to eliminate duplicated markup at both call sites. Made-with: Cursor
…sion gates Rewrite OrgSubOrgsTab using v3 design system (UnstableCard, UnstableTable, UnstablePagination, UnstableDropdownMenu, UnstableEmpty, InputGroup) and replace FontAwesome icons with lucide-react equivalents. Wrap edit, delete, and join actions with OrgPermissionCan to hide UI when the user lacks the corresponding permissions. Only show cursor-pointer on rows when the user has DirectAccess permission. Made-with: Cursor
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 27411356 | Triggered | Generic Database Assignment | bc29752 | backend/src/ee/services/pam-discovery/active-directory/active-directory-discovery-factory.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Switch from CASL_ACTION_SCHEMA_ENUM with explicit values to CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionSubOrgActions) to match the pattern used by all other subjects and fix oasdiff breaking change detection. Made-with: Cursor
Add a read-only Sub-Organization ID field to SubOrgNameChangeSection, matching the existing Organization ID field in OrgNameChangeSection. Made-with: Cursor
|
@greptile check this pr again plz |
The Edit/Delete dropdown was gated behind `subOrg.isMember`, but the backend checks these permissions against the parent org, not the sub-org. This meant admins had to join a sub-org before they could manage it. Remove the membership guard so the actions menu renders based solely on org-level permissions. Made-with: Cursor
createSubOrg validates that the org plan includes the subOrganization feature, but joinSubOrg did not. Add the same license guard so users cannot join sub-orgs when the feature is not available on their plan. Made-with: Cursor
frontend/src/pages/organization/SettingsPage/components/OrgSubOrgsTab/OrgSubOrgsTab.tsx
Outdated
Show resolved
Hide resolved
frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx
Outdated
Show resolved
Hide resolved
frontend/src/pages/organization/SettingsPage/components/OrgSubOrgsTab/OrgSubOrgsTab.tsx
Show resolved
Hide resolved
Made-with: Cursor
Remove the limit: 500 param so the query uses the server default, avoiding silently incomplete results in the dropdown. Made-with: Cursor
|
@greptile once more plz |
The dev overrides enabling enterprise features (rbac, subOrganization, samlSSO, oidcSSO, groups, enforceMfa, enforceGoogleSSO) were accidentally included. Revert to the original values from main. Made-with: Cursor
Show the Join button in the Status column for non-members, replacing the empty space. Members see the "Joined" badge, non-members see the Join button (permission-gated). The actions column now only contains the edit/delete dropdown menu. Made-with: Cursor
Remove manual error notifications from edit, delete, and login handlers since the axios interceptor already displays error toasts for failed API requests. Made-with: Cursor
Made-with: Cursor
victorvhs017
left a comment
There was a problem hiding this comment.
All tested! Nice work!
Made-with: Cursor
Context
This PR introduces several UI/UX improvements to the sub-organization experience:
sub-organization:createpermission400error when joining a sub-org the user is already a member ofScreenshots
(https://www.loom.com/share/79ca41c0bff742a9a3c9747808c142e0)
Steps to verify the change
sub-organization:create: confirm both buttons are hidden400 already a membererrorType
Checklist
type(scope): short description(scope is optional, e.g.,fix: prevent crash on syncorfix(api): handle null response).