signoz/frontend/src/container/OnboardingContainer/OnboardingContainer.tsx

321 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import './Onboarding.styles.scss';
import { ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons';
import { Button, Card, StepProps, Steps, Typography } from 'antd';
import cx from 'classnames';
import ROUTES from 'constants/routes';
import { useIsDarkMode } from 'hooks/useDarkMode';
import history from 'lib/history';
import { useEffect, useState } from 'react';
import { useEffectOnce } from 'react-use';
import { trackEvent } from 'utils/segmentAnalytics';
import APM from './APM/APM';
import InfrastructureMonitoring from './InfrastructureMonitoring/InfrastructureMonitoring';
import LogsManagement from './LogsManagement/LogsManagement';
enum ModulesMap {
APM = 'APM',
LogsManagement = 'LogsManagement',
InfrastructureMonitoring = 'InfrastructureMonitoring',
}
const defaultStepDesc = 'Configure data source';
const getStarted = 'Get Started';
const selectUseCase = 'Select the use-case';
const instrumentApp = 'Instrument Application';
const testConnection = 'Test Connection';
const verifyConnectionDesc = 'Verify that youve instrumented your application';
const verifyableLogsType = ['kubernetes', 'docker'];
interface ModuleProps {
id: string;
title: string;
desc: string;
stepDesc: string;
}
const useCases = {
APM: {
id: ModulesMap.APM,
title: 'Application Monitoring',
desc:
'Monitor performance of your applications & troubleshoot problems by installing within your infra.',
stepDesc: defaultStepDesc,
},
LogsManagement: {
id: ModulesMap.LogsManagement,
title: 'Logs Management',
desc:
'Easily search and filter logs with query builder and automatically detect logs from K8s cluster.',
stepDesc: 'Choose the logs that you want to receive on SigNoz',
},
InfrastructureMonitoring: {
id: ModulesMap.InfrastructureMonitoring,
title: 'Infrastructure Monitoring',
desc:
'Easily search and filter logs with query builder and automatically detect logs from K8s cluster.',
stepDesc: defaultStepDesc,
},
};
const defaultSteps: StepProps[] = [
{
title: getStarted,
description: selectUseCase,
},
{
title: instrumentApp,
description: defaultStepDesc,
},
{
title: testConnection,
description: verifyConnectionDesc,
},
];
export default function Onboarding(): JSX.Element {
const [selectedModule, setSelectedModule] = useState<ModuleProps>(
useCases.APM,
);
const [steps, setsteps] = useState(defaultSteps);
const [activeStep, setActiveStep] = useState(1);
const [current, setCurrent] = useState(0);
const [selectedLogsType, setSelectedLogsType] = useState<string | null>(
'kubernetes',
);
const isDarkMode = useIsDarkMode();
const baseSteps = [
{
title: getStarted,
description: selectUseCase,
},
{
title: instrumentApp,
description: selectedModule.stepDesc,
},
];
useEffectOnce(() => {
trackEvent('Onboarding Started');
});
useEffect(() => {
if (selectedModule?.id === ModulesMap.InfrastructureMonitoring) {
setsteps([...baseSteps]);
} else if (selectedModule?.id === ModulesMap.LogsManagement) {
if (selectedLogsType && verifyableLogsType?.indexOf(selectedLogsType) > -1) {
setsteps([
...baseSteps,
{
title: testConnection,
description: verifyConnectionDesc,
disabled: true,
},
]);
} else {
setsteps([...baseSteps]);
}
} else {
setsteps([
...baseSteps,
{
title: testConnection,
description: verifyConnectionDesc,
},
]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedModule, selectedLogsType]);
useEffect(() => {
// on select
trackEvent('Onboarding: Module Selected', {
selectedModule: selectedModule.id,
});
}, [selectedModule]);
const handleNext = (): void => {
// Need to add logic to validate service name and then allow next step transition in APM module
const isFormValid = true;
if (isFormValid && activeStep <= 3) {
const nextStep = activeStep + 1;
// on next
trackEvent('Onboarding: Next', {
selectedModule: selectedModule.id,
nextStepId: nextStep,
});
setActiveStep(nextStep);
setCurrent(current + 1);
}
};
const handlePrev = (): void => {
if (activeStep >= 1) {
const prevStep = activeStep - 1;
// on prev
trackEvent('Onboarding: Back', {
module: selectedModule.id,
prevStepId: prevStep,
});
setCurrent(current - 1);
setActiveStep(prevStep);
}
};
const handleOnboardingComplete = (): void => {
trackEvent('Onboarding Complete', {
module: selectedModule.id,
});
switch (selectedModule.id) {
case ModulesMap.APM:
history.push(ROUTES.APPLICATION);
break;
case ModulesMap.LogsManagement:
history.push(ROUTES.LOGS);
break;
case ModulesMap.InfrastructureMonitoring:
history.push(ROUTES.APPLICATION);
break;
default:
break;
}
};
const handleStepChange = (value: number): void => {
const stepId = value + 1;
trackEvent('Onboarding: Step Change', {
module: selectedModule.id,
step: stepId,
});
setCurrent(value);
setActiveStep(stepId);
};
const handleModuleSelect = (module: ModuleProps): void => {
setSelectedModule(module);
};
const handleLogTypeSelect = (logType: string): void => {
setSelectedLogsType(logType);
};
return (
<div className={cx('container', isDarkMode ? 'darkMode' : 'lightMode')}>
{activeStep === 1 && (
<>
<div className="onboardingHeader">
<h1>Get Started with SigNoz</h1>
<div> Select a use-case to get started </div>
</div>
<div className="modulesContainer">
<div className="moduleContainerRowStyles">
{Object.keys(ModulesMap).map((module) => {
const selectedUseCase = (useCases as any)[module];
return (
<Card
className={cx(
'moduleStyles',
selectedModule.id === selectedUseCase.id ? 'selected' : '',
)}
style={{
backgroundColor: isDarkMode ? '#000' : '#FFF',
}}
key={selectedUseCase.id}
onClick={(): void => handleModuleSelect(selectedUseCase)}
>
<Typography.Title
className="moduleTitleStyle"
level={4}
style={{
borderBottom: isDarkMode ? '1px solid #303030' : '1px solid #ddd',
backgroundColor: isDarkMode ? '#141414' : '#FFF',
}}
>
{selectedUseCase.title}
</Typography.Title>
<Typography.Paragraph
className="moduleDesc"
style={{ backgroundColor: isDarkMode ? '#000' : '#FFF' }}
>
{selectedUseCase.desc}
</Typography.Paragraph>
</Card>
);
})}
</div>
</div>
<div className="continue-to-next-step">
<Button type="primary" icon={<ArrowRightOutlined />} onClick={handleNext}>
Continue to next step
</Button>
</div>
</>
)}
{activeStep > 1 && (
<div className="stepsContainer">
<Steps
current={current}
onChange={handleStepChange}
items={steps}
size="small"
/>
<div className="step-content">
{selectedModule.id === ModulesMap.APM && <APM activeStep={activeStep} />}
{selectedModule.id === ModulesMap.LogsManagement && (
<LogsManagement
activeStep={activeStep}
handleLogTypeSelect={handleLogTypeSelect}
/>
)}
{selectedModule.id === ModulesMap.InfrastructureMonitoring && (
<InfrastructureMonitoring activeStep={activeStep} />
)}
</div>
<div className="actionButtonsContainer">
{activeStep > 0 && (
<Button icon={<ArrowLeftOutlined />} onClick={handlePrev}>
Back
</Button>
)}
{activeStep < steps.length && (
<Button
type="primary"
icon={<ArrowRightOutlined />}
onClick={handleNext}
>
Continue to next step
</Button>
)}
{activeStep === steps.length && (
<Button type="primary" onClick={handleOnboardingComplete}>
Done
</Button>
)}
</div>
</div>
)}
</div>
);
}