mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-08 23:18:05 -05:00
Merge pull request #5118 from Infisical/chore/removal-ff
feat: removed feature flag for ai and pam
This commit is contained in:
@@ -27,7 +27,6 @@ import { AiMcpServerCredentialMode } from "../ai-mcp-server/ai-mcp-server-enum";
|
||||
import { TAiMcpServerServiceFactory } from "../ai-mcp-server/ai-mcp-server-service";
|
||||
import { TAiMcpServerToolDALFactory } from "../ai-mcp-server/ai-mcp-server-tool-dal";
|
||||
import { TAiMcpServerUserCredentialDALFactory } from "../ai-mcp-server/ai-mcp-server-user-credential-dal";
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||
import { ProjectPermissionMcpEndpointActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||
import { TAiMcpEndpointDALFactory } from "./ai-mcp-endpoint-dal";
|
||||
@@ -73,7 +72,6 @@ type TAiMcpEndpointServiceFactoryDep = {
|
||||
authTokenService: Pick<TAuthTokenServiceFactory, "getUserTokenSessionById">;
|
||||
userDAL: TUserDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
// OAuth schemas for parsing cached data
|
||||
@@ -130,8 +128,7 @@ export const aiMcpEndpointServiceFactory = ({
|
||||
keyStore,
|
||||
authTokenService,
|
||||
userDAL,
|
||||
permissionService,
|
||||
licenseService
|
||||
permissionService
|
||||
}: TAiMcpEndpointServiceFactoryDep) => {
|
||||
const interactWithMcp = async ({
|
||||
endpointId,
|
||||
@@ -375,13 +372,6 @@ export const aiMcpEndpointServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
}: TCreateAiMcpEndpointDTO) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actorOrgId);
|
||||
if (!orgLicensePlan.ai) {
|
||||
throw new BadRequestError({
|
||||
message: "AI operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor,
|
||||
actorId,
|
||||
|
||||
@@ -20,7 +20,6 @@ import { ActorType, AuthMethod } from "@app/services/auth/auth-type";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||
import { TAiMcpServerDALFactory } from "./ai-mcp-server-dal";
|
||||
@@ -53,7 +52,6 @@ type TAiMcpServerServiceFactoryDep = {
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
keyStore: Pick<TKeyStoreFactory, "getItem" | "setItemWithExpiry" | "deleteItem">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TAiMcpServerServiceFactory = ReturnType<typeof aiMcpServerServiceFactory>;
|
||||
@@ -152,8 +150,7 @@ export const aiMcpServerServiceFactory = ({
|
||||
aiMcpServerUserCredentialDAL,
|
||||
kmsService,
|
||||
keyStore,
|
||||
permissionService,
|
||||
licenseService
|
||||
permissionService
|
||||
}: TAiMcpServerServiceFactoryDep) => {
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-redundant-type-constituents */
|
||||
const fetchMcpTools = async (serverUrl: string, accessToken: string): Promise<TMcpTool[]> => {
|
||||
@@ -549,13 +546,6 @@ export const aiMcpServerServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
}: TCreateAiMcpServerDTO) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actorOrgId);
|
||||
if (!orgLicensePlan.ai) {
|
||||
throw new BadRequestError({
|
||||
message: "AI operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor,
|
||||
actorId,
|
||||
|
||||
@@ -112,9 +112,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
fips: false,
|
||||
eventSubscriptions: false,
|
||||
machineIdentityAuthTemplates: false,
|
||||
pkiLegacyTemplates: false,
|
||||
pam: false,
|
||||
ai: false
|
||||
pkiLegacyTemplates: false
|
||||
});
|
||||
|
||||
export const setupLicenseRequestWithStore = (
|
||||
|
||||
@@ -92,8 +92,6 @@ export type TFeatureSet = {
|
||||
pkiLegacyTemplates: false;
|
||||
fips: false;
|
||||
eventSubscriptions: false;
|
||||
pam: false;
|
||||
ai: false;
|
||||
};
|
||||
|
||||
export type TOrgPlansTableDTO = {
|
||||
|
||||
@@ -52,7 +52,6 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||
|
||||
import { EventType, TAuditLogServiceFactory } from "../audit-log/audit-log-types";
|
||||
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TPamFolderDALFactory } from "../pam-folder/pam-folder-dal";
|
||||
import { getFullPamFolderPath } from "../pam-folder/pam-folder-fns";
|
||||
import { TPamResourceDALFactory } from "../pam-resource/pam-resource-dal";
|
||||
@@ -78,7 +77,6 @@ type TPamAccountServiceFactoryDep = {
|
||||
projectDAL: TProjectDALFactory;
|
||||
orgDAL: TOrgDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
gatewayV2Service: Pick<
|
||||
TGatewayV2ServiceFactory,
|
||||
@@ -107,7 +105,6 @@ export const pamAccountServiceFactory = ({
|
||||
orgDAL,
|
||||
userDAL,
|
||||
permissionService,
|
||||
licenseService,
|
||||
kmsService,
|
||||
gatewayV2Service,
|
||||
auditLogService,
|
||||
@@ -128,13 +125,6 @@ export const pamAccountServiceFactory = ({
|
||||
}: TCreateAccountDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
if (rotationEnabled && (rotationIntervalSeconds === undefined || rotationIntervalSeconds === null)) {
|
||||
throw new BadRequestError({
|
||||
message: "Rotation interval must be defined when rotation is enabled."
|
||||
@@ -248,13 +238,6 @@ export const pamAccountServiceFactory = ({
|
||||
}: TUpdateAccountDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const account = await pamAccountDAL.findById(accountId);
|
||||
if (!account) throw new NotFoundError({ message: `Account with ID '${accountId}' not found` });
|
||||
|
||||
@@ -591,13 +574,6 @@ export const pamAccountServiceFactory = ({
|
||||
}: TAccessAccountDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const pathSegments: string[] = accountPath.split("/").filter(Boolean);
|
||||
if (pathSegments.length === 0) {
|
||||
throw new BadRequestError({ message: "Invalid accountPath. Path must contain at least the account name." });
|
||||
@@ -940,13 +916,6 @@ export const pamAccountServiceFactory = ({
|
||||
};
|
||||
|
||||
const getSessionCredentials = async (sessionId: string, actor: OrgServiceActor) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
// To be hit by gateways only
|
||||
if (actor.type !== ActorType.IDENTITY) {
|
||||
throw new ForbiddenRequestError({ message: "Only gateways can perform this action" });
|
||||
|
||||
@@ -7,31 +7,18 @@ import { DatabaseErrorCode } from "@app/lib/error-codes";
|
||||
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TPamFolderDALFactory } from "./pam-folder-dal";
|
||||
import { TCreateFolderDTO, TUpdateFolderDTO } from "./pam-folder-types";
|
||||
|
||||
type TPamFolderServiceFactoryDep = {
|
||||
pamFolderDAL: TPamFolderDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TPamFolderServiceFactory = ReturnType<typeof pamFolderServiceFactory>;
|
||||
|
||||
export const pamFolderServiceFactory = ({
|
||||
pamFolderDAL,
|
||||
permissionService,
|
||||
licenseService
|
||||
}: TPamFolderServiceFactoryDep) => {
|
||||
export const pamFolderServiceFactory = ({ pamFolderDAL, permissionService }: TPamFolderServiceFactoryDep) => {
|
||||
const createFolder = async ({ name, description, parentId, projectId }: TCreateFolderDTO, actor: OrgServiceActor) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorAuthMethod: actor.authMethod,
|
||||
@@ -72,13 +59,6 @@ export const pamFolderServiceFactory = ({
|
||||
};
|
||||
|
||||
const updateFolder = async ({ id, name, description }: TUpdateFolderDTO, actor: OrgServiceActor) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const folder = await pamFolderDAL.findById(id);
|
||||
if (!folder) throw new NotFoundError({ message: `Folder with ID '${id}' not found` });
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import { OrgServiceActor } from "@app/lib/types";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { decryptAccountCredentials, encryptAccountCredentials } from "../pam-account/pam-account-fns";
|
||||
import { TPamResourceDALFactory } from "./pam-resource-dal";
|
||||
import { PamResource } from "./pam-resource-enums";
|
||||
@@ -31,7 +30,6 @@ import { TSSHResourceMetadata } from "./ssh/ssh-resource-types";
|
||||
type TPamResourceServiceFactoryDep = {
|
||||
pamResourceDAL: TPamResourceDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
gatewayV2Service: Pick<
|
||||
TGatewayV2ServiceFactory,
|
||||
@@ -44,7 +42,6 @@ export type TPamResourceServiceFactory = ReturnType<typeof pamResourceServiceFac
|
||||
export const pamResourceServiceFactory = ({
|
||||
pamResourceDAL,
|
||||
permissionService,
|
||||
licenseService,
|
||||
kmsService,
|
||||
gatewayV2Service
|
||||
}: TPamResourceServiceFactoryDep) => {
|
||||
@@ -76,13 +73,6 @@ export const pamResourceServiceFactory = ({
|
||||
{ resourceType, connectionDetails, gatewayId, name, projectId, rotationAccountCredentials }: TCreateResourceDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorAuthMethod: actor.authMethod,
|
||||
@@ -137,13 +127,6 @@ export const pamResourceServiceFactory = ({
|
||||
{ connectionDetails, resourceId, name, rotationAccountCredentials }: TUpdateResourceDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
const resource = await pamResourceDAL.findById(resourceId);
|
||||
if (!resource) throw new NotFoundError({ message: `Resource with ID '${resourceId}' not found` });
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { OrgPermissionGatewayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||
import { ProjectPermissionPamSessionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||
import { TPamSessionDALFactory } from "./pam-session-dal";
|
||||
@@ -21,7 +20,6 @@ type TPamSessionServiceFactoryDep = {
|
||||
pamSessionDAL: TPamSessionDALFactory;
|
||||
projectDAL: TProjectDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
@@ -31,7 +29,6 @@ export const pamSessionServiceFactory = ({
|
||||
pamSessionDAL,
|
||||
projectDAL,
|
||||
permissionService,
|
||||
licenseService,
|
||||
kmsService
|
||||
}: TPamSessionServiceFactoryDep) => {
|
||||
// Helper to check and update expired sessions when viewing session details (redundancy for scheduled job)
|
||||
@@ -111,13 +108,6 @@ export const pamSessionServiceFactory = ({
|
||||
};
|
||||
|
||||
const updateLogsById = async ({ sessionId, logs }: TUpdateSessionLogsDTO, actor: OrgServiceActor) => {
|
||||
const orgLicensePlan = await licenseService.getPlan(actor.orgId);
|
||||
if (!orgLicensePlan.pam) {
|
||||
throw new BadRequestError({
|
||||
message: "PAM operation failed due to organization plan restrictions."
|
||||
});
|
||||
}
|
||||
|
||||
// To be hit by gateways only
|
||||
if (actor.type !== ActorType.IDENTITY) {
|
||||
throw new ForbiddenRequestError({ message: "Only gateways can perform this action" });
|
||||
|
||||
@@ -2450,14 +2450,12 @@ export const registerRoutes = async (
|
||||
|
||||
const pamFolderService = pamFolderServiceFactory({
|
||||
pamFolderDAL,
|
||||
permissionService,
|
||||
licenseService
|
||||
permissionService
|
||||
});
|
||||
|
||||
const pamResourceService = pamResourceServiceFactory({
|
||||
pamResourceDAL,
|
||||
permissionService,
|
||||
licenseService,
|
||||
kmsService,
|
||||
gatewayV2Service
|
||||
});
|
||||
@@ -2479,7 +2477,6 @@ export const registerRoutes = async (
|
||||
pamAccountDAL,
|
||||
gatewayV2Service,
|
||||
kmsService,
|
||||
licenseService,
|
||||
pamFolderDAL,
|
||||
pamResourceDAL,
|
||||
pamSessionDAL,
|
||||
@@ -2505,7 +2502,6 @@ export const registerRoutes = async (
|
||||
pamSessionDAL,
|
||||
projectDAL,
|
||||
permissionService,
|
||||
licenseService,
|
||||
kmsService
|
||||
});
|
||||
|
||||
@@ -2515,8 +2511,7 @@ export const registerRoutes = async (
|
||||
aiMcpServerUserCredentialDAL,
|
||||
kmsService,
|
||||
keyStore,
|
||||
permissionService,
|
||||
licenseService
|
||||
permissionService
|
||||
});
|
||||
|
||||
const aiMcpActivityLogService = aiMcpActivityLogServiceFactory({
|
||||
@@ -2537,8 +2532,7 @@ export const registerRoutes = async (
|
||||
authTokenService: tokenService,
|
||||
aiMcpActivityLogService,
|
||||
userDAL,
|
||||
permissionService,
|
||||
licenseService
|
||||
permissionService
|
||||
});
|
||||
|
||||
const migrationService = externalMigrationServiceFactory({
|
||||
|
||||
@@ -62,6 +62,4 @@ export type SubscriptionPlan = {
|
||||
cardDeclinedReason?: string;
|
||||
cardDeclinedDays?: number;
|
||||
machineIdentityAuthTemplates: boolean;
|
||||
pam: boolean;
|
||||
ai: boolean;
|
||||
};
|
||||
|
||||
@@ -1,112 +1,87 @@
|
||||
import { useEffect } from "react";
|
||||
import { Link, Outlet, useLocation } from "@tanstack/react-router";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { Tab, TabList, Tabs } from "@app/components/v2";
|
||||
import { useOrganization, useProject, useProjectPermission, useSubscription } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useOrganization, useProject, useProjectPermission } from "@app/context";
|
||||
|
||||
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
|
||||
|
||||
export const AILayout = () => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentProject } = useProject();
|
||||
const { subscription } = useSubscription();
|
||||
const { assumedPrivilegeDetails } = useProjectPermission();
|
||||
const location = useLocation();
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"]);
|
||||
|
||||
useEffect(() => {
|
||||
if (subscription && !subscription.ai) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
description:
|
||||
"Your current plan does not provide access to Infisical AI. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
}
|
||||
}, [subscription]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
|
||||
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-project-items"
|
||||
initial={{ x: -150 }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: -150 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="px-4"
|
||||
>
|
||||
<nav className="w-full">
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/overview"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>MCP</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive ||
|
||||
location.pathname.match(/\/groups\/|\/identities\/|\/members\/|\/roles\//)
|
||||
? "selected"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
Access Control
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Audit Logs</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Settings</Tab>}
|
||||
</Link>
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</nav>
|
||||
</motion.div>
|
||||
</div>
|
||||
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
|
||||
<div className="flex-1 overflow-x-hidden overflow-y-auto bg-bunker-800 px-12 pt-10 pb-4">
|
||||
<Outlet />
|
||||
</div>
|
||||
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
|
||||
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-project-items"
|
||||
initial={{ x: -150 }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: -150 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="px-4"
|
||||
>
|
||||
<nav className="w-full">
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/overview"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>MCP</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive ||
|
||||
location.pathname.match(/\/groups\/|\/identities\/|\/members\/|\/roles\//)
|
||||
? "selected"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
Access Control
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Audit Logs</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/ai/$projectId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Settings</Tab>}
|
||||
</Link>
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</nav>
|
||||
</motion.div>
|
||||
</div>
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("upgradePlan", isOpen);
|
||||
}}
|
||||
text={popUp.upgradePlan.data?.description}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
/>
|
||||
</>
|
||||
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
|
||||
<div className="flex-1 overflow-x-hidden overflow-y-auto bg-bunker-800 px-12 pt-10 pb-4">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,147 +1,122 @@
|
||||
import { useEffect } from "react";
|
||||
import { Link, Outlet, useLocation } from "@tanstack/react-router";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { Tab, TabList, Tabs } from "@app/components/v2";
|
||||
import { useOrganization, useProject, useProjectPermission, useSubscription } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useOrganization, useProject, useProjectPermission } from "@app/context";
|
||||
|
||||
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
|
||||
|
||||
export const PamLayout = () => {
|
||||
const { currentProject } = useProject();
|
||||
const { currentOrg } = useOrganization();
|
||||
const { subscription } = useSubscription();
|
||||
const { assumedPrivilegeDetails } = useProjectPermission();
|
||||
const location = useLocation();
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"]);
|
||||
|
||||
useEffect(() => {
|
||||
if (subscription && !subscription.pam) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
description:
|
||||
"Your current plan does not provide access to Infisical PAM. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
}
|
||||
}, [subscription]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
|
||||
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-project-items"
|
||||
initial={{ x: -150 }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: -150 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="px-4"
|
||||
>
|
||||
<nav className="w-full">
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/accounts"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Accounts</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/resources"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Resources</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/sessions"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Sessions</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/approvals"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive || location.pathname.match(/\/approvals\/|\/i/) ? "selected" : ""
|
||||
}
|
||||
>
|
||||
Approvals
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive ||
|
||||
location.pathname.match(/\/groups\/|\/identities\/|\/members\/|\/roles\//)
|
||||
? "selected"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
Access Control
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Audit Logs</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Settings</Tab>}
|
||||
</Link>
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</nav>
|
||||
</motion.div>
|
||||
</div>
|
||||
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
|
||||
<div className="flex-1 overflow-x-hidden overflow-y-auto bg-bunker-800 px-12 pt-10 pb-4">
|
||||
<Outlet />
|
||||
</div>
|
||||
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
|
||||
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-project-items"
|
||||
initial={{ x: -150 }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: -150 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="px-4"
|
||||
>
|
||||
<nav className="w-full">
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/accounts"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Accounts</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/resources"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Resources</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/sessions"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Sessions</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/approvals"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive || location.pathname.match(/\/approvals\/|\/i/) ? "selected" : ""
|
||||
}
|
||||
>
|
||||
Approvals
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
value={
|
||||
isActive ||
|
||||
location.pathname.match(/\/groups\/|\/identities\/|\/members\/|\/roles\//)
|
||||
? "selected"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
Access Control
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Audit Logs</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/organizations/$orgId/projects/pam/$projectId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Settings</Tab>}
|
||||
</Link>
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</nav>
|
||||
</motion.div>
|
||||
</div>
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("upgradePlan", isOpen);
|
||||
}}
|
||||
text={popUp.upgradePlan.data?.description}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
/>
|
||||
</>
|
||||
{assumedPrivilegeDetails && <AssumePrivilegeModeBanner />}
|
||||
<div className="flex-1 overflow-x-hidden overflow-y-auto bg-bunker-800 px-12 pt-10 pb-4">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,16 +2,10 @@ import { useState } from "react";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||
import {
|
||||
ProjectPermissionMcpEndpointActions,
|
||||
ProjectPermissionSub,
|
||||
useSubscription
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { ProjectPermissionMcpEndpointActions, ProjectPermissionSub } from "@app/context";
|
||||
import { TAiMcpEndpoint, useDeleteAiMcpEndpoint } from "@app/hooks/api";
|
||||
|
||||
import { AddMCPEndpointModal } from "./AddMCPEndpointModal";
|
||||
@@ -24,18 +18,9 @@ export const MCPEndpointsTab = () => {
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [selectedEndpoint, setSelectedEndpoint] = useState<TAiMcpEndpoint | null>(null);
|
||||
|
||||
const { subscription } = useSubscription();
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"]);
|
||||
const deleteEndpoint = useDeleteAiMcpEndpoint();
|
||||
|
||||
const handleCreateEndpoint = () => {
|
||||
if (subscription && !subscription.ai) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "Your current plan does not include access to Infisical AI. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
setIsCreateModalOpen(true);
|
||||
};
|
||||
|
||||
@@ -130,13 +115,6 @@ export const MCPEndpointsTab = () => {
|
||||
onDeleteApproved={handleDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||
text={popUp.upgradePlan.data?.text}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,12 +2,10 @@ import { useState } from "react";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useSubscription } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { TAiMcpServer, useDeleteAiMcpServer } from "@app/hooks/api";
|
||||
|
||||
import { AddMCPServerModal } from "./AddMCPServerModal";
|
||||
@@ -20,18 +18,9 @@ export const MCPServersTab = () => {
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [selectedServer, setSelectedServer] = useState<TAiMcpServer | null>(null);
|
||||
|
||||
const { subscription } = useSubscription();
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"]);
|
||||
const deleteServer = useDeleteAiMcpServer();
|
||||
|
||||
const handleAddServer = () => {
|
||||
if (subscription && !subscription.ai) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "Your current plan does not include access to Infisical AI. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
setIsAddModalOpen(true);
|
||||
};
|
||||
|
||||
@@ -123,13 +112,6 @@ export const MCPServersTab = () => {
|
||||
onDeleteApproved={handleDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||
text={popUp.upgradePlan.data?.text}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { EmptyState, Input, Pagination, Spinner, Tooltip } from "@app/components/v2";
|
||||
import { useSubscription } from "@app/context";
|
||||
import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks";
|
||||
import {
|
||||
PAM_RESOURCE_TYPE_MAP,
|
||||
@@ -18,7 +17,6 @@ type Props = {
|
||||
|
||||
export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
const { isPending, data: resourceOptions } = useListPamResourceOptions();
|
||||
const { subscription } = useSubscription();
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
|
||||
|
||||
const appendedResourceOptions = useMemo(() => {
|
||||
@@ -65,14 +63,6 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
});
|
||||
|
||||
const handleResourceSelect = (resource: PamResourceType) => {
|
||||
if (!subscription.pam) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "Your current plan does not include access to Infisical PAM. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// We temporarily show a special license modal for these because we will have to write some code to complete the integration
|
||||
if (
|
||||
resource === PamResourceType.RDP ||
|
||||
|
||||
Reference in New Issue
Block a user