mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 20:53:06 +00:00
fix(global-reader): show platform nav on global scope regardless of the Global View toggle
The cross-tenant nav group (Managed Tenants, Fleet Health, Software, Geographic, SLA, Usage, Audit...) was gated on `hasGlobalScope && globalAdminMode`. globalAdminMode defaults to false (localStorage) and there is only auto-DISABLE logic, no auto-enable, so a fresh GlobalReader (or a GA with no own-tenant role) saw only "Dashboard" until they discovered the hidden "Global View" toggle in the avatar menu -- a dead end. A delegated MSP admin, by contrast, gets the full fleet nav with no toggle. Decouple nav VISIBILITY from the toggle: the platform nav is reachable for any caller with global scope (GA or read-only GlobalReader). The toggle now governs only the DATA scope (own-tenant vs cross-tenant) of the pages, not whether the nav is reachable. Mutating controls inside these views stay gated on isGlobalAdmin. Removed the now-dead globalAdminMode dependency from the sidebar. tsc clean; web 485 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,6 @@ import { CollapseState } from "../hooks/useSidebarState";
|
|||||||
import { DefaultSectionIcon, BookOpenIcon, RocketLaunchIcon, InformationCircleIcon, DocumentTextIcon, ShieldCheckIcon } from "../lib/sidebarIcons";
|
import { DefaultSectionIcon, BookOpenIcon, RocketLaunchIcon, InformationCircleIcon, DocumentTextIcon, ShieldCheckIcon } from "../lib/sidebarIcons";
|
||||||
import { DASHBOARD_ITEM, NAV_GROUPS, EXPANDABLE_NAV_GROUPS, REGULAR_USER_ITEMS, NavItem, NavGroup, ExpandableNavGroup, ExpandableNavItem } from "../lib/globalNavConfig";
|
import { DASHBOARD_ITEM, NAV_GROUPS, EXPANDABLE_NAV_GROUPS, REGULAR_USER_ITEMS, NavItem, NavGroup, ExpandableNavGroup, ExpandableNavItem } from "../lib/globalNavConfig";
|
||||||
import { PublicSiteNavbar } from "./PublicSiteNavbar";
|
import { PublicSiteNavbar } from "./PublicSiteNavbar";
|
||||||
import { useAdminMode } from "../hooks/useAdminMode";
|
|
||||||
|
|
||||||
// Sidebar pixel widths
|
// Sidebar pixel widths
|
||||||
export const SIDEBAR_PX: Record<CollapseState, number> = {
|
export const SIDEBAR_PX: Record<CollapseState, number> = {
|
||||||
@@ -46,9 +45,6 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
|
|||||||
return () => mql.removeEventListener("change", handler);
|
return () => mql.removeEventListener("change", handler);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Global admin mode from hook
|
|
||||||
const { globalAdminMode } = useAdminMode();
|
|
||||||
|
|
||||||
// --- Scroll-spy for page sections ---
|
// --- Scroll-spy for page sections ---
|
||||||
const [activeSectionId, setActiveSectionId] = useState("");
|
const [activeSectionId, setActiveSectionId] = useState("");
|
||||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||||
@@ -184,8 +180,11 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
|
|||||||
case "all": return true;
|
case "all": return true;
|
||||||
case "adminOrOperator": return isAdminOrOperator;
|
case "adminOrOperator": return isAdminOrOperator;
|
||||||
// Cross-tenant nav is a VISIBILITY surface → any platform scope (GA or read-only GlobalReader).
|
// Cross-tenant nav is a VISIBILITY surface → any platform scope (GA or read-only GlobalReader).
|
||||||
// Mutating controls inside these views are gated separately on isGlobalAdmin.
|
// Deliberately NOT gated on globalAdminMode: a pure GlobalReader (or a GA with no own-tenant role)
|
||||||
case "globalAdmin": return hasGlobalScope && globalAdminMode;
|
// would otherwise see only "Dashboard" until they discovered the hidden "Global View" toggle. The
|
||||||
|
// toggle now governs only the DATA scope (own-tenant vs cross-tenant) of the pages, not whether the
|
||||||
|
// platform nav is reachable. Mutating controls inside these views stay gated separately on isGlobalAdmin.
|
||||||
|
case "globalAdmin": return hasGlobalScope;
|
||||||
// Fleet (MSP) nav: shown to a delegated admin who does NOT have full platform scope. A GA/Reader
|
// Fleet (MSP) nav: shown to a delegated admin who does NOT have full platform scope. A GA/Reader
|
||||||
// manages tenants through the richer Global Admin section instead, so it stays hidden for them.
|
// manages tenants through the richer Global Admin section instead, so it stays hidden for them.
|
||||||
case "fleet": return isDelegated && !hasGlobalScope;
|
case "fleet": return isDelegated && !hasGlobalScope;
|
||||||
@@ -230,7 +229,7 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
|
|||||||
return { ...group, items: filteredItems };
|
return { ...group, items: filteredItems };
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [isAdminOrOperator, isGlobalAdmin, globalAdminMode, hasMcpAccess, isAdminLike, canManageBootstrapTokens, bootstrapTokenEnabled, unrestrictedModeEnabled]);
|
}, [isAdminOrOperator, isGlobalAdmin, hasMcpAccess, isAdminLike, canManageBootstrapTokens, bootstrapTokenEnabled, unrestrictedModeEnabled]);
|
||||||
|
|
||||||
// Auto-expand the group containing the current pathname
|
// Auto-expand the group containing the current pathname
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user