From e82fcd40ec38d99f23294da4294ddb425521b181 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Wed, 22 Oct 2025 12:22:13 +0200 Subject: [PATCH] add event on commandMenu command selection --- packages/common/telemetry-constants.ts | 28 ++++++++++- .../src/CommandMenu/internal/Command.tsx | 48 ++++++++++++++----- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/packages/common/telemetry-constants.ts b/packages/common/telemetry-constants.ts index 209793bcdf0..ac40f48c409 100644 --- a/packages/common/telemetry-constants.ts +++ b/packages/common/telemetry-constants.ts @@ -1978,7 +1978,7 @@ export interface CommandMenuOpenedEvent { * @source ui-patterns * @page any */ -export interface CommandInputTypedEvent { +export interface CommandMenuInputTypedEvent { action: 'command_input_typed' properties: { /** @@ -1992,6 +1992,29 @@ export interface CommandInputTypedEvent { } groups: TelemetryGroups } +/** + * User selected a command from the command menu. + * + * @group Events + * @source ui-patterns + * @page any + */ +export interface CommandMenuCommandSelectedEvent { + action: 'command_menu_command_selected' + properties: { + /** + * The selected command + */ + command_name: string + command_value?: string + command_type: 'action' | 'route' + /** + * In which app the command input was typed + */ + app: 'studio' | 'docs' | 'www' + } + groups: TelemetryGroups +} /** * @hidden @@ -2108,4 +2131,5 @@ export type TelemetryEvent = | TableRLSEnabledEvent | AuthUsersSearchSubmittedEvent | CommandMenuOpenedEvent - | CommandInputTypedEvent + | CommandMenuInputTypedEvent + | CommandMenuCommandSelectedEvent diff --git a/packages/ui-patterns/src/CommandMenu/internal/Command.tsx b/packages/ui-patterns/src/CommandMenu/internal/Command.tsx index e07c1a287ca..a2f4b9acc8c 100644 --- a/packages/ui-patterns/src/CommandMenu/internal/Command.tsx +++ b/packages/ui-patterns/src/CommandMenu/internal/Command.tsx @@ -3,8 +3,9 @@ import { type PropsWithChildren, forwardRef } from 'react' import { CommandItem_Shadcn_, cn } from 'ui' import { useCrossCompatRouter } from '../api/hooks/useCrossCompatRouter' +import { useCommandMenuTelemetryContext } from '../api/hooks/useCommandMenuTelemetryContext' import { useSetCommandMenuOpen } from '../api/hooks/viewHooks' -import { type ICommand, type IActionCommand, type IRouteCommand } from './types' +import type { ICommand, IActionCommand, IRouteCommand } from './types' const isActionCommand = (command: ICommand): command is IActionCommand => 'action' in command const isRouteCommand = (command: ICommand): command is IRouteCommand => 'route' in command @@ -52,23 +53,46 @@ const CommandItem = forwardRef< >(({ children, className, command: _command, ...props }, ref) => { const router = useCrossCompatRouter() const setIsOpen = useSetCommandMenuOpen() + const telemetryContext = useCommandMenuTelemetryContext() const command = _command as ICommand // strip the readonly applied from the proxy + const handleCommandSelect = () => { + // Send telemetry event + if (telemetryContext?.onTelemetry) { + const event = { + action: 'command_menu_command_selected' as const, + properties: { + command_name: command.name, + command_value: command.value, + command_type: isActionCommand(command) ? ('action' as const) : ('route' as const), + app: telemetryContext.app, + }, + groups: {} as Record, + } + + telemetryContext.onTelemetry( + event as unknown as Parameters[0] + ) + } + + // Execute the original command logic + if (isActionCommand(command)) { + command.action() + } else if (isRouteCommand(command)) { + if (command.route.startsWith('http')) { + setIsOpen(false) + window.open(command.route, '_blank', 'noreferrer,noopener') + } else { + router.push(command.route) + } + } + } + return ( { - command.route.startsWith('http') - ? (setIsOpen(false), window.open(command.route, '_blank', 'noreferrer,noopener')) - : router.push(command.route) - } - : () => {} - } + onSelect={handleCommandSelect} value={command.value ?? command.name} forceMount={command.forceMount} className={cn(