mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
fix: refactored admin panel layout
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { FileRouteTypes } from "@app/routeTree.gen";
|
||||
|
||||
//
|
||||
|
||||
const setRoute = <TFull extends FileRouteTypes["fullPaths"], TId extends FileRouteTypes["id"]>(
|
||||
path: TFull,
|
||||
id: TId
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faArrowLeft, faInfo, faMobile, faQuestion } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faMobile } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Link, Outlet } from "@tanstack/react-router";
|
||||
import { Outlet, useRouterState } from "@tanstack/react-router";
|
||||
|
||||
import { WishForm } from "@app/components/features/WishForm";
|
||||
import { Banner } from "@app/components/page-frames/Banner";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from "@app/components/v2";
|
||||
import { envConfig } from "@app/config/env";
|
||||
import { BreadcrumbContainer, TBreadcrumbFormat } from "@app/components/v2";
|
||||
import { useServerConfig } from "@app/context";
|
||||
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||
|
||||
import { InsecureConnectionBanner } from "../OrganizationLayout/components/InsecureConnectionBanner";
|
||||
import { INFISICAL_SUPPORT_OPTIONS } from "../OrganizationLayout/components/MinimizedOrgSidebar/MinimizedOrgSidebar";
|
||||
import { AdminSidebar } from "./Sidebar";
|
||||
|
||||
export const AdminLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
const { config } = useServerConfig();
|
||||
|
||||
const matches = useRouterState({ select: (s) => s.matches.at(-1)?.context });
|
||||
|
||||
const breadcrumbs = matches && "breadcrumbs" in matches ? matches.breadcrumbs : undefined;
|
||||
|
||||
const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen";
|
||||
|
||||
return (
|
||||
@@ -30,54 +26,11 @@ export const AdminLayout = () => {
|
||||
<div className={`dark hidden ${containerHeight} w-full flex-col overflow-x-hidden md:flex`}>
|
||||
{!window.isSecureContext && <InsecureConnectionBanner />}
|
||||
<div className="flex flex-grow flex-col overflow-y-hidden md:flex-row">
|
||||
<aside className="dark w-full border-r border-mineshaft-600 bg-gradient-to-tr from-mineshaft-700 via-mineshaft-800 to-mineshaft-900 md:w-60">
|
||||
<nav className="items-between flex h-full flex-col justify-between overflow-y-auto dark:[color-scheme:dark]">
|
||||
<div className="flex-grow">
|
||||
<Link to={`/organization/${ProjectType.SecretManager}/overview` as const}>
|
||||
<div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100">
|
||||
<FontAwesomeIcon icon={faArrowLeft} className="pr-3" />
|
||||
Back to organization
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="relative mt-10 flex w-full cursor-default flex-col items-center px-3 text-sm text-mineshaft-400">
|
||||
{(window.location.origin.includes("https://app.infisical.com") ||
|
||||
window.location.origin.includes("https://gamma.infisical.com")) && <WishForm />}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="mb-2 w-full pl-5 duration-200 hover:text-mineshaft-200">
|
||||
<FontAwesomeIcon icon={faQuestion} className="mr-3 px-[0.1rem]" />
|
||||
Help & Support
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="p-1">
|
||||
{INFISICAL_SUPPORT_OPTIONS.map(([icon, text, url]) => (
|
||||
<DropdownMenuItem key={url as string}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={String(url)}
|
||||
className="flex w-full items-center rounded-md font-normal text-mineshaft-300 duration-200"
|
||||
>
|
||||
<div className="relative flex w-full cursor-pointer select-none items-center justify-start rounded-md">
|
||||
{icon}
|
||||
<div className="text-sm">{text}</div>
|
||||
</div>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{envConfig.PLATFORM_VERSION && (
|
||||
<div className="mb-2 mt-2 w-full cursor-default pl-5 text-sm duration-200 hover:text-mineshaft-200">
|
||||
<FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" />
|
||||
Version: {envConfig.PLATFORM_VERSION}
|
||||
</div>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
<main className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 dark:[color-scheme:dark]">
|
||||
<AdminSidebar />
|
||||
<main className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800 px-4 pb-4 dark:[color-scheme:dark]">
|
||||
{breadcrumbs ? (
|
||||
<BreadcrumbContainer breadcrumbs={breadcrumbs as TBreadcrumbFormat[]} />
|
||||
) : null}
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
144
frontend/src/layouts/AdminLayout/Sidebar.tsx
Normal file
144
frontend/src/layouts/AdminLayout/Sidebar.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import { faArrowLeft, faInfo, faQuestion } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Link, useMatchRoute } from "@tanstack/react-router";
|
||||
|
||||
import { WishForm } from "@app/components/features/WishForm";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
Menu,
|
||||
MenuGroup,
|
||||
MenuItem
|
||||
} from "@app/components/v2";
|
||||
import { envConfig } from "@app/config/env";
|
||||
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||
|
||||
import { INFISICAL_SUPPORT_OPTIONS } from "../OrganizationLayout/components/MinimizedOrgSidebar/MinimizedOrgSidebar";
|
||||
|
||||
const generalTabs = [
|
||||
{
|
||||
label: "General",
|
||||
icon: "settings-cog",
|
||||
link: "/admin/"
|
||||
},
|
||||
{
|
||||
label: "Encryption",
|
||||
icon: "lock-closed",
|
||||
link: "/admin/encryption"
|
||||
},
|
||||
{
|
||||
label: "Authentication",
|
||||
icon: "check",
|
||||
link: "/admin/authentication"
|
||||
},
|
||||
{
|
||||
label: "Integrations",
|
||||
icon: "sliding-carousel",
|
||||
link: "/admin/integrations"
|
||||
},
|
||||
{
|
||||
label: "Caching",
|
||||
icon: "note",
|
||||
link: "/admin/caching"
|
||||
}
|
||||
];
|
||||
|
||||
const resourceTabs = [
|
||||
{
|
||||
label: "Organizations",
|
||||
icon: "groups",
|
||||
link: "/admin/resources/organizations"
|
||||
},
|
||||
{
|
||||
label: "User Identities",
|
||||
icon: "user",
|
||||
link: "/admin/resources/user-identities"
|
||||
},
|
||||
{
|
||||
label: "Machine Identities",
|
||||
icon: "key-user",
|
||||
link: "/admin/resources/machine-identities"
|
||||
}
|
||||
];
|
||||
|
||||
export const AdminSidebar = () => {
|
||||
const matchRoute = useMatchRoute();
|
||||
|
||||
return (
|
||||
<aside className="dark w-full border-r border-mineshaft-600 bg-gradient-to-tr from-mineshaft-700 via-mineshaft-800 to-mineshaft-900 md:w-60">
|
||||
<nav className="items-between flex h-full flex-col justify-between overflow-y-auto dark:[color-scheme:dark]">
|
||||
<div className="flex-grow">
|
||||
<Link to={`/organization/${ProjectType.SecretManager}/overview` as const}>
|
||||
<div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100">
|
||||
<FontAwesomeIcon icon={faArrowLeft} className="pr-3" />
|
||||
Back to organization
|
||||
</div>
|
||||
</Link>
|
||||
<Menu>
|
||||
<MenuGroup title="General">
|
||||
{generalTabs.map((tab) => {
|
||||
const isActive = matchRoute({ to: tab.link, fuzzy: false });
|
||||
return (
|
||||
<Link key={tab.link} to={tab.link}>
|
||||
<MenuItem isSelected={Boolean(isActive)} icon={tab.icon}>
|
||||
{tab.label}
|
||||
</MenuItem>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</MenuGroup>
|
||||
<MenuGroup title="Resources">
|
||||
{resourceTabs.map((tab) => {
|
||||
const isActive = matchRoute({ to: tab.link, fuzzy: false });
|
||||
return (
|
||||
<Link key={tab.link} to={tab.link}>
|
||||
<MenuItem isSelected={Boolean(isActive)} icon={tab.icon}>
|
||||
{tab.label}
|
||||
</MenuItem>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</MenuGroup>
|
||||
</Menu>
|
||||
</div>
|
||||
<div className="relative mt-10 flex w-full cursor-default flex-col items-center px-3 text-sm text-mineshaft-400">
|
||||
{(window.location.origin.includes("https://app.infisical.com") ||
|
||||
window.location.origin.includes("https://gamma.infisical.com")) && <WishForm />}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="mb-2 w-full pl-5 duration-200 hover:text-mineshaft-200">
|
||||
<FontAwesomeIcon icon={faQuestion} className="mr-3 px-[0.1rem]" />
|
||||
Help & Support
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="p-1">
|
||||
{INFISICAL_SUPPORT_OPTIONS.map(([icon, text, url]) => (
|
||||
<DropdownMenuItem key={url as string}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={String(url)}
|
||||
className="flex w-full items-center rounded-md font-normal text-mineshaft-300 duration-200"
|
||||
>
|
||||
<div className="relative flex w-full cursor-pointer select-none items-center justify-start rounded-md">
|
||||
{icon}
|
||||
<div className="text-sm">{text}</div>
|
||||
</div>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{envConfig.PLATFORM_VERSION && (
|
||||
<div className="mb-2 mt-2 w-full cursor-default pl-5 text-sm duration-200 hover:text-mineshaft-200">
|
||||
<FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" />
|
||||
Version: {envConfig.PLATFORM_VERSION}
|
||||
</div>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { AuthenticationPageForm } from "./components";
|
||||
|
||||
export const AuthenticationPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Authentication"
|
||||
description="Manage authentication settings for your Infisical instance."
|
||||
/>
|
||||
<AuthenticationPageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -20,7 +20,7 @@ const formSchema = z.object({
|
||||
|
||||
type TAuthForm = z.infer<typeof formSchema>;
|
||||
|
||||
export const AuthPanel = () => {
|
||||
export const AuthenticationPageForm = () => {
|
||||
const { config } = useServerConfig();
|
||||
const { enabledLoginMethods } = config;
|
||||
const { mutateAsync: updateServerConfig } = useUpdateServerConfig();
|
||||
@@ -0,0 +1 @@
|
||||
export { AuthenticationPageForm } from "./AuthenticationPageForm";
|
||||
25
frontend/src/pages/admin/AuthenticationPage/route.tsx
Normal file
25
frontend/src/pages/admin/AuthenticationPage/route.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { AuthenticationPage } from "./AuthenticationPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/authentication"
|
||||
)({
|
||||
component: AuthenticationPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Authentication",
|
||||
link: linkOptions({
|
||||
to: "/admin/authentication"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
27
frontend/src/pages/admin/CachingPage/CachingPage.tsx
Normal file
27
frontend/src/pages/admin/CachingPage/CachingPage.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { CachingPageForm } from "./components";
|
||||
|
||||
export const CachingPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Caching"
|
||||
description="Manage caching settings for your Infisical instance."
|
||||
/>
|
||||
<CachingPageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -10,7 +10,7 @@ import { useInvalidateCache } from "@app/hooks/api";
|
||||
import { useGetInvalidatingCacheStatus } from "@app/hooks/api/admin/queries";
|
||||
import { CacheType } from "@app/hooks/api/admin/types";
|
||||
|
||||
export const CachingPanel = () => {
|
||||
export const CachingPageForm = () => {
|
||||
const { mutateAsync: invalidateCache } = useInvalidateCache();
|
||||
const { user } = useUser();
|
||||
|
||||
1
frontend/src/pages/admin/CachingPage/components/index.ts
Normal file
1
frontend/src/pages/admin/CachingPage/components/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { CachingPageForm } from "./CachingPageForm";
|
||||
25
frontend/src/pages/admin/CachingPage/route.tsx
Normal file
25
frontend/src/pages/admin/CachingPage/route.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { CachingPage } from "./CachingPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/caching"
|
||||
)({
|
||||
component: CachingPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Caching",
|
||||
link: linkOptions({
|
||||
to: "/admin/caching"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
27
frontend/src/pages/admin/EncryptionPage/EncryptionPage.tsx
Normal file
27
frontend/src/pages/admin/EncryptionPage/EncryptionPage.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { EncryptionPageForm } from "./components";
|
||||
|
||||
export const EncryptionPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Encryption"
|
||||
description="Manage encryption settings for your Infisical instance."
|
||||
/>
|
||||
<EncryptionPageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -8,11 +8,11 @@ import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FormControl, Select, SelectItem } from "@app/components/v2";
|
||||
import { useSubscription } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useUpdateServerEncryptionStrategy } from "@app/hooks/api";
|
||||
import {
|
||||
RootKeyEncryptionStrategy,
|
||||
TGetServerRootKmsEncryptionDetails
|
||||
} from "@app/hooks/api/admin/types";
|
||||
useGetServerRootKmsEncryptionDetails,
|
||||
useUpdateServerEncryptionStrategy
|
||||
} from "@app/hooks/api";
|
||||
import { RootKeyEncryptionStrategy } from "@app/hooks/api/admin/types";
|
||||
|
||||
const formSchema = z.object({
|
||||
encryptionStrategy: z.nativeEnum(RootKeyEncryptionStrategy)
|
||||
@@ -25,11 +25,9 @@ const strategies: Record<RootKeyEncryptionStrategy, string> = {
|
||||
|
||||
type TForm = z.infer<typeof formSchema>;
|
||||
|
||||
type Props = {
|
||||
rootKmsDetails?: TGetServerRootKmsEncryptionDetails;
|
||||
};
|
||||
export const EncryptionPageForm = () => {
|
||||
const { data: rootKmsDetails } = useGetServerRootKmsEncryptionDetails();
|
||||
|
||||
export const EncryptionPanel = ({ rootKmsDetails }: Props) => {
|
||||
const { mutateAsync: updateEncryptionStrategy } = useUpdateServerEncryptionStrategy();
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { EncryptionPageForm } from "./EncryptionPageForm";
|
||||
25
frontend/src/pages/admin/EncryptionPage/route.tsx
Normal file
25
frontend/src/pages/admin/EncryptionPage/route.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { EncryptionPage } from "./EncryptionPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/encryption"
|
||||
)({
|
||||
component: EncryptionPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Encryption",
|
||||
link: linkOptions({
|
||||
to: "/admin/encryption"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
27
frontend/src/pages/admin/GeneralPage/GeneralPage.tsx
Normal file
27
frontend/src/pages/admin/GeneralPage/GeneralPage.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { GeneralPageForm } from "./components";
|
||||
|
||||
export const GeneralPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="General"
|
||||
description="Manage general settings for your Infisical instance."
|
||||
/>
|
||||
<GeneralPageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,309 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { faAt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectClear,
|
||||
SelectItem,
|
||||
Switch,
|
||||
TextArea
|
||||
} from "@app/components/v2";
|
||||
import { useServerConfig } from "@app/context";
|
||||
import { useGetOrganizations, useUpdateServerConfig } from "@app/hooks/api";
|
||||
|
||||
enum SignUpModes {
|
||||
Disabled = "disabled",
|
||||
Anyone = "anyone"
|
||||
}
|
||||
|
||||
const formSchema = z.object({
|
||||
signUpMode: z.nativeEnum(SignUpModes),
|
||||
allowedSignUpDomain: z.string().optional().nullable(),
|
||||
trustSamlEmails: z.boolean(),
|
||||
trustLdapEmails: z.boolean(),
|
||||
trustOidcEmails: z.boolean(),
|
||||
defaultAuthOrgId: z.string(),
|
||||
authConsentContent: z.string().optional().default(""),
|
||||
pageFrameContent: z.string().optional().default("")
|
||||
});
|
||||
|
||||
type TDashboardForm = z.infer<typeof formSchema>;
|
||||
|
||||
export const GeneralPageForm = () => {
|
||||
const data = useServerConfig();
|
||||
const { config } = data;
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
formState: { isSubmitting, isDirty }
|
||||
} = useForm<TDashboardForm>({
|
||||
resolver: zodResolver(formSchema),
|
||||
values: {
|
||||
// eslint-disable-next-line
|
||||
signUpMode: config.allowSignUp ? SignUpModes.Anyone : SignUpModes.Disabled,
|
||||
allowedSignUpDomain: config.allowedSignUpDomain,
|
||||
trustSamlEmails: config.trustSamlEmails,
|
||||
trustLdapEmails: config.trustLdapEmails,
|
||||
trustOidcEmails: config.trustOidcEmails,
|
||||
defaultAuthOrgId: config.defaultAuthOrgId ?? "",
|
||||
authConsentContent: config.authConsentContent ?? "",
|
||||
pageFrameContent: config.pageFrameContent ?? ""
|
||||
}
|
||||
});
|
||||
|
||||
const signUpMode = watch("signUpMode");
|
||||
const defaultAuthOrgId = watch("defaultAuthOrgId");
|
||||
|
||||
const { mutateAsync: updateServerConfig } = useUpdateServerConfig();
|
||||
|
||||
const organizations = useGetOrganizations();
|
||||
|
||||
const onFormSubmit = async (formData: TDashboardForm) => {
|
||||
try {
|
||||
const {
|
||||
allowedSignUpDomain,
|
||||
trustSamlEmails,
|
||||
trustLdapEmails,
|
||||
trustOidcEmails,
|
||||
authConsentContent,
|
||||
pageFrameContent
|
||||
} = formData;
|
||||
|
||||
await updateServerConfig({
|
||||
defaultAuthOrgId: defaultAuthOrgId || null,
|
||||
allowSignUp: signUpMode !== SignUpModes.Disabled,
|
||||
allowedSignUpDomain: signUpMode === SignUpModes.Anyone ? allowedSignUpDomain : null,
|
||||
trustSamlEmails,
|
||||
trustLdapEmails,
|
||||
trustOidcEmails,
|
||||
authConsentContent,
|
||||
pageFrameContent
|
||||
});
|
||||
createNotification({
|
||||
text: "Successfully changed sign up setting.",
|
||||
type: "success"
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Failed to update sign up setting."
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
className="space-y-8 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">Allow user signups</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select if you want users to be able to signup freely into your Infisical instance.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="signUpMode"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl className="max-w-sm" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Select
|
||||
className="w-full bg-mineshaft-700"
|
||||
dropdownContainerClassName="bg-mineshaft-800"
|
||||
defaultValue={field.value}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
{...field}
|
||||
>
|
||||
<SelectItem value={SignUpModes.Disabled}>Disabled</SelectItem>
|
||||
<SelectItem value={SignUpModes.Anyone}>Anyone</SelectItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{signUpMode === "anyone" && (
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-4 text-xl font-semibold text-mineshaft-100">
|
||||
Restrict signup by email domain(s)
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="allowedSignUpDomain"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Leave blank to allow any email domains"
|
||||
className="w-72"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
placeholder="gmail.com, aws.com, redhat.com"
|
||||
leftIcon={<FontAwesomeIcon icon={faAt} />}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">Default organization</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select the default organization you want to set for SAML/LDAP/OIDC/Github logins. When
|
||||
selected, user logins will be automatically scoped to the selected organization.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="defaultAuthOrgId"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl className="max-w-sm" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Select
|
||||
placeholder="Allow all organizations"
|
||||
className="w-full bg-mineshaft-700"
|
||||
dropdownContainerClassName="bg-mineshaft-800"
|
||||
defaultValue={field.value ?? " "}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
{...field}
|
||||
>
|
||||
<SelectClear
|
||||
selectValue={defaultAuthOrgId}
|
||||
onClear={() => {
|
||||
onChange("");
|
||||
}}
|
||||
>
|
||||
Allow all organizations
|
||||
</SelectClear>
|
||||
{organizations.data?.map((org) => (
|
||||
<SelectItem key={org.id} value={org.id}>
|
||||
{org.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">Trust emails</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select if you want Infisical to trust external emails from SAML/LDAP/OIDC identity
|
||||
providers. If set to false, then Infisical will prompt SAML/LDAP/OIDC provisioned users to
|
||||
verify their email upon their first login.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustSamlEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-saml-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust SAML emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustLdapEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-ldap-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust LDAP emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustOidcEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-oidc-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust OIDC emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">Notices</div>
|
||||
<div className="mb-4 max-w-lg text-sm text-mineshaft-400">
|
||||
Configure system-wide notification banners and security messages. These settings control
|
||||
the text displayed to users during authentication and throughout their session
|
||||
</div>
|
||||
<Controller
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Auth Consent Content"
|
||||
tooltipText="Formatting supported: HTML, Markdown, Plain text"
|
||||
>
|
||||
<TextArea
|
||||
placeholder="**Auth Consent Message**"
|
||||
{...field}
|
||||
rows={3}
|
||||
className="thin-scrollbar h-48 max-w-lg !resize-none bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="authConsentContent"
|
||||
/>
|
||||
<Controller
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Page Frame Content"
|
||||
tooltipText="Formatting supported: HTML, Markdown, Plain text"
|
||||
>
|
||||
<TextArea
|
||||
placeholder='<div style="background-color: red">TOP SECRET</div>'
|
||||
{...field}
|
||||
rows={3}
|
||||
className="thin-scrollbar h-48 max-w-lg !resize-none bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="pageFrameContent"
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" isLoading={isSubmitting} isDisabled={isSubmitting || !isDirty}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
1
frontend/src/pages/admin/GeneralPage/components/index.ts
Normal file
1
frontend/src/pages/admin/GeneralPage/components/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { GeneralPageForm } from "./GeneralPageForm";
|
||||
23
frontend/src/pages/admin/GeneralPage/route.tsx
Normal file
23
frontend/src/pages/admin/GeneralPage/route.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { GeneralPage } from "./GeneralPage";
|
||||
|
||||
export const Route = createFileRoute("/_authenticate/_inject-org-details/admin/_admin-layout/")({
|
||||
component: GeneralPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "General",
|
||||
link: linkOptions({
|
||||
to: "/admin"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { IntegrationsPageForm } from "./components";
|
||||
|
||||
export const IntegrationsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Integrations"
|
||||
description="Manage integrations for your Infisical instance."
|
||||
/>
|
||||
<IntegrationsPageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import { useGetAdminIntegrationsConfig } from "@app/hooks/api";
|
||||
import { MicrosoftTeamsIntegrationForm } from "./MicrosoftTeamsIntegrationForm";
|
||||
import { SlackIntegrationForm } from "./SlackIntegrationForm";
|
||||
|
||||
export const IntegrationPanel = () => {
|
||||
export const IntegrationsPageForm = () => {
|
||||
const { data: adminIntegrationsConfig } = useGetAdminIntegrationsConfig();
|
||||
|
||||
return (
|
||||
@@ -0,0 +1 @@
|
||||
export { IntegrationsPageForm } from "./IntegrationsPageForm";
|
||||
25
frontend/src/pages/admin/IntegrationsPage/route.tsx
Normal file
25
frontend/src/pages/admin/IntegrationsPage/route.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { IntegrationsPage } from "./IntegrationsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/integrations"
|
||||
)({
|
||||
component: IntegrationsPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Integrations",
|
||||
link: linkOptions({
|
||||
to: "/admin/integrations"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { MachineIdentitiesTable } from "./components";
|
||||
|
||||
export const MachineIdentitiesResourcesPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Machine Identities"
|
||||
description="Manage all machine identities within your Infisical instance."
|
||||
/>
|
||||
<MachineIdentitiesTable />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -133,7 +133,7 @@ const IdentityPanelTable = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const IdentityPanel = () => {
|
||||
export const MachineIdentitiesTable = () => {
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
"removeServerAdmin"
|
||||
] as const);
|
||||
@@ -161,9 +161,6 @@ export const IdentityPanel = () => {
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Identities</p>
|
||||
</div>
|
||||
<IdentityPanelTable handlePopUpOpen={handlePopUpOpen} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.removeServerAdmin.isOpen}
|
||||
@@ -0,0 +1 @@
|
||||
export { MachineIdentitiesTable } from "./MachineIdentitiesTable";
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { MachineIdentitiesResourcesPage } from "./MachineIdentitiesResourcesPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities"
|
||||
)({
|
||||
component: MachineIdentitiesResourcesPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Machine Identities",
|
||||
link: linkOptions({
|
||||
to: "/admin/resources/machine-identities"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { OrganizationsTable } from "./components";
|
||||
|
||||
export const OrganizationResourcesPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Organizations"
|
||||
description="Manage all organizations within your Infisical instance."
|
||||
/>
|
||||
<OrganizationsTable />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -294,7 +294,7 @@ const OrganizationsPanelTable = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const OrganizationsPanel = () => {
|
||||
export const OrganizationsTable = () => {
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
"deleteOrganization",
|
||||
"deleteOrganizationMembership",
|
||||
@@ -357,9 +357,6 @@ export const OrganizationsPanel = () => {
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Organizations</p>
|
||||
</div>
|
||||
<OrganizationsPanelTable
|
||||
popUp={popUp}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
@@ -0,0 +1 @@
|
||||
export { OrganizationsTable } from "./OrganizationsTable";
|
||||
25
frontend/src/pages/admin/OrganizationResourcesPage/route.tsx
Normal file
25
frontend/src/pages/admin/OrganizationResourcesPage/route.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { OrganizationResourcesPage } from "./OrganizationResourcesPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations"
|
||||
)({
|
||||
component: OrganizationResourcesPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "Organizations",
|
||||
link: linkOptions({
|
||||
to: "/admin/resources/organizations"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -1,433 +0,0 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faAt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Button,
|
||||
ContentLoader,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectClear,
|
||||
SelectItem,
|
||||
Switch,
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
Tabs,
|
||||
TextArea
|
||||
} from "@app/components/v2";
|
||||
import { useServerConfig, useUser } from "@app/context";
|
||||
import {
|
||||
useGetOrganizations,
|
||||
useGetServerRootKmsEncryptionDetails,
|
||||
useUpdateServerConfig
|
||||
} from "@app/hooks/api";
|
||||
import { IdentityPanel } from "@app/pages/admin/OverviewPage/components/IdentityPanel";
|
||||
|
||||
import { AuthPanel } from "./components/AuthPanel";
|
||||
import { CachingPanel } from "./components/CachingPanel";
|
||||
import { EncryptionPanel } from "./components/EncryptionPanel";
|
||||
import { IntegrationPanel } from "./components/IntegrationPanel";
|
||||
import { OrganizationsPanel } from "./components/OrganizationsPanel";
|
||||
import { UserPanel } from "./components/UserPanel";
|
||||
|
||||
enum TabSections {
|
||||
Settings = "settings",
|
||||
Encryption = "encryption",
|
||||
Auth = "auth",
|
||||
Integrations = "integrations",
|
||||
Users = "users",
|
||||
Organizations = "organizations",
|
||||
Identities = "identities",
|
||||
Kmip = "kmip",
|
||||
Caching = "caching"
|
||||
}
|
||||
|
||||
enum SignUpModes {
|
||||
Disabled = "disabled",
|
||||
Anyone = "anyone"
|
||||
}
|
||||
|
||||
const formSchema = z.object({
|
||||
signUpMode: z.nativeEnum(SignUpModes),
|
||||
allowedSignUpDomain: z.string().optional().nullable(),
|
||||
trustSamlEmails: z.boolean(),
|
||||
trustLdapEmails: z.boolean(),
|
||||
trustOidcEmails: z.boolean(),
|
||||
defaultAuthOrgId: z.string(),
|
||||
authConsentContent: z.string().optional().default(""),
|
||||
pageFrameContent: z.string().optional().default("")
|
||||
});
|
||||
|
||||
type TDashboardForm = z.infer<typeof formSchema>;
|
||||
|
||||
export const OverviewPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const data = useServerConfig();
|
||||
const { data: serverRootKmsDetails } = useGetServerRootKmsEncryptionDetails();
|
||||
const { config } = data;
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
formState: { isSubmitting, isDirty }
|
||||
} = useForm<TDashboardForm>({
|
||||
resolver: zodResolver(formSchema),
|
||||
values: {
|
||||
// eslint-disable-next-line
|
||||
signUpMode: config.allowSignUp ? SignUpModes.Anyone : SignUpModes.Disabled,
|
||||
allowedSignUpDomain: config.allowedSignUpDomain,
|
||||
trustSamlEmails: config.trustSamlEmails,
|
||||
trustLdapEmails: config.trustLdapEmails,
|
||||
trustOidcEmails: config.trustOidcEmails,
|
||||
defaultAuthOrgId: config.defaultAuthOrgId ?? "",
|
||||
authConsentContent: config.authConsentContent ?? "",
|
||||
pageFrameContent: config.pageFrameContent ?? ""
|
||||
}
|
||||
});
|
||||
|
||||
const signUpMode = watch("signUpMode");
|
||||
const defaultAuthOrgId = watch("defaultAuthOrgId");
|
||||
|
||||
const { user } = useUser();
|
||||
const { mutateAsync: updateServerConfig } = useUpdateServerConfig();
|
||||
|
||||
const organizations = useGetOrganizations();
|
||||
|
||||
const isNotAllowed = !user?.superAdmin;
|
||||
const onFormSubmit = async (formData: TDashboardForm) => {
|
||||
try {
|
||||
const {
|
||||
allowedSignUpDomain,
|
||||
trustSamlEmails,
|
||||
trustLdapEmails,
|
||||
trustOidcEmails,
|
||||
authConsentContent,
|
||||
pageFrameContent
|
||||
} = formData;
|
||||
|
||||
await updateServerConfig({
|
||||
defaultAuthOrgId: defaultAuthOrgId || null,
|
||||
allowSignUp: signUpMode !== SignUpModes.Disabled,
|
||||
allowedSignUpDomain: signUpMode === SignUpModes.Anyone ? allowedSignUpDomain : null,
|
||||
trustSamlEmails,
|
||||
trustLdapEmails,
|
||||
trustOidcEmails,
|
||||
authConsentContent,
|
||||
pageFrameContent
|
||||
});
|
||||
createNotification({
|
||||
text: "Successfully changed sign up setting.",
|
||||
type: "success"
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Failed to update sign up setting."
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: t("admin.dashboard") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={t("admin.dashboard.og-title") ?? ""} />
|
||||
<meta name="og:description" content={t("admin.dashboard.og-description") ?? ""} />
|
||||
</Helmet>
|
||||
<div className="h-full">
|
||||
<div className="container mx-auto max-w-7xl px-4 pb-12 text-white dark:[color-scheme:dark]">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl pt-6">
|
||||
<div className="mb-8 flex flex-col items-start justify-between text-xl">
|
||||
<h1 className="text-3xl font-semibold">Server Admin Console</h1>
|
||||
<p className="text-base text-bunker-300">
|
||||
Manage your instance level configurations.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{isNotAllowed ? (
|
||||
<ContentLoader text={isNotAllowed ? "Redirecting to org page..." : undefined} />
|
||||
) : (
|
||||
<div>
|
||||
<Tabs defaultValue={TabSections.Settings} className="w-full">
|
||||
<TabList className="flex w-full flex-row justify-between">
|
||||
<div className="flex w-full">
|
||||
<Tab value={TabSections.Settings}>General</Tab>
|
||||
<Tab value={TabSections.Encryption}>Encryption</Tab>
|
||||
<Tab value={TabSections.Auth}>Authentication</Tab>
|
||||
<Tab value={TabSections.Integrations}>Integrations</Tab>
|
||||
<Tab value={TabSections.Caching}>Caching</Tab>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full justify-end">
|
||||
<Tab value={TabSections.Organizations}>Organizations</Tab>
|
||||
<Tab value={TabSections.Users}>User Identities</Tab>
|
||||
<Tab value={TabSections.Identities}>Machine Identities</Tab>
|
||||
</div>
|
||||
</TabList>
|
||||
<TabPanel value={TabSections.Settings}>
|
||||
<form
|
||||
className="mb-6 space-y-8 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">
|
||||
Allow user signups
|
||||
</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select if you want users to be able to signup freely into your Infisical
|
||||
instance.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="signUpMode"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="max-w-sm"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Select
|
||||
className="w-full bg-mineshaft-700"
|
||||
dropdownContainerClassName="bg-mineshaft-800"
|
||||
defaultValue={field.value}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
{...field}
|
||||
>
|
||||
<SelectItem value={SignUpModes.Disabled}>Disabled</SelectItem>
|
||||
<SelectItem value={SignUpModes.Anyone}>Anyone</SelectItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{signUpMode === "anyone" && (
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-4 text-xl font-semibold text-mineshaft-100">
|
||||
Restrict signup by email domain(s)
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="allowedSignUpDomain"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Leave blank to allow any email domains"
|
||||
className="w-72"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
placeholder="gmail.com, aws.com, redhat.com"
|
||||
leftIcon={<FontAwesomeIcon icon={faAt} />}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">
|
||||
Default organization
|
||||
</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select the default organization you want to set for SAML/LDAP/OIDC/Github
|
||||
logins. When selected, user logins will be automatically scoped to the
|
||||
selected organization.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="defaultAuthOrgId"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="max-w-sm"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Select
|
||||
placeholder="Allow all organizations"
|
||||
className="w-full bg-mineshaft-700"
|
||||
dropdownContainerClassName="bg-mineshaft-800"
|
||||
defaultValue={field.value ?? " "}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
{...field}
|
||||
>
|
||||
<SelectClear
|
||||
selectValue={defaultAuthOrgId}
|
||||
onClear={() => {
|
||||
onChange("");
|
||||
}}
|
||||
>
|
||||
Allow all organizations
|
||||
</SelectClear>
|
||||
{organizations.data?.map((org) => (
|
||||
<SelectItem key={org.id} value={org.id}>
|
||||
{org.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">
|
||||
Trust emails
|
||||
</div>
|
||||
<div className="mb-4 max-w-sm text-sm text-mineshaft-400">
|
||||
Select if you want Infisical to trust external emails from SAML/LDAP/OIDC
|
||||
identity providers. If set to false, then Infisical will prompt
|
||||
SAML/LDAP/OIDC provisioned users to verify their email upon their first
|
||||
login.
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustSamlEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-saml-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust SAML emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustLdapEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-ldap-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust LDAP emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="trustOidcEmails"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
id="trust-oidc-emails"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Trust OIDC emails</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-start">
|
||||
<div className="mb-2 text-xl font-semibold text-mineshaft-100">Notices</div>
|
||||
<div className="mb-4 max-w-lg text-sm text-mineshaft-400">
|
||||
Configure system-wide notification banners and security messages. These
|
||||
settings control the text displayed to users during authentication and
|
||||
throughout their session
|
||||
</div>
|
||||
<Controller
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Auth Consent Content"
|
||||
tooltipText="Formatting supported: HTML, Markdown, Plain text"
|
||||
>
|
||||
<TextArea
|
||||
placeholder="**Auth Consent Message**"
|
||||
{...field}
|
||||
rows={3}
|
||||
className="thin-scrollbar h-48 max-w-lg !resize-none bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="authConsentContent"
|
||||
/>
|
||||
<Controller
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Page Frame Content"
|
||||
tooltipText="Formatting supported: HTML, Markdown, Plain text"
|
||||
>
|
||||
<TextArea
|
||||
placeholder='<div style="background-color: red">TOP SECRET</div>'
|
||||
{...field}
|
||||
rows={3}
|
||||
className="thin-scrollbar h-48 max-w-lg !resize-none bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="pageFrameContent"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting || !isDirty}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Encryption}>
|
||||
<EncryptionPanel rootKmsDetails={serverRootKmsDetails} />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Auth}>
|
||||
<AuthPanel />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Integrations}>
|
||||
<IntegrationPanel />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Organizations}>
|
||||
<OrganizationsPanel />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Users}>
|
||||
<UserPanel />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Identities}>
|
||||
<IdentityPanel />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Caching}>
|
||||
<CachingPanel />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { OverviewPage } from "./OverviewPage";
|
||||
|
||||
export const Route = createFileRoute("/_authenticate/_inject-org-details/admin/_admin-layout/")({
|
||||
component: OverviewPage
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
|
||||
import { UserIdentitiesTable } from "./components";
|
||||
|
||||
export const UserIdentitiesResourcesPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "Admin" })}</title>
|
||||
</Helmet>
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="User Identities"
|
||||
description="Manage all user identities within your Infisical instance."
|
||||
/>
|
||||
<UserIdentitiesTable />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -226,7 +226,7 @@ const UserPanelTable = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const UserPanel = () => {
|
||||
export const UserIdentitiesTable = () => {
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
"removeUser",
|
||||
"upgradePlan",
|
||||
@@ -297,9 +297,6 @@ export const UserPanel = () => {
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Users</p>
|
||||
</div>
|
||||
<UserPanelTable handlePopUpOpen={handlePopUpOpen} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.removeUser.isOpen}
|
||||
@@ -0,0 +1 @@
|
||||
export { UserIdentitiesTable } from "./UserIdentitiesTable";
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||
|
||||
import { UserIdentitiesResourcesPage } from "./UserIdentitiesResourcesPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities"
|
||||
)({
|
||||
component: UserIdentitiesResourcesPage,
|
||||
beforeLoad: async () => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: "Admin",
|
||||
link: linkOptions({ to: "/admin" })
|
||||
},
|
||||
{
|
||||
label: "User Identities",
|
||||
link: linkOptions({
|
||||
to: "/admin/resources/user-identities"
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -18,7 +18,7 @@ export const OverviewPage = () => {
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="OverviewPage"
|
||||
title="Overview Page"
|
||||
description="Manage keys and perform cryptographic operations."
|
||||
/>
|
||||
<ProjectPermissionCan
|
||||
|
||||
@@ -42,17 +42,24 @@ import { Route as adminLayoutImport } from './pages/admin/layout'
|
||||
import { Route as authProviderSuccessPageRouteImport } from './pages/auth/ProviderSuccessPage/route'
|
||||
import { Route as authProviderErrorPageRouteImport } from './pages/auth/ProviderErrorPage/route'
|
||||
import { Route as userPersonalSettingsPageRouteImport } from './pages/user/PersonalSettingsPage/route'
|
||||
import { Route as adminIntegrationsPageRouteImport } from './pages/admin/IntegrationsPage/route'
|
||||
import { Route as adminEncryptionPageRouteImport } from './pages/admin/EncryptionPage/route'
|
||||
import { Route as adminCachingPageRouteImport } from './pages/admin/CachingPage/route'
|
||||
import { Route as adminAuthenticationPageRouteImport } from './pages/admin/AuthenticationPage/route'
|
||||
import { Route as organizationSsoPageRouteImport } from './pages/organization/SsoPage/route'
|
||||
import { Route as organizationSecretScanningPageRouteImport } from './pages/organization/SecretScanningPage/route'
|
||||
import { Route as organizationBillingPageRouteImport } from './pages/organization/BillingPage/route'
|
||||
import { Route as organizationAuditLogsPageRouteImport } from './pages/organization/AuditLogsPage/route'
|
||||
import { Route as organizationAdminPageRouteImport } from './pages/organization/AdminPage/route'
|
||||
import { Route as organizationAccessManagementPageRouteImport } from './pages/organization/AccessManagementPage/route'
|
||||
import { Route as adminOverviewPageRouteImport } from './pages/admin/OverviewPage/route'
|
||||
import { Route as adminGeneralPageRouteImport } from './pages/admin/GeneralPage/route'
|
||||
import { Route as sshLayoutImport } from './pages/ssh/layout'
|
||||
import { Route as secretManagerLayoutImport } from './pages/secret-manager/layout'
|
||||
import { Route as kmsLayoutImport } from './pages/kms/layout'
|
||||
import { Route as certManagerLayoutImport } from './pages/cert-manager/layout'
|
||||
import { Route as adminUserIdentitiesResourcesPageRouteImport } from './pages/admin/UserIdentitiesResourcesPage/route'
|
||||
import { Route as adminOrganizationResourcesPageRouteImport } from './pages/admin/OrganizationResourcesPage/route'
|
||||
import { Route as adminMachineIdentitiesResourcesPageRouteImport } from './pages/admin/MachineIdentitiesResourcesPage/route'
|
||||
import { Route as organizationSshSettingsPageRouteImport } from './pages/organization/SshSettingsPage/route'
|
||||
import { Route as organizationSshOverviewPageRouteImport } from './pages/organization/SshOverviewPage/route'
|
||||
import { Route as organizationSecretSharingSettingsPageRouteImport } from './pages/organization/SecretSharingSettingsPage/route'
|
||||
@@ -546,6 +553,33 @@ const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdRoute =
|
||||
getParentRoute: () => organizationLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const adminIntegrationsPageRouteRoute = adminIntegrationsPageRouteImport.update(
|
||||
{
|
||||
id: '/integrations',
|
||||
path: '/integrations',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any,
|
||||
)
|
||||
|
||||
const adminEncryptionPageRouteRoute = adminEncryptionPageRouteImport.update({
|
||||
id: '/encryption',
|
||||
path: '/encryption',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const adminCachingPageRouteRoute = adminCachingPageRouteImport.update({
|
||||
id: '/caching',
|
||||
path: '/caching',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const adminAuthenticationPageRouteRoute =
|
||||
adminAuthenticationPageRouteImport.update({
|
||||
id: '/authentication',
|
||||
path: '/authentication',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const organizationSsoPageRouteRoute = organizationSsoPageRouteImport.update({
|
||||
id: '/sso',
|
||||
path: '/sso',
|
||||
@@ -593,7 +627,7 @@ const organizationAccessManagementPageRouteRoute =
|
||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||
} as any)
|
||||
|
||||
const adminOverviewPageRouteRoute = adminOverviewPageRouteImport.update({
|
||||
const adminGeneralPageRouteRoute = adminGeneralPageRouteImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
@@ -621,6 +655,27 @@ const certManagerLayoutRoute = certManagerLayoutImport.update({
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdRoute,
|
||||
} as any)
|
||||
|
||||
const adminUserIdentitiesResourcesPageRouteRoute =
|
||||
adminUserIdentitiesResourcesPageRouteImport.update({
|
||||
id: '/resources/user-identities',
|
||||
path: '/resources/user-identities',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const adminOrganizationResourcesPageRouteRoute =
|
||||
adminOrganizationResourcesPageRouteImport.update({
|
||||
id: '/resources/organizations',
|
||||
path: '/resources/organizations',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const adminMachineIdentitiesResourcesPageRouteRoute =
|
||||
adminMachineIdentitiesResourcesPageRouteImport.update({
|
||||
id: '/resources/machine-identities',
|
||||
path: '/resources/machine-identities',
|
||||
getParentRoute: () => adminLayoutRoute,
|
||||
} as any)
|
||||
|
||||
const organizationSshSettingsPageRouteRoute =
|
||||
organizationSshSettingsPageRouteImport.update({
|
||||
id: '/ssh/settings',
|
||||
@@ -2017,7 +2072,7 @@ declare module '@tanstack/react-router' {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/'
|
||||
path: '/'
|
||||
fullPath: '/admin/'
|
||||
preLoaderRoute: typeof adminOverviewPageRouteImport
|
||||
preLoaderRoute: typeof adminGeneralPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/access-management': {
|
||||
@@ -2062,6 +2117,34 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof organizationSsoPageRouteImport
|
||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
||||
path: '/authentication'
|
||||
fullPath: '/admin/authentication'
|
||||
preLoaderRoute: typeof adminAuthenticationPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/caching': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/caching'
|
||||
path: '/caching'
|
||||
fullPath: '/admin/caching'
|
||||
preLoaderRoute: typeof adminCachingPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/encryption': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/encryption'
|
||||
path: '/encryption'
|
||||
fullPath: '/admin/encryption'
|
||||
preLoaderRoute: typeof adminEncryptionPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/integrations': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/integrations'
|
||||
path: '/integrations'
|
||||
fullPath: '/admin/integrations'
|
||||
preLoaderRoute: typeof adminIntegrationsPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId'
|
||||
path: '/cert-manager/$projectId'
|
||||
@@ -2237,6 +2320,27 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof organizationSshSettingsPageRouteImport
|
||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities'
|
||||
path: '/resources/machine-identities'
|
||||
fullPath: '/admin/resources/machine-identities'
|
||||
preLoaderRoute: typeof adminMachineIdentitiesResourcesPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations'
|
||||
path: '/resources/organizations'
|
||||
fullPath: '/admin/resources/organizations'
|
||||
preLoaderRoute: typeof adminOrganizationResourcesPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities': {
|
||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities'
|
||||
path: '/resources/user-identities'
|
||||
fullPath: '/admin/resources/user-identities'
|
||||
preLoaderRoute: typeof adminUserIdentitiesResourcesPageRouteImport
|
||||
parentRoute: typeof adminLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
||||
path: ''
|
||||
@@ -3848,11 +3952,28 @@ const organizationLayoutRouteWithChildren =
|
||||
organizationLayoutRoute._addFileChildren(organizationLayoutRouteChildren)
|
||||
|
||||
interface adminLayoutRouteChildren {
|
||||
adminOverviewPageRouteRoute: typeof adminOverviewPageRouteRoute
|
||||
adminGeneralPageRouteRoute: typeof adminGeneralPageRouteRoute
|
||||
adminAuthenticationPageRouteRoute: typeof adminAuthenticationPageRouteRoute
|
||||
adminCachingPageRouteRoute: typeof adminCachingPageRouteRoute
|
||||
adminEncryptionPageRouteRoute: typeof adminEncryptionPageRouteRoute
|
||||
adminIntegrationsPageRouteRoute: typeof adminIntegrationsPageRouteRoute
|
||||
adminMachineIdentitiesResourcesPageRouteRoute: typeof adminMachineIdentitiesResourcesPageRouteRoute
|
||||
adminOrganizationResourcesPageRouteRoute: typeof adminOrganizationResourcesPageRouteRoute
|
||||
adminUserIdentitiesResourcesPageRouteRoute: typeof adminUserIdentitiesResourcesPageRouteRoute
|
||||
}
|
||||
|
||||
const adminLayoutRouteChildren: adminLayoutRouteChildren = {
|
||||
adminOverviewPageRouteRoute: adminOverviewPageRouteRoute,
|
||||
adminGeneralPageRouteRoute: adminGeneralPageRouteRoute,
|
||||
adminAuthenticationPageRouteRoute: adminAuthenticationPageRouteRoute,
|
||||
adminCachingPageRouteRoute: adminCachingPageRouteRoute,
|
||||
adminEncryptionPageRouteRoute: adminEncryptionPageRouteRoute,
|
||||
adminIntegrationsPageRouteRoute: adminIntegrationsPageRouteRoute,
|
||||
adminMachineIdentitiesResourcesPageRouteRoute:
|
||||
adminMachineIdentitiesResourcesPageRouteRoute,
|
||||
adminOrganizationResourcesPageRouteRoute:
|
||||
adminOrganizationResourcesPageRouteRoute,
|
||||
adminUserIdentitiesResourcesPageRouteRoute:
|
||||
adminUserIdentitiesResourcesPageRouteRoute,
|
||||
}
|
||||
|
||||
const adminLayoutRouteWithChildren = adminLayoutRoute._addFileChildren(
|
||||
@@ -4039,13 +4160,17 @@ export interface FileRoutesByFullPath {
|
||||
'/login/provider/success': typeof authProviderSuccessPageRouteRoute
|
||||
'/integrations': typeof AuthenticateInjectOrgDetailsOrgLayoutIntegrationsRouteWithChildren
|
||||
'/organization': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren
|
||||
'/admin/': typeof adminOverviewPageRouteRoute
|
||||
'/admin/': typeof adminGeneralPageRouteRoute
|
||||
'/organization/access-management': typeof organizationAccessManagementPageRouteRoute
|
||||
'/organization/admin': typeof organizationAdminPageRouteRoute
|
||||
'/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
||||
'/organization/billing': typeof organizationBillingPageRouteRoute
|
||||
'/organization/secret-scanning': typeof organizationSecretScanningPageRouteRoute
|
||||
'/organization/sso': typeof organizationSsoPageRouteRoute
|
||||
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
||||
'/admin/caching': typeof adminCachingPageRouteRoute
|
||||
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
||||
'/admin/integrations': typeof adminIntegrationsPageRouteRoute
|
||||
'/cert-manager/$projectId': typeof certManagerLayoutRouteWithChildren
|
||||
'/kms/$projectId': typeof kmsLayoutRouteWithChildren
|
||||
'/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
||||
@@ -4071,6 +4196,9 @@ export interface FileRoutesByFullPath {
|
||||
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||
'/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||
'/admin/resources/machine-identities': typeof adminMachineIdentitiesResourcesPageRouteRoute
|
||||
'/admin/resources/organizations': typeof adminOrganizationResourcesPageRouteRoute
|
||||
'/admin/resources/user-identities': typeof adminUserIdentitiesResourcesPageRouteRoute
|
||||
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
||||
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
||||
'/cert-manager/$projectId/certificates': typeof certManagerCertificatesPageRouteRoute
|
||||
@@ -4226,7 +4354,7 @@ export interface FileRoutesByTo {
|
||||
'/signup/sso': typeof authSignUpSsoPageRouteRoute
|
||||
'/secret-request/secret/$secretRequestId': typeof publicViewSecretRequestByIDPageRouteRoute
|
||||
'/shared/secret/$secretId': typeof publicViewSharedSecretByIDPageRouteRoute
|
||||
'/admin': typeof adminOverviewPageRouteRoute
|
||||
'/admin': typeof adminGeneralPageRouteRoute
|
||||
'/login/provider/error': typeof authProviderErrorPageRouteRoute
|
||||
'/login/provider/success': typeof authProviderSuccessPageRouteRoute
|
||||
'/integrations': typeof AuthenticateInjectOrgDetailsOrgLayoutIntegrationsRouteWithChildren
|
||||
@@ -4237,6 +4365,10 @@ export interface FileRoutesByTo {
|
||||
'/organization/billing': typeof organizationBillingPageRouteRoute
|
||||
'/organization/secret-scanning': typeof organizationSecretScanningPageRouteRoute
|
||||
'/organization/sso': typeof organizationSsoPageRouteRoute
|
||||
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
||||
'/admin/caching': typeof adminCachingPageRouteRoute
|
||||
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
||||
'/admin/integrations': typeof adminIntegrationsPageRouteRoute
|
||||
'/cert-manager/$projectId': typeof certManagerLayoutRouteWithChildren
|
||||
'/kms/$projectId': typeof kmsLayoutRouteWithChildren
|
||||
'/secret-manager/$projectId': typeof secretManagerLayoutRouteWithChildren
|
||||
@@ -4258,6 +4390,9 @@ export interface FileRoutesByTo {
|
||||
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||
'/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||
'/admin/resources/machine-identities': typeof adminMachineIdentitiesResourcesPageRouteRoute
|
||||
'/admin/resources/organizations': typeof adminOrganizationResourcesPageRouteRoute
|
||||
'/admin/resources/user-identities': typeof adminUserIdentitiesResourcesPageRouteRoute
|
||||
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
||||
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
||||
'/cert-manager/$projectId/certificates': typeof certManagerCertificatesPageRouteRoute
|
||||
@@ -4425,13 +4560,17 @@ export interface FileRoutesById {
|
||||
'/_authenticate/_inject-org-details/_org-layout/integrations': typeof AuthenticateInjectOrgDetailsOrgLayoutIntegrationsRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout': typeof adminLayoutRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/': typeof adminOverviewPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/': typeof adminGeneralPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/access-management': typeof organizationAccessManagementPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/admin': typeof organizationAdminPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/billing': typeof organizationBillingPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-scanning': typeof organizationSecretScanningPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/sso': typeof organizationSsoPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': typeof adminAuthenticationPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/caching': typeof adminCachingPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/encryption': typeof adminEncryptionPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/integrations': typeof adminIntegrationsPageRouteRoute
|
||||
'/_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
|
||||
@@ -4457,6 +4596,9 @@ export interface FileRoutesById {
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities': typeof adminMachineIdentitiesResourcesPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations': typeof adminOrganizationResourcesPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities': typeof adminUserIdentitiesResourcesPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': typeof certManagerLayoutRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout': typeof kmsLayoutRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout': typeof secretManagerLayoutRouteWithChildren
|
||||
@@ -4633,6 +4775,10 @@ export interface FileRouteTypes {
|
||||
| '/organization/billing'
|
||||
| '/organization/secret-scanning'
|
||||
| '/organization/sso'
|
||||
| '/admin/authentication'
|
||||
| '/admin/caching'
|
||||
| '/admin/encryption'
|
||||
| '/admin/integrations'
|
||||
| '/cert-manager/$projectId'
|
||||
| '/kms/$projectId'
|
||||
| '/organization/app-connections'
|
||||
@@ -4658,6 +4804,9 @@ export interface FileRouteTypes {
|
||||
| '/organization/secret-sharing/settings'
|
||||
| '/organization/ssh/overview'
|
||||
| '/organization/ssh/settings'
|
||||
| '/admin/resources/machine-identities'
|
||||
| '/admin/resources/organizations'
|
||||
| '/admin/resources/user-identities'
|
||||
| '/cert-manager/$projectId/alerting'
|
||||
| '/cert-manager/$projectId/certificate-authorities'
|
||||
| '/cert-manager/$projectId/certificates'
|
||||
@@ -4823,6 +4972,10 @@ export interface FileRouteTypes {
|
||||
| '/organization/billing'
|
||||
| '/organization/secret-scanning'
|
||||
| '/organization/sso'
|
||||
| '/admin/authentication'
|
||||
| '/admin/caching'
|
||||
| '/admin/encryption'
|
||||
| '/admin/integrations'
|
||||
| '/cert-manager/$projectId'
|
||||
| '/kms/$projectId'
|
||||
| '/secret-manager/$projectId'
|
||||
@@ -4844,6 +4997,9 @@ export interface FileRouteTypes {
|
||||
| '/organization/secret-sharing/settings'
|
||||
| '/organization/ssh/overview'
|
||||
| '/organization/ssh/settings'
|
||||
| '/admin/resources/machine-identities'
|
||||
| '/admin/resources/organizations'
|
||||
| '/admin/resources/user-identities'
|
||||
| '/cert-manager/$projectId/alerting'
|
||||
| '/cert-manager/$projectId/certificate-authorities'
|
||||
| '/cert-manager/$projectId/certificates'
|
||||
@@ -5016,6 +5172,10 @@ export interface FileRouteTypes {
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/billing'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-scanning'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/sso'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/caching'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/encryption'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/integrations'
|
||||
| '/_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'
|
||||
@@ -5041,6 +5201,9 @@ export interface FileRouteTypes {
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations'
|
||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout'
|
||||
@@ -5438,11 +5601,18 @@ export const routeTree = rootRoute
|
||||
"filePath": "admin/layout.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin",
|
||||
"children": [
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/"
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/authentication",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/caching",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/encryption",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/integrations",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations",
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities"
|
||||
]
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/": {
|
||||
"filePath": "admin/OverviewPage/route.tsx",
|
||||
"filePath": "admin/GeneralPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/access-management": {
|
||||
@@ -5469,6 +5639,22 @@ export const routeTree = rootRoute
|
||||
"filePath": "organization/SsoPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/authentication": {
|
||||
"filePath": "admin/AuthenticationPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/caching": {
|
||||
"filePath": "admin/CachingPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/encryption": {
|
||||
"filePath": "admin/EncryptionPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/integrations": {
|
||||
"filePath": "admin/IntegrationsPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId": {
|
||||
"filePath": "",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout",
|
||||
@@ -5596,6 +5782,18 @@ export const routeTree = rootRoute
|
||||
"filePath": "organization/SshSettingsPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/machine-identities": {
|
||||
"filePath": "admin/MachineIdentitiesResourcesPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/organizations": {
|
||||
"filePath": "admin/OrganizationResourcesPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/admin/_admin-layout/resources/user-identities": {
|
||||
"filePath": "admin/UserIdentitiesResourcesPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout": {
|
||||
"filePath": "cert-manager/layout.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId",
|
||||
|
||||
@@ -4,7 +4,16 @@ const middleware = (fileName: string, virtualRoutes: VirtualRouteNode[]) =>
|
||||
layout(`middlewares/${fileName}`, virtualRoutes);
|
||||
|
||||
const adminRoute = route("/admin", [
|
||||
layout("admin-layout", "admin/layout.tsx", [index("admin/OverviewPage/route.tsx")])
|
||||
layout("admin-layout", "admin/layout.tsx", [
|
||||
index("admin/GeneralPage/route.tsx"),
|
||||
route("/encryption", "admin/EncryptionPage/route.tsx"),
|
||||
route("/authentication", "admin/AuthenticationPage/route.tsx"),
|
||||
route("/integrations", "admin/IntegrationsPage/route.tsx"),
|
||||
route("/caching", "admin/CachingPage/route.tsx"),
|
||||
route("/resources/organizations", "admin/OrganizationResourcesPage/route.tsx"),
|
||||
route("/resources/user-identities", "admin/UserIdentitiesResourcesPage/route.tsx"),
|
||||
route("/resources/machine-identities", "admin/MachineIdentitiesResourcesPage/route.tsx")
|
||||
])
|
||||
]);
|
||||
|
||||
const organizationRoutes = route("/organization", [
|
||||
|
||||
Reference in New Issue
Block a user