diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 256819495..000000000 --- a/package-lock.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "sim", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "framer-motion": "^12.5.0" - } - }, - "node_modules/framer-motion": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.5.0.tgz", - "integrity": "sha512-buPlioFbH9/W7rDzYh1C09AuZHAk2D1xTA1BlounJ2Rb9aRg84OXexP0GLd+R83v0khURdMX7b5MKnGTaSg5iA==", - "license": "MIT", - "dependencies": { - "motion-dom": "^12.5.0", - "motion-utils": "^12.5.0", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/motion-dom": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.5.0.tgz", - "integrity": "sha512-uH2PETDh7m+Hjd1UQQ56yHqwn83SAwNjimNPE/kC+Kds0t4Yh7+29rfo5wezVFpPOv57U4IuWved5d1x0kNhbQ==", - "license": "MIT", - "dependencies": { - "motion-utils": "^12.5.0" - } - }, - "node_modules/motion-utils": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.5.0.tgz", - "integrity": "sha512-+hFFzvimn0sBMP9iPxBa9OtRX35ZQ3py0UHnb8U29VD+d8lQ8zH3dTygJWqK7av2v6yhg7scj9iZuvTS0f4+SA==", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 4ff6a286e..000000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "framer-motion": "^12.5.0" - } -} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/generic-config.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/generic-config.tsx new file mode 100644 index 000000000..53d04c5f3 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/generic-config.tsx @@ -0,0 +1,134 @@ +import { Checkbox } from '@/components/ui/checkbox' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { CopyableField } from '../ui/copyable' +import { TestResultDisplay } from '../ui/test-result' + +interface GenericConfigProps { + requireAuth: boolean + setRequireAuth: (requireAuth: boolean) => void + generalToken: string + setGeneralToken: (token: string) => void + secretHeaderName: string + setSecretHeaderName: (headerName: string) => void + allowedIps: string + setAllowedIps: (ips: string) => void + isLoadingToken: boolean + testResult: { + success: boolean + message?: string + test?: any + } | null + copied: string | null + copyToClipboard: (text: string, type: string) => void + testWebhook: () => Promise +} + +export function GenericConfig({ + requireAuth, + setRequireAuth, + generalToken, + setGeneralToken, + secretHeaderName, + setSecretHeaderName, + allowedIps, + setAllowedIps, + isLoadingToken, + testResult, + copied, + copyToClipboard, +}: GenericConfigProps) { + return ( +
+
+
+ setRequireAuth(checked as boolean)} + /> + +
+
+ + {requireAuth && ( +
+ + +
+ + setSecretHeaderName(e.target.value)} + placeholder="X-Secret-Key" + className="flex-1" + /> +

+ Custom HTTP header name for passing the authentication token instead of using Bearer + authentication. +

+
+
+ )} + +
+ + setAllowedIps(e.target.value)} + placeholder="192.168.1.1, 10.0.0.1" + className="flex-1" + /> +

+ Comma-separated list of IP addresses that are allowed to access this webhook. +

+
+ + + +
+

Setup Instructions

+
    +
  1. Copy the Webhook URL above
  2. +
  3. Configure your service to send HTTP POST requests to this URL
  4. + {requireAuth && ( + <> +
  5. + {secretHeaderName + ? `Add the "${secretHeaderName}" header with your token to all requests` + : 'Add an "Authorization: Bearer YOUR_TOKEN" header to all requests'} +
  6. + + )} +
+ +
+

+ 💡 + The webhook will receive all HTTP POST requests and pass the data to your workflow. +

+
+
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/github-config.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/github-config.tsx new file mode 100644 index 000000000..5a2ba9e78 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/github-config.tsx @@ -0,0 +1,64 @@ +import { Loader2 } from 'lucide-react' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' + +interface GithubConfigProps { + contentType: string + setContentType: (contentType: string) => void + isLoadingToken: boolean + testResult: { + success: boolean + message?: string + test?: any + } | null + copied: string | null + copyToClipboard: (text: string, type: string) => void +} + +export function GithubConfig({ + contentType, + setContentType, + isLoadingToken, + testResult, +}: GithubConfigProps) { + return ( +
+
+ + {isLoadingToken ? ( +
+ +
+ ) : ( + setContentType(e.target.value)} + placeholder="application/json" + className="flex-1" + /> + )} +
+ +
+

Setup Instructions

