Compare commits

..

4 Commits

Author SHA1 Message Date
4c8bf9bd92 Update values.yaml 2025-06-06 20:16:50 +04:00
a6554deb80 Update connection.go 2025-06-06 20:14:03 +04:00
4bd1eb6f70 Update helm-charts/infisical-gateway/CHANGELOG.md
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-06-06 04:12:04 +04:00
022ecf75e1 fix(gateway): handle malformed URL's 2025-06-06 04:02:24 +04:00
32 changed files with 284 additions and 1386 deletions

View File

@ -42,10 +42,6 @@ export type TListGroupUsersDTO = {
filter?: EFilterReturnedUsers; filter?: EFilterReturnedUsers;
} & TGenericPermission; } & TGenericPermission;
export type TListProjectGroupUsersDTO = TListGroupUsersDTO & {
projectId: string;
};
export type TAddUserToGroupDTO = { export type TAddUserToGroupDTO = {
id: string; id: string;
username: string; username: string;

View File

@ -89,7 +89,6 @@ export const GROUPS = {
limit: "The number of users to return.", limit: "The number of users to return.",
username: "The username to search for.", username: "The username to search for.",
search: "The text string that user email or name will be filtered by.", search: "The text string that user email or name will be filtered by.",
projectId: "The ID of the project the group belongs to.",
filterUsers: filterUsers:
"Whether to filter the list of returned users. 'existingMembers' will only return existing users in the group, 'nonMembers' will only return users not in the group, undefined will return all users in the organization." "Whether to filter the list of returned users. 'existingMembers' will only return existing users in the group, 'nonMembers' will only return users not in the group, undefined will return all users in the organization."
}, },

View File

@ -4,11 +4,9 @@ import {
GroupProjectMembershipsSchema, GroupProjectMembershipsSchema,
GroupsSchema, GroupsSchema,
ProjectMembershipRole, ProjectMembershipRole,
ProjectUserMembershipRolesSchema, ProjectUserMembershipRolesSchema
UsersSchema
} from "@app/db/schemas"; } from "@app/db/schemas";
import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs";
import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@ -303,61 +301,4 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) =>
return { groupMembership }; return { groupMembership };
} }
}); });
server.route({
method: "GET",
url: "/:projectId/groups/:groupId/users",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.ProjectGroups],
description: "Return project group users",
params: z.object({
projectId: z.string().trim().describe(GROUPS.LIST_USERS.projectId),
groupId: z.string().trim().describe(GROUPS.LIST_USERS.id)
}),
querystring: z.object({
offset: z.coerce.number().min(0).max(100).default(0).describe(GROUPS.LIST_USERS.offset),
limit: z.coerce.number().min(1).max(100).default(10).describe(GROUPS.LIST_USERS.limit),
username: z.string().trim().optional().describe(GROUPS.LIST_USERS.username),
search: z.string().trim().optional().describe(GROUPS.LIST_USERS.search),
filter: z.nativeEnum(EFilterReturnedUsers).optional().describe(GROUPS.LIST_USERS.filterUsers)
}),
response: {
200: z.object({
users: UsersSchema.pick({
email: true,
username: true,
firstName: true,
lastName: true,
id: true
})
.merge(
z.object({
isPartOfGroup: z.boolean(),
joinedGroupAt: z.date().nullable()
})
)
.array(),
totalCount: z.number()
})
}
},
handler: async (req) => {
const { users, totalCount } = await server.services.groupProject.listProjectGroupUsers({
id: req.params.groupId,
projectId: req.params.projectId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});
return { users, totalCount };
}
});
}; };

View File

