diff --git a/frontend/src/views/SecretApprovalPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx b/frontend/src/views/SecretApprovalPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx index b6d69d0c9..235737d4a 100644 --- a/frontend/src/views/SecretApprovalPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx +++ b/frontend/src/views/SecretApprovalPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx @@ -1,6 +1,6 @@ /* eslint-disable no-nested-ternary */ /* eslint-disable react/jsx-no-useless-fragment */ -import { useCallback, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { faCheck, faCheckCircle, @@ -11,10 +11,7 @@ import { import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { formatDistance } from "date-fns"; import { AnimatePresence, motion } from "framer-motion"; -import ms from "ms"; -import { twMerge } from "tailwind-merge"; -import { createNotification } from "@app/components/notifications"; import { Button, DropdownMenu, @@ -23,11 +20,10 @@ import { DropdownMenuLabel, DropdownMenuTrigger, EmptyState, - Modal, - ModalContent, Tooltip, UpgradePlanModal } from "@app/components/v2"; +import { Badge } from "@app/components/v2/Badge"; import { ProjectPermissionActions, ProjectPermissionSub, @@ -36,7 +32,7 @@ import { useWorkspace } from "@app/context"; import { usePopUp } from "@app/hooks"; -import { useGetWorkspaceUsers, useReviewAccessRequest } from "@app/hooks/api"; +import { useGetWorkspaceUsers } from "@app/hooks/api"; import { accessApprovalKeys, useGetAccessApprovalPolicies, @@ -44,192 +40,11 @@ import { useGetAccessRequestsCount } from "@app/hooks/api/accessApproval/queries"; import { TAccessApprovalRequest } from "@app/hooks/api/accessApproval/types"; -import { ApprovalStatus, TAccessApprovalPolicy, TWorkspaceUser } from "@app/hooks/api/types"; +import { ApprovalStatus, TWorkspaceUser } from "@app/hooks/api/types"; import { queryClient } from "@app/reactQuery"; -import { SpecificPrivilegeSecretForm } from "@app/views/Project/MembersPage/components/MemberListTab/MemberRoleForm/SpecificPrivilegeSection"; -const DisplayBadge = ({ text, className }: { text: string; className?: string }) => { - return ( -
- {text} -
- ); -}; - -const ReviewRequestModal = ({ - isOpen, - onOpenChange, - request, - projectSlug, - selectedRequester, - selectedEnvSlug -}: { - isOpen: boolean; - onOpenChange: (isOpen: boolean) => void; - request: TAccessApprovalRequest & { user: TWorkspaceUser["user"] | null }; - projectSlug: string; - selectedRequester: string | undefined; - selectedEnvSlug: string | undefined; -}) => { - const [isLoading, setIsLoading] = useState<"approved" | "rejected" | null>(null); - - const accessDetails = { - env: request.environmentName, - // secret path will be inside $glob operator - secretPath: request.policy.secretPath, - read: request.permissions?.some(({ action }) => action.includes(ProjectPermissionActions.Read)), - edit: request.permissions?.some(({ action }) => action.includes(ProjectPermissionActions.Edit)), - create: request.permissions?.some(({ action }) => - action.includes(ProjectPermissionActions.Create) - ), - delete: request.permissions?.some(({ action }) => - action.includes(ProjectPermissionActions.Delete) - ), - - temporaryAccess: { - isTemporary: request.isTemporary, - temporaryRange: request.temporaryRange - } - }; - - const requestedAccess = useMemo(() => { - const access: string[] = []; - if (accessDetails.read) access.push("Read"); - if (accessDetails.edit) access.push("Edit"); - if (accessDetails.create) access.push("Create"); - if (accessDetails.delete) access.push("Delete"); - - return access.join(", "); - }, [accessDetails]); - - const getAccessLabel = () => { - if (!accessDetails.temporaryAccess.isTemporary || !accessDetails.temporaryAccess.temporaryRange) - return "Permanent"; - - // convert the range to human readable format - ms(ms(accessDetails.temporaryAccess.temporaryRange), { long: true }); - - return ( - - ); - }; - - const reviewAccessRequest = useReviewAccessRequest(); - - const handleReview = useCallback(async (status: "approved" | "rejected") => { - setIsLoading(status); - try { - await reviewAccessRequest.mutateAsync({ - requestId: request.id, - status, - projectSlug, - envSlug: selectedEnvSlug, - requestedBy: selectedRequester - }); - } catch (error) { - console.error(error); - setIsLoading(null); - return; - } - - createNotification({ - title: `Request ${status}`, - text: `The request has been ${status}`, - type: status === "approved" ? "success" : "info" - }); - - setIsLoading(null); - onOpenChange(false); - }, []); - - return ( - - -
- - - {request.user?.firstName} {request.user?.lastName} ({request.user?.email}) - {" "} - is requesting access to the following resource: - - -
-
- Requested path: - -
- -
- Permissions: - -
- -
- Access Type: - {getAccessLabel()} -
-
- -
- - -
-
-
-
- ); -}; - -const SelectAccessModal = ({ - isOpen, - onOpenChange, - policies -}: { - isOpen: boolean; - onOpenChange: (isOpen: boolean) => void; - policies: TAccessApprovalPolicy[]; -}) => { - return ( - - - onOpenChange(false)} policies={policies} /> - - - ); -}; +import { RequestAccessModal } from "./components/RequestAccessModal"; +import { ReviewAccessRequestModal } from "./components/ReviewAccessModal"; const generateRequestText = (request: TAccessApprovalRequest, membershipId: string) => { const { isTemporary } = request; @@ -249,7 +64,7 @@ const generateRequestText = (request: TAccessApprovalRequest, membershipId: stri
{request.requestedBy === membershipId && ( - + Requested By You )}
@@ -331,29 +146,30 @@ export const AccessApprovalRequest = ({ ({ member }) => member === membership.id )?.status; - let displayData: { label: string; colorClass: string } = { label: "", colorClass: "" }; + let displayData: { label: string; type: "primary" | "danger" | "success" } = { + label: "", + type: "primary" + }; const isExpired = request.privilege && request.isApproved && new Date() > new Date(request.privilege.temporaryAccessEndTime || ("" as string)); - if (isExpired) displayData = { label: "Access Expired", colorClass: "bg-red/20 text-red" }; - else if (isAccepted) - displayData = { label: "Access Granted", colorClass: "bg-green/20 text-green" }; - else if (isRejectedByAnyone) - displayData = { label: "Rejected", colorClass: "bg-red/20 text-red" }; + if (isExpired) displayData = { label: "Access Expired", type: "danger" }; + else if (isAccepted) displayData = { label: "Access Granted", type: "success" }; + else if (isRejectedByAnyone) displayData = { label: "Rejected", type: "danger" }; else if (userReviewStatus === ApprovalStatus.APPROVED) { displayData = { label: `Pending ${request.policy.approvals - request.reviewers.length} review${ request.policy.approvals - request.reviewers.length > 1 ? "s" : "" }`, - colorClass: "bg-yellow/20 text-yellow" + type: "primary" }; } else if (!isReviewedByUser) displayData = { label: "Review Required", - colorClass: "bg-yellow/20 text-yellow" + type: "primary" }; return { @@ -486,7 +302,7 @@ export const AccessApprovalRequest = ({ icon={requestedByFilter === id && } iconPos="right" > - {user.email} + {user.username} ))} @@ -564,10 +380,9 @@ export const AccessApprovalRequest = ({
{details.isApprover && ( - + + {details.displayData.label} + )}
@@ -581,7 +396,7 @@ export const AccessApprovalRequest = ({ {!!policies && ( - { @@ -598,7 +413,7 @@ export const AccessApprovalRequest = ({ )} {!!selectedRequest && ( -