diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js index 4ffda193278ff9de1a9854191d0bdd754715fed0..3527af83e1b56bfbc228087f31112950c4db71e8 100644 --- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js +++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js @@ -49,13 +49,44 @@ export const GLOBAL_COMMANDS_GROUP_TITLE = s__('CommandPalette|Global Commands') export const USERS_GROUP_TITLE = s__('GlobalSearch|Users'); export const PAGES_GROUP_TITLE = s__('CommandPalette|Pages'); export const PROJECTS_GROUP_TITLE = s__('GlobalSearch|Projects'); -export const ISSUE_GROUP_TITLE = s__('GlobalSearch|Recent issues'); +export const ISSUES_GROUP_TITLE = s__('GlobalSearch|Issues'); export const PATH_GROUP_TITLE = s__('CommandPalette|Project files'); +export const GROUPS_GROUP_TITLE = s__('GlobalSearch|Groups'); +export const MERGE_REQUESTS_GROUP_TITLE = s__('GlobalSearch|Merge Requests'); +export const RECENT_ISSUES_GROUP_TITLE = s__('GlobalSearch|Recent issues'); +export const RECENT_EPICS_GROUP_TITLE = s__('GlobalSearch|Recent epics'); +export const RECENT_MERGE_REQUESTS_GROUP_TITLE = s__('GlobalSearch|Recent merge requests'); + +export const FREQUENTLY_VISITED_PROJECTS_HANDLE = 'FREQUENTLY_VISITED_PROJECTS_HANDLE'; +export const FREQUENTLY_VISITED_GROUPS_HANDLE = 'FREQUENTLY_VISITED_GROUPS_HANDLE'; + +export const ISSUES_ASSIGNED_TO_ME_TITLE = s__('GlobalSearch|Issues assigned to me'); +export const ISSUES_I_HAVE_CREATED_TITLE = s__("GlobalSearch|Issues I've created"); +export const MERGE_REQUESTS_ASSIGNED_TO_ME_TITLE = s__( + 'GlobalSearch|Merge requests assigned to me', +); +export const MERGE_REQUESTS_THAT_I_AM_A_REVIEWER = s__( + "GlobalSearch|Merge requests that I'm a reviewer", +); +export const MERGE_REQUESTS_I_HAVE_CREATED_TITLE = s__("GlobalSearch|Merge requests I've created"); + +export const SCOPE_SEARCH_ALL = 'scoped-in-all'; +export const SCOPE_SEARCH_GROUP = 'scoped-in-group'; +export const SCOPE_SEARCH_PROJECT = 'scoped-in-project'; + +export const MODAL_CLOSE_ESC = 'esc'; +export const MODAL_CLOSE_BACKGROUND = 'backdrop'; +export const MODAL_CLOSE_HEADERCLOSE = 'headerclose'; + +export const YOUR_WORK_TITLE = s__('GlobalSearch|Your work'); +export const EXPLORE_TITLE = s__('GlobalSearch|Explore'); +export const PROFILE_TITLE = s__('GlobalSearch|Profile'); +export const PREFERENCES_TITLE = s__('GlobalSearch|Preferences'); export const GROUP_TITLES = { [USER_HANDLE]: USERS_GROUP_TITLE, [PROJECT_HANDLE]: PROJECTS_GROUP_TITLE, - [ISSUE_HANDLE]: ISSUE_GROUP_TITLE, + [ISSUE_HANDLE]: ISSUES_GROUP_TITLE, [PATH_HANDLE]: PATH_GROUP_TITLE, }; diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue index 3c700c32568068887f2bf0218a413fa34c3213fb..a1078f0b32aa2e1bcb71748b77eed8bd6b7635b5 100644 --- a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue +++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue @@ -2,6 +2,7 @@ import { GlAvatar, GlAlert, GlLoadingIcon, GlDisclosureDropdownGroup } from '@gitlab/ui'; // eslint-disable-next-line no-restricted-imports import { mapState, mapGetters } from 'vuex'; +import { InternalEvents } from '~/tracking'; import SafeHtml from '~/vue_shared/directives/safe_html'; import highlight from '~/lib/utils/highlight'; import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants'; @@ -16,12 +17,14 @@ import { OVERLAY_FILE, USERS_GROUP_TITLE, PROJECTS_GROUP_TITLE, - ISSUE_GROUP_TITLE, PAGES_GROUP_TITLE, + ISSUES_GROUP_TITLE, } from '../command_palette/constants'; import SearchResultHoverLayover from './global_search_hover_overlay.vue'; import GlobalSearchNoResults from './global_search_no_results.vue'; +const trackingMixin = InternalEvents.mixin(); + export default { name: 'GlobalSearchAutocompleteItems', i18n: { @@ -33,8 +36,8 @@ export default { OVERLAY_FILE, USERS_GROUP_TITLE, PROJECTS_GROUP_TITLE, - ISSUE_GROUP_TITLE, PAGES_GROUP_TITLE, + ISSUES_GROUP_TITLE, }, components: { GlAvatar, @@ -47,6 +50,7 @@ export default { directives: { SafeHtml, }, + mixins: [trackingMixin], computed: { ...mapState(['search', 'loading', 'autocompleteError']), ...mapGetters(['autocompleteGroupedSearchOptions', 'scopedSearchOptions']), @@ -87,7 +91,7 @@ export default { case this.$options.i18n.PROJECTS_GROUP_TITLE: text = this.$options.i18n.OVERLAY_PROJECT; break; - case this.$options.i18n.ISSUE_GROUP_TITLE: + case this.$options.i18n.ISSUES_GROUP_TITLE: text = this.$options.i18n.OVERLAY_GOTO; break; case this.$options.i18n.PAGES_GROUP_TITLE: @@ -97,6 +101,18 @@ export default { } return text; }, + trackingTypes({ category }) { + switch (category) { + case this.$options.i18n.PROJECTS_GROUP_TITLE: { + this.trackEvent('click_project_result_in_command_palette'); + break; + } + + default: { + this.trackEvent('click_user_result_in_command_palette'); + } + } + }, }, AVATAR_SHAPE_OPTION_RECT, }; @@ -120,6 +136,7 @@ export default { :class="{ 'gl-mt-0!': index === 0 }" :group="group" bordered + @action="trackingTypes" > <template #list-item="{ item }"> <search-result-hover-layover :text-message="overlayText(group.name)"> diff --git a/config/events/click_project_result_in_command_palette.yml b/config/events/click_project_result_in_command_palette.yml new file mode 100644 index 0000000000000000000000000000000000000000..8413fdd0cdc17b21ce0d87861d368a4dd9ed7032 --- /dev/null +++ b/config/events/click_project_result_in_command_palette.yml @@ -0,0 +1,19 @@ +--- +description: User clicks a project result in the command palette +internal_events: true +action: click_project_result_in_command_palette +identifiers: +- namespace +- user +product_section: core_platform +product_stage: data_stores +product_group: global_search +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151655 +distributions: +- ce +- ee +tiers: +- free +- premium +- ultimate diff --git a/config/events/click_user_result_in_command_palette.yml b/config/events/click_user_result_in_command_palette.yml new file mode 100644 index 0000000000000000000000000000000000000000..a3b5a66483221788197bd353dfe3e51ae0a61f10 --- /dev/null +++ b/config/events/click_user_result_in_command_palette.yml @@ -0,0 +1,19 @@ +--- +description: User clicks a user result in the command palette +internal_events: true +action: click_user_result_in_command_palette +identifiers: +- namespace +- user +product_section: core_platform +product_stage: data_stores +product_group: global_search +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147919 +distributions: +- ce +- ee +tiers: +- free +- premium +- ultimate diff --git a/config/metrics/counts_28d/count_distinct_user_id_from_click_project_result_in_command_palette_monthly.yml b/config/metrics/counts_28d/count_distinct_user_id_from_click_project_result_in_command_palette_monthly.yml new file mode 100644 index 0000000000000000000000000000000000000000..fc9fc0beccd09d56b8ab50b97388c73a21372704 --- /dev/null +++ b/config/metrics/counts_28d/count_distinct_user_id_from_click_project_result_in_command_palette_monthly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_click_project_result_in_command_palette_monthly +description: Monthly count of unique users User clicks a project result in the command palette +product_section: core_platform +product_stage: data_stores +product_group: global_search +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151655 +time_frame: 28d +data_source: internal_events +data_category: optional +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +events: +- name: click_project_result_in_command_palette + unique: user.id diff --git a/config/metrics/counts_28d/count_distinct_user_id_from_click_user_result_in_command_palette_monthly.yml b/config/metrics/counts_28d/count_distinct_user_id_from_click_user_result_in_command_palette_monthly.yml new file mode 100644 index 0000000000000000000000000000000000000000..84f0c76f8c39b1353c81284fcb1213dec1932e27 --- /dev/null +++ b/config/metrics/counts_28d/count_distinct_user_id_from_click_user_result_in_command_palette_monthly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_click_user_result_in_command_palette_monthly +description: Monthly count of unique users User clicks a user result in the command palette +product_section: core_platform +product_stage: data_stores +product_group: global_search +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147919 +time_frame: 28d +data_source: internal_events +data_category: optional +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +events: +- name: click_user_result_in_command_palette + unique: user.id diff --git a/config/metrics/counts_7d/count_distinct_user_id_from_click_project_result_in_command_palette_weekly.yml b/config/metrics/counts_7d/count_distinct_user_id_from_click_project_result_in_command_palette_weekly.yml new file mode 100644 index 0000000000000000000000000000000000000000..5860f973d66114a7b9b09656f4b4d3e466def0b5 --- /dev/null +++ b/config/metrics/counts_7d/count_distinct_user_id_from_click_project_result_in_command_palette_weekly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_click_project_result_in_command_palette_weekly +description: Weekly count of unique users who click a project result in the command palette +product_section: core_platform +product_stage: data_stores +product_group: global_search +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151655 +time_frame: 7d +data_source: internal_events +data_category: optional +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +events: +- name: click_project_result_in_command_palette + unique: user.id diff --git a/config/metrics/counts_7d/count_distinct_user_id_from_click_user_result_in_command_palette_weekly.yml b/config/metrics/counts_7d/count_distinct_user_id_from_click_user_result_in_command_palette_weekly.yml new file mode 100644 index 0000000000000000000000000000000000000000..d40a89256b9b3859fcda82d318e7345b9808a1de --- /dev/null +++ b/config/metrics/counts_7d/count_distinct_user_id_from_click_user_result_in_command_palette_weekly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_click_user_result_in_command_palette_weekly +description: Weekly count of unique users who click a user result in the command palette +product_section: core_platform +product_stage: data_stores +product_group: global_search +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147919 +time_frame: 7d +data_source: internal_events +data_category: optional +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +events: +- name: click_user_result_in_command_palette + unique: user.id diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f362e78176e9b06fbc7f6301bba99d9bc32d504f..d33a003288213191fe944e51aec8444373789202 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -23748,6 +23748,9 @@ msgstr "" msgid "GlobalSearch|Create in %{namespace} %{kbdStart}↵%{kbdEnd}" msgstr "" +msgid "GlobalSearch|Explore" +msgstr "" + msgid "GlobalSearch|Fetching aggregations error." msgstr "" @@ -23793,6 +23796,9 @@ msgstr "" msgid "GlobalSearch|Initial indexing queue length" msgstr "" +msgid "GlobalSearch|Issues" +msgstr "" + msgid "GlobalSearch|Issues I've created" msgstr "" @@ -23811,6 +23817,9 @@ msgstr "" msgid "GlobalSearch|List of filtered labels." msgstr "" +msgid "GlobalSearch|Merge Requests" +msgstr "" + msgid "GlobalSearch|Merge requests I've created" msgstr "" @@ -23838,6 +23847,12 @@ msgstr "" msgid "GlobalSearch|Places" msgstr "" +msgid "GlobalSearch|Preferences" +msgstr "" + +msgid "GlobalSearch|Profile" +msgstr "" + msgid "GlobalSearch|Project" msgstr "" @@ -23937,6 +23952,9 @@ msgstr "" msgid "GlobalSearch|What are you searching for?" msgstr "" +msgid "GlobalSearch|Your work" +msgstr "" + msgid "GlobalSearch|all GitLab" msgstr "" diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js index 2a04f64f70dce9efa48bd7b88aaf14f880107f40..dd49e1c4b782a43f6d5340188a67f71ccfa84797 100644 --- a/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js +++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js @@ -13,6 +13,8 @@ import GlobalSearchAutocompleteItems from '~/super_sidebar/components/global_sea import SearchResultHoverLayover from '~/super_sidebar/components/global_search/components/global_search_hover_overlay.vue'; import GlobalSearchNoResults from '~/super_sidebar/components/global_search/components/global_search_no_results.vue'; +import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper'; +import { PROJECTS_GROUP_TITLE } from '~/super_sidebar/components/global_search/command_palette/constants'; import { MOCK_GROUPED_AUTOCOMPLETE_OPTIONS, MOCK_SCOPED_SEARCH_OPTIONS, @@ -49,6 +51,7 @@ describe('GlobalSearchAutocompleteItems', () => { }); }; + const findGlDisclosureDropdownGroup = () => wrapper.findComponent(GlDisclosureDropdownGroup); const findItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem); const findItemTitles = () => findItems().wrappers.map((w) => w.find('[data-testid="autocomplete-item-name"]').text()); @@ -65,6 +68,7 @@ describe('GlobalSearchAutocompleteItems', () => { const findNoResults = () => wrapper.findComponent(GlobalSearchNoResults); describe('template', () => { + const { bindInternalEventDocument } = useMockInternalEventsTracking(); describe('when loading is true', () => { beforeEach(() => { createComponent({ loading: true }); @@ -101,7 +105,7 @@ describe('GlobalSearchAutocompleteItems', () => { describe('when loading is false', () => { beforeEach(() => { - createComponent({ loading: false }); + createComponent(); }); it('does not render GlLoadingIcon', () => { @@ -113,6 +117,20 @@ describe('GlobalSearchAutocompleteItems', () => { expect(findItems()).toHaveLength(MOCK_SORTED_AUTOCOMPLETE_OPTIONS.length); }); + it('tracks click on project results', async () => { + const { trackEventSpy } = bindInternalEventDocument(wrapper.element); + + await findGlDisclosureDropdownGroup().vm.$emit('action', { + category: PROJECTS_GROUP_TITLE, + }); + + expect(trackEventSpy).toHaveBeenCalledWith( + 'click_project_result_in_command_palette', + {}, + undefined, + ); + }); + it('renders titles correctly', () => { const expectedTitles = MOCK_SORTED_AUTOCOMPLETE_OPTIONS.map((o) => o.value || o.text); expect(findItemTitles()).toStrictEqual(expectedTitles);