Skip to content

Commit ee3d8bc

Browse files
authored
feat[webhook]: added github webhook (#136)
1 parent 65d9f35 commit ee3d8bc

File tree

7 files changed

+117
-26
lines changed

7 files changed

+117
-26
lines changed

sim/app/blocks/blocks/starter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const StarterBlock: BlockConfig<StarterBlockOutput> = {
4040
options: [
4141
{ label: 'Generic', id: 'generic' },
4242
{ label: 'WhatsApp', id: 'whatsapp' },
43-
// { label: 'GitHub', id: 'github' },
43+
{ label: 'GitHub', id: 'github' },
4444
// { label: 'Stripe', id: 'stripe' },
4545
],
4646
value: () => 'generic',

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/providers/github-config.tsx

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
import { Loader2 } from 'lucide-react'
2-
import { Input } from '@/components/ui/input'
31
import { Label } from '@/components/ui/label'
2+
import {
3+
Select,
4+
SelectContent,
5+
SelectItem,
6+
SelectTrigger,
7+
SelectValue,
8+
} from '@/components/ui/select'
9+
import { CopyableField } from '../ui/copyable'
10+
import { TestResultDisplay } from '../ui/test-result'
411

512
interface GithubConfigProps {
613
contentType: string
714
setContentType: (contentType: string) => void
15+
webhookSecret: string
16+
setWebhookSecret: (secret: string) => void
17+
sslVerification: string
18+
setSslVerification: (value: string) => void
819
isLoadingToken: boolean
920
testResult: {
1021
success: boolean
@@ -13,50 +24,122 @@ interface GithubConfigProps {
1324
} | null
1425
copied: string | null
1526
copyToClipboard: (text: string, type: string) => void
27+
testWebhook: () => Promise<void>
1628
}
1729

1830
export function GithubConfig({
1931
contentType,
2032
setContentType,
33+
webhookSecret,
34+
setWebhookSecret,
35+
sslVerification,
36+
setSslVerification,
2137
isLoadingToken,
2238
testResult,
39+
copied,
40+
copyToClipboard,
2341
}: GithubConfigProps) {
2442
return (
2543
<div className="space-y-4">
2644
<div className="space-y-2">
2745
<Label htmlFor="github-content-type">Content Type</Label>
28-
{isLoadingToken ? (
29-
<div className="h-10 px-3 py-2 rounded-md border border-input bg-background flex items-center">
30-
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
31-
</div>
32-
) : (
33-
<Input
34-
id="github-content-type"
35-
value={contentType}
36-
onChange={(e) => setContentType(e.target.value)}
37-
placeholder="application/json"
38-
className="flex-1"
39-
/>
40-
)}
46+
<Select value={contentType} onValueChange={setContentType}>
47+
<SelectTrigger id="github-content-type">
48+
<SelectValue placeholder="Select content type" />
49+
</SelectTrigger>
50+
<SelectContent>
51+
<SelectItem value="application/json">application/json</SelectItem>
52+
<SelectItem value="application/x-www-form-urlencoded">
53+
application/x-www-form-urlencoded
54+
</SelectItem>
55+
</SelectContent>
56+
</Select>
57+
<p className="text-xs text-muted-foreground">
58+
Format GitHub will use when sending the webhook payload.
59+
</p>
4160
</div>
4261

62+
<CopyableField
63+
id="webhook-secret"
64+
label="Webhook Secret (Optional but Recommended)"
65+
value={webhookSecret}
66+
onChange={setWebhookSecret}
67+
placeholder="Enter a secret for GitHub webhook"
68+
description="A secret token to validate that webhook deliveries are coming from GitHub."
69+
isLoading={isLoadingToken}
70+
copied={copied}
71+
copyType="github-secret"
72+
copyToClipboard={copyToClipboard}
73+
/>
74+
75+
<div className="space-y-2">
76+
<Label htmlFor="github-ssl-verification">SSL Verification</Label>
77+
<Select value={sslVerification} onValueChange={setSslVerification}>
78+
<SelectTrigger id="github-ssl-verification">
79+
<SelectValue placeholder="Select SSL verification option" />
80+
</SelectTrigger>
81+
<SelectContent>
82+
<SelectItem value="enabled">Enabled (Recommended)</SelectItem>
83+
<SelectItem value="disabled">Disabled (Not recommended)</SelectItem>
84+
</SelectContent>
85+
</Select>
86+
<p className="text-xs text-muted-foreground">
87+
GitHub will verify SSL certificates when delivering webhooks.
88+
</p>
89+
</div>
90+
91+
<TestResultDisplay
92+
testResult={testResult}
93+
copied={copied}
94+
copyToClipboard={copyToClipboard}
95+
showCurlCommand={true}
96+
/>
97+
4398
<div className="space-y-2">
4499
<h4 className="font-medium">Setup Instructions</h4>
45100
<ol className="list-decimal list-inside space-y-1 text-sm">
46101
<li>Go to your GitHub repository</li>
47102
<li>Navigate to Settings {'>'} Webhooks</li>
48103
<li>Click "Add webhook"</li>
49-
<li>Enter the Webhook URL shown above</li>
104+
<li>Enter the Webhook URL shown above as the "Payload URL"</li>
50105
<li>Set Content type to "{contentType}"</li>
51-
<li>Choose which events you want to trigger the webhook</li>
52-
<li>Ensure "Active" is checked and save</li>
106+
{webhookSecret && (
107+
<li>Enter the same secret shown above in the "Secret" field for validation</li>
108+
)}
109+
<li>Choose SSL verification</li>
110+
<li>
111+
Choose which events trigger the webhook (e.g., "Just the push event" or "Send me
112+
everything")
113+
</li>
114+
<li>Ensure "Active" is checked and click "Add webhook"</li>
53115
</ol>
54116
</div>
55117

118+
<div className="bg-blue-50 dark:bg-blue-950 p-3 rounded-md mt-3 border border-blue-200 dark:border-blue-800">
119+
<h5 className="text-sm font-medium text-blue-800 dark:text-blue-300">
120+
Security Best Practices
121+
</h5>
122+
<ul className="mt-1 space-y-1">
123+
<li className="flex items-start">
124+
<span className="text-blue-500 dark:text-blue-400 mr-2"></span>
125+
<span className="text-sm text-blue-700 dark:text-blue-300">
126+
Always use a secret token to validate requests from GitHub
127+
</span>
128+
</li>
129+
<li className="flex items-start">
130+
<span className="text-blue-500 dark:text-blue-400 mr-2"></span>
131+
<span className="text-sm text-blue-700 dark:text-blue-300">
132+
Keep SSL verification enabled unless you have a specific reason to disable it
133+
</span>
134+
</li>
135+
</ul>
136+
</div>
137+
56138
<div className="bg-gray-50 dark:bg-gray-800 p-3 rounded-md mt-3 border border-gray-200 dark:border-gray-700">
57139
<p className="text-sm text-gray-700 dark:text-gray-300 flex items-center">
58140
<span className="text-gray-400 dark:text-gray-500 mr-2">💡</span>
59-
After saving, GitHub will send a ping event to verify your webhook.
141+
After saving, GitHub will send a ping event to verify your webhook. You can view delivery
142+
details and redeliver events from the webhook settings.
60143
</p>
61144
</div>
62145
</div>

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/copyable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function CopyableField({
3333
return (
3434
<div className="space-y-2">
3535
<Label htmlFor={id}>{label}</Label>
36-
<div className="flex items-center space-x-2">
36+
<div className="flex items-center space-x-2 pr-1">
3737
{isLoading ? (
3838
<div className="flex-1 h-10 px-3 py-2 rounded-md border border-input bg-background flex items-center">
3939
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
@@ -54,6 +54,7 @@ export function CopyableField({
5454
size="icon"
5555
onClick={() => copyToClipboard(value, copyType)}
5656
disabled={isLoading || !value}
57+
className="ml-1"
5758
>
5859
{copied === copyType ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
5960
</Button>

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function WebhookDialogFooter({
3131
webhookId && (webhookProvider === 'whatsapp' || webhookProvider === 'generic') && onTest
3232

3333
return (
34-
<DialogFooter className="flex justify-between mt-6 sticky bottom-0 py-3 bg-background border-t z-10">
34+
<DialogFooter className="flex justify-between sticky bottom-0 py-3 bg-background border-t z-10 mt-auto w-full">
3535
<div>
3636
{webhookId && (
3737
<div className="flex space-x-3">

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-header.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export function WebhookDialogHeader({ webhookProvider, webhookId }: WebhookDialo
1313
// Get provider icon
1414
const getProviderIcon = () => {
1515
return provider.icon({
16-
className: 'h-5 w-5 text-green-500 dark:text-green-400',
16+
className:
17+
webhookProvider === 'github' ? 'h-5 w-5' : 'h-5 w-5 text-green-500 dark:text-green-400',
1718
})
1819
}
1920

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/ui/webhook-url.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function WebhookUrlField({
1919
return (
2020
<div className="space-y-2">
2121
<Label htmlFor="webhook-url">Webhook URL</Label>
22-
<div className="flex items-center space-x-2">
22+
<div className="flex items-center space-x-2 pr-1">
2323
{isLoadingToken ? (
2424
<div className="flex-1 h-10 px-3 py-2 rounded-md border border-input bg-background flex items-center">
2525
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
@@ -33,6 +33,7 @@ export function WebhookUrlField({
3333
size="icon"
3434
onClick={() => copyToClipboard(webhookUrl, 'url')}
3535
disabled={isLoadingToken}
36+
className="ml-1"
3637
>
3738
{copied === 'url' ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
3839
</Button>

sim/app/w/[id]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,15 @@ export function WebhookModal({
374374
<GithubConfig
375375
contentType={githubContentType}
376376
setContentType={setGithubContentType}
377+
webhookSecret={generalToken}
378+
setWebhookSecret={setGeneralToken}
379+
sslVerification={requireAuth ? 'enabled' : 'disabled'}
380+
setSslVerification={(value) => setRequireAuth(value === 'enabled')}
377381
isLoadingToken={isLoadingToken}
378382
testResult={testResult}
379383
copied={copied}
380384
copyToClipboard={copyToClipboard}
385+
testWebhook={testWebhook}
381386
/>
382387
)
383388
case 'stripe':
@@ -414,10 +419,10 @@ export function WebhookModal({
414419
return (
415420
<>
416421
<Dialog open={isOpen} onOpenChange={handleClose}>
417-
<DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
422+
<DialogContent className="sm:max-w-[675px] max-h-[90vh] overflow-hidden flex flex-col">
418423
<WebhookDialogHeader webhookProvider={webhookProvider} webhookId={webhookId} />
419424

420-
<div className="space-y-4 py-2">
425+
<div className="space-y-4 py-2 px-2 overflow-y-auto flex-grow pb-6">
421426
<WebhookUrlField
422427
webhookUrl={webhookUrl}
423428
isLoadingToken={isLoadingToken}

0 commit comments

Comments
 (0)