Commit eaa438c0 authored by Denys Mishunov's avatar Denys Mishunov

Merge branch 'design-tracking-create-update' into 'master'

Track design create and update

See merge request gitlab-org/gitlab!44129
parents 05ef2590 e0b8384e
...@@ -3,6 +3,7 @@ import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui'; ...@@ -3,6 +3,7 @@ import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
import VueDraggable from 'vuedraggable'; import VueDraggable from 'vuedraggable';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { getFilename } from '~/lib/utils/file_upload';
import UploadButton from '../components/upload/button.vue'; import UploadButton from '../components/upload/button.vue';
import DeleteButton from '../components/delete_button.vue'; import DeleteButton from '../components/delete_button.vue';
import Design from '../components/list/item.vue'; import Design from '../components/list/item.vue';
...@@ -31,7 +32,7 @@ import { ...@@ -31,7 +32,7 @@ import {
isValidDesignFile, isValidDesignFile,
moveDesignOptimisticResponse, moveDesignOptimisticResponse,
} from '../utils/design_management_utils'; } from '../utils/design_management_utils';
import { getFilename } from '~/lib/utils/file_upload'; import { trackDesignCreate, trackDesignUpdate } from '../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../router/constants'; import { DESIGNS_ROUTE_NAME } from '../router/constants';
const MAXIMUM_FILE_UPLOAD_LIMIT = 10; const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
...@@ -186,6 +187,7 @@ export default { ...@@ -186,6 +187,7 @@ export default {
updateStoreAfterUploadDesign(store, designManagementUpload, this.projectQueryBody); updateStoreAfterUploadDesign(store, designManagementUpload, this.projectQueryBody);
}, },
onUploadDesignDone(res) { onUploadDesignDone(res) {
// display any warnings, if necessary
const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || []; const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || [];
const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles); const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles);
if (skippedWarningMessage) { if (skippedWarningMessage) {
...@@ -196,7 +198,19 @@ export default { ...@@ -196,7 +198,19 @@ export default {
if (!this.isLatestVersion) { if (!this.isLatestVersion) {
this.$router.push({ name: DESIGNS_ROUTE_NAME }); this.$router.push({ name: DESIGNS_ROUTE_NAME });
} }
// reset state
this.resetFilesToBeSaved(); this.resetFilesToBeSaved();
this.trackUploadDesign(res);
},
trackUploadDesign(res) {
(res?.data?.designManagementUpload?.designs || []).forEach(design => {
if (design.event === 'CREATION') {
trackDesignCreate();
} else if (design.event === 'MODIFICATION') {
trackDesignUpdate();
}
});
}, },
onUploadDesignError() { onUploadDesignError() {
this.resetFilesToBeSaved(); this.resetFilesToBeSaved();
......
import Tracking from '~/tracking'; import Tracking from '~/tracking';
// Tracking Constants // Tracking Constants
const DESIGN_TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0'; const DESIGN_TRACKING_CONTEXT_SCHEMAS = {
const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design'; VIEW_DESIGN_SCHEMA: 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0',
const DESIGN_TRACKING_EVENT_NAME = 'view_design'; };
const DESIGN_TRACKING_EVENTS = {
VIEW_DESIGN: 'view_design',
CREATE_DESIGN: 'create_design',
UPDATE_DESIGN: 'update_design',
};
export const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design';
export function trackDesignDetailView( export function trackDesignDetailView(
referer = '', referer = '',
...@@ -11,10 +18,11 @@ export function trackDesignDetailView( ...@@ -11,10 +18,11 @@ export function trackDesignDetailView(
designVersion = 1, designVersion = 1,
latestVersion = false, latestVersion = false,
) { ) {
Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENT_NAME, { const eventName = DESIGN_TRACKING_EVENTS.VIEW_DESIGN;
label: DESIGN_TRACKING_EVENT_NAME, Tracking.event(DESIGN_TRACKING_PAGE_NAME, eventName, {
label: eventName,
context: { context: {
schema: DESIGN_TRACKING_CONTEXT_SCHEMA, schema: DESIGN_TRACKING_CONTEXT_SCHEMAS.VIEW_DESIGN_SCHEMA,
data: { data: {
'design-version-number': designVersion, 'design-version-number': designVersion,
'design-is-current-version': latestVersion, 'design-is-current-version': latestVersion,
...@@ -24,3 +32,11 @@ export function trackDesignDetailView( ...@@ -24,3 +32,11 @@ export function trackDesignDetailView(
}, },
}); });
} }
export function trackDesignCreate() {
return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.CREATE_DESIGN);
}
export function trackDesignUpdate() {
return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.UPDATE_DESIGN);
}
---
title: Add product analytics for design created and modified events
merge_request: 44129
author:
type: added
...@@ -51,6 +51,34 @@ export const designListQueryResponse = { ...@@ -51,6 +51,34 @@ export const designListQueryResponse = {
}, },
}; };
export const designUploadMutationCreatedResponse = {
data: {
designManagementUpload: {
designs: [
{
id: '1',
event: 'CREATION',
filename: 'fox_1.jpg',
},
],
},
},
};
export const designUploadMutationUpdatedResponse = {
data: {
designManagementUpload: {
designs: [
{
id: '1',
event: 'MODIFICATION',
filename: 'fox_1.jpg',
},
],
},
},
};
export const permissionsQueryResponse = { export const permissionsQueryResponse = {
data: { data: {
project: { project: {
......
...@@ -4,6 +4,7 @@ import VueDraggable from 'vuedraggable'; ...@@ -4,6 +4,7 @@ import VueDraggable from 'vuedraggable';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState } from '@gitlab/ui';
import createMockApollo from 'jest/helpers/mock_apollo_helper'; import createMockApollo from 'jest/helpers/mock_apollo_helper';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import Index from '~/design_management/pages/index.vue'; import Index from '~/design_management/pages/index.vue';
import uploadDesignQuery from '~/design_management/graphql/mutations/upload_design.mutation.graphql'; import uploadDesignQuery from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
import DesignDestroyer from '~/design_management/components/design_destroyer.vue'; import DesignDestroyer from '~/design_management/components/design_destroyer.vue';
...@@ -21,6 +22,8 @@ import * as utils from '~/design_management/utils/design_management_utils'; ...@@ -21,6 +22,8 @@ import * as utils from '~/design_management/utils/design_management_utils';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants'; import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
import { import {
designListQueryResponse, designListQueryResponse,
designUploadMutationCreatedResponse,
designUploadMutationUpdatedResponse,
permissionsQueryResponse, permissionsQueryResponse,
moveDesignMutationResponse, moveDesignMutationResponse,
reorderedDesigns, reorderedDesigns,
...@@ -29,6 +32,7 @@ import { ...@@ -29,6 +32,7 @@ import {
import getDesignListQuery from '~/design_management/graphql/queries/get_design_list.query.graphql'; import getDesignListQuery from '~/design_management/graphql/queries/get_design_list.query.graphql';
import permissionsQuery from '~/design_management/graphql/queries/design_permissions.query.graphql'; import permissionsQuery from '~/design_management/graphql/queries/design_permissions.query.graphql';
import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql'; import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql';
import { DESIGN_TRACKING_PAGE_NAME } from '~/design_management/utils/tracking';
jest.mock('~/flash.js'); jest.mock('~/flash.js');
const mockPageEl = { const mockPageEl = {
...@@ -370,7 +374,7 @@ describe('Design management index page', () => { ...@@ -370,7 +374,7 @@ describe('Design management index page', () => {
createComponent({ stubs: { GlEmptyState } }); createComponent({ stubs: { GlEmptyState } });
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] }); wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
wrapper.vm.onUploadDesignDone(); wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.filesToBeSaved).toEqual([]); expect(wrapper.vm.filesToBeSaved).toEqual([]);
expect(wrapper.vm.isSaving).toBeFalsy(); expect(wrapper.vm.isSaving).toBeFalsy();
...@@ -482,6 +486,34 @@ describe('Design management index page', () => { ...@@ -482,6 +486,34 @@ describe('Design management index page', () => {
expect(createFlash).toHaveBeenCalledWith(message); expect(createFlash).toHaveBeenCalledWith(message);
}); });
}); });
describe('tracking', () => {
let trackingSpy;
beforeEach(() => {
trackingSpy = mockTracking('_category_', undefined, jest.spyOn);
createComponent({ stubs: { GlEmptyState } });
});
afterEach(() => {
unmockTracking();
});
it('tracks design creation', () => {
wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
expect(trackingSpy).toHaveBeenCalledTimes(1);
expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'create_design');
});
it('tracks design modification', () => {
wrapper.vm.onUploadDesignDone(designUploadMutationUpdatedResponse);
expect(trackingSpy).toHaveBeenCalledTimes(1);
expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'update_design');
});
});
}); });
describe('on latest version when has designs', () => { describe('on latest version when has designs', () => {
......
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