feat: brought back assume privilege banner

This commit is contained in:
=
2025-07-20 23:21:43 +05:30
parent 272207c580
commit abda494374
51 changed files with 56 additions and 875 deletions

View File

@@ -42,7 +42,8 @@ export const initProjectHelper = async ({ projectName }: { projectName: string }
const {
data: { project }
} = await createWorkspace({
projectName
projectName,
type: ProjectType.SecretManager
});
try {

View File

@@ -4,10 +4,13 @@ import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { useProjectPermission, useWorkspace } from "@app/context";
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
export const KmsLayout = () => {
const { currentWorkspace } = useWorkspace();
const { assumedPrivilegeDetails } = useProjectPermission();
return (
<div className="dark hidden h-full w-full flex-col overflow-x-hidden md:flex">
@@ -120,6 +123,7 @@ export const KmsLayout = () => {
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>

View File

@@ -15,10 +15,13 @@ import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { useProjectPermission, useWorkspace } from "@app/context";
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
export const PkiManagerLayout = () => {
const { currentWorkspace } = useWorkspace();
const { assumedPrivilegeDetails } = useProjectPermission();
const { t } = useTranslation();
return (
@@ -184,6 +187,7 @@ export const PkiManagerLayout = () => {
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>

View File

@@ -1,53 +0,0 @@
import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Menu, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
export const ProjectGeneralLayout = () => {
const { currentWorkspace } = useWorkspace();
return (
<div className="dark hidden h-full w-full flex-col overflow-x-hidden md:flex">
<div className="flex flex-grow flex-col overflow-y-hidden md:flex-row">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
animate={{ x: 0 }}
exit={{ x: -150 }}
transition={{ duration: 0.2 }}
className="dark w-full border-r border-mineshaft-600 bg-gradient-to-tr from-mineshaft-700 via-mineshaft-800 to-mineshaft-900 md:w-60"
>
<nav className="items-between flex h-full flex-col overflow-y-auto dark:[color-scheme:dark]">
<div className="border-b border-mineshaft-600 px-4 py-3.5 text-lg text-white">
Project Overview
</div>
<div className="flex-1">
<Menu>
<Link
to="/projects/$projectId/access-management"
params={{
projectId: currentWorkspace.id
}}
>
{({ isActive }) => <MenuItem isSelected={isActive}>Access Control</MenuItem>}
</Link>
<Link
to="/projects/$projectId/settings"
params={{
projectId: currentWorkspace.id
}}
>
{({ isActive }) => <MenuItem isSelected={isActive}>Project Settings</MenuItem>}
</Link>
</Menu>
</div>
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
<Outlet />
</div>
</div>
</div>
);
};

View File

@@ -1 +0,0 @@
export { ProjectGeneralLayout } from "./ProjectGeneralLayout";

View File

@@ -1,68 +0,0 @@
import { useTranslation } from "react-i18next";
import { faDotCircle, faMobile, faWindowMaximize } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, Outlet, useLocation } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { twMerge } from "tailwind-merge";
import { ShouldWrap } from "@app/components/utilities/ShouldWrapComponent";
import {
Divider,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
Lottie,
Menu,
MenuItem,
Tooltip
} from "@app/components/v2";
import { useProjectPermission, useWorkspace } from "@app/context";
import { getCurrentProductFromUrl } from "@app/helpers/project";
import { useLocalStorageState } from "@app/hooks";
import { ProjectType } from "@app/hooks/api/workspace/types";
import { AssumePrivilegeModeBanner } from "./components/AssumePrivilegeModeBanner";
enum SidebarStyle {
Expanded = "expanded",
Collapsed = "collapsed",
ExpandOnHover = "expand-on-hover"
}
const MIN_SIDEBAR_SIZE = "55px";
const MAX_SIDEBAR_SIZE = "220px";
// This is a generic layout shared by all types of projects.
// If the product layout differs significantly, create a new layout as needed.
export const ProjectLayout = () => {
const location = useLocation();
const { t } = useTranslation();
const { assumedPrivilegeDetails } = useProjectPermission();
const currentProductType = getCurrentProductFromUrl(location.pathname);
return (
<>
<div
className="dark relative hidden w-full flex-col overflow-x-hidden md:flex"
style={{
height: "calc(100vh - 3rem)",
paddingLeft: !(sidebarStyle === SidebarStyle.Expanded) ? MIN_SIDEBAR_SIZE : "0px"
}}
>
<div className="flex flex-grow flex-col overflow-y-auto overflow-x-hidden md:flex-row">
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>
</div>
<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" />
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
{` ${t("common.no-mobile")} `}
</p>
</div>
</>
);
};

View File

@@ -3,10 +3,9 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button } from "@app/components/v2";
import { useProjectPermission, useWorkspace } from "@app/context";
import { getCurrentProductFromUrl, getProjectHomePage } from "@app/helpers/project";
import { getProjectHomePage } from "@app/helpers/project";
import { useRemoveAssumeProjectPrivilege } from "@app/hooks/api";
import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { ProjectType } from "@app/hooks/api/workspace/types";
export const AssumePrivilegeModeBanner = () => {
const { currentWorkspace } = useWorkspace();
@@ -37,10 +36,7 @@ export const AssumePrivilegeModeBanner = () => {
},
{
onSuccess: () => {
const url = getProjectHomePage(
getCurrentProductFromUrl(window.location.href) || ProjectType.SecretManager
);
const url = getProjectHomePage(currentWorkspace.type);
window.location.href = url.replace("$projectId", currentWorkspace.id);
}
}

View File

@@ -1,121 +0,0 @@
import { ComponentPropsWithRef, ElementType, useRef } from "react";
import { DotLottie, DotLottieReact } from "@lottiefiles/dotlottie-react";
import { twMerge } from "tailwind-merge";
import { MenuItemProps } from "@app/components/v2";
export const MenuIconButton = <T extends ElementType = "button">({
children,
icon,
className,
isDisabled,
isSelected,
as: Item = "div",
description,
// wrapping in forward ref with generic component causes the loss of ts definitions on props
inputRef,
lottieIconMode = "forward",
...props
}: MenuItemProps<T> &
ComponentPropsWithRef<T> & { lottieIconMode?: "reverse" | "forward" }): JSX.Element => {
const iconRef = useRef<DotLottie | null>(null);
return (
<div className="px-1">
<Item
type="button"
role="menuitem"
className={twMerge(
"group relative my-1 flex w-full cursor-pointer flex-col items-center justify-center rounded p-2 font-inter text-sm text-bunker-100 transition-all duration-150 hover:bg-mineshaft-700",
isSelected && "bg-bunker-8g0 hover:bg-mineshaft-500",
isDisabled && "cursor-not-allowed hover:bg-transparent",
className
)}
onMouseEnter={() => iconRef.current?.play()}
onMouseLeave={() => iconRef.current?.stop()}
ref={inputRef}
{...props}
>
<div
className={`${isSelected ? "opacity-100" : "opacity-0"} absolute left-0 h-full w-0.5 rounded-bl rounded-tl bg-primary transition-all duration-150`}
/>
{icon && (
<div className="my-auto mb-2 h-6 w-6">
<DotLottieReact
dotLottieRefCallback={(el) => {
iconRef.current = el;
}}
src={`/lotties/${icon}.json`}
loop
className="h-full w-full"
mode={lottieIconMode}
/>
</div>
)}
<div
className="flex-grow justify-center break-words text-center"
style={{ fontSize: "10px" }}
>
{children}
</div>
</Item>
</div>
);
};
// export const MenuIconButton = <T extends ElementType = "button">({
// children,
// icon,
// className,
// isDisabled,
// isSelected,
// as: Item = "div",
// description,
// // wrapping in forward ref with generic component causes the loss of ts definitions on props
// inputRef,
// lottieIconMode = "forward",
// ...props
// }: MenuItemProps<T> &
// ComponentPropsWithRef<T> & { lottieIconMode?: "reverse" | "forward" }): JSX.Element => {
// const iconRef = useRef<DotLottie | null>(null);
// return (
// <div className="px-1">
// <Item
// type="button"
// role="menuitem"
// className={twMerge(
// "group relative my-1 flex w-full cursor-pointer flex-col items-center justify-center rounded p-2 font-inter text-sm text-bunker-100 transition-all duration-150 hover:bg-mineshaft-700",
// isSelected && "bg-mineshaft-600 hover:bg-mineshaft-700",
// isDisabled && "cursor-not-allowed hover:bg-transparent",
// className
// )}
// onMouseEnter={() => iconRef.current?.play()}
// onMouseLeave={() => iconRef.current?.stop()}
// ref={inputRef}
// {...props}
// >
// <div
// className={`${"opacity-0"} absolute left-0 h-full w-1 bg-primary transition-all duration-150`}
// />
// {icon && (
// <div className="my-auto mb-2 h-6 w-6">
// <DotLottieReact
// dotLottieRefCallback={(el) => {
// iconRef.current = el;
// }}
// src={`/lotties/${icon}.json`}
// loop
// className="h-full w-full"
// mode={lottieIconMode}
// />
// </div>
// )}
// <div
// className="flex-grow justify-center break-words text-center"
// style={{ fontSize: "10px" }}
// >
// {children}
// </div>
// </Item>
// </div>
// );
// };

View File

@@ -1,65 +0,0 @@
import { ComponentPropsWithRef, ElementType, useRef } from "react";
import { DotLottie, DotLottieReact } from "@lottiefiles/dotlottie-react";
import { twMerge } from "tailwind-merge";
import { MenuItemProps } from "@app/components/v2";
export const MenuIconButton = <T extends ElementType = "button">({
children,
icon,
className,
isDisabled,
isSelected,
as: Item = "div",
description,
// wrapping in forward ref with generic component causes the loss of ts definitions on props
inputRef,
lottieIconMode = "forward",
...props
}: MenuItemProps<T> &
ComponentPropsWithRef<T> & { lottieIconMode?: "reverse" | "forward" }): JSX.Element => {
const iconRef = useRef<DotLottie | null>(null);
return (
<div>
<Item
type="button"
role="menuitem"
className={twMerge(
"group relative flex w-full cursor-pointer flex-col items-center justify-center p-2 font-inter text-sm text-bunker-100 transition-all duration-150 hover:bg-mineshaft-700",
isSelected && "rounded-none bg-bunker-800 hover:bg-mineshaft-600",
isDisabled && "cursor-not-allowed hover:bg-transparent",
className
)}
onMouseEnter={() => iconRef.current?.play()}
onMouseLeave={() => iconRef.current?.stop()}
ref={inputRef}
{...props}
>
<div
className={`${
isSelected ? "opacity-100" : "opacity-0"
} absolute left-0 h-full w-0.5 bg-primary transition-all duration-150`}
/>
{icon && (
<div className="my-auto mb-2 h-6 w-6">
<DotLottieReact
dotLottieRefCallback={(el) => {
iconRef.current = el;
}}
src={`/lotties/${icon}.json`}
loop
className="h-full w-full"
mode={lottieIconMode}
/>
</div>
)}
<div
className="flex-grow justify-center break-words text-center"
style={{ fontSize: "10px" }}
>
{children}
</div>
</Item>
</div>
);
};

View File

@@ -1 +0,0 @@
export { MenuIconButton } from "./MenuIconButton";

View File

@@ -1,179 +0,0 @@
import {
faAngleDown,
faArrowLeft,
faArrowUpRightFromSquare,
faCheck
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate } from "@tanstack/react-router";
import {
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "@app/components/v2";
import { useOrganization, useUser } from "@app/context";
import { useGetOrganizations, useLogoutUser } from "@app/hooks/api";
import { AuthMethod } from "@app/hooks/api/users/types";
type Prop = {
onChangeOrg: (orgId: string) => void;
};
export const SidebarHeader = ({ onChangeOrg }: Prop) => {
const { currentOrg } = useOrganization();
const { user } = useUser();
const navigate = useNavigate();
const { data: orgs } = useGetOrganizations();
const logout = useLogoutUser();
const logOutUser = async () => {
try {
console.log("Logging out...");
await logout.mutateAsync();
navigate({ to: "/login" });
} catch (error) {
console.error(error);
}
};
return (
<div className="flex h-12 cursor-default items-center px-3 pt-6">
<Link to="/organization/projects">
<div className="pl-1 pr-2 text-mineshaft-400 duration-200 hover:text-mineshaft-100">
<FontAwesomeIcon icon={faArrowLeft} />
</div>
</Link>
<DropdownMenu>
<DropdownMenuTrigger asChild className="max-w-[160px] data-[state=open]:bg-mineshaft-600">
<div className="mr-auto flex items-center rounded-md py-1.5 pl-1.5 pr-2 hover:bg-mineshaft-600">
<div className="flex h-5 w-5 min-w-[20px] items-center justify-center rounded-md bg-primary text-sm">
{currentOrg?.name.charAt(0)}
</div>
<div
className="overflow-hidden truncate text-ellipsis pl-2 text-sm text-mineshaft-100"
style={{ maxWidth: "140px" }}
>
{currentOrg?.name}
</div>
<FontAwesomeIcon icon={faAngleDown} className="pl-1 pt-1 text-xs text-mineshaft-300" />
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1">
<div className="px-2 py-1 text-xs text-mineshaft-400">{user?.username}</div>
{orgs?.map((org) => {
return (
<DropdownMenuItem key={org.id}>
<Button
onClick={async () => {
if (currentOrg?.id === org.id) return;
if (org.authEnforced) {
// org has an org-level auth method enabled (e.g. SAML)
// -> logout + redirect to SAML SSO
await logout.mutateAsync();
if (org.orgAuthMethod === AuthMethod.OIDC) {
window.open(`/api/v1/sso/oidc/login?orgSlug=${org.slug}`);
} else {
window.open(`/api/v1/sso/redirect/saml2/organizations/${org.slug}`);
}
window.close();
return;
}
onChangeOrg(org?.id);
}}
variant="plain"
colorSchema="secondary"
size="xs"
className="flex w-full items-center justify-start p-0 font-normal"
leftIcon={
currentOrg?.id === org.id && (
<FontAwesomeIcon icon={faCheck} className="mr-3 text-primary" />
)
}
>
<div className="flex w-full max-w-[150px] items-center justify-between truncate">
{org.name}
</div>
</Button>
</DropdownMenuItem>
);
})}
<div className="mt-1 h-1 border-t border-mineshaft-600" />
<button type="button" onClick={logOutUser} className="w-full">
<DropdownMenuItem>Log Out</DropdownMenuItem>
</button>
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger
asChild
className="p-1 hover:bg-primary-400 hover:text-black data-[state=open]:bg-primary-400 data-[state=open]:text-black"
>
<div
className="child flex items-center justify-center rounded-full bg-mineshaft pr-1 text-mineshaft-300 hover:bg-mineshaft-500"
style={{ fontSize: "11px", width: "26px", height: "26px" }}
>
{user?.firstName?.charAt(0)}
{user?.lastName && user?.lastName?.charAt(0)}
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1">
<div className="px-2 py-1 text-xs text-mineshaft-400">{user?.username}</div>
<Link to="/personal-settings">
<DropdownMenuItem>Personal Settings</DropdownMenuItem>
</Link>
<a
href="https://infisical.com/docs/documentation/getting-started/introduction"
target="_blank"
rel="noopener noreferrer"
className="mt-3 w-full text-sm font-normal leading-[1.2rem] text-mineshaft-300 hover:text-mineshaft-100"
>
<DropdownMenuItem>
Documentation
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.06rem] pl-1.5 text-xxs"
/>
</DropdownMenuItem>
</a>
<a
href="https://infisical.com/slack"
target="_blank"
rel="noopener noreferrer"
className="mt-3 w-full text-sm font-normal leading-[1.2rem] text-mineshaft-300 hover:text-mineshaft-100"
>
<DropdownMenuItem>
Join Slack Community
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.06rem] pl-1.5 text-xxs"
/>
</DropdownMenuItem>
</a>
{user?.superAdmin && (
<Link to="/admin">
<DropdownMenuItem className="mt-1 border-t border-mineshaft-600">
Server Admin Console
</DropdownMenuItem>
</Link>
)}
<Link to="/organization/admin">
<DropdownMenuItem className="mt-1 border-t border-mineshaft-600">
Organization Admin Console
</DropdownMenuItem>
</Link>
<div className="mt-1 h-1 border-t border-mineshaft-600" />
<button type="button" onClick={logOutUser} className="w-full">
<DropdownMenuItem>Log Out</DropdownMenuItem>
</button>
</DropdownMenuContent>
</DropdownMenu>
</div>
);
};

View File

@@ -1 +0,0 @@
export { SidebarHeader } from "./SidebarHeader";

View File

@@ -1 +0,0 @@
export { ProjectLayout } from "./ProjectLayout";

View File

@@ -14,15 +14,18 @@ import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Badge, Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { useProjectPermission, useWorkspace } from "@app/context";
import {
useGetAccessRequestsCount,
useGetSecretApprovalRequestCount,
useGetSecretRotations
} from "@app/hooks/api";
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
export const SecretManagerLayout = () => {
const { currentWorkspace } = useWorkspace();
const { assumedPrivilegeDetails } = useProjectPermission();
const { t } = useTranslation();
const workspaceId = currentWorkspace?.id || "";
@@ -202,6 +205,7 @@ export const SecretManagerLayout = () => {
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>

View File

@@ -10,10 +10,13 @@ import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { useProjectPermission, useWorkspace } from "@app/context";
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
export const SecretScanningLayout = () => {
const { currentWorkspace } = useWorkspace();
const { assumedPrivilegeDetails } = useProjectPermission();
return (
<div className="dark hidden h-full w-full flex-col overflow-x-hidden md:flex">
@@ -126,6 +129,7 @@ export const SecretScanningLayout = () => {
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>

View File

@@ -5,10 +5,18 @@ import { motion } from "framer-motion";
import { ProjectPermissionCan } from "@app/components/permissions";
import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import {
ProjectPermissionActions,
ProjectPermissionSub,
useProjectPermission,
useWorkspace
} from "@app/context";
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
export const SshLayout = () => {
const { currentWorkspace } = useWorkspace();
const { assumedPrivilegeDetails } = useProjectPermission();
return (
<div className="dark hidden h-full w-full flex-col overflow-x-hidden md:flex">
@@ -131,6 +139,7 @@ export const SshLayout = () => {
</nav>
</motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
<Outlet />
</div>
</div>

View File

@@ -1,32 +0,0 @@
import { createFileRoute, stripSearchParams } from "@tanstack/react-router";
import { zodValidator } from "@tanstack/zod-adapter";
import { z } from "zod";
import { ProjectAccessControlTabs } from "@app/types/project";
import { AccessControlPage } from "./AccessControlPage";
const AccessControlPageQuerySchema = z.object({
selectedTab: z.nativeEnum(ProjectAccessControlTabs).catch(ProjectAccessControlTabs.Member),
requesterEmail: z.string().catch("")
});
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/access-management"
)({
component: AccessControlPage,
validateSearch: zodValidator(AccessControlPageQuerySchema),
search: {
middlewares: [stripSearchParams({ requesterEmail: "" })]
},
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control"
}
]
};
}
});

View File

@@ -24,7 +24,7 @@ import {
Tr
} from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { getCurrentProductFromUrl, getProjectHomePage } from "@app/helpers/project";
import { getProjectHomePage } from "@app/helpers/project";
import {
getUserTablePreference,
PreferenceKey,
@@ -36,7 +36,6 @@ import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { OrderByDirection } from "@app/hooks/api/generic/types";
import { useListProjectGroupUsers } from "@app/hooks/api/groups/queries";
import { EFilterReturnedUsers, TGroupMembership } from "@app/hooks/api/groups/types";
import { ProjectType } from "@app/hooks/api/workspace/types";
import { GroupMembershipRow } from "./GroupMembershipRow";
@@ -137,9 +136,7 @@ export const GroupMembersTable = ({ groupMembership }: Props) => {
text: "User privilege assumption has started"
});
const url = getProjectHomePage(
getCurrentProductFromUrl(window.location.href) || ProjectType.SecretManager
);
const url = getProjectHomePage(currentWorkspace.type);
window.location.href = url.replace("$projectId", currentWorkspace.id);
}
}

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/cert-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/kms/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-scanning/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/ssh/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -1,33 +0,0 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { ProjectAccessControlTabs } from "@app/types/project";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
params: {
projectId: params.projectId
},
search: {
selectedTab: ProjectAccessControlTabs.Groups
}
})
},
{
label: "Group"
}
]
};
}
});

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/cert-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/kms/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-scanning/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/ssh/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -1,33 +0,0 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { ProjectAccessControlTabs } from "@app/types/project";
import { IdentityDetailsByIDPage } from "./IdentityDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/identities/$identityId"
)({
component: IdentityDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
params: {
projectId: params.projectId
},
search: {
selectedTab: ProjectAccessControlTabs.Identities
}
})
},
{
label: "Machine Identity"
}
]
};
}
});

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/cert-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/kms/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-scanning/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/ssh/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -1,33 +0,0 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { ProjectAccessControlTabs } from "@app/types/project";
import { MemberDetailsByIDPage } from "./MemberDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/members/$membershipId"
)({
component: MemberDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
params: {
projectId: params.projectId
},
search: {
selectedTab: ProjectAccessControlTabs.Member
}
})
},
{
label: "User"
}
]
};
}
});

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/cert-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/kms/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-management/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/secret-scanning/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -15,7 +15,7 @@ export const Route = createFileRoute(
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
to: "/projects/ssh/$projectId/access-management",
params: {
projectId: params.projectId
},

View File

@@ -1,33 +0,0 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { ProjectAccessControlTabs } from "@app/types/project";
import { RoleDetailsBySlugPage } from "./RoleDetailsBySlugPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/roles/$roleSlug"
)({
component: RoleDetailsBySlugPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/projects/$projectId/access-management",
params: {
projectId: params.projectId
},
search: {
selectedTab: ProjectAccessControlTabs.Roles
}
})
},
{
label: "Roles"
}
]
};
}
});

