merge main

This commit is contained in:
Scott Wilson
2025-10-28 09:59:24 -07:00
165 changed files with 5524 additions and 3409 deletions
@@ -69,7 +69,10 @@ export const PkiSyncSelect = ({ onSelect }: Props) => {
type="button"
onClick={() =>
enterprise && !subscription.enterpriseCertificateSyncs
? handlePopUpOpen("upgradePlan")
? handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true,
text: "You can use every Certificate Sync if you switch to Infisical's Enterprise plan."
})
: onSelect(destination)
}
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center overflow-hidden rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
@@ -148,6 +151,7 @@ export const PkiSyncSelect = ({ onSelect }: Props) => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
text="You can use every Certificate Sync if you switch to Infisical's Enterprise plan."
/>
</div>
@@ -67,7 +67,9 @@ export const SecretSyncSelect = ({ onSelect }: Props) => {
type="button"
onClick={() =>
enterprise && !subscription.enterpriseSecretSyncs
? handlePopUpOpen("upgradePlan")
? handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
})
: onSelect(destination)
}
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center overflow-hidden rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
@@ -145,6 +147,7 @@ export const SecretSyncSelect = ({ onSelect }: Props) => {
)}
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use every Secret Sync if you switch to Infisical's Enterprise plan."
/>
@@ -8,13 +8,14 @@ import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Switch } from "@app/components/v2";
import { useProject } from "@app/context";
import { useOrganization, useProject } from "@app/context";
import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
import {
SecretSync,
SecretSyncInitialSyncBehavior,
TSecretSync,
useCreateSecretSync,
useDuplicateDestinationCheck,
useSecretSyncOption
} from "@app/hooks/api/secretSyncs";
@@ -48,6 +49,7 @@ export const CreateSecretSyncForm = ({
}: Props) => {
const createSecretSync = useCreateSecretSync();
const { currentProject } = useProject();
const { currentOrg } = useOrganization();
const { name: destinationName } = SECRET_SYNC_MAP[destination];
const [showConfirmation, setShowConfirmation] = useState(false);
@@ -106,11 +108,20 @@ export const CreateSecretSyncForm = ({
setSelectedTabIndex((prev) => prev - 1);
};
const { handleSubmit, trigger, control } = formMethods;
const { handleSubmit, trigger, control, watch } = formMethods;
const { hasDuplicate } = useDuplicateDestinationCheck({
destination,
projectId: currentProject?.id || "",
enabled: true,
destinationConfig: watch("destinationConfig")
});
const isStepValid = async (index: number) => trigger(FORM_TABS[index].fields);
const isFinalStep = selectedTabIndex === FORM_TABS.length - 1;
const isCreateButtonDisabled =
isFinalStep && hasDuplicate && currentOrg?.blockDuplicateSecretSyncDestinations;
const handleNext = async () => {
if (isFinalStep) {
@@ -245,7 +256,7 @@ export const CreateSecretSyncForm = ({
</FormProvider>
<div className="flex w-full flex-row-reverse justify-between gap-4 pt-4">
<Button onClick={handleNext} colorSchema="secondary">
<Button onClick={handleNext} colorSchema="secondary" isDisabled={isCreateButtonDisabled}>
{isFinalStep ? "Create Sync" : "Next"}
</Button>
{selectedTabIndex > 0 && (
@@ -6,6 +6,7 @@ type Props = {
onConfirm: () => void;
isLoading?: boolean;
duplicateProjectId?: string;
isDisabled?: boolean;
};
export const DuplicateDestinationConfirmationModal = ({
@@ -13,7 +14,8 @@ export const DuplicateDestinationConfirmationModal = ({
onOpenChange,
onConfirm,
isLoading,
duplicateProjectId
duplicateProjectId,
isDisabled
}: Props) => {
return (
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
@@ -21,7 +23,12 @@ export const DuplicateDestinationConfirmationModal = ({
<div className="mb-4 text-sm">
<p>
Another secret sync in your organization is already configured with the same
destination. Proceeding may cause conflicts or overwrite existing data.
destination.{" "}
<span className={isDisabled ? "text-red-400" : ""}>
{isDisabled
? "Your organization does not allow duplicate destination configurations."
: "Proceeding may cause conflicts or overwrite existing data."}
</span>
</p>
{duplicateProjectId && (
<p className="mt-2 text-xs text-mineshaft-400">
@@ -31,26 +38,28 @@ export const DuplicateDestinationConfirmationModal = ({
</code>
</p>
)}
<p className="mt-2">Are you sure you want to continue?</p>
{!isDisabled && <p className="mt-2">Are you sure you want to continue?</p>}
</div>
<div className="flex items-center gap-4 pt-4">
<ModalClose asChild>
<Button
onClick={onConfirm}
colorSchema="danger"
isLoading={isLoading}
isDisabled={isLoading}
>
Continue
</Button>
</ModalClose>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain" isDisabled={isLoading}>
Cancel
</Button>
</ModalClose>
</div>
{!isDisabled && (
<div className="flex items-center gap-4 pt-4">
<ModalClose asChild>
<Button
onClick={onConfirm}
colorSchema="danger"
isLoading={isLoading}
isDisabled={isLoading}
>
Continue
</Button>
</ModalClose>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain" isDisabled={isLoading}>
Cancel
</Button>
</ModalClose>
</div>
)}
</ModalContent>
</Modal>
);
@@ -5,6 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { createNotification } from "@app/components/notifications";
import { SecretSyncEditFields } from "@app/components/secret-syncs/types";
import { Button, ModalClose } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
import {
TSecretSync,
@@ -30,6 +31,7 @@ export const EditSecretSyncForm = ({ secretSync, fields, onComplete }: Props) =>
const { name: destinationName } = SECRET_SYNC_MAP[secretSync.destination];
const [showDuplicateConfirmation, setShowDuplicateConfirmation] = useState(false);
const [pendingFormData, setPendingFormData] = useState<TSecretSyncForm | null>(null);
const { currentOrg } = useOrganization();
const formMethods = useForm<TSecretSyncForm>({
resolver: zodResolver(UpdateSecretSyncFormSchema),
@@ -209,6 +211,7 @@ export const EditSecretSyncForm = ({ secretSync, fields, onComplete }: Props) =>
onConfirm={handleConfirmDuplicate}
isLoading={updateSecretSync.isPending}
duplicateProjectId={storedDuplicateProjectId}
isDisabled={currentOrg?.blockDuplicateSecretSyncDestinations}
/>
</>
);
@@ -6,7 +6,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { GenericFieldLabel } from "@app/components/secret-syncs";
import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas";
import { Badge } from "@app/components/v3";
import { useProject } from "@app/context";
import { useOrganization, useProject } from "@app/context";
import { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
import { SecretSync, useDuplicateDestinationCheck } from "@app/hooks/api/secretSyncs";
@@ -51,6 +51,7 @@ import { ZabbixSyncReviewFields } from "./ZabbixSyncReviewFields";
export const SecretSyncReviewFields = () => {
const { watch } = useFormContext<TSecretSyncForm>();
const { currentProject } = useProject();
const { currentOrg } = useOrganization();
let DestinationFieldsComponent: ReactNode;
let AdditionalSyncOptionsFieldsComponent: ReactNode;
@@ -193,18 +194,50 @@ export const SecretSyncReviewFields = () => {
{isChecking && <span className="text-xs text-mineshaft-400">Checking...</span>}
</div>
{hasDuplicate && (
<div className="mb-2 flex items-start rounded-md border border-yellow-600 bg-yellow-900/20 px-3 py-2">
<div className="flex text-sm text-yellow-100">
<FontAwesomeIcon icon={faWarning} className="mt-1 mr-2 text-yellow-600" />
<div
className={`mb-2 flex items-start rounded-md border px-3 py-2 ${
currentOrg?.blockDuplicateSecretSyncDestinations
? "border-red-600 bg-red-900/20"
: "border-yellow-600 bg-yellow-900/20"
}`}
>
<div
className={`flex text-sm ${
currentOrg?.blockDuplicateSecretSyncDestinations
? "text-red-100"
: "text-yellow-100"
}`}
>
<FontAwesomeIcon
icon={faWarning}
className={`mt-1 mr-2 ${
currentOrg?.blockDuplicateSecretSyncDestinations
? "text-red-600"
: "text-yellow-600"
}`}
/>
<div>
<p>
Another secret sync in your organization is already configured with the same
destination. This may lead to conflicts or unexpected behavior.
{currentOrg?.blockDuplicateSecretSyncDestinations
? "Another secret sync in your organization is already configured with the same destination. Your organization does not allow duplicate destination configurations."
: "Another secret sync in your organization is already configured with the same destination. This may lead to conflicts or unexpected behavior."}
</p>
{duplicateProjectId && (
<p className="mt-1 text-xs text-yellow-200">
<p
className={`mt-1 text-xs ${
currentOrg?.blockDuplicateSecretSyncDestinations
? "text-red-200"
: "text-yellow-200"
}`}
>
Duplicate found in project ID:{" "}
<code className="rounded-sm bg-yellow-800/50 px-1 py-0.5">
<code
className={`rounded-sm px-1 py-0.5 ${
currentOrg?.blockDuplicateSecretSyncDestinations
? "bg-red-800/50"
: "bg-yellow-800/50"
}`}
>
{duplicateProjectId}
</code>
</p>