chore: refactor audit page to use window function for count (#5133)

* Move count query to window function

* Unpack count and update types

* Remove count endpoint

* Update tests, wip

* Fix tests

* Update frontend, wip

* Remove space

* Fix frontend test

* Don't hang on error

* Handle no results

* Don't omit count

* Fix frontend tests
This commit is contained in:
Presley Pizzo
2022-11-21 11:30:41 -05:00
committed by GitHub
parent 7a369e0a30
commit 67941b4f80
15 changed files with 54 additions and 347 deletions
-8
View File
@@ -556,14 +556,6 @@ export const getAuditLogs = async (
return response.data
}
export const getAuditLogsCount = async (
options: TypesGen.AuditLogCountRequest = {},
): Promise<TypesGen.AuditLogCountResponse> => {
const url = getURLWithSearchParams("/api/v2/audit/count", options)
const response = await axios.get(url)
return response.data
}
export const getTemplateDAUs = async (
templateId: string,
): Promise<TypesGen.TemplateDAUsResponse> => {
+1 -10
View File
@@ -70,19 +70,10 @@ export interface AuditLog {
readonly user?: User
}
// From codersdk/audit.go
export interface AuditLogCountRequest {
readonly q?: string
}
// From codersdk/audit.go
export interface AuditLogCountResponse {
readonly count: number
}
// From codersdk/audit.go
export interface AuditLogResponse {
readonly audit_logs: AuditLog[]
readonly count: number
}
// From codersdk/audit.go
@@ -35,7 +35,7 @@ describe("readableActionMessage()", () => {
// Then
expect(friendlyString).toBe(
"<strong>TestUser</strong> updated workspace <strong>bruno-dev</strong>",
"<strong>TestUser</strong> created workspace <strong>bruno-dev</strong>",
)
})
})
+6 -21
View File
@@ -29,33 +29,22 @@ describe("AuditPage", () => {
describe("Filtering", () => {
it("filters by typing", async () => {
const getAuditLogsSpy = jest
.spyOn(API, "getAuditLogs")
.mockResolvedValue({ audit_logs: [MockAuditLog] })
render(<AuditPage />)
await waitForLoaderToBeRemoved()
// Reset spy so we can focus on the call with the filter
getAuditLogsSpy.mockReset()
await screen.findByText("updated", { exact: false })
const filterField = screen.getByLabelText("Filter")
const query = "resource_type:workspace action:create"
await userEvent.type(filterField, query)
await waitFor(() =>
expect(getAuditLogsSpy).toBeCalledWith({
limit: 25,
offset: 0,
q: query,
}),
)
await screen.findByText("created", { exact: false })
const editWorkspace = screen.queryByText("updated", { exact: false })
expect(editWorkspace).not.toBeInTheDocument()
})
it("filters by URL", async () => {
const getAuditLogsSpy = jest
.spyOn(API, "getAuditLogs")
.mockResolvedValue({ audit_logs: [MockAuditLog] })
.mockResolvedValue({ audit_logs: [MockAuditLog], count: 1 })
const query = "resource_type:workspace action:create"
history.push(`/audit?filter=${encodeURIComponent(query)}`)
@@ -67,15 +56,11 @@ describe("AuditPage", () => {
})
it("resets page to 1 when filter is changed", async () => {
const getAuditLogsSpy = jest
.spyOn(API, "getAuditLogs")
.mockResolvedValue({ audit_logs: [MockAuditLog] })
history.push(`/audit?page=2`)
render(<AuditPage />)
await waitForLoaderToBeRemoved()
getAuditLogsSpy.mockReset()
const getAuditLogsSpy = jest.spyOn(API, "getAuditLogs")
const filterField = screen.getByLabelText("Filter")
const query = "resource_type:workspace action:create"
+3 -1
View File
@@ -959,7 +959,7 @@ export const MockAuditLog: TypesGen.AuditLog = {
},
status_code: 200,
additional_fields: {},
description: "{user} updated workspace {target}",
description: "{user} created workspace {target}",
user: MockUser,
}
@@ -967,6 +967,8 @@ export const MockAuditLog2: TypesGen.AuditLog = {
...MockAuditLog,
id: "53bded77-7b9d-4e82-8771-991a34d759f9",
action: "write",
time: "2022-05-20T16:45:57.122Z",
description: "{user} updated workspace {target}",
diff: {
workspace_name: {
old: "old-workspace-name",
+7 -5
View File
@@ -212,18 +212,20 @@ export const handlers = [
// Audit
rest.get("/api/v2/audit", (req, res, ctx) => {
const filter = req.url.searchParams.get("q") as string
const logs =
filter === "resource_type:workspace action:create"
? [M.MockAuditLog]
: [M.MockAuditLog, M.MockAuditLog2]
return res(
ctx.status(200),
ctx.json({
audit_logs: [M.MockAuditLog, M.MockAuditLog2],
audit_logs: logs,
count: logs.length,
}),
)
}),
rest.get("/api/v2/audit/count", (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ count: 1000 }))
}),
// Applications host
rest.get("/api/v2/applications/host", (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ host: "*.dev.coder.com" }))
+13 -29
View File
@@ -1,6 +1,6 @@
import { getAuditLogs, getAuditLogsCount } from "api/api"
import { getAuditLogs } from "api/api"
import { getErrorMessage } from "api/errors"
import { AuditLog } from "api/typesGenerated"
import { AuditLog, AuditLogResponse } from "api/typesGenerated"
import { displayError } from "components/GlobalSnackbar/utils"
import { getPaginationData } from "components/PaginationWidget/utils"
import {
@@ -29,10 +29,7 @@ export const auditMachine = createMachine(
context: {} as AuditContext,
services: {} as {
loadAuditLogsAndCount: {
data: {
auditLogs: AuditLog[]
count: number
}
data: AuditLogResponse
}
},
events: {} as
@@ -59,17 +56,17 @@ export const auditMachine = createMachine(
invoke: {
src: "loadAuditLogsAndCount",
onDone: {
target: "success",
target: "idle",
actions: ["assignAuditLogsAndCount"],
},
onError: {
target: "error",
target: "idle",
actions: ["displayApiError"],
},
},
onDone: "success",
onDone: "idle",
},
success: {
idle: {
on: {
UPDATE_PAGE: {
actions: ["updateURL"],
@@ -80,9 +77,6 @@ export const auditMachine = createMachine(
},
},
},
error: {
type: "final",
},
},
},
{
@@ -91,7 +85,7 @@ export const auditMachine = createMachine(
auditLogs: (_) => undefined,
}),
assignAuditLogsAndCount: assign({
auditLogs: (_, event) => event.data.auditLogs,
auditLogs: (_, event) => event.data.audit_logs,
count: (_, event) => event.data.count,
}),
assignPaginationRef: assign({
@@ -117,21 +111,11 @@ export const auditMachine = createMachine(
loadAuditLogsAndCount: async (context) => {
if (context.paginationRef) {
const { offset, limit } = getPaginationData(context.paginationRef)
const [auditLogs, count] = await Promise.all([
getAuditLogs({
offset,
limit,
q: context.filter,
}).then((data) => data.audit_logs),
getAuditLogsCount({
q: context.filter,
}).then((data) => data.count),
])
return {
auditLogs,
count,
}
return getAuditLogs({
offset,
limit,
q: context.filter,
})
} else {
throw new Error("Cannot get audit logs without pagination data")
}