feat: completed all layout changes needed for frontend

This commit is contained in:
=
2025-07-20 14:50:03 +05:30
parent cc9f4fb5b3
commit ec8ea76e2c
79 changed files with 1098 additions and 697 deletions

View File

@@ -4,6 +4,7 @@ import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate } from "@tanstack/react-router";
import { twMerge } from "tailwind-merge";
import z from "zod"; import z from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
@@ -16,6 +17,7 @@ import {
Button, Button,
FormControl, FormControl,
Input, Input,
Lottie,
Modal, Modal,
ModalClose, ModalClose,
ModalContent, ModalContent,
@@ -35,6 +37,7 @@ import { getProjectHomePage } from "@app/helpers/project";
import { useCreateWorkspace, useGetExternalKmsList, useGetUserWorkspaces } from "@app/hooks/api"; import { useCreateWorkspace, useGetExternalKmsList, useGetUserWorkspaces } from "@app/hooks/api";
import { INTERNAL_KMS_KEY_ID } from "@app/hooks/api/kms/types"; import { INTERNAL_KMS_KEY_ID } from "@app/hooks/api/kms/types";
import { InfisicalProjectTemplate, useListProjectTemplates } from "@app/hooks/api/projectTemplates"; import { InfisicalProjectTemplate, useListProjectTemplates } from "@app/hooks/api/projectTemplates";
import { ProjectType } from "@app/hooks/api/workspace/types";
const formSchema = z.object({ const formSchema = z.object({
name: z.string().trim().min(1, "Required").max(64, "Too long, maximum length is 64 characters"), name: z.string().trim().min(1, "Required").max(64, "Too long, maximum length is 64 characters"),
@@ -43,6 +46,7 @@ const formSchema = z.object({
.trim() .trim()
.max(256, "Description too long, max length is 256 characters") .max(256, "Description too long, max length is 256 characters")
.optional(), .optional(),
type: z.nativeEnum(ProjectType),
kmsKeyId: z.string(), kmsKeyId: z.string(),
template: z.string() template: z.string()
}); });
@@ -56,6 +60,34 @@ interface NewProjectModalProps {
type NewProjectFormProps = Pick<NewProjectModalProps, "onOpenChange">; type NewProjectFormProps = Pick<NewProjectModalProps, "onOpenChange">;
const PROJECT_TYPE_MENU_ITEMS = [
{
label: "Secret Manager",
value: ProjectType.SecretManager,
icon: "vault"
},
{
label: "Certificate Manager",
value: ProjectType.CertificateManager,
icon: "note"
},
{
label: "KMS",
value: ProjectType.KMS,
icon: "unlock"
},
{
label: "SSH",
value: ProjectType.SSH,
icon: "terminal"
},
{
label: "Secret Scanning",
value: ProjectType.SecretScanning,
icon: "secret-scan"
}
];
const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => { const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
@@ -101,7 +133,8 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
name, name,
description, description,
kmsKeyId, kmsKeyId,
template template,
type
}: TAddProjectFormData) => { }: TAddProjectFormData) => {
// type check // type check
if (!currentOrg) return; if (!currentOrg) return;
@@ -113,7 +146,8 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
projectName: name, projectName: name,
projectDescription: description, projectDescription: description,
kmsKeyId: kmsKeyId !== INTERNAL_KMS_KEY_ID ? kmsKeyId : undefined, kmsKeyId: kmsKeyId !== INTERNAL_KMS_KEY_ID ? kmsKeyId : undefined,
template template,
type
}); });
await refetchWorkspaces(); await refetchWorkspaces();
@@ -150,6 +184,42 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
</FormControl> </FormControl>
)} )}
/> />
<Controller
control={control}
name="type"
defaultValue={ProjectType.SecretManager}
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Type"
isError={Boolean(error)}
errorText={error?.message}
className="flex-1"
>
<div className="mt-2 grid grid-cols-5 gap-4">
{PROJECT_TYPE_MENU_ITEMS.map((el) => (
<div
key={el.value}
className={twMerge(
"flex cursor-pointer flex-col items-center gap-2 rounded border border-mineshaft-600 p-4 opacity-75 transition-all hover:border-primary-400 hover:bg-mineshaft-600",
field.value === el.value && "border-primary-400 bg-mineshaft-600 opacity-100"
)}
onClick={() => field.onChange(el.value)}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "Enter") {
field.onChange(el.value);
}
}}
>
<Lottie icon={el.icon} className="h-8 w-8" />
<div className="text-center text-xs">{el.label}</div>
</div>
))}
</div>
</FormControl>
)}
/>
<Controller <Controller
control={control} control={control}
name="description" name="description"
@@ -171,6 +241,7 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
</FormControl> </FormControl>
)} )}
/> />
<Controller <Controller
control={control} control={control}
name="template" name="template"

View File

@@ -94,3 +94,14 @@ export const getProjectTitle = (type: ProjectType) => {
}; };
return titleConvert[type]; return titleConvert[type];
}; };
export const getProjectLottieIcon = (type: ProjectType) => {
const titleConvert = {
[ProjectType.SecretManager]: "vault",
[ProjectType.KMS]: "unlock",
[ProjectType.CertificateManager]: "note",
[ProjectType.SSH]: "terminal",
[ProjectType.SecretScanning]: "secret-scan"
};
return titleConvert[type];
};

View File

