1
0
mirror of https://github.com/Infisical/infisical.git synced 2025-03-29 22:02:57 +00:00

feat: added gateway page in ui for org

This commit is contained in:
=
2025-02-14 15:11:23 +05:30
parent 4bbe80c083
commit 7905017121
14 changed files with 504 additions and 4 deletions
frontend/src
context/OrgPermissionContext
hooks/api
layouts/OrganizationLayout
OrganizationLayout.tsx
components/MinimizedOrgSidebar
pages/organization
Gateways/GatewayListPage
RoleByIDPage/components
routeTree.gen.tsroutes.ts

@ -7,6 +7,14 @@ export enum OrgPermissionActions {
Delete = "delete"
}
export enum OrgGatewayPermissionActions {
// is there a better word for this. This mean can an identity be a gateway
Create = "create",
Read = "read",
Edit = "edit",
Delete = "delete"
}
export enum OrgPermissionSubjects {
Workspace = "workspace",
Role = "role",
@ -25,7 +33,8 @@ export enum OrgPermissionSubjects {
AuditLogs = "audit-logs",
ProjectTemplates = "project-templates",
AppConnections = "app-connections",
Kmip = "kmip"
Kmip = "kmip",
Gateway = "gateway"
}
export enum OrgPermissionAdminConsoleAction {
@ -68,7 +77,8 @@ export type OrgPermissionSet =
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
| [OrgPermissionAppConnectionActions, OrgPermissionSubjects.AppConnections]
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip];
| [OrgPermissionKmipActions, OrgPermissionSubjects.Kmip]
| [OrgGatewayPermissionActions, OrgPermissionSubjects.Gateway];
// TODO(scott): add back once org UI refactored
// | [
// OrgPermissionAppConnectionActions,

@ -0,0 +1,2 @@
export { useDeleteGateway } from "./mutation";
export { gatewaysQueryKeys } from "./queries";

@ -0,0 +1,15 @@
import { apiRequest } from "@app/config/request";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { gatewaysQueryKeys } from "./queries";
export const useDeleteGateway = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => {
return apiRequest.delete(`/api/v1/gateways/${id}`);
},
onSuccess: () => {
queryClient.invalidateQueries(gatewaysQueryKeys.list());
}
});
};

@ -0,0 +1,16 @@
import { apiRequest } from "@app/config/request";
import { queryOptions } from "@tanstack/react-query";
import { TGateway } from "./types";
export const gatewaysQueryKeys = {
allKey: () => ["gateways"],
listKey: () => [...gatewaysQueryKeys.allKey(), "list"],
list: () =>
queryOptions({
queryKey: gatewaysQueryKeys.listKey(),
queryFn: async () => {
const { data } = await apiRequest.get<{ gateways: TGateway[] }>("/api/v1/gateways");
return data.gateways;
}
})
};

@ -0,0 +1,17 @@
export type TGateway = {
id: string;
identityId: string;
name: string;
createdAt: string;
updatedAt: string;
issuedAt: string;
serialNumber: string;
identity: {
name: string;
id: string;
};
};
export type TDeleteGatewayDTO = {
id: string;
};

@ -10,6 +10,7 @@ export * from "./certificates";
export * from "./certificateTemplates";
export * from "./dynamicSecret";
export * from "./dynamicSecretLease";
export * from "./gateways";
export * from "./groups";
export * from "./identities";
export * from "./identityProjectAdditionalPrivilege";

