Merge pull request #3744 from Infisical/project-group-users-page

feature(group-projects): Add project group details page
This commit is contained in:
Scott Wilson
2025-06-06 14:30:50 -07:00
committed by GitHub
27 changed files with 1306 additions and 151 deletions
+69 -1
View File
@@ -21,7 +21,27 @@ export const groupKeys = {
limit: number;
search: string;
filter?: EFilterReturnedUsers;
}) => [...groupKeys.forGroupUserMemberships(slug), { offset, limit, search, filter }] as const
}) => [...groupKeys.forGroupUserMemberships(slug), { offset, limit, search, filter }] as const,
specificProjectGroupUserMemberships: ({
projectId,
slug,
offset,
limit,
search,
filter
}: {
slug: string;
projectId: string;
offset: number;
limit: number;
search: string;
filter?: EFilterReturnedUsers;
}) =>
[
...groupKeys.forGroupUserMemberships(slug),
projectId,
{ offset, limit, search, filter }
] as const
};
export const useGetGroupById = (groupId: string) => {
@@ -80,3 +100,51 @@ export const useListGroupUsers = ({
}
});
};
export const useListProjectGroupUsers = ({
id,
projectId,
groupSlug,
offset = 0,
limit = 10,
search,
filter
}: {
id: string;
groupSlug: string;
projectId: string;
offset: number;
limit: number;
search: string;
filter?: EFilterReturnedUsers;
}) => {
return useQuery({
queryKey: groupKeys.specificProjectGroupUserMemberships({
slug: groupSlug,
projectId,
offset,
limit,
search,
filter
}),
enabled: Boolean(groupSlug),
placeholderData: (previousData) => previousData,
queryFn: async () => {
const params = new URLSearchParams({
offset: String(offset),
limit: String(limit),
search,
...(filter && { filter })
});
const { data } = await apiRequest.get<{ users: TGroupUser[]; totalCount: number }>(
`/api/v2/workspace/${projectId}/groups/${id}/users`,
{
params
}
);
return data;
}
});
};
@@ -50,10 +50,13 @@ export const useUpdateGroupWorkspaceRole = () => {
return groupMembership;
},
onSuccess: (_, { projectId }) => {
onSuccess: (_, { projectId, groupId }) => {
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId)
});
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceGroupMembershipDetails(projectId, groupId)
});
}
});
};
@@ -691,6 +691,21 @@ export const useGetWorkspaceIdentityMembershipDetails = (projectId: string, iden
});
};
export const useGetWorkspaceGroupMembershipDetails = (projectId: string, groupId: string) => {
return useQuery({
enabled: Boolean(projectId && groupId),
queryKey: workspaceKeys.getWorkspaceGroupMembershipDetails(projectId, groupId),
queryFn: async () => {
const {
data: { groupMembership }
} = await apiRequest.get<{ groupMembership: TGroupMembership }>(
`/api/v2/workspace/${projectId}/groups/${groupId}`
);
return groupMembership;
}
});
};
export const useListWorkspaceGroups = (projectId: string) => {
return useQuery({
queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId),
@@ -36,6 +36,8 @@ export const workspaceKeys = {
searchWorkspace: (dto: TSearchProjectsDTO) => ["search-projects", dto] as const,
getWorkspaceGroupMemberships: (workspaceId: string) =>
[{ workspaceId }, "workspace-groups"] as const,
getWorkspaceGroupMembershipDetails: (workspaceId: string, groupId: string) =>
[{ workspaceId, groupId }, "workspace-group-membership-details"] as const,
getWorkspaceCas: ({ projectSlug }: { projectSlug: string }) =>
[{ projectSlug }, "workspace-cas"] as const,
specificWorkspaceCas: ({ projectSlug, status }: { projectSlug: string; status?: CaStatus }) =>
@@ -152,7 +152,7 @@ export const GroupMembersTable = ({ groupId, groupSlug, handlePopUpOpen }: Props
</Th>
<Th>Email</Th>
<Th>Added On</Th>
<Th />
<Th className="w-5" />
</Tr>
</THead>
<TBody>
@@ -1,8 +1,17 @@
import { faUserMinus } from "@fortawesome/free-solid-svg-icons";
import { faEllipsisV, faUserMinus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { OrgPermissionCan } from "@app/components/permissions";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
IconButton,
Td,
Tooltip,
Tr
} from "@app/components/v2";
import { OrgPermissionGroupActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { useOidcManageGroupMembershipsEnabled } from "@app/hooks/api";
import { TGroupUser } from "@app/hooks/api/groups/types";
@@ -38,30 +47,47 @@ export const GroupMembershipRow = ({
<p>{new Date(joinedGroupAt).toLocaleDateString()}</p>
</Tooltip>
</Td>
<Td className="justify-end">
<OrgPermissionCan I={OrgPermissionGroupActions.Edit} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => {
return (
<Tooltip
content={
isOidcManageGroupMembershipsEnabled
? "OIDC Group Membership Mapping Enabled. Remove user from this group in your OIDC provider."
: "Remove user from group"
}
<Td>
<Tooltip className="max-w-sm text-center" content="Options">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton
ariaLabel="Options"
colorSchema="secondary"
className="w-6"
variant="plain"
>
<IconButton
isDisabled={!isAllowed || isOidcManageGroupMembershipsEnabled}
ariaLabel="Remove user from group"
onClick={() => handlePopUpOpen("removeMemberFromGroup", { username })}
variant="plain"
colorSchema="danger"
>
<FontAwesomeIcon icon={faUserMinus} />
</IconButton>
</Tooltip>
);
}}
</OrgPermissionCan>
<FontAwesomeIcon icon={faEllipsisV} />
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={2} align="end">
<OrgPermissionCan I={OrgPermissionGroupActions.Edit} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => {
return (
<Tooltip
content={
isOidcManageGroupMembershipsEnabled
? "OIDC Group Membership Mapping Enabled. Remove user from this group in your OIDC provider."
: undefined
}
position="left"
>
<div>
<DropdownMenuItem
icon={<FontAwesomeIcon icon={faUserMinus} />}
onClick={() => handlePopUpOpen("removeMemberFromGroup", { username })}
isDisabled={!isAllowed || isOidcManageGroupMembershipsEnabled}
>
Remove User From Group
</DropdownMenuItem>
</div>
</Tooltip>
);
}}
</OrgPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</Tooltip>
</Td>
</Tr>
);
@@ -3,6 +3,7 @@ import { Controller, useForm } from "react-hook-form";
import { faCheck, faClock, faEdit, faSearch } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { PopperContentProps } from "@radix-ui/react-popper";
import { twMerge } from "tailwind-merge";
import { z } from "zod";
@@ -28,6 +29,7 @@ import { formatProjectRoleName } from "@app/helpers/roles";
import { usePopUp } from "@app/hooks";
import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api";
import { TGroupMembership } from "@app/hooks/api/groups/types";
import { TProjectRole } from "@app/hooks/api/roles/types";
import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types";
import { groupBy } from "@app/lib/fn/array";
@@ -196,33 +198,38 @@ type TForm = z.infer<typeof formSchema>;
export type TMemberRolesProp = {
disableEdit?: boolean;
groupId: string;
className?: string;
roles: TGroupMembership["roles"];
popperContentProps?: PopperContentProps;
};
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMemberRolesProp) => {
type FormProps = {
projectRoles: Omit<TProjectRole, "permissions">[] | undefined;
roles: TGroupMembership["roles"];
groupId: string;
onClose: VoidFunction;
};
const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) => {
const { currentWorkspace } = useWorkspace();
const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const);
const [searchRoles, setSearchRoles] = useState("");
const userRolesGroupBySlug = groupBy(roles, ({ customRoleSlug, role }) => customRoleSlug || role);
const updateGroupWorkspaceRole = useUpdateGroupWorkspaceRole();
const {
handleSubmit,
control,
reset,
setValue,
formState: { isSubmitting, isDirty }
} = useForm<TForm>({
resolver: zodResolver(formSchema)
});
const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(
currentWorkspace?.id ?? ""
);
const userRolesGroupBySlug = groupBy(roles, ({ customRoleSlug, role }) => customRoleSlug || role);
const updateGroupWorkspaceRole = useUpdateGroupWorkspaceRole();
const handleRoleUpdate = async (data: TForm) => {
const selectedRoles = Object.keys(data)
.filter((el) => Boolean(data[el].isChecked))
@@ -253,7 +260,7 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
roles: selectedRoles
});
createNotification({ text: "Successfully updated group role", type: "success" });
handlePopUpToggle("editRole");
onClose();
setSearchRoles("");
} catch {
createNotification({ text: "Failed to update group role", type: "error" });
@@ -261,7 +268,120 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
};
return (
<div className="flex items-center space-x-2">
<form onSubmit={handleSubmit(handleRoleUpdate)} id="role-update-form">
<div className="thin-scrollbar max-h-80 space-y-4 overflow-y-auto">
{projectRoles
?.filter(
({ name, slug }) =>
name.toLowerCase().includes(searchRoles.toLowerCase()) ||
slug.toLowerCase().includes(searchRoles.toLowerCase())
)
?.map(({ id, name, slug }) => {
const userProjectRoleDetails = userRolesGroupBySlug?.[slug]?.[0];
return (
<div key={id} className="flex items-center space-x-4">
<div className="flex-grow">
<Controller
control={control}
defaultValue={Boolean(userProjectRoleDetails?.id)}
name={`${slug}.isChecked`}
render={({ field }) => (
<Checkbox
id={slug}
isChecked={field.value}
onCheckedChange={(isChecked) => {
field.onChange(isChecked);
setValue(`${slug}.temporaryAccess`, false);
}}
>
{name}
</Checkbox>
)}
/>
</div>
<div>
<Controller
control={control}
name={`${slug}.temporaryAccess`}
defaultValue={
userProjectRoleDetails?.isTemporary
? {
isTemporary: true,
temporaryAccessStartTime:
userProjectRoleDetails.temporaryAccessStartTime as string,
temporaryRange: userProjectRoleDetails.temporaryRange as string,
temporaryAccessEndTime: userProjectRoleDetails.temporaryAccessEndTime
}
: false
}
render={({ field }) => (
<IdentityTemporaryRoleForm
temporaryConfig={
typeof field.value === "boolean"
? { isTemporary: field.value }
: field.value
}
onSetTemporary={(data) => {
setValue(`${slug}.isChecked`, true, { shouldDirty: true });
field.onChange({ isTemporary: true, ...data });
}}
onRemoveTemporary={() => {
setValue(`${slug}.isChecked`, false, { shouldDirty: true });
field.onChange(false);
}}
/>
)}
/>
</div>
</div>
);
})}
</div>
<div className="mt-3 flex items-center space-x-2 border-t border-t-gray-700 pt-3">
<div>
<Input
className="w-full p-1.5 pl-8"
size="xs"
value={searchRoles}
onChange={(el) => setSearchRoles(el.target.value)}
leftIcon={<FontAwesomeIcon icon={faSearch} />}
placeholder="Search roles.."
/>
</div>
<div>
<Button
size="xs"
type="submit"
form="role-update-form"
leftIcon={<FontAwesomeIcon icon={faCheck} />}
isDisabled={!isDirty || isSubmitting}
isLoading={isSubmitting}
>
Save
</Button>
</div>
</div>
</form>
);
};
export const GroupRoles = ({
roles = [],
disableEdit = false,
groupId,
className,
popperContentProps
}: TMemberRolesProp) => {
const { currentWorkspace } = useWorkspace();
const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const);
const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(
currentWorkspace?.id ?? ""
);
return (
<div className={twMerge("flex items-center space-x-1", className)}>
{roles
.slice(0, MAX_ROLES_TO_BE_SHOWN_IN_TABLE)
.map(({ role, customRoleName, id, isTemporary, temporaryAccessEndTime }) => {
@@ -325,119 +445,32 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
open={popUp.editRole.isOpen}
onOpenChange={(isOpen) => {
handlePopUpToggle("editRole", isOpen);
reset();
}}
>
{!disableEdit && (
<PopoverTrigger>
<PopoverTrigger onClick={(e) => e.stopPropagation()}>
<IconButton size="sm" variant="plain" ariaLabel="update">
<FontAwesomeIcon icon={faEdit} />
</IconButton>
</PopoverTrigger>
)}
<PopoverContent hideCloseBtn className="pt-4">
<PopoverContent
{...popperContentProps}
onClick={(e) => e.stopPropagation()}
hideCloseBtn
className="pt-4"
>
{isRolesLoading ? (
<div className="flex h-8 w-full items-center justify-center">
<Spinner />
</div>
) : (
<form onSubmit={handleSubmit(handleRoleUpdate)} id="role-update-form">
<div className="thin-scrollbar max-h-80 space-y-4 overflow-y-auto">
{projectRoles
?.filter(
({ name, slug }) =>
name.toLowerCase().includes(searchRoles.toLowerCase()) ||
slug.toLowerCase().includes(searchRoles.toLowerCase())
)
?.map(({ id, name, slug }) => {
const userProjectRoleDetails = userRolesGroupBySlug?.[slug]?.[0];
return (
<div key={id} className="flex items-center space-x-4">
<div className="flex-grow">
<Controller
control={control}
defaultValue={Boolean(userProjectRoleDetails?.id)}
name={`${slug}.isChecked`}
render={({ field }) => (
<Checkbox
id={slug}
isChecked={field.value}
onCheckedChange={(isChecked) => {
field.onChange(isChecked);
setValue(`${slug}.temporaryAccess`, false);
}}
>
{name}
</Checkbox>
)}
/>
</div>
<div>
<Controller
control={control}
name={`${slug}.temporaryAccess`}
defaultValue={
userProjectRoleDetails?.isTemporary
? {
isTemporary: true,
temporaryAccessStartTime:
userProjectRoleDetails.temporaryAccessStartTime as string,
temporaryRange:
userProjectRoleDetails.temporaryRange as string,
temporaryAccessEndTime:
userProjectRoleDetails.temporaryAccessEndTime
}
: false
}
render={({ field }) => (
<IdentityTemporaryRoleForm
temporaryConfig={
typeof field.value === "boolean"
? { isTemporary: field.value }
: field.value
}
onSetTemporary={(data) => {
setValue(`${slug}.isChecked`, true, { shouldDirty: true });
field.onChange({ isTemporary: true, ...data });
}}
onRemoveTemporary={() => {
setValue(`${slug}.isChecked`, false, { shouldDirty: true });
field.onChange(false);
}}
/>
)}
/>
</div>
</div>
);
})}
</div>
<div className="mt-3 flex items-center space-x-2 border-t border-t-gray-700 pt-3">
<div>
<Input
className="w-full p-1.5 pl-8"
size="xs"
value={searchRoles}
onChange={(el) => setSearchRoles(el.target.value)}
leftIcon={<FontAwesomeIcon icon={faSearch} />}
placeholder="Search roles.."
/>
</div>
<div>
<Button
size="xs"
type="submit"
form="role-update-form"
leftIcon={<FontAwesomeIcon icon={faCheck} />}
isDisabled={!isDirty || isSubmitting}
isLoading={isSubmitting}
>
Save
</Button>
</div>
</div>
</form>
<GroupRolesForm
projectRoles={projectRoles}
groupId={groupId}
roles={roles}
onClose={() => handlePopUpToggle("editRole")}
/>
)}
</PopoverContent>
</Popover>
@@ -8,6 +8,7 @@ import {
faUsers
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { format } from "date-fns";
import { ProjectPermissionCan } from "@app/components/permissions";
@@ -55,6 +56,7 @@ enum GroupsOrderBy {
export const GroupTable = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace();
const navigate = useNavigate();
const {
search,
@@ -143,7 +145,32 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
.slice(offset, perPage * page)
.map(({ group: { id, name }, roles, createdAt }) => {
return (
<Tr className="group h-10" key={`st-v3-${id}`}>
<Tr
className="group h-10 w-full cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
key={`st-v3-${id}`}
role="button"
tabIndex={0}
onKeyDown={(evt) => {
if (evt.key === "Enter") {
navigate({
to: `/${currentWorkspace.type}/$projectId/groups/$groupId` as const,
params: {
projectId: currentWorkspace.id,
groupId: id
}
});
}
}}
onClick={() =>
navigate({
to: `/${currentWorkspace.type}/$projectId/groups/$groupId` as const,
params: {
projectId: currentWorkspace.id,
groupId: id
}
})
}
>
<Td>{name}</Td>
<Td>
<ProjectPermissionCan
@@ -165,7 +192,8 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
<Tooltip content="Remove">
<IconButton
onClick={() => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("deleteGroup", {
id,
name
@@ -0,0 +1,70 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { useParams } from "@tanstack/react-router";
import { ProjectPermissionCan } from "@app/components/permissions";
import { EmptyState, PageHeader, Spinner } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { useGetWorkspaceGroupMembershipDetails } from "@app/hooks/api/workspace/queries";
import { GroupDetailsSection } from "./components/GroupDetailsSection";
import { GroupMembersSection } from "./components/GroupMembersSection";
const Page = () => {
const groupId = useParams({
strict: false,
select: (el) => el.groupId as string
});
const { currentWorkspace } = useWorkspace();
const { data: groupMembership, isPending } = useGetWorkspaceGroupMembershipDetails(
currentWorkspace.id,
groupId
);
if (isPending)
return (
<div className="flex w-full items-center justify-center p-24">
<Spinner />
</div>
);
return (
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
{groupMembership ? (
<div className="mx-auto mb-6 w-full max-w-7xl">
<PageHeader title={groupMembership.group.name} />
<div className="flex">
<div className="mr-4 w-96">
<GroupDetailsSection groupMembership={groupMembership} />
</div>
<GroupMembersSection groupMembership={groupMembership} />
</div>
</div>
) : (
<EmptyState title="Error: Unable to find the group." className="py-12" />
)}
</div>
);
};
export const GroupDetailsByIDPage = () => {
const { t } = useTranslation();
return (
<>
<Helmet>
<title>{t("common.head-title", { title: "Project Group" })}</title>
<link rel="icon" href="/infisical.ico" />
</Helmet>
<ProjectPermissionCan
I={ProjectPermissionActions.Read}
a={ProjectPermissionSub.Groups}
passThrough={false}
renderGuardBanner
>
<Page />
</ProjectPermissionCan>
</>
);
};
@@ -0,0 +1,152 @@
import { faEllipsisV, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { format } from "date-fns";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
DeleteActionModal,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
IconButton
} from "@app/components/v2";
import { CopyButton } from "@app/components/v2/CopyButton";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { usePopUp } from "@app/hooks";
import { useDeleteGroupFromWorkspace } from "@app/hooks/api";
import { TGroupMembership } from "@app/hooks/api/groups/types";
import { GroupRoles } from "@app/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles";
type Props = {
groupMembership: TGroupMembership;
};
export const GroupDetailsSection = ({ groupMembership }: Props) => {
const { handlePopUpToggle, popUp, handlePopUpClose, handlePopUpOpen } = usePopUp([
"deleteGroup"
] as const);
const { mutateAsync: deleteMutateAsync } = useDeleteGroupFromWorkspace();
const { currentWorkspace } = useWorkspace();
const navigate = useNavigate();
const onRemoveGroupSubmit = async () => {
try {
await deleteMutateAsync({
groupId: groupMembership.group.id,
projectId: currentWorkspace.id
});
createNotification({
text: "Successfully removed group from project",
type: "success"
});
navigate({
to: `/${currentWorkspace.type}/${currentWorkspace.id}/access-management?selectedTab=groups`
});
handlePopUpClose("deleteGroup");
} catch (err) {
console.error(err);
const error = err as any;
const text = error?.response?.data?.message ?? "Failed to remove group from project";
createNotification({
text,
type: "error"
});
}
};
return (
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100">Group Details</h3>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton ariaLabel="Options" colorSchema="secondary" className="w-6" variant="plain">
<FontAwesomeIcon icon={faEllipsisV} />
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={2} align="end">
<ProjectPermissionCan
I={ProjectPermissionActions.Delete}
a={ProjectPermissionSub.Groups}
>
{(isAllowed) => {
return (
<DropdownMenuItem
icon={<FontAwesomeIcon icon={faTrash} />}
onClick={() => handlePopUpOpen("deleteGroup")}
isDisabled={!isAllowed}
>
Remove Group From Project
</DropdownMenuItem>
);
}}
</ProjectPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="pt-4">
<div className="mb-4">
<p className="text-sm font-semibold text-mineshaft-300">Group ID</p>
<div className="group flex items-center gap-2">
<p className="text-sm text-mineshaft-300">{groupMembership.group.id}</p>
<CopyButton
value={groupMembership.group.id}
name="Group ID"
size="xs"
variant="plain"
/>
</div>
</div>
<div className="mb-4">
<p className="text-sm font-semibold text-mineshaft-300">Name</p>
<p className="text-sm text-mineshaft-300">{groupMembership.group.name}</p>
</div>
<div className="mb-4">
<p className="text-sm font-semibold text-mineshaft-300">Slug</p>
<div className="group flex items-center gap-2">
<p className="text-sm text-mineshaft-300">{groupMembership.group.slug}</p>
<CopyButton value={groupMembership.group.slug} name="Slug" size="xs" variant="plain" />
</div>
</div>
<div className="mb-4">
<p className="text-sm font-semibold text-mineshaft-300">Project Role</p>
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Groups}>
{(isAllowed) => (
<GroupRoles
className="mt-1"
popperContentProps={{ side: "right" }}
roles={groupMembership.roles}
groupId={groupMembership.group.id}
disableEdit={!isAllowed}
/>
)}
</ProjectPermissionCan>
</div>
<div className="mb-4">
<p className="text-sm font-semibold text-mineshaft-300">Assigned to Project</p>
<p className="text-sm text-mineshaft-300">
{format(groupMembership.createdAt, "M/d/yyyy")}
</p>
</div>
</div>
<DeleteActionModal
isOpen={popUp.deleteGroup.isOpen}
title={`Are you sure you want to remove the group ${
groupMembership.group.name
} from the project?`}
onChange={(isOpen) => handlePopUpToggle("deleteGroup", isOpen)}
deleteKey="confirm"
buttonText="Remove"
onDeleteApproved={onRemoveGroupSubmit}
/>
</div>
);
};
@@ -0,0 +1,20 @@
import { TGroupMembership } from "@app/hooks/api/groups/types";
import { GroupMembersTable } from "./GroupMembersTable";
type Props = {
groupMembership: TGroupMembership;
};
export const GroupMembersSection = ({ groupMembership }: Props) => {
return (
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100">Group Members</h3>
</div>
<div className="py-4">
<GroupMembersTable groupMembership={groupMembership} />
</div>
</div>
);
};
@@ -0,0 +1,235 @@
import { useMemo } from "react";
import {
faArrowDown,
faArrowUp,
faFolder,
faMagnifyingGlass,
faSearch
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createNotification } from "@app/components/notifications";
import {
ConfirmActionModal,
EmptyState,
IconButton,
Input,
Pagination,
Table,
TableContainer,
TableSkeleton,
TBody,
Th,
THead,
Tr
} from "@app/components/v2";
import { useWorkspace } from "@app/context";
import {
getUserTablePreference,
PreferenceKey,
setUserTablePreference
} from "@app/helpers/userTablePreferences";
import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks";
import { useAssumeProjectPrivileges } from "@app/hooks/api";
import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { OrderByDirection } from "@app/hooks/api/generic/types";
import { useListProjectGroupUsers } from "@app/hooks/api/groups/queries";
import { EFilterReturnedUsers, TGroupMembership } from "@app/hooks/api/groups/types";
import { ProjectType } from "@app/hooks/api/workspace/types";
import { GroupMembershipRow } from "./GroupMembershipRow";
type Props = {
groupMembership: TGroupMembership;
};
enum GroupMembersOrderBy {
Name = "name"
}
export const GroupMembersTable = ({ groupMembership }: Props) => {
const {
search,
setSearch,
setPage,
page,
perPage,
setPerPage,
offset,
orderDirection,
toggleOrderDirection
} = usePagination(GroupMembersOrderBy.Name, {
initPerPage: getUserTablePreference("projectGroupMembersTable", PreferenceKey.PerPage, 20)
});
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(["assumePrivileges"] as const);
const handlePerPageChange = (newPerPage: number) => {
setPerPage(newPerPage);
setUserTablePreference("projectGroupMembersTable", PreferenceKey.PerPage, newPerPage);
};
const { currentWorkspace } = useWorkspace();
const { data: groupMemberships, isPending } = useListProjectGroupUsers({
id: groupMembership.group.id,
groupSlug: groupMembership.group.slug,
projectId: currentWorkspace.id,
offset,
limit: perPage,
search,
filter: EFilterReturnedUsers.EXISTING_MEMBERS
});
const filteredGroupMemberships = useMemo(() => {
return groupMemberships && groupMemberships?.users
? groupMemberships?.users
?.filter((membership) => {
const userSearchString = `${membership.firstName && membership.firstName} ${
membership.lastName && membership.lastName
} ${membership.email && membership.email} ${
membership.username && membership.username
}`;
return userSearchString.toLowerCase().includes(search.trim().toLowerCase());
})
.sort((a, b) => {
const [membershipOne, membershipTwo] =
orderDirection === OrderByDirection.ASC ? [a, b] : [b, a];
const membershipOneComparisonString = membershipOne.firstName
? membershipOne.firstName
: membershipOne.email;
const membershipTwoComparisonString = membershipTwo.firstName
? membershipTwo.firstName
: membershipTwo.email;
const comparison = membershipOneComparisonString
.toLowerCase()
.localeCompare(membershipTwoComparisonString.toLowerCase());
return comparison;
})
: [];
}, [groupMemberships, orderDirection, search]);
useResetPageHelper({
totalCount: filteredGroupMemberships?.length,
offset,
setPage
});
const assumePrivileges = useAssumeProjectPrivileges();
const handleAssumePrivileges = async () => {
const { userId } = popUp?.assumePrivileges?.data as { userId: string };
assumePrivileges.mutate(
{
actorId: userId,
actorType: ActorType.USER,
projectId: currentWorkspace.id
},
{
onSuccess: () => {
createNotification({
type: "success",
text: "User privilege assumption has started"
});
let overviewPage: string;
switch (currentWorkspace.type) {
case ProjectType.SecretScanning:
overviewPage = "data-sources";
break;
case ProjectType.CertificateManager:
overviewPage = "subscribers";
break;
default:
overviewPage = "overview";
}
window.location.href = `/${currentWorkspace.type}/${currentWorkspace.id}/${overviewPage}`;
}
}
);
};
return (
<div>
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search users..."
/>
<TableContainer className="mt-4">
<Table>
<THead>
<Tr>
<Th className="w-1/3">
<div className="flex items-center">
Name
<IconButton
variant="plain"
className="ml-2"
ariaLabel="sort"
onClick={toggleOrderDirection}
>
<FontAwesomeIcon
icon={orderDirection === OrderByDirection.DESC ? faArrowUp : faArrowDown}
/>
</IconButton>
</div>
</Th>
<Th>Email</Th>
<Th>Added On</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{isPending && <TableSkeleton columns={4} innerKey="group-user-memberships" />}
{!isPending &&
filteredGroupMemberships.slice(offset, perPage * page).map((userGroupMembership) => {
return (
<GroupMembershipRow
key={`user-group-membership-${userGroupMembership.id}`}
user={userGroupMembership}
onAssumePrivileges={(userId) => handlePopUpOpen("assumePrivileges", { userId })}
/>
);
})}
</TBody>
</Table>
{Boolean(filteredGroupMemberships.length) && (
<Pagination
count={filteredGroupMemberships.length}
page={page}
perPage={perPage}
onChangePage={setPage}
onChangePerPage={handlePerPageChange}
/>
)}
{!isPending && !filteredGroupMemberships?.length && (
<EmptyState
title={
groupMemberships?.users.length
? "No users match this search..."
: "This group does not have any members yet"
}
icon={groupMemberships?.users.length ? faSearch : faFolder}
/>
)}
</TableContainer>
<ConfirmActionModal
isOpen={popUp.assumePrivileges.isOpen}
confirmKey="assume"
title="Do you want to assume privileges of this user?"
subTitle="This will set your privileges to those of the user for the next hour."
onChange={(isOpen) => handlePopUpToggle("assumePrivileges", isOpen)}
onConfirmed={handleAssumePrivileges}
buttonText="Confirm"
/>
</div>
);
};
@@ -0,0 +1,76 @@
import { faEllipsisV, faUser } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
IconButton,
Td,
Tooltip,
Tr
} from "@app/components/v2";
import { ProjectPermissionMemberActions, ProjectPermissionSub } from "@app/context";
import { TGroupUser } from "@app/hooks/api/groups/types";
type Props = {
user: TGroupUser;
onAssumePrivileges: (userId: string) => void;
};
export const GroupMembershipRow = ({
user: { firstName, lastName, joinedGroupAt, email, id },
onAssumePrivileges
}: Props) => {
return (
<Tr className="items-center" key={`group-user-${id}`}>
<Td>
<p>{`${firstName ?? "-"} ${lastName ?? ""}`}</p>
</Td>
<Td>
<p>{email}</p>
</Td>
<Td>
<Tooltip content={new Date(joinedGroupAt).toLocaleString()}>
<p>{new Date(joinedGroupAt).toLocaleDateString()}</p>
</Tooltip>
</Td>
<Td>
<Tooltip className="max-w-sm text-center" content="Options">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton
ariaLabel="Options"
colorSchema="secondary"
className="w-6"
variant="plain"
>
<FontAwesomeIcon icon={faEllipsisV} />
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={2} align="end">
<ProjectPermissionCan
I={ProjectPermissionMemberActions.AssumePrivileges}
a={ProjectPermissionSub.Member}
>
{(isAllowed) => {
return (
<DropdownMenuItem
icon={<FontAwesomeIcon icon={faUser} />}
onClick={() => onAssumePrivileges(id)}
isDisabled={!isAllowed}
>
Assume Privileges
</DropdownMenuItem>
);
}}
</ProjectPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</Tooltip>
</Td>
</Tr>
);
};
@@ -0,0 +1 @@
export { GroupMembersSection } from "./GroupMembersSection";
@@ -0,0 +1 @@
export { GroupDetailsSection } from "./GroupDetailsSection";
@@ -0,0 +1,28 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/cert-manager/$projectId/access-management",
params: {
projectId: params.projectId
}
})
},
{
label: "Groups"
}
]
};
}
});
@@ -0,0 +1,28 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/kms/$projectId/access-management",
params: {
projectId: params.projectId
}
})
},
{
label: "Groups"
}
]
};
}
});
@@ -0,0 +1,28 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/secret-manager/$projectId/access-management",
params: {
projectId: params.projectId
}
})
},
{
label: "Groups"
}
]
};
}
});
@@ -0,0 +1,28 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/secret-scanning/$projectId/access-management",
params: {
projectId: params.projectId
}
})
},
{
label: "Groups"
}
]
};
}
});
@@ -0,0 +1,28 @@
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId"
)({
component: GroupDetailsByIDPage,
beforeLoad: ({ context, params }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Access Control",
link: linkOptions({
to: "/ssh/$projectId/access-management",
params: {
projectId: params.projectId
}
})
},
{
label: "Groups"
}
]
};
}
});
@@ -0,0 +1,27 @@
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GroupDetailsByIDPage } from "./GroupDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId"
)({
component: GroupDetailsByIDPage,
context: () => ({
breadcrumbs: [
{
label: "Home",
icon: () => <FontAwesomeIcon icon={faHome} />,
link: linkOptions({ to: "/organization/secret-manager/overview" })
},
{
label: "Access Control",
link: linkOptions({ to: "/organization/access-management" })
},
{
label: "groups"
}
]
})
});
+145
View File
@@ -115,19 +115,24 @@ import { Route as certManagerAlertingPageRouteImport } from './pages/cert-manage
import { Route as projectRoleDetailsBySlugPageRouteSshImport } from './pages/project/RoleDetailsBySlugPage/route-ssh'
import { Route as projectMemberDetailsByIDPageRouteSshImport } from './pages/project/MemberDetailsByIDPage/route-ssh'
import { Route as projectIdentityDetailsByIDPageRouteSshImport } from './pages/project/IdentityDetailsByIDPage/route-ssh'
import { Route as projectGroupDetailsByIDPageRouteSshImport } from './pages/project/GroupDetailsByIDPage/route-ssh'
import { Route as projectRoleDetailsBySlugPageRouteSecretScanningImport } from './pages/project/RoleDetailsBySlugPage/route-secret-scanning'
import { Route as projectMemberDetailsByIDPageRouteSecretScanningImport } from './pages/project/MemberDetailsByIDPage/route-secret-scanning'
import { Route as projectIdentityDetailsByIDPageRouteSecretScanningImport } from './pages/project/IdentityDetailsByIDPage/route-secret-scanning'
import { Route as projectGroupDetailsByIDPageRouteSecretScanningImport } from './pages/project/GroupDetailsByIDPage/route-secret-scanning'
import { Route as projectRoleDetailsBySlugPageRouteSecretManagerImport } from './pages/project/RoleDetailsBySlugPage/route-secret-manager'
import { Route as projectMemberDetailsByIDPageRouteSecretManagerImport } from './pages/project/MemberDetailsByIDPage/route-secret-manager'
import { Route as projectIdentityDetailsByIDPageRouteSecretManagerImport } from './pages/project/IdentityDetailsByIDPage/route-secret-manager'
import { Route as projectGroupDetailsByIDPageRouteSecretManagerImport } from './pages/project/GroupDetailsByIDPage/route-secret-manager'
import { Route as projectRoleDetailsBySlugPageRouteKmsImport } from './pages/project/RoleDetailsBySlugPage/route-kms'
import { Route as projectMemberDetailsByIDPageRouteKmsImport } from './pages/project/MemberDetailsByIDPage/route-kms'
import { Route as projectIdentityDetailsByIDPageRouteKmsImport } from './pages/project/IdentityDetailsByIDPage/route-kms'
import { Route as projectGroupDetailsByIDPageRouteKmsImport } from './pages/project/GroupDetailsByIDPage/route-kms'
import { Route as projectRoleDetailsBySlugPageRouteCertManagerImport } from './pages/project/RoleDetailsBySlugPage/route-cert-manager'
import { Route as certManagerPkiCollectionDetailsByIDPageRoutesImport } from './pages/cert-manager/PkiCollectionDetailsByIDPage/routes'
import { Route as projectMemberDetailsByIDPageRouteCertManagerImport } from './pages/project/MemberDetailsByIDPage/route-cert-manager'
import { Route as projectIdentityDetailsByIDPageRouteCertManagerImport } from './pages/project/IdentityDetailsByIDPage/route-cert-manager'
import { Route as projectGroupDetailsByIDPageRouteCertManagerImport } from './pages/project/GroupDetailsByIDPage/route-cert-manager'
import { Route as sshSshHostGroupDetailsByIDPageRouteImport } from './pages/ssh/SshHostGroupDetailsByIDPage/route'
import { Route as sshSshCaByIDPageRouteImport } from './pages/ssh/SshCaByIDPage/route'
import { Route as secretManagerSecretDashboardPageRouteImport } from './pages/secret-manager/SecretDashboardPage/route'
@@ -1149,6 +1154,13 @@ const projectIdentityDetailsByIDPageRouteSshRoute =
getParentRoute: () => sshLayoutRoute,
} as any)
const projectGroupDetailsByIDPageRouteSshRoute =
projectGroupDetailsByIDPageRouteSshImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => sshLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteSecretScanningRoute =
projectRoleDetailsBySlugPageRouteSecretScanningImport.update({
id: '/roles/$roleSlug',
@@ -1170,6 +1182,13 @@ const projectIdentityDetailsByIDPageRouteSecretScanningRoute =
getParentRoute: () => secretScanningLayoutRoute,
} as any)
const projectGroupDetailsByIDPageRouteSecretScanningRoute =
projectGroupDetailsByIDPageRouteSecretScanningImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => secretScanningLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteSecretManagerRoute =
projectRoleDetailsBySlugPageRouteSecretManagerImport.update({
id: '/roles/$roleSlug',
@@ -1191,6 +1210,13 @@ const projectIdentityDetailsByIDPageRouteSecretManagerRoute =
getParentRoute: () => secretManagerLayoutRoute,
} as any)
const projectGroupDetailsByIDPageRouteSecretManagerRoute =
projectGroupDetailsByIDPageRouteSecretManagerImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => secretManagerLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteKmsRoute =
projectRoleDetailsBySlugPageRouteKmsImport.update({
id: '/roles/$roleSlug',
@@ -1212,6 +1238,13 @@ const projectIdentityDetailsByIDPageRouteKmsRoute =
getParentRoute: () => kmsLayoutRoute,
} as any)
const projectGroupDetailsByIDPageRouteKmsRoute =
projectGroupDetailsByIDPageRouteKmsImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => kmsLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteCertManagerRoute =
projectRoleDetailsBySlugPageRouteCertManagerImport.update({
id: '/roles/$roleSlug',
@@ -1240,6 +1273,13 @@ const projectIdentityDetailsByIDPageRouteCertManagerRoute =
getParentRoute: () => certManagerLayoutRoute,
} as any)
const projectGroupDetailsByIDPageRouteCertManagerRoute =
projectGroupDetailsByIDPageRouteCertManagerImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => certManagerLayoutRoute,
} as any)
const sshSshHostGroupDetailsByIDPageRouteRoute =
sshSshHostGroupDetailsByIDPageRouteImport.update({
id: '/ssh-host-groups/$sshHostGroupId',
@@ -2861,6 +2901,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof sshSshHostGroupDetailsByIDPageRouteImport
parentRoute: typeof sshLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId': {
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId'
path: '/groups/$groupId'
fullPath: '/cert-manager/$projectId/groups/$groupId'
preLoaderRoute: typeof projectGroupDetailsByIDPageRouteCertManagerImport
parentRoute: typeof certManagerLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId': {
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId'
path: '/identities/$identityId'
@@ -2889,6 +2936,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteCertManagerImport
parentRoute: typeof certManagerLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId': {
id: '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId'
path: '/groups/$groupId'
fullPath: '/kms/$projectId/groups/$groupId'
preLoaderRoute: typeof projectGroupDetailsByIDPageRouteKmsImport
parentRoute: typeof kmsLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId': {
id: '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId'
path: '/identities/$identityId'
@@ -2910,6 +2964,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteKmsImport
parentRoute: typeof kmsLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId': {
id: '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId'
path: '/groups/$groupId'
fullPath: '/secret-manager/$projectId/groups/$groupId'
preLoaderRoute: typeof projectGroupDetailsByIDPageRouteSecretManagerImport
parentRoute: typeof secretManagerLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId': {
id: '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId'
path: '/identities/$identityId'
@@ -2931,6 +2992,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerImport
parentRoute: typeof secretManagerLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId': {
id: '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId'
path: '/groups/$groupId'
fullPath: '/secret-scanning/$projectId/groups/$groupId'
preLoaderRoute: typeof projectGroupDetailsByIDPageRouteSecretScanningImport
parentRoute: typeof secretScanningLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId': {
id: '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId'
path: '/identities/$identityId'
@@ -2952,6 +3020,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningImport
parentRoute: typeof secretScanningLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId': {
id: '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId'
path: '/groups/$groupId'
fullPath: '/ssh/$projectId/groups/$groupId'
preLoaderRoute: typeof projectGroupDetailsByIDPageRouteSshImport
parentRoute: typeof sshLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId': {
id: '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId'
path: '/identities/$identityId'
@@ -3735,6 +3810,7 @@ interface certManagerLayoutRouteChildren {
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren
certManagerCertAuthDetailsByIDPageRouteRoute: typeof certManagerCertAuthDetailsByIDPageRouteRoute
projectGroupDetailsByIDPageRouteCertManagerRoute: typeof projectGroupDetailsByIDPageRouteCertManagerRoute
projectIdentityDetailsByIDPageRouteCertManagerRoute: typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
projectMemberDetailsByIDPageRouteCertManagerRoute: typeof projectMemberDetailsByIDPageRouteCertManagerRoute
certManagerPkiCollectionDetailsByIDPageRoutesRoute: typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
@@ -3755,6 +3831,8 @@ const certManagerLayoutRouteChildren: certManagerLayoutRouteChildren = {
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren,
certManagerCertAuthDetailsByIDPageRouteRoute:
certManagerCertAuthDetailsByIDPageRouteRoute,
projectGroupDetailsByIDPageRouteCertManagerRoute:
projectGroupDetailsByIDPageRouteCertManagerRoute,
projectIdentityDetailsByIDPageRouteCertManagerRoute:
projectIdentityDetailsByIDPageRouteCertManagerRoute,
projectMemberDetailsByIDPageRouteCertManagerRoute:
@@ -3787,6 +3865,7 @@ interface kmsLayoutRouteChildren {
kmsOverviewPageRouteRoute: typeof kmsOverviewPageRouteRoute
kmsSettingsPageRouteRoute: typeof kmsSettingsPageRouteRoute
projectAccessControlPageRouteKmsRoute: typeof projectAccessControlPageRouteKmsRoute
projectGroupDetailsByIDPageRouteKmsRoute: typeof projectGroupDetailsByIDPageRouteKmsRoute
projectIdentityDetailsByIDPageRouteKmsRoute: typeof projectIdentityDetailsByIDPageRouteKmsRoute
projectMemberDetailsByIDPageRouteKmsRoute: typeof projectMemberDetailsByIDPageRouteKmsRoute
projectRoleDetailsBySlugPageRouteKmsRoute: typeof projectRoleDetailsBySlugPageRouteKmsRoute
@@ -3797,6 +3876,8 @@ const kmsLayoutRouteChildren: kmsLayoutRouteChildren = {
kmsOverviewPageRouteRoute: kmsOverviewPageRouteRoute,
kmsSettingsPageRouteRoute: kmsSettingsPageRouteRoute,
projectAccessControlPageRouteKmsRoute: projectAccessControlPageRouteKmsRoute,
projectGroupDetailsByIDPageRouteKmsRoute:
projectGroupDetailsByIDPageRouteKmsRoute,
projectIdentityDetailsByIDPageRouteKmsRoute:
projectIdentityDetailsByIDPageRouteKmsRoute,
projectMemberDetailsByIDPageRouteKmsRoute:
@@ -4078,6 +4159,7 @@ interface secretManagerLayoutRouteChildren {
projectAccessControlPageRouteSecretManagerRoute: typeof projectAccessControlPageRouteSecretManagerRoute
AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren
secretManagerSecretDashboardPageRouteRoute: typeof secretManagerSecretDashboardPageRouteRoute
projectGroupDetailsByIDPageRouteSecretManagerRoute: typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
projectIdentityDetailsByIDPageRouteSecretManagerRoute: typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
projectMemberDetailsByIDPageRouteSecretManagerRoute: typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
projectRoleDetailsBySlugPageRouteSecretManagerRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
@@ -4098,6 +4180,8 @@ const secretManagerLayoutRouteChildren: secretManagerLayoutRouteChildren = {
AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren,
secretManagerSecretDashboardPageRouteRoute:
secretManagerSecretDashboardPageRouteRoute,
projectGroupDetailsByIDPageRouteSecretManagerRoute:
projectGroupDetailsByIDPageRouteSecretManagerRoute,
projectIdentityDetailsByIDPageRouteSecretManagerRoute:
projectIdentityDetailsByIDPageRouteSecretManagerRoute,
projectMemberDetailsByIDPageRouteSecretManagerRoute:
@@ -4146,6 +4230,7 @@ interface secretScanningLayoutRouteChildren {
secretScanningSettingsPageRouteRoute: typeof secretScanningSettingsPageRouteRoute
projectAccessControlPageRouteSecretScanningRoute: typeof projectAccessControlPageRouteSecretScanningRoute
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren
projectGroupDetailsByIDPageRouteSecretScanningRoute: typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
projectIdentityDetailsByIDPageRouteSecretScanningRoute: typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
projectMemberDetailsByIDPageRouteSecretScanningRoute: typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
projectRoleDetailsBySlugPageRouteSecretScanningRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
@@ -4159,6 +4244,8 @@ const secretScanningLayoutRouteChildren: secretScanningLayoutRouteChildren = {
projectAccessControlPageRouteSecretScanningRoute,
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute:
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren,
projectGroupDetailsByIDPageRouteSecretScanningRoute:
projectGroupDetailsByIDPageRouteSecretScanningRoute,
projectIdentityDetailsByIDPageRouteSecretScanningRoute:
projectIdentityDetailsByIDPageRouteSecretScanningRoute,
projectMemberDetailsByIDPageRouteSecretScanningRoute:
@@ -4192,6 +4279,7 @@ interface sshLayoutRouteChildren {
projectAccessControlPageRouteSshRoute: typeof projectAccessControlPageRouteSshRoute
sshSshCaByIDPageRouteRoute: typeof sshSshCaByIDPageRouteRoute
sshSshHostGroupDetailsByIDPageRouteRoute: typeof sshSshHostGroupDetailsByIDPageRouteRoute
projectGroupDetailsByIDPageRouteSshRoute: typeof projectGroupDetailsByIDPageRouteSshRoute
projectIdentityDetailsByIDPageRouteSshRoute: typeof projectIdentityDetailsByIDPageRouteSshRoute
projectMemberDetailsByIDPageRouteSshRoute: typeof projectMemberDetailsByIDPageRouteSshRoute
projectRoleDetailsBySlugPageRouteSshRoute: typeof projectRoleDetailsBySlugPageRouteSshRoute
@@ -4206,6 +4294,8 @@ const sshLayoutRouteChildren: sshLayoutRouteChildren = {
sshSshCaByIDPageRouteRoute: sshSshCaByIDPageRouteRoute,
sshSshHostGroupDetailsByIDPageRouteRoute:
sshSshHostGroupDetailsByIDPageRouteRoute,
projectGroupDetailsByIDPageRouteSshRoute:
projectGroupDetailsByIDPageRouteSshRoute,
projectIdentityDetailsByIDPageRouteSshRoute:
projectIdentityDetailsByIDPageRouteSshRoute,
projectMemberDetailsByIDPageRouteSshRoute:
@@ -4561,19 +4651,24 @@ export interface FileRoutesByFullPath {
'/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute
'/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute
'/ssh/$projectId/ssh-host-groups/$sshHostGroupId': typeof sshSshHostGroupDetailsByIDPageRouteRoute
'/cert-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
'/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute
'/kms/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteKmsRoute
'/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute
'/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute
'/secret-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
'/secret-scanning/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
'/ssh/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSshRoute
'/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute
'/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@@ -4764,19 +4859,24 @@ export interface FileRoutesByTo {
'/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute
'/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute
'/ssh/$projectId/ssh-host-groups/$sshHostGroupId': typeof sshSshHostGroupDetailsByIDPageRouteRoute
'/cert-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
'/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute
'/kms/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteKmsRoute
'/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute
'/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute
'/secret-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
'/secret-scanning/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
'/ssh/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSshRoute
'/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute
'/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@@ -4990,19 +5090,24 @@ export interface FileRoutesById {
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ca/$caId': typeof sshSshCaByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ssh-host-groups/$sshHostGroupId': typeof sshSshHostGroupDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId': typeof projectGroupDetailsByIDPageRouteCertManagerRoute
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId': typeof projectGroupDetailsByIDPageRouteKmsRoute
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
'/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSshRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@@ -5207,19 +5312,24 @@ export interface FileRouteTypes {
| '/secret-manager/$projectId/secrets/$envSlug'
| '/ssh/$projectId/ca/$caId'
| '/ssh/$projectId/ssh-host-groups/$sshHostGroupId'
| '/cert-manager/$projectId/groups/$groupId'
| '/cert-manager/$projectId/identities/$identityId'
| '/cert-manager/$projectId/members/$membershipId'
| '/cert-manager/$projectId/pki-collections/$collectionId'
| '/cert-manager/$projectId/roles/$roleSlug'
| '/kms/$projectId/groups/$groupId'
| '/kms/$projectId/identities/$identityId'
| '/kms/$projectId/members/$membershipId'
| '/kms/$projectId/roles/$roleSlug'
| '/secret-manager/$projectId/groups/$groupId'
| '/secret-manager/$projectId/identities/$identityId'
| '/secret-manager/$projectId/members/$membershipId'
| '/secret-manager/$projectId/roles/$roleSlug'
| '/secret-scanning/$projectId/groups/$groupId'
| '/secret-scanning/$projectId/identities/$identityId'
| '/secret-scanning/$projectId/members/$membershipId'
| '/secret-scanning/$projectId/roles/$roleSlug'
| '/ssh/$projectId/groups/$groupId'
| '/ssh/$projectId/identities/$identityId'
| '/ssh/$projectId/members/$membershipId'
| '/ssh/$projectId/roles/$roleSlug'
@@ -5409,19 +5519,24 @@ export interface FileRouteTypes {
| '/secret-manager/$projectId/secrets/$envSlug'
| '/ssh/$projectId/ca/$caId'
| '/ssh/$projectId/ssh-host-groups/$sshHostGroupId'
| '/cert-manager/$projectId/groups/$groupId'
| '/cert-manager/$projectId/identities/$identityId'
| '/cert-manager/$projectId/members/$membershipId'
| '/cert-manager/$projectId/pki-collections/$collectionId'
| '/cert-manager/$projectId/roles/$roleSlug'
| '/kms/$projectId/groups/$groupId'
| '/kms/$projectId/identities/$identityId'
| '/kms/$projectId/members/$membershipId'
| '/kms/$projectId/roles/$roleSlug'
| '/secret-manager/$projectId/groups/$groupId'
| '/secret-manager/$projectId/identities/$identityId'
| '/secret-manager/$projectId/members/$membershipId'
| '/secret-manager/$projectId/roles/$roleSlug'
| '/secret-scanning/$projectId/groups/$groupId'
| '/secret-scanning/$projectId/identities/$identityId'
| '/secret-scanning/$projectId/members/$membershipId'
| '/secret-scanning/$projectId/roles/$roleSlug'
| '/ssh/$projectId/groups/$groupId'
| '/ssh/$projectId/identities/$identityId'
| '/ssh/$projectId/members/$membershipId'
| '/ssh/$projectId/roles/$roleSlug'
@@ -5633,19 +5748,24 @@ export interface FileRouteTypes {
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/secrets/$envSlug'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ca/$caId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ssh-host-groups/$sshHostGroupId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/pki-collections/$collectionId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/roles/$roleSlug'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/roles/$roleSlug'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug'
| '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug'
@@ -6206,6 +6326,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/ca/$caName",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/pki-collections/$collectionId",
@@ -6220,6 +6341,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/overview",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/settings",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/access-management",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/roles/$roleSlug"
@@ -6237,6 +6359,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/access-management",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/integrations",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/secrets/$envSlug",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug"
@@ -6250,6 +6373,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/settings",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/access-management",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/data-sources",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug"
@@ -6266,6 +6390,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/access-management",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ca/$caId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ssh-host-groups/$sshHostGroupId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug"
@@ -6558,6 +6683,10 @@ export const routeTree = rootRoute
"filePath": "ssh/SshHostGroupDetailsByIDPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout"
},
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/groups/$groupId": {
"filePath": "project/GroupDetailsByIDPage/route-cert-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout"
},
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-cert-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout"
@@ -6574,6 +6703,10 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-cert-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout"
},
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/groups/$groupId": {
"filePath": "project/GroupDetailsByIDPage/route-kms.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout"
},
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-kms.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout"
@@ -6586,6 +6719,10 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-kms.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout"
},
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/groups/$groupId": {
"filePath": "project/GroupDetailsByIDPage/route-secret-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout"
},
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-secret-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout"
@@ -6598,6 +6735,10 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-secret-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout"
},
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/groups/$groupId": {
"filePath": "project/GroupDetailsByIDPage/route-secret-scanning.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout"
},
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-secret-scanning.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout"
@@ -6610,6 +6751,10 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-secret-scanning.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout"
},
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/groups/$groupId": {
"filePath": "project/GroupDetailsByIDPage/route-ssh.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout"
},
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-ssh.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout"
+10 -5
View File
@@ -270,7 +270,8 @@ const secretManagerRoutes = route("/secret-manager/$projectId", [
route("/access-management", "project/AccessControlPage/route-secret-manager.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-manager.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-secret-manager.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-secret-manager.tsx")
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-secret-manager.tsx"),
route("/groups/$groupId", "project/GroupDetailsByIDPage/route-secret-manager.tsx")
])
]);
@@ -314,7 +315,8 @@ const certManagerRoutes = route("/cert-manager/$projectId", [
route("/access-management", "project/AccessControlPage/route-cert-manager.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-cert-manager.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-cert-manager.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-cert-manager.tsx")
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-cert-manager.tsx"),
route("/groups/$groupId", "project/GroupDetailsByIDPage/route-cert-manager.tsx")
])
]);
@@ -326,7 +328,8 @@ const kmsRoutes = route("/kms/$projectId", [
route("/access-management", "project/AccessControlPage/route-kms.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-kms.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-kms.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-kms.tsx")
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-kms.tsx"),
route("/groups/$groupId", "project/GroupDetailsByIDPage/route-kms.tsx")
])
]);
@@ -341,7 +344,8 @@ const sshRoutes = route("/ssh/$projectId", [
route("/access-management", "project/AccessControlPage/route-ssh.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-ssh.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-ssh.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-ssh.tsx")
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-ssh.tsx"),
route("/groups/$groupId", "project/GroupDetailsByIDPage/route-ssh.tsx")
])
]);
@@ -356,7 +360,8 @@ const secretScanningRoutes = route("/secret-scanning/$projectId", [
route("/access-management", "project/AccessControlPage/route-secret-scanning.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-scanning.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-secret-scanning.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-secret-scanning.tsx")
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-secret-scanning.tsx"),
route("/groups/$groupId", "project/GroupDetailsByIDPage/route-secret-scanning.tsx")
])
]);