"use client"; import { useState, useEffect } from "react"; import { Credenza, CredenzaBody, CredenzaClose, CredenzaContent, CredenzaDescription, CredenzaFooter, CredenzaHeader, CredenzaTitle } from "@app/components/Credenza"; import { Button } from "@app/components/ui/button"; import { Input } from "@app/components/ui/input"; import { Label } from "@app/components/ui/label"; import { Switch } from "@app/components/ui/switch"; import { HorizontalTabs } from "@app/components/HorizontalTabs"; import { RadioGroup, RadioGroupItem } from "@app/components/ui/radio-group"; import { Checkbox } from "@app/components/ui/checkbox"; import { AlertCircle } from "lucide-react"; import { Alert, AlertDescription } from "@app/components/ui/alert"; import { createApiClient, formatAxiosError } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { toast } from "@app/hooks/useToast"; import { useTranslations } from "next-intl"; import { Destination } from "@app/components/HttpDestinationCredenza"; // ── Types ────────────────────────────────────────────────────────────────────── export type S3PayloadFormat = "json_array" | "ndjson" | "csv"; export interface S3Config { name: string; accessKeyId: string; secretAccessKey: string; region: string; bucket: string; prefix: string; endpoint: string; format: S3PayloadFormat; gzip: boolean; } // ── Helpers ──────────────────────────────────────────────────────────────────── export const defaultS3Config = (): S3Config => ({ name: "", accessKeyId: "", secretAccessKey: "", region: "us-east-1", bucket: "", prefix: "", endpoint: "", format: "json_array", gzip: false }); export function parseS3Config(raw: string): S3Config { try { return { ...defaultS3Config(), ...JSON.parse(raw) }; } catch { return defaultS3Config(); } } // ── Component ────────────────────────────────────────────────────────────────── export interface S3DestinationCredenzaProps { open: boolean; onOpenChange: (open: boolean) => void; editing: Destination | null; orgId: string; onSaved: () => void; } export function S3DestinationCredenza({ open, onOpenChange, editing, orgId, onSaved }: S3DestinationCredenzaProps) { const api = createApiClient(useEnvContext()); const t = useTranslations(); const [saving, setSaving] = useState(false); const [cfg, setCfg] = useState(defaultS3Config()); const [sendAccessLogs, setSendAccessLogs] = useState(false); const [sendActionLogs, setSendActionLogs] = useState(false); const [sendConnectionLogs, setSendConnectionLogs] = useState(false); const [sendRequestLogs, setSendRequestLogs] = useState(false); useEffect(() => { if (open) { setCfg(editing ? parseS3Config(editing.config) : defaultS3Config()); setSendAccessLogs(editing?.sendAccessLogs ?? false); setSendActionLogs(editing?.sendActionLogs ?? false); setSendConnectionLogs(editing?.sendConnectionLogs ?? false); setSendRequestLogs(editing?.sendRequestLogs ?? false); } }, [open, editing]); const update = (patch: Partial) => setCfg((prev) => ({ ...prev, ...patch })); const isValid = cfg.name.trim() !== "" && cfg.accessKeyId.trim() !== "" && cfg.secretAccessKey.trim() !== "" && cfg.region.trim() !== "" && cfg.bucket.trim() !== ""; async function handleSave() { if (!isValid) return; setSaving(true); try { const payload = { type: "s3", config: JSON.stringify(cfg), sendAccessLogs, sendActionLogs, sendConnectionLogs, sendRequestLogs }; if (editing) { await api.post( `/org/${orgId}/event-streaming-destination/${editing.destinationId}`, payload ); toast({ title: t("s3DestUpdatedSuccess") }); } else { await api.put( `/org/${orgId}/event-streaming-destination`, payload ); toast({ title: t("s3DestCreatedSuccess") }); } onSaved(); onOpenChange(false); } catch (e) { toast({ variant: "destructive", title: editing ? t("s3DestUpdateFailed") : t("s3DestCreateFailed"), description: formatAxiosError(e, t("streamingUnexpectedError")) }); } finally { setSaving(false); } } return ( {editing ? t("S3DestEditTitle") : t("S3DestAddTitle")} {editing ? t("S3DestEditDescription") : t("S3DestAddDescription")} {editing?.lastError && ( {editing.lastError} )} {/* ── Settings tab ────────────────────────────── */}
{/* Name */}
update({ name: e.target.value }) } />
{/* AWS Access Key ID */}
update({ accessKeyId: e.target.value }) } autoComplete="off" />
{/* AWS Secret Access Key */}
update({ secretAccessKey: e.target.value }) } autoComplete="new-password" />
{/* Region */}
update({ region: e.target.value }) } />
{/* Bucket */}
update({ bucket: e.target.value }) } />
{/* Prefix */}
update({ prefix: e.target.value }) } />

{t("s3DestPrefixDescription")}

{/* Custom endpoint (optional – for S3-compatible storage) */}
update({ endpoint: e.target.value }) } />

{t("s3DestEndpointDescription")}

{/* ── Format tab ───────────────────────────────── */}
{/* Gzip compression toggle */}
update({ gzip: v })} className="mt-0.5" />

{t("s3DestGzipDescription")}

{/* Payload format selector */}

{t("s3DestFormatDescription")}

update({ format: v as S3PayloadFormat }) } className="gap-2" > {/* JSON Array */} {/* NDJSON */} {/* CSV */}
{/* ── Logs tab ──────────────────────────────────── */}

{t("httpDestLogTypesDescription")}

setSendAccessLogs(v === true) } className="mt-0.5" />

{t("httpDestAccessLogsDescription")}

setSendActionLogs(v === true) } className="mt-0.5" />

{t("httpDestActionLogsDescription")}

setSendConnectionLogs(v === true) } className="mt-0.5" />

{t( "httpDestConnectionLogsDescription" )}

setSendRequestLogs(v === true) } className="mt-0.5" />

{t( "httpDestRequestLogsDescription" )}

); }