@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, ProjectMembershipRole, SecretKeyEncoding, TGroups } from "@app/db/schemas"; import { ActionProjectType, ProjectMembershipRole, SecretKeyEncoding, TGroups } from "@app/db/schemas";
import { TListProjectGroupUsersDTO } from "@app/ee/services/group/group-types";
import { import {
constructPermissionErrorMessage, constructPermissionErrorMessage,
validatePrivilegeChangeOperation validatePrivilegeChangeOperation
@ -43,7 +42,7 @@ type TGroupProjectServiceFactoryDep = {
projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany" | "transaction">; projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany" | "transaction">;
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">; projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
projectBotDAL: TProjectBotDALFactory; projectBotDAL: TProjectBotDALFactory;
groupDAL: Pick<TGroupDALFactory, "findOne" | "findAllGroupPossibleMembers">; groupDAL: Pick<TGroupDALFactory, "findOne">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">;
}; };
@ -472,54 +471,11 @@ export const groupProjectServiceFactory = ({
return groupMembership; return groupMembership;
}; };
const listProjectGroupUsers = async ({
id,
projectId,
offset,
limit,
username,
actor,
actorId,
actorAuthMethod,
actorOrgId,
search,
filter
}: TListProjectGroupUsersDTO) => {
const project = await projectDAL.findById(projectId);
if (!project) {
throw new NotFoundError({ message: `Failed to find project with ID ${projectId}` });
}
const { permission } = await permissionService.getProjectPermission({
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
const { members, totalCount } = await groupDAL.findAllGroupPossibleMembers({
orgId: project.orgId,
groupId: id,
offset,
limit,
username,
search,
filter
});
return { users: members, totalCount };
};
return { return {
addGroupToProject, addGroupToProject,
updateGroupInProject, updateGroupInProject,
removeGroupFromProject, removeGroupFromProject,
listGroupsInProject, listGroupsInProject,
getGroupInProject, getGroupInProject
listProjectGroupUsers
}; };
}; };

View File

@ -274,9 +274,27 @@ export const identityKubernetesAuthServiceFactory = ({
if (identityKubernetesAuth.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway) { if (identityKubernetesAuth.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway) {
const { kubernetesHost } = identityKubernetesAuth; const { kubernetesHost } = identityKubernetesAuth;
const lastColonIndex = kubernetesHost.lastIndexOf(":");
const k8sHost = kubernetesHost.substring(0, lastColonIndex); let urlString = kubernetesHost;
const k8sPort = kubernetesHost.substring(lastColonIndex + 1); if (!kubernetesHost.startsWith("http://") && !kubernetesHost.startsWith("https://")) {
urlString = `https://${kubernetesHost}`;
}
const url = new URL(urlString);
let { port: k8sPort } = url;
const { protocol, hostname: k8sHost } = url;
const cleanedProtocol = new RE2(/[^a-zA-Z0-9]/g).replace(protocol, "").toLowerCase();
if (!["https", "http"].includes(cleanedProtocol)) {
throw new BadRequestError({
message: "Invalid Kubernetes host URL, must start with http:// or https://"
});
}
if (!k8sPort) {
k8sPort = cleanedProtocol === "https" ? "443" : "80";
}
if (!identityKubernetesAuth.gatewayId) { if (!identityKubernetesAuth.gatewayId) {
throw new BadRequestError({ throw new BadRequestError({
@ -287,7 +305,7 @@ export const identityKubernetesAuthServiceFactory = ({
data = await $gatewayProxyWrapper( data = await $gatewayProxyWrapper(
{ {
gatewayId: identityKubernetesAuth.gatewayId, gatewayId: identityKubernetesAuth.gatewayId,
targetHost: k8sHost, // note(daniel): must include the protocol (https|http) targetHost: `${cleanedProtocol}://${k8sHost}`, // note(daniel): must include the protocol (https|http)
targetPort: k8sPort ? Number(k8sPort) : 443, targetPort: k8sPort ? Number(k8sPort) : 443,
caCert, caCert,
reviewTokenThroughGateway: true reviewTokenThroughGateway: true

View File

@ -12,6 +12,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/url"
"os" "os"
"strings" "strings"
"sync" "sync"
@ -25,9 +26,13 @@ func handleConnection(ctx context.Context, quicConn quic.Connection) {
log.Info().Msgf("New connection from: %s", quicConn.RemoteAddr().String()) log.Info().Msgf("New connection from: %s", quicConn.RemoteAddr().String())
// Use WaitGroup to track all streams // Use WaitGroup to track all streams
var wg sync.WaitGroup var wg sync.WaitGroup
contextWithTimeout, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
for { for {
// Accept the first stream, which we'll use for commands // Accept the first stream, which we'll use for commands
stream, err := quicConn.AcceptStream(ctx) stream, err := quicConn.AcceptStream(contextWithTimeout)
if err != nil { if err != nil {
log.Printf("Failed to accept QUIC stream: %v", err) log.Printf("Failed to accept QUIC stream: %v", err)
break break
@ -51,7 +56,12 @@ func handleStream(stream quic.Stream, quicConn quic.Connection) {
// Use buffered reader for better handling of fragmented data // Use buffered reader for better handling of fragmented data
reader := bufio.NewReader(stream) reader := bufio.NewReader(stream)
defer stream.Close() defer func() {
log.Info().Msgf("Closing stream %d", streamID)
if stream != nil {
stream.Close()
}
}()
for { for {
msg, err := reader.ReadBytes('\n') msg, err := reader.ReadBytes('\n')
@ -106,6 +116,11 @@ func handleStream(stream quic.Stream, quicConn quic.Connection) {
targetURL := string(argParts[0]) targetURL := string(argParts[0])
if !isValidURL(targetURL) {
log.Error().Msgf("Invalid target URL: %s", targetURL)
return
}
// Parse optional parameters // Parse optional parameters
var caCertB64, verifyParam string var caCertB64, verifyParam string
for _, part := range argParts[1:] { for _, part := range argParts[1:] {
@ -160,7 +175,6 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string,
} }
} }
// set certificate verification based on what the gateway client sent
if verifyParam != "" { if verifyParam != "" {
tlsConfig.InsecureSkipVerify = verifyParam == "false" tlsConfig.InsecureSkipVerify = verifyParam == "false"
log.Info().Msgf("TLS verification set to: %s", verifyParam) log.Info().Msgf("TLS verification set to: %s", verifyParam)
@ -169,30 +183,39 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string,
transport.TLSClientConfig = tlsConfig transport.TLSClientConfig = tlsConfig
} }
// read and parse the http request from the stream client := &http.Client{
Transport: transport,
Timeout: 30 * time.Second,
}
// Loop to handle multiple HTTP requests on the same stream
for {
req, err := http.ReadRequest(reader) req, err := http.ReadRequest(reader)
if err != nil { if err != nil {
if errors.Is(err, io.EOF) {
log.Info().Msg("Client closed HTTP connection")
return nil
}
return fmt.Errorf("failed to read HTTP request: %v", err) return fmt.Errorf("failed to read HTTP request: %v", err)
} }
log.Info().Msgf("Received HTTP request: %s", req.URL.Path)
actionHeader := req.Header.Get("x-infisical-action") actionHeader := req.Header.Get("x-infisical-action")
if actionHeader != "" { if actionHeader != "" {
if actionHeader == "inject-k8s-sa-auth-token" { if actionHeader == "inject-k8s-sa-auth-token" {
token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil { if err != nil {
stream.Write([]byte(buildHttpInternalServerError("failed to read k8s sa auth token"))) stream.Write([]byte(buildHttpInternalServerError("failed to read k8s sa auth token")))
return fmt.Errorf("failed to read k8s sa auth token: %v", err) continue // Continue to next request instead of returning
} }
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(token))) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(token)))
log.Info().Msgf("Injected gateway k8s SA auth token in request to %s", targetURL) log.Info().Msgf("Injected gateway k8s SA auth token in request to %s", targetURL)
} }
req.Header.Del("x-infisical-action") req.Header.Del("x-infisical-action")
} }
// Build full target URL
var targetFullURL string var targetFullURL string
if strings.HasPrefix(targetURL, "http://") || strings.HasPrefix(targetURL, "https://") { if strings.HasPrefix(targetURL, "http://") || strings.HasPrefix(targetURL, "https://") {
baseURL := strings.TrimSuffix(targetURL, "/") baseURL := strings.TrimSuffix(targetURL, "/")
@ -210,25 +233,21 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string,
// create the request to the target // create the request to the target
proxyReq, err := http.NewRequest(req.Method, targetFullURL, req.Body) proxyReq, err := http.NewRequest(req.Method, targetFullURL, req.Body)
proxyReq.Header = req.Header.Clone()
if err != nil { if err != nil {
return fmt.Errorf("failed to create proxy request: %v", err) log.Error().Msgf("Failed to create proxy request: %v", err)
stream.Write([]byte(buildHttpInternalServerError("failed to create proxy request")))
continue // Continue to next request
} }
proxyReq.Header = req.Header.Clone()
log.Info().Msgf("Proxying %s %s to %s", req.Method, req.URL.Path, targetFullURL) log.Info().Msgf("Proxying %s %s to %s", req.Method, req.URL.Path, targetFullURL)
client := &http.Client{
Transport: transport,
Timeout: 30 * time.Second,
}
// make the request to the target
resp, err := client.Do(proxyReq) resp, err := client.Do(proxyReq)
if err != nil { if err != nil {
log.Error().Msgf("Failed to reach target: %v", err)
stream.Write([]byte(buildHttpInternalServerError(fmt.Sprintf("failed to reach target due to networking error: %s", err.Error())))) stream.Write([]byte(buildHttpInternalServerError(fmt.Sprintf("failed to reach target due to networking error: %s", err.Error()))))
return fmt.Errorf("failed to reach target due to networking error: %v", err) continue // Continue to next request
} }
defer resp.Body.Close()
// Write the entire response (status line, headers, body) to the stream // Write the entire response (status line, headers, body) to the stream
// http.Response.Write handles this for "Connection: close" correctly. // http.Response.Write handles this for "Connection: close" correctly.
@ -237,15 +256,22 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string,
resp.Header.Del("Connection") // Good practice for proxies resp.Header.Del("Connection") // Good practice for proxies
log.Info().Msgf("Writing response to stream: %s", resp.Status) log.Info().Msgf("Writing response to stream: %s", resp.Status)
if err := resp.Write(stream); err != nil { if err := resp.Write(stream); err != nil {
// If writing the response fails, the connection to the client might be broken.
// Logging the error is important. The original error will be returned.
log.Error().Err(err).Msg("Failed to write response to stream") log.Error().Err(err).Msg("Failed to write response to stream")
resp.Body.Close()
return fmt.Errorf("failed to write response to stream: %w", err) return fmt.Errorf("failed to write response to stream: %w", err)
} }
resp.Body.Close()
// Check if client wants to close connection
if req.Header.Get("Connection") == "close" {
log.Info().Msg("Client requested connection close")
return nil return nil
} }
}
}
func buildHttpInternalServerError(message string) string { func buildHttpInternalServerError(message string) string {
return fmt.Sprintf("HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\n\r\n{\"message\": \"gateway: %s\"}", message) return fmt.Sprintf("HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\n\r\n{\"message\": \"gateway: %s\"}", message)
@ -255,6 +281,11 @@ type CloseWrite interface {
CloseWrite() error CloseWrite() error
} }
func isValidURL(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
func CopyDataFromQuicToTcp(quicStream quic.Stream, tcpConn net.Conn) { func CopyDataFromQuicToTcp(quicStream quic.Stream, tcpConn net.Conn) {
// Create a WaitGroup to wait for both copy operations // Create a WaitGroup to wait for both copy operations
var wg sync.WaitGroup var wg sync.WaitGroup

View File

@ -21,27 +21,7 @@ export const groupKeys = {
limit: number; limit: number;
search: string; search: string;
filter?: EFilterReturnedUsers; 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) => { export const useGetGroupById = (groupId: string) => {
@ -100,51 +80,3 @@ 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;
}
});
};

View File

@ -50,13 +50,10 @@ export const useUpdateGroupWorkspaceRole = () => {
return groupMembership; return groupMembership;
}, },
onSuccess: (_, { projectId, groupId }) => { onSuccess: (_, { projectId }) => {
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId) queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId)
}); });
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceGroupMembershipDetails(projectId, groupId)
});
} }
}); });
}; };

View File

@ -691,21 +691,6 @@ 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) => { export const useListWorkspaceGroups = (projectId: string) => {
return useQuery({ return useQuery({
queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId), queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId),

View File

@ -36,8 +36,6 @@ export const workspaceKeys = {
searchWorkspace: (dto: TSearchProjectsDTO) => ["search-projects", dto] as const, searchWorkspace: (dto: TSearchProjectsDTO) => ["search-projects", dto] as const,
getWorkspaceGroupMemberships: (workspaceId: string) => getWorkspaceGroupMemberships: (workspaceId: string) =>
[{ workspaceId }, "workspace-groups"] as const, [{ workspaceId }, "workspace-groups"] as const,
getWorkspaceGroupMembershipDetails: (workspaceId: string, groupId: string) =>
[{ workspaceId, groupId }, "workspace-group-membership-details"] as const,
getWorkspaceCas: ({ projectSlug }: { projectSlug: string }) => getWorkspaceCas: ({ projectSlug }: { projectSlug: string }) =>
[{ projectSlug }, "workspace-cas"] as const, [{ projectSlug }, "workspace-cas"] as const,
specificWorkspaceCas: ({ projectSlug, status }: { projectSlug: string; status?: CaStatus }) => specificWorkspaceCas: ({ projectSlug, status }: { projectSlug: string; status?: CaStatus }) =>

View File

@ -152,7 +152,7 @@ export const GroupMembersTable = ({ groupId, groupSlug, handlePopUpOpen }: Props
</Th> </Th>
<Th>Email</Th> <Th>Email</Th>
<Th>Added On</Th> <Th>Added On</Th>
<Th className="w-5" /> <Th />
</Tr> </Tr>
</THead> </THead>
<TBody> <TBody>

View File

@ -1,17 +1,8 @@
import { faEllipsisV, faUserMinus } from "@fortawesome/free-solid-svg-icons"; import { faUserMinus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { OrgPermissionCan } from "@app/components/permissions"; import { OrgPermissionCan } from "@app/components/permissions";
import { import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
IconButton,
Td,
Tooltip,
Tr
} from "@app/components/v2";
import { OrgPermissionGroupActions, OrgPermissionSubjects, useOrganization } from "@app/context"; import { OrgPermissionGroupActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { useOidcManageGroupMembershipsEnabled } from "@app/hooks/api"; import { useOidcManageGroupMembershipsEnabled } from "@app/hooks/api";
import { TGroupUser } from "@app/hooks/api/groups/types"; import { TGroupUser } from "@app/hooks/api/groups/types";
@ -47,20 +38,7 @@ export const GroupMembershipRow = ({
<p>{new Date(joinedGroupAt).toLocaleDateString()}</p> <p>{new Date(joinedGroupAt).toLocaleDateString()}</p>
</Tooltip> </Tooltip>
</Td> </Td>
<Td> <Td className="justify-end">
<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">
<OrgPermissionCan I={OrgPermissionGroupActions.Edit} a={OrgPermissionSubjects.Groups}> <OrgPermissionCan I={OrgPermissionGroupActions.Edit} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => { {(isAllowed) => {
return ( return (
@ -68,26 +46,22 @@ export const GroupMembershipRow = ({
content={ content={
isOidcManageGroupMembershipsEnabled isOidcManageGroupMembershipsEnabled
? "OIDC Group Membership Mapping Enabled. Remove user from this group in your OIDC provider." ? "OIDC Group Membership Mapping Enabled. Remove user from this group in your OIDC provider."
: undefined : "Remove user from group"
} }
position="left"
> >
<div> <IconButton
<DropdownMenuItem
icon={<FontAwesomeIcon icon={faUserMinus} />}
onClick={() => handlePopUpOpen("removeMemberFromGroup", { username })}
isDisabled={!isAllowed || isOidcManageGroupMembershipsEnabled} isDisabled={!isAllowed || isOidcManageGroupMembershipsEnabled}
ariaLabel="Remove user from group"
onClick={() => handlePopUpOpen("removeMemberFromGroup", { username })}
variant="plain"
colorSchema="danger"
> >
Remove User From Group <FontAwesomeIcon icon={faUserMinus} />
</DropdownMenuItem> </IconButton>
</div>
</Tooltip> </Tooltip>
); );
}} }}
</OrgPermissionCan> </OrgPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</Tooltip>
</Td> </Td>
</Tr> </Tr>
); );

View File

@ -3,7 +3,6 @@ import { Controller, useForm } from "react-hook-form";
import { faCheck, faClock, faEdit, faSearch } from "@fortawesome/free-solid-svg-icons"; import { faCheck, faClock, faEdit, faSearch } 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 { PopperContentProps } from "@radix-ui/react-popper";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { z } from "zod"; import { z } from "zod";
@ -29,7 +28,6 @@ import { formatProjectRoleName } from "@app/helpers/roles";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api"; import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api";
import { TGroupMembership } from "@app/hooks/api/groups/types"; 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 { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types";
import { groupBy } from "@app/lib/fn/array"; import { groupBy } from "@app/lib/fn/array";
@ -198,38 +196,33 @@ type TForm = z.infer<typeof formSchema>;
export type TMemberRolesProp = { export type TMemberRolesProp = {
disableEdit?: boolean; disableEdit?: boolean;
groupId: string; groupId: string;
className?: string;
roles: TGroupMembership["roles"]; roles: TGroupMembership["roles"];
popperContentProps?: PopperContentProps;
}; };
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2; const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
type FormProps = { export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMemberRolesProp) => {
projectRoles: Omit<TProjectRole, "permissions">[] | undefined;
roles: TGroupMembership["roles"];
groupId: string;
onClose: VoidFunction;
};
const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const);
const [searchRoles, setSearchRoles] = useState(""); const [searchRoles, setSearchRoles] = useState("");
const userRolesGroupBySlug = groupBy(roles, ({ customRoleSlug, role }) => customRoleSlug || role);
const updateGroupWorkspaceRole = useUpdateGroupWorkspaceRole();
const { const {
handleSubmit, handleSubmit,
control, control,
reset,
setValue, setValue,
formState: { isSubmitting, isDirty } formState: { isSubmitting, isDirty }
} = useForm<TForm>({ } = useForm<TForm>({
resolver: zodResolver(formSchema) 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 handleRoleUpdate = async (data: TForm) => {
const selectedRoles = Object.keys(data) const selectedRoles = Object.keys(data)
.filter((el) => Boolean(data[el].isChecked)) .filter((el) => Boolean(data[el].isChecked))
@ -260,7 +253,7 @@ const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) =>
roles: selectedRoles roles: selectedRoles
}); });
createNotification({ text: "Successfully updated group role", type: "success" }); createNotification({ text: "Successfully updated group role", type: "success" });
onClose(); handlePopUpToggle("editRole");
setSearchRoles(""); setSearchRoles("");
} catch { } catch {
createNotification({ text: "Failed to update group role", type: "error" }); createNotification({ text: "Failed to update group role", type: "error" });
@ -268,120 +261,7 @@ const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) =>
}; };
return ( return (
<form onSubmit={handleSubmit(handleRoleUpdate)} id="role-update-form"> <div className="flex items-center space-x-2">
<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 {roles
.slice(0, MAX_ROLES_TO_BE_SHOWN_IN_TABLE) .slice(0, MAX_ROLES_TO_BE_SHOWN_IN_TABLE)
.map(({ role, customRoleName, id, isTemporary, temporaryAccessEndTime }) => { .map(({ role, customRoleName, id, isTemporary, temporaryAccessEndTime }) => {
@ -445,32 +325,119 @@ export const GroupRoles = ({
open={popUp.editRole.isOpen} open={popUp.editRole.isOpen}
onOpenChange={(isOpen) => { onOpenChange={(isOpen) => {
handlePopUpToggle("editRole", isOpen); handlePopUpToggle("editRole", isOpen);
reset();
}} }}
> >
{!disableEdit && ( {!disableEdit && (
<PopoverTrigger onClick={(e) => e.stopPropagation()}> <PopoverTrigger>
<IconButton size="sm" variant="plain" ariaLabel="update"> <IconButton size="sm" variant="plain" ariaLabel="update">
<FontAwesomeIcon icon={faEdit} /> <FontAwesomeIcon icon={faEdit} />
</IconButton> </IconButton>
</PopoverTrigger> </PopoverTrigger>
)} )}
<PopoverContent <PopoverContent hideCloseBtn className="pt-4">
{...popperContentProps}
onClick={(e) => e.stopPropagation()}
hideCloseBtn
className="pt-4"
>
{isRolesLoading ? ( {isRolesLoading ? (
<div className="flex h-8 w-full items-center justify-center"> <div className="flex h-8 w-full items-center justify-center">
<Spinner /> <Spinner />
</div> </div>
) : ( ) : (
<GroupRolesForm <form onSubmit={handleSubmit(handleRoleUpdate)} id="role-update-form">
projectRoles={projectRoles} <div className="thin-scrollbar max-h-80 space-y-4 overflow-y-auto">
groupId={groupId} {projectRoles
roles={roles} ?.filter(
onClose={() => handlePopUpToggle("editRole")} ({ 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>
)} )}
</PopoverContent> </PopoverContent>
</Popover> </Popover>

View File

@ -8,7 +8,6 @@ import {
faUsers faUsers
} 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 { format } from "date-fns"; import { format } from "date-fns";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
@ -56,7 +55,6 @@ enum GroupsOrderBy {
export const GroupTable = ({ handlePopUpOpen }: Props) => { export const GroupTable = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const navigate = useNavigate();
const { const {
search, search,
@ -145,32 +143,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
.slice(offset, perPage * page) .slice(offset, perPage * page)
.map(({ group: { id, name }, roles, createdAt }) => { .map(({ group: { id, name }, roles, createdAt }) => {
return ( return (
<Tr <Tr className="group h-10" key={`st-v3-${id}`}>
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>{name}</Td>
<Td> <Td>
<ProjectPermissionCan <ProjectPermissionCan
@ -192,8 +165,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100"> <div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
<Tooltip content="Remove"> <Tooltip content="Remove">
<IconButton <IconButton
onClick={(e) => { onClick={() => {
e.stopPropagation();
handlePopUpOpen("deleteGroup", { handlePopUpOpen("deleteGroup", {
id, id,
name name

View File

@ -1,70 +0,0 @@
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>
</>
);
};

View File

@ -1,152 +0,0 @@
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>
);
};

View File

@ -1,20 +0,0 @@
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>
);
};

View File

@ -1,235 +0,0 @@
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>
);
};

View File

@ -1,76 +0,0 @@
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>
);
};

View File

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

View File

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

View File

@ -1,28 +0,0 @@
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"
}
]
};
}
});

View File

@ -1,28 +0,0 @@
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"
}
]
};
}
});

View File

@ -1,28 +0,0 @@
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"
}
]
};
}
});

View File

@ -1,28 +0,0 @@
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"
}
]
};
}
});

View File

@ -1,28 +0,0 @@
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"
}
]
};
}
});

View File

@ -1,27 +0,0 @@
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"
}
]
})
});

