@@ -7,10 +7,11 @@ import { Separator } from "@/components/ui/separator";
77import { Tooltip , TooltipContent , TooltipTrigger } from "@/components/ui/tooltip" ;
88import { createAuditAction } from "@/ee/features/audit/actions" ;
99import useCaptureEvent from "@/hooks/useCaptureEvent" ;
10+ import { cn } from "@/lib/utils" ;
1011import { computePosition , flip , offset , shift , VirtualElement } from "@floating-ui/react" ;
1112import { ReactCodeMirrorRef } from "@uiw/react-codemirror" ;
1213import { Loader2 } from "lucide-react" ;
13- import { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
14+ import { useCallback , useEffect , useMemo , useRef , useState , MouseEvent } from "react" ;
1415import { createPortal } from "react-dom" ;
1516import { useHotkeys } from "react-hotkeys-hook" ;
1617import { SymbolDefinitionPreview } from "./symbolDefinitionPreview" ;
@@ -36,7 +37,7 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
3637 const ref = useRef < HTMLDivElement > ( null ) ;
3738 const [ isSticky , setIsSticky ] = useState ( false ) ;
3839 const { toast } = useToast ( ) ;
39- const { navigateToPath } = useBrowseNavigation ( ) ;
40+ const { navigateToPath, createBrowsePath } = useBrowseNavigation ( ) ;
4041 const captureEvent = useCaptureEvent ( ) ;
4142
4243 const symbolInfo = useHoveredOverSymbolInfo ( {
@@ -106,6 +107,72 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
106107 return symbolInfo . symbolDefinitions [ 0 ] ;
107108 } , [ fileName , repoName , symbolInfo ?. symbolDefinitions ] ) ;
108109
110+ const gotoDefinitionHref = useMemo ( ( ) => {
111+ if (
112+ ! symbolInfo ||
113+ ! symbolInfo . symbolDefinitions ||
114+ ! previewedSymbolDefinition
115+ ) {
116+ return undefined ;
117+ }
118+
119+ const {
120+ fileName,
121+ repoName,
122+ revisionName,
123+ language,
124+ range : highlightRange ,
125+ } = previewedSymbolDefinition ;
126+
127+ return createBrowsePath ( {
128+ repoName,
129+ revisionName,
130+ path : fileName ,
131+ pathType : 'blob' ,
132+ highlightRange,
133+ ...( symbolInfo . symbolDefinitions . length > 1 ? {
134+ setBrowseState : {
135+ selectedSymbolInfo : {
136+ symbolName : symbolInfo . symbolName ,
137+ repoName,
138+ revisionName,
139+ language,
140+ } ,
141+ activeExploreMenuTab : "definitions" ,
142+ isBottomPanelCollapsed : false ,
143+ }
144+ } : { } ) ,
145+ } ) ;
146+ } , [ createBrowsePath , previewedSymbolDefinition , symbolInfo ] ) ;
147+
148+ const onGotoDefinitionClick = useCallback ( ( e : MouseEvent < HTMLAnchorElement > ) => {
149+ if (
150+ ! symbolInfo ||
151+ ! symbolInfo . symbolDefinitions ||
152+ ! previewedSymbolDefinition
153+ ) {
154+ e . preventDefault ( ) ;
155+ return ;
156+ }
157+
158+ captureEvent ( 'wa_goto_definition_pressed' , {
159+ source,
160+ } ) ;
161+
162+ createAuditAction ( {
163+ action : "user.performed_goto_definition" ,
164+ metadata : {
165+ message : symbolInfo . symbolName ,
166+ source : 'sourcebot-web-client' ,
167+ } ,
168+ } ) ;
169+ } , [
170+ captureEvent ,
171+ previewedSymbolDefinition ,
172+ source ,
173+ symbolInfo
174+ ] ) ;
175+
109176 const onGotoDefinition = useCallback ( ( ) => {
110177 if (
111178 ! symbolInfo ||
@@ -136,13 +203,11 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
136203 } = previewedSymbolDefinition ;
137204
138205 navigateToPath ( {
139- // Always navigate to the preview symbol definition.
140206 repoName,
141207 revisionName,
142208 path : fileName ,
143209 pathType : 'blob' ,
144210 highlightRange,
145- // If there are multiple definitions, we should open the Explore panel with the definitions.
146211 ...( symbolInfo . symbolDefinitions . length > 1 ? {
147212 setBrowseState : {
148213 selectedSymbolInfo : {
@@ -164,6 +229,49 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
164229 symbolInfo
165230 ] ) ;
166231
232+ const findReferencesHref = useMemo ( ( ) => {
233+ if ( ! symbolInfo ) {
234+ return undefined ;
235+ }
236+
237+ return createBrowsePath ( {
238+ repoName,
239+ revisionName,
240+ path : fileName ,
241+ pathType : 'blob' ,
242+ highlightRange : symbolInfo . range ,
243+ setBrowseState : {
244+ selectedSymbolInfo : {
245+ symbolName : symbolInfo . symbolName ,
246+ repoName,
247+ revisionName,
248+ language,
249+ } ,
250+ activeExploreMenuTab : "references" ,
251+ isBottomPanelCollapsed : false ,
252+ }
253+ } ) ;
254+ } , [ createBrowsePath , fileName , language , repoName , revisionName , symbolInfo ] ) ;
255+
256+ const onFindReferencesClick = useCallback ( ( e : MouseEvent < HTMLAnchorElement > ) => {
257+ if ( ! symbolInfo ) {
258+ e . preventDefault ( ) ;
259+ return ;
260+ }
261+
262+ captureEvent ( 'wa_find_references_pressed' , {
263+ source,
264+ } ) ;
265+
266+ createAuditAction ( {
267+ action : "user.performed_find_references" ,
268+ metadata : {
269+ message : symbolInfo . symbolName ,
270+ source : 'sourcebot-web-client' ,
271+ } ,
272+ } ) ;
273+ } , [ captureEvent , source , symbolInfo ] ) ;
274+
167275 const onFindReferences = useCallback ( ( ) => {
168276 if ( ! symbolInfo ) {
169277 return ;
@@ -276,13 +384,20 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
276384 disabled = { ! previewedSymbolDefinition }
277385 variant = "outline"
278386 size = "sm"
279- onClick = { onGotoDefinition }
387+ asChild = { ! symbolInfo . isSymbolDefinitionsLoading && ! ! previewedSymbolDefinition }
280388 >
281- {
282- ! symbolInfo . isSymbolDefinitionsLoading && ! previewedSymbolDefinition ?
283- "No definition found" :
284- `Go to ${ symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 1 ? "definitions" : "definition" } `
285- }
389+ { ! symbolInfo . isSymbolDefinitionsLoading && previewedSymbolDefinition ? (
390+ < a
391+ href = { gotoDefinitionHref }
392+ onClick = { onGotoDefinitionClick }
393+ >
394+ { `Go to ${ symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 1 ? "definitions" : "definition" } ` }
395+ </ a >
396+ ) : (
397+ < span >
398+ { symbolInfo . isSymbolDefinitionsLoading ? "Loading..." : "No definition found" }
399+ </ span >
400+ ) }
286401 </ LoadingButton >
287402 </ TooltipTrigger >
288403 < TooltipContent
@@ -299,9 +414,15 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
299414 < Button
300415 variant = "outline"
301416 size = "sm"
302- onClick = { onFindReferences }
417+ asChild
303418 >
304- Find references
419+ < a
420+ href = { findReferencesHref }
421+ onClick = { onFindReferencesClick }
422+ className = { cn ( ! symbolInfo && "pointer-events-none opacity-50" ) }
423+ >
424+ Find references
425+ </ a >
305426 </ Button >
306427 </ TooltipTrigger >
307428 < TooltipContent
0 commit comments