From 844f2bb72c7bb7bf0a147bde69fe57e8d0fd8e6f Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Wed, 16 Jul 2025 14:48:57 -0700 Subject: [PATCH 1/3] improvements: org and project policy page ui improvements --- .../RoleByIDPage/RoleByIDPage.tsx | 90 +++++++++++------- .../components/RoleDetailsSection.tsx | 95 ------------------- .../OrgPermissionAdminConsoleRow.tsx | 15 +-- .../OrgPermissionAppConnectionRow.tsx | 15 +-- .../OrgPermissionBillingRow.tsx | 15 +-- .../OrgPermissionGatewayRow.tsx | 15 +-- .../OrgPermissionGroupRow.tsx | 15 +-- .../OrgPermissionIdentityRow.tsx | 15 +-- .../OrgPermissionKmipRow.tsx | 15 +-- .../OrgPermissionSecretShareRow.tsx | 15 +-- .../OrgRoleWorkspaceRow.tsx | 15 +-- .../RolePermissionRow.tsx | 15 +-- .../RolePermissionsSection.tsx | 40 ++++---- .../RoleDetailsBySlugPage.tsx | 26 +++++ .../components/GeneralPermissionPolicies.tsx | 6 +- .../components/RolePermissionsSection.tsx | 3 +- 16 files changed, 187 insertions(+), 223 deletions(-) delete mode 100644 frontend/src/pages/organization/RoleByIDPage/components/RoleDetailsSection.tsx diff --git a/frontend/src/pages/organization/RoleByIDPage/RoleByIDPage.tsx b/frontend/src/pages/organization/RoleByIDPage/RoleByIDPage.tsx index 7b68b7fdd..19a5608be 100644 --- a/frontend/src/pages/organization/RoleByIDPage/RoleByIDPage.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/RoleByIDPage.tsx @@ -1,7 +1,8 @@ import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; +import { faCopy, faEllipsisV } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate, useParams } from "@tanstack/react-router"; -import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { OrgPermissionCan } from "@app/components/permissions"; @@ -12,8 +13,7 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, - PageHeader, - Tooltip + PageHeader } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; @@ -22,7 +22,7 @@ import { usePopUp } from "@app/hooks/usePopUp"; import { DuplicateOrgRoleModal } from "@app/pages/organization/RoleByIDPage/components/DuplicateOrgRoleModal"; import { OrgAccessControlTabSections } from "@app/types/org"; -import { RoleDetailsSection, RoleModal, RolePermissionsSection } from "./components"; +import { RoleModal, RolePermissionsSection } from "./components"; export const Page = () => { const navigate = useNavigate(); @@ -80,29 +80,64 @@ export const Page = () => {
{data && (
- + +
+ {data.name} +

+ {data.slug} {data.description && `- ${data.description}`} +

+
+
+ } + > {isCustomRole && ( - -
- - - -
+ + - + + { + navigator.clipboard.writeText(data.id); + + createNotification({ + text: "Copied ID to clipboard", + type: "info" + }); + }} + icon={} + > + Copy ID + + { + navigator.clipboard.writeText(data.slug); + + createNotification({ + text: "Copied slug to clipboard", + type: "info" + }); + }} + icon={} + > + Copy Slug + {(isAllowed) => ( { + onClick={() => { handlePopUpOpen("role", { roleId }); }} - disabled={!isAllowed} + isDisabled={!isAllowed} > Edit Role @@ -111,13 +146,10 @@ export const Page = () => { {(isAllowed) => ( { handlePopUpOpen("duplicateRole"); }} - disabled={!isAllowed} + isDisabled={!isAllowed} > Duplicate Role @@ -126,15 +158,10 @@ export const Page = () => { {(isAllowed) => ( { + onClick={() => { handlePopUpOpen("deleteOrgRole"); }} - disabled={!isAllowed} + isDisabled={!isAllowed} > Delete Role @@ -144,12 +171,7 @@ export const Page = () => {
)} -
-
- -
- -
+
)} diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RoleDetailsSection.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RoleDetailsSection.tsx deleted file mode 100644 index ee93ccfba..000000000 --- a/frontend/src/pages/organization/RoleByIDPage/components/RoleDetailsSection.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { faCheck, faCopy, faPencil } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { OrgPermissionCan } from "@app/components/permissions"; -import { IconButton, Tooltip } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; -import { useTimedReset } from "@app/hooks"; -import { useGetOrgRole } from "@app/hooks/api"; -import { UsePopUpState } from "@app/hooks/usePopUp"; - -type Props = { - roleId: string; - handlePopUpOpen: (popUpName: keyof UsePopUpState<["role"]>, data?: object) => void; -}; - -export const RoleDetailsSection = ({ roleId, handlePopUpOpen }: Props) => { - const [copyTextId, isCopyingId, setCopyTextId] = useTimedReset({ - initialState: "Copy ID to clipboard" - }); - - const { currentOrg } = useOrganization(); - const orgId = currentOrg?.id || ""; - const { data } = useGetOrgRole(orgId, roleId); - const isCustomRole = !["admin", "member", "no-access"].includes(data?.slug ?? ""); - - return data ? ( -
-
-

Org Role Details

- {isCustomRole && ( - - {(isAllowed) => { - return ( - - - handlePopUpOpen("role", { - roleId - }) - } - > - - - - ); - }} - - )} -
-
-
-

Role ID

-
-

{roleId}

-
- - { - navigator.clipboard.writeText(roleId); - setCopyTextId("Copied"); - }} - > - - - -
-
-
-
-

Name

-

{data.name}

-
-
-

Slug

-

{data.slug}

-
-
-

Description

-

- {data.description?.length ? data.description : "-"} -

-
-
-
- ) : ( -
- ); -}; diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAdminConsoleRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAdminConsoleRow.tsx index 2c2ac5dce..e9f103153 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAdminConsoleRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAdminConsoleRow.tsx @@ -76,17 +76,18 @@ export const OrgPermissionAdminConsoleRow = ({ isEditable, control, setValue }: className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700" onClick={() => setIsRowExpanded.toggle()} > - - + + - Organization Admin Console + Organization Admin Console No Access Read Only @@ -147,9 +148,9 @@ export const OrgPermissionAppConnectionRow = ({ isEditable, control, setValue }: -
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( setIsRowExpanded.toggle()} > - - + + - Billing + Billing No Access Read Only @@ -144,9 +145,9 @@ export const OrgGatewayPermissionRow = ({ isEditable, control, setValue }: Props -
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( setIsRowExpanded.toggle()} > - - + + - Group Management + Group Management No Access Read Only @@ -178,9 +179,9 @@ export const OrgPermissionIdentityRow = ({ isEditable, control, setValue }: Prop -
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( setIsRowExpanded.toggle()} > - - + + - KMIP + KMIP No Access Custom @@ -91,9 +92,9 @@ export const OrgPermissionSecretShareRow = ({ isEditable, control, setValue }: P -
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700" onClick={() => setIsRowExpanded.toggle()} > - - + + - Project + Project No Access Read Only @@ -181,9 +182,9 @@ export const RolePermissionRow = ({ isEditable, title, formName, control, setVal -
+
{getPermissionList(formName).map(({ action, label }) => { return ( { className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4" >
-

Permissions

+
+

Policies

+

Configure granular access policies

+
{isCustomRole && (
+ {isDirty && ( + + )} -
)}
- - - - - - {SIMPLE_PERMISSION_OPTIONS.map((permission) => { return ( diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx index af062aa13..3293554f8 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx @@ -111,6 +111,32 @@ const Page = () => { + { + navigator.clipboard.writeText(data.id); + + createNotification({ + text: "Copied ID to clipboard", + type: "info" + }); + }} + icon={} + > + Copy ID + + { + navigator.clipboard.writeText(data.slug); + + createNotification({ + text: "Copied slug to clipboard", + type: "info" + }); + }} + icon={} + > + Copy Slug + +
- + -
{title}
+
{title}
{fields.length > 1 && (
diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx index 216d514e4..dc6323ecb 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx @@ -4,7 +4,6 @@ import { MongoAbility, MongoQuery, RawRuleOf } from "@casl/ability"; import { faSave } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; -import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { AccessTree } from "@app/components/permissions"; @@ -163,7 +162,7 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => {
- {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( - {isRowExpanded && ( -
- ResourcePermission
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAppConnectionRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAppConnectionRow.tsx index 8350c3730..bce7f2403 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAppConnectionRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionAppConnectionRow.tsx @@ -146,10 +146,7 @@ export const OrgPermissionAppConnectionRow = ({ isEditable, control, setValue }:
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionBillingRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionBillingRow.tsx index e8dfca206..db9d5cb54 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionBillingRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionBillingRow.tsx @@ -134,10 +134,7 @@ export const OrgPermissionBillingRow = ({ isEditable, control, setValue }: Props
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGatewayRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGatewayRow.tsx index 5b1d4e341..2c94aa6b5 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGatewayRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGatewayRow.tsx @@ -143,10 +143,7 @@ export const OrgGatewayPermissionRow = ({ isEditable, control, setValue }: Props
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGroupRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGroupRow.tsx index 10f0b2cd7..5f5287847 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGroupRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionGroupRow.tsx @@ -167,10 +167,7 @@ export const OrgPermissionGroupRow = ({ isEditable, control, setValue }: Props)
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionIdentityRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionIdentityRow.tsx index 4fff84852..8ea639828 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionIdentityRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionIdentityRow.tsx @@ -177,10 +177,7 @@ export const OrgPermissionIdentityRow = ({ isEditable, control, setValue }: Prop
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionKmipRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionKmipRow.tsx index b890bd11a..28ce55803 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionKmipRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionKmipRow.tsx @@ -93,10 +93,7 @@ export const OrgPermissionKmipRow = ({ isEditable, control, setValue }: Props) =
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionSecretShareRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionSecretShareRow.tsx index 8cd890a36..d1b6705c7 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionSecretShareRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgPermissionSecretShareRow.tsx @@ -90,10 +90,7 @@ export const OrgPermissionSecretShareRow = ({ isEditable, control, setValue }: P
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx index f3216b82a..2746e10bc 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx @@ -90,10 +90,7 @@ export const OrgRoleWorkspaceRow = ({ isEditable, control, setValue }: Props) =>
+
{PERMISSION_ACTIONS.map(({ action, label }) => { return ( diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/RolePermissionRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/RolePermissionRow.tsx index 853180f1b..969024c07 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/RolePermissionRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/RolePermissionRow.tsx @@ -180,10 +180,7 @@ export const RolePermissionRow = ({ isEditable, title, formName, control, setVal
+
{getPermissionList(formName).map(({ action, label }) => { return (