Files
supabase/apps/studio/components/ui/DataTable/DataTable.utils.ts
T
Joshen LimandJonathan Summers-Muir f223b455d6 Unified Logs (Part 1) (#36298)
* init new unified page

* moar logs

* init

* add infinite and live logs example

* Update useLogsPreview.tsx

* add more sources

* wrapped auth logs with edge logs

* add role and user id

* move unified logs

* init

* move demo pages. create a new directory to work in

* extracted beta unified logs into own components

* add example base page and components

* add new files to use actual logging query

* more organization

* change import

* adds new logs page. adds new query

* add data table to UI pacakges

* revert

* table styles

* text size

* add timestamp, table, icons for log types, status code styling

* add host

* add log count to edge functions

* starts to add dynamic filtering

* spiking trace UI

* Update status-code.ts

* add new linik

* now using POST

* fix chart data for default 1 hour view

* update API to accept POST requests

* new filters

* Update level.ts

* fixed up chart to work on level filter. split up the logic into new files

* prep for log type

* prepped query for WHERE

* fix: issue with white space in url param column parsing

* level param now being removed correctly.

* fix issue with chart showing wrong buckets for different time ranges

* remove old query

* refactor the queries into function for each source

* total count fixed

* lots of layout

* start fixing log counts

* comment out min and max for a while

* added trace logging prototype in

* random trace logs added for demo

* added logs and ui to view logs if any

* add Auth user

* fix the live logs issue

* some left over code

* Midway

* First pass refactor + clean up + reorganize files

* Fix TS issues

* Remove unused files

* Clean up

* Final clean up

* more clean up

* More clean up

* Remove unused packages

* Fix

* Lint

* Add feature flag for unified logs

* Refactor

* Remove trace UI

* Snake case log types

* more clean up

* More clean up

* Fix ts

* more clean up

* fixes

* add flag check and redirect if flag is false

* Update middleware.ts

* Nit lint

* Fix

* Last refactors

---------

Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
2025-06-20 12:46:17 +08:00

130 lines
3.6 KiB
TypeScript

import { FilterFn } from '@tanstack/react-table'
import { isAfter, isBefore, isSameDay } from 'date-fns'
import { LEVELS } from './DataTable.constants'
export function formatCompactNumber(value: number) {
if (value >= 100 && value < 1000) {
return value.toString() // Keep the number as is if it's in the hundreds
} else if (value >= 1000 && value < 1000000) {
return (value / 1000).toFixed(1) + 'k' // Convert to 'k' for thousands
} else if (value >= 1000000) {
return (value / 1000000).toFixed(1) + 'M' // Convert to 'M' for millions
} else {
return value.toString() // Optionally handle numbers less than 100 if needed
}
}
export function isArrayOfNumbers(arr: any): arr is number[] {
if (!Array.isArray(arr)) return false
return arr.every((item) => typeof item === 'number')
}
export function isArrayOfDates(arr: any): arr is Date[] {
if (!Array.isArray(arr)) return false
return arr.every((item) => item instanceof Date)
}
export function isArrayOfStrings(arr: any): arr is string[] {
if (!Array.isArray(arr)) return false
return arr.every((item) => typeof item === 'string')
}
export function isArrayOfBooleans(arr: any): arr is boolean[] {
if (!Array.isArray(arr)) return false
return arr.every((item) => typeof item === 'boolean')
}
export const inDateRange: FilterFn<any> = (row, columnId, value) => {
const date = new Date(row.getValue(columnId))
const [start, end] = value as Date[]
if (isNaN(date.getTime())) return false
// if no end date, check if it's the same day
if (!end) return isSameDay(date, start)
return isAfter(date, start) && isBefore(date, end)
}
inDateRange.autoRemove = (val: any) => !Array.isArray(val) || !val.length || !isArrayOfDates(val)
export const arrSome: FilterFn<any> = (row, columnId, filterValue) => {
if (!Array.isArray(filterValue)) return false
return filterValue.some((val) => row.getValue<unknown[]>(columnId) === val)
}
arrSome.autoRemove = (val: any) => !Array.isArray(val) || !val?.length
export function getLevelColor(
value: (typeof LEVELS)[number]
): Record<'text' | 'bg' | 'border', string> {
switch (value) {
case 'success':
return {
text: 'text-muted',
bg: 'bg-muted',
border: 'border-muted',
}
case 'warning':
return {
text: 'text-warning',
bg: 'bg-warning',
border: 'border-warning',
}
case 'error':
return {
text: 'text-destructive',
bg: 'bg-destructive',
border: 'border-destructive',
}
case 'info':
default:
return {
text: 'text-info',
bg: 'bg-info',
border: 'border-info',
}
}
}
export function getStatusColor(value?: number | string): Record<'text' | 'bg' | 'border', string> {
switch (value) {
case '1':
case 'info':
return {
text: 'text-blue-500',
bg: '',
border: 'border-blue-200 dark:border-blue-800',
}
case '2':
case 'success':
return {
text: 'text-foreground-lighter',
bg: '',
border: 'border-green-200 dark:border-green-800',
}
case '4':
case 'warning':
case 'redirect':
return {
text: 'text-warning-600 dark:text-warning',
bg: 'bg-warning-300 dark:bg-waning-200',
border: 'border border-warning-400/50 dark:border-warning-400/50',
}
case '5':
case 'error':
return {
text: 'text-destructive',
bg: 'bg-destructive-300 dark:bg-destructive-300/50',
border: 'border border-destructive-400/50 dark:border-destructive-400/50',
}
default:
return {
text: 'text-foreground-lighter',
bg: '',
border: '',
}
}
}