mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-13 13:31:30 +08:00
321 lines
8.0 KiB
TypeScript
321 lines
8.0 KiB
TypeScript
/* 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 you’ve 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>
|
||
);
|
||
}
|