Skip to content

Commit 972325b

Browse files
mfranciscDevtools
andauthored
feat(sandbox): add init eddl attributes (#1281)
* add eddl support --------- Co-authored-by: Devtools <devtools@redhat.com>
1 parent 391dbd5 commit 972325b

16 files changed

Lines changed: 567 additions & 17 deletions

workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleLaunchInfoModal.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { Visibility, VisibilityOff } from '@mui/icons-material';
3838
import { Link } from '@backstage/core-components';
3939
import { useSandboxContext } from '../../hooks/useSandboxContext';
4040
import { AnsibleStatus } from '../../utils/aap-utils';
41+
import { pushCtaEvent } from '../../utils/eddl-utils';
42+
import { Intcmp } from '../../hooks/useProductURLs';
4143

4244
// Import the logos
4345
import AnsibleLogo from '../../assets/logos/ansible.svg';
@@ -53,13 +55,26 @@ export const AnsibleLaunchInfoModal: React.FC<AnsibleLaunchInfoModalProps> = ({
5355
setOpen,
5456
}) => {
5557
const theme = useTheme();
58+
5659
const {
5760
ansibleUILink,
5861
ansibleUIUser,
5962
ansibleUIPassword,
6063
ansibleError,
6164
ansibleStatus,
6265
} = useSandboxContext();
66+
67+
// Handle CTA click for analytics
68+
const handleAnsibleCtaClick = () => {
69+
if (ansibleUILink) {
70+
pushCtaEvent(
71+
'Get Started - Ansible',
72+
'Catalog',
73+
ansibleUILink,
74+
Intcmp.AAP,
75+
);
76+
}
77+
};
6378
const [showPassword, setShowPassword] = useState<boolean>(false);
6479

6580
const handleClose = () => {
@@ -357,7 +372,13 @@ export const AnsibleLaunchInfoModal: React.FC<AnsibleLaunchInfoModalProps> = ({
357372
)}
358373
</DialogContent>
359374
<DialogActions sx={{ justifyContent: 'flex-start', pl: 3, pb: 3 }}>
360-
<Link to={ansibleUILink ?? ''} underline="none" target="_blank">
375+
<Link
376+
to={ansibleUILink || ''}
377+
underline="none"
378+
target="_blank"
379+
onClick={handleAnsibleCtaClick}
380+
data-analytics-track-by-analytics-manager="false"
381+
>
361382
<Button
362383
variant="contained"
363384
color="primary"

workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/PhoneNumberStep.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import IconButton from '@mui/material/IconButton';
3232
import CloseIcon from '@mui/icons-material/Close';
3333

3434
import CircularProgress from '@mui/material/CircularProgress';
35+
import { getEddlDataAttributes } from '../../../utils/eddl-utils';
3536

3637
const FLAG_FETCH_URL =
3738
'https://catamphetamine.github.io/country-flag-icons/3x2';
@@ -64,6 +65,14 @@ export const PhoneNumberStep: React.FC<PhoneNumberFormProps> = ({
6465
error,
6566
}) => {
6667
const theme = useTheme();
68+
const sendCodeEddlAttributes = getEddlDataAttributes(
69+
'Send Code',
70+
'Verification',
71+
);
72+
const cancelEddlAttributes = getEddlDataAttributes(
73+
'Cancel Verification',
74+
'Verification',
75+
);
6776

6877
const PhoneInputField = forwardRef(function PhoneInputField(
6978
props: TextFieldProps,
@@ -210,6 +219,7 @@ export const PhoneNumberStep: React.FC<PhoneNumberFormProps> = ({
210219
endIcon={
211220
loading && <CircularProgress size={20} sx={{ color: '#AFAFAF' }} />
212221
}
222+
{...sendCodeEddlAttributes}
213223
>
214224
Send code
215225
</Button>
@@ -224,6 +234,7 @@ export const PhoneNumberStep: React.FC<PhoneNumberFormProps> = ({
224234
borderColor: '#1976d2',
225235
},
226236
}}
237+
{...cancelEddlAttributes}
227238
>
228239
Cancel
229240
</Button>

workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/VerificationCodeStep.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { useSandboxContext } from '../../../hooks/useSandboxContext';
3939
import { Country, getCountryCallingCode } from 'react-phone-number-input';
4040
import { useApi } from '@backstage/core-plugin-api';
4141
import { registerApiRef } from '../../../api';
42+
import { getEddlDataAttributes } from '../../../utils/eddl-utils';
4243

4344
type VerificationCodeProps = {
4445
id: Product;
@@ -68,6 +69,18 @@ export const VerificationCodeStep: React.FC<VerificationCodeProps> = ({
6869
setLoading,
6970
}) => {
7071
const theme = useTheme();
72+
const startTrialEddlAttributes = getEddlDataAttributes(
73+
'Start Trial',
74+
'Verification',
75+
);
76+
const resendCodeEddlAttributes = getEddlDataAttributes(
77+
'Resend Code',
78+
'Verification',
79+
);
80+
const cancelVerificationEddlAttributes = getEddlDataAttributes(
81+
'Cancel Verification',
82+
'Verification',
83+
);
7184

7285
const inputRefs = useRef<any>([]);
7386
const { refetchUserData, handleAAPInstance } = useSandboxContext();
@@ -287,6 +300,7 @@ export const VerificationCodeStep: React.FC<VerificationCodeProps> = ({
287300
handleResendCode();
288301
inputRefs.current[0]?.focus();
289302
}}
303+
{...resendCodeEddlAttributes}
290304
>
291305
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
292306
{codeResent ? (
@@ -322,6 +336,7 @@ export const VerificationCodeStep: React.FC<VerificationCodeProps> = ({
322336
endIcon={
323337
loading && <CircularProgress size={20} sx={{ color: '#AFAFAF' }} />
324338
}
339+
{...startTrialEddlAttributes}
325340
>
326341
Start trial
327342
</Button>
@@ -336,6 +351,7 @@ export const VerificationCodeStep: React.FC<VerificationCodeProps> = ({
336351
borderColor: '#1976d2',
337352
},
338353
}}
354+
{...cancelVerificationEddlAttributes}
339355
>
340356
Cancel
341357
</Button>

workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/PhoneNumberStep.test.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,44 @@ describe('PhoneNumberStep', () => {
164164
const inputValue = inputElement?.value || '';
165165
expect(inputValue).toBe('+1 737 307 2270');
166166
});
167+
168+
describe('EDDL data attributes', () => {
169+
test('should have correct EDDL data attributes on Send Code button', () => {
170+
renderComponent(phoneNumber);
171+
172+
const sendCodeButton = screen.getByRole('button', { name: /Send code/i });
173+
174+
expect(sendCodeButton).toHaveAttribute(
175+
'data-analytics-category',
176+
'Developer Sandbox|Verification',
177+
);
178+
expect(sendCodeButton).toHaveAttribute(
179+
'data-analytics-text',
180+
'Send Code',
181+
);
182+
expect(sendCodeButton).toHaveAttribute(
183+
'data-analytics-region',
184+
'sandbox-verification',
185+
);
186+
});
187+
188+
test('should have correct EDDL data attributes on Cancel button', () => {
189+
renderComponent(phoneNumber);
190+
191+
const cancelButton = screen.getByRole('button', { name: /Cancel/i });
192+
193+
expect(cancelButton).toHaveAttribute(
194+
'data-analytics-category',
195+
'Developer Sandbox|Verification',
196+
);
197+
expect(cancelButton).toHaveAttribute(
198+
'data-analytics-text',
199+
'Cancel Verification',
200+
);
201+
expect(cancelButton).toHaveAttribute(
202+
'data-analytics-region',
203+
'sandbox-verification',
204+
);
205+
});
206+
});
167207
});

workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/VerificationCodeStep.test.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ describe('VerificationCodeStep', () => {
158158

159159
expect(mockRefetchUserData).toHaveBeenCalled();
160160
expect(mockOpen).toHaveBeenCalledWith(
161-
'https://sandboxcluster.test//k8s/cluster/projects/bob-2-dev',
161+
`https://sandboxcluster.test//k8s/cluster/projects/bob-2-dev`,
162162
'_blank',
163163
); // check it opens the url after signup
164164
mockOpen.mockRestore();
@@ -360,4 +360,78 @@ describe('VerificationCodeStep', () => {
360360
expect(mockRefetchUserData).toHaveBeenCalled();
361361
expect(mockHandleAAPInstance).not.toHaveBeenCalled(); // verify handleAAP is not called
362362
});
363+
364+
describe('EDDL data attributes', () => {
365+
beforeEach(() => {
366+
const mockRefetchUserData = jest.fn();
367+
const mockHandleAAPInstance = jest.fn();
368+
const mockUseSandboxContext = useSandboxContext as jest.MockedFunction<
369+
typeof useSandboxContext
370+
>;
371+
mockUseSandboxContext.mockReturnValue({
372+
refetchUserData: mockRefetchUserData,
373+
refetchAAP: mockRefetchAAP,
374+
handleAAPInstance: mockHandleAAPInstance,
375+
} as any);
376+
});
377+
378+
test('should have correct EDDL data attributes on Start trial button', () => {
379+
renderComponent();
380+
381+
const startTrialButton = screen.getByRole('button', {
382+
name: /Start trial/i,
383+
});
384+
385+
expect(startTrialButton).toHaveAttribute(
386+
'data-analytics-category',
387+
'Developer Sandbox|Verification',
388+
);
389+
expect(startTrialButton).toHaveAttribute(
390+
'data-analytics-text',
391+
'Start Trial',
392+
);
393+
expect(startTrialButton).toHaveAttribute(
394+
'data-analytics-region',
395+
'sandbox-verification',
396+
);
397+
});
398+
399+
test('should have correct EDDL data attributes on Cancel button', () => {
400+
renderComponent();
401+
402+
const cancelButton = screen.getByRole('button', { name: /Cancel/i });
403+
404+
expect(cancelButton).toHaveAttribute(
405+
'data-analytics-category',
406+
'Developer Sandbox|Verification',
407+
);
408+
expect(cancelButton).toHaveAttribute(
409+
'data-analytics-text',
410+
'Cancel Verification',
411+
);
412+
expect(cancelButton).toHaveAttribute(
413+
'data-analytics-region',
414+
'sandbox-verification',
415+
);
416+
});
417+
418+
test('should have correct EDDL data attributes on Resend code link', () => {
419+
renderComponent();
420+
421+
const resendCodeLink = screen.getByTestId('resend-code-link');
422+
423+
expect(resendCodeLink).toHaveAttribute(
424+
'data-analytics-category',
425+
'Developer Sandbox|Verification',
426+
);
427+
expect(resendCodeLink).toHaveAttribute(
428+
'data-analytics-text',
429+
'Resend Code',
430+
);
431+
expect(resendCodeLink).toHaveAttribute(
432+
'data-analytics-region',
433+
'sandbox-verification',
434+
);
435+
});
436+
});
363437
});

workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleLaunchInfoModal.test.tsx

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ import { AnsibleLaunchInfoModal } from '../AnsibleLaunchInfoModal';
2121
import { useSandboxContext } from '../../../hooks/useSandboxContext';
2222
import { AnsibleStatus } from '../../../utils/aap-utils';
2323
import { wrapInTestApp } from '@backstage/test-utils';
24+
import { Intcmp } from '../../../hooks/useProductURLs';
25+
import * as eddlUtils from '../../../utils/eddl-utils';
2426

2527
// Mock the useSandboxContext hook
2628
jest.mock('../../../hooks/useSandboxContext');
2729

30+
// Mock the EDDL utils
31+
jest.mock('../../../utils/eddl-utils');
32+
2833
// Mock clipboard API
2934
Object.defineProperty(window.navigator, 'clipboard', {
3035
value: {
@@ -44,9 +49,12 @@ describe('AnsibleLaunchInfoModal', () => {
4449
const mockUseSandboxContext = useSandboxContext as jest.MockedFunction<
4550
typeof useSandboxContext
4651
>;
52+
const mockPushCtaEvent = jest.spyOn(eddlUtils, 'pushCtaEvent');
4753

4854
beforeEach(() => {
4955
jest.clearAllMocks();
56+
// Setup window.appEventData for tests
57+
(global as any).window = { appEventData: [] };
5058
});
5159

5260
const renderModal = (contextOverrides = {}) => {
@@ -243,7 +251,7 @@ describe('AnsibleLaunchInfoModal', () => {
243251

244252
// The button should be wrapped in a Link component that targets the ansible URL
245253
const linkElement = getStartedButton.closest('a');
246-
expect(linkElement).toHaveAttribute('href', 'https://ansible.example.com');
254+
expect(linkElement).toHaveAttribute('href', `https://ansible.example.com`);
247255
expect(linkElement).toHaveAttribute('target', '_blank');
248256
});
249257

@@ -260,4 +268,59 @@ describe('AnsibleLaunchInfoModal', () => {
260268
),
261269
).toBeInTheDocument();
262270
});
271+
272+
describe('CTA Event Pushing', () => {
273+
it('should disable automatic tracking and push CTA event when Get started link is clicked', () => {
274+
renderModal();
275+
276+
const getStartedButton = screen.getByRole('button', {
277+
name: /Get started/i,
278+
});
279+
280+
// The button should be wrapped in a Link component
281+
const linkElement = getStartedButton.closest('a');
282+
283+
// Should have automatic tracking disabled
284+
expect(linkElement).toHaveAttribute(
285+
'data-analytics-track-by-analytics-manager',
286+
'false',
287+
);
288+
289+
// Click the link
290+
fireEvent.click(linkElement!);
291+
292+
// Should push CTA event with correct parameters
293+
expect(mockPushCtaEvent).toHaveBeenCalledWith(
294+
'Get Started - Ansible',
295+
'Catalog',
296+
'https://ansible.example.com',
297+
Intcmp.AAP,
298+
);
299+
});
300+
301+
it('should not push CTA event if ansibleUILink is not available', () => {
302+
// Clear all mocks to ensure clean state
303+
jest.clearAllMocks();
304+
305+
const contextOverrides = {
306+
ansibleStatus: AnsibleStatus.READY,
307+
ansibleUILink: undefined, // No link available
308+
ansibleUIUser: 'admin',
309+
ansibleUIPassword: 'password123',
310+
ansibleError: null,
311+
};
312+
313+
renderModal(contextOverrides);
314+
315+
const getStartedButton = screen.getByRole('button', {
316+
name: /Get started/i,
317+
});
318+
319+
const linkElement = getStartedButton.closest('a');
320+
fireEvent.click(linkElement!);
321+
322+
// Should not push event when link is not available
323+
expect(mockPushCtaEvent).not.toHaveBeenCalled();
324+
});
325+
});
263326
});

0 commit comments

Comments
 (0)