Improve USB policy history with filters and pagination

- Fix bug where APPLYING status would not transition to APPLIED
- Add status and date range filters to policy history
- Add cursor-based pagination with "Load more" button
- Use DateRangeButton component for date filtering
- Reset filters and pagination when switching filters

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
esdrasrenan 2025-12-06 23:24:23 -03:00
parent 5846c299ce
commit 873305fa7f
2 changed files with 212 additions and 48 deletions

View file

@ -117,7 +117,9 @@ export const reportUsbPolicyStatus = mutation({
.order("desc")
.first()
if (latestEvent && latestEvent.status === "PENDING") {
// Atualiza o evento se ainda nao foi finalizado (PENDING ou APPLYING)
// Isso permite a transicao: PENDING -> APPLYING -> APPLIED/FAILED
if (latestEvent && (latestEvent.status === "PENDING" || latestEvent.status === "APPLYING")) {
await ctx.db.patch(latestEvent._id, {
status: args.status,
error: errorValue,
@ -185,27 +187,57 @@ export const listUsbPolicyEvents = query({
args: {
machineId: v.id("machines"),
limit: v.optional(v.number()),
cursor: v.optional(v.number()),
status: v.optional(v.string()),
dateFrom: v.optional(v.number()),
dateTo: v.optional(v.number()),
},
handler: async (ctx, args) => {
const limit = args.limit ?? 50
const limit = args.limit ?? 10
const events = await ctx.db
let events = await ctx.db
.query("usbPolicyEvents")
.withIndex("by_machine_created", (q) => q.eq("machineId", args.machineId))
.order("desc")
.take(limit)
.collect()
return events.map((event) => ({
id: event._id,
oldPolicy: event.oldPolicy,
newPolicy: event.newPolicy,
status: event.status,
error: event.error,
actorEmail: event.actorEmail,
actorName: event.actorName,
createdAt: event.createdAt,
appliedAt: event.appliedAt,
}))
// Aplica filtro de cursor (paginacao)
if (args.cursor !== undefined) {
events = events.filter((e) => e.createdAt < args.cursor!)
}
// Aplica filtro de status
if (args.status) {
events = events.filter((e) => e.status === args.status)
}
// Aplica filtro de data
if (args.dateFrom !== undefined) {
events = events.filter((e) => e.createdAt >= args.dateFrom!)
}
if (args.dateTo !== undefined) {
events = events.filter((e) => e.createdAt <= args.dateTo!)
}
const hasMore = events.length > limit
const results = events.slice(0, limit)
const nextCursor = results.length > 0 ? results[results.length - 1].createdAt : undefined
return {
events: results.map((event) => ({
id: event._id,
oldPolicy: event.oldPolicy,
newPolicy: event.newPolicy,
status: event.status,
error: event.error,
actorEmail: event.actorEmail,
actorName: event.actorName,
createdAt: event.createdAt,
appliedAt: event.appliedAt,
})),
hasMore,
nextCursor,
}
},
})