From 36efb5ae4437b52d100205c55b71feb26d256c87 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Tue, 28 Oct 2025 09:46:08 +0200 Subject: [PATCH 01/18] Add Comet Debugger Mode feature and related components - Introduced a new feature toggle for Comet Debugger Mode in the configuration and frontend. - Added `useIsNetworkOnline` hook to monitor network status. - Implemented `AppNetworkStatus` component to display network and server connection status. - Created `UserMenuAppDebugInfoToggle` for toggling debug info visibility in the user menu. - Updated layouts and components to integrate the new debug features, including `NoUserMenu` and `AppDebugInfo`. - Added `comet.svg` icon for visual representation. This commit enhances the debugging capabilities of the application, allowing developers to monitor backend connectivity and toggle debug information visibility. --- apps/opik-backend/config.yml | 4 + .../opik-frontend/src/api/debug/useIsAlive.ts | 42 +++++++++ .../components/feature-toggles-provider.tsx | 1 + .../layout/AppDebugInfo/AppDebugInfo.tsx | 52 +++++++++++ .../src/components/layout/NoUserMenu.tsx | 92 +++++++++++++++++++ .../PartialPageLayout/PartialPageLayout.tsx | 6 +- .../layout/SMEPageLayout/SMEPageLayout.tsx | 4 +- .../src/components/layout/TopBar/TopBar.tsx | 7 +- .../src/hooks/useIsNetworkOnline.ts | 21 +++++ apps/opik-frontend/src/icons/comet.svg | 1 + .../src/plugins/comet/AppNetworkStatus.tsx | 71 ++++++++++++++ .../src/plugins/comet/UserMenu.tsx | 8 ++ .../comet/UserMenuAppDebugInfoToggle.tsx | 48 ++++++++++ apps/opik-frontend/src/store/DebugStore.ts | 14 +++ .../src/types/feature-toggles.ts | 1 + 15 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 apps/opik-frontend/src/api/debug/useIsAlive.ts create mode 100644 apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx create mode 100644 apps/opik-frontend/src/components/layout/NoUserMenu.tsx create mode 100644 apps/opik-frontend/src/hooks/useIsNetworkOnline.ts create mode 100644 apps/opik-frontend/src/icons/comet.svg create mode 100644 apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx create mode 100644 apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx create mode 100644 apps/opik-frontend/src/store/DebugStore.ts diff --git a/apps/opik-backend/config.yml b/apps/opik-backend/config.yml index fc6496fc57d..eaec8b6577c 100644 --- a/apps/opik-backend/config.yml +++ b/apps/opik-backend/config.yml @@ -526,6 +526,10 @@ serviceToggles: # Default: false # Description: Whether or not Welcome Wizard is enabled welcomeWizardEnabled: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"false"} + # Default: false + # Description: Whether or not Comet Debugger Mode is enabled + cometDebuggerModeEnabled: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"false"} + # Trace Thread configuration traceThreadConfig: diff --git a/apps/opik-frontend/src/api/debug/useIsAlive.ts b/apps/opik-frontend/src/api/debug/useIsAlive.ts new file mode 100644 index 00000000000..ad44a3a0e82 --- /dev/null +++ b/apps/opik-frontend/src/api/debug/useIsAlive.ts @@ -0,0 +1,42 @@ +import api from "@/api/api"; +import { useQuery } from "@tanstack/react-query"; + +const PING_FETCHING_TIMEOUT_SECONDS = 5; +const CONNECTED_PING_REFETCH_INTERVAL_SECONDS = 10; +const DISCONNECTED_PING_REFETCH_INTERVAL_SECONDS = 5; + +interface IsAlivePingResponse { + healthy: boolean; + rtt: number; +} + +const getPing = async (): Promise => { + const startTime = performance.now(); + + const { data } = await api.get("/is-alive/ping", { + timeout: PING_FETCHING_TIMEOUT_SECONDS * 1000, + }); + + const endTime = performance.now(); + + const rtt = endTime - startTime; + + return { ...data, rtt }; +}; + +export const usePingBackend = (isNetworkOnline: boolean) => + useQuery({ + queryKey: ["backend-ping"], + queryFn: getPing, + enabled: isNetworkOnline, + retryDelay: 1000, + refetchInterval: (query) => { + const { error: isError, data } = query.state; + const isConnected = !isError && data?.healthy; + + return isConnected + ? CONNECTED_PING_REFETCH_INTERVAL_SECONDS * 1000 + : DISCONNECTED_PING_REFETCH_INTERVAL_SECONDS * 1000; + }, + refetchOnReconnect: true, + }); diff --git a/apps/opik-frontend/src/components/feature-toggles-provider.tsx b/apps/opik-frontend/src/components/feature-toggles-provider.tsx index e0c83a78f0a..b46a026517e 100644 --- a/apps/opik-frontend/src/components/feature-toggles-provider.tsx +++ b/apps/opik-frontend/src/components/feature-toggles-provider.tsx @@ -20,6 +20,7 @@ const DEFAULT_STATE: FeatureToggles = { [FeatureToggleKeys.TOGGLE_OPIK_AI_ENABLED]: false, [FeatureToggleKeys.TOGGLE_ALERTS_ENABLED]: false, [FeatureToggleKeys.WELCOME_WIZARD_ENABLED]: false, + [FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED]: false, }; const initialState: FeatureTogglesState = { diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx new file mode 100644 index 00000000000..495e0919aa1 --- /dev/null +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -0,0 +1,52 @@ +import { useIsFeatureEnabled } from "@/components/feature-toggles-provider"; +import { toast } from "@/components/ui/use-toast"; +import { APP_VERSION } from "@/constants/app"; +import AppNetworkStatus from "@/plugins/comet/AppNetworkStatus"; +import { COMET_DEBUGGER_MODE_KEY } from "@/plugins/comet/UserMenuAppDebugInfoToggle"; +import { useDebugStore } from "@/store/DebugStore"; +import { FeatureToggleKeys } from "@/types/feature-toggles"; +import copy from "clipboard-copy"; +import { Copy } from "lucide-react"; +import { useEffect } from "react"; + +const AppDebugInfo = () => { + const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); + const isCometDebuggerModeEnabled = useIsFeatureEnabled( + FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, + ); + const setShowAppDebugInfo = useDebugStore( + (state) => state.setShowAppDebugInfo, + ); + + useEffect(() => { + const localStorageValue = localStorage.getItem(COMET_DEBUGGER_MODE_KEY); + const shouldShowAppDebugInfo = + isCometDebuggerModeEnabled && localStorageValue?.toLowerCase() === "true"; + + setShowAppDebugInfo(shouldShowAppDebugInfo); + }, [isCometDebuggerModeEnabled, setShowAppDebugInfo]); + + return ( + showAppDebugInfo && ( + <> +
+ +
+
{ + copy(APP_VERSION); + toast({ description: "Successfully copied version" }); + }} + > + + 🦉 OPIK VERSION {APP_VERSION} + + +
+ + ) + ); +}; + +export default AppDebugInfo; diff --git a/apps/opik-frontend/src/components/layout/NoUserMenu.tsx b/apps/opik-frontend/src/components/layout/NoUserMenu.tsx new file mode 100644 index 00000000000..dc15226ba03 --- /dev/null +++ b/apps/opik-frontend/src/components/layout/NoUserMenu.tsx @@ -0,0 +1,92 @@ +import { Check, Copy, Settings2 } from "lucide-react"; +import copy from "clipboard-copy"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuPortal, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { useThemeOptions } from "@/hooks/useThemeOptions"; +import { APP_VERSION } from "@/constants/app"; +import { toast } from "../ui/use-toast"; +import UserMenuAppDebugInfoToggle from "@/plugins/comet/UserMenuAppDebugInfoToggle"; +import { FeatureToggleKeys } from "@/types/feature-toggles"; +import { useIsFeatureEnabled } from "../feature-toggles-provider"; + +const NoUserMenu = () => { + const isCometDebuggerModeEnabled = useIsFeatureEnabled( + FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, + ); + const { theme, themeOptions, currentOption, CurrentIcon, handleThemeSelect } = + useThemeOptions(); + + return ( + + + + + + + {isCometDebuggerModeEnabled && } + + + + Theme + + + + {themeOptions.map(({ value, label, icon: Icon }) => ( + handleThemeSelect(value)} + > +
+ {theme === value && ( + + )} + + {label} +
+
+ ))} +
+
+
+
+ {APP_VERSION && ( + <> + + { + copy(APP_VERSION); + toast({ description: "Successfully copied version" }); + }} + > + + VERSION {APP_VERSION} + + + + + )} +
+
+ ); +}; + +export default NoUserMenu; diff --git a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx index 7a6f2db5a7c..52f22ad4dfa 100644 --- a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx @@ -3,7 +3,8 @@ import useAppStore from "@/store/AppStore"; import usePluginsStore from "@/store/PluginsStore"; import { Link, Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; +import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; +import NoUserMenu from "../NoUserMenu"; export const PartialPageLayout = ({ children = , @@ -30,7 +31,8 @@ export const PartialPageLayout = ({ - {UserMenu ? : } + + {UserMenu ? : }
diff --git a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx index cd4492d9793..bbc88f92e38 100644 --- a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx @@ -2,7 +2,7 @@ import React from "react"; import usePluginsStore from "@/store/PluginsStore"; import { Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; +import NoUserMenu from "../NoUserMenu"; export const SMEPageLayout = ({ children = , @@ -22,7 +22,7 @@ export const SMEPageLayout = ({
diff --git a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx index c681149bb36..fcae0f9d60f 100644 --- a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx +++ b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx @@ -1,7 +1,7 @@ -import React from "react"; import Breadcrumbs from "@/components/layout/Breadcrumbs/Breadcrumbs"; import usePluginsStore from "@/store/PluginsStore"; -import ThemeToggle from "../ThemeToggle/ThemeToggle"; +import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; +import NoUserMenu from "../NoUserMenu"; const TopBar = () => { const UserMenu = usePluginsStore((state) => state.UserMenu); @@ -12,7 +12,8 @@ const TopBar = () => { - {UserMenu ? : } + + {UserMenu ? : } ); }; diff --git a/apps/opik-frontend/src/hooks/useIsNetworkOnline.ts b/apps/opik-frontend/src/hooks/useIsNetworkOnline.ts new file mode 100644 index 00000000000..49e64939210 --- /dev/null +++ b/apps/opik-frontend/src/hooks/useIsNetworkOnline.ts @@ -0,0 +1,21 @@ +import { useState, useEffect } from "react"; + +const useIsNetworkOnline = () => { + const [isNetworkOnline, setIsNetworkOnline] = useState(navigator.onLine); + + useEffect(() => { + const updateNetworkStatus = () => setIsNetworkOnline(navigator.onLine); + + window.addEventListener("online", updateNetworkStatus); + window.addEventListener("offline", updateNetworkStatus); + + return () => { + window.removeEventListener("online", updateNetworkStatus); + window.removeEventListener("offline", updateNetworkStatus); + }; + }, []); + + return isNetworkOnline; +}; + +export default useIsNetworkOnline; diff --git a/apps/opik-frontend/src/icons/comet.svg b/apps/opik-frontend/src/icons/comet.svg new file mode 100644 index 00000000000..f289c18d2a1 --- /dev/null +++ b/apps/opik-frontend/src/icons/comet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx new file mode 100644 index 00000000000..89c2fb3856f --- /dev/null +++ b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx @@ -0,0 +1,71 @@ +import { cn } from "@/lib/utils"; + +import CometIcon from "@/icons/comet.svg?react"; +import { usePingBackend } from "@/api/debug/useIsAlive"; +import useIsNetworkOnline from "@/hooks/useIsNetworkOnline"; +import { WifiOffIcon, WifiIcon, SatelliteDishIcon } from "lucide-react"; +import TooltipWrapper from "@/components/shared/TooltipWrapper/TooltipWrapper"; + +const AppNetworkStatus = () => { + const isNetworkOnline = useIsNetworkOnline(); + const { data: pingResponse, isError } = usePingBackend(isNetworkOnline); + const rtt = pingResponse?.rtt; + const rttInSeconds = rtt ? (rtt / 1000).toFixed(2) : null; + const isConnectedToCometServer = + isNetworkOnline && !isError && pingResponse?.healthy; + + return ( +
+ {isConnectedToCometServer && ( +
+ + + RTT: {rttInSeconds}s + +
+ )} + {isNetworkOnline && ( +
+
+ + + +
+ )} +
+
+ + {isNetworkOnline ? ( + + ) : ( + + )} + +
+
+ ); +}; + +export default AppNetworkStatus; diff --git a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx index b6d8cef38a3..d9067adac8b 100644 --- a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx +++ b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx @@ -48,6 +48,9 @@ import { buildUrl, isOnPremise, isProduction } from "./utils"; import useAllWorkspaces from "@/plugins/comet/useAllWorkspaces"; import useUserInvitedWorkspaces from "@/plugins/comet/useUserInvitedWorkspaces"; import useInviteMembersURL from "@/plugins/comet/useInviteMembersURL"; +import UserMenuAppDebugInfoToggle from "./UserMenuAppDebugInfoToggle"; +import { useIsFeatureEnabled } from "@/components/feature-toggles-provider"; +import { FeatureToggleKeys } from "@/types/feature-toggles"; const UserMenu = () => { const navigate = useNavigate(); @@ -61,6 +64,10 @@ const UserMenu = () => { (match) => match.staticData?.hideUpgradeButton, ); + const isCometDebuggerModeEnabled = useIsFeatureEnabled( + FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, + ); + const { data: user } = useUser(); const { data: organizations, isLoading } = useOrganizations({ enabled: !!user?.loggedIn, @@ -376,6 +383,7 @@ const UserMenu = () => { + {isCometDebuggerModeEnabled && } diff --git a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx new file mode 100644 index 00000000000..4685adaaf1f --- /dev/null +++ b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx @@ -0,0 +1,48 @@ +import { useDebugStore } from "@/store/DebugStore"; +import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; +import { SquareMousePointerIcon } from "lucide-react"; +import TooltipWrapper from "@/components/shared/TooltipWrapper/TooltipWrapper"; +import { Switch } from "@/components/ui/switch"; + +export const COMET_DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same in EM + +const UserMenuAppDebugInfoToggle = () => { + const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); + const setShowAppDebugInfo = useDebugStore( + (state) => state.setShowAppDebugInfo, + ); + + const handleToggle = (event: React.MouseEvent) => { + event.preventDefault(); + const shouldShowAppDebugInfo = !showAppDebugInfo; + + localStorage.setItem( + COMET_DEBUGGER_MODE_KEY, + String(shouldShowAppDebugInfo).toLowerCase(), + ); + setShowAppDebugInfo(shouldShowAppDebugInfo); + }; + + return ( + +
+ + + + Debugger + + +
+ +
+ ); +}; + +export default UserMenuAppDebugInfoToggle; diff --git a/apps/opik-frontend/src/store/DebugStore.ts b/apps/opik-frontend/src/store/DebugStore.ts new file mode 100644 index 00000000000..5b869244c7c --- /dev/null +++ b/apps/opik-frontend/src/store/DebugStore.ts @@ -0,0 +1,14 @@ +import { create } from "zustand"; +import { devtools } from "zustand/middleware"; + +interface DebugStore { + showAppDebugInfo: boolean; + setShowAppDebugInfo: (show: boolean) => void; +} + +export const useDebugStore = create()( + devtools((set) => ({ + showAppDebugInfo: false, + setShowAppDebugInfo: (show) => set({ showAppDebugInfo: show }), + })), +); diff --git a/apps/opik-frontend/src/types/feature-toggles.ts b/apps/opik-frontend/src/types/feature-toggles.ts index 5de68ea254d..632631a83a3 100644 --- a/apps/opik-frontend/src/types/feature-toggles.ts +++ b/apps/opik-frontend/src/types/feature-toggles.ts @@ -6,4 +6,5 @@ export enum FeatureToggleKeys { TOGGLE_OPIK_AI_ENABLED = "opik_aienabled", TOGGLE_ALERTS_ENABLED = "alerts_enabled", WELCOME_WIZARD_ENABLED = "welcome_wizard_enabled", + COMET_DEBUGGER_MODE_ENABLED = "comet_debugger_mode_enabled", } From 0296fa0d08fea2a06c81416436ab03117cdfedd1 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 15:46:16 +0200 Subject: [PATCH 02/18] Add Opik icon to AppDebugInfo component - Imported Opik icon as a React component in AppDebugInfo. - Updated the layout to include the icon alongside the OPIK VERSION text for improved visual representation. This change enhances the user interface by providing a clearer branding element in the debug information section. --- .../src/components/layout/AppDebugInfo/AppDebugInfo.tsx | 6 ++++-- apps/opik-frontend/src/icons/opik.svg | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 apps/opik-frontend/src/icons/opik.svg diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index 495e0919aa1..c81d183e34f 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -2,6 +2,7 @@ import { useIsFeatureEnabled } from "@/components/feature-toggles-provider"; import { toast } from "@/components/ui/use-toast"; import { APP_VERSION } from "@/constants/app"; import AppNetworkStatus from "@/plugins/comet/AppNetworkStatus"; +import OpikIcon from "@/icons/opik.svg?react"; import { COMET_DEBUGGER_MODE_KEY } from "@/plugins/comet/UserMenuAppDebugInfoToggle"; import { useDebugStore } from "@/store/DebugStore"; import { FeatureToggleKeys } from "@/types/feature-toggles"; @@ -39,8 +40,9 @@ const AppDebugInfo = () => { toast({ description: "Successfully copied version" }); }} > - - 🦉 OPIK VERSION {APP_VERSION} + + + OPIK VERSION {APP_VERSION}
diff --git a/apps/opik-frontend/src/icons/opik.svg b/apps/opik-frontend/src/icons/opik.svg new file mode 100644 index 00000000000..1b3a57c1cad --- /dev/null +++ b/apps/opik-frontend/src/icons/opik.svg @@ -0,0 +1,9 @@ + + + + + + + + + From 2aad3c79aeb927347eb783da4f61ec213737c90c Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 15:46:58 +0200 Subject: [PATCH 03/18] Enhance Switch Component with Extra Small Size Variant - Added 'xs' size variant to the switch component for improved responsiveness. - Updated UserMenuAppDebugInfoToggle to utilize the new 'xs' size for the debug info switch, enhancing UI consistency. --- apps/opik-frontend/src/components/ui/switch.tsx | 2 ++ .../src/plugins/comet/UserMenuAppDebugInfoToggle.tsx | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opik-frontend/src/components/ui/switch.tsx b/apps/opik-frontend/src/components/ui/switch.tsx index 80868cf1d41..af960ff0efe 100644 --- a/apps/opik-frontend/src/components/ui/switch.tsx +++ b/apps/opik-frontend/src/components/ui/switch.tsx @@ -11,6 +11,7 @@ const switchVariants = cva( size: { default: "h-6 w-11", sm: "h-5 w-9", + xs: "h-4 w-7", }, }, defaultVariants: { @@ -27,6 +28,7 @@ const switchThumbVariants = cva( default: "size-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0", sm: "size-4 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0", + xs: "size-3 data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0", }, }, defaultVariants: { diff --git a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx index 4685adaaf1f..5bace3c9375 100644 --- a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx +++ b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx @@ -31,13 +31,13 @@ const UserMenuAppDebugInfoToggle = () => {
- + Debugger
From 0572251faf88905306931e8aba5b0ecce2dd2593 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 15:57:28 +0200 Subject: [PATCH 04/18] Enhance AppNetworkStatus component with styled RTT display - Updated the RTT display in the AppNetworkStatus component to use a new class for improved styling, enhancing the visual appeal and consistency of the user interface. --- apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx index 89c2fb3856f..401c103b970 100644 --- a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx +++ b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx @@ -20,7 +20,7 @@ const AppNetworkStatus = () => {
- RTT: {rttInSeconds}s + RTT: {rttInSeconds}s
)} From d52576e554907ed1a5832af021a8b4e5eb1406fb Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 15:57:39 +0200 Subject: [PATCH 05/18] Add cometDebuggerModeEnabled toggle to ServiceTogglesConfig - Introduced a new boolean field `cometDebuggerModeEnabled` in the ServiceTogglesConfig class to manage the debugger mode feature. - This addition enhances the configuration options available for service toggles, allowing for better control over debugging functionalities. --- .../com/comet/opik/infrastructure/ServiceTogglesConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java index 2914bb782e0..f65e92f1e13 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java @@ -19,4 +19,6 @@ public class ServiceTogglesConfig { @NotNull boolean alertsEnabled; @JsonProperty @NotNull boolean welcomeWizardEnabled; + @JsonProperty + @NotNull boolean cometDebuggerModeEnabled; } From 354036383e6e806da430d8ed6e092de4adab22ea Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 17:02:15 +0200 Subject: [PATCH 06/18] Update AppDebugInfo component to conditionally render OPIK version display - Modified the AppDebugInfo component to only display the OPIK version section if the APP_VERSION is defined, improving the component's robustness and preventing potential rendering issues when the version is not available. --- .../layout/AppDebugInfo/AppDebugInfo.tsx | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index c81d183e34f..7b540cd320a 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -33,19 +33,22 @@ const AppDebugInfo = () => {
-
{ - copy(APP_VERSION); - toast({ description: "Successfully copied version" }); - }} - > - - - OPIK VERSION {APP_VERSION} - - -
+ + {APP_VERSION && ( +
{ + copy(APP_VERSION); + toast({ description: "Successfully copied version" }); + }} + > + + + OPIK VERSION {APP_VERSION} + + +
+ )} ) ); From aa1d2723739db92101a6b3b01746678311a7d1a7 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 17:02:32 +0200 Subject: [PATCH 07/18] Update end-to-end workflows and configuration for Comet Debugger Mode - Modified the end-to-end workflow files to include the `TOGGLE_COMET_DEBUGGER_MODE_ENABLED` environment variable during the build process. - Updated the `config.yml` to set the default value of `cometDebuggerModeEnabled` to true, enhancing the service toggles configuration. - Added the `TOGGLE_COMET_DEBUGGER_MODE_ENABLED` variable to the Docker Compose configuration, ensuring it is available in the deployment environment. --- .github/workflows/end2end_suites.yml | 2 +- .github/workflows/end2end_suites_typescript.yml | 2 +- apps/opik-backend/config.yml | 4 ++-- deployment/docker-compose/docker-compose.yaml | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/end2end_suites.yml b/.github/workflows/end2end_suites.yml index 8665c89af49..9d06a308ec0 100644 --- a/.github/workflows/end2end_suites.yml +++ b/.github/workflows/end2end_suites.yml @@ -66,7 +66,7 @@ jobs: OPIK_USAGE_REPORT_ENABLED: false run: | cd ${{ github.workspace }} - TOGGLE_WELCOME_WIZARD_ENABLED="false" ./opik.sh --build + TOGGLE_WELCOME_WIZARD_ENABLED="false" TOGGLE_COMET_DEBUGGER_MODE_ENABLED="false" ./opik.sh --build - name: Check Docker pods are up (Local) run: | diff --git a/.github/workflows/end2end_suites_typescript.yml b/.github/workflows/end2end_suites_typescript.yml index fd54dec50d6..42111966d82 100644 --- a/.github/workflows/end2end_suites_typescript.yml +++ b/.github/workflows/end2end_suites_typescript.yml @@ -88,7 +88,7 @@ jobs: OPIK_USAGE_REPORT_ENABLED: false run: | cd ${{ github.workspace }} - TOGGLE_WELCOME_WIZARD_ENABLED="false" ./opik.sh --build + TOGGLE_WELCOME_WIZARD_ENABLED="false" TOGGLE_COMET_DEBUGGER_MODE_ENABLED="false" ./opik.sh --build - name: Check Docker pods are up (Local) run: | diff --git a/apps/opik-backend/config.yml b/apps/opik-backend/config.yml index eaec8b6577c..c3d88306c11 100644 --- a/apps/opik-backend/config.yml +++ b/apps/opik-backend/config.yml @@ -526,9 +526,9 @@ serviceToggles: # Default: false # Description: Whether or not Welcome Wizard is enabled welcomeWizardEnabled: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"false"} - # Default: false + # Default: true # Description: Whether or not Comet Debugger Mode is enabled - cometDebuggerModeEnabled: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"false"} + cometDebuggerModeEnabled: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"true"} # Trace Thread configuration diff --git a/deployment/docker-compose/docker-compose.yaml b/deployment/docker-compose/docker-compose.yaml index 7d2ea12be29..fe1b93384ae 100644 --- a/deployment/docker-compose/docker-compose.yaml +++ b/deployment/docker-compose/docker-compose.yaml @@ -163,6 +163,7 @@ services: PYTHON_EVALUATOR_URL: http://python-backend:8000 TOGGLE_GUARDRAILS_ENABLED: ${TOGGLE_GUARDRAILS_ENABLED:-"false"} TOGGLE_WELCOME_WIZARD_ENABLED: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"true"} + TOGGLE_COMET_DEBUGGER_MODE_ENABLED: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"true"} CORS: ${CORS:-false} ATTACHMENTS_STRIP_MIN_SIZE: ${ATTACHMENTS_STRIP_MIN_SIZE:-256000} JACKSON_MAX_STRING_LENGTH: ${JACKSON_MAX_STRING_LENGTH:-104857600} From 2a9ce720e7a67c8c0f4c918efcd8ec9876a667e6 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 17:08:13 +0200 Subject: [PATCH 08/18] [OPIK-2848] Fix Tailwind CSS classnames order --- .../src/components/layout/AppDebugInfo/AppDebugInfo.tsx | 2 +- .../src/plugins/comet/UserMenuAppDebugInfoToggle.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index 7b540cd320a..8a9e2314a85 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -42,7 +42,7 @@ const AppDebugInfo = () => { toast({ description: "Successfully copied version" }); }} > - + OPIK VERSION {APP_VERSION} diff --git a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx index 5bace3c9375..958bac38a66 100644 --- a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx +++ b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx @@ -25,13 +25,13 @@ const UserMenuAppDebugInfoToggle = () => { return (
- + Debugger From 432575421b3f4db167525403f20823a3a70e80a5 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 17:22:00 +0200 Subject: [PATCH 09/18] Refactor UserMenu component to use logical AND for APP_VERSION check - Updated the UserMenu component to conditionally render the OPIK version section using a logical AND operator instead of a ternary operator, improving code readability and consistency. --- apps/opik-frontend/src/plugins/comet/UserMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx index d9067adac8b..a5edcc7a587 100644 --- a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx +++ b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx @@ -425,7 +425,7 @@ const UserMenu = () => { Logout - {APP_VERSION ? ( + {APP_VERSION && ( <> { - ) : null} + )} ); From 576b15d2084aec0a2ddd010c0e4c0749cf2e8cb8 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Fri, 7 Nov 2025 17:31:01 +0200 Subject: [PATCH 10/18] Wrap CometIcon in a span within AppNetworkStatus component for improved layout consistency --- apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx index 401c103b970..2873a2e693f 100644 --- a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx +++ b/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx @@ -39,7 +39,9 @@ const AppNetworkStatus = () => { : "Not connected to Comet server" } > - + + +
)} From 4dbd0e5a665e8ae87100ecccbb9ba0ae637fc3f3 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Sun, 9 Nov 2025 11:33:34 +0200 Subject: [PATCH 11/18] Revision 2: Add keyboard shortcut for debugger mode and remove menu toggles - Add Meta/Ctrl + c + . keyboard shortcut to toggle debugger mode - Remove UserMenuAppDebugInfoToggle from UserMenu and NoUserMenu - Debugger mode now controlled exclusively via keyboard shortcut --- .../layout/AppDebugInfo/AppDebugInfo.tsx | 54 +++++++++++++++++-- .../src/components/layout/NoUserMenu.tsx | 7 --- .../src/plugins/comet/UserMenu.tsx | 8 --- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index 8a9e2314a85..f9ea454cb69 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -12,7 +12,7 @@ import { useEffect } from "react"; const AppDebugInfo = () => { const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); - const isCometDebuggerModeEnabled = useIsFeatureEnabled( + const cometDebuggerModeEnabled = useIsFeatureEnabled( FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, ); const setShowAppDebugInfo = useDebugStore( @@ -22,10 +22,58 @@ const AppDebugInfo = () => { useEffect(() => { const localStorageValue = localStorage.getItem(COMET_DEBUGGER_MODE_KEY); const shouldShowAppDebugInfo = - isCometDebuggerModeEnabled && localStorageValue?.toLowerCase() === "true"; + cometDebuggerModeEnabled && localStorageValue?.toLowerCase() === "true"; setShowAppDebugInfo(shouldShowAppDebugInfo); - }, [isCometDebuggerModeEnabled, setShowAppDebugInfo]); + }, [cometDebuggerModeEnabled, setShowAppDebugInfo]); + + // Keyboard shortcut handler for debugger mode: Meta/Ctrl + c + . + useEffect(() => { + if (!cometDebuggerModeEnabled) { + return; + } + + let isWaitingForPeriod = false; + + const handleKeyDown = (event: KeyboardEvent) => { + const isMetaOrCtrl = event.metaKey || event.ctrlKey; + const isCKey = event.key === "c" || event.key === "C"; + const isPeriodKey = event.key === "." || event.key === ">"; + + // First part: Meta/Ctrl + c - start waiting for period + if (isMetaOrCtrl && isCKey && !isWaitingForPeriod) { + isWaitingForPeriod = true; + return; + } + + // Second part: Period while still holding Meta/Ctrl - complete sequence + if (isMetaOrCtrl && isPeriodKey && isWaitingForPeriod) { + event.preventDefault(); + event.stopPropagation(); + isWaitingForPeriod = false; + + // Toggle debugger mode + const shouldShowAppDebugInfo = !showAppDebugInfo; + localStorage.setItem( + COMET_DEBUGGER_MODE_KEY, + String(shouldShowAppDebugInfo).toLowerCase(), + ); + setShowAppDebugInfo(shouldShowAppDebugInfo); + return; + } + + // If waiting for period and any other key is pressed, reset sequence + if (isWaitingForPeriod) { + isWaitingForPeriod = false; + } + }; + + window.addEventListener("keydown", handleKeyDown); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [cometDebuggerModeEnabled, setShowAppDebugInfo, showAppDebugInfo]); return ( showAppDebugInfo && ( diff --git a/apps/opik-frontend/src/components/layout/NoUserMenu.tsx b/apps/opik-frontend/src/components/layout/NoUserMenu.tsx index dc15226ba03..3402bd7ab3e 100644 --- a/apps/opik-frontend/src/components/layout/NoUserMenu.tsx +++ b/apps/opik-frontend/src/components/layout/NoUserMenu.tsx @@ -17,14 +17,8 @@ import { import { useThemeOptions } from "@/hooks/useThemeOptions"; import { APP_VERSION } from "@/constants/app"; import { toast } from "../ui/use-toast"; -import UserMenuAppDebugInfoToggle from "@/plugins/comet/UserMenuAppDebugInfoToggle"; -import { FeatureToggleKeys } from "@/types/feature-toggles"; -import { useIsFeatureEnabled } from "../feature-toggles-provider"; const NoUserMenu = () => { - const isCometDebuggerModeEnabled = useIsFeatureEnabled( - FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, - ); const { theme, themeOptions, currentOption, CurrentIcon, handleThemeSelect } = useThemeOptions(); @@ -40,7 +34,6 @@ const NoUserMenu = () => { - {isCometDebuggerModeEnabled && } diff --git a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx index a5edcc7a587..767e28af89a 100644 --- a/apps/opik-frontend/src/plugins/comet/UserMenu.tsx +++ b/apps/opik-frontend/src/plugins/comet/UserMenu.tsx @@ -48,9 +48,6 @@ import { buildUrl, isOnPremise, isProduction } from "./utils"; import useAllWorkspaces from "@/plugins/comet/useAllWorkspaces"; import useUserInvitedWorkspaces from "@/plugins/comet/useUserInvitedWorkspaces"; import useInviteMembersURL from "@/plugins/comet/useInviteMembersURL"; -import UserMenuAppDebugInfoToggle from "./UserMenuAppDebugInfoToggle"; -import { useIsFeatureEnabled } from "@/components/feature-toggles-provider"; -import { FeatureToggleKeys } from "@/types/feature-toggles"; const UserMenu = () => { const navigate = useNavigate(); @@ -64,10 +61,6 @@ const UserMenu = () => { (match) => match.staticData?.hideUpgradeButton, ); - const isCometDebuggerModeEnabled = useIsFeatureEnabled( - FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, - ); - const { data: user } = useUser(); const { data: organizations, isLoading } = useOrganizations({ enabled: !!user?.loggedIn, @@ -383,7 +376,6 @@ const UserMenu = () => { - {isCometDebuggerModeEnabled && } From 51f169beaf2b4f9062f94c24b35fbbac8212201d Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Sun, 9 Nov 2025 15:12:17 +0200 Subject: [PATCH 12/18] Revision 2: Remove COMET_DEBUGGER_MODE from feature toggles --- .github/workflows/end2end_suites.yml | 2 +- .../workflows/end2end_suites_typescript.yml | 2 +- apps/opik-backend/config.yml | 3 -- .../infrastructure/ServiceTogglesConfig.java | 2 - .../components/feature-toggles-provider.tsx | 1 - .../layout/AppDebugInfo/AppDebugInfo.tsx | 19 ++------ .../comet/UserMenuAppDebugInfoToggle.tsx | 48 ------------------- .../src/types/feature-toggles.ts | 1 - deployment/docker-compose/docker-compose.yaml | 1 - 9 files changed, 7 insertions(+), 72 deletions(-) delete mode 100644 apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx diff --git a/.github/workflows/end2end_suites.yml b/.github/workflows/end2end_suites.yml index 9d06a308ec0..8665c89af49 100644 --- a/.github/workflows/end2end_suites.yml +++ b/.github/workflows/end2end_suites.yml @@ -66,7 +66,7 @@ jobs: OPIK_USAGE_REPORT_ENABLED: false run: | cd ${{ github.workspace }} - TOGGLE_WELCOME_WIZARD_ENABLED="false" TOGGLE_COMET_DEBUGGER_MODE_ENABLED="false" ./opik.sh --build + TOGGLE_WELCOME_WIZARD_ENABLED="false" ./opik.sh --build - name: Check Docker pods are up (Local) run: | diff --git a/.github/workflows/end2end_suites_typescript.yml b/.github/workflows/end2end_suites_typescript.yml index 42111966d82..fd54dec50d6 100644 --- a/.github/workflows/end2end_suites_typescript.yml +++ b/.github/workflows/end2end_suites_typescript.yml @@ -88,7 +88,7 @@ jobs: OPIK_USAGE_REPORT_ENABLED: false run: | cd ${{ github.workspace }} - TOGGLE_WELCOME_WIZARD_ENABLED="false" TOGGLE_COMET_DEBUGGER_MODE_ENABLED="false" ./opik.sh --build + TOGGLE_WELCOME_WIZARD_ENABLED="false" ./opik.sh --build - name: Check Docker pods are up (Local) run: | diff --git a/apps/opik-backend/config.yml b/apps/opik-backend/config.yml index c3d88306c11..8169b2d1c08 100644 --- a/apps/opik-backend/config.yml +++ b/apps/opik-backend/config.yml @@ -526,9 +526,6 @@ serviceToggles: # Default: false # Description: Whether or not Welcome Wizard is enabled welcomeWizardEnabled: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"false"} - # Default: true - # Description: Whether or not Comet Debugger Mode is enabled - cometDebuggerModeEnabled: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"true"} # Trace Thread configuration diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java index f65e92f1e13..2914bb782e0 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/ServiceTogglesConfig.java @@ -19,6 +19,4 @@ public class ServiceTogglesConfig { @NotNull boolean alertsEnabled; @JsonProperty @NotNull boolean welcomeWizardEnabled; - @JsonProperty - @NotNull boolean cometDebuggerModeEnabled; } diff --git a/apps/opik-frontend/src/components/feature-toggles-provider.tsx b/apps/opik-frontend/src/components/feature-toggles-provider.tsx index b46a026517e..e0c83a78f0a 100644 --- a/apps/opik-frontend/src/components/feature-toggles-provider.tsx +++ b/apps/opik-frontend/src/components/feature-toggles-provider.tsx @@ -20,7 +20,6 @@ const DEFAULT_STATE: FeatureToggles = { [FeatureToggleKeys.TOGGLE_OPIK_AI_ENABLED]: false, [FeatureToggleKeys.TOGGLE_ALERTS_ENABLED]: false, [FeatureToggleKeys.WELCOME_WIZARD_ENABLED]: false, - [FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED]: false, }; const initialState: FeatureTogglesState = { diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index f9ea454cb69..1b974fc720e 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -1,38 +1,29 @@ -import { useIsFeatureEnabled } from "@/components/feature-toggles-provider"; import { toast } from "@/components/ui/use-toast"; import { APP_VERSION } from "@/constants/app"; import AppNetworkStatus from "@/plugins/comet/AppNetworkStatus"; import OpikIcon from "@/icons/opik.svg?react"; -import { COMET_DEBUGGER_MODE_KEY } from "@/plugins/comet/UserMenuAppDebugInfoToggle"; import { useDebugStore } from "@/store/DebugStore"; -import { FeatureToggleKeys } from "@/types/feature-toggles"; import copy from "clipboard-copy"; import { Copy } from "lucide-react"; import { useEffect } from "react"; +const COMET_DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same in EM + const AppDebugInfo = () => { const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); - const cometDebuggerModeEnabled = useIsFeatureEnabled( - FeatureToggleKeys.COMET_DEBUGGER_MODE_ENABLED, - ); const setShowAppDebugInfo = useDebugStore( (state) => state.setShowAppDebugInfo, ); useEffect(() => { const localStorageValue = localStorage.getItem(COMET_DEBUGGER_MODE_KEY); - const shouldShowAppDebugInfo = - cometDebuggerModeEnabled && localStorageValue?.toLowerCase() === "true"; + const shouldShowAppDebugInfo = localStorageValue?.toLowerCase() === "true"; setShowAppDebugInfo(shouldShowAppDebugInfo); - }, [cometDebuggerModeEnabled, setShowAppDebugInfo]); + }, [setShowAppDebugInfo]); // Keyboard shortcut handler for debugger mode: Meta/Ctrl + c + . useEffect(() => { - if (!cometDebuggerModeEnabled) { - return; - } - let isWaitingForPeriod = false; const handleKeyDown = (event: KeyboardEvent) => { @@ -73,7 +64,7 @@ const AppDebugInfo = () => { return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [cometDebuggerModeEnabled, setShowAppDebugInfo, showAppDebugInfo]); + }, [setShowAppDebugInfo, showAppDebugInfo]); return ( showAppDebugInfo && ( diff --git a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx b/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx deleted file mode 100644 index 958bac38a66..00000000000 --- a/apps/opik-frontend/src/plugins/comet/UserMenuAppDebugInfoToggle.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useDebugStore } from "@/store/DebugStore"; -import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; -import { SquareMousePointerIcon } from "lucide-react"; -import TooltipWrapper from "@/components/shared/TooltipWrapper/TooltipWrapper"; -import { Switch } from "@/components/ui/switch"; - -export const COMET_DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same in EM - -const UserMenuAppDebugInfoToggle = () => { - const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); - const setShowAppDebugInfo = useDebugStore( - (state) => state.setShowAppDebugInfo, - ); - - const handleToggle = (event: React.MouseEvent) => { - event.preventDefault(); - const shouldShowAppDebugInfo = !showAppDebugInfo; - - localStorage.setItem( - COMET_DEBUGGER_MODE_KEY, - String(shouldShowAppDebugInfo).toLowerCase(), - ); - setShowAppDebugInfo(shouldShowAppDebugInfo); - }; - - return ( - -
- - - - Debugger - - -
- -
- ); -}; - -export default UserMenuAppDebugInfoToggle; diff --git a/apps/opik-frontend/src/types/feature-toggles.ts b/apps/opik-frontend/src/types/feature-toggles.ts index 632631a83a3..5de68ea254d 100644 --- a/apps/opik-frontend/src/types/feature-toggles.ts +++ b/apps/opik-frontend/src/types/feature-toggles.ts @@ -6,5 +6,4 @@ export enum FeatureToggleKeys { TOGGLE_OPIK_AI_ENABLED = "opik_aienabled", TOGGLE_ALERTS_ENABLED = "alerts_enabled", WELCOME_WIZARD_ENABLED = "welcome_wizard_enabled", - COMET_DEBUGGER_MODE_ENABLED = "comet_debugger_mode_enabled", } diff --git a/deployment/docker-compose/docker-compose.yaml b/deployment/docker-compose/docker-compose.yaml index fe1b93384ae..7d2ea12be29 100644 --- a/deployment/docker-compose/docker-compose.yaml +++ b/deployment/docker-compose/docker-compose.yaml @@ -163,7 +163,6 @@ services: PYTHON_EVALUATOR_URL: http://python-backend:8000 TOGGLE_GUARDRAILS_ENABLED: ${TOGGLE_GUARDRAILS_ENABLED:-"false"} TOGGLE_WELCOME_WIZARD_ENABLED: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"true"} - TOGGLE_COMET_DEBUGGER_MODE_ENABLED: ${TOGGLE_COMET_DEBUGGER_MODE_ENABLED:-"true"} CORS: ${CORS:-false} ATTACHMENTS_STRIP_MIN_SIZE: ${ATTACHMENTS_STRIP_MIN_SIZE:-256000} JACKSON_MAX_STRING_LENGTH: ${JACKSON_MAX_STRING_LENGTH:-104857600} From ba430328ae8101961173a4ce8f0fd02e1d5fda70 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Sun, 9 Nov 2025 15:53:20 +0200 Subject: [PATCH 13/18] Revision 3: Revert to ThemeToggle and remove redundant empty line --- apps/opik-backend/config.yml | 1 - .../src/components/layout/NoUserMenu.tsx | 85 ------------------- .../PartialPageLayout/PartialPageLayout.tsx | 4 +- .../layout/SMEPageLayout/SMEPageLayout.tsx | 4 +- .../src/components/layout/TopBar/TopBar.tsx | 4 +- 5 files changed, 6 insertions(+), 92 deletions(-) delete mode 100644 apps/opik-frontend/src/components/layout/NoUserMenu.tsx diff --git a/apps/opik-backend/config.yml b/apps/opik-backend/config.yml index 8169b2d1c08..fc6496fc57d 100644 --- a/apps/opik-backend/config.yml +++ b/apps/opik-backend/config.yml @@ -527,7 +527,6 @@ serviceToggles: # Description: Whether or not Welcome Wizard is enabled welcomeWizardEnabled: ${TOGGLE_WELCOME_WIZARD_ENABLED:-"false"} - # Trace Thread configuration traceThreadConfig: # Default: true diff --git a/apps/opik-frontend/src/components/layout/NoUserMenu.tsx b/apps/opik-frontend/src/components/layout/NoUserMenu.tsx deleted file mode 100644 index 3402bd7ab3e..00000000000 --- a/apps/opik-frontend/src/components/layout/NoUserMenu.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Check, Copy, Settings2 } from "lucide-react"; -import copy from "clipboard-copy"; - -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuPortal, - DropdownMenuSeparator, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { useThemeOptions } from "@/hooks/useThemeOptions"; -import { APP_VERSION } from "@/constants/app"; -import { toast } from "../ui/use-toast"; - -const NoUserMenu = () => { - const { theme, themeOptions, currentOption, CurrentIcon, handleThemeSelect } = - useThemeOptions(); - - return ( - - - - - - - - - - Theme - - - - {themeOptions.map(({ value, label, icon: Icon }) => ( - handleThemeSelect(value)} - > -
- {theme === value && ( - - )} - - {label} -
-
- ))} -
-
-
-
- {APP_VERSION && ( - <> - - { - copy(APP_VERSION); - toast({ description: "Successfully copied version" }); - }} - > - - VERSION {APP_VERSION} - - - - - )} -
-
- ); -}; - -export default NoUserMenu; diff --git a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx index 52f22ad4dfa..c7315030609 100644 --- a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx @@ -4,7 +4,7 @@ import usePluginsStore from "@/store/PluginsStore"; import { Link, Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; -import NoUserMenu from "../NoUserMenu"; +import ThemeToggle from "../ThemeToggle/ThemeToggle"; export const PartialPageLayout = ({ children = , @@ -32,7 +32,7 @@ export const PartialPageLayout = ({
- {UserMenu ? : } + {UserMenu ? : }
diff --git a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx index bbc88f92e38..209b6a06ecf 100644 --- a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx @@ -2,7 +2,7 @@ import React from "react"; import usePluginsStore from "@/store/PluginsStore"; import { Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import NoUserMenu from "../NoUserMenu"; +import ThemeToggle from "../ThemeToggle/ThemeToggle"; export const SMEPageLayout = ({ children = , @@ -22,7 +22,7 @@ export const SMEPageLayout = ({
diff --git a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx index fcae0f9d60f..2fa235333df 100644 --- a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx +++ b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx @@ -1,7 +1,7 @@ import Breadcrumbs from "@/components/layout/Breadcrumbs/Breadcrumbs"; import usePluginsStore from "@/store/PluginsStore"; import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; -import NoUserMenu from "../NoUserMenu"; +import ThemeToggle from "../ThemeToggle/ThemeToggle"; const TopBar = () => { const UserMenu = usePluginsStore((state) => state.UserMenu); @@ -13,7 +13,7 @@ const TopBar = () => { - {UserMenu ? : } + {UserMenu ? : } ); }; From d7f810e5d8952eaae52c8f302a9e3a5bc0dfb045 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Sun, 9 Nov 2025 16:08:15 +0200 Subject: [PATCH 14/18] Revision 4: Use absolute imports for ThemeToggle component --- .../components/layout/PartialPageLayout/PartialPageLayout.tsx | 2 +- .../src/components/layout/SMEPageLayout/SMEPageLayout.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx index c7315030609..57a2e298d65 100644 --- a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx @@ -4,7 +4,7 @@ import usePluginsStore from "@/store/PluginsStore"; import { Link, Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; -import ThemeToggle from "../ThemeToggle/ThemeToggle"; +import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; export const PartialPageLayout = ({ children = , diff --git a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx index 209b6a06ecf..cd4492d9793 100644 --- a/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/SMEPageLayout/SMEPageLayout.tsx @@ -2,7 +2,7 @@ import React from "react"; import usePluginsStore from "@/store/PluginsStore"; import { Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import ThemeToggle from "../ThemeToggle/ThemeToggle"; +import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; export const SMEPageLayout = ({ children = , From e2842f6d4bcedd0ae4758d2e7b6c8f63afaf35d5 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Sun, 9 Nov 2025 16:45:13 +0200 Subject: [PATCH 15/18] Revision 5: Remove redundant DebugStore and use simple localStorage state --- .../layout/AppDebugInfo/AppDebugInfo.tsx | 28 ++++++------------- apps/opik-frontend/src/store/DebugStore.ts | 14 ---------- 2 files changed, 9 insertions(+), 33 deletions(-) delete mode 100644 apps/opik-frontend/src/store/DebugStore.ts diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx index 1b974fc720e..9992dcb81bb 100644 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx @@ -1,27 +1,18 @@ +import { useEffect, useState } from "react"; import { toast } from "@/components/ui/use-toast"; import { APP_VERSION } from "@/constants/app"; import AppNetworkStatus from "@/plugins/comet/AppNetworkStatus"; import OpikIcon from "@/icons/opik.svg?react"; -import { useDebugStore } from "@/store/DebugStore"; import copy from "clipboard-copy"; import { Copy } from "lucide-react"; -import { useEffect } from "react"; const COMET_DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same in EM const AppDebugInfo = () => { - const showAppDebugInfo = useDebugStore((state) => state.showAppDebugInfo); - const setShowAppDebugInfo = useDebugStore( - (state) => state.setShowAppDebugInfo, + const [showAppDebugInfo, setShowAppDebugInfo] = useState( + () => localStorage.getItem(COMET_DEBUGGER_MODE_KEY) === "true", ); - useEffect(() => { - const localStorageValue = localStorage.getItem(COMET_DEBUGGER_MODE_KEY); - const shouldShowAppDebugInfo = localStorageValue?.toLowerCase() === "true"; - - setShowAppDebugInfo(shouldShowAppDebugInfo); - }, [setShowAppDebugInfo]); - // Keyboard shortcut handler for debugger mode: Meta/Ctrl + c + . useEffect(() => { let isWaitingForPeriod = false; @@ -44,12 +35,11 @@ const AppDebugInfo = () => { isWaitingForPeriod = false; // Toggle debugger mode - const shouldShowAppDebugInfo = !showAppDebugInfo; - localStorage.setItem( - COMET_DEBUGGER_MODE_KEY, - String(shouldShowAppDebugInfo).toLowerCase(), - ); - setShowAppDebugInfo(shouldShowAppDebugInfo); + setShowAppDebugInfo((prev) => { + const newValue = !prev; + localStorage.setItem(COMET_DEBUGGER_MODE_KEY, String(newValue)); + return newValue; + }); return; } @@ -64,7 +54,7 @@ const AppDebugInfo = () => { return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [setShowAppDebugInfo, showAppDebugInfo]); + }, []); return ( showAppDebugInfo && ( diff --git a/apps/opik-frontend/src/store/DebugStore.ts b/apps/opik-frontend/src/store/DebugStore.ts deleted file mode 100644 index 5b869244c7c..00000000000 --- a/apps/opik-frontend/src/store/DebugStore.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { create } from "zustand"; -import { devtools } from "zustand/middleware"; - -interface DebugStore { - showAppDebugInfo: boolean; - setShowAppDebugInfo: (show: boolean) => void; -} - -export const useDebugStore = create()( - devtools((set) => ({ - showAppDebugInfo: false, - setShowAppDebugInfo: (show) => set({ showAppDebugInfo: show }), - })), -); From c9ce85370672e35ef8ff1b5eca4d710f8145170b Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Mon, 10 Nov 2025 15:04:34 +0200 Subject: [PATCH 16/18] Revision 2: Refactor AppDebugInfo to use react-hotkeys-hook and make available for all versions - Replace manual keyboard event handling with useHotkeys hook - Change hotkey to Cmd/Ctrl+Shift+. to avoid conflict with system copy command - Extract platform detection (isMac, modifierKey) to shared utils - Move AppDebugInfo and AppNetworkStatus from plugins/comet to components/shared - Update AppNetworkStatus to use generic 'backend server' terminology instead of 'Comet server' - Maintain same localStorage key (comet-debugger-mode) for consistency with EM --- .../layout/AppDebugInfo/AppDebugInfo.tsx | 86 ------------------- .../PartialPageLayout/PartialPageLayout.tsx | 2 +- .../src/components/layout/TopBar/TopBar.tsx | 2 +- .../components/pages/SMEFlowPage/hotkeys.ts | 7 +- .../shared/AppDebugInfo/AppDebugInfo.tsx | 58 +++++++++++++ .../AppNetworkStatus}/AppNetworkStatus.tsx | 18 ++-- apps/opik-frontend/src/lib/utils.ts | 6 ++ 7 files changed, 77 insertions(+), 102 deletions(-) delete mode 100644 apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx create mode 100644 apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx rename apps/opik-frontend/src/{plugins/comet => components/shared/AppNetworkStatus}/AppNetworkStatus.tsx (84%) diff --git a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx deleted file mode 100644 index 9992dcb81bb..00000000000 --- a/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useEffect, useState } from "react"; -import { toast } from "@/components/ui/use-toast"; -import { APP_VERSION } from "@/constants/app"; -import AppNetworkStatus from "@/plugins/comet/AppNetworkStatus"; -import OpikIcon from "@/icons/opik.svg?react"; -import copy from "clipboard-copy"; -import { Copy } from "lucide-react"; - -const COMET_DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same in EM - -const AppDebugInfo = () => { - const [showAppDebugInfo, setShowAppDebugInfo] = useState( - () => localStorage.getItem(COMET_DEBUGGER_MODE_KEY) === "true", - ); - - // Keyboard shortcut handler for debugger mode: Meta/Ctrl + c + . - useEffect(() => { - let isWaitingForPeriod = false; - - const handleKeyDown = (event: KeyboardEvent) => { - const isMetaOrCtrl = event.metaKey || event.ctrlKey; - const isCKey = event.key === "c" || event.key === "C"; - const isPeriodKey = event.key === "." || event.key === ">"; - - // First part: Meta/Ctrl + c - start waiting for period - if (isMetaOrCtrl && isCKey && !isWaitingForPeriod) { - isWaitingForPeriod = true; - return; - } - - // Second part: Period while still holding Meta/Ctrl - complete sequence - if (isMetaOrCtrl && isPeriodKey && isWaitingForPeriod) { - event.preventDefault(); - event.stopPropagation(); - isWaitingForPeriod = false; - - // Toggle debugger mode - setShowAppDebugInfo((prev) => { - const newValue = !prev; - localStorage.setItem(COMET_DEBUGGER_MODE_KEY, String(newValue)); - return newValue; - }); - return; - } - - // If waiting for period and any other key is pressed, reset sequence - if (isWaitingForPeriod) { - isWaitingForPeriod = false; - } - }; - - window.addEventListener("keydown", handleKeyDown); - - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; - }, []); - - return ( - showAppDebugInfo && ( - <> -
- -
- - {APP_VERSION && ( -
{ - copy(APP_VERSION); - toast({ description: "Successfully copied version" }); - }} - > - - - OPIK VERSION {APP_VERSION} - - -
- )} - - ) - ); -}; - -export default AppDebugInfo; diff --git a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx index 57a2e298d65..4519ef122bc 100644 --- a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx @@ -3,7 +3,7 @@ import useAppStore from "@/store/AppStore"; import usePluginsStore from "@/store/PluginsStore"; import { Link, Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; +import AppDebugInfo from "@/components/shared/AppDebugInfo/AppDebugInfo"; import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; export const PartialPageLayout = ({ diff --git a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx index 2fa235333df..4588e7b135b 100644 --- a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx +++ b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx @@ -1,6 +1,6 @@ import Breadcrumbs from "@/components/layout/Breadcrumbs/Breadcrumbs"; import usePluginsStore from "@/store/PluginsStore"; -import AppDebugInfo from "../AppDebugInfo/AppDebugInfo"; +import AppDebugInfo from "@/components/shared/AppDebugInfo/AppDebugInfo"; import ThemeToggle from "../ThemeToggle/ThemeToggle"; const TopBar = () => { diff --git a/apps/opik-frontend/src/components/pages/SMEFlowPage/hotkeys.ts b/apps/opik-frontend/src/components/pages/SMEFlowPage/hotkeys.ts index 39f84b96006..5edf0844e7a 100644 --- a/apps/opik-frontend/src/components/pages/SMEFlowPage/hotkeys.ts +++ b/apps/opik-frontend/src/components/pages/SMEFlowPage/hotkeys.ts @@ -1,3 +1,5 @@ +import { modifierKey, isMac } from "@/lib/utils"; + export enum SME_ACTION { PREVIOUS = "previous", NEXT = "next", @@ -7,11 +9,6 @@ export enum SME_ACTION { FOCUS_FEEDBACK_SCORES = "focus_feedback_scores", } -const isMac = - typeof navigator !== "undefined" && - navigator.platform.toUpperCase().indexOf("MAC") >= 0; -const modifierKey = isMac ? "meta" : "ctrl"; - export const SME_HOTKEYS = { [SME_ACTION.PREVIOUS]: { key: "p", diff --git a/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx new file mode 100644 index 00000000000..dea2b4b3e88 --- /dev/null +++ b/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx @@ -0,0 +1,58 @@ +import { useState } from "react"; +import { useHotkeys } from "react-hotkeys-hook"; +import { toast } from "@/components/ui/use-toast"; +import { APP_VERSION } from "@/constants/app"; +import AppNetworkStatus from "@/components/shared/AppNetworkStatus/AppNetworkStatus"; +import OpikIcon from "@/icons/opik.svg?react"; +import copy from "clipboard-copy"; +import { Copy } from "lucide-react"; +import { modifierKey } from "@/lib/utils"; + +const DEBUGGER_MODE_KEY = "comet-debugger-mode"; // Same key used in EM for consistency + +const AppDebugInfo = () => { + const [showAppDebugInfo, setShowAppDebugInfo] = useState( + () => localStorage.getItem(DEBUGGER_MODE_KEY) === "true", + ); + + // Keyboard shortcut handler for debugger mode: Meta/Ctrl + Shift + . (all pressed simultaneously) + useHotkeys(`${modifierKey}+shift+period`, (keyboardEvent: KeyboardEvent) => { + keyboardEvent.preventDefault(); + keyboardEvent.stopPropagation(); + + // Toggle debugger mode + setShowAppDebugInfo((prev) => { + const newValue = !prev; + localStorage.setItem(DEBUGGER_MODE_KEY, String(newValue)); + return newValue; + }); + }); + + return ( + showAppDebugInfo && ( + <> +
+ +
+ + {APP_VERSION && ( +
{ + copy(APP_VERSION); + toast({ description: "Successfully copied version" }); + }} + > + + + OPIK VERSION {APP_VERSION} + + +
+ )} + + ) + ); +}; + +export default AppDebugInfo; diff --git a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx b/apps/opik-frontend/src/components/shared/AppNetworkStatus/AppNetworkStatus.tsx similarity index 84% rename from apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx rename to apps/opik-frontend/src/components/shared/AppNetworkStatus/AppNetworkStatus.tsx index 2873a2e693f..861a63b2273 100644 --- a/apps/opik-frontend/src/plugins/comet/AppNetworkStatus.tsx +++ b/apps/opik-frontend/src/components/shared/AppNetworkStatus/AppNetworkStatus.tsx @@ -1,6 +1,6 @@ import { cn } from "@/lib/utils"; -import CometIcon from "@/icons/comet.svg?react"; +import OpikIcon from "@/icons/opik.svg?react"; import { usePingBackend } from "@/api/debug/useIsAlive"; import useIsNetworkOnline from "@/hooks/useIsNetworkOnline"; import { WifiOffIcon, WifiIcon, SatelliteDishIcon } from "lucide-react"; @@ -11,15 +11,15 @@ const AppNetworkStatus = () => { const { data: pingResponse, isError } = usePingBackend(isNetworkOnline); const rtt = pingResponse?.rtt; const rttInSeconds = rtt ? (rtt / 1000).toFixed(2) : null; - const isConnectedToCometServer = + const isConnectedToBackend = isNetworkOnline && !isError && pingResponse?.healthy; return (
- {isConnectedToCometServer && ( + {isConnectedToBackend && (
- + RTT: {rttInSeconds}s
@@ -29,18 +29,18 @@ const AppNetworkStatus = () => {
- +
diff --git a/apps/opik-frontend/src/lib/utils.ts b/apps/opik-frontend/src/lib/utils.ts index 36babbe97cc..a997f0afd72 100644 --- a/apps/opik-frontend/src/lib/utils.ts +++ b/apps/opik-frontend/src/lib/utils.ts @@ -238,3 +238,9 @@ export const updateTextAreaHeight = ( export const capitalizeFirstLetter = (str?: string | null) => str ? str.charAt(0).toUpperCase() + str.slice(1) : ""; + +export const isMac = + typeof navigator !== "undefined" && + navigator.platform.toUpperCase().includes("MAC"); + +export const modifierKey = isMac ? "meta" : "ctrl"; From 2bb63cba87ed1083947395a926db75ce943ab612 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Mon, 10 Nov 2025 16:34:05 +0200 Subject: [PATCH 17/18] Revision 3: Move AppNetworkStatus to layout components --- .../{shared => layout}/AppNetworkStatus/AppNetworkStatus.tsx | 0 .../src/components/shared/AppDebugInfo/AppDebugInfo.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename apps/opik-frontend/src/components/{shared => layout}/AppNetworkStatus/AppNetworkStatus.tsx (100%) diff --git a/apps/opik-frontend/src/components/shared/AppNetworkStatus/AppNetworkStatus.tsx b/apps/opik-frontend/src/components/layout/AppNetworkStatus/AppNetworkStatus.tsx similarity index 100% rename from apps/opik-frontend/src/components/shared/AppNetworkStatus/AppNetworkStatus.tsx rename to apps/opik-frontend/src/components/layout/AppNetworkStatus/AppNetworkStatus.tsx diff --git a/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx index dea2b4b3e88..4e704cce742 100644 --- a/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx +++ b/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { toast } from "@/components/ui/use-toast"; import { APP_VERSION } from "@/constants/app"; -import AppNetworkStatus from "@/components/shared/AppNetworkStatus/AppNetworkStatus"; +import AppNetworkStatus from "@/components/layout/AppNetworkStatus/AppNetworkStatus"; import OpikIcon from "@/icons/opik.svg?react"; import copy from "clipboard-copy"; import { Copy } from "lucide-react"; From 8c1312ebfb44773af939891e4120da24dbd67478 Mon Sep 17 00:00:00 2001 From: Daniel Dimenshtein Date: Mon, 10 Nov 2025 16:36:08 +0200 Subject: [PATCH 18/18] Revision 4: Move AppDebugInfo to layout components --- .../components/{shared => layout}/AppDebugInfo/AppDebugInfo.tsx | 0 .../components/layout/PartialPageLayout/PartialPageLayout.tsx | 2 +- apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename apps/opik-frontend/src/components/{shared => layout}/AppDebugInfo/AppDebugInfo.tsx (100%) diff --git a/apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx b/apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx similarity index 100% rename from apps/opik-frontend/src/components/shared/AppDebugInfo/AppDebugInfo.tsx rename to apps/opik-frontend/src/components/layout/AppDebugInfo/AppDebugInfo.tsx diff --git a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx index 4519ef122bc..37f0757da20 100644 --- a/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx +++ b/apps/opik-frontend/src/components/layout/PartialPageLayout/PartialPageLayout.tsx @@ -3,7 +3,7 @@ import useAppStore from "@/store/AppStore"; import usePluginsStore from "@/store/PluginsStore"; import { Link, Outlet } from "@tanstack/react-router"; import Logo from "@/components/layout/Logo/Logo"; -import AppDebugInfo from "@/components/shared/AppDebugInfo/AppDebugInfo"; +import AppDebugInfo from "@/components/layout/AppDebugInfo/AppDebugInfo"; import ThemeToggle from "@/components/layout/ThemeToggle/ThemeToggle"; export const PartialPageLayout = ({ diff --git a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx index 4588e7b135b..5451dd12bc5 100644 --- a/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx +++ b/apps/opik-frontend/src/components/layout/TopBar/TopBar.tsx @@ -1,6 +1,6 @@ import Breadcrumbs from "@/components/layout/Breadcrumbs/Breadcrumbs"; import usePluginsStore from "@/store/PluginsStore"; -import AppDebugInfo from "@/components/shared/AppDebugInfo/AppDebugInfo"; +import AppDebugInfo from "@/components/layout/AppDebugInfo/AppDebugInfo"; import ThemeToggle from "../ThemeToggle/ThemeToggle"; const TopBar = () => {