diff --git a/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.test.tsx b/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.test.tsx
new file mode 100644
index 0000000000..6fcad5f43f
--- /dev/null
+++ b/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.test.tsx
@@ -0,0 +1,41 @@
+import { screen } from '@testing-library/react';
+import { render } from 'utils/testRenderer';
+import { testServerRoute, testServerSetup } from 'utils/testServer';
+import type { ProjectDoraMetricsSchema } from 'openapi';
+import { LeadTimeForChanges } from './LeadTimeForChanges';
+import { Route, Routes } from 'react-router-dom';
+
+const server = testServerSetup();
+
+const setupApi = (outdatedSdks: ProjectDoraMetricsSchema) => {
+ testServerRoute(server, '/api/admin/projects/default/dora', outdatedSdks);
+};
+
+test('Show outdated SDKs and apps using them', async () => {
+ setupApi({
+ features: [
+ {
+ name: 'ABCD',
+ timeToProduction: 57,
+ },
+ ],
+ projectAverage: 67,
+ });
+ render(
+
+ }
+ />
+ ,
+ {
+ route: '/projects/default',
+ },
+ );
+
+ await screen.findByText('Lead time for changes (per release toggle)');
+ await screen.findByText('ABCD');
+ await screen.findByText('57 days');
+ await screen.findByText('Low');
+ await screen.findByText('10 days');
+});
diff --git a/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.tsx b/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.tsx
new file mode 100644
index 0000000000..3512221cc9
--- /dev/null
+++ b/frontend/src/component/project/Project/ProjectInsights/LeadTimeForChanges/LeadTimeForChanges.tsx
@@ -0,0 +1,261 @@
+import { Box, styled, Tooltip, Typography, useMediaQuery } from '@mui/material';
+import { useProjectDoraMetrics } from 'hooks/api/getters/useProjectDoraMetrics/useProjectDoraMetrics';
+import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
+import { useMemo } from 'react';
+import { useTable, useGlobalFilter, useSortBy } from 'react-table';
+import {
+ Table,
+ SortableTableHeader,
+ TableBody,
+ TableCell,
+ TableRow,
+ TablePlaceholder,
+} from 'component/common/Table';
+import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
+import { Badge } from 'component/common/Badge/Badge';
+import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
+import theme from 'themes/theme';
+
+const Container = styled(Box)(({ theme }) => ({
+ gridColumn: 'span 5',
+ backgroundColor: theme.palette.background.paper,
+ padding: theme.spacing(3),
+ display: 'flex',
+ flexDirection: 'column',
+ gap: theme.spacing(2),
+ borderRadius: theme.shape.borderRadiusLarge,
+ overflowY: 'auto',
+ maxHeight: theme.spacing(100),
+}));
+
+const resolveDoraMetrics = (input: number) => {
+ const ONE_MONTH = 30;
+ const ONE_WEEK = 7;
+
+ if (input >= ONE_MONTH) {
+ return Low;
+ }
+
+ if (input <= ONE_MONTH && input >= ONE_WEEK + 1) {
+ return Medium;
+ }
+
+ if (input <= ONE_WEEK) {
+ return High;
+ }
+};
+
+export const LeadTimeForChanges = () => {
+ const projectId = useRequiredPathParam('projectId');
+
+ const { dora, loading } = useProjectDoraMetrics(projectId);
+
+ const data = useMemo(() => {
+ if (loading) {
+ return Array(5).fill({
+ name: 'Featurename',
+ timeToProduction: 'Data for production',
+ });
+ }
+
+ return dora.features;
+ }, [dora, loading]);
+
+ const columns = useMemo(
+ () => [
+ {
+ Header: 'Name',
+ accessor: 'name',
+ width: '40%',
+ Cell: ({
+ row: {
+ original: { name },
+ },
+ }: any) => {
+ return (
+
+ {name}
+
+ );
+ },
+ sortType: 'alphanumeric',
+ },
+ {
+ Header: 'Time to production',
+ id: 'timetoproduction',
+ align: 'center',
+ Cell: ({ row: { original } }: any) => (
+
+
+ {original.timeToProduction} days
+
+
+ ),
+ width: 200,
+ disableGlobalFilter: true,
+ disableSortBy: true,
+ },
+ {
+ Header: `Deviation`,
+ id: 'deviation',
+ align: 'center',
+ Cell: ({ row: { original } }: any) => (
+
+
+ {Math.round(
+ (dora.projectAverage
+ ? dora.projectAverage
+ : 0) - original.timeToProduction,
+ )}{' '}
+ days
+
+
+ ),
+ width: 300,
+ disableGlobalFilter: true,
+ disableSortBy: true,
+ },
+ {
+ Header: 'DORA',
+ id: 'dora',
+ align: 'center',
+ Cell: ({ row: { original } }: any) => (
+
+
+ {resolveDoraMetrics(original.timeToProduction)}
+
+
+ ),
+ width: 200,
+ disableGlobalFilter: true,
+ disableSortBy: true,
+ },
+ ],
+ [JSON.stringify(dora.features), loading],
+ );
+
+ const initialState = useMemo(
+ () => ({
+ sortBy: [
+ {
+ id: 'name',
+ desc: false,
+ },
+ ],
+ }),
+ [],
+ );
+
+ const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
+
+ const {
+ getTableProps,
+ getTableBodyProps,
+ headerGroups,
+ rows,
+ prepareRow,
+ state: { globalFilter },
+ setHiddenColumns,
+ } = useTable(
+ {
+ columns: columns as any[],
+ data,
+ initialState,
+ autoResetGlobalFilter: false,
+ autoResetSortBy: false,
+ disableSortRemove: true,
+ },
+ useGlobalFilter,
+ useSortBy,
+ );
+
+ useConditionallyHiddenColumns(
+ [
+ {
+ condition: isExtraSmallScreen,
+ columns: ['deviation'],
+ },
+ ],
+ setHiddenColumns,
+ columns,
+ );
+
+ return (
+
+
+ Lead time for changes (per release toggle)
+
+
+
+
+ {rows.map((row) => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map((cell) => (
+
+ {cell.render('Cell')}
+
+ ))}
+
+ );
+ })}
+
+
+ 0}
+ show={
+
+ No features with data found “
+ {globalFilter}
+ ”
+
+ }
+ />
+ }
+ />
+
+ );
+};
diff --git a/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx b/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
index dd83b8beba..cf40a9b82e 100644
--- a/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
+++ b/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
@@ -1,4 +1,5 @@
import { Box, styled } from '@mui/material';
+import { LeadTimeForChanges } from './LeadTimeForChanges/LeadTimeForChanges';
const Grid = styled(Box)(({ theme }) => ({
display: 'grid',
@@ -14,10 +15,6 @@ const Health = styled(Box)(({ theme }) => ({
gridColumn: 'span 5',
}));
-const LeadTime = styled(Box)(({ theme }) => ({
- gridColumn: 'span 5',
-}));
-
const ToggleTypesUsed = styled(Box)(({ theme }) => ({
gridColumn: 'span 2',
}));
@@ -38,7 +35,7 @@ export const ProjectInsights = () => {
flags
Project Health
- Lead time
+
Toggle types used
Project members
Change Requests