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'; 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 { setCurrentStep, setDiagnosticType } from '../../slices/diagnosticSlice';
import CpuIcon from '../assets/images/CpuIcon.svg'; import CpuIcon from '../assets/images/CpuIcon.svg';
import { DiagnosticType } from './utils'; import { DiagnosticType } from './utils';
import { useFormikContext } from 'formik';
import { Alert } from '@material-ui/lab';
import { languageFeatureMap } from './useDiagnosticMapping';
interface Button { interface Button {
id: DiagnosticType; id: DiagnosticType;
icon: React.ReactNode; icon: React.ReactNode;
@@ -35,6 +38,19 @@ const buttons: Button[] = [
const DefaultDiagnosticStep: React.FC = (): React.JSX.Element => { const DefaultDiagnosticStep: React.FC = (): React.JSX.Element => {
const dispatch = useDispatch(); 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 = ( const handleDiagnosticSelection = (
e: React.MouseEvent<HTMLButtonElement>, e: React.MouseEvent<HTMLButtonElement>,
buttonId: DiagnosticType, buttonId: DiagnosticType,
@@ -43,18 +59,36 @@ const DefaultDiagnosticStep: React.FC = (): React.JSX.Element => {
dispatch(setCurrentStep(1)); 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 ( return (
<> <>
<Typography variant="body1">Please choose one of the following options:</Typography> <Grid container spacing={2} style={{ marginTop: '16px' }}>
<Grid container spacing={2} justifyContent="center" style={{ marginTop: '16px' }}> {!isMetricsPortConfigured && values?.metadata?.language === 'Golang' ? (
{buttons.map(button => ( <Alert severity={'warning'}>
<Grid item key={button.id}> {
<IconButton onClick={e => handleDiagnosticSelection(e, button.id)} color="primary"> 'Metrics port is needed for diagnostics in Golang services. Please configure metrics port to check for diagnostics.'
{button.icon} }
<Typography variant="subtitle1">{button.label}</Typography> </Alert>
</IconButton> ) : (
</Grid> <DiagnosticFeatures />
))} )}
</Grid> </Grid>
</> </>
); );

View File

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

View File

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

View File

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