feat: updated ui based on feedback

This commit is contained in:
=
2025-04-21 20:02:23 +05:30
parent 2ee423174a
commit 40781949a6
8 changed files with 47 additions and 60 deletions
@@ -1,7 +1,9 @@
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { TProjectAssumePrivilegesDTO } from "./types";
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
import { TProjectAssumePrivilegesDTO } from "./types";
export const useAssumeProjectPrivileges = () => export const useAssumeProjectPrivileges = () =>
useMutation({ useMutation({
mutationFn: async ({ projectId, actorId, actorType }: TProjectAssumePrivilegesDTO) => { mutationFn: async ({ projectId, actorId, actorType }: TProjectAssumePrivilegesDTO) => {
+1 -1
View File
@@ -1,7 +1,7 @@
export * from "./accessApproval"; export * from "./accessApproval";
export * from "./assumePrivileges";
export * from "./admin"; export * from "./admin";
export * from "./apiKeys"; export * from "./apiKeys";
export * from "./assumePrivileges";
export * from "./auditLogs"; export * from "./auditLogs";
export * from "./auditLogStreams"; export * from "./auditLogStreams";
export * from "./auth"; export * from "./auth";
+1 -1
View File
@@ -10,6 +10,7 @@ import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext/type
import { groupBy } from "@app/lib/fn/array"; import { groupBy } from "@app/lib/fn/array";
import { omit } from "@app/lib/fn/object"; import { omit } from "@app/lib/fn/object";
import { ActorType } from "../auditLogs/enums";
import { OrgUser, TProjectMembership } from "../users/types"; import { OrgUser, TProjectMembership } from "../users/types";
import { import {
TGetUserOrgPermissionsDTO, TGetUserOrgPermissionsDTO,
@@ -18,7 +19,6 @@ import {
TPermission, TPermission,
TProjectRole TProjectRole
} from "./types"; } from "./types";
import { ActorType } from "../auditLogs/enums";
const $glob: FieldInstruction<string> = { const $glob: FieldInstruction<string> = {
type: "field", type: "field",
@@ -19,8 +19,8 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectType } from "@app/hooks/api/workspace/types";
import { ProjectSelect } from "./components/ProjectSelect";
import { AssumePrivilegeModeBanner } from "./components/AssumePrivilegeModeBanner"; import { AssumePrivilegeModeBanner } from "./components/AssumePrivilegeModeBanner";
import { ProjectSelect } from "./components/ProjectSelect";
// This is a generic layout shared by all types of projects. // This is a generic layout shared by all types of projects.
// If the product layout differs significantly, create a new layout as needed. // If the product layout differs significantly, create a new layout as needed.
@@ -64,6 +64,7 @@ export const ProjectLayout = () => {
return ( return (
<> <>
<div className="dark hidden h-screen w-full flex-col overflow-x-hidden md:flex"> <div className="dark hidden h-screen w-full flex-col overflow-x-hidden md:flex">
{impersonation && <AssumePrivilegeModeBanner />}
<div className="flex flex-grow flex-col overflow-y-hidden md:flex-row"> <div className="flex flex-grow flex-col overflow-y-hidden md:flex-row">
<motion.div <motion.div
key="menu-project-items" key="menu-project-items"
@@ -269,7 +270,6 @@ export const ProjectLayout = () => {
</div> </div>
</div> </div>
</div> </div>
{impersonation && <AssumePrivilegeModeBanner />}
<div className="z-[200] flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 md:hidden"> <div className="z-[200] flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 md:hidden">
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" /> <FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
<p className="max-w-sm px-6 text-center text-lg text-gray-200"> <p className="max-w-sm px-6 text-center text-lg text-gray-200">
@@ -1,7 +1,7 @@
import { faIdCard, faUser } from "@fortawesome/free-solid-svg-icons"; import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button, HoverCard, HoverCardContent, HoverCardTrigger } from "@app/components/v2"; import { Button } from "@app/components/v2";
import { useProjectPermission, useWorkspace } from "@app/context"; import { useProjectPermission, useWorkspace } from "@app/context";
import { useRemoveAssumeProjectPrivilege } from "@app/hooks/api"; import { useRemoveAssumeProjectPrivilege } from "@app/hooks/api";
import { ActorType } from "@app/hooks/api/auditLogs/enums"; import { ActorType } from "@app/hooks/api/auditLogs/enums";
@@ -14,55 +14,36 @@ export const AssumePrivilegeModeBanner = () => {
if (!impersonation) return null; if (!impersonation) return null;
return ( return (
<div className="fixed bottom-4 right-4 z-50 flex items-center gap-2 rounded border border-mineshaft-600 bg-mineshaft-800 p-2 shadow"> <div className="z-10 -mx-4 flex items-center justify-center gap-2 rounded border border-mineshaft-600 bg-primary-400 p-2 text-mineshaft-800 shadow">
<HoverCard openDelay={200}> <div>
<HoverCardTrigger asChild> <FontAwesomeIcon icon={faInfoCircle} className="mr-2" />
<Button You are currently viewing the project with privileges of{" "}
leftIcon={ <b>
<FontAwesomeIcon {impersonation?.actorType === ActorType.IDENTITY ? "identity" : "user"}{" "}
icon={impersonation?.actorType === ActorType.USER ? faUser : faIdCard} {impersonation?.actorName}
/> </b>
} </div>
onClick={() => { <div>
exitAssumePrivilegeMode.mutate( <Button
{ size="xs"
projectId: currentWorkspace.id variant="outline_bg"
}, className="hover:bg-mineshaft-500"
{ onClick={() => {
onSuccess: () => { exitAssumePrivilegeMode.mutate(
window.location.href = `/${currentWorkspace.type}/${currentWorkspace.id}/overview`; {
} projectId: currentWorkspace.id
},
{
onSuccess: () => {
window.location.href = `/${currentWorkspace.type}/${currentWorkspace.id}/overview`;
} }
); }
}} );
> }}
Exit Assume Privilege Mode
</Button>
</HoverCardTrigger>
<HoverCardContent
className="bg-mineshaft-800 pt-4"
sideOffset={10}
style={{ width: "360px" }}
> >
<div className="flex gap-2"> Click to exit
<div className="flex px-2 pt-2"> </Button>
<FontAwesomeIcon </div>
className="text-3xl text-mineshaft-400"
icon={impersonation?.actorType === ActorType.USER ? faUser : faIdCard}
/>
</div>
<div className="mb-4">
<div className="text-lg">{impersonation?.actorName}</div>
{impersonation?.actorEmail && (
<div className="text-xs">{impersonation?.actorEmail}</div>
)}
{impersonation?.actorType === ActorType.IDENTITY && (
<div className="text-xs">{impersonation?.actorId}</div>
)}
</div>
</div>
</HoverCardContent>
</HoverCard>
</div> </div>
); );
}; };
@@ -139,6 +139,7 @@ const Page = () => {
a={ProjectPermissionSub.Identity} a={ProjectPermissionSub.Identity}
renderTooltip renderTooltip
allowedLabel="Assume or impersonate privileges of the user" allowedLabel="Assume or impersonate privileges of the user"
passThrough={false}
> >
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
@@ -147,7 +148,7 @@ const Page = () => {
isDisabled={!isAllowed} isDisabled={!isAllowed}
onClick={() => handlePopUpOpen("assumePrivileges")} onClick={() => handlePopUpOpen("assumePrivileges")}
> >
Impersonate Identity Test Privileges
</Button> </Button>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>
@@ -191,7 +192,7 @@ const Page = () => {
<ConfirmActionModal <ConfirmActionModal
isOpen={popUp.assumePrivileges.isOpen} isOpen={popUp.assumePrivileges.isOpen}
confirmKey="assume" confirmKey="assume"
title="Do you want to impersonate privileges of this identity?" title="Do you want to assume privileges of this identity?"
subTitle="This will set your privileges to those of the identity for the next hour." subTitle="This will set your privileges to those of the identity for the next hour."
onChange={(isOpen) => handlePopUpToggle("assumePrivileges", isOpen)} onChange={(isOpen) => handlePopUpToggle("assumePrivileges", isOpen)}
onConfirmed={handleAssumePrivileges} onConfirmed={handleAssumePrivileges}
@@ -130,6 +130,7 @@ export const Page = () => {
a={ProjectPermissionSub.Member} a={ProjectPermissionSub.Member}
renderTooltip renderTooltip
allowedLabel="Assume or impersonate privileges of the user" allowedLabel="Assume or impersonate privileges of the user"
passThrough={false}
> >
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
@@ -141,7 +142,7 @@ export const Page = () => {
handlePopUpOpen("assumePrivileges", { userId: membershipDetails?.user?.id }) handlePopUpOpen("assumePrivileges", { userId: membershipDetails?.user?.id })
} }
> >
Impersonate User Test Privileges
</Button> </Button>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>
@@ -187,7 +188,7 @@ export const Page = () => {
<ConfirmActionModal <ConfirmActionModal
isOpen={popUp.assumePrivileges.isOpen} isOpen={popUp.assumePrivileges.isOpen}
confirmKey="assume" confirmKey="assume"
title="Do you want to impersonate privileges of this user?" title="Do you want to assume privileges of this user?"
subTitle="This will set your privileges to those of the user for the next hour." subTitle="This will set your privileges to those of the user for the next hour."
onChange={(isOpen) => handlePopUpToggle("assumePrivileges", isOpen)} onChange={(isOpen) => handlePopUpToggle("assumePrivileges", isOpen)}
onConfirmed={handleAssumePrivileges} onConfirmed={handleAssumePrivileges}
@@ -92,7 +92,8 @@ const MemberPolicyActionSchema = z.object({
[ProjectPermissionMemberActions.Create]: z.boolean().optional(), [ProjectPermissionMemberActions.Create]: z.boolean().optional(),
[ProjectPermissionMemberActions.Edit]: z.boolean().optional(), [ProjectPermissionMemberActions.Edit]: z.boolean().optional(),
[ProjectPermissionMemberActions.Delete]: z.boolean().optional(), [ProjectPermissionMemberActions.Delete]: z.boolean().optional(),
[ProjectPermissionMemberActions.GrantPrivileges]: z.boolean().optional() [ProjectPermissionMemberActions.GrantPrivileges]: z.boolean().optional(),
[ProjectPermissionMemberActions.AssumePrivileges]: z.boolean().optional()
}); });
const IdentityPolicyActionSchema = z.object({ const IdentityPolicyActionSchema = z.object({
@@ -100,7 +101,8 @@ const IdentityPolicyActionSchema = z.object({
[ProjectPermissionIdentityActions.Create]: z.boolean().optional(), [ProjectPermissionIdentityActions.Create]: z.boolean().optional(),
[ProjectPermissionIdentityActions.Edit]: z.boolean().optional(), [ProjectPermissionIdentityActions.Edit]: z.boolean().optional(),
[ProjectPermissionIdentityActions.Delete]: z.boolean().optional(), [ProjectPermissionIdentityActions.Delete]: z.boolean().optional(),
[ProjectPermissionIdentityActions.GrantPrivileges]: z.boolean().optional() [ProjectPermissionIdentityActions.GrantPrivileges]: z.boolean().optional(),
[ProjectPermissionIdentityActions.AssumePrivileges]: z.boolean().optional()
}); });
const GroupPolicyActionSchema = z.object({ const GroupPolicyActionSchema = z.object({