Skip to content

Commit 1b03f75

Browse files
committed
feat(web): replace EmailIntegrationCard with EmailTriggerDialog and HttpIntegrationDialog for enhanced workflow integration management
1 parent 38d7020 commit 1b03f75

11 files changed

Lines changed: 441 additions & 332 deletions

apps/web/src/components/deployments/email-integration-card.tsx

Lines changed: 0 additions & 75 deletions
This file was deleted.

apps/web/src/components/ui/action-bar.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,23 @@ import { cn } from "@/utils/utils";
1111
export interface ActionBarGroupProps {
1212
children: React.ReactNode;
1313
vertical?: boolean;
14+
className?: string;
1415
}
1516

1617
export function ActionBarGroup({
1718
children,
1819
vertical = false,
20+
className = "",
1921
}: ActionBarGroupProps) {
2022
const horizontalClasses =
2123
"flex items-center gap-0.5 [&>*:first-child]:rounded-l-lg [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-r-lg [&>*:last-child]:rounded-l-none [&>*:only-child]:rounded-lg";
2224
const verticalClasses =
2325
"flex flex-col items-center gap-0.5 [&>*:first-child]:rounded-t-lg [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-b-lg [&>*:last-child]:rounded-t-none [&>*:only-child]:rounded-lg";
2426

2527
return (
26-
<div className={vertical ? verticalClasses : horizontalClasses}>
28+
<div
29+
className={cn(vertical ? verticalClasses : horizontalClasses, className)}
30+
>
2731
{children}
2832
</div>
2933
);
@@ -33,7 +37,7 @@ export interface ActionBarButtonProps {
3337
onClick: (e: React.MouseEvent) => void;
3438
disabled?: boolean;
3539
className?: string;
36-
tooltip: React.ReactNode;
40+
tooltip?: React.ReactNode;
3741
children: React.ReactNode;
3842
tooltipSide?: "top" | "bottom" | "left" | "right";
3943
}
@@ -46,20 +50,24 @@ export function ActionBarButton({
4650
children,
4751
tooltipSide = "top",
4852
}: ActionBarButtonProps) {
53+
const trigger = (
54+
<Button
55+
onClick={onClick}
56+
disabled={disabled}
57+
className={cn("h-10 px-3 rounded-none", className, {
58+
"opacity-50 cursor-not-allowed": disabled,
59+
})}
60+
>
61+
{children}
62+
</Button>
63+
);
64+
if (!tooltip) {
65+
return trigger;
66+
}
4967
return (
5068
<Tooltip delayDuration={0}>
5169
<div className="bg-background rounded-none overflow-hidden">
52-
<TooltipTrigger asChild>
53-
<Button
54-
onClick={onClick}
55-
disabled={disabled}
56-
className={cn("h-10 px-3 rounded-none", className, {
57-
"opacity-50 cursor-not-allowed": disabled,
58-
})}
59-
>
60-
{children}
61-
</Button>
62-
</TooltipTrigger>
70+
<TooltipTrigger asChild>{trigger}</TooltipTrigger>
6371
<TooltipContent side={tooltipSide}>{tooltip}</TooltipContent>
6472
</div>
6573
</Tooltip>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { Mail } from "lucide-react";
2+
import { toast } from "sonner";
3+
4+
import { Button } from "@/components/ui/button";
5+
import {
6+
Dialog,
7+
DialogContent,
8+
DialogDescription,
9+
DialogHeader,
10+
DialogTitle,
11+
} from "@/components/ui/dialog";
12+
import { Input } from "@/components/ui/input";
13+
import { Label } from "@/components/ui/label";
14+
15+
interface EmailTriggerDialogProps {
16+
isOpen: boolean;
17+
onClose: (open: boolean) => void;
18+
orgHandle: string;
19+
workflowHandle: string;
20+
deploymentVersion?: string;
21+
emailDomain?: string;
22+
}
23+
24+
export function EmailTriggerDialog({
25+
isOpen,
26+
onClose,
27+
orgHandle,
28+
workflowHandle,
29+
deploymentVersion,
30+
emailDomain = "dafthunk.com",
31+
}: EmailTriggerDialogProps) {
32+
let emailAddress = `workflow+${orgHandle}+${workflowHandle}`;
33+
if (deploymentVersion && deploymentVersion !== "latest") {
34+
emailAddress += `+${deploymentVersion}`;
35+
}
36+
emailAddress += `@${emailDomain}`;
37+
38+
const handleCopyEmail = () => {
39+
navigator.clipboard.writeText(emailAddress);
40+
toast.success("Email address copied to clipboard");
41+
};
42+
43+
const description = deploymentVersion
44+
? `Send emails to this address to trigger version ${deploymentVersion} of the workflow.`
45+
: "Send emails to this address to trigger the workflow. This will always trigger the latest deployed version of the workflow.";
46+
47+
return (
48+
<Dialog open={isOpen} onOpenChange={onClose}>
49+
<DialogContent className="max-w-2xl">
50+
<DialogHeader>
51+
<DialogTitle className="text-xl flex items-center gap-2">
52+
<Mail className="h-5 w-5" />
53+
Email Trigger
54+
</DialogTitle>
55+
<DialogDescription>{description}</DialogDescription>
56+
</DialogHeader>
57+
58+
<div className="space-y-4">
59+
<div className="space-y-2">
60+
<Label htmlFor="email-address">Workflow Email Address</Label>
61+
<div className="flex items-center gap-2">
62+
<Input
63+
id="email-address"
64+
value={emailAddress}
65+
readOnly
66+
className="font-mono h-9"
67+
/>
68+
<Button variant="outline" onClick={handleCopyEmail}>
69+
Copy
70+
</Button>
71+
</div>
72+
</div>
73+
74+
<div className="space-y-4">
75+
<div>
76+
<h4 className="text-sm font-medium mb-2">How it works:</h4>
77+
<ul className="list-disc pl-5 space-y-1 text-sm text-muted-foreground">
78+
<li>
79+
The email subject will be used as the 'subject' input for the
80+
workflow
81+
</li>
82+
<li>
83+
The email body (text version) will be used as the 'body' input
84+
for the workflow
85+
</li>
86+
<li>
87+
Your workflow must be configured to accept these inputs for
88+
the integration to work properly
89+
</li>
90+
<li>
91+
Only the text version of the email body is processed; HTML
92+
content is ignored
93+
</li>
94+
</ul>
95+
</div>
96+
97+
<div>
98+
<h4 className="text-sm font-medium mb-2">Example usage:</h4>
99+
<div className="bg-muted p-3 rounded-md text-sm font-mono">
100+
To: {emailAddress}
101+
<br />
102+
Subject: Process my document
103+
<br />
104+
Body: Please analyze the attached data and provide insights.
105+
</div>
106+
</div>
107+
</div>
108+
</div>
109+
</DialogContent>
110+
</Dialog>
111+
);
112+
}

apps/web/src/components/workflow/execution-email-dialog.tsx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ import {
1515
import { Button } from "@/components/ui/button";
1616
import { Input } from "@/components/ui/input";
1717
import { Label } from "@/components/ui/label";
18-
import { Textarea } from "@/components/ui/textarea"; // For body field
18+
import { Textarea } from "@/components/ui/textarea";
1919

20-
// Define the Zod schema as the primary source of truth for the form's shape
21-
const emailDialogZodSchema = z.object({
20+
const executionEmailDialogZodSchema = z.object({
2221
from: z
2322
.string()
2423
.email({ message: "Invalid email address for From field." })
@@ -27,45 +26,38 @@ const emailDialogZodSchema = z.object({
2726
body: z.string().min(1, { message: "Body is required." }),
2827
});
2928

30-
// Infer the TypeScript type from the Zod schema. This will be used by the form.
31-
type EmailDialogFormShape = z.infer<typeof emailDialogZodSchema>;
29+
type ExecutionEmailDialogFormShape = z.infer<
30+
typeof executionEmailDialogZodSchema
31+
>;
3232

33-
// The EmailData interface is exported for use by parent components/services.
34-
// It must be structurally identical to EmailDialogFormShape.
3533
export interface EmailData {
3634
from: string;
3735
subject: string;
3836
body: string;
3937
}
4038

41-
// Helper type assertion (optional, for development, can be removed)
42-
// This ensures EmailData and EmailDialogFormShape are compatible.
43-
type Assert<T, U extends T> = U;
44-
type _SchemaMatchesData = Assert<EmailData, EmailDialogFormShape>;
45-
type _DataMatchesSchema = Assert<EmailDialogFormShape, EmailData>;
46-
47-
type EmailDialogProps = {
39+
type ExecutionEmailDialogProps = {
4840
isOpen: boolean;
4941
onClose: () => void;
5042
// The onSubmit prop uses EmailData, which must align with EmailDialogFormShape
5143
onSubmit: (formData: EmailData) => void;
5244
onCancel?: () => void;
5345
};
5446

55-
export function EmailDialog({
47+
export function ExecutionEmailDialog({
5648
isOpen,
5749
onClose,
5850
onSubmit,
5951
onCancel,
60-
}: EmailDialogProps) {
52+
}: ExecutionEmailDialogProps) {
6153
const {
6254
control,
6355
handleSubmit,
6456
reset,
6557
formState: { errors, isDirty, isValid },
66-
} = useForm<EmailDialogFormShape>({
67-
// Use the inferred type from the Zod schema
68-
resolver: zodResolver(emailDialogZodSchema), // Use the Zod schema directly
58+
} = useForm<ExecutionEmailDialogFormShape>({
59+
// @ts-expect-error - zodResolver is not typed correctly
60+
resolver: zodResolver(executionEmailDialogZodSchema),
6961
mode: "onChange",
7062
defaultValues: {
7163
from: "",
@@ -85,7 +77,9 @@ export function EmailDialog({
8577
}, [isOpen, reset]);
8678

8779
// processSubmit now works with EmailDialogFormShape
88-
const processSubmit: SubmitHandler<EmailDialogFormShape> = (data) => {
80+
const processSubmit: SubmitHandler<ExecutionEmailDialogFormShape> = (
81+
data
82+
) => {
8983
// onSubmit expects EmailData. Since EmailDialogFormShape and EmailData are structurally identical,
9084
// this assignment is safe.
9185
onSubmit(data);

0 commit comments

Comments
 (0)