import { ChevronLeft, AppWindow, Store, ShieldQuestion } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; import { Link } from "@/lib/router"; import { useCompany } from "@/context/CompanyContext"; import { useSidebar } from "@/context/SidebarContext"; import { queryKeys } from "@/lib/queryKeys"; import { toolsApi } from "@/api/tools"; import { DEVELOPER_TABS, advancedTabHref, isExperimentalToolTab } from "@/pages/tools/tool-tabs"; import { useSmokeLabEnabled } from "@/hooks/useSmokeLabEnabled"; import { useReviewCount } from "@/pages/apps/useReviewCount"; import { SidebarNavItem } from "./SidebarNavItem"; /** * Secondary sidebar for the prosumer Apps area (PAP-10856; three-door IA * PAP-13254 / U3). * * โ† Back ยท APPS: Browse / Connections / Review (n) * DEVELOPER: Gateways / Profiles / Rules / Health / Activity * * The three consumer doors are peers: "Browse" (the store โ€” discover + add), * "Connections" (your connected tools + health), and "Review" (PAP-12371, * Finding B โ€” decisions waiting on your OK, with a live pending count). * "Needs attention" is no longer a door: health/error triage folds into * Connections as a status filter + banner, so approvals are never buried * behind an error label. The Developer section was folded in from the retired * ToolsSidebar (PAP-10915) so the whole Apps area shares one sidebar; a * one-line caption frames who it's for (Finding A). "Run your own" and "Paste a * config" moved out of the sidebar into rows on the Connect-an-app page * (PAP-10922). */ export function AppsSidebar() { const { selectedCompany, selectedCompanyId } = useCompany(); const { isMobile, setSidebarOpen } = useSidebar(); const reviewCount = useReviewCount(); const { enabled: smokeLabEnabled } = useSmokeLabEnabled(); const developerTabs = DEVELOPER_TABS.filter( (tab) => !isExperimentalToolTab(tab.key) || smokeLabEnabled, ); const runtimeSlots = useQuery({ queryKey: queryKeys.tools.runtimeSlots(selectedCompanyId ?? "__none__"), queryFn: () => toolsApi.listRuntimeSlots(selectedCompanyId!), enabled: !!selectedCompanyId, refetchInterval: 15_000, }); const runtimeActiveCount = (runtimeSlots.data?.runtimeSlots ?? []) .filter((slot) => slot.status === "running").length; return ( ); }