mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 21:26:02 +08:00
feat: onboarding flow - add analytics (#3594)
This commit is contained in:
parent
04acc49154
commit
4b0a7cc4d3
@ -76,9 +76,9 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLoggedInState && user && user.userId && user.email) {
|
if (isLoggedInState && user && user.userId && user.email) {
|
||||||
window.analytics.identify(user?.userId, {
|
window.analytics.identify(user?.email, {
|
||||||
email: user?.email || '',
|
email: user?.email,
|
||||||
name: user?.name || '',
|
name: user?.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
import './APM.styles.scss';
|
import './APM.styles.scss';
|
||||||
|
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import GoLang from './GoLang/GoLang';
|
import GoLang from './GoLang/GoLang';
|
||||||
import Java from './Java/Java';
|
import Java from './Java/Java';
|
||||||
@ -36,6 +37,15 @@ export default function APM({
|
|||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState('java');
|
const [selectedLanguage, setSelectedLanguage] = useState('java');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: APM', {
|
||||||
|
selectedLanguage,
|
||||||
|
activeStep,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedLanguage]);
|
||||||
|
|
||||||
const renderSelectedLanguageSetupInstructions = (): JSX.Element => {
|
const renderSelectedLanguageSetupInstructions = (): JSX.Element => {
|
||||||
switch (selectedLanguage) {
|
switch (selectedLanguage) {
|
||||||
case 'java':
|
case 'java':
|
||||||
|
@ -3,7 +3,8 @@ import './Java.styles.scss';
|
|||||||
import { MDXProvider } from '@mdx-js/react';
|
import { MDXProvider } from '@mdx-js/react';
|
||||||
import { Form, Input, Select } from 'antd';
|
import { Form, Input, Select } from 'antd';
|
||||||
import Header from 'container/OnboardingContainer/common/Header/Header';
|
import Header from 'container/OnboardingContainer/common/Header/Header';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
||||||
import JavaDocs from './md-docs/java.md';
|
import JavaDocs from './md-docs/java.md';
|
||||||
@ -27,6 +28,14 @@ export default function Java({
|
|||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: APM : Java', {
|
||||||
|
selectedFrameWork,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedFrameWork]);
|
||||||
|
|
||||||
const renderDocs = (): JSX.Element => {
|
const renderDocs = (): JSX.Element => {
|
||||||
switch (selectedFrameWork) {
|
switch (selectedFrameWork) {
|
||||||
case 'tomcat':
|
case 'tomcat':
|
||||||
|
@ -3,7 +3,8 @@ import './Javascript.styles.scss';
|
|||||||
import { MDXProvider } from '@mdx-js/react';
|
import { MDXProvider } from '@mdx-js/react';
|
||||||
import { Form, Input, Select } from 'antd';
|
import { Form, Input, Select } from 'antd';
|
||||||
import Header from 'container/OnboardingContainer/common/Header/Header';
|
import Header from 'container/OnboardingContainer/common/Header/Header';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
||||||
import ExpressDocs from './md-docs/express.md';
|
import ExpressDocs from './md-docs/express.md';
|
||||||
@ -25,6 +26,14 @@ export default function Javascript({
|
|||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: APM : Javascript', {
|
||||||
|
selectedFrameWork,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedFrameWork]);
|
||||||
|
|
||||||
const renderDocs = (): JSX.Element => {
|
const renderDocs = (): JSX.Element => {
|
||||||
switch (selectedFrameWork) {
|
switch (selectedFrameWork) {
|
||||||
case 'nodejs':
|
case 'nodejs':
|
||||||
|
@ -3,7 +3,8 @@ import './Python.styles.scss';
|
|||||||
import { MDXProvider } from '@mdx-js/react';
|
import { MDXProvider } from '@mdx-js/react';
|
||||||
import { Form, Input, Select } from 'antd';
|
import { Form, Input, Select } from 'antd';
|
||||||
import Header from 'container/OnboardingContainer/common/Header/Header';
|
import Header from 'container/OnboardingContainer/common/Header/Header';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
import ConnectionStatus from '../common/ConnectionStatus/ConnectionStatus';
|
||||||
import DjangoDocs from './md-docs/django.md';
|
import DjangoDocs from './md-docs/django.md';
|
||||||
@ -29,6 +30,14 @@ export default function Python({
|
|||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: APM : Python', {
|
||||||
|
selectedFrameWork,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedFrameWork]);
|
||||||
|
|
||||||
const renderDocs = (): JSX.Element => {
|
const renderDocs = (): JSX.Element => {
|
||||||
switch (selectedFrameWork) {
|
switch (selectedFrameWork) {
|
||||||
case 'django':
|
case 'django':
|
||||||
|
@ -16,6 +16,7 @@ import { UPDATE_TIME_INTERVAL } from 'types/actions/globalTime';
|
|||||||
import { PayloadProps as QueryServicePayloadProps } from 'types/api/metrics/getService';
|
import { PayloadProps as QueryServicePayloadProps } from 'types/api/metrics/getService';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { Tags } from 'types/reducer/trace';
|
import { Tags } from 'types/reducer/trace';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
interface ConnectionStatusProps {
|
interface ConnectionStatusProps {
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
@ -112,6 +113,10 @@ export default function ConnectionStatus({
|
|||||||
if (data || isError) {
|
if (data || isError) {
|
||||||
setRetryCount(retryCount - 1);
|
setRetryCount(retryCount - 1);
|
||||||
if (retryCount < 0) {
|
if (retryCount < 0) {
|
||||||
|
trackEvent('❌ Onboarding: APM: Connection Status', {
|
||||||
|
serviceName,
|
||||||
|
status: 'Failed',
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,6 +127,11 @@ export default function ConnectionStatus({
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
setIsReceivingData(true);
|
setIsReceivingData(true);
|
||||||
|
|
||||||
|
trackEvent('✅ Onboarding: APM: Connection Status', {
|
||||||
|
serviceName,
|
||||||
|
status: 'Successful',
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,31 +140,35 @@ export default function ConnectionStatus({
|
|||||||
|
|
||||||
// Use useEffect to update query parameters when the polling interval lapses
|
// Use useEffect to update query parameters when the polling interval lapses
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const pollingTimer = setInterval(() => {
|
let pollingTimer: string | number | NodeJS.Timer | undefined;
|
||||||
// Trigger a refetch with the updated parameters
|
|
||||||
const updatedMinTime = (Date.now() - 15 * 60 * 1000) * 1000000;
|
|
||||||
const updatedMaxTime = Date.now() * 1000000;
|
|
||||||
|
|
||||||
const payload = {
|
if (loading) {
|
||||||
maxTime: updatedMaxTime,
|
pollingTimer = setInterval(() => {
|
||||||
minTime: updatedMinTime,
|
// Trigger a refetch with the updated parameters
|
||||||
selectedTime,
|
const updatedMinTime = (Date.now() - 15 * 60 * 1000) * 1000000;
|
||||||
};
|
const updatedMaxTime = Date.now() * 1000000;
|
||||||
|
|
||||||
dispatch({
|
const payload = {
|
||||||
type: UPDATE_TIME_INTERVAL,
|
maxTime: updatedMaxTime,
|
||||||
payload,
|
minTime: updatedMinTime,
|
||||||
});
|
selectedTime,
|
||||||
|
};
|
||||||
|
|
||||||
// refetch(updatedParams);
|
dispatch({
|
||||||
}, pollingInterval); // Same interval as pollingInterval
|
type: UPDATE_TIME_INTERVAL,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
}, pollingInterval); // Same interval as pollingInterval
|
||||||
|
} else if (!loading && pollingTimer) {
|
||||||
|
clearInterval(pollingTimer);
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up the interval when the component unmounts
|
// Clean up the interval when the component unmounts
|
||||||
return (): void => {
|
return (): void => {
|
||||||
clearInterval(pollingTimer);
|
clearInterval(pollingTimer);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [refetch, selectedTags, selectedTime]);
|
}, [refetch, selectedTags, selectedTime, loading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
verifyApplicationData(data);
|
verifyApplicationData(data);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { MDXProvider } from '@mdx-js/react';
|
import { MDXProvider } from '@mdx-js/react';
|
||||||
import { Select } from 'antd';
|
import { Select } from 'antd';
|
||||||
import Header from 'container/OnboardingContainer/common/Header/Header';
|
import Header from 'container/OnboardingContainer/common/Header/Header';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import FluentBit from './md-docs/fluentBit.md';
|
import FluentBit from './md-docs/fluentBit.md';
|
||||||
import FluentD from './md-docs/fluentD.md';
|
import FluentD from './md-docs/fluentD.md';
|
||||||
@ -16,6 +17,14 @@ enum FrameworksMap {
|
|||||||
export default function ExistingCollectors(): JSX.Element {
|
export default function ExistingCollectors(): JSX.Element {
|
||||||
const [selectedFrameWork, setSelectedFrameWork] = useState('fluent_d');
|
const [selectedFrameWork, setSelectedFrameWork] = useState('fluent_d');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: Logs Management: Existing Collectors', {
|
||||||
|
selectedFrameWork,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedFrameWork]);
|
||||||
|
|
||||||
const renderDocs = (): JSX.Element => {
|
const renderDocs = (): JSX.Element => {
|
||||||
switch (selectedFrameWork) {
|
switch (selectedFrameWork) {
|
||||||
case 'fluent_d':
|
case 'fluent_d':
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
import './LogsManagement.styles.scss';
|
import './LogsManagement.styles.scss';
|
||||||
|
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import ApplicationLogs from './ApplicationLogs/ApplicationLogs';
|
import ApplicationLogs from './ApplicationLogs/ApplicationLogs';
|
||||||
import Docker from './Docker/Docker';
|
import Docker from './Docker/Docker';
|
||||||
@ -60,6 +61,15 @@ export default function LogsManagement({
|
|||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [selectedLogsType, setSelectedLogsType] = useState('kubernetes');
|
const [selectedLogsType, setSelectedLogsType] = useState('kubernetes');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on language select
|
||||||
|
trackEvent('Onboarding: Logs Management', {
|
||||||
|
selectedLogsType,
|
||||||
|
activeStep,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedLogsType]);
|
||||||
|
|
||||||
const renderSelectedLanguageSetupInstructions = ():
|
const renderSelectedLanguageSetupInstructions = ():
|
||||||
| JSX.Element
|
| JSX.Element
|
||||||
| undefined => {
|
| undefined => {
|
||||||
|
@ -16,6 +16,7 @@ import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
|||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
interface ConnectionStatusProps {
|
interface ConnectionStatusProps {
|
||||||
logType: string;
|
logType: string;
|
||||||
@ -95,6 +96,10 @@ export default function LogsConnectionStatus({
|
|||||||
setRetryCount(retryCount - 1);
|
setRetryCount(retryCount - 1);
|
||||||
|
|
||||||
if (retryCount < 0) {
|
if (retryCount < 0) {
|
||||||
|
trackEvent('❌ Onboarding: Logs Management: Connection Status', {
|
||||||
|
status: 'Failed',
|
||||||
|
});
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setPollingInterval(false);
|
setPollingInterval(false);
|
||||||
}
|
}
|
||||||
@ -123,6 +128,11 @@ export default function LogsConnectionStatus({
|
|||||||
setIsReceivingData(true);
|
setIsReceivingData(true);
|
||||||
setRetryCount(-1);
|
setRetryCount(-1);
|
||||||
setPollingInterval(false);
|
setPollingInterval(false);
|
||||||
|
|
||||||
|
trackEvent('✅ Onboarding: Logs Management: Connection Status', {
|
||||||
|
status: 'Successful',
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import ROUTES from 'constants/routes';
|
|||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useEffectOnce } from 'react-use';
|
||||||
|
import { trackEvent } from 'utils/segmentAnalytics';
|
||||||
|
|
||||||
import APM from './APM/APM';
|
import APM from './APM/APM';
|
||||||
import InfrastructureMonitoring from './InfrastructureMonitoring/InfrastructureMonitoring';
|
import InfrastructureMonitoring from './InfrastructureMonitoring/InfrastructureMonitoring';
|
||||||
@ -98,6 +100,10 @@ export default function Onboarding(): JSX.Element {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
useEffectOnce(() => {
|
||||||
|
trackEvent('Onboarding Started');
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedModule?.id === ModulesMap.InfrastructureMonitoring) {
|
if (selectedModule?.id === ModulesMap.InfrastructureMonitoring) {
|
||||||
setsteps([...baseSteps]);
|
setsteps([...baseSteps]);
|
||||||
@ -123,27 +129,55 @@ export default function Onboarding(): JSX.Element {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedModule, selectedLogsType]);
|
}, [selectedModule, selectedLogsType]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// on select
|
||||||
|
trackEvent('Onboarding: Module Selected', {
|
||||||
|
selectedModule: selectedModule.id,
|
||||||
|
});
|
||||||
|
}, [selectedModule]);
|
||||||
|
|
||||||
const handleNext = (): void => {
|
const handleNext = (): void => {
|
||||||
// Need to add logic to validate service name and then allow next step transition in APM module
|
// Need to add logic to validate service name and then allow next step transition in APM module
|
||||||
const isFormValid = true;
|
const isFormValid = true;
|
||||||
|
|
||||||
if (isFormValid && activeStep <= 3) {
|
if (isFormValid && activeStep <= 3) {
|
||||||
setActiveStep(activeStep + 1);
|
const nextStep = activeStep + 1;
|
||||||
|
|
||||||
|
// on next
|
||||||
|
trackEvent('Onboarding: Next', {
|
||||||
|
selectedModule: selectedModule.id,
|
||||||
|
nextStepId: nextStep,
|
||||||
|
});
|
||||||
|
|
||||||
|
setActiveStep(nextStep);
|
||||||
setCurrent(current + 1);
|
setCurrent(current + 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePrev = (): void => {
|
const handlePrev = (): void => {
|
||||||
if (activeStep >= 1) {
|
if (activeStep >= 1) {
|
||||||
|
const prevStep = activeStep - 1;
|
||||||
|
|
||||||
|
// on prev
|
||||||
|
trackEvent('Onboarding: Back', {
|
||||||
|
module: selectedModule.id,
|
||||||
|
prevStepId: prevStep,
|
||||||
|
});
|
||||||
|
|
||||||
setCurrent(current - 1);
|
setCurrent(current - 1);
|
||||||
setActiveStep(activeStep - 1);
|
setActiveStep(prevStep);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnboardingComplete = (): void => {
|
const handleOnboardingComplete = (): void => {
|
||||||
|
trackEvent('Onboarding Complete', {
|
||||||
|
module: selectedModule.id,
|
||||||
|
});
|
||||||
|
|
||||||
switch (selectedModule.id) {
|
switch (selectedModule.id) {
|
||||||
case ModulesMap.APM:
|
case ModulesMap.APM:
|
||||||
history.push(ROUTES.APPLICATION);
|
history.push(ROUTES.APPLICATION);
|
||||||
@ -160,8 +194,15 @@ export default function Onboarding(): JSX.Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleStepChange = (value: number): void => {
|
const handleStepChange = (value: number): void => {
|
||||||
|
const stepId = value + 1;
|
||||||
|
|
||||||
|
trackEvent('Onboarding: Step Change', {
|
||||||
|
module: selectedModule.id,
|
||||||
|
step: stepId,
|
||||||
|
});
|
||||||
|
|
||||||
setCurrent(value);
|
setCurrent(value);
|
||||||
setActiveStep(value + 1);
|
setActiveStep(stepId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModuleSelect = (module: ModuleProps): void => {
|
const handleModuleSelect = (module: ModuleProps): void => {
|
||||||
|
@ -4,7 +4,7 @@ function trackPageView(pageName: string): void {
|
|||||||
|
|
||||||
function trackEvent(
|
function trackEvent(
|
||||||
eventName: string,
|
eventName: string,
|
||||||
properties: Record<string, string>,
|
properties?: Record<string, unknown>,
|
||||||
): void {
|
): void {
|
||||||
window.analytics.track(eventName, properties);
|
window.analytics.track(eventName, properties);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user