Files
supabase/apps/studio/components/ui/DataTable/DataTable.utils.ts
Danny White e5df232b44 fix(studio): polish unified logs row alignment and success colours (#47829)
## What kind of change does this PR introduce?

UI polish

## What is the current behavior?

Unified logs row chrome is slightly misaligned (checkbox vs filter
toggle, uneven gaps around the level dot), success grey is too dark and
doesn’t match the Level key, and log-type icons read a bit heavy.

## What is the new behavior?

- Aligns the row checkbox with the filter sidebar toggle and spaces the
level dot evenly between checkbox and timestamp
- Drops the checkbox `translate-y` nudge in favour of normal middle
alignment
- Introduces `--chart-success` so the chart and Level key/dots share a
lighter grey
- Softens log-type icon colour on each row

| Before | After |
| --- | --- |
| <img width="1024" height="759" alt="1293"
src="https://github.com/user-attachments/assets/af7ab83f-8917-41cb-99f3-1c1f92df769e"
/> | <img width="1024" height="759" alt="52159"
src="https://github.com/user-attachments/assets/9b859308-2101-4a02-bdc1-75e5750f84fa"
/> |


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
* Improved Unified Logs table spacing and alignment, including narrower
selection and level columns.
  * Refined checkbox and date-cell presentation for a cleaner layout.
  * Updated log type icons to use muted foreground styling.

* **Bug Fixes**
* Success statuses and chart indicators now consistently use the
dedicated success color across light and dark themes.


<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-11 03:13:41 +10:00

90 lines
2.8 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-[var(--chart-success)] group-data-[state=selected]/row:bg-foreground-lighter',
border:
'border-[var(--chart-success)] group-data-[state=selected]/row:border-foreground-lighter',
}
case 'warning':
return {
text: 'text-warning',
bg: 'bg-warning',
border: 'border-warning',
}
case 'error':
return {
text: 'text-destructive',
bg: 'bg-destructive',
border: 'border-destructive',
}
default:
return {
text: 'text-info',
bg: 'bg-info',
border: 'border-info',
}
}
}