Commit cbdc69d1 authored by Tim Zallmann's avatar Tim Zallmann

Merge branch '7424-create-a-generic-event-listener-for-tracking-clicks-on-gitlab-com' into 'master'

Resolve "Create a generic event listener for tracking clicks on GitLab.com"

Closes #7424

See merge request gitlab-org/gitlab-ee!7403
parents 9b5e7122 036958b7
- active_tab = local_assigns.fetch(:active_tab, 'blank') - active_tab = local_assigns.fetch(:active_tab, 'blank')
- track_label = local_assigns.fetch(:track_label, 'import_project')
.project-import .project-import
.form-group.import-btn-container.clearfix .form-group.import-btn-container.clearfix
...@@ -7,60 +8,62 @@ ...@@ -7,60 +8,62 @@
.import-buttons .import-buttons
- if gitlab_project_import_enabled? - if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body' } } .import_gitlab_project.has-tooltip{ data: { container: 'body' } }
= link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "gitlab_export" } do
= icon('gitlab', text: 'GitLab export') = icon('gitlab', text: 'GitLab export')
- if github_import_enabled? - if github_import_enabled?
%div %div
= link_to new_import_github_path, class: 'btn js-import-github' do = link_to new_import_github_path, class: 'btn js-import-github', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "github" } do
= icon('github', text: 'GitHub') = icon('github', text: 'GitHub')
- if bitbucket_import_enabled? - if bitbucket_import_enabled?
%div %div
= link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}",
data: { track_label: "#{track_label}", track_event: "click_button", track_property: "bitbucket_cloud" } do
= icon('bitbucket', text: 'Bitbucket Cloud') = icon('bitbucket', text: 'Bitbucket Cloud')
- unless bitbucket_import_configured? - unless bitbucket_import_configured?
= render 'bitbucket_import_modal' = render 'bitbucket_import_modal'
- if bitbucket_server_import_enabled? - if bitbucket_server_import_enabled?
%div %div
= link_to status_import_bitbucket_server_path, class: "btn import_bitbucket" do = link_to status_import_bitbucket_server_path, class: "btn import_bitbucket", data: { track_label: "#{track_label}", track_event: "click_button", track_property: "bitbucket_server" } do
= icon('bitbucket-square', text: 'Bitbucket Server') = icon('bitbucket-square', text: 'Bitbucket Server')
%div %div
- if gitlab_import_enabled? - if gitlab_import_enabled?
%div %div
= link_to status_import_gitlab_path, class: "btn import_gitlab #{'how_to_import_link' unless gitlab_import_configured?}" do = link_to status_import_gitlab_path, class: "btn import_gitlab #{'how_to_import_link' unless gitlab_import_configured?}",
data: { track_label: "#{track_label}", track_event: "click_button", track_property: "gitlab_com" } do
= icon('gitlab', text: 'GitLab.com') = icon('gitlab', text: 'GitLab.com')
- unless gitlab_import_configured? - unless gitlab_import_configured?
= render 'gitlab_import_modal' = render 'gitlab_import_modal'
- if google_code_import_enabled? - if google_code_import_enabled?
%div %div
= link_to new_import_google_code_path, class: 'btn import_google_code' do = link_to new_import_google_code_path, class: 'btn import_google_code', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "google_code" } do
= icon('google', text: 'Google Code') = icon('google', text: 'Google Code')
- if fogbugz_import_enabled? - if fogbugz_import_enabled?
%div %div
= link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do = link_to new_import_fogbugz_path, class: 'btn import_fogbugz', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "fogbugz" } do
= icon('bug', text: 'Fogbugz') = icon('bug', text: 'Fogbugz')
- if gitea_import_enabled? - if gitea_import_enabled?
%div %div
= link_to new_import_gitea_path, class: 'btn import_gitea' do = link_to new_import_gitea_path, class: 'btn import_gitea', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "gitea" } do
= custom_icon('go_logo') = custom_icon('go_logo')
Gitea Gitea
- if git_import_enabled? - if git_import_enabled?
%div %div
%button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } } %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active', track_label: "#{track_label}" , track_event: "click_button", track_property: "repo_url" } }
= icon('git', text: 'Repo by URL') = icon('git', text: 'Repo by URL')
- if manifest_import_enabled? - if manifest_import_enabled?
%div %div
= link_to new_import_manifest_path, class: 'btn import_manifest' do = link_to new_import_manifest_path, class: 'btn import_manifest', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "manifest_file" } do
= icon('file-text-o', text: 'Manifest file') = icon('file-text-o', text: 'Manifest file')
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') } .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
= form_for @project, html: { class: 'new_project' } do |f| = form_for @project, html: { class: 'new_project' } do |f|
%hr %hr
= render "shared/import_form", f: f = render "shared/import_form", f: f
= render 'new_project_fields', f: f, project_name_id: "import-url-name", hide_init_with_readme: true = render 'new_project_fields', f: f, project_name_id: "import-url-name", hide_init_with_readme: true, track_label: track_label
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility - visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
- ci_cd_only = local_assigns.fetch(:ci_cd_only, false) - ci_cd_only = local_assigns.fetch(:ci_cd_only, false)
- hide_init_with_readme = local_assigns.fetch(:hide_init_with_readme, false) - hide_init_with_readme = local_assigns.fetch(:hide_init_with_readme, false)
- track_label = local_assigns.fetch(:track_label, 'blank_project')
.row{ id: project_name_id } .row{ id: project_name_id }
= f.hidden_field :ci_cd_only, value: ci_cd_only = f.hidden_field :ci_cd_only, value: ci_cd_only
.form-group.project-name.col-sm-12 .form-group.project-name.col-sm-12
= f.label :name, class: 'label-bold' do = f.label :name, class: 'label-bold' do
%span= _("Project name") %span= _("Project name")
= f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true = f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true, data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "project_name", track_value: "" }
.form-group.project-path.col-sm-6 .form-group.project-path.col-sm-6
= f.label :namespace_id, class: 'label-bold' do = f.label :namespace_id, class: 'label-bold' do
%span= s_("Project URL") %span= s_("Project URL")
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
display_path: true, display_path: true,
extra_group: namespace_id), extra_group: namespace_id),
{}, {},
{ class: 'select2 js-select-namespace qa-project-namespace-select', tabindex: 1}) { class: 'select2 js-select-namespace qa-project-namespace-select', tabindex: 1, data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "project_path", track_value: "" }})
- else - else
.input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' } .input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
...@@ -42,7 +43,7 @@ ...@@ -42,7 +43,7 @@
= f.label :description, class: 'label-bold' do = f.label :description, class: 'label-bold' do
Project description Project description
%span (optional) %span (optional)
= f.text_area :description, placeholder: 'Description format', class: "form-control", rows: 3, maxlength: 250 = f.text_area :description, placeholder: 'Description format', class: "form-control", rows: 3, maxlength: 250, data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "project_description", track_value: "" }
= f.label :visibility_level, class: 'label-bold' do = f.label :visibility_level, class: 'label-bold' do
Visibility Level Visibility Level
...@@ -53,12 +54,12 @@ ...@@ -53,12 +54,12 @@
.form-group.row.initialize-with-readme-setting .form-group.row.initialize-with-readme-setting
%div{ :class => "col-sm-12" } %div{ :class => "col-sm-12" }
.form-check .form-check
= check_box_tag 'project[initialize_with_readme]', '1', false, class: 'form-check-input' = check_box_tag 'project[initialize_with_readme]', '1', false, class: 'form-check-input', data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "init_with_readme" }
= label_tag 'project[initialize_with_readme]', class: 'form-check-label' do = label_tag 'project[initialize_with_readme]', class: 'form-check-label' do
.option-title .option-title
%strong Initialize repository with a README %strong Initialize repository with a README
.option-description .option-description
Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository. Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository.
= f.submit 'Create project', class: "btn btn-success project-submit", tabindex: 4 = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4, data: { track_label: "#{track_label}", track_event: "click_button", track_property: "create_project", track_value: "" }
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel' = link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "cancel" }
...@@ -5,4 +5,4 @@ ...@@ -5,4 +5,4 @@
.project-fields-form .project-fields-form
= render 'projects/project_templates/project_fields_form' = render 'projects/project_templates/project_fields_form'
= render 'projects/new_project_fields', f: f, project_name_id: "template-project-name", hide_init_with_readme: true = render 'projects/new_project_fields', f: f, project_name_id: "template-project-name", hide_init_with_readme: true, track_label: "create_from_template"
...@@ -34,15 +34,15 @@ ...@@ -34,15 +34,15 @@
.col-lg-9.js-toggle-container .col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' } %ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li.nav-item{ role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab', track_label: 'blank_project', track_event: "click_tab" }, role: 'tab' }
%span.d-none.d-sm-block Blank project %span.d-none.d-sm-block Blank project
%span.d-block.d-sm-none Blank %span.d-block.d-sm-none Blank
%li.nav-item{ role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab', track_label: 'create_from_template', track_event: "click_tab" }, role: 'tab' }
%span.d-none.d-sm-block Create from template %span.d-none.d-sm-block Create from template
%span.d-block.d-sm-none Template %span.d-block.d-sm-none Template
%li.nav-item{ role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab', track_label: 'import_project', track_event: "click_tab" }, role: 'tab' }
%span.d-none.d-sm-block Import project %span.d-none.d-sm-block Import project
%span.d-block.d-sm-none Import %span.d-block.d-sm-none Import
-# EE-specific start -# EE-specific start
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
= template.description = template.description
.controls.d-flex.align-items-center .controls.d-flex.align-items-center
%label.btn.btn-success.template-button.choose-template.append-right-10.append-bottom-0{ for: template.name } %label.btn.btn-success.template-button.choose-template.append-right-10.append-bottom-0{ for: template.name }
%input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name } %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name,
data: { track_label: "create_from_template", track_property: "template_use", track_event: "click_button" } }
%span %span
= _("Use template") = _("Use template")
%a.btn.btn-default{ href: template.preview, rel: 'noopener noreferrer', target: '_blank' } %a.btn.btn-default{ href: template.preview, rel: 'noopener noreferrer', target: '_blank',
data: { track_label: "create_from_template", track_property: "template_preview", track_event: "click_button", track_value: template.name } }
= _("Preview") = _("Preview")
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
- restricted = restricted_visibility_levels.include?(level) - restricted = restricted_visibility_levels.include?(level)
- disabled = disallowed || restricted - disabled = disallowed || restricted
.form-check{ class: [('disabled' if disabled), ('restricted' if restricted)] } .form-check{ class: [('disabled' if disabled), ('restricted' if restricted)] }
= form.radio_button model_method, level, checked: (selected_level == level), disabled: disabled, class: 'form-check-input' = form.radio_button model_method, level, checked: (selected_level == level), disabled: disabled, class: 'form-check-input',
data: { track_label: "blank_project", track_event: "activate_form_input", track_property: "#{model_method}", track_value: "#{level}" }
= form.label "#{model_method}_#{level}", class: 'form-check-label' do = form.label "#{model_method}_#{level}", class: 'form-check-label' do
= visibility_level_icon(level) = visibility_level_icon(level)
.option-title .option-title
......
import '~/pages/projects/new/index'; import '~/pages/projects/new/index';
import initCustomProjectTemplates from 'ee/projects/custom_project_templates'; import initCustomProjectTemplates from 'ee/projects/custom_project_templates';
import bindTrackEvents from 'ee/projects/track_project_new';
document.addEventListener('DOMContentLoaded', initCustomProjectTemplates); document.addEventListener('DOMContentLoaded', () => {
initCustomProjectTemplates();
bindTrackEvents('.js-toggle-container');
});
import Stats from 'ee/stats';
const bindTrackEvents = (container) => {
Stats.bindTrackableContainer(container);
};
export default bindTrackEvents;
import $ from 'jquery';
const snowPlowEnabled = () => typeof window.snowplow === 'function';
const trackEvent = (category, eventName, additionalData = { label: '', property: '', value: '' }) => {
if (!snowPlowEnabled()) {
return;
}
if (!category || !eventName) {
return;
}
const { label, property, value } = additionalData;
try {
window.snowplow(
'trackStructEvent',
category,
eventName,
label,
property,
value,
);
} catch (e) {
// do nothing
}
};
const bindTrackableContainer = (container = '', category = document.body.dataset.page) => {
if (!snowPlowEnabled()) {
return;
}
const clickHandler = (e) => {
const target = e.currentTarget;
const label = target.getAttribute('data-track-label');
const property = target.getAttribute('data-track-property') || '';
const eventName = target.getAttribute('data-track-event');
let value = target.value || '';
// overrides value for checkboxes
if (target.type === 'checkbox') {
value = target.checked;
}
// overrides value if data-track_value is set
if (typeof target.getAttribute('data-track-value') !== 'undefined' && target.getAttribute('data-track-value') !== null) {
value = target.getAttribute('data-track-value');
}
trackEvent(category, eventName, { label, property, value });
};
const trackableElements = document.querySelectorAll(`${container} [data-track-label]`);
trackableElements.forEach(element => {
element.addEventListener('click', (e) => clickHandler(e));
});
// jquery required for select2 events
// see: https://github.com/select2/select2/issues/4686#issuecomment-264747428
$(`${container} .select2[data-track-label]`).on('click', (e) => clickHandler(e));
};
export default {
trackEvent,
bindTrackableContainer,
};
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
post: true, post: true,
contexts: { contexts: {
webPage: true, webPage: true,
} },
stateStorageStrategy: "localStorage"
}); });
window.snowplow('enableActivityTracking', 30, 30); window.snowplow('enableActivityTracking', 30, 30);
......
- return unless ci_cd_projects_available? - return unless ci_cd_projects_available?
- track_label = local_assigns.fetch(:track_label, 'cicd_for_external_repo')
.tab-pane.js-toggle-container{ id: 'ci-cd-project-pane', class: active_when(active_tab == 'ci_cd_only'), role: 'tabpanel' } .tab-pane.js-toggle-container{ id: 'ci-cd-project-pane', class: active_when(active_tab == 'ci_cd_only'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f| = form_for @project, html: { class: 'new_project' } do |f|
...@@ -18,14 +19,14 @@ ...@@ -18,14 +19,14 @@
.import-buttons .import-buttons
%div %div
- if github_import_enabled? - if github_import_enabled?
= link_to new_import_github_path(ci_cd_only: true), class: 'btn js-import-github' do = link_to new_import_github_path(ci_cd_only: true), class: 'btn js-import-github', data: { track_label: "#{track_label}", track_property: 'github', track_event: "click_button" } do
= icon('github', text: 'GitHub') = icon('github', text: 'GitHub')
%div %div
- if git_import_enabled? - if git_import_enabled?
%button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } } %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active', track_label: "#{track_label}", track_property: 'repo_url', track_event: "click_button" } }
= icon('git', text: _('Repo by URL')) = icon('git', text: _('Repo by URL'))
.col-lg-12 .col-lg-12
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'ci_cd_only') } .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'ci_cd_only') }
%hr %hr
= render "shared/import_form", f: f, ci_cd_only: true = render "shared/import_form", f: f, ci_cd_only: true
= render 'new_project_fields', f: f, project_name_id: "import-url-name", ci_cd_only: true, hide_init_with_readme: true = render 'new_project_fields', f: f, project_name_id: "import-url-name", ci_cd_only: true, hide_init_with_readme: true, track_label: track_label
- return unless ci_cd_projects_available? - return unless ci_cd_projects_available?
%li{ class: active_when(active_tab == 'ci_cd_only'), role: 'presentation' } %li.nav-item{ class: active_when(active_tab == 'ci_cd_only'), role: 'presentation' }
%a{ href: '#ci-cd-project-pane', id: 'ci-cd-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#ci-cd-project-pane', id: 'ci-cd-project-tab', data: { toggle: 'tab', track_label: 'cicd_for_external_repo', track_event: "click_tab" }, role: 'tab' }
%span.d-none.d-sm-block %span.d-none.d-sm-block
= _('CI/CD for external repo') = _('CI/CD for external repo')
%span.d-block.d-sm-none %span.d-block.d-sm-none
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
.project-fields-form .project-fields-form
= render 'projects/project_templates/project_fields_form' = render 'projects/project_templates/project_fields_form'
= f.hidden_field(:use_custom_template, value: false) = f.hidden_field(:use_custom_template, value: false)
= render 'projects/new_project_fields', f: f, project_name_id: "template-project-name", hide_init_with_readme: true = render 'projects/new_project_fields', f: f, project_name_id: "template-project-name", hide_init_with_readme: true, track_label: "create_from_template"
- else - else
= render_ce 'projects/project_templates', f: f = render_ce 'projects/project_templates', f: f
---
title: Create a generic JS function that we can apply to being able to track arbitrary events
merge_request: 7403
author:
type: other
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment