Files
supabase/apps/studio/tests/components/AuditLogs/OrgAuditLogs.utils.test.ts
T
Samir Ketema d666b950ff feat: update audit log schema & UI (#45389)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

- Update to the audit log schema (changes were already applied in
staging)
- Updates the org & project audit log page to reflect the changes to the
schema
- The schema should be agnostic to whether logs were emitted to logflare
with the old & new schema format - the backend adjusts old logs to the
new format.

## What is the current behavior?

Currently, the frontend is parsing the legacy schema as the backend
returns this by default. It also doesn't show some of these new fields
yet.

## What is the new behavior?

### Org Audit Logs - Table View
<img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 27 22"
src="https://github.com/user-attachments/assets/47fec068-1ffa-4e52-bc46-3bffdef55adb"
/>

### Org Audit Logs - Single log View

<img width="1842" height="1494" alt="CleanShot 2026-04-29 at 18 27 37"
src="https://github.com/user-attachments/assets/3cff3bdf-4a6a-4981-acaa-7f95bb3ae9cf"
/>

Note that the `Target` field is no longer there. We just show the
`metadata` JSON.
<img width="1842" height="1494" alt="CleanShot 2026-04-29 at 18 27 40"
src="https://github.com/user-attachments/assets/d2e681f0-41a6-4bc7-a3d7-ec7e8101616c"
/>

### Account (Profile) Audit Logs - Table View

<img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 25 20"
src="https://github.com/user-attachments/assets/c72e19df-9b82-4611-8889-7af463769550"
/>

### Account (Profile) Audit Logs - Single log View

<img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 25 32"
src="https://github.com/user-attachments/assets/46f8d3b6-4f2f-4944-b891-431a93e5f3c3"
/>

## Additional context

⚠️ currently leaving the `do not merge` tag on, until:
- [x] I have verified it works in staging
- [x] We've deployed the new schema to production


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

* **New Features**
* Audit logs now use the v2 format with microsecond-accurate timestamps,
improved ordering, and a revamped details panel showing clearer
actor/action/request/project/org fields and fallback labels.
* Page/header layout updated so audit logs render at top level with
adjusted spacing.

* **Refactor**
* Shared sorting and filtering utilities added for consistent
user/project filtering and non-mutating log sorting.

* **Tests**
* Added tests for timestamp conversion, sorting, filtering, and
date-range formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-30 13:52:16 -07:00

84 lines
2.3 KiB
TypeScript

import dayjs from 'dayjs'
import { afterEach, describe, expect, test, vi } from 'vitest'
import { formatSelectedDateRange } from '@/components/interfaces/Organization/AuditLogs/AuditLogs.utils'
// Pin "now" to a fixed point so date comparisons are deterministic
const NOW = dayjs('2024-06-15T14:30:00')
afterEach(() => {
vi.useRealTimers()
})
function fakeNow() {
vi.setSystemTime(NOW.toDate())
}
describe('formatSelectedDateRange', () => {
test('two different dates: preserves current time on both ends', () => {
fakeNow()
const result = formatSelectedDateRange({
from: '2024-06-10',
to: '2024-06-14',
})
const from = dayjs(result.from)
const to = dayjs(result.to)
expect(from.date()).toBe(10)
expect(to.date()).toBe(14)
// Both should carry current H:M:S
expect(from.hour()).toBe(NOW.hour())
expect(to.hour()).toBe(NOW.hour())
})
test('single date matching today: from is set to 00:00:00', () => {
fakeNow()
const today = NOW.format('YYYY-MM-DD')
const result = formatSelectedDateRange({ from: today, to: today })
const from = dayjs(result.from)
expect(from.hour()).toBe(0)
expect(from.minute()).toBe(0)
expect(from.second()).toBe(0)
})
test('single date matching today: to keeps current time', () => {
fakeNow()
const today = NOW.format('YYYY-MM-DD')
const result = formatSelectedDateRange({ from: today, to: today })
const to = dayjs(result.to)
expect(to.hour()).toBe(NOW.hour())
expect(to.minute()).toBe(NOW.minute())
})
test('single date in the past: to is set to 23:59:59', () => {
fakeNow()
const result = formatSelectedDateRange({
from: '2024-06-01',
to: '2024-06-01',
})
const to = dayjs(result.to)
expect(to.hour()).toBe(23)
expect(to.minute()).toBe(59)
expect(to.second()).toBe(59)
})
test('single date in the past: from keeps current time', () => {
fakeNow()
const result = formatSelectedDateRange({
from: '2024-06-01',
to: '2024-06-01',
})
const from = dayjs(result.from)
expect(from.hour()).toBe(NOW.hour())
})
test('output is in UTC ISO format', () => {
fakeNow()
const result = formatSelectedDateRange({
from: '2024-06-10',
to: '2024-06-14',
})
expect(result.from).toMatch(/Z$/)
expect(result.to).toMatch(/Z$/)
})
})