Merge branch 'main' into ENG-4021

This commit is contained in:
x032205
2025-11-03 14:06:57 -05:00
635 changed files with 18573 additions and 8076 deletions
@@ -5,6 +5,7 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import { Button, DeleteActionModal } from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import { OrgPermissionGroupActions, OrgPermissionSubjects, useSubscription } from "@app/context";
import { useDeleteGroup } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp";
@@ -26,8 +27,8 @@ export const OrgGroupsSection = () => {
const handleAddGroupModal = () => {
if (!subscription?.groups) {
handlePopUpOpen("upgradePlan", {
description:
"You can manage users more efficiently with groups if you upgrade your Infisical plan to an Enterprise license."
text: "Your current plan does not allow adding groups. To unlock this feature, please upgrade to Infisical Enterprise plan.",
isEnterpriseFeature: true
});
} else {
handlePopUpOpen("group");
@@ -57,7 +58,10 @@ export const OrgGroupsSection = () => {
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<p className="text-xl font-medium text-mineshaft-100">Groups</p>
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Groups</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups" />
</div>
<OrgPermissionCan I={OrgPermissionGroupActions.Create} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => (
<Button
@@ -92,7 +96,8 @@ export const OrgGroupsSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
text={popUp.upgradePlan?.data?.text}
/>
</div>
);
@@ -55,7 +55,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -277,7 +280,9 @@ export const IdentityAliCloudAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -292,7 +297,9 @@ export const IdentityAliCloudAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -315,7 +322,9 @@ export const IdentityAliCloudAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -4,7 +4,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { Badge, FormControl, Select, SelectItem, Tooltip } from "@app/components/v2";
import { FormControl, Select, SelectItem, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -277,7 +278,7 @@ export const IdentityAuthMethodModalContent = ({
>
{label}{" "}
{alreadyConfigured && !isSelectedAuthAlreadyConfigured && (
<Badge>Configured</Badge>
<Badge variant="info">Configured</Badge>
)}
</SelectItem>
</Tooltip>
@@ -291,7 +292,8 @@ export const IdentityAuthMethodModalContent = ({
<UpgradePlanModal
isOpen={popUp?.upgradePlan?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use IP allowlisting if you switch to Infisical's Pro plan."
text={`Your current plan does not include access to ${popUp.upgradePlan.data?.featureName}. To unlock this feature, please upgrade to Infisical ${popUp.upgradePlan.data?.isEnterpriseFeature ? "Enterprise" : "Pro"} plan.`}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</>
);
@@ -57,7 +57,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -315,7 +318,9 @@ export const IdentityAwsAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -330,7 +335,9 @@ export const IdentityAwsAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -353,7 +360,9 @@ export const IdentityAwsAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -52,7 +52,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -311,7 +314,9 @@ export const IdentityAzureAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -326,7 +331,9 @@ export const IdentityAzureAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -349,7 +356,9 @@ export const IdentityAzureAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -55,7 +55,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -350,7 +353,9 @@ export const IdentityGcpAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -365,7 +370,9 @@ export const IdentityGcpAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -388,7 +395,9 @@ export const IdentityGcpAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -88,7 +88,10 @@ const schema = z.discriminatedUnion("configurationType", [
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -619,7 +622,9 @@ export const IdentityJwtAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -634,7 +639,9 @@ export const IdentityJwtAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -657,7 +664,9 @@ export const IdentityJwtAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -22,11 +22,12 @@ import {
TextArea,
Tooltip
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import { useOrganization, useOrgPermission, useSubscription } from "@app/context";
import {
OrgGatewayPermissionActions,
OrgPermissionSubjects
} from "@app/context/OrgPermissionContext/types";
import { OrgMembershipRole } from "@app/helpers/roles";
import {
gatewaysQueryKeys,
useAddIdentityKubernetesAuth,
@@ -95,7 +96,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -129,6 +133,8 @@ export const IdentityKubernetesAuthForm = ({
] as const);
const { data: vaultConfigs = [] } = useGetVaultExternalMigrationConfigs();
const hasVaultConnection = vaultConfigs.some((config) => config.connectionId);
const { hasOrgRole } = useOrgPermission();
const isOrgAdmin = hasOrgRole(OrgMembershipRole.Admin);
const {
control,
@@ -409,20 +415,29 @@ export const IdentityKubernetesAuthForm = ({
<FontAwesomeIcon icon={faInfoCircle} className="mt-0.5 text-primary" />
<span className="text-mineshaft-200">Load values from HashiCorp Vault</span>
</div>
<Button
variant="outline_bg"
size="xs"
leftIcon={
<img
src="/images/integrations/Vault.png"
alt="HashiCorp Vault"
className="h-4 w-4"
/>
<Tooltip
content={
!isOrgAdmin
? "Only organization admins can import configurations from HashiCorp Vault"
: undefined
}
onClick={() => handleImportPopUpToggle("importFromVault", true)}
>
Load from Vault
</Button>
<Button
variant="outline_bg"
size="xs"
leftIcon={
<img
src="/images/integrations/Vault.png"
alt="HashiCorp Vault"
className="h-4 w-4"
/>
}
onClick={() => handleImportPopUpToggle("importFromVault", true)}
isDisabled={!isOrgAdmin}
>
Load from Vault
</Button>
</Tooltip>
</div>
)}
<div className="flex w-full items-center gap-2">
@@ -695,7 +710,9 @@ export const IdentityKubernetesAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -710,7 +727,9 @@ export const IdentityKubernetesAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -733,7 +752,9 @@ export const IdentityKubernetesAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -147,7 +147,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { isEnterpriseFeature?: boolean; featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -304,7 +307,10 @@ export const IdentityLdapAuthForm = ({
useEffect(() => {
if (!subscription?.ldap) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true,
featureName: "LDAP authentication"
});
handlePopUpToggle("identityAuthMethod", false);
}
}, [subscription, handlePopUpOpen, handlePopUpToggle]);
@@ -831,7 +837,9 @@ export const IdentityLdapAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -846,7 +854,9 @@ export const IdentityLdapAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -869,7 +879,9 @@ export const IdentityLdapAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -63,7 +63,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -297,7 +300,9 @@ export const IdentityOciAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -312,7 +317,9 @@ export const IdentityOciAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -335,7 +342,9 @@ export const IdentityOciAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -75,7 +75,10 @@ const schema = z.object({
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -606,7 +609,9 @@ export const IdentityOidcAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -621,7 +626,9 @@ export const IdentityOidcAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -644,7 +651,9 @@ export const IdentityOidcAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -1,15 +1,11 @@
import {
faArrowUpRightFromSquare,
faBookOpen,
faLink,
faPlus
} from "@fortawesome/free-solid-svg-icons";
import { faLink, 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 { OrgPermissionCan } from "@app/components/permissions";
import { Button, DeleteActionModal, Modal, ModalContent } from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import {
OrgPermissionIdentityActions,
OrgPermissionSubjects,
@@ -113,22 +109,9 @@ export const IdentitySection = withPermission(
<div>
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex w-full items-center gap-4">
<div className="flex flex-1 items-center gap-1">
<div className="flex flex-1 items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
<a
href="https://infisical.com/docs/documentation/platform/identities/overview"
target="_blank"
rel="noopener noreferrer"
>
<div className="mt-[0.16rem] ml-1 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div>
{isSubOrganization && (
<OrgPermissionCan
@@ -162,8 +145,7 @@ export const IdentitySection = withPermission(
onClick={() => {
if (!isMoreIdentitiesAllowed && !isEnterprise) {
handlePopUpOpen("upgradePlan", {
description:
"You can add more identities if you upgrade your Infisical plan."
text: "You have reached the maximum number of identities allowed on your current plan. Upgrade to Infisical Pro plan to add more identities."
});
return;
}
@@ -181,22 +163,9 @@ export const IdentitySection = withPermission(
{/* Identity Auth Templates Section */}
<div className="mt-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-1">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Identity Auth Templates</p>
<a
href="https://infisical.com/docs/documentation/platform/identities/auth-templates"
target="_blank"
rel="noopener noreferrer"
>
<div className="mt-[0.16rem] ml-1 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/auth-templates" />
</div>
<OrgPermissionCan
I={OrgPermissionMachineIdentityAuthTemplateActions.CreateTemplates}
@@ -209,7 +178,10 @@ export const IdentitySection = withPermission(
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (subscription && !subscription.machineIdentityAuthTemplates) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true,
text: "Your current plan does not include access to creating Identity Auth Templates. To unlock this feature, please upgrade to Infisical Enterprise plan."
});
return;
}
handlePopUpOpen("createTemplate");
@@ -279,7 +251,8 @@ export const IdentitySection = withPermission(
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use Identity Auth Templates if you switch to Infisical's Enterprise plan."
text={popUp.upgradePlan.data?.text}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -50,7 +50,10 @@ const schema = z.object({
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -286,7 +289,9 @@ export const IdentityTlsCertAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -301,7 +306,9 @@ export const IdentityTlsCertAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -324,7 +331,9 @@ export const IdentityTlsCertAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -49,7 +49,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -248,7 +251,9 @@ export const IdentityTokenAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -263,7 +268,9 @@ export const IdentityTokenAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -286,7 +293,9 @@ export const IdentityTokenAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -87,7 +87,10 @@ const schema = z
export type FormData = z.infer<typeof schema>;
type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["upgradePlan"]>,
data?: { featureName?: string }
) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
@@ -409,7 +412,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -424,7 +429,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -447,7 +454,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -477,7 +486,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
placeholder="123.456.789.0"
/>
@@ -492,7 +503,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
size="lg"
colorSchema="danger"
@@ -515,7 +528,9 @@ export const IdentityUniversalAuthForm = ({
return;
}
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
featureName: "IP allowlisting"
});
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
@@ -1,13 +1,13 @@
import { useState } from "react";
import { faBan, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { BanIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Badge,
Button,
DeleteActionModal,
EmailServiceSetupModal,
@@ -15,6 +15,7 @@ import {
ModalContent,
Tooltip
} from "@app/components/v2";
import { Badge, DocumentationLinkBadge } from "@app/components/v3";
import {
OrgPermissionActions,
OrgPermissionSubjects,
@@ -75,7 +76,7 @@ export const OrgMembersSection = () => {
if (!isMoreIdentitiesAllowed && !isEnterprise) {
handlePopUpOpen("upgradePlan", {
description: "You can add more members if you upgrade your Infisical plan."
text: "You have reached the maximum number of members allowed on your current plan. Upgrade to Infisical Pro plan to add more members."
});
return;
}
@@ -207,7 +208,10 @@ export const OrgMembersSection = () => {
</div>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<p className="text-xl font-medium text-mineshaft-100">Users</p>
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Users</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
{(isAllowed) => (
<Button
@@ -303,15 +307,10 @@ export const OrgMembersSection = () => {
</p>
{userId === member.user.id && (
<Tooltip content="You cannot remove yourself from this organization">
<div className="inline-block">
<Badge
variant="danger"
className="mt-[0.05rem] ml-1 inline-flex w-min items-center gap-1.5 whitespace-nowrap"
>
<FontAwesomeIcon icon={faBan} />
<span>Ignored</span>
</Badge>
</div>
<Badge variant="danger" className="ml-2">
<BanIcon />
Ignored
</Badge>
</Tooltip>
)}
</div>
@@ -324,7 +323,7 @@ export const OrgMembersSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
text={popUp.upgradePlan?.data?.text}
/>
<EmailServiceSetupModal
isOpen={popUp.setUpEmail?.isOpen}
@@ -11,19 +11,18 @@ import {
faMagnifyingGlass,
faSearch,
faUsers,
faUserShield,
faUserSlash,
faUserXmark
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { UserCogIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { LastLoginSection } from "@app/components/organization/LastLoginSection";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Badge,
Button,
Checkbox,
DropdownMenu,
@@ -50,6 +49,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import {
OrgPermissionActions,
OrgPermissionSubjects,
@@ -82,7 +82,7 @@ type Props = {
data?: {
orgMembershipId?: string;
username?: string;
description?: string;
text?: string;
selectedOrgMemberships?: OrgUser[];
}
) => void;
@@ -133,7 +133,7 @@ export const OrgMembersTable = ({
if (isCustomRole && subscription && !subscription?.rbac) {
handlePopUpOpen("upgradePlan", {
description: "You can assign custom roles to members if you upgrade your Infisical plan."
text: "Your current plan does not include access to assigning custom roles to members. To unlock this feature, please upgrade to Infisical Pro plan."
});
return;
}
@@ -519,17 +519,17 @@ export const OrgMembersTable = ({
<Td
className={twMerge("group max-w-0", isActive ? "" : "text-mineshaft-400")}
>
<div className="flex items-center">
<div className="flex items-center gap-x-2">
<p className="truncate">
{name ?? <span className="text-mineshaft-400">Not Set</span>}
</p>
{u.superAdmin && (
<Badge variant="primary" className="ml-2 w-min whitespace-nowrap">
<span className="mr-1 hidden xl:inline">Server Admin</span>
<Tooltip content="Server Admin">
<FontAwesomeIcon className="xl:hidden" icon={faUserShield} />
</Tooltip>
</Badge>
<Tooltip content="Server Admin">
<Badge variant="info">
<UserCogIcon />
<span className="hidden xl:inline">Server Admin</span>
</Badge>
</Tooltip>
)}
{lastLoginAuthMethod && lastLoginTime && (
<Tooltip
@@ -14,13 +14,13 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { ServerIcon, WrenchIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Badge,
Button,
DeleteActionModal,
DropdownMenu,
@@ -41,13 +41,14 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge, DocumentationLinkBadge } from "@app/components/v3";
import {
OrgPermissionActions,
OrgPermissionSubjects,
useOrganization,
useSubscription
} from "@app/context";
import { isCustomOrgRole, isCustomProjectRole } from "@app/helpers/roles";
import { isCustomOrgRole } from "@app/helpers/roles";
import {
getUserTablePreference,
PreferenceKey,
@@ -103,8 +104,7 @@ export const OrgRoleTable = () => {
if (isCustomRole && subscription && !subscription?.rbac) {
handlePopUpOpen("upgradePlan", {
description:
"You can set the default org role to a custom role if you upgrade your Infisical plan."
text: "Your current plan does not include access to set a custom default organization role. To unlock this feature, please upgrade to Infisical Pro plan."
});
return;
}
@@ -200,9 +200,12 @@ export const OrgRoleTable = () => {
return (
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<p className="text-xl font-medium text-mineshaft-100">
{isSubOrganization ? "Sub-" : ""}Organization Roles
</p>
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">
{isSubOrganization ? "Sub-" : ""}Organization Roles
</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/organization#roles-and-access-control" />
</div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Role}>
{(isAllowed) => (
<Button
@@ -295,17 +298,13 @@ export const OrgRoleTable = () => {
}
>
<Td className="max-w-md">
<div className="flex">
<div className="flex gap-x-1.5">
<p className="overflow-hidden text-ellipsis whitespace-nowrap">{name}</p>
{isDefaultOrgRole && (
<Tooltip
content={`Members joining your organization will be assigned the ${name} role unless otherwise specified.`}
>
<div>
<Badge variant="success" className="ml-1">
Default
</Badge>
</div>
<Badge variant="info">Default</Badge>
</Tooltip>
)}
</div>
@@ -314,8 +313,18 @@ export const OrgRoleTable = () => {
{slug}
</Td>
<Td>
<Badge className="w-min bg-mineshaft-400/50 whitespace-nowrap text-bunker-200">
{isCustomProjectRole(slug) ? "Custom" : "Default"}
<Badge variant="ghost">
{isCustomOrgRole(slug) ? (
<>
<WrenchIcon />
Custom
</>
) : (
<>
<ServerIcon />
Platform
</>
)}
</Badge>
</Td>
<Td>
@@ -461,7 +470,7 @@ export const OrgRoleTable = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
text={popUp.upgradePlan?.data?.text}
/>
<DuplicateOrgRoleModal
isOpen={popUp.duplicateRole.isOpen}
@@ -20,6 +20,7 @@ import { AzureKeyVaultConnectionForm } from "./AzureKeyVaultConnectionForm";
import { BitbucketConnectionForm } from "./BitbucketConnectionForm";
import { CamundaConnectionForm } from "./CamundaConnectionForm";
import { ChecklyConnectionForm } from "./ChecklyConnectionForm";
import { ChefConnectionForm } from "./ChefConnectionForm";
import { CloudflareConnectionForm } from "./CloudflareConnectionForm";
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
import { DigitalOceanConnectionForm } from "./DigitalOceanConnectionForm";
@@ -36,6 +37,7 @@ import { LdapConnectionForm } from "./LdapConnectionForm";
import { MsSqlConnectionForm } from "./MsSqlConnectionForm";
import { MySqlConnectionForm } from "./MySqlConnectionForm";
import { NetlifyConnectionForm } from "./NetlifyConnectionForm";
import { NorthflankConnectionForm } from "./NorthflankConnectionForm";
import { OCIConnectionForm } from "./OCIConnectionForm";
import { OktaConnectionForm } from "./OktaConnectionForm";
import { OracleDBConnectionForm } from "./OracleDBConnectionForm";
@@ -163,12 +165,16 @@ const CreateForm = ({ app, onComplete, projectId }: CreateFormProps) => {
return <RailwayConnectionForm onSubmit={onSubmit} />;
case AppConnection.Checkly:
return <ChecklyConnectionForm onSubmit={onSubmit} />;
case AppConnection.Chef:
return <ChefConnectionForm onSubmit={onSubmit} />;
case AppConnection.Supabase:
return <SupabaseConnectionForm onSubmit={onSubmit} />;
case AppConnection.DigitalOcean:
return <DigitalOceanConnectionForm onSubmit={onSubmit} />;
case AppConnection.Netlify:
return <NetlifyConnectionForm onSubmit={onSubmit} />;
case AppConnection.Northflank:
return <NorthflankConnectionForm onSubmit={onSubmit} />;
case AppConnection.Okta:
return <OktaConnectionForm onSubmit={onSubmit} />;
case AppConnection.Redis:
@@ -326,10 +332,14 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
return <RailwayConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Checkly:
return <ChecklyConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Chef:
return <ChefConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Supabase:
return <SupabaseConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.DigitalOcean:
return <DigitalOceanConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Northflank:
return <NorthflankConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Okta:
return <OktaConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Redis:
@@ -0,0 +1,195 @@
import { Controller, FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Button,
FormControl,
Input,
ModalClose,
SecretInput,
Select,
SelectItem
} from "@app/components/v2";
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
import { ChefConnectionMethod, TChefConnection } from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import {
genericAppConnectionFieldsSchema,
GenericAppConnectionsFields
} from "./GenericAppConnectionFields";
type Props = {
appConnection?: TChefConnection;
onSubmit: (formData: FormData) => Promise<void>;
};
const rootSchema = genericAppConnectionFieldsSchema.extend({
app: z.literal(AppConnection.Chef)
});
const formSchema = z.discriminatedUnion("method", [
rootSchema.extend({
method: z.literal(ChefConnectionMethod.UserKey),
credentials: z.object({
serverUrl: z.string().trim().url("Valid Chef Server URL required").optional(),
orgName: z.string().trim().min(1, "Organization name required"),
userName: z.string().trim().min(1, "User name required"),
privateKey: z.string().trim().min(1, "Private key required")
})
})
]);
type FormData = z.infer<typeof formSchema>;
export const ChefConnectionForm = ({ appConnection, onSubmit }: Props) => {
const isUpdate = Boolean(appConnection);
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: appConnection ?? {
app: AppConnection.Chef,
method: ChefConnectionMethod.UserKey
}
});
const {
handleSubmit,
control,
formState: { isSubmitting, isDirty }
} = form;
return (
<FormProvider {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
{!isUpdate && <GenericAppConnectionsFields />}
<Controller
name="credentials.serverUrl"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Chef Server URL (optional)"
tooltipText="Will default to Chef Cloud if not specified."
>
<Input
placeholder="https://api.chef.io"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<Controller
name="method"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipText={`The method you would like to use to connect with ${
APP_CONNECTION_MAP[AppConnection.Chef].name
}. This field cannot be changed after creation.`}
errorText={error?.message}
isError={Boolean(error?.message)}
label="Method"
>
<Select
isDisabled={isUpdate}
value={value}
onValueChange={(val) => onChange(val)}
className="w-full border border-mineshaft-500"
position="popper"
dropdownContainerClassName="max-w-none"
>
{Object.values(ChefConnectionMethod).map((method) => {
return (
<SelectItem value={method} key={method}>
{getAppConnectionMethodDetails(method).name}{" "}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
<Controller
name="credentials.orgName"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Organization Short Name"
>
<Input
className="border border-mineshaft-500 bg-mineshaft-900"
placeholder="your-org"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<Controller
name="credentials.userName"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="User Name"
>
<Input
className="border border-mineshaft-500 bg-mineshaft-900"
placeholder="your-username"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<Controller
name="credentials.privateKey"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Private Key"
tooltipText="Your Chef user's private key (.pem file)"
>
<SecretInput
containerClassName="text-gray-400 group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<div className="mt-8 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
colorSchema="secondary"
isLoading={isSubmitting}
isDisabled={isSubmitting || !isDirty}
>
{isUpdate ? "Update Credentials" : "Connect to Chef"}
</Button>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">
Cancel
</Button>
</ModalClose>
</div>
</form>
</FormProvider>
);
};
@@ -0,0 +1,135 @@
import { Controller, FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Button,
FormControl,
ModalClose,
SecretInput,
Select,
SelectItem
} from "@app/components/v2";
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import {
NorthflankConnectionMethod,
TNorthflankConnection
} from "@app/hooks/api/appConnections/types/northflank-connection";
import {
genericAppConnectionFieldsSchema,
GenericAppConnectionsFields
} from "./GenericAppConnectionFields";
type Props = {
appConnection?: TNorthflankConnection;
onSubmit: (formData: FormData) => void;
};
const rootSchema = genericAppConnectionFieldsSchema.extend({
app: z.literal(AppConnection.Northflank)
});
const formSchema = z.discriminatedUnion("method", [
rootSchema.extend({
method: z.literal(NorthflankConnectionMethod.ApiToken),
credentials: z.object({
apiToken: z.string().trim().min(1, "API Token required")
})
})
]);
type FormData = z.infer<typeof formSchema>;
export const NorthflankConnectionForm = ({ appConnection, onSubmit }: Props) => {
const isUpdate = Boolean(appConnection);
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: appConnection ?? {
app: AppConnection.Northflank,
method: NorthflankConnectionMethod.ApiToken
}
});
const {
handleSubmit,
control,
formState: { isSubmitting, isDirty }
} = form;
return (
<FormProvider {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
{!isUpdate && <GenericAppConnectionsFields />}
<Controller
name="method"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipText={`The method you would like to use to connect with ${
APP_CONNECTION_MAP[AppConnection.Northflank].name
}. This field cannot be changed after creation.`}
errorText={error?.message}
isError={Boolean(error?.message)}
label="Method"
>
<Select
isDisabled={isUpdate}
value={value}
onValueChange={(val) => onChange(val)}
className="w-full border border-mineshaft-500"
position="popper"
dropdownContainerClassName="max-w-none"
>
{Object.values(NorthflankConnectionMethod).map((method) => {
return (
<SelectItem value={method} key={method}>
{getAppConnectionMethodDetails(method).name}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
<Controller
name="credentials.apiToken"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="API Token"
>
<SecretInput
containerClassName="text-gray-400 group-focus-within:border-primary-400/50! border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<div className="mt-8 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
colorSchema="secondary"
isLoading={isSubmitting}
isDisabled={isSubmitting || !isDirty}
>
{isUpdate ? "Update Credentials" : "Connect to Northflank"}
</Button>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">
Cancel
</Button>
</ModalClose>
</div>
</form>
</FormProvider>
);
};
@@ -1,6 +1,6 @@
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { DocumentationLinkBadge } from "@app/components/v3";
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
@@ -29,23 +29,11 @@ export const AppConnectionHeader = ({ app, isConnected, onBack }: Props) => {
)}
</div>
<div>
<div className="flex items-center text-mineshaft-300">
<div className="flex items-center gap-x-2 text-mineshaft-300">
{appDetails.name}
<a
<DocumentationLinkBadge
href={`https://infisical.com/docs/integrations/app-connections/${app}`}
target="_blank"
className="mb-1 ml-1"
rel="noopener noreferrer"
>
<div className="inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1 mb-[0.03rem] text-[12px]" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1 text-[10px]"
/>
</div>
</a>
/>
</div>
<p className="text-sm leading-4 text-mineshaft-400">
{isConnected ? `${appDetails.name} Connection` : `Connect to ${appDetails.name}`}
@@ -72,10 +72,13 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
return (
<button
key={option.app}
type="button"
onClick={() =>
enterprise && !subscription.enterpriseAppConnections
? handlePopUpOpen("upgradePlan")
? handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
})
: onSelect(option.app)
}
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
@@ -166,7 +169,8 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use every App Connection if you switch to Infisical's Enterprise plan."
text="All App Connections can be unlocked if you switch to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -8,18 +8,17 @@ import {
faEdit,
faEllipsisV,
faInfoCircle,
faServer,
faTable,
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link } from "@tanstack/react-router";
import { ServerIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { VariablePermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -29,6 +28,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { OrgPermissionSubjects, ProjectPermissionSub } from "@app/context";
import { OrgPermissionAppConnectionActions } from "@app/context/OrgPermissionContext/types";
import { ProjectPermissionAppConnectionActions } from "@app/context/ProjectPermissionContext/types";
@@ -157,9 +157,9 @@ export const AppConnectionRow = ({
{isPlatformManagedCredentials && (
<Tooltip side="left" content="This connection's credentials are managed by Infisical.">
<div>
<Badge className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap">
<FontAwesomeIcon icon={faServer} />
<span>Platform Managed Credentials</span>
<Badge variant="info">
<ServerIcon />
Platform Managed Credentials
</Badge>
</div>
</Tooltip>
@@ -2,8 +2,6 @@ import { useMemo, useState } from "react";
import {
faArrowDown,
faArrowUp,
faArrowUpRightFromSquare,
faBookOpen,
faCheckCircle,
faFilter,
faMagnifyingGlass,
@@ -34,6 +32,7 @@ import {
THead,
Tr
} from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import { OrgPermissionSubjects, ProjectPermissionSub } from "@app/context";
import { OrgPermissionAppConnectionActions } from "@app/context/OrgPermissionContext/types";
import { ProjectPermissionAppConnectionActions } from "@app/context/ProjectPermissionContext/types";
@@ -212,22 +211,9 @@ export const AppConnectionsTable = ({ projectId, projectType }: Props) => {
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<div>
<div className="flex items-center gap-1">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">App Connections</p>
<a
href="https://infisical.com/docs/integrations/app-connections/overview"
target="_blank"
rel="noopener noreferrer"
>
<div className="mt-[0.12rem] ml-1 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/integrations/app-connections/overview" />
</div>
<p className="text-sm text-bunker-300">
Create and configure connections with third-party apps for re-use across your project
@@ -633,7 +633,9 @@ export const OAuthCallbackPage = () => {
connectionName: data.connection.name,
...(data.returnUrl.includes("integrations")
? {
selectedTab: IntegrationsListPageTabs.SecretSyncs
selectedTab: localStorage.getItem("pkiSyncFormData")
? IntegrationsListPageTabs.PkiSyncs
: IntegrationsListPageTabs.SecretSyncs
}
: {})
}
@@ -8,7 +8,6 @@ import { AnimatePresence, motion } from "framer-motion";
import { twMerge } from "tailwind-merge";
import {
Badge,
Button,
DropdownMenu,
DropdownMenuContent,
@@ -20,6 +19,7 @@ import {
Select,
SelectItem
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useOrganization } from "@app/context";
import { useGetUserProjects } from "@app/hooks/api";
import {
@@ -124,7 +124,7 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
<Button variant="outline_bg" colorSchema="primary" className="relative">
<FontAwesomeIcon icon={faFilterCircleXmark} />
{activeFilterCount > 0 && (
<Badge className="absolute right-0 bottom-0" variant="primary">
<Badge className="absolute -top-2 -right-2" variant="info">
{activeFilterCount}
</Badge>
)}
@@ -137,7 +137,7 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
<div className="flex w-full items-center justify-between">
<div className="flex items-center gap-2">
<span>Filters</span>
<Badge className="px-1.5 py-0.5" variant="primary">
<Badge isSquare variant="info">
{activeFilterCount}
</Badge>
</div>
@@ -1,9 +1,8 @@
import { useEffect, useState } from "react";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import ms from "ms";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { DocumentationLinkBadge } from "@app/components/v3";
import {
OrgPermissionAuditLogsActions,
OrgPermissionSubjects,
@@ -76,22 +75,9 @@ const LogsSectionComponent = ({
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-y-2">
<div>
<div className="flex items-center gap-1 whitespace-nowrap">
<div className="flex items-center gap-x-2 whitespace-nowrap">
<p className="text-xl font-medium text-mineshaft-100">Audit History</p>
<a
href="https://infisical.com/docs/documentation/platform/audit-logs"
target="_blank"
rel="noopener noreferrer"
>
<div className="mt-[0.1rem] ml-1 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/audit-logs" />
</div>
</div>
<div className="flex flex-wrap items-center gap-2 lg:justify-end">
@@ -137,7 +123,7 @@ const LogsSectionComponent = ({
onOpenChange={(isOpen) => {
handlePopUpToggle("upgradePlan", isOpen);
}}
text="You can use audit logs if you switch to a paid Infisical plan."
text="Your current plan does not include access to audit logs. To unlock this feature, please upgrade to Infisical Pro plan."
/>
</div>
</div>
@@ -181,7 +167,7 @@ const LogsSectionComponent = ({
onOpenChange={(isOpen) => {
handlePopUpToggle("upgradePlan", isOpen);
}}
text="You can use audit logs if you switch to a paid Infisical plan."
text="Your current plan does not include access to audit logs. To unlock this feature, please upgrade to Infisical Pro plan."
/>
</div>
);
@@ -5,7 +5,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate, useParams } from "@tanstack/react-router";
import { twMerge } from "tailwind-merge";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
@@ -51,8 +50,7 @@ const Page = () => {
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"groupCreateUpdate",
"deleteGroup",
"upgradePlan"
"deleteGroup"
] as const);
const onDeleteGroupSubmit = async ({ name, id }: { name: string; id: string }) => {
@@ -184,11 +182,6 @@ const Page = () => {
onDeleteGroupSubmit(popUp?.deleteGroup?.data as { name: string; id: string })
}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
/>
</div>
);
};
@@ -120,7 +120,8 @@ const Page = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
text={`Your current plan does not include access to ${popUp.upgradePlan.data?.featureName}. To unlock this feature, please upgrade to Infisical ${popUp.upgradePlan.data?.isEnterpriseFeature ? "Enterprise" : "Pro"} plan.`}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
<DeleteActionModal
isOpen={popUp.deleteIdentity.isOpen}
@@ -183,7 +183,7 @@ export const Content = ({
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
text={`Your current plan does not include access to ${popUp.upgradePlan.data?.featureName}. To unlock this feature, please upgrade to Infisical ${popUp.upgradePlan.data?.isEnterpriseFeature ? "Enterprise" : "Pro"} plan.`}
/>
</>
);
@@ -1,7 +1,8 @@
import { faBan, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EyeIcon } from "lucide-react";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useGetIdentityJwtAuth } from "@app/hooks/api";
import { IdentityJwtConfigurationType } from "@app/hooks/api/identities/enums";
import { IdentityJwtAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm";
@@ -78,12 +79,10 @@ export const ViewIdentityJwtAuthContent = ({
<p className="rounded-sm bg-mineshaft-600 p-2 break-words">{data.jwksCaCert}</p>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -103,12 +102,10 @@ export const ViewIdentityJwtAuthContent = ({
</p>
}
>
<div className="inline-block w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Key {index + 1}</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Key {index + 1}
</Badge>
</Tooltip>
))}
</div>
@@ -138,12 +135,10 @@ export const ViewIdentityJwtAuthContent = ({
</pre>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -1,9 +1,10 @@
import { useMemo } from "react";
import { faBan, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBan } from "@fortawesome/free-solid-svg-icons";
import { useQuery } from "@tanstack/react-query";
import { EyeIcon } from "lucide-react";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { gatewaysQueryKeys, useGetIdentityKubernetesAuth } from "@app/hooks/api";
import { IdentityKubernetesAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm";
@@ -89,12 +90,10 @@ export const ViewIdentityKubernetesAuthContent = ({
</p>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
) : (
<p className="text-base leading-4 text-bunker-400 italic">Not set</p>
@@ -122,12 +121,10 @@ export const ViewIdentityKubernetesAuthContent = ({
className="max-w-xl p-2"
content={<p className="rounded-sm bg-mineshaft-600 p-2 break-words">{data.caCert}</p>}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -1,7 +1,8 @@
import { faBan, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EyeIcon } from "lucide-react";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useClearIdentityLdapAuthLockouts, useGetIdentityLdapAuth } from "@app/hooks/api";
import { IdentityLdapAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityLdapAuthForm";
import { ViewIdentityContentWrapper } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityContentWrapper";
@@ -72,12 +73,10 @@ export const ViewIdentityLdapAuthContent = ({
className="max-w-xl p-2"
content={<p className="rounded-sm bg-mineshaft-600 p-2 break-words">{data.bindPass}</p>}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Search Base / DN">
@@ -95,12 +94,10 @@ export const ViewIdentityLdapAuthContent = ({
</p>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -1,7 +1,8 @@
import { faBan, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EyeIcon } from "lucide-react";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useGetIdentityOidcAuth } from "@app/hooks/api";
import { IdentityOidcAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm";
import { ViewIdentityContentWrapper } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityContentWrapper";
@@ -73,12 +74,10 @@ export const ViewIdentityOidcAuthContent = ({
className="max-w-xl p-2"
content={<p className="rounded-sm bg-mineshaft-600 p-2 break-words">{data.caCert}</p>}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -102,12 +101,10 @@ export const ViewIdentityOidcAuthContent = ({
</pre>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -122,12 +119,10 @@ export const ViewIdentityOidcAuthContent = ({
</pre>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
@@ -1,7 +1,8 @@
import { faBan, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EyeIcon } from "lucide-react";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useGetIdentityTlsCertAuth } from "@app/hooks/api";
import { IdentityTlsCertAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTlsCertAuthForm";
@@ -71,12 +72,10 @@ export const ViewIdentityTlsCertAuthContent = ({
<p className="rounded-sm bg-mineshaft-600 p-2 break-words">{data.caCertificate}</p>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
<Badge variant="neutral">
<EyeIcon />
Reveal
</Badge>
</Tooltip>
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Allowed Common Names">
@@ -1,7 +1,5 @@
import { useState } from "react";
import {
faArrowUpRightFromSquare,
faBookOpen,
faCopy,
faDoorClosed,
faEdit,
@@ -39,6 +37,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import {
OrgGatewayPermissionActions,
OrgPermissionSubjects
@@ -106,22 +105,9 @@ export const GatewayTab = withPermission(
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-2 flex items-center justify-between">
<div className="flex grow items-center gap-2">
<div className="flex grow items-center gap-x-2">
<h3 className="text-lg font-medium text-mineshaft-100">Gateways</h3>
<a
href="https://infisical.com/docs/documentation/platform/gateways/overview"
target="_blank"
rel="noopener noreferrer"
>
<div className="inline-block rounded-md bg-yellow/20 px-1.5 py-0.5 text-sm font-normal text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/gateways/overview" />
<div className="flex grow" />
<Button
variant="outline_bg"
@@ -1,7 +1,5 @@
import { useEffect, useState } from "react";
import {
faArrowUpRightFromSquare,
faBookOpen,
faCopy,
faDoorClosed,
faEllipsisV,
@@ -37,6 +35,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import { ROUTE_PATHS } from "@app/const/routes";
import {
OrgPermissionSubjects,
@@ -116,22 +115,9 @@ export const RelayTab = withPermission(
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-2 flex items-center justify-between">
<div className="flex grow items-center gap-2">
<div className="flex grow items-center gap-x-2">
<h3 className="text-lg font-medium text-mineshaft-100">Relays</h3>
<a
href="https://infisical.com/docs/documentation/platform/gateways/relay-deployment"
target="_blank"
rel="noopener noreferrer"
>
<div className="inline-block rounded-md bg-yellow/20 px-1.5 py-0.5 text-sm font-normal text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/gateways/relay-deployment" />
<div className="flex grow" />
<Button
variant="outline_bg"
@@ -92,7 +92,7 @@ export const ProjectsPage = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You have exceeded the number of projects allowed on the free plan."
text="You have reached the maximum number of projects allowed on your current plan. Upgrade to Infisical Pro plan to add more projects."
/>
</div>
);
@@ -2,7 +2,6 @@ import { useState } from "react";
import {
faArrowDownAZ,
faBorderAll,
faCheck,
faCheckCircle,
faFolderOpen,
faList,
@@ -11,13 +10,13 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { CheckIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import { RequestProjectAccessModal } from "@app/components/projects/RequestProjectAccessModal";
import {
Badge,
Button,
DropdownMenu,
DropdownMenuContent,
@@ -31,6 +30,7 @@ import {
Skeleton,
Tooltip
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
import { OrgPermissionAdminConsoleAction } from "@app/context/OrgPermissionContext/types";
import { getProjectHomePage, getProjectLottieIcon, getProjectTitle } from "@app/helpers/project";
@@ -308,9 +308,9 @@ export const AllProjectView = ({
</div>
</div>
{workspace.isMember ? (
<Badge className="flex items-center" variant="success">
<FontAwesomeIcon icon={faCheck} className="mr-1" />
<span>Joined</span>
<Badge variant="info">
<CheckIcon />
Joined
</Badge>
) : (
<OrgPermissionCan
@@ -3,7 +3,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { createNotification } from "@app/components/notifications";
import { Badge, IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import {
SecretSharingAccessType,
TSharedSecret,
@@ -35,27 +36,23 @@ export const RequestedSecretsRow = ({
{isExpired && !row.encryptedSecret ? (
<Badge variant="danger">Expired</Badge>
) : (
<Badge variant={row.encryptedSecret ? "success" : "primary"}>
<Badge variant={row.encryptedSecret ? "success" : "warning"}>
{row.encryptedSecret ? "Secret Provided" : "Pending Secret"}
</Badge>
)}
</Td>
<Td>
<Badge variant="primary">
<Tooltip
content={
row.accessType === SecretSharingAccessType.Anyone
? "Anyone can input the secret."
: "Only members of the organization can input the secret."
}
>
<div>
{row.accessType === SecretSharingAccessType.Anyone
? "Anyone"
: "Organization Members"}
</div>
</Tooltip>
</Badge>
<Tooltip
content={
row.accessType === SecretSharingAccessType.Anyone
? "Anyone can input the secret."
: "Only members of the organization can input the secret."
}
>
<Badge variant="info">
{row.accessType === SecretSharingAccessType.Anyone ? "Anyone" : "Organization Members"}
</Badge>
</Tooltip>
</Td>
<Td>{`${format(new Date(row.createdAt), "yyyy-MM-dd - HH:mm a")}`}</Td>
<Td>{row.expiresAt ? format(new Date(row.expiresAt), "yyyy-MM-dd - HH:mm a") : "-"}</Td>
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { Badge } from "@app/components/v2/Badge";
import { Badge } from "@app/components/v3";
import { TSharedSecret } from "@app/hooks/api/secretSharing";
import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -29,7 +29,9 @@ export const AuditLogStreamsTab = withPermission(
<Button
onClick={() => {
if (subscription && !subscription?.auditLogStreams) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
handlePopUpOpen("auditLogStreamForm");
@@ -55,7 +57,8 @@ export const AuditLogStreamsTab = withPermission(
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can add audit log streams if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to audit log streams. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -1,6 +1,6 @@
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { DocumentationLinkBadge } from "@app/components/v3";
import { AUDIT_LOG_STREAM_PROVIDER_MAP } from "@app/helpers/auditLogStreams";
import { LogProvider } from "@app/hooks/api/auditLogStreams/enums";
@@ -34,20 +34,9 @@ export const AuditLogStreamHeader = ({ provider, logStreamExists, onBack }: Prop
)}
</div>
<div>
<div className="mb-1 flex items-center text-mineshaft-300">
<div className="mb-1 flex items-center gap-x-2 text-mineshaft-300">
{providerDetails.name}
<a
href="https://infisical.com/docs/documentation/platform/audit-log-streams/audit-log-streams#example-providers"
target="_blank"
className="ml-1"
rel="noopener noreferrer"
>
<div className="inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1 mb-px text-xs" />
<span>Docs</span>
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="mb-px ml-1 text-[10px]" />
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/audit-log-streams/audit-log-streams#example-providers" />
</div>
<p className="text-sm leading-4 text-mineshaft-400">
{logStreamExists
@@ -70,7 +70,9 @@ export const LogStreamProviderSelect = ({ onSelect }: Props) => {
type="button"
onClick={() => {
if (option.provider === LogProvider.QRadar) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
} else {
onSelect(option.provider);
}
@@ -109,7 +111,8 @@ export const LogStreamProviderSelect = ({ onSelect }: Props) => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="This audit log stream provider requires an enterprise license."
text="Your current plan does not include access to this audit log stream provider. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -180,7 +180,9 @@ const OrgConfigSection = ({
className="mt-2"
onClick={() => {
if (subscription && !subscription.kmip) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -250,7 +252,8 @@ const OrgConfigSection = ({
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="KMIP requires an enterprise plan."
text="Your current plan does not include access to KMIP. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</>
);
@@ -2,7 +2,8 @@ import { Controller, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { createNotification } from "@app/components/notifications";
import { Badge, Button, FormControl, Input, Select, SelectItem } from "@app/components/v2";
import { Button, FormControl, Input, Select, SelectItem } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useOrganization } from "@app/context";
import { useAddExternalKms, useUpdateExternalKms } from "@app/hooks/api";
import {
@@ -244,7 +245,7 @@ export const AwsKmsForm = ({ onCompleted, onCancel, kms }: Props) => {
>
{AWS_REGIONS.map((awsRegion) => (
<SelectItem value={awsRegion.slug} key={`kms-aws-region-${awsRegion.slug}`}>
{awsRegion.name} <Badge variant="success">{awsRegion.slug}</Badge>
{awsRegion.name} <Badge variant="neutral">{awsRegion.slug}</Badge>
</SelectItem>
))}
</Select>
@@ -27,6 +27,7 @@ type Props = {
kmsId?: string;
name?: string;
provider?: string;
isEnterpriseFeature?: boolean;
}
) => void;
subscription: SubscriptionPlan;
@@ -111,7 +112,9 @@ export const ExternalKmsItem = ({ kms, handlePopUpOpen, subscription }: Props) =
onClick={(e) => {
e.stopPropagation();
if (subscription && !subscription?.externalKms) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -3,7 +3,8 @@ import { Controller, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { createNotification } from "@app/components/notifications";
import { Badge, Button, FilterableSelect, FormControl, Input } from "@app/components/v2";
import { Button, FilterableSelect, FormControl, Input } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useOrganization } from "@app/context";
import {
useAddExternalKms,
@@ -71,7 +72,7 @@ const GCP_REGIONS = [
const formatOptionLabel = ({ value, label }: { value: string; label: string }) => (
<div className="flex w-full flex-row items-center justify-between">
<span>{label}</span>
<Badge variant="success">{value}</Badge>
<Badge variant="neutral">{value}</Badge>
</div>
);
@@ -74,7 +74,9 @@ export const OrgEncryptionTab = withPermission(
<Button
onClick={() => {
if (subscription && !subscription?.externalKms) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
handlePopUpOpen("addExternalKms");
@@ -123,7 +125,8 @@ export const OrgEncryptionTab = withPermission(
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can configure external KMS if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to external KMS. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
<AddExternalKmsForm
isOpen={popUp.addExternalKms.isOpen}
@@ -0,0 +1,72 @@
import { useState } from "react";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import { Switch } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { useUpdateOrg } from "@app/hooks/api/organization/queries";
export const OrgProductSettingsTab = () => {
const { currentOrg } = useOrganization();
const { mutateAsync: updateOrg } = useUpdateOrg();
const [isLoading, setIsLoading] = useState(false);
const handleToggle = async (state: boolean) => {
setIsLoading(true);
try {
if (!currentOrg?.id) {
setIsLoading(false);
return;
}
await updateOrg({
orgId: currentOrg.id,
blockDuplicateSecretSyncDestinations: state
});
createNotification({
text: `Successfully ${state ? "enabled" : "disabled"} blocking duplicate secret sync destinations for this organization`,
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update blocking duplicate secret sync destinations setting for this organization",
type: "error"
});
} finally {
setIsLoading(false);
}
};
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
<div className="mb-6">
<h2 className="text-xl font-medium text-mineshaft-100">Secrets Management</h2>
</div>
<div className="flex items-center justify-between">
<div>
<h3 className="mb-2 text-lg font-medium text-mineshaft-100">
Unique Secret Sync Destination Policy
</h3>
<p className="text-sm text-mineshaft-400">
When enabled, ensures each destination can only be used by one secret sync
configuration, preventing potential conflicts or overwrites.
</p>
</div>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<Switch
id="blockDuplicateSecretSyncDestinations"
isDisabled={!isAllowed || isLoading}
isChecked={currentOrg?.blockDuplicateSecretSyncDestinations ?? false}
onCheckedChange={(state) => handleToggle(state as boolean)}
/>
)}
</OrgPermissionCan>
</div>
</div>
);
};
@@ -0,0 +1 @@
export { OrgProductSettingsTab } from "./OrgProductSettingsTab";
@@ -111,7 +111,9 @@ export const OrgGithubSyncSection = () => {
onClick={() =>
subscription.githubOrgSync
? handlePopUpOpen("githubOrgSyncConfig")
: handlePopUpOpen("upgradePlan")
: handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
})
}
colorSchema="secondary"
isDisabled={!isAllowed}
@@ -202,7 +204,8 @@ export const OrgGithubSyncSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use GitHub Organization Plan if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to GitHub Organization Sync. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -29,7 +29,9 @@ export const OrgScimSection = () => {
if (subscription?.scim) {
handlePopUpOpen("scimToken");
} else {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
}
};
@@ -37,7 +39,9 @@ export const OrgScimSection = () => {
try {
if (!currentOrg?.id) return;
if (!subscription?.scim) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -90,7 +94,9 @@ export const OrgScimSection = () => {
if (subscription?.scim) {
handleEnableSCIMToggle(value);
} else {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
}
}}
isChecked={currentOrg?.scimEnabled ?? false}
@@ -111,7 +117,8 @@ export const OrgScimSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use SCIM Provisioning if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to SCIM Provisioning. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -110,7 +110,7 @@ export const OrgGenericAuthSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can enforce user MFA if you switch to Infisical's Pro plan."
text="Your current plan does not include access to enforce user MFA. To unlock this feature, please upgrade to Infisical Pro plan."
/>
</div>
);
@@ -312,7 +312,7 @@ export const OrgGeneralAuthSection = ({
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can enforce SAML SSO if you switch to Infisical's Pro plan."
text="Your current plan does not include access to enforce SAML SSO. To unlock this feature, please upgrade to Infisical Pro plan."
/>
</div>
);
@@ -34,7 +34,9 @@ export const OrgLDAPSection = (): JSX.Element => {
try {
if (!currentOrg?.id) return;
if (!subscription?.ldap) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -78,7 +80,9 @@ export const OrgLDAPSection = (): JSX.Element => {
handlePopUpOpen("addLDAP");
} else {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
}
} catch (err) {
console.error(err);
@@ -87,7 +91,9 @@ export const OrgLDAPSection = (): JSX.Element => {
const openLDAPGroupMapModal = () => {
if (!subscription?.ldap) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -185,7 +191,8 @@ export const OrgLDAPSection = (): JSX.Element => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use LDAP authentication if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to LDAP authentication. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -207,7 +207,7 @@ export const OrgOIDCSection = (): JSX.Element => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use OIDC SSO if you switch to Infisical's Pro plan."
text="Your current plan does not include access to OIDC SSO. To unlock this feature, please upgrade to Infisical Pro plan."
/>
</div>
);
@@ -27,7 +27,6 @@ export const OrgSSOSection = (): JSX.Element => {
const { mutateAsync } = useUpdateSSOConfig();
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"upgradePlan",
"upgradeEnterprisePlan",
"addSSO"
] as const);
@@ -38,7 +37,9 @@ export const OrgSSOSection = (): JSX.Element => {
if (!currentOrg?.id) return;
if (!subscription?.samlSSO) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
text: "Your current plan does not include access to SAML SSO. To unlock this feature, please upgrade to Infisical Pro plan."
});
return;
}
@@ -65,7 +66,10 @@ export const OrgSSOSection = (): JSX.Element => {
if (!currentOrg?.id) return;
if (!subscription?.samlSSO || !subscription?.groups) {
handlePopUpOpen("upgradeEnterprisePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true,
text: "Your current plan does not include access to SAML group mapping. To unlock this feature, please upgrade to Infisical Enterprise plan."
});
return;
}
@@ -105,7 +109,9 @@ export const OrgSSOSection = (): JSX.Element => {
handlePopUpOpen("addSSO");
} else {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
text: "Your current plan does not include access to SAML SSO. To unlock this feature, please upgrade to Infisical Pro plan."
});
}
} catch (err) {
console.error(err);
@@ -234,12 +240,8 @@ export const OrgSSOSection = (): JSX.Element => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use SAML SSO if you switch to Infisical's Pro plan."
/>
<UpgradePlanModal
isOpen={popUp.upgradeEnterprisePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradeEnterprisePlan", isOpen)}
text="You can use SAML group mapping if you switch to Infisical's Enterprise plan."
text={popUp.upgradePlan.data?.text}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
);
@@ -93,7 +93,7 @@ export const OrgSsoTab = withPermission(
colorSchema="secondary"
onClick={() => {
if (!subscription?.samlSSO) {
handlePopUpOpen("upgradePlan", { feature: "SAML SSO", plan: "Pro" });
handlePopUpOpen("upgradePlan", { featureName: "SAML SSO" });
return;
}
@@ -116,7 +116,7 @@ export const OrgSsoTab = withPermission(
colorSchema="secondary"
onClick={() => {
if (!subscription?.oidcSSO) {
handlePopUpOpen("upgradePlan", { feature: "OIDC SSO", plan: "Pro" });
handlePopUpOpen("upgradePlan", { featureName: "OIDC SSO" });
return;
}
@@ -134,7 +134,10 @@ export const OrgSsoTab = withPermission(
colorSchema="secondary"
onClick={() => {
if (!subscription?.ldap) {
handlePopUpOpen("upgradePlan", { feature: "LDAP", plan: "Enterprise" });
handlePopUpOpen("upgradePlan", {
featureName: "LDAP",
isEnterpriseFeature: true
});
return;
}
@@ -205,11 +208,8 @@ export const OrgSsoTab = withPermission(
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={`You can use ${
(popUp.upgradePlan.data as { feature: string })?.feature
} if you switch to Infisical's ${
(popUp.upgradePlan.data as { plan: string })?.plan
} plan.`}
text={`Your current plan does not include access to ${popUp.upgradePlan.data?.featureName}. To unlock this feature, please upgrade to Infisical ${popUp.upgradePlan.data?.isEnterpriseFeature ? "Enterprise" : "Pro"} plan.`}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</>
);
@@ -1,5 +1,4 @@
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { DocumentationLinkBadge } from "@app/components/v3";
type ProviderDetails = {
label: string;
@@ -24,23 +23,9 @@ export const SSOModalHeader = ({ providerDetails, isConnected }: Props) => {
className="h-12 w-12 rounded-md bg-bunker-500 p-2"
/>
<div>
<div className="flex items-center text-mineshaft-300">
<div className="flex items-center gap-x-2 text-mineshaft-300">
{providerDetails.label}
<a
href={`${docsBaseUrl}/${providerDetails.docsUrl}`}
target="_blank"
className="mb-1 ml-1"
rel="noopener noreferrer"
>
<div className="inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1 mb-[0.03rem] text-[12px]" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href={`${docsBaseUrl}/${providerDetails.docsUrl}`} />
</div>
<p className="text-sm leading-4 text-mineshaft-400">
{isConnected
@@ -10,6 +10,7 @@ import { ExternalMigrationsTab } from "../ExternalMigrationsTab";
import { KmipTab } from "../KmipTab/OrgKmipTab";
import { OrgEncryptionTab } from "../OrgEncryptionTab";
import { OrgGeneralTab } from "../OrgGeneralTab";
import { OrgProductSettingsTab } from "../OrgProductSettingsTab";
import { OrgProvisioningTab } from "../OrgProvisioningTab";
import { OrgSecurityTab } from "../OrgSecurityTab";
import { OrgSsoTab } from "../OrgSsoTab";
@@ -63,7 +64,12 @@ export const OrgTabGroup = () => {
key: "project-templates",
component: ProjectTemplatesTab
},
{ name: "KMIP", key: "kmip", component: KmipTab }
{ name: "KMIP", key: "kmip", component: KmipTab },
{
name: "Product Enforcements",
key: "product-enforcements",
component: OrgProductSettingsTab
}
];
const [selectedTab, setSelectedTab] = useState(search.selectedTab || tabs[0].key);
@@ -7,7 +7,6 @@ import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Badge,
Button,
DeleteActionModal,
DropdownMenu,
@@ -24,6 +23,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { withPermission } from "@app/hoc";
import { usePopUp } from "@app/hooks";
@@ -48,7 +48,7 @@ const renderStatus = (status: WorkflowIntegrationStatus) => {
}
if (status === WorkflowIntegrationStatus.Pending) {
return <Badge variant="primary">Pending</Badge>;
return <Badge variant="warning">Pending</Badge>;
}
return <Badge variant="danger">Failed</Badge>;
@@ -1,10 +1,11 @@
import { useState } from "react";
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { OrgPermissionCan } from "@app/components/permissions";
import { Button } from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
import { TProjectTemplate } from "@app/hooks/api/projectTemplates";
import { usePopUp } from "@app/hooks/usePopUp";
@@ -33,22 +34,9 @@ export const ProjectTemplatesSection = () => {
project setup
</p>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-start">
<div className="mb-4 flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Project Templates</p>
<a
target="_blank"
rel="noopener noreferrer"
href="https://infisical.com/docs/documentation/platform/project-templates"
>
<div className="mt-[0.32rem] ml-2 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/project-templates" />
<OrgPermissionCan
I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.ProjectTemplates}
@@ -60,7 +48,9 @@ export const ProjectTemplatesSection = () => {
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (!subscription?.projectTemplates) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -83,7 +73,8 @@ export const ProjectTemplatesSection = () => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can create project templates if you switch to Infisical's Enterprise plan."
text="Your current plan does not include access to project templates. To unlock this feature, please upgrade to Infisical Enterprise plan."
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
/>
</div>
</div>
@@ -1 +1,2 @@
export { OrgProductSettingsTab } from "./OrgProductSettingsTab";
export { OrgTabGroup } from "./OrgTabGroup";
@@ -305,7 +305,7 @@ const Page = withPermission(
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
text={popUp.upgradePlan?.data?.text}
/>
<UserOrgMembershipModal
popUp={popUp}
@@ -148,8 +148,7 @@ export const UserOrgMembershipModal = ({ popUp, handlePopUpOpen, handlePopUpTogg
if (isCustomRole && subscription && !subscription?.rbac) {
handlePopUpOpen("upgradePlan", {
description:
"You can assign custom roles to members if you upgrade your Infisical plan."
text: "Your current plan does not include access to assig custom roles to members. To unlock this feature, please upgrade to Infisical Pro plan."
});
return;
}