Allow configuring the webhook body

This commit is contained in:
Owen
2026-05-02 13:26:35 -07:00
parent 96c450fd08
commit e1afbc226c
6 changed files with 158 additions and 15 deletions

View File

@@ -12,12 +12,15 @@ import {
} from "@app/components/ui/command";
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage
} from "@app/components/ui/form";
import { Input } from "@app/components/ui/input";
import { Switch } from "@app/components/ui/switch";
import { Textarea } from "@app/components/ui/textarea";
import {
Popover,
PopoverContent,
@@ -962,6 +965,69 @@ function WebhookActionFields({
/>
</div>
<WebhookHeadersField index={index} control={control} form={form} />
{/* Body Template */}
<div className="space-y-3">
<div>
<label className="font-medium text-sm block">
{t("httpDestBodyTemplateTitle")}
</label>
<p className="text-xs text-muted-foreground mt-0.5">
{t("httpDestBodyTemplateDescription")}
</p>
</div>
<FormField
control={control}
name={`actions.${index}.useBodyTemplate`}
render={({ field }) => (
<FormItem>
<div className="flex items-center gap-3">
<FormControl>
<Switch
id={`body-template-${index}`}
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<Label
htmlFor={`body-template-${index}`}
className="cursor-pointer"
>
{t("httpDestEnableBodyTemplate")}
</Label>
</div>
</FormItem>
)}
/>
{useWatch({
control,
name: `actions.${index}.useBodyTemplate`
}) && (
<FormField
control={control}
name={`actions.${index}.bodyTemplate`}
render={({ field }) => (
<FormItem>
<FormLabel>
{t("httpDestBodyTemplateLabel")}
</FormLabel>
<FormControl>
<Textarea
{...field}
placeholder={
'{{\n "event": "{{event}}",\n "timestamp": "{{timestamp}}",\n "status": "{{status}}",\n "data": {{data}}\n}}'
}
className="font-mono text-xs min-h-45 resize-y"
/>
</FormControl>
<FormDescription>
{t("httpDestBodyTemplateHint")}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)}
</div>
</div>
);
}

View File

@@ -368,7 +368,9 @@ export default function AlertRuleGraphEditor({
customHeaderName:
"",
customHeaderValue:
""
"",
useBodyTemplate: false,
bodyTemplate: ""
});
}
}}

View File

@@ -45,6 +45,8 @@ export type AlertRuleFormAction =
basicCredentials: string;
customHeaderName: string;
customHeaderValue: string;
useBodyTemplate: boolean;
bodyTemplate: string;
};
export type AlertRuleFormValues = {
@@ -130,6 +132,8 @@ export type AlertRuleApiResponse = {
customHeaderValue?: string;
headers?: { key: string; value: string }[];
method?: string;
useBodyTemplate?: boolean;
bodyTemplate?: string;
} | null;
}[];
};
@@ -187,7 +191,9 @@ export function buildFormSchema(t: (k: string) => string) {
bearerToken: z.string(),
basicCredentials: z.string(),
customHeaderName: z.string(),
customHeaderValue: z.string()
customHeaderValue: z.string(),
useBodyTemplate: z.boolean().default(false),
bodyTemplate: z.string().default("")
})
])
)
@@ -415,7 +421,9 @@ export function apiResponseToFormValues(
bearerToken: cfg?.bearerToken ?? "",
basicCredentials: cfg?.basicCredentials ?? "",
customHeaderName: cfg?.customHeaderName ?? "",
customHeaderValue: cfg?.customHeaderValue ?? ""
customHeaderValue: cfg?.customHeaderValue ?? "",
useBodyTemplate: cfg?.useBodyTemplate ?? false,
bodyTemplate: cfg?.bodyTemplate ?? ""
});
}
@@ -479,7 +487,11 @@ export function formValuesToApiPayload(
customHeaderName: action.customHeaderName || undefined,
customHeaderValue: action.customHeaderValue || undefined,
headers: action.headers.filter((h) => h.key.trim()),
method: action.method
method: action.method,
useBodyTemplate: action.useBodyTemplate || undefined,
bodyTemplate: action.useBodyTemplate
? action.bodyTemplate || undefined
: undefined
})
});
}