diff --git a/messages/en-US.json b/messages/en-US.json index acb6ee0a..8ded612b 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -454,11 +454,12 @@ "filterByResource": "Filter By Resource", "selectApprovalState": "Select Approval State", "filterByApprovalState": "Filter By Approval State", - "approvalListEmpty": "No approval yet at the moment", + "approvalListEmpty": "No approvals", "approvalState": "Approval State", "approve": "Approve", "approved": "Approved", "denied": "Denied", + "all": "All", "deny": "Deny", "viewDetails": "View Details", "requestingNewDeviceApproval": "is requesting new device", diff --git a/server/private/routers/approvals/listApprovals.ts b/server/private/routers/approvals/listApprovals.ts index f7428073..e44fc1be 100644 --- a/server/private/routers/approvals/listApprovals.ts +++ b/server/private/routers/approvals/listApprovals.ts @@ -21,7 +21,7 @@ import type { Request, Response, NextFunction } from "express"; import { build } from "@server/build"; import { getOrgTierData } from "@server/lib/billing"; import { TierId } from "@server/lib/billing/tiers"; -import { approvals, clients, db, users } from "@server/db"; +import { approvals, clients, db, users, type Approval } from "@server/db"; import { eq, isNull, sql, not, and, desc } from "drizzle-orm"; import response from "@server/lib/response"; @@ -41,10 +41,35 @@ const querySchema = z.strictObject({ .optional() .default("0") .transform(Number) - .pipe(z.int().nonnegative()) + .pipe(z.int().nonnegative()), + approvalState: z + .enum(["pending", "approved", "denied", "all"]) + .optional() + .default("pending") + .catch("all") }); -async function queryApprovals(orgId: string, limit: number, offset: number) { +async function queryApprovals( + orgId: string, + limit: number, + offset: number, + approvalState: z.infer["approvalState"] +) { + let state: Array = []; + switch (approvalState) { + case "pending": + state = ["pending"]; + break; + case "approved": + state = ["approved"]; + break; + case "denied": + state = ["denied"]; + break; + default: + state = ["approved", "denied", "pending"]; + } + const res = await db .select({ approvalId: approvals.id, @@ -67,7 +92,12 @@ async function queryApprovals(orgId: string, limit: number, offset: number) { not(isNull(clients.userId)) // only user devices ) ) - .where(eq(approvals.orgId, orgId)) + .where( + and( + eq(approvals.orgId, orgId), + sql`${approvals.decision} in ${state}` + ) + ) .orderBy( sql`CASE ${approvals.decision} WHEN 'pending' THEN 0 ELSE 1 END`, desc(approvals.timestamp) @@ -107,7 +137,7 @@ export async function listApprovals( ) ); } - const { limit, offset } = parsedQuery.data; + const { limit, offset, approvalState } = parsedQuery.data; const { orgId } = parsedParams.data; @@ -127,7 +157,8 @@ export async function listApprovals( const approvalsList = await queryApprovals( orgId.toString(), limit, - offset + offset, + approvalState ); const [{ count }] = await db diff --git a/src/components/ApprovalFeed.tsx b/src/components/ApprovalFeed.tsx index 20e05d90..1132129c 100644 --- a/src/components/ApprovalFeed.tsx +++ b/src/components/ApprovalFeed.tsx @@ -36,15 +36,11 @@ export function ApprovalFeed({ orgId }: ApprovalFeedProps) { ); const { data, isFetching, refetch } = useQuery( - approvalQueries.listApprovals(orgId) + approvalQueries.listApprovals(orgId, filters) ); const approvals = data?.approvals ?? []; - console.log({ - approvals - }); - return (
@@ -75,11 +71,16 @@ export function ApprovalFeed({ orgId }: ApprovalFeedProps) { /> - Pending - - Approved + + {t("pending")} - All + + {t("approved")} + + + {t("denied")} + + {t("all")}
diff --git a/src/lib/queries.ts b/src/lib/queries.ts index 4bdd2310..9746e2c3 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -321,13 +321,22 @@ export const approvalFiltersSchema = z.object({ }); export const approvalQueries = { - listApprovals: (orgId: string) => + listApprovals: ( + orgId: string, + filters: z.infer + ) => queryOptions({ - queryKey: ["APPROVALS", orgId] as const, + queryKey: ["APPROVALS", orgId, filters] as const, queryFn: async ({ signal, meta }) => { + const sp = new URLSearchParams(); + + if (filters.approvalState) { + sp.set("approvalState", filters.approvalState); + } + const res = await meta!.api.get< AxiosResponse - >(`/org/${orgId}/approvals`, { + >(`/org/${orgId}/approvals?${sp.toString()}`, { signal }); return res.data.data;