Commit 969ab7fe authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch 'add-snowplow-events-to-agent-registration' into 'master'

Added Snowplow events to the Clusters page

See merge request gitlab-org/gitlab!75223
parents fec794ba bdfd2635
<script>
import { GlTabs, GlTab } from '@gitlab/ui';
import { CLUSTERS_TABS, MAX_CLUSTERS_LIST, MAX_LIST_COUNT, AGENT } from '../constants';
import Tracking from '~/tracking';
import {
CLUSTERS_TABS,
MAX_CLUSTERS_LIST,
MAX_LIST_COUNT,
AGENT,
EVENT_LABEL_TABS,
EVENT_ACTIONS_CHANGE,
} from '../constants';
import Agents from './agents.vue';
import InstallAgentModal from './install_agent_modal.vue';
import ClustersActions from './clusters_actions.vue';
import Clusters from './clusters.vue';
import ClustersViewAll from './clusters_view_all.vue';
const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_TABS });
export default {
components: {
GlTabs,
......@@ -18,6 +28,7 @@ export default {
InstallAgentModal,
},
CLUSTERS_TABS,
mixins: [trackingMixin],
props: {
defaultBranchName: {
default: '.noBranch',
......@@ -34,9 +45,12 @@ export default {
methods: {
onTabChange(tabName) {
this.selectedTabIndex = CLUSTERS_TABS.findIndex((tab) => tab.queryParamValue === tabName);
this.maxAgents = tabName === AGENT ? MAX_LIST_COUNT : MAX_CLUSTERS_LIST;
},
trackTabChange(tab) {
const tabName = CLUSTERS_TABS[tab].queryParamValue;
this.track(EVENT_ACTIONS_CHANGE, { property: tabName });
},
},
};
</script>
......@@ -47,6 +61,7 @@ export default {
sync-active-tab-with-query-params
nav-class="gl-flex-grow-1 gl-align-items-center"
lazy
@input="trackTabChange"
>
<gl-tab
v-for="(tab, idx) in $options.CLUSTERS_TABS"
......
......@@ -11,8 +11,19 @@ import {
import { helpPagePath } from '~/helpers/help_page_helper';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import Tracking from '~/tracking';
import { generateAgentRegistrationCommand } from '../clusters_util';
import { INSTALL_AGENT_MODAL_ID, I18N_AGENT_MODAL, KAS_DISABLED_ERROR } from '../constants';
import {
INSTALL_AGENT_MODAL_ID,
I18N_AGENT_MODAL,
KAS_DISABLED_ERROR,
EVENT_LABEL_MODAL,
EVENT_ACTIONS_OPEN,
EVENT_ACTIONS_SELECT,
EVENT_ACTIONS_CLICK,
MODAL_TYPE_EMPTY,
MODAL_TYPE_REGISTER,
} from '../constants';
import { addAgentToStore, addAgentConfigToStore } from '../graphql/cache_update';
import createAgent from '../graphql/mutations/create_agent.mutation.graphql';
import createAgentToken from '../graphql/mutations/create_agent_token.mutation.graphql';
......@@ -20,8 +31,13 @@ import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
import agentConfigurations from '../graphql/queries/agent_configurations.query.graphql';
import AvailableAgentsDropdown from './available_agents_dropdown.vue';
const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_MODAL });
export default {
modalId: INSTALL_AGENT_MODAL_ID,
EVENT_ACTIONS_OPEN,
EVENT_ACTIONS_CLICK,
EVENT_LABEL_MODAL,
components: {
AvailableAgentsDropdown,
ClipboardButton,
......@@ -34,6 +50,7 @@ export default {
GlModal,
GlSprintf,
},
mixins: [trackingMixin],
inject: ['projectPath', 'kasAddress', 'emptyStateImage'],
props: {
defaultBranchName: {
......@@ -81,7 +98,7 @@ export default {
return !this.registering && this.agentName !== null;
},
canCancel() {
return !this.registered && !this.registering && this.isRegisterModal;
return !this.registered && !this.registering && this.isAgentRegistrationModal;
},
agentRegistrationCommand() {
return generateAgentRegistrationCommand(this.agentToken, this.kasAddress);
......@@ -117,21 +134,24 @@ export default {
return `/${this.projectPath}`;
},
modalType() {
return !this.availableAgents?.length && !this.registered ? 'install' : 'register';
return !this.availableAgents?.length && !this.registered
? MODAL_TYPE_EMPTY
: MODAL_TYPE_REGISTER;
},
modalSize() {
return this.isInstallModal ? 'sm' : 'md';
return this.isEmptyStateModal ? 'sm' : 'md';
},
isInstallModal() {
return this.modalType === 'install';
isEmptyStateModal() {
return this.modalType === MODAL_TYPE_EMPTY;
},
isRegisterModal() {
return this.modalType === 'register';
isAgentRegistrationModal() {
return this.modalType === MODAL_TYPE_REGISTER;
},
},
methods: {
setAgentName(name) {
this.agentName = name;
this.track(EVENT_ACTIONS_SELECT);
},
closeModal() {
this.$refs.modal.hide();
......@@ -242,8 +262,9 @@ export default {
static
lazy
@hidden="resetModal"
@show="track($options.EVENT_ACTIONS_OPEN, { property: modalType })"
>
<template v-if="isRegisterModal">
<template v-if="isAgentRegistrationModal">
<template v-if="!registered">
<p>
<strong>{{ i18n.selectAgentTitle }}</strong>
......@@ -347,23 +368,40 @@ export default {
</template>
<template #modal-footer>
<gl-button v-if="canCancel" @click="closeModal">{{ i18n.cancel }} </gl-button>
<gl-button
v-if="canCancel"
:data-track-action="$options.EVENT_ACTIONS_CLICK"
:data-track-label="$options.EVENT_LABEL_MODAL"
data-track-property="cancel"
@click="closeModal"
>{{ i18n.cancel }}
</gl-button>
<gl-button v-if="registered" variant="confirm" category="primary" @click="closeModal"
<gl-button
v-if="registered"
variant="confirm"
category="primary"
:data-track-action="$options.EVENT_ACTIONS_CLICK"
:data-track-label="$options.EVENT_LABEL_MODAL"
data-track-property="close"
@click="closeModal"
>{{ i18n.close }}
</gl-button>
<gl-button
v-else-if="isRegisterModal"
v-else-if="isAgentRegistrationModal"
:disabled="!nextButtonDisabled"
variant="confirm"
category="primary"
:data-track-action="$options.EVENT_ACTIONS_CLICK"
:data-track-label="$options.EVENT_LABEL_MODAL"
data-track-property="register"
@click="registerAgent"
>{{ i18n.registerAgentButton }}
</gl-button>
<gl-button
v-if="isInstallModal"
v-if="isEmptyStateModal"
:href="repositoryPath"
variant="confirm"
category="secondary"
......@@ -371,7 +409,14 @@ export default {
>{{ i18n.secondaryButton }}
</gl-button>
<gl-button v-if="isInstallModal" variant="confirm" category="primary" @click="closeModal"
<gl-button
v-if="isEmptyStateModal"
variant="confirm"
category="primary"
:data-track-action="$options.EVENT_ACTIONS_CLICK"
:data-track-label="$options.EVENT_LABEL_MODAL"
data-track-property="done"
@click="closeModal"
>{{ i18n.done }}
</gl-button>
</template>
......
......@@ -65,7 +65,7 @@ export const STATUSES = {
};
export const I18N_AGENT_MODAL = {
register: {
agent_registration: {
registerAgentButton: s__('ClusterAgents|Register Agent'),
close: __('Close'),
cancel: __('Cancel'),
......@@ -104,7 +104,7 @@ export const I18N_AGENT_MODAL = {
registrationErrorTitle: __('Failed to register Agent'),
unknownError: s__('ClusterAgents|An unknown error occurred. Please try again.'),
},
install: {
empty_state: {
modalTitle: s__('ClusterAgents|Install new Agent'),
modalBody: s__(
'ClusterAgents|To install an Agent you should create an agent directory in the Repository first. We recommend that you add the Agent configuration to the directory before you start the installation process.',
......@@ -236,3 +236,13 @@ export const CLUSTERS_ACTIONS = {
export const AGENT = 'agent';
export const CERTIFICATE_BASED = 'certificate_based';
export const EVENT_LABEL_MODAL = 'agent_registration_modal';
export const EVENT_LABEL_TABS = 'kubernetes_section_tabs';
export const EVENT_ACTIONS_OPEN = 'open_modal';
export const EVENT_ACTIONS_SELECT = 'select_agent';
export const EVENT_ACTIONS_CLICK = 'click_button';
export const EVENT_ACTIONS_CHANGE = 'change_tab';
export const MODAL_TYPE_EMPTY = 'empty_state';
export const MODAL_TYPE_REGISTER = 'agent_registration';
import { GlTabs, GlTab } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import ClustersMainView from '~/clusters_list/components/clusters_main_view.vue';
import InstallAgentModal from '~/clusters_list/components/install_agent_modal.vue';
import {
......@@ -8,12 +9,15 @@ import {
CLUSTERS_TABS,
MAX_CLUSTERS_LIST,
MAX_LIST_COUNT,
EVENT_LABEL_TABS,
EVENT_ACTIONS_CHANGE,
} from '~/clusters_list/constants';
const defaultBranchName = 'default-branch';
describe('ClustersMainViewComponent', () => {
let wrapper;
let trackingSpy;
const propsData = {
defaultBranchName,
......@@ -23,6 +27,7 @@ describe('ClustersMainViewComponent', () => {
wrapper = shallowMountExtended(ClustersMainView, {
propsData,
});
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
afterEach(() => {
......@@ -71,6 +76,7 @@ describe('ClustersMainViewComponent', () => {
beforeEach(() => {
findComponent().vm.$emit('changeTab', AGENT);
});
it('changes the tab', () => {
expect(findTabs().attributes('value')).toBe('1');
});
......@@ -78,5 +84,13 @@ describe('ClustersMainViewComponent', () => {
it('passes correct max-agents param to the modal', () => {
expect(findModal().props('maxAgents')).toBe(MAX_LIST_COUNT);
});
it('sends the correct tracking event', () => {
findTabs().vm.$emit('input', 1);
expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTIONS_CHANGE, {
label: EVENT_LABEL_TABS,
property: AGENT,
});
});
});
});
......@@ -2,9 +2,18 @@ import { GlAlert, GlButton, GlFormInputGroup } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import AvailableAgentsDropdown from '~/clusters_list/components/available_agents_dropdown.vue';
import InstallAgentModal from '~/clusters_list/components/install_agent_modal.vue';
import { I18N_AGENT_MODAL, MAX_LIST_COUNT } from '~/clusters_list/constants';
import {
I18N_AGENT_MODAL,
MAX_LIST_COUNT,
EVENT_LABEL_MODAL,
EVENT_ACTIONS_OPEN,
EVENT_ACTIONS_SELECT,
MODAL_TYPE_EMPTY,
MODAL_TYPE_REGISTER,
} from '~/clusters_list/constants';
import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
import getAgentConfigurations from '~/clusters_list/graphql/queries/agent_configurations.query.graphql';
import createAgentMutation from '~/clusters_list/graphql/mutations/create_agent.mutation.graphql';
......@@ -34,6 +43,7 @@ const maxAgents = MAX_LIST_COUNT;
describe('InstallAgentModal', () => {
let wrapper;
let apolloProvider;
let trackingSpy;
const configurations = [{ agentName: 'agent-name' }];
const apolloQueryResponse = {
......@@ -56,7 +66,7 @@ describe('InstallAgentModal', () => {
const findActionButton = () => findButtonByVariant('confirm');
const findCancelButton = () => findButtonByVariant('default');
const findSecondaryButton = () => wrapper.findByTestId('agent-secondary-button');
const findImage = () => wrapper.findByRole('img', { alt: I18N_AGENT_MODAL.install.altText });
const findImage = () => wrapper.findByRole('img', { alt: I18N_AGENT_MODAL.empty_state.altText });
const expectDisabledAttribute = (element, disabled) => {
if (disabled) {
......@@ -121,6 +131,7 @@ describe('InstallAgentModal', () => {
[getAgentConfigurations, jest.fn().mockResolvedValue(apolloQueryResponse)],
]);
createWrapper();
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
afterEach(() => {
......@@ -129,7 +140,7 @@ describe('InstallAgentModal', () => {
});
describe('when agent configurations are present', () => {
const i18n = I18N_AGENT_MODAL.register;
const i18n = I18N_AGENT_MODAL.agent_registration;
describe('initial state', () => {
it('renders the dropdown for available agents', () => {
......@@ -150,6 +161,14 @@ describe('InstallAgentModal', () => {
expect(findActionButton().text()).toBe(i18n.registerAgentButton);
expectDisabledAttribute(findActionButton(), true);
});
it('sends the event with the modalType', () => {
findModal().vm.$emit('show');
expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTIONS_OPEN, {
label: EVENT_LABEL_MODAL,
property: MODAL_TYPE_REGISTER,
});
});
});
describe('an agent is selected', () => {
......@@ -161,6 +180,12 @@ describe('InstallAgentModal', () => {
expect(findActionButton().isVisible()).toBe(true);
expectDisabledAttribute(findActionButton(), false);
});
it('sends the correct tracking event', () => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTIONS_SELECT, {
label: EVENT_LABEL_MODAL,
});
});
});
describe('registering an agent', () => {
......@@ -247,7 +272,7 @@ describe('InstallAgentModal', () => {
});
describe('when there are no agent configurations present', () => {
const i18n = I18N_AGENT_MODAL.install;
const i18n = I18N_AGENT_MODAL.empty_state;
const apolloQueryEmptyResponse = {
data: {
project: {
......@@ -272,5 +297,13 @@ describe('InstallAgentModal', () => {
expect(findSecondaryButton().isVisible()).toBe(true);
expect(findSecondaryButton().text()).toBe(i18n.secondaryButton);
});
it('sends the event with the modalType', () => {
findModal().vm.$emit('show');
expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTIONS_OPEN, {
label: EVENT_LABEL_MODAL,
property: MODAL_TYPE_EMPTY,
});
});
});
});
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