Skip to content

Commit c927f2f

Browse files
david-crespobenjaminleonardfakemonster
authored
Audit log (#2860)
https://console-git-audit-log-oxidecomputer.vercel.app/system/audit-log Copied from [#2849](<#2849>), which I accidentally merged and couldn't reopen even after I fixed `main`. --- Still very rough, but has been a helpful exercise in working through some of the design due to the sheer amount of information and differing layout from other pages. https://github.com/user-attachments/assets/84cbb9f6-d22b-4e64-9b1d-e39d74d22902 Stubbing out based on [https://github.com/oxidecomputer/omicron/pull/7339](<https://github.com/oxidecomputer/omicron/pull/7339>). Uses [Tanstack Virtual](<https://tanstack.com/virtual/latest>). On testing with > 500 lines without virtualisation it starts to get a bit chunky especially if you're interacting with the page (e.g. opening the row). Hoping that silo name and actor display name can be plumbed through so those are hard-coded for now. Still needs: - [X] Error state - [X] Loading/placeholder state - [X] Copy JSON to clipboard - [ ] Equivalent CLI/API command - [X] Fix giant footer spacing - [X] Arrow key selected item navigation - [X] Hide overflowing columns - [X] Improved focus visible look - [ ] Timestamp hover - [X] Fix gradient on light mode - [X] Syntax highlighting --------- Co-authored-by: Benjamin Leonard <benji@oxide.computer> Co-authored-by: Joe Thel <joe.thel@oxidecomputer.com>
1 parent c1e623c commit c927f2f

25 files changed

Lines changed: 1388 additions & 47 deletions

‎app/components/form/fields/DateTimeRangePicker.tsx‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ const tz = getLocalTimeZone()
4242

4343
/**
4444
* Exposes `startTime` and `endTime` plus the whole set of picker UI controls as
45-
* a JSX element to render. When we're using a relative preset like last N
46-
* hours, automatically slide the window forward live by updating the range to
47-
* have `endTime` of _now_ every `SLIDE_INTERVAL` ms.
45+
* a JSX element to render.
4846
*/
4947
export function useDateTimeRangePicker({
5048
initialPreset,
@@ -84,15 +82,17 @@ export function useDateTimeRangePicker({
8482
items,
8583
}
8684

87-
// Without these useMemos, we get re-renders every 400ms because when the
88-
// debounce timeout expires, it updates the value, which triggers a render for
89-
// itself because the time gets remade by toDate() (i.e., even though it is
90-
// the same time, it is a new object)
91-
const rangeStart = useMemo(() => range.start.toDate(tz), [range.start])
92-
const [startTime] = useDebounce(rangeStart, 400)
93-
94-
const rangeEnd = useMemo(() => range.end.toDate(tz), [range.end])
95-
const [endTime] = useDebounce(rangeEnd, 400)
85+
// Debounce only while a custom range is being edited: the date fields fire
86+
// onChange on every keystroke. Picking a preset is a single deliberate action
87+
// and applies immediately. The range is debounced as one value so start and
88+
// end can't land in separate renders and fire a request for a mixed range.
89+
const [debouncedRange] = useDebounce(range, 400)
90+
const effectiveRange = preset === 'custom' ? debouncedRange : range
91+
92+
// toDate() makes a new Date each call, so memoize on the stable DateValue to
93+
// keep the query key from changing on every render
94+
const startTime = useMemo(() => effectiveRange.start.toDate(tz), [effectiveRange.start])
95+
const endTime = useMemo(() => effectiveRange.end.toDate(tz), [effectiveRange.end])
9696

9797
return {
9898
startTime,

‎app/layouts/SystemLayout.tsx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
Access16Icon,
1313
Cloud16Icon,
1414
IpGlobal16Icon,
15+
Logs16Icon,
1516
Metrics16Icon,
1617
Servers16Icon,
1718
SoftwareUpdate16Icon,
@@ -57,6 +58,7 @@ export default function SystemLayout() {
5758
{ value: 'Subnet Pools', path: pb.subnetPools() },
5859
{ value: 'System Update', path: pb.systemUpdate() },
5960
{ value: 'Fleet Access', path: pb.fleetAccess() },
61+
{ value: 'Audit Log', path: pb.auditLog() },
6062
]
6163
// filter out the entry for the path we're currently on
6264
.filter((i) => i.path !== pathname)
@@ -107,6 +109,9 @@ export default function SystemLayout() {
107109
<NavLinkItem to={pb.fleetAccess()}>
108110
<Access16Icon /> Fleet Access
109111
</NavLinkItem>
112+
<NavLinkItem to={pb.auditLog()}>
113+
<Logs16Icon /> Audit Log
114+
</NavLinkItem>
110115
</Sidebar.Nav>
111116
</Sidebar>
112117
<ContentPane />

0 commit comments

Comments
 (0)