Commit a0b783de authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'migrate-upload-button-experminent-to-glmodal' into 'master'

Migrate upload file experiment

See merge request gitlab-org/gitlab!56084
parents a429b96c c907a1ab
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
import $ from 'jquery'; import $ from 'jquery';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import { trackUploadFileFormSubmitted } from '~/projects/upload_file_experiment';
import { HIDDEN_CLASS } from '../lib/utils/constants'; import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf'; import csrf from '../lib/utils/csrf';
import { visitUrl } from '../lib/utils/url_utility'; import { visitUrl } from '../lib/utils/url_utility';
...@@ -85,8 +84,6 @@ export default class BlobFileDropzone { ...@@ -85,8 +84,6 @@ export default class BlobFileDropzone {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
trackUploadFileFormSubmitted();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) { if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert(__('Please select a file')); alert(__('Please select a file'));
......
...@@ -4,7 +4,6 @@ import $ from 'jquery'; ...@@ -4,7 +4,6 @@ import $ from 'jquery';
import initPopover from '~/blob/suggest_gitlab_ci_yml'; import initPopover from '~/blob/suggest_gitlab_ci_yml';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils'; import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
import { initUploadFileTrigger } from '~/projects/upload_file_experiment';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import BlobFileDropzone from '../blob/blob_file_dropzone'; import BlobFileDropzone from '../blob/blob_file_dropzone';
import NewCommitForm from '../new_commit_form'; import NewCommitForm from '../new_commit_form';
...@@ -48,7 +47,6 @@ export const initUploadForm = () => { ...@@ -48,7 +47,6 @@ export const initUploadForm = () => {
new NewCommitForm(uploadBlobForm); new NewCommitForm(uploadBlobForm);
disableButtonIfEmptyField(uploadBlobForm.find('.js-commit-message'), '.btn-upload-file'); disableButtonIfEmptyField(uploadBlobForm.find('.js-commit-message'), '.btn-upload-file');
initUploadFileTrigger();
} }
}; };
......
...@@ -5,6 +5,7 @@ import BlobViewer from '~/blob/viewer/index'; ...@@ -5,6 +5,7 @@ import BlobViewer from '~/blob/viewer/index';
import { initUploadForm } from '~/blob_edit/blob_bundle'; import { initUploadForm } from '~/blob_edit/blob_bundle';
import leaveByUrl from '~/namespaces/leave_by_url'; import leaveByUrl from '~/namespaces/leave_by_url';
import initVueNotificationsDropdown from '~/notifications'; import initVueNotificationsDropdown from '~/notifications';
import { initUploadFileTrigger } from '~/projects/upload_file_experiment';
import initReadMore from '~/read_more'; import initReadMore from '~/read_more';
import UserCallout from '~/user_callout'; import UserCallout from '~/user_callout';
import Star from '../../../star'; import Star from '../../../star';
...@@ -41,3 +42,5 @@ leaveByUrl('project'); ...@@ -41,3 +42,5 @@ leaveByUrl('project');
initVueNotificationsDropdown(); initVueNotificationsDropdown();
new ShortcutsNavigation(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new
initUploadFileTrigger();
<script> <script>
import { GlButton, GlModalDirective } from '@gitlab/ui'; import { GlButton, GlModalDirective } from '@gitlab/ui';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue'; import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
import { trackFileUploadEvent } from '../upload_file_experiment_tracking';
const UPLOAD_BLOB_MODAL_ID = 'details-modal-upload-blob'; const UPLOAD_BLOB_MODAL_ID = 'details-modal-upload-blob';
...@@ -16,7 +17,7 @@ export default { ...@@ -16,7 +17,7 @@ export default {
targetBranch: { targetBranch: {
default: '', default: '',
}, },
origionalBranch: { originalBranch: {
default: '', default: '',
}, },
canPushCode: { canPushCode: {
...@@ -29,19 +30,28 @@ export default { ...@@ -29,19 +30,28 @@ export default {
default: '', default: '',
}, },
}, },
methods: {
trackOpenModal() {
trackFileUploadEvent('click_upload_modal_trigger');
},
},
uploadBlobModalId: UPLOAD_BLOB_MODAL_ID, uploadBlobModalId: UPLOAD_BLOB_MODAL_ID,
}; };
</script> </script>
<template> <template>
<span> <span>
<gl-button v-gl-modal="$options.uploadBlobModalId" icon="upload">{{ <gl-button
__('Upload File') v-gl-modal="$options.uploadBlobModalId"
}}</gl-button> icon="upload"
data-testid="upload-file-button"
@click="trackOpenModal"
>{{ __('Upload File') }}</gl-button
>
<upload-blob-modal <upload-blob-modal
:modal-id="$options.uploadBlobModalId" :modal-id="$options.uploadBlobModalId"
:commit-message="__('Upload New File')" :commit-message="__('Upload New File')"
:target-branch="targetBranch" :target-branch="targetBranch"
:origional-branch="origionalBranch" :original-branch="originalBranch"
:can-push-code="canPushCode" :can-push-code="canPushCode"
:path="path" :path="path"
/> />
......
import ExperimentTracking from '~/experimentation/experiment_tracking'; import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import createRouter from '~/repository/router';
import UploadButton from './details/upload_button.vue';
function trackEvent(eventName) { export const initUploadFileTrigger = () => {
const isEmpty = Boolean(document.querySelector('.project-home-panel.empty-project')); const uploadFileTriggerEl = document.querySelector('.js-upload-file-experiment-trigger');
const property = isEmpty ? 'empty' : 'nonempty';
const label = 'blob-upload-modal';
const Tracking = new ExperimentTracking('empty_repo_upload', { label, property });
Tracking.event(eventName); if (!uploadFileTriggerEl) return false;
}
export function initUploadFileTrigger() { const {
const uploadFileTriggerEl = document.querySelector('.js-upload-file-experiment-trigger'); targetBranch,
originalBranch,
canPushCode,
path,
projectPath,
} = uploadFileTriggerEl.dataset;
if (uploadFileTriggerEl) { return new Vue({
uploadFileTriggerEl.addEventListener('click', () => { el: uploadFileTriggerEl,
trackEvent('click_upload_modal_trigger'); router: createRouter(projectPath, originalBranch),
provide: {
targetBranch,
originalBranch,
canPushCode: parseBoolean(canPushCode),
path,
projectPath,
},
render(h) {
return h(UploadButton);
},
}); });
} };
}
export function trackUploadFileFormSubmitted() {
trackEvent('click_upload_modal_form_submit');
}
import ExperimentTracking from '~/experimentation/experiment_tracking';
export const trackFileUploadEvent = (eventName) => {
const isEmpty = Boolean(document.querySelector('.project-home-panel.empty-project'));
const property = isEmpty ? 'empty' : 'nonempty';
const label = 'blob-upload-modal';
const FileUploadTracking = new ExperimentTracking('empty_repo_upload', { label, property });
FileUploadTracking.event(eventName);
};
...@@ -15,6 +15,7 @@ import { ContentTypeMultipartFormData } from '~/lib/utils/headers'; ...@@ -15,6 +15,7 @@ import { ContentTypeMultipartFormData } from '~/lib/utils/headers';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import { visitUrl, joinPaths } from '~/lib/utils/url_utility'; import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
const PRIMARY_OPTIONS_TEXT = __('Upload file'); const PRIMARY_OPTIONS_TEXT = __('Upload file');
...@@ -62,7 +63,7 @@ export default { ...@@ -62,7 +63,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
origionalBranch: { originalBranch: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -113,7 +114,7 @@ export default { ...@@ -113,7 +114,7 @@ export default {
return numberToHumanSize(this.file.size); return numberToHumanSize(this.file.size);
}, },
showCreateNewMrToggle() { showCreateNewMrToggle() {
return this.canPushCode && this.target !== this.origionalBranch; return this.canPushCode && this.target !== this.originalBranch;
}, },
formCompleted() { formCompleted() {
return this.file && this.commit && this.target; return this.file && this.commit && this.target;
...@@ -158,6 +159,7 @@ export default { ...@@ -158,6 +159,7 @@ export default {
}, },
}) })
.then((response) => { .then((response) => {
trackFileUploadEvent('click_upload_modal_form_submit');
visitUrl(response.data.filePath); visitUrl(response.data.filePath);
}) })
.catch(() => { .catch(() => {
......
...@@ -253,8 +253,11 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated ...@@ -253,8 +253,11 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
nil, nil,
nil, nil,
{ {
'toggle' => 'modal', 'target_branch' => default_branch_or_master,
'target' => '#modal-upload-blob' 'original_branch' => default_branch_or_master,
'can_push_code' => 'true',
'path' => project_create_blob_path(project, default_branch_or_master),
'project_path' => project.path
} }
) )
end end
......
import $ from 'jquery'; import $ from 'jquery';
import BlobFileDropzone from '~/blob/blob_file_dropzone'; import BlobFileDropzone from '~/blob/blob_file_dropzone';
import { trackUploadFileFormSubmitted } from '~/projects/upload_file_experiment';
jest.mock('~/projects/upload_file_experiment', () => ({
trackUploadFileFormSubmitted: jest.fn(),
}));
describe('BlobFileDropzone', () => { describe('BlobFileDropzone', () => {
let dropzone; let dropzone;
...@@ -45,13 +40,5 @@ describe('BlobFileDropzone', () => { ...@@ -45,13 +40,5 @@ describe('BlobFileDropzone', () => {
expect(replaceFileButton.is(':disabled')).toEqual(true); expect(replaceFileButton.is(':disabled')).toEqual(true);
expect(dropzone.processQueue).toHaveBeenCalled(); expect(dropzone.processQueue).toHaveBeenCalled();
}); });
it('calls the tracking event', () => {
jest.spyOn(window, 'alert').mockImplementation(() => {});
replaceFileButton.click();
expect(trackUploadFileFormSubmitted).toHaveBeenCalled();
});
}); });
}); });
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import UploadButton from '~/projects/details/upload_button.vue'; import UploadButton from '~/projects/details/upload_button.vue';
import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue'; import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
jest.mock('~/projects/upload_file_experiment_tracking');
const MODAL_ID = 'details-modal-upload-blob'; const MODAL_ID = 'details-modal-upload-blob';
describe('UploadButton', () => { describe('UploadButton', () => {
...@@ -47,6 +50,10 @@ describe('UploadButton', () => { ...@@ -47,6 +50,10 @@ describe('UploadButton', () => {
wrapper.find(GlButton).vm.$emit('click'); wrapper.find(GlButton).vm.$emit('click');
}); });
it('tracks the click_upload_modal_trigger event', () => {
expect(trackFileUploadEvent).toHaveBeenCalledWith('click_upload_modal_trigger');
});
it('opens the modal', () => { it('opens the modal', () => {
expect(glModalDirective).toHaveBeenCalledWith(MODAL_ID); expect(glModalDirective).toHaveBeenCalledWith(MODAL_ID);
}); });
......
import ExperimentTracking from '~/experimentation/experiment_tracking'; import ExperimentTracking from '~/experimentation/experiment_tracking';
import * as UploadFileExperiment from '~/projects/upload_file_experiment'; import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
jest.mock('~/experimentation/experiment_tracking'); jest.mock('~/experimentation/experiment_tracking');
const fixture = `<a class='js-upload-file-experiment-trigger' data-toggle='modal' data-target='#modal-upload-blob'></a><div id='modal-upload-blob'></div><div class='project-home-panel empty-project'></div>`; const eventName = 'click_upload_modal_form_submit';
const findModal = () => document.querySelector('[aria-modal="true"]'); const fixture = `<a class='js-upload-file-experiment-trigger'></a><div class='project-home-panel empty-project'></div>`;
const findTrigger = () => document.querySelector('.js-upload-file-experiment-trigger');
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = fixture; document.body.innerHTML = fixture;
...@@ -15,23 +14,26 @@ afterEach(() => { ...@@ -15,23 +14,26 @@ afterEach(() => {
document.body.innerHTML = ''; document.body.innerHTML = '';
}); });
describe('trackUploadFileFormSubmitted', () => { describe('trackFileUploadEvent', () => {
it('initializes ExperimentTracking with the correct arguments and calls the tracking event with correct arguments', () => { it('initializes ExperimentTracking with the correct tracking event', () => {
UploadFileExperiment.trackUploadFileFormSubmitted(); trackFileUploadEvent(eventName);
expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(eventName);
});
it('calls ExperimentTracking with the correct arguments', () => {
trackFileUploadEvent(eventName);
expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', { expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', {
label: 'blob-upload-modal', label: 'blob-upload-modal',
property: 'empty', property: 'empty',
}); });
expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(
'click_upload_modal_form_submit',
);
}); });
it('initializes ExperimentTracking with the correct arguments when the project is not empty', () => { it('calls ExperimentTracking with the correct arguments when the project is not empty', () => {
document.querySelector('.empty-project').remove(); document.querySelector('.empty-project').remove();
UploadFileExperiment.trackUploadFileFormSubmitted(); trackFileUploadEvent(eventName);
expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', { expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', {
label: 'blob-upload-modal', label: 'blob-upload-modal',
...@@ -39,14 +41,3 @@ describe('trackUploadFileFormSubmitted', () => { ...@@ -39,14 +41,3 @@ describe('trackUploadFileFormSubmitted', () => {
}); });
}); });
}); });
describe('initUploadFileTrigger', () => {
it('calls modal and tracks event', () => {
UploadFileExperiment.initUploadFileTrigger();
expect(findModal()).not.toExist();
findTrigger().click();
expect(findModal()).toExist();
expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith('click_upload_modal_trigger');
});
});
...@@ -6,9 +6,11 @@ import waitForPromises from 'helpers/wait_for_promises'; ...@@ -6,9 +6,11 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue'; import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
jest.mock('~/projects/upload_file_experiment_tracking');
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(), visitUrl: jest.fn(),
...@@ -19,7 +21,7 @@ const initialProps = { ...@@ -19,7 +21,7 @@ const initialProps = {
modalId: 'upload-blob', modalId: 'upload-blob',
commitMessage: 'Upload New File', commitMessage: 'Upload New File',
targetBranch: 'master', targetBranch: 'master',
origionalBranch: 'master', originalBranch: 'master',
canPushCode: true, canPushCode: true,
path: 'new_upload', path: 'new_upload',
}; };
...@@ -160,6 +162,10 @@ describe('UploadBlobModal', () => { ...@@ -160,6 +162,10 @@ describe('UploadBlobModal', () => {
await waitForPromises(); await waitForPromises();
}); });
it('tracks the click_upload_modal_trigger event when opening the modal', () => {
expect(trackFileUploadEvent).toHaveBeenCalledWith('click_upload_modal_form_submit');
});
it('redirects to the uploaded file', () => { it('redirects to the uploaded file', () => {
expect(visitUrl).toHaveBeenCalled(); expect(visitUrl).toHaveBeenCalled();
}); });
...@@ -179,6 +185,10 @@ describe('UploadBlobModal', () => { ...@@ -179,6 +185,10 @@ describe('UploadBlobModal', () => {
await waitForPromises(); await waitForPromises();
}); });
it('does not track an event', () => {
expect(trackFileUploadEvent).not.toHaveBeenCalled();
});
it('creates a flash error', () => { it('creates a flash error', () => {
expect(createFlash).toHaveBeenCalledWith('Error uploading file. Please try again.'); expect(createFlash).toHaveBeenCalledWith('Error uploading file. Please try again.');
}); });
......
...@@ -563,6 +563,51 @@ RSpec.describe ProjectPresenter do ...@@ -563,6 +563,51 @@ RSpec.describe ProjectPresenter do
end end
end end
end end
describe '#upload_anchor_data' do
context 'with empty_repo_upload enabled' do
before do
stub_experiments(empty_repo_upload: :candidate)
end
context 'user can push to branch' do
before do
project.add_developer(user)
end
it 'returns upload_anchor_data' do
expect(presenter.upload_anchor_data).to have_attributes(
is_link: false,
label: a_string_including('Upload file'),
data: {
"can_push_code" => "true",
"original_branch" => "master",
"path" => "/#{project.full_path}/-/create/master",
"project_path" => project.path,
"target_branch" => "master"
}
)
end
end
context 'user cannot push to branch' do
it 'returns nil' do
expect(presenter.upload_anchor_data).to be_nil
end
end
end
context 'with empty_repo_upload disabled' do
before do
stub_experiments(empty_repo_upload: :control)
project.add_developer(user)
end
it 'returns nil' do
expect(presenter.upload_anchor_data).to be_nil
end
end
end
end end
describe '#statistics_buttons' do describe '#statistics_buttons' do
......
...@@ -97,18 +97,16 @@ end ...@@ -97,18 +97,16 @@ end
RSpec.shared_examples 'uploads and commits a new text file via "upload file" button' do RSpec.shared_examples 'uploads and commits a new text file via "upload file" button' do
it 'uploads and commits a new text file via "upload file" button', :js do it 'uploads and commits a new text file via "upload file" button', :js do
find('.js-upload-file-experiment-trigger', text: 'Upload file').click find('[data-testid="upload-file-button"]').click
drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt')) attach_file('upload_file', File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'), make_visible: true)
page.within('#modal-upload-blob') do page.within('#details-modal-upload-blob') do
fill_in(:commit_message, with: 'New commit message') fill_in(:commit_message, with: 'New commit message')
end end
click_button('Upload file') click_button('Upload file')
wait_for_requests
expect(page).to have_content('New commit message') expect(page).to have_content('New commit message')
expect(page).to have_content('Lorem ipsum dolor sit amet') expect(page).to have_content('Lorem ipsum dolor sit amet')
expect(page).to have_content('Sed ut perspiciatis unde omnis') expect(page).to have_content('Sed ut perspiciatis unde omnis')
......
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