/* eslint-disable react-refresh/only-export-components */ /* eslint-disable react-hooks/exhaustive-deps */ import type { TabHandle } from "@termix/plugin-sdk/frontend"; import { toast } from "sonner"; import { useTranslation } from "react-i18next"; import { Separator } from "@/components/separator"; import { Button } from "@/components/button"; import { Sheet, SheetContent } from "@/components/sheet"; import { ChevronLeft, ChevronRight, Maximize2, Minimize2, PanelRight, RotateCcw, SquareArrowOutUpRight, } from "lucide-react"; import { useState, useRef, useCallback, useEffect, useLayoutEffect, createRef, lazy, Suspense, } from "react"; import { createPortal } from "react-dom"; import { useIsMobile } from "@/hooks/use-mobile"; import { resetPermissionsCache } from "@/hooks/use-permissions"; import { MobileBottomBar } from "@/shell/MobileBottomBar"; import { AppRail, type RailView } from "@/sidebar/AppRail"; import { isCoreRailView, railItemLabel, promotableIds, rightDockableIds, useRailItems, } from "@/sidebar/rail-items"; import { MultiPanelHint } from "@/sidebar/MultiPanelHint"; import { OnboardingDialog } from "@/onboarding/OnboardingDialog"; import { UI_ONBOARDING_VERSION } from "@/types/ui-preferences"; import { useUiPreferencesContext } from "@/contexts/UiPreferencesContext"; import { defaultSizes, SplitView, type RowColSizes } from "@/shell/SplitView"; import { renderTabContent } from "@/shell/tabUtils"; import { TabBar } from "@/shell/TabBar"; import { dispatchCtrlW, isShiftKey } from "@/lib/app-keyboard-shortcuts"; import { parseCustomKeybindings } from "@/api/open-tabs-api"; import { findMatchingKeybinding } from "@/lib/keybinding-match"; import type { CustomKeybinding, KeybindingActionType, } from "@/types/keybindings"; // Shell surfaces that are not needed for first paint. const CommandPalette = lazy(() => import("@/shell/CommandPalette").then((m) => ({ default: m.CommandPalette, })), ); const HostsPanel = lazy(() => import("@/sidebar/HostsPanel").then((m) => ({ default: m.HostsPanel })), ); const QuickConnectPanel = lazy(() => import("@/sidebar/QuickConnectPanel").then((m) => ({ default: m.QuickConnectPanel, })), ); const SerialPanel = lazy(() => import("@/sidebar/SerialPanel").then((m) => ({ default: m.SerialPanel })), ); const SplitScreenPanel = lazy(() => import("@/sidebar/SplitScreenPanel").then((m) => ({ default: m.SplitScreenPanel, })), ); const AlertManager = lazy(() => import("@/dashboard/panels/alerts/AlertManager").then((m) => ({ default: m.AlertManager, })), ); // Secondary rail panels — load on first open, not with the shell critical path. const SshToolsPanel = lazy(() => import("@/sidebar/SshToolsPanel").then((m) => ({ default: m.SshToolsPanel })), ); const CollabPanel = lazy(() => import("@/sidebar/CollabPanel").then((m) => ({ default: m.CollabPanel })), ); const MacrosPanel = lazy(() => import("@/sidebar/MacrosPanel").then((m) => ({ default: m.MacrosPanel })), ); const ShareSessionModal = lazy(() => import("@/features/session-sharing/ShareSessionModal").then((m) => ({ default: m.ShareSessionModal, })), ); /** What a session tab's handle gives the shell's share dialog. */ interface ShareTarget { hostId: number; sessionId: string; protocol: "ssh"; tabInstanceId?: string; } const SessionLogsPanel = lazy(() => import("@/sidebar/SessionLogsPanel").then((m) => ({ default: m.SessionLogsPanel, })), ); // One screen behind both rail entries. It lazy-loads the profile and admin // panels itself, so the shell no longer imports either directly. const SettingsScreen = lazy(() => import("@/settings/SettingsScreen").then((m) => ({ default: m.SettingsScreen, })), ); const CredentialsPanel = lazy(() => import("@/sidebar/CredentialsPanel").then((m) => ({ default: m.CredentialsPanel, })), ); const TermixIdPanel = lazy(() => import("@/sidebar/TermixIdPanel").then((m) => ({ default: m.TermixIdPanel })), ); const ConnectionsPanel = lazy(() => import("@/sidebar/ConnectionsPanel").then((m) => ({ default: m.ConnectionsPanel, })), ); function SidebarPanelFallback() { return (