@@ -51,7 +51,7 @@ export type IdentityMembershipOrg = {
export type IdentityMembership = { export type IdentityMembership = {
id: string; id: string;
identity: Identity; identity: Identity;
project: Pick<Workspace, "id" | "name">; project: Pick<Workspace, "id" | "name" | "type">;
roles: Array< roles: Array<
{ {
id: string; id: string;

View File

@@ -184,6 +184,7 @@ export type TSearchProjectsDTO = {
name?: string; name?: string;
limit?: number; limit?: number;
offset?: number; offset?: number;
type?: ProjectType;
options?: { enabled?: boolean }; options?: { enabled?: boolean };
orderBy?: ProjectIdentityOrderBy; orderBy?: ProjectIdentityOrderBy;
orderDirection?: OrderByDirection; orderDirection?: OrderByDirection;

View File

@@ -1,10 +1,10 @@
import { 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 } from "@tanstack/react-router";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCog, faUsers } from "@fortawesome/free-solid-svg-icons";
export const KmsLayout = () => { export const KmsLayout = () => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
@@ -34,7 +34,16 @@ export const KmsLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>Overview</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faCube} />
</div>
Overview
</div>
</MenuItem>
)}
</Link> </Link>
<Link <Link
to="/projects/kms/$projectId/kmip" to="/projects/kms/$projectId/kmip"
@@ -42,7 +51,16 @@ export const KmsLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>KMIP</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faLock} />
</div>
KMIP
</div>
</MenuItem>
)}
</Link> </Link>
</MenuGroup> </MenuGroup>
<MenuGroup title="Others"> <MenuGroup title="Others">
@@ -83,6 +101,22 @@ export const KmsLayout = () => {
</MenuGroup> </MenuGroup>
</Menu> </Menu>
</div> </div>
<div>
<Menu>
<Link to="/organization/projects">
<MenuItem
className="relative flex items-center gap-2 overflow-hidden text-sm text-mineshaft-400 hover:text-mineshaft-300"
leftIcon={
<div className="w-6">
<FontAwesomeIcon className="mx-1 inline-block shrink-0" icon={faHome} />
</div>
}
>
Organization Home
</MenuItem>
</Link>
</Menu>
</div>
</nav> </nav>
</motion.div> </motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8"> <div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">

View File

@@ -1,5 +1,15 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { faCog, faMobile, faUsers } from "@fortawesome/free-solid-svg-icons"; import {
faBell,
faCertificate,
faCog,
faFileLines,
faHome,
faMobile,
faSitemap,
faStamp,
faUsers
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, Outlet } from "@tanstack/react-router"; import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
@@ -37,7 +47,16 @@ export const PkiManagerLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>Subscribers</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faSitemap} />
</div>
Subscribers
</div>
</MenuItem>
)}
</Link> </Link>
<Link <Link
to="/projects/cert-management/$projectId/certificate-templates" to="/projects/cert-management/$projectId/certificate-templates"
@@ -46,7 +65,14 @@ export const PkiManagerLayout = () => {
}} }}
> >
{({ isActive }) => ( {({ isActive }) => (
<MenuItem isSelected={isActive}> Certificate Templates</MenuItem> <MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faFileLines} />
</div>
Certificate Templates
</div>
</MenuItem>
)} )}
</Link> </Link>
<Link <Link
@@ -55,7 +81,16 @@ export const PkiManagerLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}> Certificates</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faCertificate} />
</div>
Certificates
</div>
</MenuItem>
)}
</Link> </Link>
<Link <Link
to="/projects/cert-management/$projectId/certificate-authorities" to="/projects/cert-management/$projectId/certificate-authorities"
@@ -64,7 +99,14 @@ export const PkiManagerLayout = () => {
}} }}
> >
{({ isActive }) => ( {({ isActive }) => (
<MenuItem isSelected={isActive}> Certificates Authorities</MenuItem> <MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faStamp} />
</div>
Certificates Authority
</div>
</MenuItem>
)} )}
</Link> </Link>
<Link <Link
@@ -73,7 +115,16 @@ export const PkiManagerLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>Alerting</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faBell} />
</div>
Alerting
</div>
</MenuItem>
)}
</Link> </Link>
</MenuGroup> </MenuGroup>
<MenuGroup title="Others"> <MenuGroup title="Others">
@@ -114,6 +165,22 @@ export const PkiManagerLayout = () => {
</MenuGroup> </MenuGroup>
</Menu> </Menu>
</div> </div>
<div>
<Menu>
<Link to="/organization/projects">
<MenuItem
className="relative flex items-center gap-2 overflow-hidden text-sm text-mineshaft-400 hover:text-mineshaft-300"
leftIcon={
<div className="w-6">
<FontAwesomeIcon className="mx-1 inline-block shrink-0" icon={faHome} />
</div>
}
>
Organization Home
</MenuItem>
</Link>
</Menu>
</div>
</nav> </nav>
</motion.div> </motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8"> <div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">

View File

@@ -3,6 +3,7 @@ import {
faArrowsSpin, faArrowsSpin,
faCheckToSlot, faCheckToSlot,
faCog, faCog,
faHome,
faMobile, faMobile,
faPuzzlePiece, faPuzzlePiece,
faUsers, faUsers,
@@ -182,6 +183,22 @@ export const SecretManagerLayout = () => {
</MenuGroup> </MenuGroup>
</Menu> </Menu>
</div> </div>
<div>
<Menu>
<Link to="/organization/projects">
<MenuItem
className="relative flex items-center gap-2 overflow-hidden text-sm text-mineshaft-400 hover:text-mineshaft-300"
leftIcon={
<div className="w-6">
<FontAwesomeIcon className="mx-1 inline-block shrink-0" icon={faHome} />
</div>
}
>
Organization Home
</MenuItem>
</Link>
</Menu>
</div>
</nav> </nav>
</motion.div> </motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8"> <div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">

View File

@@ -1,9 +1,15 @@
import { faCog, faUsers } from "@fortawesome/free-solid-svg-icons"; import {
faCog,
faDatabase,
faHome,
faMagnifyingGlass,
faUsers
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, Outlet } from "@tanstack/react-router"; import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { Menu, MenuGroup, MenuItem } from "@app/components/v2"; import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
export const SecretScanningLayout = () => { export const SecretScanningLayout = () => {
@@ -21,7 +27,8 @@ export const SecretScanningLayout = () => {
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" 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]"> <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"> <div className="flex items-center gap-3 border-b border-mineshaft-600 px-4 py-3.5 text-lg text-white">
<Lottie className="inline-block h-5 w-5 shrink-0" icon="secret-scan" />
Secret Scanning Secret Scanning
</div> </div>
<div className="flex-1"> <div className="flex-1">
@@ -33,7 +40,16 @@ export const SecretScanningLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}> Data Sources</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faDatabase} />
</div>
Data Sources
</div>
</MenuItem>
)}
</Link> </Link>
<Link <Link
to="/projects/secret-scanning/$projectId/findings" to="/projects/secret-scanning/$projectId/findings"
@@ -41,7 +57,16 @@ export const SecretScanningLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>Findings</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faMagnifyingGlass} />
</div>
Findings
</div>
</MenuItem>
)}
</Link> </Link>
</MenuGroup> </MenuGroup>
<MenuGroup title="Others"> <MenuGroup title="Others">
@@ -82,6 +107,22 @@ export const SecretScanningLayout = () => {
</MenuGroup> </MenuGroup>
</Menu> </Menu>
</div> </div>
<div>
<Menu>
<Link to="/organization/projects">
<MenuItem
className="relative flex items-center gap-2 overflow-hidden text-sm text-mineshaft-400 hover:text-mineshaft-300"
leftIcon={
<div className="w-6">
<FontAwesomeIcon className="mx-1 inline-block shrink-0" icon={faHome} />
</div>
}
>
Organization Home
</MenuItem>
</Link>
</Menu>
</div>
</nav> </nav>
</motion.div> </motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8"> <div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">

View File

@@ -1,11 +1,11 @@
import { faCog, faHome, faServer, faStamp, faUsers } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, Outlet } from "@tanstack/react-router"; import { Link, Outlet } from "@tanstack/react-router";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { Menu, MenuGroup, MenuItem } from "@app/components/v2"; import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCog, faUsers } from "@fortawesome/free-solid-svg-icons";
export const SshLayout = () => { export const SshLayout = () => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
@@ -22,7 +22,10 @@ export const SshLayout = () => {
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" 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]"> <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">SSH</div> <div className="flex items-center gap-3 border-b border-mineshaft-600 px-4 py-3.5 text-lg text-white">
<Lottie className="inline-block h-5 w-5 shrink-0" icon="terminal" />
SSH
</div>
<div className="flex-1"> <div className="flex-1">
<Menu> <Menu>
<MenuGroup title="Resources"> <MenuGroup title="Resources">
@@ -32,7 +35,16 @@ export const SshLayout = () => {
projectId: currentWorkspace.id projectId: currentWorkspace.id
}} }}
> >
{({ isActive }) => <MenuItem isSelected={isActive}>Hosts</MenuItem>} {({ isActive }) => (
<MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faServer} />
</div>
Hosts
</div>
</MenuItem>
)}
</Link> </Link>
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionActions.Read} I={ProjectPermissionActions.Read}
@@ -47,7 +59,14 @@ export const SshLayout = () => {
}} }}
> >
{({ isActive }) => ( {({ isActive }) => (
<MenuItem isSelected={isActive}>Certificate Authorities</MenuItem> <MenuItem isSelected={isActive}>
<div className="mx-1 flex gap-2">
<div className="w-6">
<FontAwesomeIcon icon={faStamp} />
</div>
Certificates Authority
</div>
</MenuItem>
)} )}
</Link> </Link>
) )
@@ -93,6 +112,22 @@ export const SshLayout = () => {
</MenuGroup> </MenuGroup>
</Menu> </Menu>
</div> </div>
<div>
<Menu>
<Link to="/organization/projects">
<MenuItem
className="relative flex items-center gap-2 overflow-hidden text-sm text-mineshaft-400 hover:text-mineshaft-300"
leftIcon={
<div className="w-6">
<FontAwesomeIcon className="mx-1 inline-block shrink-0" icon={faHome} />
</div>
}
>
Organization Home
</MenuItem>
</Link>
</Menu>
</div>
</nav> </nav>
</motion.div> </motion.div>
<div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8"> <div className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 p-4 pt-8">

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { CertificateAuthoritiesPage } from './CertificateAuthoritiesPage' import { CertificateAuthoritiesPage } from "./CertificateAuthoritiesPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificate-authorities', "/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificate-authorities"
)({ )({
component: CertificateAuthoritiesPage, component: CertificateAuthoritiesPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Certificate Authorities', label: "Certificate Authorities"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { CertificatesPage } from './CertificatesPage' import { CertificatesPage } from "./CertificatesPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificates', "/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificates"
)({ )({
component: CertificatesPage, component: CertificatesPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Certificates', label: "Certificates"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { PkiSubscribersPage } from './PkiSubscribersPage' import { PkiSubscribersPage } from "./PkiSubscribersPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/subscribers/', "/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/subscribers/"
)({ )({
component: PkiSubscribersPage, component: PkiSubscribersPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Subscribers', label: "Subscribers"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { PkiTemplateListPage } from './PkiTemplateListPage' import { PkiTemplateListPage } from "./PkiTemplateListPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificate-templates/', "/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificate-templates/"
)({ )({
component: PkiTemplateListPage, component: PkiTemplateListPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Certificate Templates', label: "Certificate Templates"
}, }
], ]
} };
}, }
}) });

