diff --git a/components/change-failure-rate/changeFailureRate.js b/components/change-failure-rate/changeFailureRate.js new file mode 100644 index 0000000..c60947e --- /dev/null +++ b/components/change-failure-rate/changeFailureRate.js @@ -0,0 +1,28 @@ +// components/deploymentFrequency.js +import { useState, useEffect } from 'react'; +import { getDaysBetweenDates } from '@/components/date-range-selector' + +export default function useChangeFailureRate(appName, dateRange) { + const [cfrData, setCfrData] = useState([]); + const [loading, setLoading] = useState(true); // Add loading state + + useEffect(() => { + const fetchData = async () => { + try { + const req = `${process.env.NEXT_PUBLIC_PELORUS_API_URL}/sdp/change_failure_rate/${appName}/data?range=${getDaysBetweenDates(dateRange)}d&start=${dateRange.to.getTime() / 1000}`; + const response = await fetch(req); + const data = await response.json(); + const sortedData = data.sort((d1, d2) => (d1.timestamp > d2.timestamp) ? 1 : (d1.timestamp < d2.timestamp) ? -1 : 0); + setCfrData(sortedData); + } catch (error) { + console.error('Error fetching deployment frequency data:', error); + } finally { + setLoading(false); // Set loading to false regardless of success or failure + } + }; + + fetchData(); + }, [appName, dateRange]); + + return { cfrData, loading }; // Return loading state along with cfrData +} diff --git a/components/change-failure-rate/iso-chart.jsx b/components/change-failure-rate/chart.jsx similarity index 55% rename from components/change-failure-rate/iso-chart.jsx rename to components/change-failure-rate/chart.jsx index 3fd9c9d..3f186c6 100644 --- a/components/change-failure-rate/iso-chart.jsx +++ b/components/change-failure-rate/chart.jsx @@ -5,10 +5,8 @@ import { format } from 'date-fns' import { useTheme } from "next-themes" import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ComposedChart, Area, Line, ReferenceLine } from 'recharts' import { ChangeFailureRateTooltip } from './tooltip' - -const dateFormatter = date => { - return format(new Date(date), "MMM d") -} +import { dateFormatter, dayFormatter } from '@/lib/date-funcs'; +import useChangeFailureRate from './changeFailureRate' const calculateMean = data => { if (data.length < 1) { @@ -17,7 +15,39 @@ const calculateMean = data => { return data.reduce((prev, current) => prev + current) / data.length } -export function IsolatedChangeFailureRateChart({ data }) { +function eventsPerDay(data) { + // Object to store the count of deployments per day + const countPerDay = {}; + + // Loop through each item in the data array + data.forEach(item => { + // Convert timestamp to Date object and extract the date + const date = new Date(item.timestamp * 1000); + // Format the date to YYYY-MM-DD + const formattedDate = date.toLocaleDateString().split('T')[0]; + + // Increment the count of deployments for the corresponding date + if (countPerDay[formattedDate]) { + countPerDay[formattedDate]++; + } else { + countPerDay[formattedDate] = 1; + } + }); + + // Convert the deployments count per day object into an array of objects + const result = Object.keys(countPerDay).map(date => ({ + // Convert date back to epoch format and assign to day_epoch property + day_epoch: new Date(date).getTime() / 1000, + // Assign the count of deployments to the count property + count: countPerDay[date] + })); + + // Return the result + return result; +} + + +export function ChangeFailureRateChart({ dateRange, appName }) { const { resolvedTheme } = useTheme() const animationDuration = 1000 @@ -36,27 +66,37 @@ export function IsolatedChangeFailureRateChart({ data }) { const strokeRollingAverage = '#f43f5e' // Rose 500 const strokeGoal = '#f59e0b' // Amber 500 + const { cfrData, loading } = useChangeFailureRate(appName, dateRange); + console.log('Chart cfrData: ', cfrData) + + if (loading) { + return
Loading...
; // Render loading state while data is being fetched + } + + var countPerDay = eventsPerDay(cfrData); + console.log('Count per day', countPerDay) + // Calculate the mean - const averages = data.map(element => { + const averages = cfrData.map(element => { return element.rollingAverage }) const chartMean = calculateMean(averages) - // Reports - const [reportChangeFailureRateData, setReportChangeFailureRateData] = useState(null) - const [showReportChangeFailureRateData, setShowReportChangeFailureRateData] = useState(false) + // // Reports + // const [reportChangeFailureRateData, setReportChangeFailureRateData] = useState(null) + // const [showReportChangeFailureRateData, setShowReportChangeFailureRateData] = useState(false) - function handleChartClick(event) { - setReportChangeFailureRateData(event) - setShowReportChangeFailureRateData(true) - } + // function handleChartClick(event) { + // setReportChangeFailureRateData(event) + // setShowReportChangeFailureRateData(true) + // } - // Anomaly detection - const showAnomalyWarning = data.some((day) => { - if (day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1]) { return true } - return false - }) + // // Anomaly detection + // const showAnomalyWarning = data.some((day) => { + // if (day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1]) { return true } + // return false + // }) const customAnomalyLabel = props => { return ( @@ -70,20 +110,20 @@ export function IsolatedChangeFailureRateChart({ data }) { return ( <> - + - - `${tick}%`} /> + + } cursor={{ stroke: strokeCursor }} /> - + - {data.map((day, index) => ( + {/* {data.map((day, index) => ( day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1] && ( ) - ))} + ))} */} {/* */} diff --git a/components/change-failure-rate/table.jsx b/components/change-failure-rate/table.jsx index 143914e..af409e3 100644 --- a/components/change-failure-rate/table.jsx +++ b/components/change-failure-rate/table.jsx @@ -9,250 +9,48 @@ import { TableHeader, TableRow, } from "@/components/ui/table" -import { Calendar, GitBranch, GitCommit, Globe } from "lucide-react" +import { Orbit, CalendarCheck, Ticket } from "lucide-react" +import useChangeFailureRate from "./changeFailureRate"; +import { dateFormatter, dayFormatter } from '@/lib/date-funcs'; + +export function ChangeFailureRateTable({ dateRange, appName }) { + + const { cfrData, loading } = useChangeFailureRate(appName, dateRange); + console.log('Table cfrData: ', cfrData) + + if (loading) { + return
Loading...
; // Render loading state while data is being fetched + } -export function ChangeFailureRateTable({ data }) { return ( - Deployment name - Service - Date - Status + Ticket Reference + App Name + Date Created - - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
- - -
- - project-crimson-prototype-q6yb8whv -
-
- -
- Main -
-
- 0577e50 Commit name description -
-
- -
- - Jul 26, 2023 -
-
-
Error
-
+ {cfrData.map (({ issue_id, timestamp }) => ( + + +
+ {issue_id} +
+
+ +
+ {appName} +
+
+ +
+ { dateFormatter(timestamp) } +
+
+
+ ))}
) diff --git a/components/change-failure-rate/tooltip.jsx b/components/change-failure-rate/tooltip.jsx index ed3b971..162bd1e 100644 --- a/components/change-failure-rate/tooltip.jsx +++ b/components/change-failure-rate/tooltip.jsx @@ -23,12 +23,12 @@ export const ChangeFailureRateTooltip = ({ active, payload, label }) => { if (active && payload && payload.length) { return (
-
{format(new Date(label), "MMM d, y")}
+
{format(new Date(label * 1000), "MMM d, y")}
{payload.map((data, index) => (
{toSentence(data.name)}
-
{data.value instanceof Array ? data.value.join('-') : data.value}%
+
{data.value instanceof Array ? data.value.join('-') : data.value} issues
))}
diff --git a/components/dashboard.jsx b/components/dashboard.jsx index ce1862e..a112358 100644 --- a/components/dashboard.jsx +++ b/components/dashboard.jsx @@ -17,8 +17,8 @@ import { import { DeploymentFrequencyChart } from '@/components/deployment-frequency/chart' import { LeadTimeForChangeChart } from '@/components/lead-time-for-change/chart' -import { IsolatedChangeFailureRateChart } from '@/components/change-failure-rate/iso-chart' -import { IsolatedMeanTimeToRecoveryChart } from '@/components/mean-time-to-recovery/iso-chart' +import { ChangeFailureRateChart } from '@/components/change-failure-rate/chart' +import { MeanTimeToRecoveryChart } from '@/components/mean-time-to-recovery/chart' import { DeploymentFrequencyTabTrigger } from './deployment-frequency/tab-trigger' import { ChangeFailureRateTabTrigger } from './change-failure-rate/tab-trigger' @@ -91,7 +91,6 @@ export function Dashboard({ data, appList }) {
-
@@ -158,26 +157,26 @@ export function Dashboard({ data, appList }) {
- +

Failed deployments

- +
- +

Pull requests

- +
diff --git a/components/deployment-frequency/tab-trigger.jsx b/components/deployment-frequency/tab-trigger.jsx index af80399..263fcaa 100644 --- a/components/deployment-frequency/tab-trigger.jsx +++ b/components/deployment-frequency/tab-trigger.jsx @@ -1,6 +1,6 @@ 'use client' -import { Rocket, ArrowDown, ArrowUp } from 'lucide-react' +import { Rocket, ArrowUp } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { InfoTooltip } from '@/components/info-tooltip' import { DeploymentFrequencyRating } from '@/components/deployment-frequency/rating' diff --git a/components/deployment-frequency/table.jsx b/components/deployment-frequency/table.jsx index 2f6f1dd..462d536 100644 --- a/components/deployment-frequency/table.jsx +++ b/components/deployment-frequency/table.jsx @@ -10,7 +10,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table" -import { Orbit, FileCode, Clock } from "lucide-react" +import { Orbit, FileCode, CalendarCheck, Blocks, Fingerprint } from "lucide-react" import useDeploymentFrequencyData from './deploymentFrequency'; import { dateFormatter } from '@/lib/date-funcs'; @@ -37,17 +37,17 @@ export function DeploymentFrequencyTable({ dateRange, appName }) {
- {appName} + {appName}
- {image} + {image}
- { dateFormatter(timestamp) } + { dateFormatter(timestamp) }
diff --git a/components/lead-time-for-change/table.jsx b/components/lead-time-for-change/table.jsx index 92280aa..70e34fe 100644 --- a/components/lead-time-for-change/table.jsx +++ b/components/lead-time-for-change/table.jsx @@ -10,7 +10,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table" -import { Calendar, GitBranch, GitCommit, Globe, Timer } from "lucide-react" +import { Calendar, GitCommit, GitGraph, Timer } from "lucide-react" import { getDaysBetweenDates } from '@/components/date-range-selector' import {dateFormatter, dayFormatter} from '@/lib/date-funcs'; @@ -39,12 +39,12 @@ export function LeadTimeForChangeTable({ dateRange, appName }) {
- {commit} + {commit}
- { dateFormatter(timestamp) } + { dateFormatter(timestamp) }
diff --git a/components/mean-time-to-recovery/iso-chart.jsx b/components/mean-time-to-recovery/chart.jsx similarity index 67% rename from components/mean-time-to-recovery/iso-chart.jsx rename to components/mean-time-to-recovery/chart.jsx index 93f8c30..0e228aa 100644 --- a/components/mean-time-to-recovery/iso-chart.jsx +++ b/components/mean-time-to-recovery/chart.jsx @@ -5,10 +5,8 @@ import { useTheme } from "next-themes" import { format } from 'date-fns' import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ComposedChart, Area, Line, ReferenceLine } from 'recharts' import { MeanTimeToRecoveryTooltip } from './tooltip' - -const dateFormatter = date => { - return format(new Date(date), "MMM d") -} +import useMeanTimeToRestore from './meantimetorestore' +import { dateFormatter, dayFormatter } from '@/lib/date-funcs'; const calculateMean = data => { if (data.length < 1) { @@ -17,7 +15,7 @@ const calculateMean = data => { return data.reduce((prev, current) => prev + current) / data.length } -export function IsolatedMeanTimeToRecoveryChart({ data }) { +export function MeanTimeToRecoveryChart({ appName, dateRange }) { const { resolvedTheme } = useTheme() const animationDuration = 1000 @@ -36,27 +34,34 @@ export function IsolatedMeanTimeToRecoveryChart({ data }) { const strokeRollingAverage = '#10b981' // Emerald 500 const strokeGoal = '#f59e0b' // Amber 500 + const { mttrData, loading } = useMeanTimeToRestore(appName, dateRange); + console.log('Chart mttrData: ', mttrData) + + if (loading) { + return
Loading...
; // Render loading state while data is being fetched + } + // Calculate the mean - const averages = data.map(element => { + const averages = mttrData.map(element => { return element.rollingAverage }) const chartMean = calculateMean(averages) - // Reports - const [reportMeanTimeToRecoveryData, setReportMeanTimeToRecoveryData] = useState(null) - const [showReportMeanTimeToRecoveryData, setShowReportMeanTimeToRecoveryData] = useState(false) + // // Reports + // const [reportMeanTimeToRecoveryData, setReportMeanTimeToRecoveryData] = useState(null) + // const [showReportMeanTimeToRecoveryData, setShowReportMeanTimeToRecoveryData] = useState(false) - function handleChartClick(event) { - setReportMeanTimeToRecoveryData(event) - setShowReportMeanTimeToRecoveryData(true) - } + // function handleChartClick(event) { + // setReportMeanTimeToRecoveryData(event) + // setShowReportMeanTimeToRecoveryData(true) + // } - // Anomaly detection - const showAnomalyWarning = data.some((day) => { - if (day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1]) { return true } - return false - }) + // // Anomaly detection + // const showAnomalyWarning = data.some((day) => { + // if (day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1]) { return true } + // return false + // }) const customAnomalyLabel = props => { return ( @@ -70,20 +75,20 @@ export function IsolatedMeanTimeToRecoveryChart({ data }) { return ( <> - + - - `${tick}d`} /> + + } cursor={{ stroke: strokeCursor }} /> - + - {data.map((day, index) => ( + {/* {data.map((day, index) => ( day.rollingAverage < day.expectedRange[0] || day.rollingAverage > day.expectedRange[1] && ( ) - ))} + ))} */} {/* */} diff --git a/components/mean-time-to-recovery/meantimetorestore.js b/components/mean-time-to-recovery/meantimetorestore.js new file mode 100644 index 0000000..7d9af01 --- /dev/null +++ b/components/mean-time-to-recovery/meantimetorestore.js @@ -0,0 +1,29 @@ +// components/deploymentFrequency.js +import { useState, useEffect } from 'react'; +import { getDaysBetweenDates } from '@/components/date-range-selector' + +export default function useMeanTimeToRestore(appName, dateRange) { + const [mttrData, setMttrData] = useState([]); + const [loading, setLoading] = useState(true); // Add loading state + + useEffect(() => { + const fetchData = async () => { + try { + const req = `${process.env.NEXT_PUBLIC_PELORUS_API_URL}/sdp/mean_time_to_restore/${appName}/data?range=${getDaysBetweenDates(dateRange)}d&start=${dateRange.to.getTime() / 1000}`; + console.log(req) + const response = await fetch(req); + const data = await response.json(); + const sortedData = data.sort((d1, d2) => (d1.timestamp > d2.timestamp) ? 1 : (d1.timestamp < d2.timestamp) ? -1 : 0); + setMttrData(sortedData); + } catch (error) { + console.error('Error fetching deployment frequency data:', error); + } finally { + setLoading(false); // Set loading to false regardless of success or failure + } + }; + + fetchData(); + }, [appName, dateRange]); + + return { mttrData, loading }; // Return loading state along with dfData +} \ No newline at end of file diff --git a/components/mean-time-to-recovery/table.jsx b/components/mean-time-to-recovery/table.jsx index 17266c4..b98fbe3 100644 --- a/components/mean-time-to-recovery/table.jsx +++ b/components/mean-time-to-recovery/table.jsx @@ -9,290 +9,54 @@ import { TableHeader, TableRow, } from "@/components/ui/table" -import { Calendar, GitBranch, GitCommit, Globe, Timer } from "lucide-react" +import { Orbit, FileCode, CalendarCheck, Ticket, Timer } from "lucide-react" +import useMeanTimeToRestore from "./meantimetorestore"; +import { dateFormatter, dayFormatter } from '@/lib/date-funcs'; + +export function MeanTimeToRecoveryTable({ dateRange, appName }) { + + const { mttrData, loading } = useMeanTimeToRestore(appName, dateRange); + console.log('Table mttrData: ', mttrData) + + if (loading) { + return
Loading...
; // Render loading state while data is being fetched + } -export function MeanTimeToRecoveryTable({ data }) { return ( - Failed deployment - Pull request - Mean time - Status + Ticket Reference + App Name + Time to Resolve + Date Resolved - - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
- - -
- Main -
-
- project-crimson-prototype-q6yb8whv -
-
Jul 19, 2023
-
- -
- Feature/authentication -
-
- 0577e50 Commit name description -
-
Jul 26, 2023
-
- -
- - 8 days -
-
-
Ready
-
+ {mttrData.map (({ issue_id, time_to_resolve, timestamp }) => ( + + +
+ {issue_id} +
+
+ +
+ {appName} +
+
+ +
+ {dayFormatter(time_to_resolve)} +
+
+ +
+ { dateFormatter(timestamp) } +
+
+
+ ))}
) diff --git a/components/mean-time-to-recovery/tooltip.jsx b/components/mean-time-to-recovery/tooltip.jsx index a21aa30..81da4a2 100644 --- a/components/mean-time-to-recovery/tooltip.jsx +++ b/components/mean-time-to-recovery/tooltip.jsx @@ -23,7 +23,7 @@ export const MeanTimeToRecoveryTooltip = ({ active, payload, label }) => { if (active && payload && payload.length) { return (
-
{format(new Date(label), "MMM d, y")}
+
{format(new Date(label * 1000), "MMM d, y")}
{payload.map((data, index) => (
diff --git a/package.json b/package.json index d886a9d..aae0817 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "eslint-config-next": "13.4.12", "framer-motion": "^10.13.1", "init": "^0.1.2", - "lucide-react": "^0.263.1", + "lucide-react": "^0.315.0", "next": "^13.4.12", "next-auth": "^4.22.3", "next-themes": "^0.2.1",