mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
💄 filter by approval state
This commit is contained in:
@@ -454,11 +454,12 @@
|
|||||||
"filterByResource": "Filter By Resource",
|
"filterByResource": "Filter By Resource",
|
||||||
"selectApprovalState": "Select Approval State",
|
"selectApprovalState": "Select Approval State",
|
||||||
"filterByApprovalState": "Filter By Approval State",
|
"filterByApprovalState": "Filter By Approval State",
|
||||||
"approvalListEmpty": "No approval yet at the moment",
|
"approvalListEmpty": "No approvals",
|
||||||
"approvalState": "Approval State",
|
"approvalState": "Approval State",
|
||||||
"approve": "Approve",
|
"approve": "Approve",
|
||||||
"approved": "Approved",
|
"approved": "Approved",
|
||||||
"denied": "Denied",
|
"denied": "Denied",
|
||||||
|
"all": "All",
|
||||||
"deny": "Deny",
|
"deny": "Deny",
|
||||||
"viewDetails": "View Details",
|
"viewDetails": "View Details",
|
||||||
"requestingNewDeviceApproval": "is requesting new device",
|
"requestingNewDeviceApproval": "is requesting new device",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import type { Request, Response, NextFunction } from "express";
|
|||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { getOrgTierData } from "@server/lib/billing";
|
import { getOrgTierData } from "@server/lib/billing";
|
||||||
import { TierId } from "@server/lib/billing/tiers";
|
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 { eq, isNull, sql, not, and, desc } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
|
|
||||||
@@ -41,10 +41,35 @@ const querySchema = z.strictObject({
|
|||||||
.optional()
|
.optional()
|
||||||
.default("0")
|
.default("0")
|
||||||
.transform(Number)
|
.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<typeof querySchema>["approvalState"]
|
||||||
|
) {
|
||||||
|
let state: Array<Approval["decision"]> = [];
|
||||||
|
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
|
const res = await db
|
||||||
.select({
|
.select({
|
||||||
approvalId: approvals.id,
|
approvalId: approvals.id,
|
||||||
@@ -67,7 +92,12 @@ async function queryApprovals(orgId: string, limit: number, offset: number) {
|
|||||||
not(isNull(clients.userId)) // only user devices
|
not(isNull(clients.userId)) // only user devices
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.where(eq(approvals.orgId, orgId))
|
.where(
|
||||||
|
and(
|
||||||
|
eq(approvals.orgId, orgId),
|
||||||
|
sql`${approvals.decision} in ${state}`
|
||||||
|
)
|
||||||
|
)
|
||||||
.orderBy(
|
.orderBy(
|
||||||
sql`CASE ${approvals.decision} WHEN 'pending' THEN 0 ELSE 1 END`,
|
sql`CASE ${approvals.decision} WHEN 'pending' THEN 0 ELSE 1 END`,
|
||||||
desc(approvals.timestamp)
|
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;
|
const { orgId } = parsedParams.data;
|
||||||
|
|
||||||
@@ -127,7 +157,8 @@ export async function listApprovals(
|
|||||||
const approvalsList = await queryApprovals(
|
const approvalsList = await queryApprovals(
|
||||||
orgId.toString(),
|
orgId.toString(),
|
||||||
limit,
|
limit,
|
||||||
offset
|
offset,
|
||||||
|
approvalState
|
||||||
);
|
);
|
||||||
|
|
||||||
const [{ count }] = await db
|
const [{ count }] = await db
|
||||||
|
|||||||
@@ -36,15 +36,11 @@ export function ApprovalFeed({ orgId }: ApprovalFeedProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data, isFetching, refetch } = useQuery(
|
const { data, isFetching, refetch } = useQuery(
|
||||||
approvalQueries.listApprovals(orgId)
|
approvalQueries.listApprovals(orgId, filters)
|
||||||
);
|
);
|
||||||
|
|
||||||
const approvals = data?.approvals ?? [];
|
const approvals = data?.approvals ?? [];
|
||||||
|
|
||||||
console.log({
|
|
||||||
approvals
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-5">
|
<div className="flex flex-col gap-5">
|
||||||
<Card className="">
|
<Card className="">
|
||||||
@@ -75,11 +71,16 @@ export function ApprovalFeed({ orgId }: ApprovalFeedProps) {
|
|||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent className="w-full">
|
<SelectContent className="w-full">
|
||||||
<SelectItem value="pending">Pending</SelectItem>
|
<SelectItem value="pending">
|
||||||
<SelectItem value="approved">
|
{t("pending")}
|
||||||
Approved
|
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="all">All</SelectItem>
|
<SelectItem value="approved">
|
||||||
|
{t("approved")}
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="denied">
|
||||||
|
{t("denied")}
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="all">{t("all")}</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -321,13 +321,22 @@ export const approvalFiltersSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const approvalQueries = {
|
export const approvalQueries = {
|
||||||
listApprovals: (orgId: string) =>
|
listApprovals: (
|
||||||
|
orgId: string,
|
||||||
|
filters: z.infer<typeof approvalFiltersSchema>
|
||||||
|
) =>
|
||||||
queryOptions({
|
queryOptions({
|
||||||
queryKey: ["APPROVALS", orgId] as const,
|
queryKey: ["APPROVALS", orgId, filters] as const,
|
||||||
queryFn: async ({ signal, meta }) => {
|
queryFn: async ({ signal, meta }) => {
|
||||||
|
const sp = new URLSearchParams();
|
||||||
|
|
||||||
|
if (filters.approvalState) {
|
||||||
|
sp.set("approvalState", filters.approvalState);
|
||||||
|
}
|
||||||
|
|
||||||
const res = await meta!.api.get<
|
const res = await meta!.api.get<
|
||||||
AxiosResponse<ListApprovalsResponse>
|
AxiosResponse<ListApprovalsResponse>
|
||||||
>(`/org/${orgId}/approvals`, {
|
>(`/org/${orgId}/approvals?${sp.toString()}`, {
|
||||||
signal
|
signal
|
||||||
});
|
});
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
|
|||||||
Reference in New Issue
Block a user