diff --git a/ui/app/mirrors/edit/[mirrorId]/aggregatedCountsByInterval.js b/ui/app/mirrors/edit/[mirrorId]/aggregatedCountsByInterval.js new file mode 100644 index 0000000000..89acfd648c --- /dev/null +++ b/ui/app/mirrors/edit/[mirrorId]/aggregatedCountsByInterval.js @@ -0,0 +1,126 @@ +function aggregateCountsByInterval(timestamps, interval, startTimestamp, endTimestamp) { + //startTimestamp = roundUpToNearest15Minutes(startTimestamp); + // Define the time unit based on the provided interval + let timeUnit; + switch (interval) { + case 'hour': + timeUnit = 'YYYY-MM-DD HH:00:00'; + break; + case '15min': + timeUnit = 'YYYY-MM-DD HH:mm'; + break; + case 'month': + timeUnit = 'YYYY-MM'; + break; + case 'day': + timeUnit = 'YYYY-MM-DD'; + break; + default: + throw new Error('Invalid interval provided'); + } + + // Create an object to store the aggregated counts + const aggregatedCounts = {}; + + // Iterate through the timestamps and populate the aggregatedCounts object + for (let { timestamp, count } of timestamps) { + timestamp = roundUpToNearest15Minutes(timestamp); + const date = new Date(timestamp); + const formattedTimestamp = formatTimestamp(date, timeUnit); + + if (!aggregatedCounts[formattedTimestamp]) { + aggregatedCounts[formattedTimestamp] = 0; + } + + aggregatedCounts[formattedTimestamp] += count; + } + + + // Get the start and end timestamps or use the earliest and latest timestamps from the data + //const firstTimestamp = new Date(timestamps[0].timestamp); + //const lastTimestamp = new Date(timestamps[timestamps.length - 1].timestamp); + //startTimestamp = startTimestamp ? new Date(startTimestamp) : firstTimestamp; + //endTimestamp = endTimestamp ? new Date(endTimestamp) : lastTimestamp; + + // Create an array of intervals between the start and end timestamps + const intervals = []; + //let currentTimestamp = new Date(startTimestamp); + let currentTimestamp = new Date(); + + if(interval === "15min"){ + currentTimestamp = roundUpToNearest15Minutes(currentTimestamp); + } + + while (intervals.length < 30) { + intervals.push(formatTimestamp(currentTimestamp, timeUnit)); + if (interval === 'hour') { + currentTimestamp.setHours(currentTimestamp.getHours() - 1); + } else if (interval === '15min') { + currentTimestamp.setMinutes(currentTimestamp.getMinutes() - 15); + } else if (interval === 'month') { + currentTimestamp.setMonth(currentTimestamp.getMonth() - 1); + } else if(interval === 'day'){ + currentTimestamp.setDate(currentTimestamp.getDate() - 1); + } + } + + // Populate the result array with intervals and counts + const resultArray = intervals.map((interval) => [interval, aggregatedCounts[interval] || 0]); + return resultArray; + } + + function roundUpToNearest15Minutes(date) { + const minutes = date.getMinutes(); + const remainder = minutes % 15; + + if (remainder > 0) { + // Round up to the nearest 15 minutes + date.setMinutes(minutes + (15 - remainder)); + } + + // Reset seconds and milliseconds to zero to maintain the same time + date.setSeconds(0); + date.setMilliseconds(0); + + return date; + } + + // Helper function to format a timestamp + function formatTimestamp(date, format) { + const year = date.getFullYear(); + const month = padZero(date.getMonth() + 1); // Months are zero-based + const day = padZero(date.getDate()); + const hour = padZero(date.getHours()); + const minutes = padZero(date.getMinutes()); + + return format + .replace('YYYY', year) + .replace('MM', month) + .replace('DD', day) + .replace('HH', hour) + .replace('mm', minutes); + } + + // Helper function to pad single digits with leading zeros + function padZero(number) { + return number < 10 ? `0${number}` : `${number}`; + } + +// // Example usage +// const timestamps = [ +// { timestamp: '2023-11-03T09:30:00', count: 5 }, +// { timestamp: '2023-11-03T10:15:00', count: 10 }, +// { timestamp: '2023-11-03T11:45:00', count: 7 }, +// // Add more timestamps as needed +// ]; + +// const resultByHour = aggregateCountsByInterval(timestamps, 'hour', '2023-11-03T09:00:00', '2023-11-03T11:00:00'); +// const resultBy15Min = aggregateCountsByInterval(timestamps, '15min', '2023-11-03T09:00:00', '2023-11-03T11:30:00'); +// const resultByMonth = aggregateCountsByInterval(timestamps, 'month', '2023-11-01', '2023-11-03'); + +// console.log('Counts by Hour:', resultByHour); +// console.log('Counts by 15 Minutes:', resultBy15Min); +// console.log('Counts by Month:', resultByMonth); + + +export default aggregateCountsByInterval \ No newline at end of file diff --git a/ui/app/mirrors/edit/[mirrorId]/cdcGraph.tsx b/ui/app/mirrors/edit/[mirrorId]/cdcGraph.tsx new file mode 100644 index 0000000000..701076b669 --- /dev/null +++ b/ui/app/mirrors/edit/[mirrorId]/cdcGraph.tsx @@ -0,0 +1,82 @@ +import { Label } from '@/lib/Label'; +import { useState, useEffect } from 'react'; +import { format } from 'date-fns' + +type SyncStatusRow = { + batchId: number; + startTime: Date; + endTime: Date | null; + numRows: number; +}; + +import aggregateCountsByInterval from './aggregatedCountsByInterval' + + function CdcGraph({syncs}:{syncs:SyncStatusRow[]}) { + + let [aggregateType,setAggregateType] = useState('hour'); + let [counts,setCounts] = useState([]); + + + let rows = syncs.map((sync) => ({ + timestamp: sync.startTime, + count: sync.numRows, + })) + + useEffect(()=>{ + let counts = aggregateCountsByInterval(rows,aggregateType, undefined, new Date()); + counts = counts.slice(0,29) + counts = counts.reverse(); + setCounts(counts) + + },[aggregateType, rows]) + + return