Skip to content

Organization Admins Cannot See the Admin Section in the Account Dropdown #409

Description

@morepriyam

Overview

hasDefaultOrganizationAdminAccess() always returns false, for every user, unconditionally. It reads the role from a field that is hardcoded to null when the session user is constructed. As a result, organization owners and admins never see the Admin section of the account dropdown — the "Members" entry only appears for users who happen to also be enterprise admins, via an unrelated code path. The correct role data is already fetched and available; the accessor is reading the wrong field.

Current State

  • src/lib/useSession.tsx:97 hardcodes organizationMembership: null when building the user object.
  • src/lib/organizationAccess.ts:10getDefaultOrganizationRole() returns user?.organizationMembership?.role ?? null, i.e. always null.
  • hasDefaultOrganizationRole() and therefore hasDefaultOrganizationAdminAccess() always evaluate to false.
  • src/ui/UserDropdown.tsx:67 gates the Admin section on hasDefaultOrganizationAdminAccess(user). Because it is always false, the Admin section and its "Members" entry render only through the enterprises.length > 0 branch — so an org owner/admin who is not an enterprise admin has no route to organization member management from the account menu.
  • The correct data is already loaded: orgApi.listOrganizations() returns each org with a resolved role ('owner' | 'admin' | 'member' | null), and it is populated in both src/lib/useSession.tsx (as user.organizations) and src/lib/TeamContext.tsx (as organizations).

Proposed Changes

1. Resolve the role from the selected organization

  • Replace the organizationMembership-based accessor with one that derives the role from the already-populated org list and the currently selected org:
    • getOrganizationRole(organizations, selectedOrgId)organizations.find(o => o.id === selectedOrgId)?.role ?? null
    • hasOrganizationAdminAccess(organizations, selectedOrgId) → role is owner or admin
  • This mirrors the existing, working getEnterpriseRole / hasEnterpriseAdminAccess pair in the same file, which already take (list, selectedId).

2. Update the call site

  • src/ui/UserDropdown.tsx gates the Admin section on the new accessor, reading organizations and selectedOrgId from useTeam().
  • Admin entries then correctly follow the organization the user is currently in, rather than a single global notion of "default organization".

3. Remove the dead field and accessors

  • Drop organizationMembership from the user type if nothing else consumes it, along with getDefaultOrganizationRole / hasDefaultOrganizationRole / hasDefaultOrganizationAdminAccess once the call site is migrated, so the broken accessor cannot be reintroduced.

4. Consider the duplicate organization fetch

  • useSession.fetchSession and TeamContext.refetchOrganizations both call orgApi.listOrganizations() on login, producing two orgs_list round-trips. If user.organizations has no remaining consumers after this change, the session copy can be dropped.

Acceptance Criteria

  • An organization owner sees the Admin section and the "Members" entry without being an enterprise admin.
  • An organization admin sees the Admin section and the "Members" entry without being an enterprise admin.
  • An organization member (non-admin) does not see the Admin section.
  • Enterprise admins continue to see the Admin section, including the Enterprise entry.
  • Admin visibility reflects the currently selected organization: switching to an org where the user is only a member hides the Admin entries, and switching back restores them.
  • No accessor remains that reads organizationMembership.
  • npm run lint, npm run typecheck, npm run format, and npm run test:all all pass.

Out of Scope (for Now)

  • Moving the organization/team switcher into the nav header — tracked in its own issue.
  • Any change to how roles are resolved server-side in meteor-backend/server/organizations.js; this is a frontend-only wiring fix.
  • Enterprise role handling, which already works correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions