import { useQuery } from "@tanstack/react-query"; import { ChevronLeft, Clock3, CloudUpload, Cpu, FlaskConical, KeyRound, MailPlus, MonitorCog, Puzzle, Settings, Shield, SlidersHorizontal, UserRoundPen, Users, } from "lucide-react"; import type { PluginRecord } from "@paperclipai/shared"; import { sidebarBadgesApi } from "@/api/sidebarBadges"; import { instanceSettingsApi } from "@/api/instanceSettings"; import { pluginsApi } from "@/api/plugins"; import { ApiError } from "@/api/client"; import { Link, NavLink } from "@/lib/router"; import { INSTANCE_SETTINGS_PATH_PREFIX } from "@/lib/instance-settings"; import { SIDEBAR_SCROLL_RESET_STATE } from "@/lib/navigation-scroll"; import { queryKeys } from "@/lib/queryKeys"; import { useCompany } from "@/context/CompanyContext"; import { useSidebar } from "@/context/SidebarContext"; import { usePluginSlots } from "@/plugins/slots"; import { SidebarNavItem } from "./SidebarNavItem"; /** * Sandbox-provider-only plugins (e.g. E2B, exe.dev, Modal) have no per-plugin * settings page, so a sidebar entry would lead nowhere useful. Filter them out * here. Plugins that mix a sandbox provider with other contributions still * appear. */ function isSandboxProviderOnly(plugin: PluginRecord): boolean { const drivers = plugin.manifestJson.environmentDrivers ?? []; if (drivers.length === 0) return false; return drivers.every((d) => d.kind === "sandbox_provider"); } export function CompanySettingsSidebar() { const { selectedCompany, selectedCompanyId } = useCompany(); const { isMobile, setSidebarOpen } = useSidebar(); const { slots: companySettingsPluginSlots } = usePluginSlots({ slotTypes: ["companySettingsPage"], companyId: selectedCompanyId, enabled: !!selectedCompanyId, }); const { data: badges } = useQuery({ queryKey: selectedCompanyId ? queryKeys.sidebarBadges(selectedCompanyId) : ["sidebar-badges", "__disabled__"] as const, queryFn: async () => { try { return await sidebarBadgesApi.get(selectedCompanyId!); } catch (error) { if (error instanceof ApiError && (error.status === 401 || error.status === 403)) { return null; } throw error; } }, enabled: !!selectedCompanyId, retry: false, refetchInterval: 15_000, }); const { data: experimentalSettings } = useQuery({ queryKey: queryKeys.instance.experimentalSettings, queryFn: () => instanceSettingsApi.getExperimental(), }); const { data: plugins } = useQuery({ queryKey: queryKeys.plugins.all, queryFn: () => pluginsApi.list(), }); const showCloudUpstream = experimentalSettings?.enableCloudSync === true; const sidebarPlugins = (plugins ?? []).filter((plugin) => !isSandboxProviderOnly(plugin)); return ( ); }