@ -101,6 +101,13 @@ export const OrganizationLayout = () => {
</MenuItem>
)}
</Link>
<Link to="/organization/gateways">
{({ isActive }) => (
<MenuItem isSelected={isActive} icon="jigsaw-puzzle">
Gateways
</MenuItem>
)}
</Link>
<Link to="/organization/settings">
{({ isActive }) => (
<MenuItem isSelected={isActive} icon="toggle-settings">

@ -5,6 +5,7 @@ import {
faBook,
faCheck,
faCog,
faDoorClosed,
faEnvelope,
faInfinity,
faInfo,
@ -352,6 +353,13 @@ export const MinimizedOrgSidebar = () => {
App Connections
</DropdownMenuItem>
</Link>
<Link to="/organization/gateways">
<DropdownMenuItem
icon={<FontAwesomeIcon className="w-3" icon={faDoorClosed} />}
>
Gateways
</DropdownMenuItem>
</Link>
{(window.location.origin.includes("https://app.infisical.com") ||
window.location.origin.includes("https://eu.infisical.com") ||
window.location.origin.includes("https://gamma.infisical.com")) && (

@ -0,0 +1,132 @@
import { useState } from "react";
import { Helmet } from "react-helmet";
import {
faArrowUpRightFromSquare,
faBookOpen,
faMagnifyingGlass,
faPlug,
faSearch
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useQuery } from "@tanstack/react-query";
import { format } from "date-fns";
import {
EmptyState,
Input,
PageHeader,
Table,
TableContainer,
TableSkeleton,
TBody,
Td,
Th,
THead,
Tr
} from "@app/components/v2";
import {
OrgPermissionAppConnectionActions,
OrgPermissionSubjects
} from "@app/context/OrgPermissionContext/types";
import { withPermission } from "@app/hoc";
import { gatewaysQueryKeys } from "@app/hooks/api/gateways";
export const GatewayListPage = withPermission(
() => {
const [search, setSearch] = useState("");
const { data: gateways, isPending: isGatewayLoading } = useQuery(gatewaysQueryKeys.list());
const filteredGateway = gateways?.filter((el) =>
el.name.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="bg-bunker-800">
<Helmet>
<title>Infisical | Gateways</title>
<meta property="og:image" content="/images/message.png" />
</Helmet>
<div className="flex w-full justify-center bg-bunker-800 text-white">
<div className="w-full max-w-7xl">
<PageHeader
className="w-full"
title={
<div className="flex w-full items-center">
<span>Gateways</span>
<a
className="-mt-1.5"
href="https://infisical.com/docs/integrations/gateways/overview"
target="_blank"
rel="noopener noreferrer"
>
<div className="ml-2 inline-block rounded-md bg-yellow/20 px-1.5 text-sm font-normal text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
</div>
}
description="Create and configure connections with third-party apps for re-use across Infisical projects"
/>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div>
<div className="flex gap-2">
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search connections..."
className="flex-1"
/>
</div>
<TableContainer className="mt-4">
<Table>
<THead>
<Tr>
<Th className="w-1/3">Name</Th>
<Th>Issued At</Th>
<Th>Identity</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{isGatewayLoading && (
<TableSkeleton innerKey="gateway-table" columns={4} key="gateway-table" />
)}
{filteredGateway?.map((el) => (
<Tr key={el.id}>
<Td>{el.name}</Td>
<Td>{format(new Date(el.issuedAt), "yyyy-MM-dd")}</Td>
<Td>{el.identity.name}</Td>
<Td />
</Tr>
))}
</TBody>
</Table>
{!isGatewayLoading && !filteredGateway?.length && (
<EmptyState
title={
gateways?.length
? "No Gateways match search..."
: "No Gateways have been configured"
}
icon={gateways?.length ? faSearch : faPlug}
/>
)}
</TableContainer>
</div>
</div>
</div>
</div>
</div>
);
},
{
action: OrgPermissionAppConnectionActions.Read,
subject: OrgPermissionSubjects.AppConnections
}
);

@ -0,0 +1,23 @@
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { GatewayListPage } from "./GatewayListPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/organization/gateways/"
)({
component: GatewayListPage,
context: () => ({
breadcrumbs: [
{
label: "Home",
icon: () => <FontAwesomeIcon icon={faHome} />,
link: linkOptions({ to: "/organization/secret-manager/overview" })
},
{
label: "Gateways"
}
]
})
});

@ -3,6 +3,7 @@ import { z } from "zod";
import { OrgPermissionSubjects } from "@app/context";
import {
OrgGatewayPermissionActions,
OrgPermissionAppConnectionActions,
OrgPermissionKmipActions
} from "@app/context/OrgPermissionContext/types";
@ -34,6 +35,15 @@ const kmipPermissionSchema = z
})
.optional();
const orgGatewayPermissionSchema = z
.object({
[OrgGatewayPermissionActions.Read]: z.boolean().optional(),
[OrgGatewayPermissionActions.Edit]: z.boolean().optional(),
[OrgGatewayPermissionActions.Delete]: z.boolean().optional(),
[OrgGatewayPermissionActions.Create]: z.boolean().optional()
})
.optional();
const adminConsolePermissionSchmea = z
.object({
"access-all-projects": z.boolean().optional()
@ -72,7 +82,8 @@ export const formSchema = z.object({
[OrgPermissionSubjects.Kms]: generalPermissionSchema,
[OrgPermissionSubjects.ProjectTemplates]: generalPermissionSchema,
"app-connections": appConnectionsPermissionSchema,
kmip: kmipPermissionSchema
kmip: kmipPermissionSchema,
[OrgPermissionSubjects.Gateway]: orgGatewayPermissionSchema
})
.optional()
});

@ -0,0 +1,182 @@
import { useEffect, useMemo } from "react";
import { Control, Controller, UseFormSetValue, useWatch } from "react-hook-form";
import { faChevronDown, faChevronRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createNotification } from "@app/components/notifications";
import { Checkbox, Select, SelectItem, Td, Tr } from "@app/components/v2";
import { OrgGatewayPermissionActions } from "@app/context/OrgPermissionContext/types";
import { useToggle } from "@app/hooks";
import { TFormSchema } from "../OrgRoleModifySection.utils";
type Props = {
isEditable: boolean;
setValue: UseFormSetValue<TFormSchema>;
control: Control<TFormSchema>;
};
enum Permission {
NoAccess = "no-access",
ReadOnly = "read-only",
FullAccess = "full-access",
Custom = "custom"
}
const PERMISSION_ACTIONS = [
{ action: OrgGatewayPermissionActions.Read, label: "Read" },
{ action: OrgGatewayPermissionActions.Create, label: "Create" },
{ action: OrgGatewayPermissionActions.Edit, label: "Modify" },
{ action: OrgGatewayPermissionActions.Delete, label: "Remove" }
] as const;
export const OrgGatewayPermissionRow = ({ isEditable, control, setValue }: Props) => {
const [isRowExpanded, setIsRowExpanded] = useToggle();
const [isCustom, setIsCustom] = useToggle();
const rule = useWatch({
control,
name: "permissions.gateway"
});
const selectedPermissionCategory = useMemo(() => {
const actions = Object.keys(rule || {}) as Array<keyof typeof rule>;
const totalActions = PERMISSION_ACTIONS.length;
const score = actions.map((key) => (rule?.[key] ? 1 : 0)).reduce((a, b) => a + b, 0 as number);
if (isCustom) return Permission.Custom;
if (score === 0) return Permission.NoAccess;
if (score === totalActions) return Permission.FullAccess;
if (score === 1 && rule?.[OrgGatewayPermissionActions.Read]) return Permission.ReadOnly;
return Permission.Custom;
}, [rule, isCustom]);
useEffect(() => {
if (selectedPermissionCategory === Permission.Custom) setIsCustom.on();
else setIsCustom.off();
}, [selectedPermissionCategory]);
useEffect(() => {
const isRowCustom = selectedPermissionCategory === Permission.Custom;
if (isRowCustom) {
setIsRowExpanded.on();
}
}, []);
const handlePermissionChange = (val: Permission) => {
if (!val) return;
if (val === Permission.Custom) {
setIsRowExpanded.on();
setIsCustom.on();
return;
}
setIsCustom.off();
switch (val) {
case Permission.FullAccess:
setValue(
"permissions.app-connections",
{
[OrgGatewayPermissionActions.Read]: true,
[OrgGatewayPermissionActions.Edit]: true,
[OrgGatewayPermissionActions.Create]: true,
[OrgGatewayPermissionActions.Delete]: true
},
{ shouldDirty: true }
);
break;
case Permission.ReadOnly:
setValue(
"permissions.app-connections",
{
[OrgGatewayPermissionActions.Read]: true,
[OrgGatewayPermissionActions.Edit]: false,
[OrgGatewayPermissionActions.Create]: false,
[OrgGatewayPermissionActions.Delete]: false
},
{ shouldDirty: true }
);
break;
case Permission.NoAccess:
default:
setValue(
"permissions.app-connections",
{
[OrgGatewayPermissionActions.Read]: false,
[OrgGatewayPermissionActions.Edit]: false,
[OrgGatewayPermissionActions.Create]: false,
[OrgGatewayPermissionActions.Delete]: false
},
{ shouldDirty: true }
);
}
};
return (
<>
<Tr
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
onClick={() => setIsRowExpanded.toggle()}
>
<Td>
<FontAwesomeIcon icon={isRowExpanded ? faChevronDown : faChevronRight} />
</Td>
<Td>Gateways</Td>
<Td>
<Select
value={selectedPermissionCategory}
className="w-40 bg-mineshaft-600"
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
onValueChange={handlePermissionChange}
isDisabled={!isEditable}
>
<SelectItem value={Permission.NoAccess}>No Access</SelectItem>
<SelectItem value={Permission.ReadOnly}>Read Only</SelectItem>
<SelectItem value={Permission.FullAccess}>Full Access</SelectItem>
<SelectItem value={Permission.Custom}>Custom</SelectItem>
</Select>
</Td>
</Tr>
{isRowExpanded && (
<Tr>
<Td
colSpan={3}
className={`bg-bunker-600 px-0 py-0 ${isRowExpanded && "border-mineshaft-500 p-8"}`}
>
<div className="grid grid-cols-3 gap-4">
{PERMISSION_ACTIONS.map(({ action, label }) => {
return (
<Controller
name={`permissions.gateway.${action}`}
key={`permissions.gateway.${action}`}
control={control}
render={({ field }) => (
<Checkbox
isChecked={Boolean(field.value)}
onCheckedChange={(e) => {
if (!isEditable) {
createNotification({
type: "error",
text: "Failed to update default role"
});
return;
}
field.onChange(e);
}}
id={`permissions.gateways.${action}`}
>
{label}
</Checkbox>
)}
/>
);
})}
</div>
</Td>
</Tr>
)}
</>
);
};

@ -60,6 +60,7 @@ import { Route as organizationKmsOverviewPageRouteImport } from './pages/organiz
import { Route as organizationIdentityDetailsByIDPageRouteImport } from './pages/organization/IdentityDetailsByIDPage/route'
import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route'
import { Route as organizationCertManagerOverviewPageRouteImport } from './pages/organization/CertManagerOverviewPage/route'
import { Route as organizationGatewaysGatewayListPageRouteImport } from './pages/organization/Gateways/GatewayListPage/route'
import { Route as organizationAppConnectionsAppConnectionsPageRouteImport } from './pages/organization/AppConnections/AppConnectionsPage/route'
import { Route as projectAccessControlPageRouteSshImport } from './pages/project/AccessControlPage/route-ssh'
import { Route as projectAccessControlPageRouteSecretManagerImport } from './pages/project/AccessControlPage/route-secret-manager'
@ -209,6 +210,10 @@ const AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdImport =
createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId',
)()
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport =
createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/organization/gateways',
)()
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport =
createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections',
@ -454,6 +459,14 @@ const AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRoute =
getParentRoute: () => organizationLayoutRoute,
} as any)
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute =
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport.update({
id: '/gateways',
path: '/gateways',
getParentRoute: () =>
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
} as any)
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute =
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport.update({
id: '/app-connections',
@ -625,6 +638,14 @@ const organizationCertManagerOverviewPageRouteRoute =
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
} as any)
const organizationGatewaysGatewayListPageRouteRoute =
organizationGatewaysGatewayListPageRouteImport.update({
id: '/',
path: '/',
getParentRoute: () =>
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute,
} as any)
const organizationAppConnectionsAppConnectionsPageRouteRoute =
organizationAppConnectionsAppConnectionsPageRouteImport.update({
id: '/',
@ -1886,6 +1907,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
}
'/_authenticate/_inject-org-details/_org-layout/organization/gateways': {
id: '/_authenticate/_inject-org-details/_org-layout/organization/gateways'
path: '/gateways'
fullPath: '/organization/gateways'
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
}
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId': {
id: '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId'
path: '/secret-manager/$projectId'
@ -1907,6 +1935,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof organizationAppConnectionsAppConnectionsPageRouteImport
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport
}
'/_authenticate/_inject-org-details/_org-layout/organization/gateways/': {
id: '/_authenticate/_inject-org-details/_org-layout/organization/gateways/'
path: '/'
fullPath: '/organization/gateways/'
preLoaderRoute: typeof organizationGatewaysGatewayListPageRouteImport
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysImport
}
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview': {
id: '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview'
path: '/cert-manager/overview'
@ -2900,6 +2935,21 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithCh
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteChildren,
)
interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren {
organizationGatewaysGatewayListPageRouteRoute: typeof organizationGatewaysGatewayListPageRouteRoute
}
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren =
{
organizationGatewaysGatewayListPageRouteRoute:
organizationGatewaysGatewayListPageRouteRoute,
}
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren =
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute._addFileChildren(
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteChildren,
)
interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren {
organizationAccessManagementPageRouteRoute: typeof organizationAccessManagementPageRouteRoute
organizationAdminPageRouteRoute: typeof organizationAdminPageRouteRoute
@ -2909,6 +2959,7 @@ interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren {
organizationSecretSharingPageRouteRoute: typeof organizationSecretSharingPageRouteRoute
organizationSettingsPageRouteRoute: typeof organizationSettingsPageRouteRoute
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
organizationCertManagerOverviewPageRouteRoute: typeof organizationCertManagerOverviewPageRouteRoute
organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute
organizationIdentityDetailsByIDPageRouteRoute: typeof organizationIdentityDetailsByIDPageRouteRoute
@ -2933,6 +2984,8 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: Authentica
organizationSettingsPageRouteRoute: organizationSettingsPageRouteRoute,
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute:
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren,
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute:
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren,
organizationCertManagerOverviewPageRouteRoute:
organizationCertManagerOverviewPageRouteRoute,
organizationGroupDetailsByIDPageRouteRoute:
@ -3608,9 +3661,11 @@ export interface FileRoutesByFullPath {
'/cert-manager/$projectId': typeof certManagerLayoutRouteWithChildren
'/kms/$projectId': typeof kmsLayoutRouteWithChildren
'/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
'/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
'/secret-manager/$projectId': typeof secretManagerLayoutRouteWithChildren
'/ssh/$projectId': typeof sshLayoutRouteWithChildren
'/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
'/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
@ -3780,6 +3835,7 @@ export interface FileRoutesByTo {
'/secret-manager/$projectId': typeof secretManagerLayoutRouteWithChildren
'/ssh/$projectId': typeof sshLayoutRouteWithChildren
'/organization/app-connections': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
'/organization/gateways': typeof organizationGatewaysGatewayListPageRouteRoute
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
@ -3956,9 +4012,11 @@ export interface FileRoutesById {
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutKmsProjectIdRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/organization/gateways': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSshProjectIdRouteWithChildren
'/_authenticate/_inject-org-details/_org-layout/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organization/gateways/': typeof organizationGatewaysGatewayListPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
@ -4136,9 +4194,11 @@ export interface FileRouteTypes {
| '/cert-manager/$projectId'
| '/kms/$projectId'
| '/organization/app-connections'
| '/organization/gateways'
| '/secret-manager/$projectId'
| '/ssh/$projectId'
| '/organization/app-connections/'
| '/organization/gateways/'
| '/organization/cert-manager/overview'
| '/organization/groups/$groupId'
| '/organization/identities/$identityId'
@ -4307,6 +4367,7 @@ export interface FileRouteTypes {
| '/secret-manager/$projectId'
| '/ssh/$projectId'
| '/organization/app-connections'
| '/organization/gateways'
| '/organization/cert-manager/overview'
| '/organization/groups/$groupId'
| '/organization/identities/$identityId'
@ -4481,9 +4542,11 @@ export interface FileRouteTypes {
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId'
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId'
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections'
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways'
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId'
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId'
| '/_authenticate/_inject-org-details/_org-layout/organization/app-connections/'
| '/_authenticate/_inject-org-details/_org-layout/organization/gateways/'
| '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview'
| '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
| '/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId'
@ -4848,6 +4911,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
"/_authenticate/_inject-org-details/_org-layout/organization/settings",
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections",
"/_authenticate/_inject-org-details/_org-layout/organization/gateways",
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview",
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId",
@ -4919,6 +4983,13 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections/$appConnection/oauth/callback"
]
},
"/_authenticate/_inject-org-details/_org-layout/organization/gateways": {
"filePath": "",
"parent": "/_authenticate/_inject-org-details/_org-layout/organization",
"children": [
"/_authenticate/_inject-org-details/_org-layout/organization/gateways/"
]
},
"/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId": {
"filePath": "",
"parent": "/_authenticate/_inject-org-details/_org-layout",
@ -4937,6 +5008,10 @@ export const routeTree = rootRoute
"filePath": "organization/AppConnections/AppConnectionsPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/app-connections"
},
"/_authenticate/_inject-org-details/_org-layout/organization/gateways/": {
"filePath": "organization/Gateways/GatewayListPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/gateways"
},
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview": {
"filePath": "organization/CertManagerOverviewPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"

@ -29,7 +29,8 @@ const organizationRoutes = route("/organization", [
"/$appConnection/oauth/callback",
"organization/AppConnections/OauthCallbackPage/route.tsx"
)
])
]),
route("/gateways", [index("organization/Gateways/GatewayListPage/route.tsx")])
]);
const secretManagerRoutes = route("/secret-manager/$projectId", [