Merge pull request #738 from navi-infra/INFRA-3746

INFRA-3746 | Abhishek | Allow features in diagnostics section based on language
This commit is contained in:
Abhishek K
2024-12-24 18:56:16 +05:30
committed by GitHub
4 changed files with 101 additions and 41 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
@@ -8,6 +8,9 @@ import { AccountTree as AccountTreeIcon, Waves as WavesIcon } from '@material-ui
import { setCurrentStep, setDiagnosticType } from '../../slices/diagnosticSlice';
import CpuIcon from '../assets/images/CpuIcon.svg';
import { DiagnosticType } from './utils';
import { useFormikContext } from 'formik';
import { Alert } from '@material-ui/lab';
import { languageFeatureMap } from './useDiagnosticMapping';
interface Button {
id: DiagnosticType;
icon: React.ReactNode;
@@ -35,6 +38,19 @@ const buttons: Button[] = [
const DefaultDiagnosticStep: React.FC = (): React.JSX.Element => {
const dispatch = useDispatch();
const { values }: { values: any } = useFormikContext();
const [isMetricsPortConfigured, setIsMetricsPortConfigured] = useState<boolean>(false);
const allowedButtons = buttons.filter(b =>
languageFeatureMap[values.metadata?.language].includes(b.id),
);
useEffect(() => {
let metricsPort = values?.deployment?.exposedPorts.filter(port => port.name == 'metrics');
if (metricsPort.length !== 0) {
setIsMetricsPortConfigured(true);
}
});
const handleDiagnosticSelection = (
e: React.MouseEvent<HTMLButtonElement>,
buttonId: DiagnosticType,
@@ -43,18 +59,36 @@ const DefaultDiagnosticStep: React.FC = (): React.JSX.Element => {
dispatch(setCurrentStep(1));
};
const DiagnosticFeatures = () => {
return (
<>
<Typography variant="body1">Please choose one of the following options:</Typography>
<Grid container spacing={4} justifyContent="center">
{allowedButtons.map(button => (
<Grid item key={button.id}>
<IconButton onClick={e => handleDiagnosticSelection(e, button.id)} color="primary">
{button.icon}
<Typography variant="subtitle1">{button.label}</Typography>
</IconButton>
</Grid>
))}
</Grid>
</>
);
};
return (
<>
<Typography variant="body1">Please choose one of the following options:</Typography>
<Grid container spacing={2} justifyContent="center" style={{ marginTop: '16px' }}>
{buttons.map(button => (
<Grid item key={button.id}>
<IconButton onClick={e => handleDiagnosticSelection(e, button.id)} color="primary">
{button.icon}
<Typography variant="subtitle1">{button.label}</Typography>
</IconButton>
</Grid>
))}
<Grid container spacing={2} style={{ marginTop: '16px' }}>
{!isMetricsPortConfigured && values?.metadata?.language === 'Golang' ? (
<Alert severity={'warning'}>
{
'Metrics port is needed for diagnostics in Golang services. Please configure metrics port to check for diagnostics.'
}
</Alert>
) : (
<DiagnosticFeatures />
)}
</Grid>
</>
);

View File

@@ -63,7 +63,7 @@ const GenerateDiagnostic: React.FC<GenerateDiagnosticProps> = (props: GenerateDi
}
}, [disabled]);
const languagesEnabled: string[] = ['Java', 'Kotlin'];
const languagesEnabled: string[] = ['Java', 'Kotlin', 'Golang'];
if (!languagesEnabled.includes(language)) return null;
return (
@@ -81,7 +81,7 @@ const GenerateDiagnostic: React.FC<GenerateDiagnosticProps> = (props: GenerateDi
</Button>
</span>
</Tooltip>
{currentStep >= 0 && <Step />}
{currentStep >= 0 && <Step language={language} />}
</>
);
};

View File

@@ -32,10 +32,14 @@ import {
import './GenerateDump.module.css';
import useDiagnosticMapping from './useDiagnosticMapping';
interface StepProps {
language: string;
}
const createDumpEndpoint: string = `/api/diagnostic`;
const Step: React.FC = () => {
const Step = (props: StepProps) => {
const state: Diagnostic = useSelector((state: RootState) => state?.diagnostic);
const diagnosticMapping = useDiagnosticMapping();
const diagnosticMapping = useDiagnosticMapping(props.language);
const currentDiag = diagnosticMapping?.[state?.diagnosticType] ?? {};
const { currentStep, title, content } = currentDiag?.[state?.currentStep] ?? {};
const dispatch = useDispatch();

View File

@@ -13,7 +13,14 @@ interface DiagnosticData {
steps: React.JSX.Element[];
};
}
const useDiagnosticMapping = () => {
export const languageFeatureMap = {
Golang: [DiagnosticType.HeapDump, DiagnosticType.CpuProfile],
Java: [DiagnosticType.HeapDump, DiagnosticType.ThreadDump, DiagnosticType.CpuProfile],
Kotlin: [DiagnosticType.HeapDump, DiagnosticType.ThreadDump, DiagnosticType.CpuProfile],
};
const useDiagnosticMapping = (language: string) => {
const [diagnosticMapping, setDiagnosticMapping] = useState({});
const defaultDiagnosticStep = [<DefaultDiagnostic />];
const threadDumpSteps: React.JSX.Element[] = [
@@ -24,42 +31,57 @@ const useDiagnosticMapping = () => {
...defaultDiagnosticStep,
<CpuProfilePodsSelection />,
];
const heapDumpSteps: React.JSX.Element[] = [
...defaultDiagnosticStep,
<HeapDumpTypeSelection />,
<HeapDumpPodsSelection />,
];
const heapDumpSteps = (language: string) => {
const steps = {
Java: [...defaultDiagnosticStep, <HeapDumpTypeSelection />, <HeapDumpPodsSelection />],
Kotlin: [...defaultDiagnosticStep, <HeapDumpTypeSelection />, <HeapDumpPodsSelection />],
Golang: [...defaultDiagnosticStep, <HeapDumpPodsSelection />],
};
return steps[language];
};
const defaultTitles: string[] = ['Select Diagnostic Type'];
const heapDumpTitles: string[] = [...defaultTitles, 'Select Heap Dump Type', 'Select Pods'];
const threadDumpTitles: string[] = [...defaultTitles, 'Select Pods'];
const cpuProfileTitles: string[] = [...defaultTitles, 'Select Pods'];
const heapDumpTitles = (language): string[] => {
const titles = {
Java: [...defaultTitles, 'Select Heap Dump Type', 'Select Pods'],
Kotlin: [...defaultTitles, 'Select Heap Dump Type', 'Select Pods'],
Golang: [...defaultTitles, 'Select Pods'],
};
return titles[language];
};
const diagnosticData: DiagnosticData = {
[DiagnosticType.Default]: {
title: defaultTitles,
steps: defaultDiagnosticStep,
},
[DiagnosticType.HeapDump]: {
title: heapDumpTitles,
steps: heapDumpSteps,
},
[DiagnosticType.ThreadDump]: {
title: threadDumpTitles,
steps: threadDumpSteps,
},
[DiagnosticType.CpuProfile]: {
title: cpuProfileTitles,
steps: cpuProfileSteps,
},
const diagnosticData = (language: string) => {
return {
[DiagnosticType.Default]: {
title: defaultTitles,
steps: defaultDiagnosticStep,
},
[DiagnosticType.HeapDump]: {
title: heapDumpTitles(language),
steps: heapDumpSteps(language),
},
[DiagnosticType.ThreadDump]: {
title: threadDumpTitles,
steps: threadDumpSteps,
},
[DiagnosticType.CpuProfile]: {
title: cpuProfileTitles,
steps: cpuProfileSteps,
},
};
};
useEffect(() => {
const mapping = generateMapping(diagnosticData);
const mapping = generateMapping(diagnosticData(language));
setDiagnosticMapping(mapping);
}, []);
return diagnosticMapping;
};
const generateMapping = (diagnosticData: DiagnosticData) => {
const generateMapping = diagnosticData => {
console.log(diagnosticData);
return Object.keys(diagnosticData).reduce((acc, type) => {
const { title, steps } = diagnosticData[type];
acc[type] = title.map((title, index) => ({