View File

@@ -2,12 +2,13 @@ import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
const tabs = [ const tabs = [
{ {
name: "General", name: "General",
key: "tab-project-general", key: "tab-project-general",
Component: () => <div className="text-white">Coming soon</div> Component: ProjectGeneralTab
} }
]; ];

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from './SettingsPage' import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/settings', "/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/settings"
)({ )({
component: SettingsPage, component: SettingsPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Settings', label: "Settings"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,10 +1,10 @@
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
import { PkiManagerLayout } from "@app/layouts/PkiManagerLayout";
import { workspaceKeys } from "@app/hooks/api";
import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries";
import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries";
import { BreadcrumbTypes } from "@app/components/v2"; import { BreadcrumbTypes } from "@app/components/v2";
import { workspaceKeys } from "@app/hooks/api";
import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries";
import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries";
import { PkiManagerLayout } from "@app/layouts/PkiManagerLayout";
import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect"; import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect";
export const Route = createFileRoute( export const Route = createFileRoute(

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { KmipPage } from './KmipPage' import { KmipPage } from "./KmipPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/kms/$projectId/_kms-layout/kmip', "/_authenticate/_inject-org-details/_org-layout/projects/kms/$projectId/_kms-layout/kmip"
)({ )({
component: KmipPage, component: KmipPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'KMIP', label: "KMIP"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { OverviewPage } from './OverviewPage' import { OverviewPage } from "./OverviewPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/kms/$projectId/_kms-layout/overview', "/_authenticate/_inject-org-details/_org-layout/projects/kms/$projectId/_kms-layout/overview"
)({ )({
component: OverviewPage, component: OverviewPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Overview', label: "Overview"
}, }
], ]
} };
}, }
}) });

View File

@@ -2,12 +2,13 @@ import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
const tabs = [ const tabs = [
{ {
name: "General", name: "General",
key: "tab-project-general", key: "tab-project-general",
Component: () => <div className="text-white">Coming soon...</div> Component: ProjectGeneralTab
} }
]; ];

View File

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

View File