+
    +
  1. Go to your GitHub repository
  2. +
  3. Navigate to Settings {'>'} Webhooks
  4. +
  5. Click "Add webhook"
  6. +
  7. Enter the Webhook URL shown above
  8. +
  9. Set Content type to "{contentType}"
  10. +
  11. Choose which events you want to trigger the webhook
  12. +
  13. Ensure "Active" is checked and save
  14. +
+
+ +
+

+ 💡 + After saving, GitHub will send a ping event to verify your webhook. +

+
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/stripe-config.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/stripe-config.tsx new file mode 100644 index 000000000..9d59b2575 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/stripe-config.tsx @@ -0,0 +1,38 @@ +interface StripeConfigProps { + isLoadingToken: boolean + testResult: { + success: boolean + message?: string + test?: any + } | null + copied: string | null + copyToClipboard: (text: string, type: string) => void +} + +export function StripeConfig({ + isLoadingToken, + testResult, + copied, + copyToClipboard, +}: StripeConfigProps) { + return ( +
+

Setup Instructions

+
    +
  1. Go to your Stripe Dashboard
  2. +
  3. Navigate to Developers {'>'} Webhooks
  4. +
  5. Click "Add endpoint"
  6. +
  7. Enter the Webhook URL shown above
  8. +
  9. Select the events you want to listen for
  10. +
  11. Add the endpoint
  12. +
+ +
+

+ 💡 + Stripe will send a test event to verify your webhook endpoint. +

+
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/whatsapp-config.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/whatsapp-config.tsx new file mode 100644 index 000000000..68c9b0a0f --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/whatsapp-config.tsx @@ -0,0 +1,104 @@ +import { CopyableField } from '../ui/copyable' +import { TestResultDisplay } from '../ui/test-result' + +interface WhatsAppConfigProps { + verificationToken: string + setVerificationToken: (token: string) => void + isLoadingToken: boolean + testResult: { + success: boolean + message?: string + test?: any + } | null + copied: string | null + copyToClipboard: (text: string, type: string) => void +} + +export function WhatsAppConfig({ + verificationToken, + setVerificationToken, + isLoadingToken, + testResult, + copied, + copyToClipboard, +}: WhatsAppConfigProps) { + return ( +
+ + + + +
+

Setup Instructions

+
    +
  1. + 1. + Go to WhatsApp Business Platform dashboard +
  2. +
  3. + 2. + Navigate to "Configuration" in the sidebar +
  4. +
  5. + 3. + + Enter the URL above as "Callback URL" (exactly as shown) + +
  6. +
  7. + 4. + Enter your token as "Verify token" +
  8. +
  9. + 5. + Click "Verify and save" and subscribe to "messages" +
  10. +
+
+
Requirements
+
    +
  • + • + + URL must be publicly accessible with HTTPS + +
  • +
  • + • + + Self-signed SSL certificates not supported + +
  • +
  • + • + + For local testing, use ngrok to expose your server + +
  • +
+
+
+

+ 💡 + After saving, use "Test" to verify your webhook configuration. +

+
+
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/confirmation.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/confirmation.tsx new file mode 100644 index 000000000..47ab172f0 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/confirmation.tsx @@ -0,0 +1,76 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog' + +interface DeleteConfirmDialogProps { + open: boolean + setOpen: (open: boolean) => void + onConfirm: () => void + isDeleting: boolean +} + +export function DeleteConfirmDialog({ + open, + setOpen, + onConfirm, + isDeleting, +}: DeleteConfirmDialogProps) { + return ( + + + + Are you sure? + + This will delete the webhook configuration. This action cannot be undone. + + + + Cancel + + {isDeleting ? 'Deleting...' : 'Delete'} + + + + + ) +} + +interface UnsavedChangesDialogProps { + open: boolean + setOpen: (open: boolean) => void + onCancel: () => void + onConfirm: () => void +} + +export function UnsavedChangesDialog({ + open, + setOpen, + onCancel, + onConfirm, +}: UnsavedChangesDialogProps) { + return ( + + + + Unsaved changes + + You have unsaved changes. Are you sure you want to close without saving? + + + + Cancel + + Discard changes + + + + + ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/copyable.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/copyable.tsx new file mode 100644 index 000000000..169ced516 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/copyable.tsx @@ -0,0 +1,64 @@ +import { Check, Copy, Loader2 } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' + +interface CopyableFieldProps { + id: string + label: string + value: string + onChange?: (value: string) => void + placeholder?: string + description?: string + isLoading?: boolean + copied: string | null + copyType: string + copyToClipboard: (text: string, type: string) => void + readOnly?: boolean +} + +export function CopyableField({ + id, + label, + value, + onChange, + placeholder, + description, + isLoading = false, + copied, + copyType, + copyToClipboard, + readOnly = false, +}: CopyableFieldProps) { + return ( +
+ +
+ {isLoading ? ( +
+ +
+ ) : ( + onChange(e.target.value) : undefined} + placeholder={placeholder} + className="flex-1" + readOnly={readOnly} + /> + )} + +
+ {description &&

{description}

} +
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/test-result.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/test-result.tsx new file mode 100644 index 000000000..f9d8fba20 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/test-result.tsx @@ -0,0 +1,69 @@ +import { motion } from 'framer-motion' +import { Check, Copy } from 'lucide-react' +import { Button } from '@/components/ui/button' + +interface TestResultDisplayProps { + testResult: { + success: boolean + message?: string + test?: { + curlCommand?: string + status?: number + contentType?: string + responseText?: string + headers?: Record + samplePayload?: Record + } + } | null + copied: string | null + copyToClipboard: (text: string, type: string) => void + showCurlCommand?: boolean +} + +export function TestResultDisplay({ + testResult, + copied, + copyToClipboard, + showCurlCommand = false, +}: TestResultDisplayProps) { + if (!testResult) return null + + return ( + +

{testResult.message}

+ + {showCurlCommand && testResult.success && testResult.test?.curlCommand && ( + + +
{testResult.test.curlCommand}
+
+ )} +
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-footer.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-footer.tsx new file mode 100644 index 000000000..b592affdc --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-footer.tsx @@ -0,0 +1,92 @@ +import { Loader2, Trash2 } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { DialogFooter } from '@/components/ui/dialog' + +interface WebhookDialogFooterProps { + webhookId: string | undefined + webhookProvider: string + isSaving: boolean + isDeleting: boolean + isLoadingToken: boolean + isTesting: boolean + onSave: () => void + onDelete: () => void + onTest?: () => void + onClose: () => void +} + +export function WebhookDialogFooter({ + webhookId, + webhookProvider, + isSaving, + isDeleting, + isLoadingToken, + isTesting, + onSave, + onDelete, + onTest, + onClose, +}: WebhookDialogFooterProps) { + const showTestButton = + webhookId && (webhookProvider === 'whatsapp' || webhookProvider === 'generic') && onTest + + return ( + +
+ {webhookId && ( +
+ + {showTestButton && ( + + )} +
+ )} +
+
+ + +
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-header.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-header.tsx new file mode 100644 index 000000000..140943fb3 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-header.tsx @@ -0,0 +1,50 @@ +import { Badge } from '@/components/ui/badge' +import { DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog' +import { WEBHOOK_PROVIDERS } from '../../webhook-config' + +interface WebhookDialogHeaderProps { + webhookProvider: string + webhookId: string | undefined +} + +export function WebhookDialogHeader({ webhookProvider, webhookId }: WebhookDialogHeaderProps) { + const provider = WEBHOOK_PROVIDERS[webhookProvider] || WEBHOOK_PROVIDERS.generic + + // Get provider icon + const getProviderIcon = () => { + return provider.icon({ + className: 'h-5 w-5 text-green-500 dark:text-green-400', + }) + } + + // Get provider-specific title + const getProviderTitle = () => { + return `${provider.name} Integration` + } + + return ( + +
+
{getProviderIcon()}
+
+ {getProviderTitle()} + + {webhookProvider === 'generic' + ? 'Configure your webhook integration' + : `Configure your ${provider.name.toLowerCase()} integration`} + +
+
+
+ {webhookId && ( + + Connected + + )} +
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-url.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-url.tsx new file mode 100644 index 000000000..bcb697b06 --- /dev/null +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-url.tsx @@ -0,0 +1,42 @@ +import { Check, Copy, Loader2 } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' + +interface WebhookUrlFieldProps { + webhookUrl: string + isLoadingToken: boolean + copied: string | null + copyToClipboard: (text: string, type: string) => void +} + +export function WebhookUrlField({ + webhookUrl, + isLoadingToken, + copied, + copyToClipboard, +}: WebhookUrlFieldProps) { + return ( +
+ +
+ {isLoadingToken ? ( +
+ +
+ ) : ( + + )} + +
+
+ ) +} diff --git a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx index 2e2086863..7e060f431 100644 --- a/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx +++ b/sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx @@ -1,31 +1,16 @@ import { useEffect, useState } from 'react' -import { motion } from 'framer-motion' -import { Check, Copy, Loader2, Trash2 } from 'lucide-react' -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from '@/components/ui/alert-dialog' -import { Badge } from '@/components/ui/badge' -import { Button } from '@/components/ui/button' -import { Checkbox } from '@/components/ui/checkbox' -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' +import { Dialog, DialogContent } from '@/components/ui/dialog' import { createLogger } from '@/lib/logs/console-logger' import { ProviderConfig, WEBHOOK_PROVIDERS } from '../webhook-config' +import { GenericConfig } from './providers/generic-config' +import { GithubConfig } from './providers/github-config' +import { StripeConfig } from './providers/stripe-config' +import { WhatsAppConfig } from './providers/whatsapp-config' +import { DeleteConfirmDialog } from './ui/confirmation' +import { UnsavedChangesDialog } from './ui/confirmation' +import { WebhookDialogFooter } from './ui/webhook-footer' +import { WebhookDialogHeader } from './ui/webhook-header' +import { WebhookUrlField } from './ui/webhook-url' const logger = createLogger('WebhookModal') @@ -370,488 +355,58 @@ export function WebhookModal({ } } - // Get provider icon - const getProviderIcon = () => { - return provider.icon({ - className: 'h-5 w-5 text-green-500 dark:text-green-400', - }) - } - - // Get provider-specific title - const getProviderTitle = () => { - return `${provider.name} Integration` - } - - // Provider-specific setup instructions and configuration fields + // Provider-specific component rendering const renderProviderContent = () => { switch (webhookProvider) { case 'whatsapp': return ( -
-
- -
- {isLoadingToken ? ( -
- -
- ) : ( - setWhatsappVerificationToken(e.target.value)} - placeholder="Enter a verification token for WhatsApp" - className="flex-1" - /> - )} - -
-

- This token will be used to verify your webhook with WhatsApp. -

-
- - {testResult && ( - -

{testResult.message}

-
- )} - -
-

Setup Instructions

-
    -
  1. - 1. - Go to WhatsApp Business Platform dashboard -
  2. -
  3. - 2. - Navigate to "Configuration" in the sidebar -
  4. -
  5. - 3. - - Enter the URL above as "Callback URL" (exactly as shown) - -
  6. -
  7. - 4. - Enter your token as "Verify token" -
  8. -
  9. - 5. - - Click "Verify and save" and subscribe to "messages" - -
  10. -
-
-
- Requirements -
-
    -
  • - • - - URL must be publicly accessible with HTTPS - -
  • -
  • - • - - Self-signed SSL certificates not supported - -
  • -
  • - • - - For local testing, use ngrok to expose your server - -
  • -
-
-
-

- 💡 - After saving, use "Test" to verify your webhook configuration. -

-
-
-
+ ) case 'github': return ( -
-
- - {isLoadingToken ? ( -
- -
- ) : ( - setGithubContentType(e.target.value)} - placeholder="application/json" - className="flex-1" - /> - )} -
- -
-

Setup Instructions

-
    -
  1. Go to your GitHub repository
  2. -
  3. Navigate to Settings {'>'} Webhooks
  4. -
  5. Click "Add webhook"
  6. -
  7. Enter the Webhook URL shown above
  8. -
  9. Set Content type to "{githubContentType}"
  10. -
  11. Choose which events you want to trigger the webhook
  12. -
  13. Ensure "Active" is checked and save
  14. -
-
- -
-

- 💡 - After saving, GitHub will send a ping event to verify your webhook. -

-
-
+ ) case 'stripe': return ( -
-

Setup Instructions

-
    -
  1. Go to your Stripe Dashboard
  2. -
  3. Navigate to Developers {'>'} Webhooks
  4. -
  5. Click "Add endpoint"
  6. -
  7. Enter the Webhook URL shown above
  8. -
  9. Select the events you want to listen for
  10. -
  11. Add the endpoint
  12. -
- -
-

- 💡 - Stripe will send a test event to verify your webhook endpoint. -

-
-
+ ) case 'generic': - return ( -
-
-
- setRequireAuth(checked as boolean)} - /> - -
-
- - {requireAuth && ( -
-
- -
- {isLoadingToken ? ( -
- -
- ) : ( - setGeneralToken(e.target.value)} - placeholder="Enter an auth token" - className="flex-1" - /> - )} - -
-

- This token will be used to authenticate requests to your webhook (via Bearer - token). -

-
- -
- - setSecretHeaderName(e.target.value)} - placeholder="X-Secret-Key" - className="flex-1" - /> -

- Custom HTTP header name for passing the authentication token instead of using - Bearer authentication. -

-
-
- )} - -
- - setAllowedIps(e.target.value)} - placeholder="192.168.1.1, 10.0.0.1" - className="flex-1" - /> -

- Comma-separated list of IP addresses that are allowed to access this webhook. -

-
- - {testResult && testResult.success && ( - -

{testResult.message}

-
- )} - -
-

Setup Instructions

-
    -
  1. Copy the Webhook URL above
  2. -
  3. Configure your service to send HTTP POST requests to this URL
  4. - {requireAuth && ( - <> -
  5. - {secretHeaderName - ? `Add the "${secretHeaderName}" header with your token to all requests` - : 'Add an "Authorization: Bearer YOUR_TOKEN" header to all requests'} -
  6. - - )} -
- -
-

- 💡 - The webhook will receive all HTTP POST requests and pass the data to your - workflow. -

-
-
- - {testResult && testResult.success && testResult.test?.curlCommand && ( - - -
-                  {testResult.test.curlCommand}
-                
-
- )} - - {testResult && !testResult.success && ( - -

{testResult.message}

-
- )} -
- ) default: return ( -
-
- setRequireAuth(checked === true)} - className="h-3.5 w-3.5" - /> -
- -

- Enable authentication to secure your webhook endpoint. -

-
-
- - {requireAuth && ( -
-
- -
- {isLoadingToken ? ( -
- -
- ) : ( - setGeneralToken(e.target.value)} - placeholder="Enter an authentication token" - className="flex-1" - /> - )} - -
-

- This token will be used to authenticate requests to your webhook (via Bearer - token). -

-
- -
- - setSecretHeaderName(e.target.value)} - placeholder="X-Secret-Key" - className="flex-1" - /> -

- Custom HTTP header name for passing the authentication token instead of using - Bearer authentication. -

-
-
- )} - -
- - setAllowedIps(e.target.value)} - placeholder="192.168.1.1, 10.0.0.1" - className="flex-1" - /> -

