diff --git a/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app.vue b/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app.vue index 3a727e295dc0c38480c731040044cdb405eb8940..4b915b00dbb5f4b5956f2f4823bf97682b9cfb7e 100644 --- a/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app.vue +++ b/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app.vue @@ -1,5 +1,6 @@ <script> import { GlButton } from '@gitlab/ui'; +import { InternalEvents } from '~/tracking'; import { INSTANCE_TYPE, STATUS_ONLINE, STATUS_OFFLINE } from '~/ci/runner/constants'; import RunnerListHeader from '~/ci/runner/components/runner_list_header.vue'; @@ -10,6 +11,8 @@ import RunnerJobFailures from '../components/runner_job_failures.vue'; import AdminRunnersActiveList from './admin_runners_active_list.vue'; import AdminRunnersWaitTimes from './admin_runners_wait_times.vue'; +const trackingMixin = InternalEvents.mixin(); + export default { components: { GlButton, @@ -20,6 +23,7 @@ export default { RunnerUsage, RunnerJobFailures, }, + mixins: [trackingMixin], inject: { clickhouseCiAnalyticsAvailable: { default: false, @@ -35,6 +39,11 @@ export default { required: true, }, }, + mounted() { + this.trackEvent('view_runner_fleet_dashboard_pageload', { + label: 'instance', + }); + }, INSTANCE_TYPE, STATUS_ONLINE, STATUS_OFFLINE, diff --git a/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue index 8e8110bf0a83e8db4484e9e4405e542a399fba21..7ee37af624169720085ad5ab1f7200d9f58610ff 100644 --- a/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue +++ b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue @@ -1,5 +1,6 @@ <script> import { GlButton } from '@gitlab/ui'; +import { InternalEvents } from '~/tracking'; import { GROUP_TYPE, STATUS_ONLINE, STATUS_OFFLINE } from '~/ci/runner/constants'; import RunnerListHeader from '~/ci/runner/components/runner_list_header.vue'; import RunnerUsage from '../components/runner_usage.vue'; @@ -8,6 +9,8 @@ import RunnerDashboardStatStatus from '../components/runner_dashboard_stat_statu import GroupRunnersActiveList from './group_runners_active_list.vue'; import GroupRunnersWaitTimes from './group_runners_wait_times.vue'; +const trackingMixin = InternalEvents.mixin(); + export default { components: { GlButton, @@ -17,6 +20,7 @@ export default { RunnerDashboardStatStatus, RunnerUsage, }, + mixins: [trackingMixin], inject: { clickhouseCiAnalyticsAvailable: { default: false, @@ -36,6 +40,11 @@ export default { required: true, }, }, + mounted() { + this.trackEvent('view_runner_fleet_dashboard_pageload', { + label: 'group', + }); + }, GROUP_TYPE, STATUS_ONLINE, STATUS_OFFLINE, diff --git a/ee/config/events/view_runner_fleet_dashboard_pageload.yml b/ee/config/events/view_runner_fleet_dashboard_pageload.yml new file mode 100644 index 0000000000000000000000000000000000000000..26edfbdf577f9959af5c506b009d4c367ee8d27f --- /dev/null +++ b/ee/config/events/view_runner_fleet_dashboard_pageload.yml @@ -0,0 +1,16 @@ +--- +description: Triggers when user visits runner fleet dashboard. +internal_events: true +action: view_runner_fleet_dashboard_pageload +identifiers: +- user +additional_properties: + label: + description: The dashboard level, which can be `project`, `group`, or `instance` +product_group: runner +milestone: '17.2' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157589 +distributions: +- ee +tiers: +- ultimate diff --git a/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_monthly.yml b/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_monthly.yml new file mode 100644 index 0000000000000000000000000000000000000000..2b6a471b2d3c13783018382648e4864b7b2edd51 --- /dev/null +++ b/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_monthly.yml @@ -0,0 +1,21 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_monthly +description: Monthly count of unique users who visited a group runner fleet dashboard +product_group: runner +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.2' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157589 +time_frame: 28d +data_source: internal_events +data_category: optional +distribution: +- ee +tier: +- ultimate +events: +- name: view_runner_fleet_dashboard_pageload + unique: user.id + filter: + label: group diff --git a/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_monthly.yml b/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_monthly.yml new file mode 100644 index 0000000000000000000000000000000000000000..a1e28303f15b90a2a9c96aa7a98d72488dc6e251 --- /dev/null +++ b/ee/config/metrics/counts_28d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_monthly.yml @@ -0,0 +1,21 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_monthly +description: Monthly count of unique users who visited the instance's runner fleet dashboard +product_group: runner +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.2' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157589 +time_frame: 28d +data_source: internal_events +data_category: optional +distribution: +- ee +tier: +- ultimate +events: +- name: view_runner_fleet_dashboard_pageload + unique: user.id + filter: + label: instance diff --git a/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_weekly.yml b/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_weekly.yml new file mode 100644 index 0000000000000000000000000000000000000000..2502b0e5627fc46dfd5a6610ed7657d39f93d1ba --- /dev/null +++ b/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_weekly.yml @@ -0,0 +1,21 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_group_weekly +description: Weekly count of unique users who visited a group runner fleet dashboard +product_group: runner +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.2' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157589 +time_frame: 7d +data_source: internal_events +data_category: optional +distribution: +- ee +tier: +- ultimate +events: +- name: view_runner_fleet_dashboard_pageload + unique: user.id + filter: + label: group diff --git a/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_weekly.yml b/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_weekly.yml new file mode 100644 index 0000000000000000000000000000000000000000..246edf98300dce62c1e2dabf3dd3b22b731143e8 --- /dev/null +++ b/ee/config/metrics/counts_7d/count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_weekly.yml @@ -0,0 +1,21 @@ +--- +key_path: redis_hll_counters.count_distinct_user_id_from_view_runner_fleet_dashboard_pageload_on_instance_weekly +description: Weekly count of unique users who visited the instance's runner fleet dashboard +product_group: runner +performance_indicator_type: [] +value_type: number +status: active +milestone: '17.2' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157589 +time_frame: 7d +data_source: internal_events +data_category: optional +distribution: +- ee +tier: +- ultimate +events: +- name: view_runner_fleet_dashboard_pageload + unique: user.id + filter: + label: instance diff --git a/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app_spec.js b/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app_spec.js index c7127d9a8c9b629c88dbeb77d9e6b6918dd2accd..1d1526c9892b2131cfa096f4362ca21668582fdf 100644 --- a/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app_spec.js +++ b/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_dashboard_app_spec.js @@ -10,6 +10,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import RunnerDashboardStatStatus from 'ee/ci/runner/components/runner_dashboard_stat_status.vue'; import RunnerUsage from 'ee/ci/runner/components/runner_usage.vue'; import RunnerJobFailures from 'ee/ci/runner/components/runner_job_failures.vue'; +import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper'; const mockAdminRunnersPath = '/runners/list'; const mockNewRunnerPath = '/runners/new'; @@ -17,6 +18,7 @@ const mockNewRunnerPath = '/runners/new'; describe('AdminRunnersDashboardApp', () => { let wrapper; + const { bindInternalEventDocument } = useMockInternalEventsTracking(); const createComponent = (options) => { wrapper = shallowMountExtended(AdminRunnersDashboardApp, { propsData: { @@ -41,6 +43,18 @@ describe('AdminRunnersDashboardApp', () => { expect(newBtn.attributes('href')).toBe(mockNewRunnerPath); }); + it('should track that the admin runner fleet dashboard has been viewed', () => { + const { trackEventSpy } = bindInternalEventDocument(wrapper.element); + + expect(trackEventSpy).toHaveBeenCalledWith( + 'view_runner_fleet_dashboard_pageload', + { + label: 'instance', + }, + undefined, + ); + }); + it('shows dashboard panels', () => { expect(wrapper.findAllComponents(RunnerDashboardStatStatus).at(0).props()).toEqual({ scope: INSTANCE_TYPE, diff --git a/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js index cafa75e9371b853cc9a1f3335087839f0ae1aea8..1961ea1a1adf25ac32f94cb63d6394a6f2968874 100644 --- a/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js +++ b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js @@ -9,6 +9,7 @@ import RunnerDashboardStatStatus from 'ee/ci/runner/components/runner_dashboard_ import RunnerUsage from 'ee/ci/runner/components/runner_usage.vue'; import GroupRunnersActiveList from 'ee/ci/runner/group_runners_dashboard/group_runners_active_list.vue'; import GroupRunnersWaitTimes from 'ee/ci/runner/group_runners_dashboard/group_runners_wait_times.vue'; +import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper'; const mockGroupPath = 'group'; const mockGroupRunnersPath = '/group/-/runners'; @@ -20,6 +21,7 @@ describe('GroupRunnersDashboardApp', () => { const findGroupRunnersActiveList = () => wrapper.findComponent(GroupRunnersActiveList); const findGroupRunnersWaitTimes = () => wrapper.findComponent(GroupRunnersWaitTimes); + const { bindInternalEventDocument } = useMockInternalEventsTracking(); const createComponent = (options) => { wrapper = shallowMountExtended(GroupRunnersDashboardApp, { propsData: { @@ -65,6 +67,18 @@ describe('GroupRunnersDashboardApp', () => { }); }); + it('should track that the group runner fleet dashboard has been viewed', () => { + const { trackEventSpy } = bindInternalEventDocument(wrapper.element); + + expect(trackEventSpy).toHaveBeenCalledWith( + 'view_runner_fleet_dashboard_pageload', + { + label: 'group', + }, + undefined, + ); + }); + describe('when clickhouse is available', () => { beforeEach(() => { createComponent({