View File

@ -115,24 +115,19 @@ import { Route as certManagerAlertingPageRouteImport } from './pages/cert-manage
import { Route as projectRoleDetailsBySlugPageRouteSshImport } from './pages/project/RoleDetailsBySlugPage/route-ssh' import { Route as projectRoleDetailsBySlugPageRouteSshImport } from './pages/project/RoleDetailsBySlugPage/route-ssh'
import { Route as projectMemberDetailsByIDPageRouteSshImport } from './pages/project/MemberDetailsByIDPage/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 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 projectRoleDetailsBySlugPageRouteSecretScanningImport } from './pages/project/RoleDetailsBySlugPage/route-secret-scanning'
import { Route as projectMemberDetailsByIDPageRouteSecretScanningImport } from './pages/project/MemberDetailsByIDPage/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 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 projectRoleDetailsBySlugPageRouteSecretManagerImport } from './pages/project/RoleDetailsBySlugPage/route-secret-manager'
import { Route as projectMemberDetailsByIDPageRouteSecretManagerImport } from './pages/project/MemberDetailsByIDPage/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 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 projectRoleDetailsBySlugPageRouteKmsImport } from './pages/project/RoleDetailsBySlugPage/route-kms'
import { Route as projectMemberDetailsByIDPageRouteKmsImport } from './pages/project/MemberDetailsByIDPage/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 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 projectRoleDetailsBySlugPageRouteCertManagerImport } from './pages/project/RoleDetailsBySlugPage/route-cert-manager'
import { Route as certManagerPkiCollectionDetailsByIDPageRoutesImport } from './pages/cert-manager/PkiCollectionDetailsByIDPage/routes' import { Route as certManagerPkiCollectionDetailsByIDPageRoutesImport } from './pages/cert-manager/PkiCollectionDetailsByIDPage/routes'
import { Route as projectMemberDetailsByIDPageRouteCertManagerImport } from './pages/project/MemberDetailsByIDPage/route-cert-manager' 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 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 sshSshHostGroupDetailsByIDPageRouteImport } from './pages/ssh/SshHostGroupDetailsByIDPage/route'
import { Route as sshSshCaByIDPageRouteImport } from './pages/ssh/SshCaByIDPage/route' import { Route as sshSshCaByIDPageRouteImport } from './pages/ssh/SshCaByIDPage/route'
import { Route as secretManagerSecretDashboardPageRouteImport } from './pages/secret-manager/SecretDashboardPage/route' import { Route as secretManagerSecretDashboardPageRouteImport } from './pages/secret-manager/SecretDashboardPage/route'
@ -1154,13 +1149,6 @@ const projectIdentityDetailsByIDPageRouteSshRoute =
getParentRoute: () => sshLayoutRoute, getParentRoute: () => sshLayoutRoute,
} as any) } as any)
const projectGroupDetailsByIDPageRouteSshRoute =
projectGroupDetailsByIDPageRouteSshImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => sshLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteSecretScanningRoute = const projectRoleDetailsBySlugPageRouteSecretScanningRoute =
projectRoleDetailsBySlugPageRouteSecretScanningImport.update({ projectRoleDetailsBySlugPageRouteSecretScanningImport.update({
id: '/roles/$roleSlug', id: '/roles/$roleSlug',
@ -1182,13 +1170,6 @@ const projectIdentityDetailsByIDPageRouteSecretScanningRoute =
getParentRoute: () => secretScanningLayoutRoute, getParentRoute: () => secretScanningLayoutRoute,
} as any) } as any)
const projectGroupDetailsByIDPageRouteSecretScanningRoute =
projectGroupDetailsByIDPageRouteSecretScanningImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => secretScanningLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteSecretManagerRoute = const projectRoleDetailsBySlugPageRouteSecretManagerRoute =
projectRoleDetailsBySlugPageRouteSecretManagerImport.update({ projectRoleDetailsBySlugPageRouteSecretManagerImport.update({
id: '/roles/$roleSlug', id: '/roles/$roleSlug',
@ -1210,13 +1191,6 @@ const projectIdentityDetailsByIDPageRouteSecretManagerRoute =
getParentRoute: () => secretManagerLayoutRoute, getParentRoute: () => secretManagerLayoutRoute,
} as any) } as any)
const projectGroupDetailsByIDPageRouteSecretManagerRoute =
projectGroupDetailsByIDPageRouteSecretManagerImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => secretManagerLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteKmsRoute = const projectRoleDetailsBySlugPageRouteKmsRoute =
projectRoleDetailsBySlugPageRouteKmsImport.update({ projectRoleDetailsBySlugPageRouteKmsImport.update({
id: '/roles/$roleSlug', id: '/roles/$roleSlug',
@ -1238,13 +1212,6 @@ const projectIdentityDetailsByIDPageRouteKmsRoute =
getParentRoute: () => kmsLayoutRoute, getParentRoute: () => kmsLayoutRoute,
} as any) } as any)
const projectGroupDetailsByIDPageRouteKmsRoute =
projectGroupDetailsByIDPageRouteKmsImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => kmsLayoutRoute,
} as any)
const projectRoleDetailsBySlugPageRouteCertManagerRoute = const projectRoleDetailsBySlugPageRouteCertManagerRoute =
projectRoleDetailsBySlugPageRouteCertManagerImport.update({ projectRoleDetailsBySlugPageRouteCertManagerImport.update({
id: '/roles/$roleSlug', id: '/roles/$roleSlug',
@ -1273,13 +1240,6 @@ const projectIdentityDetailsByIDPageRouteCertManagerRoute =
getParentRoute: () => certManagerLayoutRoute, getParentRoute: () => certManagerLayoutRoute,
} as any) } as any)
const projectGroupDetailsByIDPageRouteCertManagerRoute =
projectGroupDetailsByIDPageRouteCertManagerImport.update({
id: '/groups/$groupId',
path: '/groups/$groupId',
getParentRoute: () => certManagerLayoutRoute,
} as any)
const sshSshHostGroupDetailsByIDPageRouteRoute = const sshSshHostGroupDetailsByIDPageRouteRoute =
sshSshHostGroupDetailsByIDPageRouteImport.update({ sshSshHostGroupDetailsByIDPageRouteImport.update({
id: '/ssh-host-groups/$sshHostGroupId', id: '/ssh-host-groups/$sshHostGroupId',
@ -2901,13 +2861,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof sshSshHostGroupDetailsByIDPageRouteImport preLoaderRoute: typeof sshSshHostGroupDetailsByIDPageRouteImport
parentRoute: typeof sshLayoutImport 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': { '/_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' id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId'
path: '/identities/$identityId' path: '/identities/$identityId'
@ -2936,13 +2889,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteCertManagerImport preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteCertManagerImport
parentRoute: typeof certManagerLayoutImport 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': { '/_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' id: '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId'
path: '/identities/$identityId' path: '/identities/$identityId'
@ -2964,13 +2910,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteKmsImport preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteKmsImport
parentRoute: typeof kmsLayoutImport 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': { '/_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' id: '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId'
path: '/identities/$identityId' path: '/identities/$identityId'
@ -2992,13 +2931,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerImport preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerImport
parentRoute: typeof secretManagerLayoutImport 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': { '/_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' id: '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId'
path: '/identities/$identityId' path: '/identities/$identityId'
@ -3020,13 +2952,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningImport preLoaderRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningImport
parentRoute: typeof secretScanningLayoutImport 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': { '/_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' id: '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId'
path: '/identities/$identityId' path: '/identities/$identityId'
@ -3810,7 +3735,6 @@ interface certManagerLayoutRouteChildren {
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren
certManagerCertAuthDetailsByIDPageRouteRoute: typeof certManagerCertAuthDetailsByIDPageRouteRoute certManagerCertAuthDetailsByIDPageRouteRoute: typeof certManagerCertAuthDetailsByIDPageRouteRoute
projectGroupDetailsByIDPageRouteCertManagerRoute: typeof projectGroupDetailsByIDPageRouteCertManagerRoute
projectIdentityDetailsByIDPageRouteCertManagerRoute: typeof projectIdentityDetailsByIDPageRouteCertManagerRoute projectIdentityDetailsByIDPageRouteCertManagerRoute: typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
projectMemberDetailsByIDPageRouteCertManagerRoute: typeof projectMemberDetailsByIDPageRouteCertManagerRoute projectMemberDetailsByIDPageRouteCertManagerRoute: typeof projectMemberDetailsByIDPageRouteCertManagerRoute
certManagerPkiCollectionDetailsByIDPageRoutesRoute: typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute certManagerPkiCollectionDetailsByIDPageRoutesRoute: typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
@ -3831,8 +3755,6 @@ const certManagerLayoutRouteChildren: certManagerLayoutRouteChildren = {
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren, AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren,
certManagerCertAuthDetailsByIDPageRouteRoute: certManagerCertAuthDetailsByIDPageRouteRoute:
certManagerCertAuthDetailsByIDPageRouteRoute, certManagerCertAuthDetailsByIDPageRouteRoute,
projectGroupDetailsByIDPageRouteCertManagerRoute:
projectGroupDetailsByIDPageRouteCertManagerRoute,
projectIdentityDetailsByIDPageRouteCertManagerRoute: projectIdentityDetailsByIDPageRouteCertManagerRoute:
projectIdentityDetailsByIDPageRouteCertManagerRoute, projectIdentityDetailsByIDPageRouteCertManagerRoute,
projectMemberDetailsByIDPageRouteCertManagerRoute: projectMemberDetailsByIDPageRouteCertManagerRoute:
@ -3865,7 +3787,6 @@ interface kmsLayoutRouteChildren {
kmsOverviewPageRouteRoute: typeof kmsOverviewPageRouteRoute kmsOverviewPageRouteRoute: typeof kmsOverviewPageRouteRoute
kmsSettingsPageRouteRoute: typeof kmsSettingsPageRouteRoute kmsSettingsPageRouteRoute: typeof kmsSettingsPageRouteRoute
projectAccessControlPageRouteKmsRoute: typeof projectAccessControlPageRouteKmsRoute projectAccessControlPageRouteKmsRoute: typeof projectAccessControlPageRouteKmsRoute
projectGroupDetailsByIDPageRouteKmsRoute: typeof projectGroupDetailsByIDPageRouteKmsRoute
projectIdentityDetailsByIDPageRouteKmsRoute: typeof projectIdentityDetailsByIDPageRouteKmsRoute projectIdentityDetailsByIDPageRouteKmsRoute: typeof projectIdentityDetailsByIDPageRouteKmsRoute
projectMemberDetailsByIDPageRouteKmsRoute: typeof projectMemberDetailsByIDPageRouteKmsRoute projectMemberDetailsByIDPageRouteKmsRoute: typeof projectMemberDetailsByIDPageRouteKmsRoute
projectRoleDetailsBySlugPageRouteKmsRoute: typeof projectRoleDetailsBySlugPageRouteKmsRoute projectRoleDetailsBySlugPageRouteKmsRoute: typeof projectRoleDetailsBySlugPageRouteKmsRoute
@ -3876,8 +3797,6 @@ const kmsLayoutRouteChildren: kmsLayoutRouteChildren = {
kmsOverviewPageRouteRoute: kmsOverviewPageRouteRoute, kmsOverviewPageRouteRoute: kmsOverviewPageRouteRoute,
kmsSettingsPageRouteRoute: kmsSettingsPageRouteRoute, kmsSettingsPageRouteRoute: kmsSettingsPageRouteRoute,
projectAccessControlPageRouteKmsRoute: projectAccessControlPageRouteKmsRoute, projectAccessControlPageRouteKmsRoute: projectAccessControlPageRouteKmsRoute,
projectGroupDetailsByIDPageRouteKmsRoute:
projectGroupDetailsByIDPageRouteKmsRoute,
projectIdentityDetailsByIDPageRouteKmsRoute: projectIdentityDetailsByIDPageRouteKmsRoute:
projectIdentityDetailsByIDPageRouteKmsRoute, projectIdentityDetailsByIDPageRouteKmsRoute,
projectMemberDetailsByIDPageRouteKmsRoute: projectMemberDetailsByIDPageRouteKmsRoute:
@ -4159,7 +4078,6 @@ interface secretManagerLayoutRouteChildren {
projectAccessControlPageRouteSecretManagerRoute: typeof projectAccessControlPageRouteSecretManagerRoute projectAccessControlPageRouteSecretManagerRoute: typeof projectAccessControlPageRouteSecretManagerRoute
AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren
secretManagerSecretDashboardPageRouteRoute: typeof secretManagerSecretDashboardPageRouteRoute secretManagerSecretDashboardPageRouteRoute: typeof secretManagerSecretDashboardPageRouteRoute
projectGroupDetailsByIDPageRouteSecretManagerRoute: typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
projectIdentityDetailsByIDPageRouteSecretManagerRoute: typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute projectIdentityDetailsByIDPageRouteSecretManagerRoute: typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
projectMemberDetailsByIDPageRouteSecretManagerRoute: typeof projectMemberDetailsByIDPageRouteSecretManagerRoute projectMemberDetailsByIDPageRouteSecretManagerRoute: typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
projectRoleDetailsBySlugPageRouteSecretManagerRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute projectRoleDetailsBySlugPageRouteSecretManagerRoute: typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
@ -4180,8 +4098,6 @@ const secretManagerLayoutRouteChildren: secretManagerLayoutRouteChildren = {
AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren, AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren,
secretManagerSecretDashboardPageRouteRoute: secretManagerSecretDashboardPageRouteRoute:
secretManagerSecretDashboardPageRouteRoute, secretManagerSecretDashboardPageRouteRoute,
projectGroupDetailsByIDPageRouteSecretManagerRoute:
projectGroupDetailsByIDPageRouteSecretManagerRoute,
projectIdentityDetailsByIDPageRouteSecretManagerRoute: projectIdentityDetailsByIDPageRouteSecretManagerRoute:
projectIdentityDetailsByIDPageRouteSecretManagerRoute, projectIdentityDetailsByIDPageRouteSecretManagerRoute,
projectMemberDetailsByIDPageRouteSecretManagerRoute: projectMemberDetailsByIDPageRouteSecretManagerRoute:
@ -4230,7 +4146,6 @@ interface secretScanningLayoutRouteChildren {
secretScanningSettingsPageRouteRoute: typeof secretScanningSettingsPageRouteRoute secretScanningSettingsPageRouteRoute: typeof secretScanningSettingsPageRouteRoute
projectAccessControlPageRouteSecretScanningRoute: typeof projectAccessControlPageRouteSecretScanningRoute projectAccessControlPageRouteSecretScanningRoute: typeof projectAccessControlPageRouteSecretScanningRoute
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren
projectGroupDetailsByIDPageRouteSecretScanningRoute: typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
projectIdentityDetailsByIDPageRouteSecretScanningRoute: typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute projectIdentityDetailsByIDPageRouteSecretScanningRoute: typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
projectMemberDetailsByIDPageRouteSecretScanningRoute: typeof projectMemberDetailsByIDPageRouteSecretScanningRoute projectMemberDetailsByIDPageRouteSecretScanningRoute: typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
projectRoleDetailsBySlugPageRouteSecretScanningRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute projectRoleDetailsBySlugPageRouteSecretScanningRoute: typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
@ -4244,8 +4159,6 @@ const secretScanningLayoutRouteChildren: secretScanningLayoutRouteChildren = {
projectAccessControlPageRouteSecretScanningRoute, projectAccessControlPageRouteSecretScanningRoute,
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute: AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRoute:
AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren, AuthenticateInjectOrgDetailsOrgLayoutSecretScanningProjectIdSecretScanningLayoutDataSourcesRouteWithChildren,
projectGroupDetailsByIDPageRouteSecretScanningRoute:
projectGroupDetailsByIDPageRouteSecretScanningRoute,
projectIdentityDetailsByIDPageRouteSecretScanningRoute: projectIdentityDetailsByIDPageRouteSecretScanningRoute:
projectIdentityDetailsByIDPageRouteSecretScanningRoute, projectIdentityDetailsByIDPageRouteSecretScanningRoute,
projectMemberDetailsByIDPageRouteSecretScanningRoute: projectMemberDetailsByIDPageRouteSecretScanningRoute:
@ -4279,7 +4192,6 @@ interface sshLayoutRouteChildren {
projectAccessControlPageRouteSshRoute: typeof projectAccessControlPageRouteSshRoute projectAccessControlPageRouteSshRoute: typeof projectAccessControlPageRouteSshRoute
sshSshCaByIDPageRouteRoute: typeof sshSshCaByIDPageRouteRoute sshSshCaByIDPageRouteRoute: typeof sshSshCaByIDPageRouteRoute
sshSshHostGroupDetailsByIDPageRouteRoute: typeof sshSshHostGroupDetailsByIDPageRouteRoute sshSshHostGroupDetailsByIDPageRouteRoute: typeof sshSshHostGroupDetailsByIDPageRouteRoute
projectGroupDetailsByIDPageRouteSshRoute: typeof projectGroupDetailsByIDPageRouteSshRoute
projectIdentityDetailsByIDPageRouteSshRoute: typeof projectIdentityDetailsByIDPageRouteSshRoute projectIdentityDetailsByIDPageRouteSshRoute: typeof projectIdentityDetailsByIDPageRouteSshRoute
projectMemberDetailsByIDPageRouteSshRoute: typeof projectMemberDetailsByIDPageRouteSshRoute projectMemberDetailsByIDPageRouteSshRoute: typeof projectMemberDetailsByIDPageRouteSshRoute
projectRoleDetailsBySlugPageRouteSshRoute: typeof projectRoleDetailsBySlugPageRouteSshRoute projectRoleDetailsBySlugPageRouteSshRoute: typeof projectRoleDetailsBySlugPageRouteSshRoute
@ -4294,8 +4206,6 @@ const sshLayoutRouteChildren: sshLayoutRouteChildren = {
sshSshCaByIDPageRouteRoute: sshSshCaByIDPageRouteRoute, sshSshCaByIDPageRouteRoute: sshSshCaByIDPageRouteRoute,
sshSshHostGroupDetailsByIDPageRouteRoute: sshSshHostGroupDetailsByIDPageRouteRoute:
sshSshHostGroupDetailsByIDPageRouteRoute, sshSshHostGroupDetailsByIDPageRouteRoute,
projectGroupDetailsByIDPageRouteSshRoute:
projectGroupDetailsByIDPageRouteSshRoute,
projectIdentityDetailsByIDPageRouteSshRoute: projectIdentityDetailsByIDPageRouteSshRoute:
projectIdentityDetailsByIDPageRouteSshRoute, projectIdentityDetailsByIDPageRouteSshRoute,
projectMemberDetailsByIDPageRouteSshRoute: projectMemberDetailsByIDPageRouteSshRoute:
@ -4651,24 +4561,19 @@ export interface FileRoutesByFullPath {
'/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute '/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute
'/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute '/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute
'/ssh/$projectId/ssh-host-groups/$sshHostGroupId': typeof sshSshHostGroupDetailsByIDPageRouteRoute '/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/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute '/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute '/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
'/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute '/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute
'/kms/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteKmsRoute
'/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute '/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute
'/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute '/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute '/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute
'/secret-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute '/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute '/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute '/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
'/secret-scanning/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute '/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute '/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute '/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
'/ssh/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSshRoute
'/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute '/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute
'/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute '/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute '/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@ -4859,24 +4764,19 @@ export interface FileRoutesByTo {
'/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute '/secret-manager/$projectId/secrets/$envSlug': typeof secretManagerSecretDashboardPageRouteRoute
'/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute '/ssh/$projectId/ca/$caId': typeof sshSshCaByIDPageRouteRoute
'/ssh/$projectId/ssh-host-groups/$sshHostGroupId': typeof sshSshHostGroupDetailsByIDPageRouteRoute '/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/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute '/cert-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteCertManagerRoute
'/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute '/cert-manager/$projectId/pki-collections/$collectionId': typeof certManagerPkiCollectionDetailsByIDPageRoutesRoute
'/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute '/cert-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteCertManagerRoute
'/kms/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteKmsRoute
'/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute '/kms/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteKmsRoute
'/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute '/kms/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute '/kms/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute
'/secret-manager/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute '/secret-manager/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute '/secret-manager/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretManagerRoute
'/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute '/secret-manager/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretManagerRoute
'/secret-scanning/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute '/secret-scanning/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute '/secret-scanning/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSecretScanningRoute
'/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute '/secret-scanning/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSecretScanningRoute
'/ssh/$projectId/groups/$groupId': typeof projectGroupDetailsByIDPageRouteSshRoute
'/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute '/ssh/$projectId/identities/$identityId': typeof projectIdentityDetailsByIDPageRouteSshRoute
'/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute '/ssh/$projectId/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute '/ssh/$projectId/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@ -5090,24 +4990,19 @@ 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/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/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/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/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/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/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/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/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/members/$membershipId': typeof projectMemberDetailsByIDPageRouteKmsRoute
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteKmsRoute '/_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/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/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-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/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/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/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/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/members/$membershipId': typeof projectMemberDetailsByIDPageRouteSshRoute
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug': typeof projectRoleDetailsBySlugPageRouteSshRoute
@ -5312,24 +5207,19 @@ export interface FileRouteTypes {
| '/secret-manager/$projectId/secrets/$envSlug' | '/secret-manager/$projectId/secrets/$envSlug'
| '/ssh/$projectId/ca/$caId' | '/ssh/$projectId/ca/$caId'
| '/ssh/$projectId/ssh-host-groups/$sshHostGroupId' | '/ssh/$projectId/ssh-host-groups/$sshHostGroupId'
| '/cert-manager/$projectId/groups/$groupId'
| '/cert-manager/$projectId/identities/$identityId' | '/cert-manager/$projectId/identities/$identityId'
| '/cert-manager/$projectId/members/$membershipId' | '/cert-manager/$projectId/members/$membershipId'
| '/cert-manager/$projectId/pki-collections/$collectionId' | '/cert-manager/$projectId/pki-collections/$collectionId'
| '/cert-manager/$projectId/roles/$roleSlug' | '/cert-manager/$projectId/roles/$roleSlug'
| '/kms/$projectId/groups/$groupId'
| '/kms/$projectId/identities/$identityId' | '/kms/$projectId/identities/$identityId'
| '/kms/$projectId/members/$membershipId' | '/kms/$projectId/members/$membershipId'
| '/kms/$projectId/roles/$roleSlug' | '/kms/$projectId/roles/$roleSlug'
| '/secret-manager/$projectId/groups/$groupId'
| '/secret-manager/$projectId/identities/$identityId' | '/secret-manager/$projectId/identities/$identityId'
| '/secret-manager/$projectId/members/$membershipId' | '/secret-manager/$projectId/members/$membershipId'
| '/secret-manager/$projectId/roles/$roleSlug' | '/secret-manager/$projectId/roles/$roleSlug'
| '/secret-scanning/$projectId/groups/$groupId'
| '/secret-scanning/$projectId/identities/$identityId' | '/secret-scanning/$projectId/identities/$identityId'
| '/secret-scanning/$projectId/members/$membershipId' | '/secret-scanning/$projectId/members/$membershipId'
| '/secret-scanning/$projectId/roles/$roleSlug' | '/secret-scanning/$projectId/roles/$roleSlug'
| '/ssh/$projectId/groups/$groupId'
| '/ssh/$projectId/identities/$identityId' | '/ssh/$projectId/identities/$identityId'
| '/ssh/$projectId/members/$membershipId' | '/ssh/$projectId/members/$membershipId'
| '/ssh/$projectId/roles/$roleSlug' | '/ssh/$projectId/roles/$roleSlug'
@ -5519,24 +5409,19 @@ export interface FileRouteTypes {
| '/secret-manager/$projectId/secrets/$envSlug' | '/secret-manager/$projectId/secrets/$envSlug'
| '/ssh/$projectId/ca/$caId' | '/ssh/$projectId/ca/$caId'
| '/ssh/$projectId/ssh-host-groups/$sshHostGroupId' | '/ssh/$projectId/ssh-host-groups/$sshHostGroupId'
| '/cert-manager/$projectId/groups/$groupId'
| '/cert-manager/$projectId/identities/$identityId' | '/cert-manager/$projectId/identities/$identityId'
| '/cert-manager/$projectId/members/$membershipId' | '/cert-manager/$projectId/members/$membershipId'
| '/cert-manager/$projectId/pki-collections/$collectionId' | '/cert-manager/$projectId/pki-collections/$collectionId'
| '/cert-manager/$projectId/roles/$roleSlug' | '/cert-manager/$projectId/roles/$roleSlug'
| '/kms/$projectId/groups/$groupId'
| '/kms/$projectId/identities/$identityId' | '/kms/$projectId/identities/$identityId'
| '/kms/$projectId/members/$membershipId' | '/kms/$projectId/members/$membershipId'
| '/kms/$projectId/roles/$roleSlug' | '/kms/$projectId/roles/$roleSlug'
| '/secret-manager/$projectId/groups/$groupId'
| '/secret-manager/$projectId/identities/$identityId' | '/secret-manager/$projectId/identities/$identityId'
| '/secret-manager/$projectId/members/$membershipId' | '/secret-manager/$projectId/members/$membershipId'
| '/secret-manager/$projectId/roles/$roleSlug' | '/secret-manager/$projectId/roles/$roleSlug'
| '/secret-scanning/$projectId/groups/$groupId'
| '/secret-scanning/$projectId/identities/$identityId' | '/secret-scanning/$projectId/identities/$identityId'
| '/secret-scanning/$projectId/members/$membershipId' | '/secret-scanning/$projectId/members/$membershipId'
| '/secret-scanning/$projectId/roles/$roleSlug' | '/secret-scanning/$projectId/roles/$roleSlug'
| '/ssh/$projectId/groups/$groupId'
| '/ssh/$projectId/identities/$identityId' | '/ssh/$projectId/identities/$identityId'
| '/ssh/$projectId/members/$membershipId' | '/ssh/$projectId/members/$membershipId'
| '/ssh/$projectId/roles/$roleSlug' | '/ssh/$projectId/roles/$roleSlug'
@ -5748,24 +5633,19 @@ export interface FileRouteTypes {
| '/_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/secrets/$envSlug'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ca/$caId' | '/_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/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/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/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/pki-collections/$collectionId'
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/roles/$roleSlug' | '/_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/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/members/$membershipId' | '/_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/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/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/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug' | '/_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/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/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug' | '/_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/identities/$identityId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId' | '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug' | '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug'
@ -6326,7 +6206,6 @@ 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/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/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/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/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/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/pki-collections/$collectionId",
@ -6341,7 +6220,6 @@ 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/overview",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/settings", "/_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/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/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/members/$membershipId", "/_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/kms/$projectId/_kms-layout/roles/$roleSlug"
@ -6359,7 +6237,6 @@ 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/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/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/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/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/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug" "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/roles/$roleSlug"
@ -6373,7 +6250,6 @@ 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/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/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/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/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/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug" "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/roles/$roleSlug"
@ -6390,7 +6266,6 @@ 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/access-management",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/ca/$caId", "/_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/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/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId", "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/members/$membershipId",
"/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug" "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug"
@ -6683,10 +6558,6 @@ export const routeTree = rootRoute
"filePath": "ssh/SshHostGroupDetailsByIDPage/route.tsx", "filePath": "ssh/SshHostGroupDetailsByIDPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout" "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": { "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-cert-manager.tsx", "filePath": "project/IdentityDetailsByIDPage/route-cert-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout" "parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout"
@ -6703,10 +6574,6 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-cert-manager.tsx", "filePath": "project/RoleDetailsBySlugPage/route-cert-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout" "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": { "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-kms.tsx", "filePath": "project/IdentityDetailsByIDPage/route-kms.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout" "parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout"
@ -6719,10 +6586,6 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-kms.tsx", "filePath": "project/RoleDetailsBySlugPage/route-kms.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout" "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": { "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-secret-manager.tsx", "filePath": "project/IdentityDetailsByIDPage/route-secret-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout" "parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout"
@ -6735,10 +6598,6 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-secret-manager.tsx", "filePath": "project/RoleDetailsBySlugPage/route-secret-manager.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout" "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": { "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-secret-scanning.tsx", "filePath": "project/IdentityDetailsByIDPage/route-secret-scanning.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout" "parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout"
@ -6751,10 +6610,6 @@ export const routeTree = rootRoute
"filePath": "project/RoleDetailsBySlugPage/route-secret-scanning.tsx", "filePath": "project/RoleDetailsBySlugPage/route-secret-scanning.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/secret-scanning/$projectId/_secret-scanning-layout" "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": { "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/identities/$identityId": {
"filePath": "project/IdentityDetailsByIDPage/route-ssh.tsx", "filePath": "project/IdentityDetailsByIDPage/route-ssh.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout" "parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout"

View File

@ -270,8 +270,7 @@ const secretManagerRoutes = route("/secret-manager/$projectId", [
route("/access-management", "project/AccessControlPage/route-secret-manager.tsx"), route("/access-management", "project/AccessControlPage/route-secret-manager.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-manager.tsx"), route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-manager.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/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")
]) ])
]); ]);
@ -315,8 +314,7 @@ const certManagerRoutes = route("/cert-manager/$projectId", [
route("/access-management", "project/AccessControlPage/route-cert-manager.tsx"), route("/access-management", "project/AccessControlPage/route-cert-manager.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-cert-manager.tsx"), route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-cert-manager.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/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")
]) ])
]); ]);
@ -328,8 +326,7 @@ const kmsRoutes = route("/kms/$projectId", [
route("/access-management", "project/AccessControlPage/route-kms.tsx"), route("/access-management", "project/AccessControlPage/route-kms.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-kms.tsx"), route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-kms.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/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")
]) ])
]); ]);
@ -344,8 +341,7 @@ const sshRoutes = route("/ssh/$projectId", [
route("/access-management", "project/AccessControlPage/route-ssh.tsx"), route("/access-management", "project/AccessControlPage/route-ssh.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-ssh.tsx"), route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-ssh.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/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")
]) ])
]); ]);
@ -360,8 +356,7 @@ const secretScanningRoutes = route("/secret-scanning/$projectId", [
route("/access-management", "project/AccessControlPage/route-secret-scanning.tsx"), route("/access-management", "project/AccessControlPage/route-secret-scanning.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-scanning.tsx"), route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-secret-scanning.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/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")
]) ])
]); ]);

View File

@ -1,3 +1,7 @@
## 0.0.3 (June 6, 2025)
* Minor fix for handling malformed URLs for HTTP forwarding
## 0.0.2 (June 6, 2025) ## 0.0.2 (June 6, 2025)
* Bumped default CLI image version from 0.41.1 -> 0.41.8. * Bumped default CLI image version from 0.41.1 -> 0.41.8.

View File

@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.0.2 version: 0.0.3
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "0.0.2" appVersion: "0.0.3"

View File

@ -1,6 +1,6 @@
image: image:
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
tag: "0.41.8" tag: "0.41.82"
secret: secret:
# The secret that contains the environment variables to be used by the gateway, such as INFISICAL_API_URL and TOKEN # The secret that contains the environment variables to be used by the gateway, such as INFISICAL_API_URL and TOKEN