- Comma-separated list of IP addresses that are allowed to access this webhook. -

-
- -
-

Setup Instructions

-
    -
  1. Copy the Webhook URL above
  2. -
  3. Configure your service to send HTTP POST requests to this URL
  4. - {requireAuth && ( - <> -
  5. - {secretHeaderName - ? `Add the "${secretHeaderName}" header with your token to all requests` - : 'Add an "Authorization: Bearer YOUR_TOKEN" header to all requests'} -
  6. - - )} -
- -
-

- 💡 - The webhook will receive all HTTP POST requests and pass the data to your - workflow. -

-
-
- - {testResult && ( - -

{testResult.message}

-
- )} -
+ ) } } @@ -860,153 +415,47 @@ export function WebhookModal({ <> - -
-
{getProviderIcon()}
-
- {getProviderTitle()} - - {webhookProvider === 'generic' - ? 'Configure your webhook integration' - : `Configure your ${provider.name.toLowerCase()} integration`} - -
-
-
- {webhookId && ( - - Connected - - )} -
-
+
-
- -
- {isLoadingToken ? ( -
- -
- ) : ( - - )} - -
-
+ {renderProviderContent()}
- -
- {webhookId && ( -
- - {(webhookProvider === 'whatsapp' || webhookProvider === 'generic') && ( - - )} -
- )} -
-
- - -
-
+ setShowDeleteConfirm(true)} + onTest={testWebhook} + onClose={handleClose} + />
- - - - Are you sure? - - This will delete the webhook configuration. This action cannot be undone. - - - - Cancel - - {isDeleting ? 'Deleting...' : 'Delete'} - - - - + - - - - Unsaved changes - - You have unsaved changes. Are you sure you want to close without saving? - - - - Cancel - - Discard changes - - - - + ) }