Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9c7a8ff
feat(audit-log): split changes from data access, add resource/action/…
Makisuo Nov 9, 2026
add9406
feat(audit-log): filter from an entry's detail, name members, show wh…
Makisuo Nov 9, 2026
8b8805a
feat(audit-log): day headings, a red edge on refusals, quieter reads
Makisuo Nov 9, 2026
7312a1b
chore(ui): index the day-label page kit module
Makisuo Nov 9, 2026
44f4017
fix(audit-log): mute reads only in the All view
Makisuo Nov 9, 2026
789d476
fix(audit-log): a shared entry link opens its entry however busy that…
Makisuo Nov 9, 2026
391e40d
Merge branch 'audit-log-ui/b-detail-pivots' into audit-log-ui/c-rows-…
Makisuo Nov 9, 2026
aba17d0
refactor(audit-log): one access-action list for the server and the web
Makisuo Nov 9, 2026
14c88ee
test(audit-log): a filter change drops the shared entry link
Makisuo Nov 9, 2026
bd28017
Merge branch 'audit-log-ui/b-detail-pivots' into audit-log-ui/c-rows-…
Makisuo Nov 9, 2026
ea5fbdc
feat(audit-log): icons for the kind of action, the actor, the surface…
Makisuo Nov 10, 2026
5bbc8e8
fix(audit-log): the action keeps its room beside the resource, every …
Makisuo Nov 10, 2026
9833c48
Merge remote-tracking branch 'origin/main' into audit-log-ui/a-views-…
Makisuo Nov 10, 2026
b491fc3
Merge branch 'audit-log-ui/b-detail-pivots' into audit-log-ui/c-rows-…
Makisuo Nov 10, 2026
924400a
Merge branch 'audit-log-ui/a-views-filters' into audit-log-ui/b-detai…
Makisuo Nov 10, 2026
f637218
Merge branch 'audit-log-ui/c-rows-layout' into audit-log-ui/d-icons
Makisuo Nov 10, 2026
9eea2ea
docs(audit-log): the action label's doc comment sits on its function …
Makisuo Nov 10, 2026
e9a39df
Merge branch 'audit-log-ui/c-rows-layout' into audit-log-ui/d-icons
Makisuo Nov 10, 2026
81ba0ce
fix(audit-log): an entry Maple itself made still names its surface
Makisuo Nov 10, 2026
0b85f10
Merge branch 'audit-log-ui/b-detail-pivots' into audit-log-ui/c-rows-…
Makisuo Nov 10, 2026
7bd013d
Merge branch 'audit-log-ui/c-rows-layout' into audit-log-ui/d-icons
Makisuo Nov 10, 2026
6398dc5
feat(audit-log): a consistency pass over the list, filters and entry …
Makisuo Nov 10, 2026
6b46d45
Merge branch 'main' into audit-log-ui/b-detail-pivots
Makisuo Nov 10, 2026
e77896b
fix(audit-log): review findings on the consistency pass
Makisuo Nov 10, 2026
7fbd842
fix(audit-log): Filter from a shared entry link leaves that link's on…
Makisuo Nov 10, 2026
669d9ed
Merge branch 'audit-log-ui/b-detail-pivots' into audit-log-ui/c-rows-…
Makisuo Nov 10, 2026
33f2691
Merge branch 'main' into audit-log-ui/c-rows-layout
Makisuo Nov 10, 2026
c6d9ed8
Merge branch 'audit-log-ui/c-rows-layout' into audit-log-ui/d-icons
Makisuo Nov 10, 2026
d28aeb9
Merge branch 'main' into audit-log-ui/d-icons
Makisuo Nov 10, 2026
f07b432
Merge branch 'audit-log-ui/d-icons' into audit-log-ui/e-design-pass
Makisuo Nov 10, 2026
6d48f87
fix(audit-log): the custom range calendar is no longer clipped to the…
Makisuo Nov 10, 2026
4f9003f
fix(audit-log): Escape closes the date range popover from its calendar
Makisuo Nov 10, 2026
c358bbb
Merge branch 'main' into audit-log-ui/e-design-pass
Makisuo Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions apps/web/src/lab/audit-log-lab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,13 @@ const answer = (state: LabState, model: AuditModel.Model, commands: ReadonlyArra
).model
}

/** The kit's own commands and the custom range's clock read; every API read is answered above. */
/** The kit's own commands and the custom range's clock read and focus; every API read is answered above. */
const local = (commands: ReadonlyArray<AuditCommand> | undefined) => [
...keepLocal(commands),
...Arr.filter(commands ?? [], (command) => command.name === "ResolveAuditCustomToday"),
...Arr.filter(
commands ?? [],
(command) => command.name === "ResolveAuditCustomToday" || command.name === "FocusAuditDateRange",
),
]

const lift = (commands: ReadonlyArray<AuditCommand>) =>
Expand Down
39 changes: 39 additions & 0 deletions apps/web/src/page/settings/audit-log/audit-log.scene.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,20 @@ describe("audit log tab", () => {
expect(picked.model.customRange).toBeNull()
})

