From 4611de3f3d36f02bf177ec4aba7d2e9b74b69e79 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Fri, 14 Feb 2025 09:44:07 +0000 Subject: [PATCH] Update tooltip text for search buttons (#23448) GitOrigin-RevId: d189aac06c5f68e009eeb125d7cc225b41e8cc0c --- .../web/frontend/extracted-translations.json | 2 ++ .../features/event-tracking/search-events.ts | 33 +++++++++++++++++++ .../components/codemirror-search-form.tsx | 24 ++++++++++++-- .../components/codemirror-toolbar.tsx | 14 ++------ .../toolbar/toggle-search-button.tsx | 22 +++++++++++++ .../source-editor/extensions/search.ts | 33 ++++++++++++++++++- .../extensions/toolbar/commands.ts | 7 ++++ .../js/shared/context/layout-context.tsx | 5 +++ services/web/locales/en.json | 2 ++ 9 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 services/web/frontend/js/features/event-tracking/search-events.ts create mode 100644 services/web/frontend/js/features/source-editor/components/toolbar/toggle-search-button.tsx diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 62156517a1..fa3e53a789 100644 --- a/services/web/frontend/extracted-translations.json +++ b/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": "", diff --git a/services/web/frontend/js/features/event-tracking/search-events.ts b/services/web/frontend/js/features/event-tracking/search-events.ts new file mode 100644 index 0000000000..9829a2024e --- /dev/null +++ b/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 = ( + eventName: T, + segmentation: SearchEventSegmentation[T] +) => { + sendMB(eventName, segmentation) +} diff --git a/services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx b/services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx index 570f9cd58e..79a642c325 100644 --- a/services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx +++ b/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 = () => { replaceNext(view)} + onClick={() => { + sendSearchEvent('search-replace-click', { + searchType: 'document', + action: 'replace', + method: 'button', + }) + replaceNext(view) + }} > {t('search_replace')} @@ -467,7 +480,14 @@ const CodeMirrorSearchForm: FC = () => { replaceAll(view)} + onClick={() => { + sendSearchEvent('search-replace-click', { + searchType: 'document', + action: 'replace-all', + method: 'button', + }) + replaceAll(view) + }} > {t('search_replace_all')} diff --git a/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx b/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx index 07f0a76993..4eb9ed2842 100644 --- a/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx +++ b/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} > - - + diff --git a/services/web/frontend/js/features/source-editor/components/toolbar/toggle-search-button.tsx b/services/web/frontend/js/features/source-editor/components/toolbar/toggle-search-button.tsx new file mode 100644 index 0000000000..9b8874c2ec --- /dev/null +++ b/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 ( + + ) +} diff --git a/services/web/frontend/js/features/source-editor/extensions/search.ts b/services/web/frontend/js/features/source-editor/extensions/search.ts index 75bdae4c10..1e531b8a8f 100644 --- a/services/web/frontend/js/features/source-editor/extensions/search.ts +++ b/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() @@ -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), diff --git a/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts b/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts index 677dd71cce..7b1b05369c 100644 --- a/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts +++ b/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 diff --git a/services/web/frontend/js/shared/context/layout-context.tsx b/services/web/frontend/js/shared/context/layout-context.tsx index 153f81a695..1c2ad44002 100644 --- a/services/web/frontend/js/shared/context/layout-context.tsx +++ b/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) } } diff --git a/services/web/locales/en.json b/services/web/locales/en.json index e6889cd69a..2bde88bc24 100644 --- a/services/web/locales/en.json +++ b/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__\"",