chore: aws integration UI events (#7172)

* chore: add constants for AWS Integration UI event names

* chore: log event for account viewed and account connection attempt started

* chore: log telemetry event on successful account connection

* chore: log telemetry event when an account connection attempt times out

* chore: log telemetry event on redirecting to AWS for account connection

* chore: log telemetry event on opening account settings

* chore: log telemetry event on saving account settings

* chore: log telemetry event on removing account

* chore: log telemetry event on viewing details of a service

* chore: log telemetry event on opening service settings

* chore: log telemetry event on saving service settings

* chore: some cleanup

* chore: address PR comment

* chore: minor cleanup
This commit is contained in:
Raj Kamal Singh 2025-02-26 23:14:00 +05:30 committed by GitHub
parent ae73033826
commit a3bc290500
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 85 additions and 9 deletions

View File

@ -3,6 +3,7 @@ import './AccountActions.style.scss';
import { Color } from '@signozhq/design-tokens'; import { Color } from '@signozhq/design-tokens';
import { Button, Select, Skeleton } from 'antd'; import { Button, Select, Skeleton } from 'antd';
import { SelectProps } from 'antd/lib'; import { SelectProps } from 'antd/lib';
import logEvent from 'api/common/logEvent';
import { useAwsAccounts } from 'hooks/integration/aws/useAwsAccounts'; import { useAwsAccounts } from 'hooks/integration/aws/useAwsAccounts';
import useUrlQuery from 'hooks/useUrlQuery'; import useUrlQuery from 'hooks/useUrlQuery';
import { Check, ChevronDown } from 'lucide-react'; import { Check, ChevronDown } from 'lucide-react';
@ -167,9 +168,31 @@ function AccountActions(): JSX.Element {
}, [initialAccount]); }, [initialAccount]);
const [isIntegrationModalOpen, setIsIntegrationModalOpen] = useState(false); const [isIntegrationModalOpen, setIsIntegrationModalOpen] = useState(false);
const startAccountConnectionAttempt = (): void => {
setIsIntegrationModalOpen(true);
logEvent('AWS Integration: Account connection attempt started', {});
};
const [isAccountSettingsModalOpen, setIsAccountSettingsModalOpen] = useState( const [isAccountSettingsModalOpen, setIsAccountSettingsModalOpen] = useState(
false, false,
); );
const openAccountSettings = (): void => {
setIsAccountSettingsModalOpen(true);
logEvent('AWS Integration: Account settings viewed', {
cloudAccountId: activeAccount?.cloud_account_id,
});
};
// log telemetry event when an account is viewed.
useEffect(() => {
if (activeAccount) {
logEvent('AWS Integration: Account viewed', {
cloudAccountId: activeAccount?.cloud_account_id,
status: activeAccount?.status,
enabledRegions: activeAccount?.config?.regions,
});
}
}, [activeAccount]);
const selectOptions: SelectProps['options'] = useMemo( const selectOptions: SelectProps['options'] = useMemo(
() => () =>
@ -196,8 +219,8 @@ function AccountActions(): JSX.Element {
navigate({ search: urlQuery.toString() }); navigate({ search: urlQuery.toString() });
} }
}} }}
onIntegrationModalOpen={(): void => setIsIntegrationModalOpen(true)} onIntegrationModalOpen={startAccountConnectionAttempt}
onAccountSettingsModalOpen={(): void => setIsAccountSettingsModalOpen(true)} onAccountSettingsModalOpen={openAccountSettings}
/> />
{isIntegrationModalOpen && ( {isIntegrationModalOpen && (

View File

@ -12,6 +12,7 @@ import history from 'lib/history';
import { Dispatch, SetStateAction, useCallback } from 'react'; import { Dispatch, SetStateAction, useCallback } from 'react';
import { useQueryClient } from 'react-query'; import { useQueryClient } from 'react-query';
import logEvent from '../../../../api/common/logEvent';
import { CloudAccount } from '../../ServicesSection/types'; import { CloudAccount } from '../../ServicesSection/types';
import { RegionSelector } from './RegionSelector'; import { RegionSelector } from './RegionSelector';
import RemoveIntegrationAccount from './RemoveIntegrationAccount'; import RemoveIntegrationAccount from './RemoveIntegrationAccount';
@ -50,6 +51,11 @@ function AccountSettingsModal({
urlQuery.delete('cloudAccountId'); urlQuery.delete('cloudAccountId');
handleClose(); handleClose();
history.replace({ search: urlQuery.toString() }); history.replace({ search: urlQuery.toString() });
logEvent('AWS Integration: Account removed', {
id: account?.id,
cloudAccountId: account?.cloud_account_id,
});
}; };
const renderRegionSelector = useCallback(() => { const renderRegionSelector = useCallback(() => {

View File

@ -106,7 +106,7 @@ function CloudAccountSetupModal({
// Handle success state first // Handle success state first
if (modalState === ModalStateEnum.SUCCESS) { if (modalState === ModalStateEnum.SUCCESS) {
return { return {
title: 'AWS Webservice Integration', title: 'AWS Integration',
okText: ( okText: (
<div className="cloud-account-setup-success-view__footer-button"> <div className="cloud-account-setup-success-view__footer-button">
Continue Continue

View File

@ -5,6 +5,7 @@ import { useRef } from 'react';
import { AccountStatusResponse } from 'types/api/integrations/aws'; import { AccountStatusResponse } from 'types/api/integrations/aws';
import { regions } from 'utils/regions'; import { regions } from 'utils/regions';
import logEvent from '../../../../api/common/logEvent';
import { ModalStateEnum, RegionFormProps } from '../types'; import { ModalStateEnum, RegionFormProps } from '../types';
import AlertMessage from './AlertMessage'; import AlertMessage from './AlertMessage';
import { import {
@ -41,7 +42,7 @@ export function RegionForm({
}: RegionFormProps): JSX.Element { }: RegionFormProps): JSX.Element {
const startTimeRef = useRef(Date.now()); const startTimeRef = useRef(Date.now());
const refetchInterval = 10 * 1000; const refetchInterval = 10 * 1000;
const errorTimeout = 5 * 60 * 1000; const errorTimeout = 10 * 60 * 1000;
const { isLoading: isAccountStatusLoading } = useAccountStatus(accountId, { const { isLoading: isAccountStatusLoading } = useAccountStatus(accountId, {
refetchInterval, refetchInterval,
@ -49,9 +50,15 @@ export function RegionForm({
onSuccess: (data: AccountStatusResponse) => { onSuccess: (data: AccountStatusResponse) => {
if (data.data.status.integration.last_heartbeat_ts_ms !== null) { if (data.data.status.integration.last_heartbeat_ts_ms !== null) {
setModalState(ModalStateEnum.SUCCESS); setModalState(ModalStateEnum.SUCCESS);
logEvent('AWS Integration: Account connected', {
cloudAccountId: data?.data?.cloud_account_id,
status: data?.data?.status,
});
} else if (Date.now() - startTimeRef.current >= errorTimeout) { } else if (Date.now() - startTimeRef.current >= errorTimeout) {
// 5 minutes in milliseconds
setModalState(ModalStateEnum.ERROR); setModalState(ModalStateEnum.ERROR);
logEvent('AWS Integration: Account connection attempt timed out', {
id: accountId,
});
} }
}, },
onError: () => { onError: () => {

View File

@ -11,6 +11,8 @@ import { useUpdateServiceConfig } from 'hooks/integration/aws/useUpdateServiceCo
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useQueryClient } from 'react-query'; import { useQueryClient } from 'react-query';
import logEvent from '../../../api/common/logEvent';
interface IConfigureServiceModalProps { interface IConfigureServiceModalProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
@ -82,6 +84,13 @@ function ConfigureServiceModal({
serviceId, serviceId,
]); ]);
onClose(); onClose();
logEvent('AWS Integration: Service settings saved', {
cloudAccountId,
serviceId,
logsEnabled: values?.logs,
metricsEnabled: values?.metrics,
});
}, },
onError: (error) => { onError: (error) => {
console.error('Failed to update service config:', error); console.error('Failed to update service config:', error);

View File

@ -7,8 +7,9 @@ import { IServiceStatus } from 'container/CloudIntegrationPage/ServicesSection/t
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useServiceDetails } from 'hooks/integration/aws/useServiceDetails'; import { useServiceDetails } from 'hooks/integration/aws/useServiceDetails';
import useUrlQuery from 'hooks/useUrlQuery'; import useUrlQuery from 'hooks/useUrlQuery';
import { useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import logEvent from '../../../api/common/logEvent';
import ConfigureServiceModal from './ConfigureServiceModal'; import ConfigureServiceModal from './ConfigureServiceModal';
const getStatus = ( const getStatus = (
@ -57,6 +58,13 @@ function ServiceDetails(): JSX.Element | null {
const [isConfigureServiceModalOpen, setIsConfigureServiceModalOpen] = useState( const [isConfigureServiceModalOpen, setIsConfigureServiceModalOpen] = useState(
false, false,
); );
const openServiceConfigModal = (): void => {
setIsConfigureServiceModalOpen(true);
logEvent('AWS Integration: Service settings viewed', {
cloudAccountId,
serviceId,
});
};
const { data: serviceDetailsData, isLoading } = useServiceDetails( const { data: serviceDetailsData, isLoading } = useServiceDetails(
serviceId || '', serviceId || '',
@ -80,6 +88,16 @@ function ServiceDetails(): JSX.Element | null {
[config], [config],
); );
// log telemetry event on visiting details of a service.
useEffect(() => {
if (serviceId) {
logEvent('AWS Integration: Service viewed', {
cloudAccountId,
serviceId,
});
}
}, [cloudAccountId, serviceId]);
if (isLoading) { if (isLoading) {
return <Spinner size="large" height="50vh" />; return <Spinner size="large" height="50vh" />;
} }
@ -119,7 +137,7 @@ function ServiceDetails(): JSX.Element | null {
(isAnySignalConfigured ? ( (isAnySignalConfigured ? (
<Button <Button
className="configure-button configure-button--default" className="configure-button configure-button--default"
onClick={(): void => setIsConfigureServiceModalOpen(true)} onClick={openServiceConfigModal}
> >
Configure ({enabledSignals}/{totalSupportedSignals}) Configure ({enabledSignals}/{totalSupportedSignals})
</Button> </Button>
@ -127,7 +145,7 @@ function ServiceDetails(): JSX.Element | null {
<Button <Button
type="primary" type="primary"
className="configure-button configure-button--primary" className="configure-button configure-button--primary"
onClick={(): void => setIsConfigureServiceModalOpen(true)} onClick={openServiceConfigModal}
> >
Enable Service Enable Service
</Button> </Button>

View File

@ -14,6 +14,8 @@ import {
import { AccountConfigPayload } from 'types/api/integrations/aws'; import { AccountConfigPayload } from 'types/api/integrations/aws';
import { regions } from 'utils/regions'; import { regions } from 'utils/regions';
import logEvent from '../../../api/common/logEvent';
interface UseAccountSettingsModalProps { interface UseAccountSettingsModalProps {
onClose: () => void; onClose: () => void;
account: CloudAccount; account: CloudAccount;
@ -84,8 +86,14 @@ export function useAccountSettingsModal({
{ accountId: account?.id, payload }, { accountId: account?.id, payload },
{ {
onSuccess: (response) => { onSuccess: (response) => {
setActiveAccount(response.data); const newActiveAccount = response?.data;
setActiveAccount(newActiveAccount);
onClose(); onClose();
logEvent('AWS Integration: Account settings Updated', {
cloudAccountId: newActiveAccount?.cloud_account_id,
enabledRegions: newActiveAccount?.config?.regions,
});
}, },
}, },
); );

View File

@ -20,6 +20,7 @@ import {
} from 'types/api/integrations/aws'; } from 'types/api/integrations/aws';
import { regions } from 'utils/regions'; import { regions } from 'utils/regions';
import logEvent from '../../../api/common/logEvent';
import { useConnectionParams } from './useConnectionParams'; import { useConnectionParams } from './useConnectionParams';
import { useGenerateConnectionUrl } from './useGenerateConnectionUrl'; import { useGenerateConnectionUrl } from './useGenerateConnectionUrl';
@ -117,6 +118,9 @@ export function useIntegrationModal({
(payload: GenerateConnectionUrlPayload): void => { (payload: GenerateConnectionUrlPayload): void => {
generateUrl(payload, { generateUrl(payload, {
onSuccess: (data: ConnectionUrlResponse) => { onSuccess: (data: ConnectionUrlResponse) => {
logEvent('AWS Integration: Account connection attempt redirected to AWS', {
id: data.account_id,
});
window.open(data.connection_url, '_blank'); window.open(data.connection_url, '_blank');
setModalState(ModalStateEnum.WAITING); setModalState(ModalStateEnum.WAITING);
setAccountId(data.account_id); setAccountId(data.account_id);

View File

@ -26,6 +26,7 @@ export interface AccountStatusResponse {
status: 'success'; status: 'success';
data: { data: {
id: string; id: string;
cloud_account_id: string;
status: { status: {
integration: { integration: {
last_heartbeat_ts_ms: number | null; last_heartbeat_ts_ms: number | null;