diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx index 952cbb91d7..faae4e5126 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx @@ -173,6 +173,8 @@ export function ActionSummaryCard({ case ActionType.CALL_WEBHOOK: summaryContent = `Call webhook: ${action.url?.value || "unset"}`; + tooltipText = + "Sends email details and rule execution data to your webhook endpoint when this rule is triggered."; break; case ActionType.TRACK_THREAD: diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx index 712ac584da..1eacf6a992 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx @@ -96,6 +96,7 @@ import { FolderSelector } from "@/components/FolderSelector"; import { useFolders } from "@/hooks/useFolders"; import type { OutlookFolder } from "@/utils/outlook/folders"; import { cn } from "@/utils"; +import { WebhookDocumentationLink } from "@/components/WebhookDocumentation"; export function Rule({ ruleId, @@ -1271,7 +1272,14 @@ function ActionCard({ registerProps={register( `actions.${index}.${field.name}.value`, )} + placeholder={field.placeholder} /> + {field.name === "url" && + action.type === ActionType.CALL_WEBHOOK && ( +
+ +
+ )} )} diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx index 8f5ac2b2c5..369d86a2e1 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx @@ -5,7 +5,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; export function RulesTab() { return ( -
+
diff --git a/apps/web/app/(app)/[emailAccountId]/settings/WebhookSection.tsx b/apps/web/app/(app)/[emailAccountId]/settings/WebhookSection.tsx index 70855ef38f..3b381f0a0c 100644 --- a/apps/web/app/(app)/[emailAccountId]/settings/WebhookSection.tsx +++ b/apps/web/app/(app)/[emailAccountId]/settings/WebhookSection.tsx @@ -14,7 +14,7 @@ export function WebhookSection() {
@@ -26,10 +26,12 @@ export function WebhookSection() { )} - +
+ +
)} diff --git a/apps/web/components/WebhookDocumentation.tsx b/apps/web/components/WebhookDocumentation.tsx new file mode 100644 index 0000000000..e986d35844 --- /dev/null +++ b/apps/web/components/WebhookDocumentation.tsx @@ -0,0 +1,164 @@ +"use client"; + +import { useState } from "react"; +import { Copy, Check } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; + +export function WebhookDocumentationDialog({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + + Webhook Payload + + + + + ); +} + +export function WebhookPayloadDocumentation() { + const [copied, setCopied] = useState(false); + + const copyToClipboard = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch (err) { + console.error("Failed to copy text: ", err); + } + }; + + const payloadExample = { + email: { + threadId: "thread_abc123", + messageId: "message_xyz789", + subject: "Important Contract Document", + from: "client@company.com", + cc: "team@company.com", + bcc: "archive@company.com", + headerMessageId: "", + }, + executedRule: { + id: "exec_rule_123", + ruleId: "rule_456", + reason: "Email matched rule: Archive contracts", + automated: true, + createdAt: "2024-01-15T10:30:00.000Z", + }, + }; + + const payloadJson = JSON.stringify(payloadExample, null, 2); + + return ( +
+
+ When a rule with a webhook action is triggered, we'll send a POST + request to your URL with the following payload: +
+ +
+
+

Webhook Payload Structure

+ +
+ +
+          {payloadJson}
+        
+ +
+
+
Email Fields
+
+
+ threadId - Gmail/Outlook thread ID +
+
+ messageId - Unique message ID +
+
+ subject - Email subject line +
+
+ from - Sender's email address +
+
+ cc/bcc - Optional CC/BCC recipients +
+
+ headerMessageId - Email Message-ID header +
+
+
+ +
+
Rule Execution Fields
+
+
+ id - Execution ID +
+
+ ruleId - Rule that was triggered +
+
+ reason - Why the rule was triggered +
+
+ automated - Whether rule ran automatically +
+
+ createdAt - When the rule was executed (ISO 8601) +
+
+
+
+ +
+
+ Authentication: Each request includes an{" "} + X-Webhook-Secret header with your webhook secret for + verification. +
+
+
+
+ ); +} + +export function WebhookDocumentationLink() { + return ( + + + + ); +} diff --git a/apps/web/utils/action-item.ts b/apps/web/utils/action-item.ts index be7fdb09d9..ab64370411 100644 --- a/apps/web/utils/action-item.ts +++ b/apps/web/utils/action-item.ts @@ -22,6 +22,7 @@ export const actionInputs: Record< label: string; textArea?: boolean; expandable?: boolean; + placeholder?: string; }[]; } > = { @@ -139,6 +140,7 @@ export const actionInputs: Record< { name: "url", label: "URL", + placeholder: "https://example.com/webhook", }, ], }, diff --git a/version.txt b/version.txt index 8bfc76e4ee..841c56f2d0 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v2.6.12 \ No newline at end of file +v2.6.13 \ No newline at end of file