diff --git a/frontend/src/components/features/WishForm.tsx b/frontend/src/components/features/WishForm.tsx index fc38d0731..118900bc9 100644 --- a/frontend/src/components/features/WishForm.tsx +++ b/frontend/src/components/features/WishForm.tsx @@ -63,14 +63,14 @@ export const WishForm = () => { open={isOpen} > -
+
Request a feature
( -
- - +const BreadcrumbContainer = ({ + breadcrumbs, + className +}: { + breadcrumbs: TBreadcrumbFormat[]; + className?: string; +}) => ( +
+ + {(breadcrumbs as TBreadcrumbFormat[]).map((el, index) => { const isNotLastCrumb = index + 1 !== breadcrumbs.length; const BreadcrumbSegment = isNotLastCrumb ? BreadcrumbLink : BreadcrumbPage; @@ -165,8 +171,8 @@ const BreadcrumbContainer = ({ breadcrumbs }: { breadcrumbs: TBreadcrumbFormat[] const Component = el.component; return ( - - + + diff --git a/frontend/src/components/v2/PageHeader/PageHeader.tsx b/frontend/src/components/v2/PageHeader/PageHeader.tsx index 01e710cd3..3c9e743ff 100644 --- a/frontend/src/components/v2/PageHeader/PageHeader.tsx +++ b/frontend/src/components/v2/PageHeader/PageHeader.tsx @@ -5,29 +5,48 @@ import { ReactNode } from "@tanstack/react-router"; import { twMerge } from "tailwind-merge"; import { Badge } from "@app/components/v2"; +import { BadgeProps } from "@app/components/v2/Badge/Badge"; +import { ProjectType } from "@app/hooks/api/projects/types"; type Props = { title: ReactNode; description?: ReactNode; children?: ReactNode; className?: string; - scope: "org" | "project" | "namespace" | "instance"; + scope: "org" | "namespace" | "instance" | ProjectType | null; }; const SCOPE_NAME: Record, { label: string; icon: IconDefinition }> = { org: { label: "Organization", icon: faGlobe }, - project: { label: "Project", icon: faCube }, + [ProjectType.SecretManager]: { label: "Project", icon: faCube }, + [ProjectType.CertificateManager]: { label: "Project", icon: faCube }, + [ProjectType.SSH]: { label: "Project", icon: faCube }, + [ProjectType.KMS]: { label: "Project", icon: faCube }, + [ProjectType.PAM]: { label: "Project", icon: faCube }, + [ProjectType.SecretScanning]: { label: "Project", icon: faCube }, namespace: { label: "Namespace", icon: faCubes }, instance: { label: "Server", icon: faServer } }; +const SCOPE_VARIANT: Record, BadgeProps["variant"]> = { + org: "org", + [ProjectType.SecretManager]: "project", + [ProjectType.CertificateManager]: "project", + [ProjectType.SSH]: "project", + [ProjectType.KMS]: "project", + [ProjectType.PAM]: "project", + [ProjectType.SecretScanning]: "project", + namespace: "namespace", + instance: "instance" +}; + export const PageHeader = ({ title, description, children, className, scope }: Props) => ( -
+

{title}

{scope && ( - + {SCOPE_NAME[scope].label} diff --git a/frontend/src/components/v2/Tabs/Tabs.tsx b/frontend/src/components/v2/Tabs/Tabs.tsx index 4100fd144..ebe8eb2ed 100644 --- a/frontend/src/components/v2/Tabs/Tabs.tsx +++ b/frontend/src/components/v2/Tabs/Tabs.tsx @@ -1,10 +1,19 @@ +import { IconDefinition } from "@fortawesome/free-brands-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as TabsPrimitive from "@radix-ui/react-tabs"; import { twMerge } from "tailwind-merge"; export type TabsProps = TabsPrimitive.TabsProps; export const Tabs = ({ className, children, ...props }: TabsProps) => ( - + {children} ); @@ -13,7 +22,11 @@ export type TabListProps = TabsPrimitive.TabsListProps; export const TabList = ({ className, children, ...props }: TabListProps) => ( {children} @@ -26,18 +39,29 @@ export const Tab = ({ className, children, variant = "project", + icon, ...props -}: TabProps & { variant?: "project" | "namespace" | "org" }) => ( +}: TabProps & { + icon?: IconDefinition; + variant?: "project" | "namespace" | "org" | "instance"; +}) => ( + {icon && } {children} ); @@ -46,7 +70,10 @@ export type TabPanelProps = TabsPrimitive.TabsContentProps; export const TabPanel = ({ className, children, ...props }: TabPanelProps) => ( {children} diff --git a/frontend/src/index.css b/frontend/src/index.css index 360894c2f..7c9b7db9b 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -42,7 +42,7 @@ --font-inter: "Inter", sans-serif; --color-org-v1: #30B3FF; --color-namespace-v1: #96ff59; - + --max-width-8xl: 88rem; /* 1408px */ /* Primary */ --color-primary-50: #fffff5; --color-primary-100: #fcfce8; diff --git a/frontend/src/layouts/AdminLayout/AdminLayout.tsx b/frontend/src/layouts/AdminLayout/AdminLayout.tsx index 859ce9627..89e8a761e 100644 --- a/frontend/src/layouts/AdminLayout/AdminLayout.tsx +++ b/frontend/src/layouts/AdminLayout/AdminLayout.tsx @@ -12,7 +12,7 @@ import { RedisBanner } from "@app/layouts/OrganizationLayout/components/RedisBan import { SmtpBanner } from "@app/layouts/OrganizationLayout/components/SmtpBanner"; import { InsecureConnectionBanner } from "../OrganizationLayout/components/InsecureConnectionBanner"; -import { AdminSidebar } from "./Sidebar"; +import { AdminNavBar } from "./AdminNavBar"; export const AdminLayout = () => { const { t } = useTranslation(); @@ -33,9 +33,9 @@ export const AdminLayout = () => { {!isLoading && !serverDetails?.emailConfigured && } {!isLoading && subscription.auditLogs && } {!window.isSecureContext && } -
- -
+
+ +
diff --git a/frontend/src/layouts/AdminLayout/AdminNavBar.tsx b/frontend/src/layouts/AdminLayout/AdminNavBar.tsx new file mode 100644 index 000000000..49cc1edf9 --- /dev/null +++ b/frontend/src/layouts/AdminLayout/AdminNavBar.tsx @@ -0,0 +1,99 @@ +import { faCheckCircle } from "@fortawesome/free-regular-svg-icons"; +import { + faArrowLeft, + faBuilding, + faCog, + faDatabase, + faKey, + faLock, + faPlug, + faUserTie +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Link, useMatchRoute } from "@tanstack/react-router"; +import { motion } from "framer-motion"; + +import { Tab, TabList, Tabs, Tooltip } from "@app/components/v2"; + +const generalTabs = [ + { + label: "General", + icon: faCog, + link: "/admin/" + }, + { + label: "Resource Overview", + icon: faBuilding, + link: "/admin/resources/overview" + }, + { + label: "Access Control", + icon: faUserTie, + link: "/admin/access-management" + }, + { + label: "Encryption", + icon: faLock, + link: "/admin/encryption" + }, + { + label: "Authentication", + icon: faCheckCircle, + link: "/admin/authentication" + }, + { + label: "Integrations", + icon: faPlug, + link: "/admin/integrations" + }, + { + label: "Caching", + icon: faDatabase, + link: "/admin/caching" + }, + { + label: "Environment Variables", + icon: faKey, + link: "/admin/environment" + } +]; + +export const AdminNavBar = () => { + const matchRoute = useMatchRoute(); + + return ( +
+ + + +
+ ); +}; diff --git a/frontend/src/layouts/AdminLayout/Sidebar.tsx b/frontend/src/layouts/AdminLayout/Sidebar.tsx deleted file mode 100644 index 185ea1dbf..000000000 --- a/frontend/src/layouts/AdminLayout/Sidebar.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { faCheckCircle } from "@fortawesome/free-regular-svg-icons"; -import { - faBuilding, - faChevronLeft, - faCog, - faDatabase, - faKey, - faLock, - faPlug, - faUserTie -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Link, useMatchRoute } from "@tanstack/react-router"; - -import { Menu, MenuGroup, MenuItem } from "@app/components/v2"; - -const generalTabs = [ - { - label: "General", - icon: faCog, - link: "/admin/" - }, - { - label: "Encryption", - icon: faLock, - link: "/admin/encryption" - }, - { - label: "Authentication", - icon: faCheckCircle, - link: "/admin/authentication" - }, - { - label: "Integrations", - icon: faPlug, - link: "/admin/integrations" - }, - { - label: "Caching", - icon: faDatabase, - link: "/admin/caching" - }, - { - label: "Environment Variables", - icon: faKey, - link: "/admin/environment" - } -]; - -const othersTabs = [ - { - label: "Access Controls", - icon: faUserTie, - link: "/admin/access-management" - }, - { - label: "Resource Overview", - icon: faBuilding, - link: "/admin/resources/overview" - } -]; - -export const AdminSidebar = () => { - const matchRoute = useMatchRoute(); - - return ( - - ); -}; diff --git a/frontend/src/layouts/KmsLayout/KmsLayout.tsx b/frontend/src/layouts/KmsLayout/KmsLayout.tsx index 4aa1c1406..c4fdf32eb 100644 --- a/frontend/src/layouts/KmsLayout/KmsLayout.tsx +++ b/frontend/src/layouts/KmsLayout/KmsLayout.tsx @@ -1,9 +1,7 @@ -import { faBook, faCog, faCube, faHome, faLock, faUsers } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Link, Outlet } from "@tanstack/react-router"; +import { Link, Outlet, useLocation } from "@tanstack/react-router"; import { motion } from "framer-motion"; -import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; +import { Tab, TabList, Tabs } from "@app/components/v2"; import { useProject, useProjectPermission } from "@app/context"; import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; @@ -12,138 +10,81 @@ export const KmsLayout = () => { const { currentProject } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); + const location = useLocation(); + return (
-
+
-
+ + {({ isActive }) => KMIP} + + + {({ isActive }) => ( + + Access Control + + )} + + + {({ isActive }) => Audit Logs} + + + {({ isActive }) => Settings} + + + -
- {assumedPrivilegeDetails && } - -
+
+ {assumedPrivilegeDetails && } +
+
); diff --git a/frontend/src/layouts/OrganizationLayout/OrganizationLayout.tsx b/frontend/src/layouts/OrganizationLayout/OrganizationLayout.tsx index f2866259c..c1cc10e41 100644 --- a/frontend/src/layouts/OrganizationLayout/OrganizationLayout.tsx +++ b/frontend/src/layouts/OrganizationLayout/OrganizationLayout.tsx @@ -13,7 +13,7 @@ import { useFetchServerStatus } from "@app/hooks/api"; import { AuditLogBanner } from "./components/AuditLogBanner"; import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner"; import { Navbar } from "./components/NavBar"; -import { OrgSidebar } from "./components/OrgSidebar"; +import { OrgNavBar } from "./components/OrgNavBar"; import { RedisBanner } from "./components/RedisBanner"; import { SmtpBanner } from "./components/SmtpBanner"; @@ -41,16 +41,16 @@ export const OrganizationLayout = () => { className={`dark hidden ${containerHeight} w-full flex-col overflow-x-hidden bg-bunker-800 transition-all md:flex`} > - {!isLoading && !serverDetails?.redisConfigured && } - {!isLoading && !serverDetails?.emailConfigured && } - {!isLoading && subscription.auditLogs && } - {!window.isSecureContext && } -
- +
+ + {!isLoading && !isInsideProject && !serverDetails?.redisConfigured && } + {!isLoading && !isInsideProject && !serverDetails?.emailConfigured && } + {!isLoading && !isInsideProject && subscription.auditLogs && } + {!window.isSecureContext && !isInsideProject && }
diff --git a/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx b/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx index 596202bf6..f3182ab83 100644 --- a/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx +++ b/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx @@ -9,6 +9,7 @@ import { faEnvelope, faExclamationTriangle, faGlobe, + faInfinity, faInfo, faInfoCircle, faServer, @@ -43,7 +44,7 @@ import { envConfig } from "@app/config/env"; import { useOrganization, useSubscription, useUser } from "@app/context"; import { isInfisicalCloud } from "@app/helpers/platform"; import { useToggle } from "@app/hooks"; -import { projectKeys, useGetOrganizations, useLogoutUser } from "@app/hooks/api"; +import { projectKeys, useGetOrganizations, useGetOrgTrialUrl, useLogoutUser } from "@app/hooks/api"; import { authKeys, selectOrganization } from "@app/hooks/api/auth/queries"; import { MfaMethod } from "@app/hooks/api/auth/types"; import { getAuthToken } from "@app/hooks/api/reactQuery"; @@ -162,6 +163,8 @@ export const Navbar = () => { await navigateUserToOrg(navigate, orgId); }; + const { mutateAsync } = useGetOrgTrialUrl(); + const logout = useLogoutUser(); const logOutUser = async () => { try { @@ -201,144 +204,192 @@ export const Navbar = () => { const isServerAdminPanel = location.pathname.startsWith("/admin"); - const isOrgScope = breadcrumbs?.length === 1; // TODO: scott/akhil is this adequate? + const isOrgScope = location.pathname.startsWith("/organization"); // TODO: scott/akhil is this adequate? return ( -
-
- - infisical logo - -
-

/

- {isServerAdminPanel ? ( - <> - -
- -
-
Server Console
+
+
+
+ + infisical logo -

/

- {breadcrumbs ? ( - // scott: remove /admin as we show server console above - - ) : null} - - ) : ( - <> -
- - -
- - - {currentOrg?.name} - -
- {getPlan(subscription)} -
- {subscription.cardDeclined && ( - +

/

+ {isServerAdminPanel ? ( + <> + +
+ +
+
Server Console
+ +

/

+ {breadcrumbs ? ( + // scott: remove /admin as we show server console above + + ) : null} + + ) : ( + <> +
+ + +
+ -
- -
- - )} -
- - -
- - - -
-
- -
organizations
- {orgs?.map((org) => { - return ( - - - - ); - })} -
- } onClick={logOutUser}> - Log Out - - - -
-

/

- {breadcrumbs ? ( - - ) : null} - + + )} +
+ + +
+ + + +
+
+ +
+ organizations +
+ {orgs?.map((org) => { + return ( + + + + ); + })} +
+ } + onClick={logOutUser} + > + Log Out + + + +
+ {!isOrgScope && ( + <> +

/

+ {breadcrumbs ? ( + + ) : null} + + )} + + )} +
+ {subscription && subscription.slug === "starter" && !subscription.has_used_trial && ( + + + + )} + {user.superAdmin && !location.pathname.startsWith("/admin") && ( + + + Server Console + )} -
diff --git a/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/OrgNavBar.tsx b/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/OrgNavBar.tsx new file mode 100644 index 000000000..ba34877f9 --- /dev/null +++ b/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/OrgNavBar.tsx @@ -0,0 +1,109 @@ +import { Link, useLocation } from "@tanstack/react-router"; +import { motion } from "framer-motion"; + +import { CreateOrgModal } from "@app/components/organization/CreateOrgModal"; +import { Tab, TabList, Tabs } from "@app/components/v2"; +import { usePopUp } from "@app/hooks"; + +type Props = { + isHidden?: boolean; +}; + +export const OrgNavBar = ({ isHidden }: Props) => { + const { popUp, handlePopUpToggle } = usePopUp(["createOrg"] as const); + + const { pathname } = useLocation(); + + return ( + <> + {!isHidden && ( +
+ + + +
+ )} + handlePopUpToggle("createOrg", false)} + /> + + ); +}; diff --git a/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/index.tsx b/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/index.tsx new file mode 100644 index 000000000..06509e919 --- /dev/null +++ b/frontend/src/layouts/OrganizationLayout/components/OrgNavBar/index.tsx @@ -0,0 +1 @@ +export { OrgNavBar } from "./OrgNavBar"; diff --git a/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/OrgSidebar.tsx b/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/OrgSidebar.tsx deleted file mode 100644 index 51e14721e..000000000 --- a/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/OrgSidebar.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import { - faBook, - faCog, - faInfinity, - faMoneyBill, - faNetworkWired, - faPlug, - faShare, - faTable, - faUsers, - faUserTie -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Link } from "@tanstack/react-router"; -import { AnimatePresence, motion } from "framer-motion"; - -import { CreateOrgModal } from "@app/components/organization/CreateOrgModal"; -import { Menu, MenuGroup, MenuItem, Tooltip } from "@app/components/v2"; -import { useOrganization, useSubscription, useUser } from "@app/context"; -import { usePopUp } from "@app/hooks"; -import { useGetOrgTrialUrl } from "@app/hooks/api"; - -type Props = { - isHidden?: boolean; -}; - -export const OrgSidebar = ({ isHidden }: Props) => { - const { subscription } = useSubscription(); - - const { user } = useUser(); - const { mutateAsync } = useGetOrgTrialUrl(); - - const { currentOrg } = useOrganization(); - - const { popUp, handlePopUpToggle } = usePopUp(["createOrg"] as const); - - return ( - <> - - {!isHidden && ( - -
- } - > - Server Console - - - )} - - - - )} - - handlePopUpToggle("createOrg", false)} - /> - - ); -}; diff --git a/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/index.tsx b/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/index.tsx deleted file mode 100644 index 315d7ffab..000000000 --- a/frontend/src/layouts/OrganizationLayout/components/OrgSidebar/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { OrgSidebar } from "./OrgSidebar"; diff --git a/frontend/src/layouts/PamLayout/PamLayout.tsx b/frontend/src/layouts/PamLayout/PamLayout.tsx index 48f6af116..f34c29d0d 100644 --- a/frontend/src/layouts/PamLayout/PamLayout.tsx +++ b/frontend/src/layouts/PamLayout/PamLayout.tsx @@ -1,19 +1,9 @@ import { useEffect } from "react"; -import { - faBook, - faBoxOpen, - faCog, - faDisplay, - faHome, - faUser, - faUsers -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Link, Outlet } from "@tanstack/react-router"; +import { Link, Outlet, useLocation } from "@tanstack/react-router"; import { motion } from "framer-motion"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; -import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; +import { Tab, TabList, Tabs } from "@app/components/v2"; import { useProject, useProjectPermission, useSubscription } from "@app/context"; import { usePopUp } from "@app/hooks"; @@ -23,7 +13,7 @@ export const PamLayout = () => { const { currentProject } = useProject(); const { subscription } = useSubscription(); const { assumedPrivilegeDetails } = useProjectPermission(); - + const location = useLocation(); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"]); useEffect(() => { @@ -35,152 +25,85 @@ export const PamLayout = () => { return ( <>
-
+
-
+ + {({ isActive }) => Resources} + + + {({ isActive }) => Sessions} + + + {({ isActive }) => ( + + Access Control + + )} + + + {({ isActive }) => Audit Logs} + + + {({ isActive }) => Settings} + + + -
- {assumedPrivilegeDetails && } - -
+
+ {assumedPrivilegeDetails && } +
+
{ return ( <> -
+
{!window.isSecureContext && }
- -
+
diff --git a/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx b/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx index 93fa04ac9..5f99a1f90 100644 --- a/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx +++ b/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx @@ -1,23 +1,10 @@ import { useTranslation } from "react-i18next"; -import { - faBell, - faBook, - faCertificate, - faCog, - faFileLines, - faHome, - faMobile, - faPlug, - faPuzzlePiece, - faSitemap, - faStamp, - faUsers -} from "@fortawesome/free-solid-svg-icons"; +import { faMobile } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Link, Outlet } from "@tanstack/react-router"; +import { Link, Outlet, useLocation } from "@tanstack/react-router"; import { motion } from "framer-motion"; -import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; +import { Tab, TabList, Tabs } from "@app/components/v2"; import { useProject, useProjectPermission } from "@app/context"; import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; @@ -27,223 +14,139 @@ export const PkiManagerLayout = () => { const { assumedPrivilegeDetails } = useProjectPermission(); const { t } = useTranslation(); + const location = useLocation(); return ( <>
-
+
-
+ + {({ isActive }) => ( + Certificate Templates + )} + + + {({ isActive }) => ( + + Certificates + + )} + + + {({ isActive }) => ( + + Certificate Authorities + + )} + + + {({ isActive }) => Alerting} + + + {({ isActive }) => Integrations} + + + {({ isActive }) => ( + App Connections + )} + + + {({ isActive }) => ( + + Access Control + + )} + + + {({ isActive }) => Audit Logs} + + + {({ isActive }) => Settings} + + + -
- {assumedPrivilegeDetails && } - -
+
+ {assumedPrivilegeDetails && } +
+
diff --git a/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx b/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx index 71af774ca..45978e3d7 100644 --- a/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx +++ b/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx @@ -15,7 +15,7 @@ export const AssumePrivilegeModeBanner = () => { if (!assumedPrivilegeDetails) return null; return ( -
+
You are currently viewing the project with privileges of{" "} @@ -24,7 +24,7 @@ export const AssumePrivilegeModeBanner = () => { {assumedPrivilegeDetails?.actorName}
-
+
- )} - +
+ + Docs + +
+
- setSearch(e.target.value)} - leftIcon={} - placeholder="Search identities by name..." - /> - - - - - - - - - - - - {isPending && } - {!isPending && - data && - data.identityMemberships.length > 0 && - data.identityMemberships.map((identityMember) => { - const { - identity: { id, name }, - roles, - createdAt - } = identityMember; - return ( - { - if (evt.key === "Enter") { - navigate({ - to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId` as const, - params: { - projectId: currentProject.id, - identityId: id - } - }); - } - }} - onClick={() => + + {(isAllowed) => ( + + )} + + + setSearch(e.target.value)} + leftIcon={} + placeholder="Search identities by name..." + /> + +
-
- Name - handleSort(ProjectIdentityOrderBy.Name)} - > - - -
-
RoleAdded on{isFetching ? : null}
+ + + + + + + + + + {isPending && } + {!isPending && + data && + data.identityMemberships.length > 0 && + data.identityMemberships.map((identityMember) => { + const { + identity: { id, name }, + roles, + createdAt + } = identityMember; + return ( + { + if (evt.key === "Enter") { navigate({ to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId` as const, params: { projectId: currentProject.id, identityId: id } - }) + }); } - > - + }} + onClick={() => + navigate({ + to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId` as const, + params: { + projectId: currentProject.id, + identityId: id + } + }) + } + > + - - - - - ); - })} - -
+
+ Name + handleSort(ProjectIdentityOrderBy.Name)} + > + + +
+
RoleAdded on{isFetching ? : null}
{name}{name} -
- {roles - .slice(0, MAX_ROLES_TO_BE_SHOWN_IN_TABLE) - .map( - ({ - role, - customRoleName, - id: roleId, - isTemporary, - temporaryAccessEndTime - }) => { - const isExpired = - new Date() > new Date(temporaryAccessEndTime || ("" as string)); - return ( - -
-
- {formatProjectRoleName(role, customRoleName)} -
- {isTemporary && ( -
- - - -
- )} +
+
+ {roles + .slice(0, MAX_ROLES_TO_BE_SHOWN_IN_TABLE) + .map( + ({ + role, + customRoleName, + id: roleId, + isTemporary, + temporaryAccessEndTime + }) => { + const isExpired = + new Date() > new Date(temporaryAccessEndTime || ("" as string)); + return ( + +
+
+ {formatProjectRoleName(role, customRoleName)}
- - ); - } - )} - {roles.length > MAX_ROLES_TO_BE_SHOWN_IN_TABLE && ( - - - +{roles.length - MAX_ROLES_TO_BE_SHOWN_IN_TABLE} - - - {roles - .slice(MAX_ROLES_TO_BE_SHOWN_IN_TABLE) - .map( - ({ - role, - customRoleName, - id: roleId, - isTemporary, - temporaryAccessEndTime - }) => { - const isExpired = - new Date() > - new Date(temporaryAccessEndTime || ("" as string)); - return ( - -
-
- {formatProjectRoleName(role, customRoleName)} -
- {isTemporary && ( -
- - - new Date( - temporaryAccessEndTime as string - ) && "text-red-600" - )} - /> - -
- )} -
-
- ); - } - )} -
-
+ {isTemporary && ( +
+ + + +
+ )} +
+
+ ); + } )} -
-
{format(new Date(createdAt), "yyyy-MM-dd")} - - - - - - - - - - {(isAllowed) => ( - } - isDisabled={!isAllowed} - onClick={(evt) => { - evt.stopPropagation(); - evt.preventDefault(); - handlePopUpOpen("deleteIdentity", { - identityId: id, - name - }); - }} - > - Remove Identity From Project - + {roles.length > MAX_ROLES_TO_BE_SHOWN_IN_TABLE && ( + + + +{roles.length - MAX_ROLES_TO_BE_SHOWN_IN_TABLE} + + + {roles + .slice(MAX_ROLES_TO_BE_SHOWN_IN_TABLE) + .map( + ({ + role, + customRoleName, + id: roleId, + isTemporary, + temporaryAccessEndTime + }) => { + const isExpired = + new Date() > + new Date(temporaryAccessEndTime || ("" as string)); + return ( + +
+
{formatProjectRoleName(role, customRoleName)}
+ {isTemporary && ( +
+ + + new Date( + temporaryAccessEndTime as string + ) && "text-red-600" + )} + /> + +
+ )} +
+
+ ); + } )} -
-
-
-
-
- {!isPending && data && totalCount > 0 && ( - setPage(newPage)} - onChangePerPage={handlePerPageChange} - /> - )} - {!isPending && data && data?.identityMemberships.length === 0 && ( - 0 - ? "No identities match search filter" - : "No identities have been added to this project" - } - icon={faServer} - /> - )} -
- - handlePopUpToggle("deleteIdentity", isOpen)} - deleteKey="confirm" - onDeleteApproved={() => - onRemoveIdentitySubmit( - (popUp?.deleteIdentity?.data as { identityId: string })?.identityId - ) - } - /> -
- + + + )} +
+ + {format(new Date(createdAt), "yyyy-MM-dd")} + + + + + + + + + + + {(isAllowed) => ( + } + isDisabled={!isAllowed} + onClick={(evt) => { + evt.stopPropagation(); + evt.preventDefault(); + handlePopUpOpen("deleteIdentity", { + identityId: id, + name + }); + }} + > + Remove Identity From Project + + )} + + + + + + + ); + })} + + + {!isPending && data && totalCount > 0 && ( + setPage(newPage)} + onChangePerPage={handlePerPageChange} + /> + )} + {!isPending && data && data?.identityMemberships.length === 0 && ( + 0 + ? "No identities match search filter" + : "No identities have been added to this project" + } + icon={faServer} + /> + )} + + + handlePopUpToggle("deleteIdentity", isOpen)} + deleteKey="confirm" + onDeleteApproved={() => + onRemoveIdentitySubmit( + (popUp?.deleteIdentity?.data as { identityId: string })?.identityId + ) + } + /> +
); }, { action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.Identity } diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/MembersTab.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/MembersTab.tsx index 77a5ba827..bb120627a 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/MembersTab.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/MembersTab.tsx @@ -1,5 +1,3 @@ -import { motion } from "framer-motion"; - import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; import { withProjectPermission } from "@app/hoc"; @@ -7,17 +5,7 @@ import { MembersSection } from "./components"; export const MembersTab = withProjectPermission( () => { - return ( - - - - ); + return ; }, { action: ProjectPermissionActions.Read, diff --git a/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/ProjectRoleListTab.tsx b/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/ProjectRoleListTab.tsx index 89ac57801..0d200477d 100644 --- a/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/ProjectRoleListTab.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/ProjectRoleListTab.tsx @@ -1,5 +1,3 @@ -import { motion } from "framer-motion"; - import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; import { withProjectPermission } from "@app/hoc"; @@ -7,17 +5,7 @@ import { ProjectRoleList } from "./components/ProjectRoleList"; export const ProjectRoleListTab = withProjectPermission( () => { - return ( - - - - ); + return ; }, { action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.Role } ); diff --git a/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/ServiceTokenTab.tsx b/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/ServiceTokenTab.tsx index eefd73a09..8327b8322 100644 --- a/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/ServiceTokenTab.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/ServiceTokenTab.tsx @@ -1,20 +1,12 @@ // import { faWarning } from "@fortawesome/free-solid-svg-icons"; // import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { motion } from "framer-motion"; import { ServiceTokenSection } from "./components"; export const ServiceTokenTab = () => { return ( - -
- {/*
+
+ {/*
Deprecation Notice @@ -42,8 +34,7 @@ export const ServiceTokenTab = () => {

*/} - -
- + +
); }; diff --git a/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx b/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx index 78665e624..6bf14a79b 100644 --- a/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx +++ b/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx @@ -21,9 +21,9 @@ export const AppConnectionsPage = withProjectPermission(
-
+
{ const { currentProject } = useProject(); return ( -
+
Project Audit Logs
-
+
diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx index 409d78633..f3f153b5b 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx @@ -1,11 +1,16 @@ import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; -import { useParams } from "@tanstack/react-router"; +import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Link, useParams } from "@tanstack/react-router"; +import { formatRelative } from "date-fns"; import { ProjectPermissionCan } from "@app/components/permissions"; import { EmptyState, PageHeader, Spinner } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; +import { getProjectBaseURL } from "@app/helpers/project"; import { useGetWorkspaceGroupMembershipDetails } from "@app/hooks/api/projects/queries"; +import { ProjectAccessControlTabs } from "@app/types/project"; import { GroupDetailsSection } from "./components/GroupDetailsSection"; import { GroupMembersSection } from "./components/GroupMembersSection"; @@ -31,10 +36,27 @@ const Page = () => { ); return ( -
+
{groupMembership ? ( -
- +
+ + + Groups + +
diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx index 061d537b1..e49e05022 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx @@ -1,7 +1,9 @@ import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; import { subject } from "@casl/ability"; -import { useNavigate, useParams } from "@tanstack/react-router"; +import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Link, useNavigate, useParams } from "@tanstack/react-router"; import { formatRelative } from "date-fns"; import { createNotification } from "@app/components/notifications"; @@ -28,6 +30,7 @@ import { useGetWorkspaceIdentityMembershipDetails } from "@app/hooks/api"; import { ActorType } from "@app/hooks/api/auditLogs/enums"; +import { ProjectAccessControlTabs } from "@app/types/project"; import { IdentityProjectAdditionalPrivilegeSection } from "./components/IdentityProjectAdditionalPrivilegeSection"; import { IdentityRoleDetailsSection } from "./components/IdentityRoleDetailsSection"; @@ -113,11 +116,24 @@ const Page = () => { } return ( -
+
{identityMembershipDetails ? ( <> + + + Identities + diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx index 717226cfc..b23456a9f 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx @@ -1,6 +1,8 @@ import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; -import { useNavigate, useParams } from "@tanstack/react-router"; +import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Link, useNavigate, useParams } from "@tanstack/react-router"; import { formatRelative } from "date-fns"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; @@ -29,6 +31,7 @@ import { useGetWorkspaceUserDetails } from "@app/hooks/api"; import { ActorType } from "@app/hooks/api/auditLogs/enums"; +import { ProjectAccessControlTabs } from "@app/types/project"; import { MemberProjectAdditionalPrivilegeSection } from "./components/MemberProjectAdditionalPrivilegeSection"; import { MemberRoleDetailsSection } from "./components/MemberRoleDetailsSection"; @@ -115,11 +118,24 @@ export const Page = () => { } return ( -
+
{membershipDetails ? ( <> + + + Users + { ); return ( -
+
{data && ( -
+
+ + + Roles + -
- {data.name} -

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

-
-
+ scope={currentProject.type} + title={data.name} + description={ + <> + {data.slug} {data.description && `- ${data.description}`} + } > {isCustomRole && ( diff --git a/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx b/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx index 760c4b852..7160e9adf 100644 --- a/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx +++ b/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx @@ -35,7 +35,7 @@ export const DeleteProjectProtection = () => {

Delete Protection

{(isAllowed) => ( -
+
{ onCheckedChange={(state) => { handleToggleDeleteProjectProtection(state as boolean); }} + allowMultilineLabel > Protects the project from being deleted accidentally. While this option is enabled, you can't delete the project. diff --git a/frontend/src/pages/public/ErrorPage/ErrorPage.tsx b/frontend/src/pages/public/ErrorPage/ErrorPage.tsx index 1feeeb32a..4bdd3abc4 100644 --- a/frontend/src/pages/public/ErrorPage/ErrorPage.tsx +++ b/frontend/src/pages/public/ErrorPage/ErrorPage.tsx @@ -17,7 +17,7 @@ export const ErrorPage = ({ error }: ErrorComponentProps) => { } return ( -
+

diff --git a/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx b/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx index 7c8bd2a02..18153e257 100644 --- a/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx +++ b/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx @@ -64,7 +64,7 @@ export const CommitDetailsPage = () => { }; return ( -

+
diff --git a/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx b/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx index a3a25b1cc..43992d73a 100644 --- a/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx +++ b/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx @@ -24,6 +24,7 @@ import { } from "@app/context/ProjectPermissionContext/types"; import { usePopUp } from "@app/hooks"; import { useCommitRollback, useGetRollbackPreview } from "@app/hooks/api/folderCommits/queries"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { SecretVersionDiffView } from "../SecretVersionDiffView"; @@ -297,7 +298,7 @@ export const RollbackPreviewTab = (): JSX.Element => { }; return ( -
+
{
diff --git a/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx b/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx index e456bbdf3..4fc37b659 100644 --- a/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx +++ b/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx @@ -1,4 +1,6 @@ -import { useNavigate, useParams, useSearch } from "@tanstack/react-router"; +import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Link, useNavigate, useParams, useSearch } from "@tanstack/react-router"; import { ProjectPermissionCan } from "@app/components/permissions"; import { PageHeader } from "@app/components/v2"; @@ -9,6 +11,7 @@ import { ProjectPermissionCommitsActions, ProjectPermissionSub } from "@app/context/ProjectPermissionContext/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { CommitHistoryTab } from "./components/CommitHistoryTab"; @@ -46,10 +49,21 @@ export const CommitsPage = () => { }; return ( -
-
+
+
+ + + Secrets + diff --git a/frontend/src/pages/secret-manager/IPAllowlistPage/IPAllowlistPage.tsx b/frontend/src/pages/secret-manager/IPAllowlistPage/IPAllowlistPage.tsx index 6453e3118..7492ea6a1 100644 --- a/frontend/src/pages/secret-manager/IPAllowlistPage/IPAllowlistPage.tsx +++ b/frontend/src/pages/secret-manager/IPAllowlistPage/IPAllowlistPage.tsx @@ -15,7 +15,7 @@ export const IPAllowListPage = () => {
-
+

IP Allowlist

diff --git a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx index 0eaa7dfac..3b5600665 100644 --- a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx @@ -90,11 +90,11 @@ export const IntegrationDetailsByIDPage = () => { -
+
{integration ? ( -
+
diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/IntegrationsListPage.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/IntegrationsListPage.tsx index 4e2a0a703..bd261d7b9 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/IntegrationsListPage.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/IntegrationsListPage.tsx @@ -7,6 +7,7 @@ import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { ProjectPermissionSecretSyncActions } from "@app/context/ProjectPermissionContext/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { IntegrationsListPageTabs } from "@app/types/integrations"; import { @@ -45,21 +46,25 @@ export const IntegrationsListPage = () => { -
+
- + - Secret Syncs - Native Integrations - + + Secret Syncs + + + Native Integrations + + Framework Integrations - + Infrastructure Integrations diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 5ec480298..d49121e86 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -93,7 +93,7 @@ import { import { useGetProjectSecretsOverview } from "@app/hooks/api/dashboard/queries"; import { DashboardSecretsOrderBy, ProjectSecretsImportedBy } from "@app/hooks/api/dashboard/types"; import { OrderByDirection } from "@app/hooks/api/generic/types"; -import { ProjectVersion } from "@app/hooks/api/projects/types"; +import { ProjectType, ProjectVersion } from "@app/hooks/api/projects/types"; import { useUpdateFolderBatch } from "@app/hooks/api/secretFolders/queries"; import { TUpdateFolderBatchDTO } from "@app/hooks/api/secretFolders/types"; import { TSecretRotationV2 } from "@app/hooks/api/secretRotationsV2"; @@ -929,11 +929,11 @@ export const OverviewPage = () => { -
+
Inject your secrets using @@ -977,7 +977,7 @@ export const OverviewPage = () => { } />
-
+
{isTableFiltered && ( diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchDynamicSecretItem.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchDynamicSecretItem.tsx index 79911b6ee..06dff9d3f 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchDynamicSecretItem.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchDynamicSecretItem.tsx @@ -46,7 +46,7 @@ export const QuickSearchDynamicSecretItem = ({ {" "} - + {reverseTruncate(groupDynamicSecret.path)} diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchFolderItem.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchFolderItem.tsx index 92d2fac3e..55b21b162 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchFolderItem.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchFolderItem.tsx @@ -32,7 +32,7 @@ export const QuickSearchFolderItem = ({ folderGroup, onClose }: Props) => { > - +
{reverseTruncate(groupFolder.path)}
diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretItem.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretItem.tsx index a593b0023..60ad93a57 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretItem.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretItem.tsx @@ -126,7 +126,7 @@ export const QuickSearchSecretItem = ({ {" "} - + {reverseTruncate(groupSecret.path ?? "")} diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretRotationItem.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretRotationItem.tsx index fc4b66978..8790f1c74 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretRotationItem.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretSearchInput/components/QuickSearchSecretRotationItem.tsx @@ -42,7 +42,7 @@ export const QuickSearchSecretRotationItem = ({ secretRotationGroup, onClose }: {" "} - + {reverseTruncate(groupSecretRotation.folder.path)} diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretTableResourceCount/SecretTableResourceCount.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretTableResourceCount/SecretTableResourceCount.tsx index 76b4345c1..615922560 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretTableResourceCount/SecretTableResourceCount.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretTableResourceCount/SecretTableResourceCount.tsx @@ -25,7 +25,7 @@ export const SecretTableResourceCount = ({ secretRotationCount = 0 }: Props) => { return ( -
+
{importCount > 0 && ( ({ marginLeft: scrollOffset, - width: "calc(100vw - 275px)", // accounts for sidebar and margin - maxWidth: "1270px" // largest width of table on ultra-wide + width: "calc(100vw - 110px)", // accounts for sidebar and margin + maxWidth: "1404px" // largest width of table on ultra-wide }); type GetHeaderStyleParams = { diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx index 6813aac07..069f2728d 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx @@ -5,6 +5,7 @@ import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { Badge } from "@app/components/v2/Badge"; import { useProject } from "@app/context"; import { useGetAccessRequestsCount, useGetSecretApprovalRequestCount } from "@app/hooks/api"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { AccessApprovalRequest } from "./components/AccessApprovalRequest"; import { ApprovalPolicyList } from "./components/ApprovalPolicyList"; @@ -38,27 +39,29 @@ export const SecretApprovalsPage = () => { -
+
- + - + Change Requests {Boolean(secretApprovalReqCount?.open) && ( {secretApprovalReqCount?.open} )} - + Access Requests {Boolean(accessApprovalRequestCount?.pendingCount) && ( {accessApprovalRequestCount?.pendingCount} )} - Policies + + Policies + 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 fce55b077..b1df86312 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx @@ -19,7 +19,6 @@ import { } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { format, formatDistance } from "date-fns"; -import { AnimatePresence, motion } from "framer-motion"; import { twMerge } from "tailwind-merge"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; @@ -298,108 +297,132 @@ export const AccessApprovalRequest = ({ const isFiltered = Boolean(search || envFilter || requestedByFilter); return ( - - -
-
-
-
-

Access Requests

- -
- - Docs - -
-
-
-

- Request and review access to secrets in sensitive environments and folders -

-
- - - +
+ + Docs + +
+
+
+

+ Request and review access to secrets in sensitive environments and folders +

- setSearch(e.target.value)} - leftIcon={} - placeholder="Search approval requests by requesting user or environment..." - className="flex-1" - containerClassName="mb-4" - /> -
-
setStatusFilter("open")} - onKeyDown={(evt) => { - if (evt.key === "Enter") setStatusFilter("open"); + +
-
setStatusFilter("close")} - onKeyDown={(evt) => { - if (evt.key === "Enter") setStatusFilter("close"); - }} - > - - {!!requestCount && requestCount.finalizedCount} Closed -
-
+ Request Access + + +
+ setSearch(e.target.value)} + leftIcon={} + placeholder="Search approval requests by requesting user or environment..." + className="flex-1" + containerClassName="mb-4" + /> +
+
setStatusFilter("open")} + onKeyDown={(evt) => { + if (evt.key === "Enter") setStatusFilter("open"); + }} + className={twMerge( + "font-medium", + statusFilter === "close" && "text-gray-500 duration-100 hover:text-gray-400" + )} + > + + {!!requestCount && requestCount?.pendingCount} Pending +
+
setStatusFilter("close")} + onKeyDown={(evt) => { + if (evt.key === "Enter") setStatusFilter("close"); + }} + > + + {!!requestCount && requestCount.finalizedCount} Closed +
+
+ + + + + + + Select an Environment + + {currentProject?.environments.map(({ slug, name }) => ( + setEnvFilter((state) => (state === slug ? undefined : slug))} + key={`request-filter-${slug}`} + icon={envFilter === slug && } + iconPos="right" + > + {name} + + ))} + + + {!!permission.can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member) && ( - Select an Environment + Select Requesting User - {currentProject?.environments.map(({ slug, name }) => ( + {members?.map(({ user: membershipUser, id }) => ( setEnvFilter((state) => (state === slug ? undefined : slug))} - key={`request-filter-${slug}`} - icon={envFilter === slug && } + onClick={() => + setRequestedByFilter((state) => + state === membershipUser.id ? undefined : membershipUser.id + ) + } + key={`request-filter-member-${id}`} + icon={ + requestedByFilter === membershipUser.id && ( + + ) + } iconPos="right" > - {name} + {membershipUser.username} ))} - {!!permission.can( - ProjectPermissionMemberActions.Read, - ProjectPermissionSub.Member - ) && ( - - - - - - - Select Requesting User - - {members?.map(({ user: membershipUser, id }) => ( - - setRequestedByFilter((state) => - state === membershipUser.id ? undefined : membershipUser.id - ) - } - key={`request-filter-member-${id}`} - icon={ - requestedByFilter === membershipUser.id && ( - - ) - } - iconPos="right" - > - {membershipUser.username} - - ))} - - - )} -
-
-
- {filteredRequests?.length === 0 && !isFiltered && ( -
- -
- )} - {Boolean(!filteredRequests?.length && isFiltered && !areRequestsPending) && ( -
- -
- )} - {!!filteredRequests?.length && - filteredRequests?.slice(offset, perPage * page).map((request) => { - const details = generateRequestDetails(request); - - return ( -
handleSelectRequest(request)} - onKeyDown={(evt) => { - if (evt.key === "Enter") { - handleSelectRequest(request); - } - }} - > -
-
-
- - {generateRequestText(request)} -
-
-
- {membersGroupById?.[request.requestedByUserId]?.user && ( - <> - Requested {formatDistance(new Date(request.createdAt), new Date())}{" "} - ago by{" "} - {membersGroupById?.[request.requestedByUserId]?.user?.firstName}{" "} - {membersGroupById?.[request.requestedByUserId]?.user?.lastName} ( - {membersGroupById?.[request.requestedByUserId]?.user?.email}){" "} - - )} -
-
-
-
- {request.requestedByUserId === user.id && ( -
- - Requested By You -
- )} - -
- - {details.displayData.icon && ( - - )} - {details.displayData.label} - -
-
-
-
-
- ); - })} - {Boolean(filteredRequests.length) && ( - )}
- {!!policies && ( - { - queryClient.invalidateQueries({ - queryKey: accessApprovalKeys.getAccessApprovalRequests( - projectSlug, - envFilter, - requestedByFilter - ) - }); - handlePopUpClose("requestAccess"); - }} - /> - )} +
+ {filteredRequests?.length === 0 && !isFiltered && ( +
+ +
+ )} + {Boolean(!filteredRequests?.length && isFiltered && !areRequestsPending) && ( +
+ +
+ )} + {!!filteredRequests?.length && + filteredRequests?.slice(offset, perPage * page).map((request) => { + const details = generateRequestDetails(request); - {!!selectedRequest && ( - { - handlePopUpClose("reviewRequest"); - setSelectedRequest(null); - refetchRequests(); - }} - onUpdate={(request) => { - // scott: this isn't ideal but our current use of state makes this complicated... - // we shouldn't be using state like this... - handleSelectRequest({ - ...selectedRequest, - isTemporary: request.isTemporary, - temporaryRange: request.temporaryRange, - reviewers: [] - }); - }} - canBypass={generateRequestDetails(selectedRequest).canBypass} - /> - )} - - handlePopUpClose("upgradePlan")} + return ( +
handleSelectRequest(request)} + onKeyDown={(evt) => { + if (evt.key === "Enter") { + handleSelectRequest(request); + } + }} + > +
+
+
+ + {generateRequestText(request)} +
+
+
+ {membersGroupById?.[request.requestedByUserId]?.user && ( + <> + Requested {formatDistance(new Date(request.createdAt), new Date())}{" "} + ago by{" "} + {membersGroupById?.[request.requestedByUserId]?.user?.firstName}{" "} + {membersGroupById?.[request.requestedByUserId]?.user?.lastName} ( + {membersGroupById?.[request.requestedByUserId]?.user?.email}){" "} + + )} +
+
+
+
+ {request.requestedByUserId === user.id && ( +
+ + Requested By You +
+ )} + +
+ + {details.displayData.icon && ( + + )} + {details.displayData.label} + +
+
+
+
+
+ ); + })} + {Boolean(filteredRequests.length) && ( + + )} +
+
+ {!!policies && ( + { + queryClient.invalidateQueries({ + queryKey: accessApprovalKeys.getAccessApprovalRequests( + projectSlug, + envFilter, + requestedByFilter + ) + }); + handlePopUpClose("requestAccess"); + }} /> - - + )} + + {!!selectedRequest && ( + { + handlePopUpClose("reviewRequest"); + setSelectedRequest(null); + refetchRequests(); + }} + onUpdate={(request) => { + // scott: this isn't ideal but our current use of state makes this complicated... + // we shouldn't be using state like this... + handleSelectRequest({ + ...selectedRequest, + isTemporary: request.isTemporary, + temporaryRange: request.temporaryRange, + reviewers: [] + }); + }} + canBypass={generateRequestDetails(selectedRequest).canBypass} + /> + )} + + handlePopUpClose("upgradePlan")} + /> + ); }; diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx index 3d2302535..4daee7e41 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx @@ -12,7 +12,6 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { AnimatePresence, motion } from "framer-motion"; import { twMerge } from "tailwind-merge"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; @@ -240,262 +239,253 @@ export const ApprovalPolicyList = ({ projectId }: IProps) => { orderDirection === OrderByDirection.DESC && orderBy === col ? faArrowUp : faArrowDown; return ( - - -
-
-
-
-

Policies

- -
- - Docs - -
-
-
-

- Implement granular policies for access requests and secrets management -

-
- - {(isAllowed) => ( - - )} - -
-
- setSearch(e.target.value)} - leftIcon={} - placeholder="Search policies by name, type, environment or secret path..." - className="flex-1" - /> - - - - - - - +
+
+
+
+

Policies

+ - Policy Type - - setFilters((prev) => ({ - ...prev, - type: null - })) - } - icon={!filters && } - iconPos="right" - > - All - - - setFilters((prev) => ({ - ...prev, - type: PolicyType.AccessPolicy - })) - } - icon={ - filters.type === PolicyType.AccessPolicy && ( - - ) - } - iconPos="right" - > - Access Policy - - - setFilters((prev) => ({ - ...prev, - type: PolicyType.ChangePolicy - })) - } - icon={ - filters.type === PolicyType.ChangePolicy && ( - - ) - } - iconPos="right" - > - Change Policy - - Environment - {currentProject.environments.map((env) => ( - { - e.preventDefault(); - setFilters((prev) => ({ - ...prev, - environmentIds: prev.environmentIds.includes(env.id) - ? prev.environmentIds.filter((i) => i !== env.id) - : [...prev.environmentIds, env.id] - })); - }} - key={env.id} - icon={ - filters.environmentIds.includes(env.id) && ( - - ) - } - iconPos="right" - > - {env.name} - - ))} - - -
- - - - - - - - - - - - {isPoliciesLoading && ( - + + Docs + - )} - {!isPoliciesLoading && !policies?.length && ( - - - - )} - {!!currentProject && - filteredPolicies - ?.slice(offset, perPage * page) - .map((policy) => ( - handlePopUpOpen("policyForm", policy)} - onDelete={() => handlePopUpOpen("deletePolicy", policy)} - /> - ))} - -
-
- Name - handleSort(PolicyOrderBy.Name)} - > - - -
-
-
- Environment - handleSort(PolicyOrderBy.Environment)} - > - - -
-
-
- Secret Path - handleSort(PolicyOrderBy.SecretPath)} - > - - -
-
-
- Type - handleSort(PolicyOrderBy.Type)} - > - - -
-
-
- -
- {Boolean(!filteredPolicies.length && policies.length && !isPoliciesLoading) && ( - +
+ +
+

+ Implement granular policies for access requests and secrets management +

+
+ + {(isAllowed) => ( + )} - {Boolean(filteredPolicies.length) && ( - - )} - +
- +
+ setSearch(e.target.value)} + leftIcon={} + placeholder="Search policies by name, type, environment or secret path..." + className="flex-1" + /> + + + + + + + + Policy Type + + setFilters((prev) => ({ + ...prev, + type: null + })) + } + icon={!filters && } + iconPos="right" + > + All + + + setFilters((prev) => ({ + ...prev, + type: PolicyType.AccessPolicy + })) + } + icon={ + filters.type === PolicyType.AccessPolicy && ( + + ) + } + iconPos="right" + > + Access Policy + + + setFilters((prev) => ({ + ...prev, + type: PolicyType.ChangePolicy + })) + } + icon={ + filters.type === PolicyType.ChangePolicy && ( + + ) + } + iconPos="right" + > + Change Policy + + Environment + {currentProject.environments.map((env) => ( + { + e.preventDefault(); + setFilters((prev) => ({ + ...prev, + environmentIds: prev.environmentIds.includes(env.id) + ? prev.environmentIds.filter((i) => i !== env.id) + : [...prev.environmentIds, env.id] + })); + }} + key={env.id} + icon={ + filters.environmentIds.includes(env.id) && ( + + ) + } + iconPos="right" + > + {env.name} + + ))} + + +
+ + + + + + + + + + + + {isPoliciesLoading && ( + + )} + {!isPoliciesLoading && !policies?.length && ( + + + + )} + {!!currentProject && + filteredPolicies + ?.slice(offset, perPage * page) + .map((policy) => ( + handlePopUpOpen("policyForm", policy)} + onDelete={() => handlePopUpOpen("deletePolicy", policy)} + /> + ))} + +
+
+ Name + handleSort(PolicyOrderBy.Name)} + > + + +
+
+
+ Environment + handleSort(PolicyOrderBy.Environment)} + > + + +
+
+
+ Secret Path + handleSort(PolicyOrderBy.SecretPath)} + > + + +
+
+
+ Type + handleSort(PolicyOrderBy.Type)} + > + + +
+
+
+ +
+ {Boolean(!filteredPolicies.length && policies.length && !isPoliciesLoading) && ( + + )} + {Boolean(filteredPolicies.length) && ( + + )} +
+
{ onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)} text="You can add secret approval policy if you switch to Infisical's Enterprise plan." /> -
+ ); }; 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 509f5f289..7e5f9236f 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx @@ -14,7 +14,6 @@ import { import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useSearch } from "@tanstack/react-router"; import { format, formatDistance } from "date-fns"; -import { AnimatePresence, motion } from "framer-motion"; import { twMerge } from "tailwind-merge"; import { @@ -131,284 +130,250 @@ export const SecretApprovalRequest = () => { const isFiltered = Boolean(searchFilter || envFilter || committerFilter); - return ( - - {isSecretApprovalScreen ? ( - - - - ) : ( - -
-
-
-
-

Change Requests

- -
- - Docs - -
-
-
-

Review pending and closed change requests

-
-
- setSearchFilter(e.target.value)} - leftIcon={} - placeholder="Search change requests by author, environment or policy path..." - className="flex-1" - containerClassName="mb-4" - /> -
-
setStatusFilter("open")} - onKeyDown={(evt) => { - if (evt.key === "Enter") setStatusFilter("open"); - }} - className={twMerge( - "font-medium", - statusFilter === "close" && "text-gray-500 duration-100 hover:text-gray-400" - )} - > - - {isSecretApprovalReqCountSuccess && secretApprovalRequestCount?.open} Open -
-
setStatusFilter("close")} - onKeyDown={(evt) => { - if (evt.key === "Enter") setStatusFilter("close"); - }} - > - - {isSecretApprovalReqCountSuccess && secretApprovalRequestCount.closed} Closed -
-
- - - - - - - Select an Environment - - {currentProject?.environments.map(({ slug, name }) => ( - setEnvFilter((state) => (state === slug ? undefined : slug))} - key={`request-filter-${slug}`} - icon={envFilter === slug && } - iconPos="right" - > - {name} - - ))} - - - {!!permission.can( - ProjectPermissionMemberActions.Read, - ProjectPermissionSub.Member - ) && ( - - - - - - - Select an Author - - {members?.map(({ user, id }) => ( - - setCommitterFilter((state) => (state === user.id ? undefined : user.id)) - } - key={`request-filter-member-${id}`} - icon={ - committerFilter === user.id && - } - iconPos="right" - > - {user.username} - - ))} - - - )} -
-
-
- {isRequestListEmpty && !isFiltered && ( -
- -
- )} - {secretApprovalRequests.map((secretApproval) => { - const { - id: reqId, - commits, - createdAt, - reviewers, - status, - committerUser, - hasMerged, - updatedAt - } = secretApproval; - const isReviewed = reviewers.some( - ({ status: reviewStatus, userId }) => - userId === userSession.id && reviewStatus === ApprovalStatus.APPROVED - ); - return ( -
setSelectedApprovalId(secretApproval.id)} - onKeyDown={(evt) => { - if (evt.key === "Enter") setSelectedApprovalId(secretApproval.id); - }} - > -
-
- - {secretApproval.isReplicated - ? `${commits.length} secret pending import` - : generateCommitText(commits)} - #{secretApproval.slug} -
- - Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "} - {committerUser ? ( - <> - {committerUser?.firstName || ""} {committerUser?.lastName || ""} ( - {committerUser?.email}) - - ) : ( - Deleted User - )} - {!isReviewed && status === "open" && " - Review required"} - -
- {status === "close" && ( - -
- - - {hasMerged ? "Merged" : "Rejected"} - -
-
- )} -
- ); - })} - {Boolean( - !secretApprovalRequests.length && isFiltered && !isApprovalRequestLoading - ) && ( -
- -
- )} - {Boolean(totalApprovalCount) && ( - + ) : ( +
+
+ + setSearchFilter(e.target.value)} + leftIcon={} + placeholder="Search change requests by author, environment or policy path..." + className="flex-1" + containerClassName="mb-4" + /> +
+
setStatusFilter("open")} + onKeyDown={(evt) => { + if (evt.key === "Enter") setStatusFilter("open"); + }} + className={twMerge( + "font-medium", + statusFilter === "close" && "text-gray-500 duration-100 hover:text-gray-400" + )} + > + + {isSecretApprovalReqCountSuccess && secretApprovalRequestCount?.open} Open +
+
setStatusFilter("close")} + onKeyDown={(evt) => { + if (evt.key === "Enter") setStatusFilter("close"); + }} + > + + {isSecretApprovalReqCountSuccess && secretApprovalRequestCount.closed} Closed +
+
+ + + + + + + Select an Environment + + {currentProject?.environments.map(({ slug, name }) => ( + setEnvFilter((state) => (state === slug ? undefined : slug))} + key={`request-filter-${slug}`} + icon={envFilter === slug && } + iconPos="right" + > + {name} + + ))} + + + {!!permission.can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member) && ( + + + + + + + Select an Author + + {members?.map(({ user, id }) => ( + + setCommitterFilter((state) => (state === user.id ? undefined : user.id)) + } + key={`request-filter-member-${id}`} + icon={committerFilter === user.id && } + iconPos="right" + > + {user.username} + + ))} + + + )} +
+
+
+ {isRequestListEmpty && !isFiltered && ( +
+ +
+ )} + {secretApprovalRequests.map((secretApproval) => { + const { + id: reqId, + commits, + createdAt, + reviewers, + status, + committerUser, + hasMerged, + updatedAt + } = secretApproval; + const isReviewed = reviewers.some( + ({ status: reviewStatus, userId }) => + userId === userSession.id && reviewStatus === ApprovalStatus.APPROVED + ); + return ( +
setSelectedApprovalId(secretApproval.id)} + onKeyDown={(evt) => { + if (evt.key === "Enter") setSelectedApprovalId(secretApproval.id); + }} + > +
+
+ + {secretApproval.isReplicated + ? `${commits.length} secret pending import` + : generateCommitText(commits)} + #{secretApproval.slug}
+ + Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "} + {committerUser ? ( + <> + {committerUser?.firstName || ""} {committerUser?.lastName || ""} ( + {committerUser?.email}) + + ) : ( + Deleted User + )} + {!isReviewed && status === "open" && " - Review required"} + +
+ {status === "close" && ( + +
+ + + {hasMerged ? "Merged" : "Rejected"} + +
+
)}
+ ); + })} + {Boolean(!secretApprovalRequests.length && isFiltered && !isApprovalRequestLoading) && ( +
+
- - )} - + )} + {Boolean(totalApprovalCount) && ( + + )} + {isApprovalRequestLoading && ( +
+ {Array.apply(0, Array(3)).map((_x, index) => ( +
+
+ + +
+ +
+ ))} +
+ )} +
+
); }; diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx index 9a99208a5..24d306314 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx @@ -228,7 +228,7 @@ export const SecretApprovalRequestChanges = ({ approvalRequestId, onGoBack }: Pr return (
-
+
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx index da31fcf09..caef19326 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx @@ -3,9 +3,14 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; import { subject } from "@casl/ability"; -import { faArrowDown, faArrowUp, faInfoCircle } from "@fortawesome/free-solid-svg-icons"; +import { + faArrowDown, + faArrowUp, + faChevronLeft, + faInfoCircle +} from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useNavigate, useParams, useSearch } from "@tanstack/react-router"; +import { Link, useNavigate, useParams, useSearch } from "@tanstack/react-router"; import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; @@ -51,7 +56,7 @@ import { dashboardKeys } from "@app/hooks/api/dashboard/queries"; import { DashboardSecretsOrderBy } from "@app/hooks/api/dashboard/types"; import { useGetFolderCommitsCount } from "@app/hooks/api/folderCommits"; import { OrderByDirection } from "@app/hooks/api/generic/types"; -import { ProjectVersion } from "@app/hooks/api/projects/types"; +import { ProjectType, ProjectVersion } from "@app/hooks/api/projects/types"; import { queryClient } from "@app/hooks/api/reactQuery"; import { PendingAction } from "@app/hooks/api/secretFolders/types"; import { useCreateCommit } from "@app/hooks/api/secrets/mutations"; @@ -760,9 +765,19 @@ const Page = () => { ); return ( -
+
+ + + Secrets Overview + diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx index 18f83cc20..146820bde 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx @@ -383,7 +383,7 @@ export const CommitForm: React.FC = ({
} subTitle="Write a commit message and review the changes you're about to save." - className="max-h-[90vh] max-w-[95%] md:max-w-7xl" + className="max-h-[90vh] max-w-[95%] md:max-w-8xl" >
{/* Changes List */} diff --git a/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx b/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx index f4b474b9e..600ab3710 100644 --- a/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx +++ b/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx @@ -52,6 +52,7 @@ import { useGetSecretRotations, useRestartSecretRotation } from "@app/hooks/api"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { TSecretRotationProviderTemplate } from "@app/hooks/api/secretRotation/types"; import { CreateRotationForm } from "@app/pages/secret-manager/SecretRotationPage/components/CreateRotationForm"; @@ -145,9 +146,9 @@ const Page = () => { }; return ( -
+
diff --git a/frontend/src/pages/secret-manager/SecretSyncDetailsByIDPage/SecretSyncDetailsByIDPage.tsx b/frontend/src/pages/secret-manager/SecretSyncDetailsByIDPage/SecretSyncDetailsByIDPage.tsx index 548c1c847..c009167ed 100644 --- a/frontend/src/pages/secret-manager/SecretSyncDetailsByIDPage/SecretSyncDetailsByIDPage.tsx +++ b/frontend/src/pages/secret-manager/SecretSyncDetailsByIDPage/SecretSyncDetailsByIDPage.tsx @@ -73,7 +73,7 @@ const PageContent = () => { return ( <>
-
+