From 12fd063cd58b40dd72f18060f8e9a2e31f8f07ba Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Wed, 18 Jun 2025 20:15:25 -0700 Subject: [PATCH] improvements: minor ui adjustments/additions and pagination for access request table --- frontend/src/helpers/policies.ts | 14 +++- .../AccessApprovalRequest.tsx | 76 ++++++++++++++----- .../components/ApprovalPolicyRow.tsx | 11 ++- .../SecretApprovalRequest.tsx | 2 +- 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/frontend/src/helpers/policies.ts b/frontend/src/helpers/policies.ts index c97f25965..d798d3c10 100644 --- a/frontend/src/helpers/policies.ts +++ b/frontend/src/helpers/policies.ts @@ -1,12 +1,20 @@ +import { IconDefinition } from "@fortawesome/free-brands-svg-icons"; +import { faArrowRightToBracket, faEdit } from "@fortawesome/free-solid-svg-icons"; + import { PolicyType } from "@app/hooks/api/policies/enums"; -export const policyDetails: Record = { +export const policyDetails: Record< + PolicyType, + { name: string; className: string; icon: IconDefinition } +> = { [PolicyType.AccessPolicy]: { className: "bg-green/20 text-green", - name: "Access Policy" + name: "Access Policy", + icon: faArrowRightToBracket }, [PolicyType.ChangePolicy]: { className: "bg-yellow/20 text-yellow", - name: "Change Policy" + name: "Change Policy", + icon: faEdit } }; diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx index a3fb8aeb4..6985bf915 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx @@ -7,6 +7,7 @@ import { faCheck, faCheckCircle, faChevronDown, + faClipboardCheck, faLock, faMagnifyingGlass, faPlus, @@ -28,6 +29,7 @@ import { DropdownMenuTrigger, EmptyState, Input, + Pagination, Tooltip } from "@app/components/v2"; import { Badge } from "@app/components/v2/Badge"; @@ -39,7 +41,12 @@ import { useUser, useWorkspace } from "@app/context"; -import { usePopUp } from "@app/hooks"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; +import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useGetWorkspaceUsers } from "@app/hooks/api"; import { accessApprovalKeys, @@ -59,7 +66,7 @@ const generateRequestText = (request: TAccessApprovalRequest) => { const { isTemporary } = request; return ( -
+
Requested {isTemporary ? "temporary" : "permanent"} access to{" "} @@ -130,7 +137,14 @@ export const AccessApprovalRequest = ({ envSlug: envFilter }); - const [searchFilter, setSearchFilter] = useState(""); + const { search, setSearch, setPage, page, perPage, setPerPage, offset } = usePagination("", { + initPerPage: getUserTablePreference("accessRequestsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("accessRequestsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredRequests = useMemo(() => { let accessRequests: typeof requests; @@ -150,19 +164,27 @@ export const AccessApprovalRequest = ({ request.reviewers.some((reviewer) => reviewer.status === ApprovalStatus.REJECTED) ); - return accessRequests?.filter((request) => { - const { environmentName, requestedByUser } = request; + return ( + accessRequests?.filter((request) => { + const { environmentName, requestedByUser } = request; - const searchValue = searchFilter.trim().toLowerCase(); + const searchValue = search.trim().toLowerCase(); - return ( - environmentName?.toLowerCase().includes(searchValue) || - `${requestedByUser?.email ?? ""} ${requestedByUser?.firstName ?? ""} ${requestedByUser?.lastName ?? ""}` - .toLowerCase() - .includes(searchValue) - ); - }); - }, [requests, statusFilter, requestedByFilter, envFilter, searchFilter]); + return ( + environmentName?.toLowerCase().includes(searchValue) || + `${requestedByUser?.email ?? ""} ${requestedByUser?.firstName ?? ""} ${requestedByUser?.lastName ?? ""}` + .toLowerCase() + .includes(searchValue) + ); + }) ?? [] + ); + }, [requests, statusFilter, requestedByFilter, envFilter, search]); + + useResetPageHelper({ + totalCount: filteredRequests.length, + offset, + setPage + }); const generateRequestDetails = useCallback( (request: TAccessApprovalRequest) => { @@ -299,8 +321,8 @@ export const AccessApprovalRequest = ({
setSearchFilter(e.target.value)} + value={search} + onChange={(e) => setSearch(e.target.value)} leftIcon={} placeholder="Search approval requests by requesting user or environment..." className="flex-1" @@ -423,7 +445,7 @@ export const AccessApprovalRequest = ({ )} {!!filteredRequests?.length && - filteredRequests?.map((request) => { + filteredRequests?.slice(offset, perPage * page).map((request) => { const details = generateRequestDetails(request); return ( @@ -463,21 +485,35 @@ export const AccessApprovalRequest = ({
-
+
{request.requestedByUserId === user.id && (
Requested By You
)} - - {details.displayData.label} + + + {details.displayData.label}
); })} + {Boolean(filteredRequests.length) && ( + + )} {!!policies && ( diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx index 375e86aa6..683820be6 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx @@ -1,6 +1,7 @@ import { useMemo } from "react"; import { faEdit, faEllipsisV, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { twMerge } from "tailwind-merge"; import { ProjectPermissionCan } from "@app/components/permissions"; import { @@ -107,8 +108,14 @@ export const ApprovalPolicyRow = ({ {policy.environment.name} {policy.secretPath || "*"} - - {policyDetails[policy.policyType].name} + + + {policyDetails[policy.policyType].name} diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx index fc602d6f9..c9bdd072b 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx @@ -316,7 +316,7 @@ export const SecretApprovalRequest = () => { if (evt.key === "Enter") setSelectedApprovalId(secretApproval.id); }} > -
+