([]);
const formSchema = z.object({
name: z.string().min(1),
@@ -123,6 +128,9 @@ export default function CreateVirtualApiKeyForm({
setSelectedResources([]);
setPendingBudgetRows([]);
setAttemptedBudgetsSave(false);
+ setSendEmail(false);
+ setSendToAttributedUser(false);
+ setEmailTags([]);
form.reset();
}
@@ -141,6 +149,20 @@ export default function CreateVirtualApiKeyForm({
return;
}
+ if (
+ env.email.emailEnabled &&
+ sendEmail &&
+ !sendToAttributedUser &&
+ emailTags.length === 0
+ ) {
+ toast({
+ variant: "destructive",
+ title: t("virtualApiKeysEmailRecipientsRequired"),
+ description: t("virtualApiKeysEmailRecipientsRequired")
+ });
+ return;
+ }
+
return onSubmit(values);
}
@@ -157,7 +179,16 @@ export default function CreateVirtualApiKeyForm({
allResources,
resourceIds: allResources
? []
- : selectedResources.map((r) => r.resourceId)
+ : selectedResources.map((r) => r.resourceId),
+ sendEmail: env.email.emailEnabled && sendEmail,
+ sendToAttributedUser:
+ env.email.emailEnabled &&
+ sendEmail &&
+ sendToAttributedUser,
+ emails:
+ env.email.emailEnabled && sendEmail
+ ? emailTags.map((tag) => tag.text)
+ : []
}
)
.catch((e) => {
@@ -473,6 +504,26 @@ export default function CreateVirtualApiKeyForm({
)}
+
+
@@ -505,7 +556,7 @@ export default function CreateVirtualApiKeyForm({
)}
+
+
diff --git a/src/components/VirtualApiKeyEmailSection.tsx b/src/components/VirtualApiKeyEmailSection.tsx
new file mode 100644
index 000000000..a00abd69e
--- /dev/null
+++ b/src/components/VirtualApiKeyEmailSection.tsx
@@ -0,0 +1,151 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { Checkbox } from "@app/components/ui/checkbox";
+import { FormLabel } from "@app/components/ui/form";
+import { TagInput, type Tag } from "@app/components/tags/tag-input";
+import { useTranslations } from "next-intl";
+
+type VirtualApiKeyEmailSectionProps = {
+ emailEnabled: boolean;
+ mode: "create" | "edit";
+ sendEmail: boolean;
+ onSendEmailChange: (value: boolean) => void;
+ sendToAttributedUser: boolean;
+ onSendToAttributedUserChange: (value: boolean) => void;
+ hasAssociatedUser: boolean;
+ emailTags: Tag[];
+ onEmailTagsChange: (tags: Tag[]) => void;
+};
+
+export default function VirtualApiKeyEmailSection({
+ emailEnabled,
+ mode,
+ sendEmail,
+ onSendEmailChange,
+ sendToAttributedUser,
+ onSendToAttributedUserChange,
+ hasAssociatedUser,
+ emailTags,
+ onEmailTagsChange
+}: VirtualApiKeyEmailSectionProps) {
+ const t = useTranslations();
+ const [activeEmailTagIndex, setActiveEmailTagIndex] = useState<
+ number | null
+ >(null);
+
+ useEffect(() => {
+ if (!hasAssociatedUser && sendToAttributedUser) {
+ onSendToAttributedUserChange(false);
+ }
+ }, [hasAssociatedUser, sendToAttributedUser, onSendToAttributedUserChange]);
+
+ const checkboxId =
+ mode === "create"
+ ? "virtual-api-key-send-email"
+ : "edit-virtual-api-key-send-email";
+ const sendToUserId =
+ mode === "create"
+ ? "virtual-api-key-send-to-user"
+ : "edit-virtual-api-key-send-to-user";
+
+ return (
+
+
+
{
+ if (emailEnabled) {
+ onSendEmailChange(val === true);
+ }
+ }}
+ className="mt-0.5"
+ />
+
+
+
+ {emailEnabled
+ ? t(
+ mode === "create"
+ ? "virtualApiKeysEmailOnGenerateDescription"
+ : "virtualApiKeysEmailThisKeyDescription"
+ )
+ : t("virtualApiKeysEmailSmtpRequiredDescription")}
+
+
+
+
+ {emailEnabled && sendEmail && (
+
+
+
+ onSendToAttributedUserChange(val === true)
+ }
+ className="mt-0.5"
+ />
+
+
+
+ {hasAssociatedUser
+ ? t(
+ "virtualApiKeysEmailSendToUserDescription"
+ )
+ : t(
+ "virtualApiKeysEmailSendToUserDisabled"
+ )}
+
+
+
+
+
+
+ {t("virtualApiKeysEmailAdditional")}
+
+ {
+ const next =
+ typeof newTags === "function"
+ ? newTags(emailTags)
+ : newTags;
+ onEmailTagsChange(next as Tag[]);
+ }}
+ allowDuplicates={false}
+ sortTags
+ validateTag={(tag) =>
+ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(tag)
+ }
+ delimiterList={[",", "Enter"]}
+ />
+
+
+ )}
+
+ );
+}