test("opening the custom range moves focus into the popover, so Escape still closes it", () => {
const search = { tab: "audit-log" } as const
const opened = update(
init(search).model,
Message.ResolvedCustomToday({
timeZone: "UTC",
today: { year: 2026, month: 11, day: 9 },
lastDay: { year: 2026, month: 11, day: 9 },
}),
search,
)
expect(Arr.map(opened.commands ?? [], ({ name }) => name)).toEqual(["FocusAuditDateRange"])
})

describe("an entry's detail", () => {
const search = { tab: "audit-log" } as const
const loadedWith = (searchFor: typeof SettingsSearch.Type) => {
Expand Down Expand Up @@ -422,6 +436,31 @@ describe("audit log tab", () => {
scene(sceneOf(search), given(opened), expectView(text("Surface")).toExist())
})

test("an open entry offers a filter beside its actor, action and resource", () => {
const target = AUDIT_ENTRIES[2]
if (target === undefined) throw new Error("fixture")
const opened = update(
loadedWith(search).model,
Message.ToggledEntry({ id: target.id }),
search,
).model
scene(
sceneOf(search),
given(opened),
expectView(role("button", { name: "Show every entry with this actor" })).toExist(),
expectView(role("button", { name: "Show every entry with this action" })).toExist(),
expectView(role("button", { name: "Show every entry with this resource" })).toExist(),
)
})

test("a row names the kind of actor behind an API key", () => {
scene(
sceneOf(search),
given(loadedWith(search).model),
expectView(role("img", { name: "API key" })).toExist(),
)
})

test("the Origin section names the country an entry came from", () => {
const target = AUDIT_ENTRIES[4]
if (target === undefined) throw new Error("fixture")
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/page/settings/audit-log/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,6 @@ export const Message = defineMessageUnion({
/** "Filter" beside a value in an entry's detail: the filter key and the value to filter by. */
ClickedPivot: { key: Schema.String, value: Schema.String },
CompletedScrollToEntry: {},
CompletedFocusDateRange: {},
})
export type Message = typeof Message.Type
16 changes: 15 additions & 1 deletion apps/web/src/page/settings/audit-log/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { formatWarehouseDateTime, parseWarehouseDateTime } from "@maple/query-engine/datetime"
import * as CustomRange from "../../kit/custom-range"
import { Clock, DateTime, Effect, Option, Result, Schema, Array as Arr, String as Str } from "effect"
import { Command } from "foldkit"
import { Command, Dom } from "foldkit"
import { toLoadFailure } from "@maple/views/data/load-failure"
import { isClerkAuthEnabled } from "../../../lib/services/common/auth-mode"
import { MapleApiV2Client } from "../../../platform/api-clients"
Expand All @@ -24,6 +24,7 @@ import { memberDisplayName } from "../kit/members"
import { AppRoute, hrefOf } from "../../../route"
import type { SettingsSearch as SettingsSearchSchema } from "../../../route/search"
import * as CopyButton from "@maple/views/ui/copy-button"
import { popupId } from "@maple/views/ui/overlay/popup-state"
import * as Popover from "@maple/views/ui/popover"
import * as Select from "@maple/views/ui/select"
import { PageOutMessage, type PageReturn } from "../../contract"
Expand Down Expand Up @@ -324,6 +325,17 @@ const ScrollToAuditEntry = Command.define("ScrollToAuditEntry", {
}),
})

/** Focus back inside the popover once the calendar replaces the pressed preset, so Escape still closes it. */
const FocusAuditDateRange = Command.define("FocusAuditDateRange", {
args: { id: Schema.String },
messages: [Message.CompletedFocusDateRange],
execute: ({ id }) =>
Dom.focus(`#${CSS.escape(popupId(id))}`).pipe(
Effect.ignore,
Effect.as(Message.CompletedFocusDateRange()),
),
})

/** The filters a detail pivot navigates to: the value replaces that filter, the rest stay. */
const pivoted = (filters: AuditLogFilters, key: string, value: string): AuditLogFilters => {
switch (key) {
Expand Down Expand Up @@ -485,6 +497,7 @@ export const update = (model: Model, message: Message, search: SettingsSearch):
)
},
CompletedScrollToEntry: () => ({ model }),
CompletedFocusDateRange: () => ({ model }),
ClickedCustomRange: ({ timeZone }) => ({ model, commands: [ResolveAuditCustomToday({ timeZone })] }),
ResolvedCustomToday: ({ timeZone, today, lastDay }) => {
const range = filters.range
Expand All @@ -499,6 +512,7 @@ export const update = (model: Model, message: Message, search: SettingsSearch):
lastDay,
}),
),
commands: [FocusAuditDateRange({ id: model.dateRange.id })],
}
},
GotCustomRangeMessage: ({ message: child }) => {
Expand Down
Loading
Loading