@@ -6,7 +6,6 @@ import { format } from "date-fns";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project"; import { getProjectBaseURL } from "@app/helpers/project";
import { formatProjectRoleName } from "@app/helpers/roles"; import { formatProjectRoleName } from "@app/helpers/roles";
import { useGetUserWorkspaces } from "@app/hooks/api"; import { useGetUserWorkspaces } from "@app/hooks/api";
@@ -34,7 +33,6 @@ export const IdentityProjectRow = ({
}: Props) => { }: Props) => {
const { data: workspaces } = useGetUserWorkspaces(); const { data: workspaces } = useGetUserWorkspaces();
const navigate = useNavigate(); const navigate = useNavigate();
const { currentWorkspace } = useWorkspace();
const isAccessible = useMemo(() => { const isAccessible = useMemo(() => {
const workspaceIds = new Map(); const workspaceIds = new Map();
@@ -53,7 +51,7 @@ export const IdentityProjectRow = ({
onClick={() => { onClick={() => {
if (isAccessible) { if (isAccessible) {
navigate({ navigate({
to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, to: `${getProjectBaseURL(project.type)}/access-management` as const,
params: { params: {
projectId: project.id projectId: project.id
}, },

View File

@@ -4,6 +4,7 @@ import {
faArrowDownAZ, faArrowDownAZ,
faBorderAll, faBorderAll,
faCheck, faCheck,
faCheckCircle,
faFolderOpen, faFolderOpen,
faList, faList,
faMagnifyingGlass, faMagnifyingGlass,
@@ -17,6 +18,11 @@ import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions"; import { OrgPermissionCan } from "@app/components/permissions";
import { import {
Button, Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
FormControl, FormControl,
IconButton, IconButton,
Input, Input,
@@ -27,7 +33,7 @@ import {
Tooltip Tooltip
} from "@app/components/v2"; } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
import { getProjectHomePage } from "@app/helpers/project"; import { getProjectHomePage, getProjectTitle } from "@app/helpers/project";
import { import {
getUserTablePreference, getUserTablePreference,
PreferenceKey, PreferenceKey,
@@ -35,7 +41,7 @@ import {
} from "@app/helpers/userTablePreferences"; } from "@app/helpers/userTablePreferences";
import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks";
import { useRequestProjectAccess, useSearchProjects } from "@app/hooks/api"; import { useRequestProjectAccess, useSearchProjects } from "@app/hooks/api";
import { Workspace } from "@app/hooks/api/workspace/types"; import { ProjectType, Workspace } from "@app/hooks/api/workspace/types";
type Props = { type Props = {
onAddNewProject: () => void; onAddNewProject: () => void;
@@ -98,6 +104,7 @@ export const AllProjectView = ({
const navigate = useNavigate(); const navigate = useNavigate();
const [searchFilter, setSearchFilter] = useState(""); const [searchFilter, setSearchFilter] = useState("");
const [debouncedSearch] = useDebounce(searchFilter); const [debouncedSearch] = useDebounce(searchFilter);
const [projectTypeFilter, setProjectTypeFilter] = useState<ProjectType>();
const { const {
setPage, setPage,
perPage, perPage,
@@ -124,7 +131,8 @@ export const AllProjectView = ({
limit, limit,
offset, offset,
name: debouncedSearch || undefined, name: debouncedSearch || undefined,
orderDirection orderDirection,
type: projectTypeFilter
}); });
useResetPageHelper({ useResetPageHelper({
@@ -134,6 +142,9 @@ export const AllProjectView = ({
}); });
const requestedWorkspaceDetails = (popUp.requestAccessConfirmation.data || {}) as Workspace; const requestedWorkspaceDetails = (popUp.requestAccessConfirmation.data || {}) as Workspace;
const handleToggleFilterByProjectType = (el: ProjectType) =>
setProjectTypeFilter((state) => (state === el ? undefined : el));
return ( return (
<div> <div>
<div className="flex w-full flex-row"> <div className="flex w-full flex-row">
@@ -160,6 +171,49 @@ export const AllProjectView = ({
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</div> </div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div
className={twMerge(
"ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1",
projectTypeFilter && "border-primary-400 text-primary-400"
)}
>
<Tooltip content="Choose visible project type" className="mb-2">
<IconButton
ariaLabel="project-types"
className={twMerge(
"min-w-[2.4rem] border-none hover:bg-mineshaft-600",
projectTypeFilter && "text-primary-400"
)}
variant="plain"
size="xs"
colorSchema="secondary"
>
<FontAwesomeIcon icon={faList} />
</IconButton>
</Tooltip>
</div>
</DropdownMenuTrigger>
<DropdownMenuContent className="thin-scrollbar overflow-y-auto" align="end">
<DropdownMenuLabel>Filter By Project Type</DropdownMenuLabel>
{Object.values(ProjectType).map((el) => (
<DropdownMenuItem
key={`filter-item-${el}`}
onClick={(e) => {
e.preventDefault();
handleToggleFilterByProjectType(el);
}}
icon={projectTypeFilter === el && <FontAwesomeIcon icon={faCheckCircle} />}
iconPos="right"
>
<div className="flex items-center gap-2">
<span>{getProjectTitle(el)}</span>
</div>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
<div className="ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1"> <div className="ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1">
<Tooltip content="Disabled across All Project view."> <Tooltip content="Disabled across All Project view.">
<IconButton <IconButton
@@ -270,7 +324,8 @@ export const AllProjectView = ({
</div> </div>
</div> </div>
<div className="mt-1 max-w-lg overflow-hidden text-ellipsis whitespace-nowrap text-xs text-mineshaft-300"> <div className="mt-1 max-w-lg overflow-hidden text-ellipsis whitespace-nowrap text-xs text-mineshaft-300">
{workspace.description} {getProjectTitle(workspace.type)}{" "}
{workspace.description ? `- ${workspace.description}` : ""}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,9 @@ import { ReactNode, useMemo, useState } from "react";
import { faFolderOpen, faStar } from "@fortawesome/free-regular-svg-icons"; import { faFolderOpen, faStar } from "@fortawesome/free-regular-svg-icons";
import { import {
faArrowDownAZ, faArrowDownAZ,
faArrowRight,
faArrowUpZA, faArrowUpZA,
faBorderAll, faBorderAll,
faCheckCircle,
faList, faList,
faMagnifyingGlass, faMagnifyingGlass,
faPlus, faPlus,
@@ -13,12 +13,26 @@ import {
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate } from "@tanstack/react-router";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions"; import { OrgPermissionCan } from "@app/components/permissions";
import { Button, IconButton, Input, Pagination, Skeleton, Tooltip } from "@app/components/v2"; import {
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
IconButton,
Input,
Lottie,
Pagination,
Skeleton,
Tooltip
} from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { getProjectHomePage } from "@app/helpers/project"; import { getProjectHomePage, getProjectLottieIcon, getProjectTitle } from "@app/helpers/project";
import { import {
getUserTablePreference, getUserTablePreference,
PreferenceKey, PreferenceKey,
@@ -29,7 +43,7 @@ import { useGetUserWorkspaces } from "@app/hooks/api";
import { OrderByDirection } from "@app/hooks/api/generic/types"; import { OrderByDirection } from "@app/hooks/api/generic/types";
import { useUpdateUserProjectFavorites } from "@app/hooks/api/users/mutation"; import { useUpdateUserProjectFavorites } from "@app/hooks/api/users/mutation";
import { useGetUserProjectFavorites } from "@app/hooks/api/users/queries"; import { useGetUserProjectFavorites } from "@app/hooks/api/users/queries";
import { Workspace } from "@app/hooks/api/workspace/types"; import { ProjectType, Workspace } from "@app/hooks/api/workspace/types";
type Props = { type Props = {
onAddNewProject: () => void; onAddNewProject: () => void;
@@ -53,6 +67,9 @@ export const MyProjectView = ({
}: Props) => { }: Props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const [projectTypeFilter, setProjectTypeFilter] = useState<Partial<Record<ProjectType, boolean>>>(
{}
);
const { data: workspaces = [], isPending: isWorkspaceLoading } = useGetUserWorkspaces(); const { data: workspaces = [], isPending: isWorkspaceLoading } = useGetUserWorkspaces();
const { const {
@@ -67,6 +84,7 @@ export const MyProjectView = ({
} = usePagination(ProjectOrderBy.Name, { } = usePagination(ProjectOrderBy.Name, {
initPerPage: getUserTablePreference("myProjectsTable", PreferenceKey.PerPage, 24) initPerPage: getUserTablePreference("myProjectsTable", PreferenceKey.PerPage, 24)
}); });
const isTableFilteredByType = Boolean(Object.values(projectTypeFilter).some((el) => el));
const handlePerPageChange = (newPerPage: number) => { const handlePerPageChange = (newPerPage: number) => {
setPerPage(newPerPage); setPerPage(newPerPage);
@@ -88,13 +106,18 @@ export const MyProjectView = ({
const filteredWorkspaces = useMemo( const filteredWorkspaces = useMemo(
() => () =>
workspaces workspaces
.filter((ws) => ws?.name?.toLowerCase().includes(searchFilter.toLowerCase())) .filter((ws) => {
if (isTableFilteredByType && !projectTypeFilter?.[ws.type]) {
return false;
}
return ws?.name?.toLowerCase().includes(searchFilter.toLowerCase());
})
.sort((a, b) => .sort((a, b) =>
orderDirection === OrderByDirection.ASC orderDirection === OrderByDirection.ASC
? a.name.toLowerCase().localeCompare(b.name.toLowerCase()) ? a.name.toLowerCase().localeCompare(b.name.toLowerCase())
: b.name.toLowerCase().localeCompare(a.name.toLowerCase()) : b.name.toLowerCase().localeCompare(a.name.toLowerCase())
), ),
[searchFilter, orderDirection, workspaces] [searchFilter, orderDirection, workspaces, projectTypeFilter]
); );
useResetPageHelper({ useResetPageHelper({
@@ -117,6 +140,15 @@ export const MyProjectView = ({
}; };
}, [filteredWorkspaces, projectFavorites, offset, limit, page]); }, [filteredWorkspaces, projectFavorites, offset, limit, page]);
const handleToggleFilterByProjectType = (type: ProjectType) => {
setProjectTypeFilter((state) => {
return {
...(state || {}),
[type]: !state?.[type]
};
});
};
const addProjectToFavorites = async (projectId: string) => { const addProjectToFavorites = async (projectId: string) => {
try { try {
if (currentOrg?.id) { if (currentOrg?.id) {
@@ -160,53 +192,46 @@ export const MyProjectView = ({
}); });
}} }}
key={workspace.id} key={workspace.id}
className="flex h-40 min-w-72 cursor-pointer flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4" className="relative flex h-36 min-w-72 cursor-pointer flex-col rounded-md border border-mineshaft-500 bg-mineshaft-800 p-4 transition-all hover:border-mineshaft-400"
> >
<div className="flex flex-row justify-between"> <div className="flex items-center gap-4">
<div className="mt-0 truncate text-lg text-mineshaft-100">{workspace.name}</div> <div className="h-12 w-12 rounded bg-mineshaft-600 p-2">
{isFavorite ? ( <Lottie icon={getProjectLottieIcon(workspace.type)} className="h-full w-full" />
<FontAwesomeIcon </div>
icon={faSolidStar} <div className="flex-1">
className="text-sm text-yellow-600 hover:text-mineshaft-400" <div className="flex">
onClick={(e) => { <div className="flex-1 truncate text-lg font-semibold text-mineshaft-100">
e.stopPropagation(); {workspace.name}
removeProjectFromFavorites(workspace.id); </div>
}} <div className="">
/> {isFavorite ? (
) : ( <FontAwesomeIcon
<FontAwesomeIcon icon={faSolidStar}
icon={faStar} className="text-sm text-yellow-600 hover:text-mineshaft-400"
className="text-sm text-mineshaft-400 hover:text-mineshaft-300" onClick={(e) => {
onClick={(e) => { e.stopPropagation();
e.stopPropagation(); removeProjectFromFavorites(workspace.id);
addProjectToFavorites(workspace.id); }}
}} />
/> ) : (
)} <FontAwesomeIcon
</div> icon={faStar}
className="text-sm text-mineshaft-400 hover:text-mineshaft-300"
<div onClick={(e) => {
className="mb-2.5 mt-1 grow text-sm text-mineshaft-300" e.stopPropagation();
style={{ addProjectToFavorites(workspace.id);
overflow: "hidden", }}
display: "-webkit-box", />
WebkitBoxOrient: "vertical", )}
WebkitLineClamp: 2 </div>
}}
>
{workspace.description}
</div>
<div className="flex w-full flex-row items-end justify-between place-self-end">
<button type="button">
<div className="group ml-auto w-max cursor-pointer rounded-full border border-mineshaft-600 bg-mineshaft-900 px-4 py-2 text-sm text-mineshaft-300 transition-all hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200">
Explore{" "}
<FontAwesomeIcon
icon={faArrowRight}
className="pl-1.5 pr-0.5 duration-200 hover:pl-2 hover:pr-0"
/>
</div> </div>
</button> <div className="truncate text-sm text-mineshaft-300">
{getProjectTitle(workspace.type)}
</div>
</div>
</div>
<div className="mt-4 text-sm text-mineshaft-400">
{workspace.description || "No description"}
</div> </div>
</div> </div>
); );
@@ -222,12 +247,16 @@ export const MyProjectView = ({
}); });
}} }}
key={workspace.id} key={workspace.id}
className={`group grid h-14 min-w-72 cursor-pointer grid-cols-6 border-l border-r border-t border-mineshaft-600 bg-mineshaft-800 px-6 hover:bg-mineshaft-700 ${ className={`group grid h-16 min-w-72 cursor-pointer grid-cols-6 border-l border-r border-t border-mineshaft-600 bg-mineshaft-800 px-6 hover:bg-mineshaft-700 ${
index === 0 && "rounded-t-md" index === 0 && "rounded-t-md"
}`} }`}
> >
<div className="flex items-center sm:col-span-3 lg:col-span-4"> <div className="flex flex-col justify-center sm:col-span-3 lg:col-span-4">
<div className="truncate text-sm text-mineshaft-100">{workspace.name}</div> <div className="truncate text-sm text-mineshaft-100">{workspace.name}</div>
<div className="mt-1 text-xs text-mineshaft-300">
{getProjectTitle(workspace.type)}{" "}
{workspace.description ? `- ${workspace.description}` : ""}
</div>
</div> </div>
<div className="flex items-center justify-end sm:col-span-3 lg:col-span-2"> <div className="flex items-center justify-end sm:col-span-3 lg:col-span-2">
{isFavorite ? ( {isFavorite ? (
@@ -258,7 +287,7 @@ export const MyProjectView = ({
switch (projectsViewMode) { switch (projectsViewMode) {
case ProjectsViewMode.GRID: case ProjectsViewMode.GRID:
projectsComponents = ( projectsComponents = (
<div className="mt-4 grid w-full grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4"> <div className="mt-4 grid w-full grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3">
{isProjectViewLoading && {isProjectViewLoading &&
Array.apply(0, Array(3)).map((_x, i) => ( Array.apply(0, Array(3)).map((_x, i) => (
<div <div
@@ -351,6 +380,49 @@ export const MyProjectView = ({
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</div> </div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div
className={twMerge(
"ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1",
isTableFilteredByType && "border-primary-400 text-primary-400"
)}
>
<Tooltip content="Choose visible project type" className="mb-2">
<IconButton
ariaLabel="project-types"
className={twMerge(
"min-w-[2.4rem] border-none hover:bg-mineshaft-600",
isTableFilteredByType && "text-primary-400"
)}
variant="plain"
size="xs"
colorSchema="secondary"
>
<FontAwesomeIcon icon={faList} />
</IconButton>
</Tooltip>
</div>
</DropdownMenuTrigger>
<DropdownMenuContent className="thin-scrollbar overflow-y-auto" align="end">
<DropdownMenuLabel>Filter By Project Type</DropdownMenuLabel>
{Object.values(ProjectType).map((el) => (
<DropdownMenuItem
key={`filter-item-${el}`}
onClick={(e) => {
e.preventDefault();
handleToggleFilterByProjectType(el);
}}
icon={projectTypeFilter?.[el] && <FontAwesomeIcon icon={faCheckCircle} />}
iconPos="right"
>
<div className="flex items-center gap-2">
<span>{getProjectTitle(el)}</span>
</div>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
<div className="ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1"> <div className="ml-2 flex rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1">
<IconButton <IconButton
variant="outline_bg" variant="outline_bg"

View File

@@ -5,13 +5,12 @@ import { useNavigate } from "@tanstack/react-router";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { getProjectBaseURL } from "@app/helpers/project";
import { formatProjectRoleName } from "@app/helpers/roles"; import { formatProjectRoleName } from "@app/helpers/roles";
import { useGetUserWorkspaces } from "@app/hooks/api"; import { useGetUserWorkspaces } from "@app/hooks/api";
import { TWorkspaceUser } from "@app/hooks/api/types"; import { TWorkspaceUser } from "@app/hooks/api/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
import { OrgAccessControlTabSections } from "@app/types/org"; import { OrgAccessControlTabSections } from "@app/types/org";
import { getProjectBaseURL } from "@app/helpers/project";
import { useWorkspace } from "@app/context";
type Props = { type Props = {
membership: TWorkspaceUser; membership: TWorkspaceUser;
@@ -27,7 +26,6 @@ export const UserProjectRow = ({
}: Props) => { }: Props) => {
const { data: workspaces = [] } = useGetUserWorkspaces(); const { data: workspaces = [] } = useGetUserWorkspaces();
const navigate = useNavigate(); const navigate = useNavigate();
const { currentWorkspace } = useWorkspace();
const isAccessible = useMemo(() => { const isAccessible = useMemo(() => {
const workspaceIds = new Map(); const workspaceIds = new Map();
@@ -46,7 +44,7 @@ export const UserProjectRow = ({
onClick={() => { onClick={() => {
if (isAccessible) { if (isAccessible) {
navigate({ navigate({
to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, to: `${getProjectBaseURL(project.type)}/access-management` as const,
params: { params: {
projectId: project.id projectId: project.id
}, },

View File

@@ -33,6 +33,7 @@ import {
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { import {
getUserTablePreference, getUserTablePreference,
PreferenceKey, PreferenceKey,
@@ -44,7 +45,6 @@ import { OrderByDirection } from "@app/hooks/api/generic/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
import { GroupRoles } from "./GroupRoles"; import { GroupRoles } from "./GroupRoles";
import { getProjectBaseURL } from "@app/helpers/project";
type Props = { type Props = {
handlePopUpOpen: ( handlePopUpOpen: (

View File

@@ -46,6 +46,7 @@ import {
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { formatProjectRoleName } from "@app/helpers/roles"; import { formatProjectRoleName } from "@app/helpers/roles";
import { import {
getUserTablePreference, getUserTablePreference,
@@ -60,7 +61,6 @@ import { ProjectIdentityOrderBy } from "@app/hooks/api/workspace/types";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
import { IdentityModal } from "./components/IdentityModal"; import { IdentityModal } from "./components/IdentityModal";
import { getProjectBaseURL } from "@app/helpers/project";
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2; const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;

View File

@@ -2,10 +2,10 @@ import { Link } from "@tanstack/react-router";
import { Alert, AlertDescription } from "@app/components/v2"; import { Alert, AlertDescription } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { TWorkspaceUser } from "@app/hooks/api/types"; import { TWorkspaceUser } from "@app/hooks/api/types";
import { MemberRbacSection } from "./MemberRbacSection"; import { MemberRbacSection } from "./MemberRbacSection";
import { getProjectBaseURL } from "@app/helpers/project";
type Props = { type Props = {
projectMember: TWorkspaceUser; projectMember: TWorkspaceUser;

View File

@@ -50,6 +50,7 @@ import {
useUser, useUser,
useWorkspace useWorkspace
} from "@app/context"; } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { formatProjectRoleName } from "@app/helpers/roles"; import { formatProjectRoleName } from "@app/helpers/roles";
import { import {
getUserTablePreference, getUserTablePreference,
@@ -60,7 +61,6 @@ import { usePagination, useResetPageHelper } from "@app/hooks";
import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api"; import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api";
import { OrderByDirection } from "@app/hooks/api/generic/types"; import { OrderByDirection } from "@app/hooks/api/generic/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
import { getProjectBaseURL } from "@app/helpers/project";
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2; const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;

View File

@@ -40,6 +40,7 @@ import {
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { isCustomProjectRole } from "@app/helpers/roles"; import { isCustomProjectRole } from "@app/helpers/roles";
import { import {
getUserTablePreference, getUserTablePreference,
@@ -52,7 +53,6 @@ import { OrderByDirection } from "@app/hooks/api/generic/types";
import { ProjectMembershipRole, TProjectRole } from "@app/hooks/api/roles/types"; import { ProjectMembershipRole, TProjectRole } from "@app/hooks/api/roles/types";
import { DuplicateProjectRoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal"; import { DuplicateProjectRoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal";
import { RoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/RoleModal"; import { RoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/RoleModal";
import { getProjectBaseURL } from "@app/helpers/project";
enum RolesOrderBy { enum RolesOrderBy {
Name = "name", Name = "name",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,11 +15,11 @@ import {
} from "@app/components/v2"; } from "@app/components/v2";
import { CopyButton } from "@app/components/v2/CopyButton"; import { CopyButton } from "@app/components/v2/CopyButton";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { useDeleteGroupFromWorkspace } from "@app/hooks/api"; import { useDeleteGroupFromWorkspace } from "@app/hooks/api";
import { TGroupMembership } from "@app/hooks/api/groups/types"; import { TGroupMembership } from "@app/hooks/api/groups/types";
import { GroupRoles } from "@app/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles"; import { GroupRoles } from "@app/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles";
import { getProjectBaseURL } from "@app/helpers/project";
type Props = { type Props = {
groupMembership: TGroupMembership; groupMembership: TGroupMembership;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,6 +17,7 @@ import {
PageHeader PageHeader
} from "@app/components/v2"; } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { useDeleteProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api"; import { useDeleteProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api";
import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
@@ -25,7 +26,6 @@ import { RolePermissionsSection } from "@app/pages/project/RoleDetailsBySlugPage
import { ProjectAccessControlTabs } from "@app/types/project"; import { ProjectAccessControlTabs } from "@app/types/project";
import { RoleModal } from "./components/RoleModal"; import { RoleModal } from "./components/RoleModal";
import { getProjectBaseURL } from "@app/helpers/project";
const Page = () => { const Page = () => {
const navigate = useNavigate(); const navigate = useNavigate();

View File

@@ -7,10 +7,10 @@ import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input, Modal, ModalContent, Spinner } from "@app/components/v2"; import { Button, FormControl, Input, Modal, ModalContent, Spinner } from "@app/components/v2";
import { ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionSub, useWorkspace } from "@app/context";
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
import { getProjectBaseURL } from "@app/helpers/project";
import { useCreateProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api"; import { useCreateProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api";
import { TProjectRole } from "@app/hooks/api/roles/types"; import { TProjectRole } from "@app/hooks/api/roles/types";
import { slugSchema } from "@app/lib/schemas"; import { slugSchema } from "@app/lib/schemas";
import { getProjectBaseURL } from "@app/helpers/project";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;

View File

@@ -7,6 +7,7 @@ import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
import { getProjectBaseURL } from "@app/helpers/project";
import { import {
useCreateProjectRole, useCreateProjectRole,
useGetProjectRoleBySlug, useGetProjectRoleBySlug,
@@ -14,7 +15,6 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
import { slugSchema } from "@app/lib/schemas"; import { slugSchema } from "@app/lib/schemas";
import { getProjectBaseURL } from "@app/helpers/project";
const schema = z const schema = z
.object({ .object({

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,4 +16,4 @@ export const Route = createFileRoute(
] ]
}; };
} }
}); });

View File

@@ -16,4 +16,4 @@ export const Route = createFileRoute(
] ]
}; };
} }
}); });

View File

@@ -16,4 +16,4 @@ export const Route = createFileRoute(
] ]
}; };
} }
}); });

View File

@@ -16,4 +16,4 @@ export const Route = createFileRoute(
] ]
}; };
} }
}); });

View File

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

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { IPAllowListPage } from './IPAllowlistPage' import { IPAllowListPage } from "./IPAllowlistPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/allowlist', "/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/allowlist"
)({ )({
component: () => IPAllowListPage, component: () => IPAllowListPage
}) });

View File

@@ -1,15 +1,15 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { zodValidator } from '@tanstack/zod-adapter' import { zodValidator } from "@tanstack/zod-adapter";
import { z } from 'zod' import { z } from "zod";
import { SecretApprovalsPage } from './SecretApprovalsPage' import { SecretApprovalsPage } from "./SecretApprovalsPage";
const SecretApprovalPageQueryParams = z.object({ const SecretApprovalPageQueryParams = z.object({
requestId: z.string().catch(''), requestId: z.string().catch("")
}) });
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/approval', "/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/approval"
)({ )({
component: SecretApprovalsPage, component: SecretApprovalsPage,
validateSearch: zodValidator(SecretApprovalPageQueryParams), validateSearch: zodValidator(SecretApprovalPageQueryParams),
@@ -18,9 +18,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Approvals', label: "Approvals"
}, }
], ]
} };
}, }
}) });

View File

@@ -52,6 +52,7 @@ import {
useWorkspace useWorkspace
} from "@app/context"; } from "@app/context";
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
import { getProjectBaseURL } from "@app/helpers/project";
import { usePopUp, useToggle } from "@app/hooks"; import { usePopUp, useToggle } from "@app/hooks";
import { useGetSecretVersion } from "@app/hooks/api"; import { useGetSecretVersion } from "@app/hooks/api";
import { ActorType } from "@app/hooks/api/auditLogs/enums"; import { ActorType } from "@app/hooks/api/auditLogs/enums";
@@ -64,7 +65,6 @@ import { camelCaseToSpaces } from "@app/lib/fn/string";
import { CreateReminderForm } from "./CreateReminderForm"; import { CreateReminderForm } from "./CreateReminderForm";
import { HIDDEN_SECRET_VALUE } from "./SecretItem"; import { HIDDEN_SECRET_VALUE } from "./SecretItem";
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils"; import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
import { getProjectBaseURL } from "@app/helpers/project";
type Props = { type Props = {
isOpen?: boolean; isOpen?: boolean;

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SecretRotationPage } from './SecretRotationPage' import { SecretRotationPage } from "./SecretRotationPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/secret-rotation', "/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/secret-rotation"
)({ )({
component: SecretRotationPage, component: SecretRotationPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Secret Rotation', label: "Secret Rotation"
}, }
], ]
} };
}, }
}) });

View File

@@ -4,9 +4,10 @@ import { useTranslation } from "react-i18next";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
import { ProjectVersion } from "@app/hooks/api/workspace/types"; import { ProjectVersion } from "@app/hooks/api/workspace/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
import { EncryptionTab } from "./components/EncryptionTab"; import { EncryptionTab } from "./components/EncryptionTab";
import { ProjectGeneralTab } from "./components/ProjectGeneralTab"; import { SecretSettingsTab } from "./components/ProjectGeneralTab";
import { WebhooksTab } from "./components/WebhooksTab"; import { WebhooksTab } from "./components/WebhooksTab";
import { WorkflowIntegrationTab } from "./components/WorkflowIntegrationSection"; import { WorkflowIntegrationTab } from "./components/WorkflowIntegrationSection";
@@ -15,6 +16,7 @@ export const SettingsPage = () => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const tabs = [ const tabs = [
{ name: "General", key: "tab-project-general", Component: ProjectGeneralTab }, { name: "General", key: "tab-project-general", Component: ProjectGeneralTab },
{ name: "Secrets Settings", key: "tab-secret-general", Component: SecretSettingsTab },
{ {
name: "Encryption", name: "Encryption",
key: "tab-project-encryption", key: "tab-project-encryption",

View File

@@ -6,7 +6,7 @@ import { SecretSharingSection } from "../SecretSharingSection";
import { SecretSnapshotsLegacySection } from "../SecretSnapshotsLegacySection"; import { SecretSnapshotsLegacySection } from "../SecretSnapshotsLegacySection";
import { SecretTagsSection } from "../SecretTagsSection"; import { SecretTagsSection } from "../SecretTagsSection";
export const ProjectGeneralTab = () => { export const SecretSettingsTab = () => {
return ( return (
<div> <div>
<EnvironmentSection /> <EnvironmentSection />

View File

@@ -1 +1 @@
export { ProjectGeneralTab } from "./ProjectGeneralTab"; export { SecretSettingsTab } from "./ProjectGeneralTab";

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SettingsPage } from './SettingsPage' import { SettingsPage } from "./SettingsPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/settings', "/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/settings"
)({ )({
component: SettingsPage, component: SettingsPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Settings', label: "Settings"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SecretScanningDataSourcesPage } from './SecretScanningDataSourcesPage' import { SecretScanningDataSourcesPage } from "./SecretScanningDataSourcesPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/data-sources/', "/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/data-sources/"
)({ )({
component: SecretScanningDataSourcesPage, component: SecretScanningDataSourcesPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Data Sources', label: "Data Sources"
}, }
], ]
} };
}, }
}) });

View File

@@ -1,32 +1,29 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { zodValidator } from '@tanstack/zod-adapter' import { zodValidator } from "@tanstack/zod-adapter";
import { z } from 'zod' import { z } from "zod";
import { SecretScanningFindingStatus } from '@app/hooks/api/secretScanningV2' import { SecretScanningFindingStatus } from "@app/hooks/api/secretScanningV2";
import { SecretScanningFindingsPage } from './SecretScanningFindingsPage' import { SecretScanningFindingsPage } from "./SecretScanningFindingsPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/findings', "/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/findings"
)({ )({
validateSearch: zodValidator( validateSearch: zodValidator(
z.object({ z.object({
search: z.string().optional(), search: z.string().optional(),
status: z status: z.nativeEnum(SecretScanningFindingStatus).optional().catch(undefined)
.nativeEnum(SecretScanningFindingStatus) })
.optional()
.catch(undefined),
}),
), ),
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
return { return {
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Findings', label: "Findings"
}, }
], ]
} };
}, },
component: SecretScanningFindingsPage, component: SecretScanningFindingsPage
}) });

View File

@@ -10,6 +10,7 @@ import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectPermissionSub, useSubscription } from "@app/context"; import { ProjectPermissionSub, useSubscription } from "@app/context";
import { ProjectPermissionSecretScanningConfigActions } from "@app/context/ProjectPermissionContext/types"; import { ProjectPermissionSecretScanningConfigActions } from "@app/context/ProjectPermissionContext/types";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
import { ProjectScanningConfigTab } from "./components/ProjectScanningConfigTab"; import { ProjectScanningConfigTab } from "./components/ProjectScanningConfigTab";
@@ -62,8 +63,12 @@ export const SettingsPage = () => {
<Tabs defaultValue="tab-project-general"> <Tabs defaultValue="tab-project-general">
<TabList> <TabList>
<Tab value="tab-project-general">General</Tab> <Tab value="tab-project-general">General</Tab>
<Tab value="tab-project-secret-scanning">Scanning Settings</Tab>
</TabList> </TabList>
<TabPanel value="tab-project-general"> <TabPanel value="tab-project-general">
<ProjectGeneralTab />
</TabPanel>
<TabPanel value="tab-project-secret-scanning">
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionSecretScanningConfigActions.Read} I={ProjectPermissionSecretScanningConfigActions.Read}
a={ProjectPermissionSub.SecretScanningConfigs} a={ProjectPermissionSub.SecretScanningConfigs}

View File

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

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
import { ProjectSshTab } from "./components/ProjectSshTab"; import { ProjectSshTab } from "./components/ProjectSshTab";
@@ -20,8 +21,12 @@ export const SettingsPage = () => {
<Tabs defaultValue="tab-project-general"> <Tabs defaultValue="tab-project-general">
<TabList> <TabList>
<Tab value="tab-project-general">General</Tab> <Tab value="tab-project-general">General</Tab>
<Tab value="tab-ssh-settings">SSH Settings</Tab>
</TabList> </TabList>
<TabPanel value="tab-project-general"> <TabPanel value="tab-project-general">
<ProjectGeneralTab />
</TabPanel>
<TabPanel value="tab-ssh-settings">
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Edit}
a={ProjectPermissionSub.Project} a={ProjectPermissionSub.Project}

View File

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

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SshCertsPage } from './SshCertsPage' import { SshCertsPage } from "./SshCertsPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/certificates', "/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/certificates"
)({ )({
component: SshCertsPage, component: SshCertsPage
}) });

View File

@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from "@tanstack/react-router";
import { SshHostsPage } from './SshHostsPage' import { SshHostsPage } from "./SshHostsPage";
export const Route = createFileRoute( export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/overview', "/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/overview"
)({ )({
component: SshHostsPage, component: SshHostsPage,
beforeLoad: ({ context }) => { beforeLoad: ({ context }) => {
@@ -11,9 +11,9 @@ export const Route = createFileRoute(
breadcrumbs: [ breadcrumbs: [
...context.breadcrumbs, ...context.breadcrumbs,
{ {
label: 'Hosts', label: "Hosts"
}, }
], ]
} };
}, }
}) });