Просмотр исходного кода

Update tooltip text for search buttons (#23448)

GitOrigin-RevId: d189aac06c5f68e009eeb125d7cc225b41e8cc0c
Alf Eaton 1 год назад
Родитель
Сommit
4611de3f3d

+ 2 - 0
services/web/frontend/extracted-translations.json

@@ -1413,6 +1413,7 @@
   "search_next": "",
   "search_only_the_bib_files_in_your_project_only_by_citekeys": "",
   "search_previous": "",
+  "search_project": "",
   "search_projects": "",
   "search_references": "",
   "search_regexp": "",
@@ -1421,6 +1422,7 @@
   "search_replace_with": "",
   "search_search_for": "",
   "search_terms": "",
+  "search_this_file": "",
   "search_whole_word": "",
   "search_within_selection": "",
   "searched_path_for_lines_containing": "",

+ 33 - 0
services/web/frontend/js/features/event-tracking/search-events.ts

@@ -0,0 +1,33 @@
+import { sendMB } from '@/infrastructure/event-tracking'
+
+type SearchEventSegmentation = {
+  'search-open':
+    | ({
+        searchType: 'full-project'
+      } & ({ method: 'keyboard' } | { method: 'button'; location: 'toolbar' }))
+    | ({
+        searchType: 'document'
+        mode: 'visual' | 'source'
+      } & ({ method: 'keyboard' } | { method: 'button'; location: 'toolbar' }))
+
+  'search-execute': {
+    searchType: 'full-project'
+    totalDocs: number
+    totalResults: number
+  }
+  'search-result-click': {
+    searchType: 'full-project'
+  }
+  'search-replace-click': {
+    searchType: 'document'
+    method: 'keyboard' | 'button'
+    action: 'replace' | 'replace-all'
+  }
+}
+
+export const sendSearchEvent = <T extends keyof SearchEventSegmentation>(
+  eventName: T,
+  segmentation: SearchEventSegmentation[T]
+) => {
+  sendMB(eventName, segmentation)
+}

+ 22 - 2
services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx

@@ -29,6 +29,7 @@ import { useUserSettingsContext } from '@/shared/context/user-settings-context'
 import { getStoredSelection, setStoredSelection } from '../extensions/search'
 import { debounce } from 'lodash'
 import { EditorSelection, EditorState } from '@codemirror/state'
+import { sendSearchEvent } from '@/features/event-tracking/search-events'
 
 const MATCH_COUNT_DEBOUNCE_WAIT = 100 // the amount of ms to wait before counting matches
 const MAX_MATCH_COUNT = 999 // the maximum number of matches to count
@@ -197,6 +198,11 @@ const CodeMirrorSearchForm: FC = () => {
         case 'Enter':
           event.preventDefault()
           replaceNext(view)
+          sendSearchEvent('search-replace-click', {
+            searchType: 'document',
+            action: 'replace',
+            method: 'keyboard',
+          })
           break
 
         case 'Tab': {
@@ -459,7 +465,14 @@ const CodeMirrorSearchForm: FC = () => {
             <OLButton
               variant="secondary"
               size="sm"
-              onClick={() => replaceNext(view)}
+              onClick={() => {
+                sendSearchEvent('search-replace-click', {
+                  searchType: 'document',
+                  action: 'replace',
+                  method: 'button',
+                })
+                replaceNext(view)
+              }}
             >
               {t('search_replace')}
             </OLButton>
@@ -467,7 +480,14 @@ const CodeMirrorSearchForm: FC = () => {
             <OLButton
               variant="secondary"
               size="sm"
-              onClick={() => replaceAll(view)}
+              onClick={() => {
+                sendSearchEvent('search-replace-click', {
+                  searchType: 'document',
+                  action: 'replace-all',
+                  method: 'button',
+                })
+                replaceAll(view)
+              }}
             >
               {t('search_replace_all')}
             </OLButton>

+ 2 - 12
services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx

@@ -4,11 +4,8 @@ import {
   useCodeMirrorStateContext,
   useCodeMirrorViewContext,
 } from './codemirror-context'
-import { searchPanelOpen } from '@codemirror/search'
 import { useResizeObserver } from '@/shared/hooks/use-resize-observer'
-import { ToolbarButton } from './toolbar/toolbar-button'
 import { ToolbarItems } from './toolbar/toolbar-items'
-import * as commands from '../extensions/toolbar/commands'
 import { ToolbarOverflow } from './toolbar/overflow'
 import useDropdown from '../../../shared/hooks/use-dropdown'
 import { getPanel } from '@codemirror/view'
@@ -21,8 +18,8 @@ import { isVisual } from '../extensions/visual/visual'
 import { language } from '@codemirror/language'
 import { minimumListDepthForSelection } from '../utils/tree-operations/ancestors'
 import { debugConsole } from '@/utils/debugging'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { useTranslation } from 'react-i18next'
+import { ToggleSearchButton } from '@/features/source-editor/components/toolbar/toggle-search-button'
 
 export const CodeMirrorToolbar = () => {
   const view = useCodeMirrorViewContext()
@@ -173,14 +170,7 @@ const Toolbar = memo(function Toolbar() {
         className="ol-cm-toolbar-button-group ol-cm-toolbar-end"
         ref={handleButtons}
       >
-        <ToolbarButton
-          id="toolbar-toggle-search"
-          label="Toggle Search"
-          command={commands.toggleSearch}
-          active={searchPanelOpen(state)}
-          icon={bsVersion({ bs5: 'search', bs3: 'search' })}
-        />
-
+        <ToggleSearchButton state={state} />
         <SwitchToPDFButton />
         <DetacherSynctexControl />
         <DetachCompileButtonWrapper />

+ 22 - 0
services/web/frontend/js/features/source-editor/components/toolbar/toggle-search-button.tsx

@@ -0,0 +1,22 @@
+import { FC } from 'react'
+import * as commands from '@/features/source-editor/extensions/toolbar/commands'
+import { searchPanelOpen } from '@codemirror/search'
+import { ToolbarButton } from '@/features/source-editor/components/toolbar/toolbar-button'
+import { EditorState } from '@codemirror/state'
+import { useTranslation } from 'react-i18next'
+import { isMac } from '@/shared/utils/os'
+
+export const ToggleSearchButton: FC<{ state: EditorState }> = ({ state }) => {
+  const { t } = useTranslation()
+
+  return (
+    <ToolbarButton
+      id="toolbar-toggle-search"
+      label={t('search_this_file')}
+      command={commands.toggleSearch}
+      active={searchPanelOpen(state)}
+      icon="search"
+      shortcut={isMac ? '⌘F' : 'Ctrl+F'}
+    />
+  )
+}

+ 32 - 1
services/web/frontend/js/features/source-editor/extensions/search.ts

@@ -9,17 +9,26 @@ import {
   highlightSelectionMatches,
   togglePanel,
 } from '@codemirror/search'
-import { Decoration, EditorView, keymap, ViewPlugin } from '@codemirror/view'
+import {
+  Decoration,
+  EditorView,
+  KeyBinding,
+  keymap,
+  ViewPlugin,
+} from '@codemirror/view'
 import {
   Annotation,
   Compartment,
   EditorSelection,
   EditorState,
+  Prec,
   SelectionRange,
   StateEffect,
   StateField,
   TransactionSpec,
 } from '@codemirror/state'
+import { sendSearchEvent } from '@/features/event-tracking/search-events'
+import { isVisual } from '@/features/source-editor/extensions/visual/visual'
 
 const restoreSearchQueryAnnotation = Annotation.define<boolean>()
 
@@ -122,6 +131,25 @@ const scrollToMatch = (range: SelectionRange, view: EditorView) => {
   })
 }
 
+const searchEventKeymap: KeyBinding[] = [
+  // record an event when the search panel is opened using the keyboard shortcut
+  {
+    key: 'Mod-f',
+    preventDefault: true,
+    scope: 'editor search-panel',
+    run(view) {
+      if (!searchPanelOpen(view.state)) {
+        sendSearchEvent('search-open', {
+          searchType: 'document',
+          method: 'keyboard',
+          mode: isVisual(view) ? 'visual' : 'source',
+        })
+      }
+      return false // continue with the regular search shortcut
+    },
+  },
+]
+
 /**
  * A collection of extensions related to the search feature.
  */
@@ -129,6 +157,9 @@ export const search = () => {
   let open = false
 
   return [
+    // keymap for search events
+    Prec.high(keymap.of(searchEventKeymap)),
+
     // keymap for search
     keymap.of(searchKeymap),
 

+ 7 - 0
services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts

@@ -20,6 +20,7 @@ import { snippet } from '@codemirror/autocomplete'
 import { snippets } from './snippets'
 import { minimumListDepthForSelection } from '../../utils/tree-operations/ancestors'
 import { isVisual } from '../visual/visual'
+import { sendSearchEvent } from '@/features/event-tracking/search-events'
 
 export const toggleBold = toggleRanges('\\textbf')
 export const toggleItalic = toggleRanges('\\textit')
@@ -151,6 +152,12 @@ export const toggleSearch: Command = view => {
   if (searchPanelOpen(view.state)) {
     closeSearchPanel(view)
   } else {
+    sendSearchEvent('search-open', {
+      searchType: 'document',
+      method: 'button',
+      location: 'toolbar',
+      mode: isVisual(view) ? 'visual' : 'source',
+    })
     openSearchPanel(view)
   }
   return true

+ 5 - 0
services/web/frontend/js/shared/context/layout-context.tsx

@@ -20,6 +20,7 @@ import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
 import useEventListener from '@/shared/hooks/use-event-listener'
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
 import { isMac } from '@/shared/utils/os'
+import { sendSearchEvent } from '@/features/event-tracking/search-events'
 
 export type IdeLayout = 'sideBySide' | 'flat'
 export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
@@ -142,6 +143,10 @@ export const LayoutProvider: FC = ({ children }) => {
       ) {
         if (isSplitTestEnabled('full-project-search')) {
           event.preventDefault()
+          sendSearchEvent('search-open', {
+            searchType: 'full-project',
+            method: 'keyboard',
+          })
           setProjectSearchIsOpen(true)
         }
       }

+ 2 - 0
services/web/locales/en.json

@@ -1870,6 +1870,7 @@
   "search_next": "next",
   "search_only_the_bib_files_in_your_project_only_by_citekeys": "Search only the .bib files in your project, only by citekeys.",
   "search_previous": "previous",
+  "search_project": "Search project",
   "search_projects": "Search projects",
   "search_references": "Search the .bib files in this project",
   "search_regexp": "Regular expression",
@@ -1878,6 +1879,7 @@
   "search_replace_with": "Replace with",
   "search_search_for": "Search for",
   "search_terms": "Search terms",
+  "search_this_file": "Search this file",
   "search_whole_word": "Whole word",
   "search_within_selection": "Within selection",
   "searched_path_for_lines_containing": "Searched __path__ for lines containing \"__query__\"",