diff --git a/apps/web/prisma/migrations/20250822125136_add_domain_access_to_api_keys/migration.sql b/apps/web/prisma/migrations/20250822125136_add_domain_access_to_api_keys/migration.sql new file mode 100644 index 00000000..318681ae --- /dev/null +++ b/apps/web/prisma/migrations/20250822125136_add_domain_access_to_api_keys/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "ApiKey" ADD COLUMN "domainId" INTEGER; + +-- AddForeignKey +ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_domainId_fkey" FOREIGN KEY ("domainId") REFERENCES "Domain"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/web/prisma/schema.prisma b/apps/web/prisma/schema.prisma index a2ae7ed8..a1a29d0c 100644 --- a/apps/web/prisma/schema.prisma +++ b/apps/web/prisma/schema.prisma @@ -195,6 +195,7 @@ model Domain { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + apiKeys ApiKey[] } enum ApiPermission { @@ -209,11 +210,13 @@ model ApiKey { partialToken String name String permission ApiPermission @default(SENDING) + domainId Int? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt lastUsed DateTime? teamId Int team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull, onUpdate: Cascade) } enum EmailStatus { diff --git a/apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx b/apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx index b6e674bc..e3728c28 100644 --- a/apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx +++ b/apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx @@ -27,11 +27,19 @@ import { FormLabel, FormMessage, } from "@usesend/ui/src/form"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@usesend/ui/src/select"; const apiKeySchema = z.object({ name: z.string({ required_error: "Name is required" }).min(1, { message: "Name is required", }), + domainId: z.string().optional(), }); export default function AddApiKey() { @@ -41,12 +49,15 @@ export default function AddApiKey() { const [isCopied, setIsCopied] = useState(false); const [showApiKey, setShowApiKey] = useState(false); + const domainsQuery = api.domain.domains.useQuery(); + const utils = api.useUtils(); const apiKeyForm = useForm>({ resolver: zodResolver(apiKeySchema), defaultValues: { name: "", + domainId: "all", }, }); @@ -55,6 +66,8 @@ export default function AddApiKey() { { name: values.name, permission: "FULL", + domainId: + values.domainId === "all" ? undefined : Number(values.domainId), }, { onSuccess: (data) => { @@ -62,7 +75,7 @@ export default function AddApiKey() { setApiKey(data); apiKeyForm.reset(); }, - }, + } ); } @@ -180,6 +193,41 @@ export default function AddApiKey() { )} /> + ( + + Domain access + + + Choose which domain this API key can send emails from. + + + )} + />