-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
395 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
ui/app/mirrors/edit/[mirrorId]/aggregatedCountsByInterval.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import moment from 'moment'; | ||
|
||
type timestampType = { | ||
timestamp: Date; | ||
count: number; | ||
}; | ||
|
||
function aggregateCountsByInterval( | ||
timestamps: timestampType[], | ||
interval: string | ||
): [string, number][] { | ||
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: { [key: string]: number } = {}; | ||
|
||
// Iterate through the timestamps and populate the aggregatedCounts object | ||
for (let { timestamp, count } of timestamps) { | ||
const date = roundUpToNearest15Minutes(timestamp); | ||
const formattedTimestamp = moment(date).format(timeUnit); | ||
|
||
if (!aggregatedCounts[formattedTimestamp]) { | ||
aggregatedCounts[formattedTimestamp] = 0; | ||
} | ||
|
||
aggregatedCounts[formattedTimestamp] += count; | ||
} | ||
|
||
// Create an array of intervals between the start and end timestamps | ||
const intervals = []; | ||
|
||
let currentTimestamp = new Date(); | ||
|
||
if (interval === '15min') { | ||
currentTimestamp = roundUpToNearest15Minutes(currentTimestamp); | ||
} | ||
|
||
while (intervals.length < 30) { | ||
intervals.push(moment(currentTimestamp).format(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: [string, number][] = intervals.map((interval) => [ | ||
interval, | ||
aggregatedCounts[interval] || 0, | ||
]); | ||
|
||
return resultArray; | ||
} | ||
|
||
function roundUpToNearest15Minutes(date: 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; | ||
} | ||
|
||
export default aggregateCountsByInterval; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,117 @@ | ||
'use client'; | ||
import { FlowConnectionConfigs } from '@/grpc_generated/flow'; | ||
import { Badge } from '@/lib/Badge'; | ||
import { Icon } from '@/lib/Icon'; | ||
import { Label } from '@/lib/Label'; | ||
import moment from 'moment'; | ||
import CdcGraph from './cdcGraph'; | ||
|
||
type CDCDetailsProps = { | ||
config: FlowConnectionConfigs | undefined; | ||
import PeerButton from '@/components/PeerComponent'; | ||
import { dBTypeFromJSON } from '@/grpc_generated/peers'; | ||
|
||
type SyncStatusRow = { | ||
batchId: number; | ||
startTime: Date; | ||
endTime: Date | null; | ||
numRows: number; | ||
}; | ||
|
||
export default function CDCDetails({ config }: CDCDetailsProps) { | ||
if (!config) { | ||
return <div className='text-red-500'>No configuration provided</div>; | ||
} | ||
type props = { | ||
syncs: SyncStatusRow[]; | ||
mirrorConfig: FlowConnectionConfigs | undefined; | ||
}; | ||
function CdcDetails({ syncs, mirrorConfig }: props) { | ||
let lastSyncedAt = moment(syncs[0]?.startTime).fromNow(); | ||
let rowsSynced = syncs.reduce((acc, sync) => acc + sync.numRows, 0); | ||
|
||
return ( | ||
<div className='p-4 rounded-md'> | ||
<h2 className='text-xl font-semibold mb-4'>CDC Details</h2> | ||
<div className='overflow-x-auto'> | ||
<table className='min-w-full divide-y divide-gray-300'> | ||
<tbody> | ||
<tr> | ||
<td className='px-4 py-2 font-medium'>Source</td> | ||
<td className='px-4 py-2'>{config.source?.name || '-'}</td> | ||
</tr> | ||
<tr> | ||
<td className='px-4 py-2 font-medium'>Destination</td> | ||
<td className='px-4 py-2'>{config.destination?.name || '-'}</td> | ||
</tr> | ||
<tr> | ||
<td className='px-4 py-2 font-medium'>Flow Job Name</td> | ||
<td className='px-4 py-2'>{config.flowJobName}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
<> | ||
<div className='mt-10'> | ||
<div className='flex flex-row'> | ||
<div className='basis-1/4 md:basis-1/3'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Status | ||
</Label> | ||
</div> | ||
<div> | ||
<Label variant='body'> | ||
<Badge variant='positive' key={1}> | ||
<Icon name='play_circle' /> | ||
Active | ||
</Badge> | ||
</Label> | ||
</div> | ||
</div> | ||
<div className='basis-1/4 md:basis-1/3'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Mirror Type | ||
</Label> | ||
</div> | ||
<div> | ||
<Label variant='body'>CDC</Label> | ||
</div> | ||
</div> | ||
<div className='basis-1/4 md:basis-1/3'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Source | ||
</Label> | ||
</div> | ||
<div> | ||
<PeerButton | ||
peerName={mirrorConfig?.source?.name ?? ''} | ||
peerType={dBTypeFromJSON(mirrorConfig?.source?.type)} | ||
/> | ||
</div> | ||
</div> | ||
<div className='basis-1/4 md:basis-1/3'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Destination | ||
</Label> | ||
</div> | ||
<div> | ||
<PeerButton | ||
peerName={mirrorConfig?.destination?.name ?? ''} | ||
peerType={dBTypeFromJSON(mirrorConfig?.destination?.type)} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
<div className='flex flex-row mt-10'> | ||
<div className='basis-1/4'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Last Sync | ||
</Label> | ||
</div> | ||
<div> | ||
<Label variant='body'>{lastSyncedAt}</Label> | ||
</div> | ||
</div> | ||
<div className='basis-1/4'> | ||
<div> | ||
<Label variant='subheadline' colorName='lowContrast'> | ||
Rows synced | ||
</Label> | ||
</div> | ||
<div> | ||
<Label variant='body'>{numberWithCommas(rowsSynced)}</Label> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div className='mt-10'> | ||
<CdcGraph syncs={syncs} /> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
function numberWithCommas(x: Number): string { | ||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); | ||
} | ||
|
||
export default CdcDetails; |
Oops, something went wrong.