View File

@@ -1,40 +0,0 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectGeneralTab } from "./components/ProjectGeneralTab";
const tabs = [{ name: "General", key: "tab-project-general", Component: ProjectGeneralTab }];
export const SettingsPage = () => {
const { t } = useTranslation();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
</Helmet>
<div className="w-full max-w-7xl">
<PageHeader
title={t("settings.project.title")}
description="Configure your project details and project-specific settings"
/>
<Tabs defaultValue={tabs[0].key}>
<TabList>
{tabs.map((tab) => (
<Tab value={tab.key} key={tab.key}>
{tab.name}
</Tab>
))}
</TabList>
{tabs.map(({ key, Component }) => (
<TabPanel value={key} key={key}>
<Component />
</TabPanel>
))}
</Tabs>
</div>
</div>
);
};

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/_project-layout/projects/ssh/$projectId/_ssh-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,19 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout/settings"
)({
component: SettingsPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Settings"
}
]
};
}
});

View File

@@ -1,9 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { ProjectGeneralLayout } from "@app/layouts/ProjectGeneralLayout";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/projects/$projectId/_project-layout/_project-general-layout"
)({
component: ProjectGeneralLayout
});

View File

@@ -1,21 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
import { BreadcrumbTypes } from "@app/components/v2";
import { ProjectLayout } from "@app/layouts/ProjectLayout";
import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/_project-layout"
)({
component: ProjectLayout,
beforeLoad: async () => {
return {
breadcrumbs: [
{
type: BreadcrumbTypes.Component,
component: ProjectSelect
}
]
};
}
});