Skip to content

Commit ea76575

Browse files
committed
feat(api, web): update email handling to support new format and integrate EmailIntegrationCard in deployment pages
1 parent ab0f210 commit ea76575

5 files changed

Lines changed: 112 additions & 53 deletions

File tree

apps/api/src/email.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,29 @@ export async function handleIncomingEmail(
4545

4646
// Extract the handle from the to address
4747
const localPart = to.split("@")[0];
48-
const parts = localPart.split(".");
49-
let organizationIdOrHandle: string;
50-
let workflowIdOrHandle: string;
51-
let version: string;
52-
53-
if (parts.length === 2) {
54-
// Format: organizationIdOrHandle.workflowIdOrHandle@domain.com
55-
organizationIdOrHandle = parts[0];
56-
workflowIdOrHandle = parts[1];
57-
version = "latest"; // Default to latest if no version is specified
58-
} else if (parts.length === 3) {
59-
// Format: organizationIdOrHandle.workflowIdOrHandle.version@domain.com
60-
organizationIdOrHandle = parts[0];
61-
workflowIdOrHandle = parts[1];
62-
version = parts[2];
63-
} else {
48+
const parts = localPart.split("+");
49+
50+
if (parts.length < 3 || parts.length > 4) {
51+
console.error(
52+
`Invalid email format: ${to}. Expected <type>+<organizationIdOrHandle>+<workflowIdOrHandle>[+<version>]@domain.com`
53+
);
54+
return;
55+
}
56+
57+
let [triggerType, organizationIdOrHandle, workflowIdOrHandle, version] =
58+
parts;
59+
60+
if (triggerType !== "workflow") {
6461
console.error(
65-
`Invalid email format: ${to}. Expected organizationIdOrHandle.workflowIdOrHandle@domain.com or organizationIdOrHandle.workflowIdOrHandle.version@domain.com`
62+
`Invalid trigger type: ${triggerType}. Expected "workflow".`
6663
);
6764
return;
6865
}
6966

67+
if (!version) {
68+
version = "latest";
69+
}
70+
7071
const db = createDatabase(env.DB);
7172

7273
// Get workflow data either from deployment or directly from workflow

apps/api/src/routes/workflows.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { apiKeyOrJwtMiddleware, jwtMiddleware } from "../auth";
2121
import { ApiContext } from "../context";
2222
import {
2323
createDatabase,
24+
createHandle,
2425
createWorkflow,
2526
deleteWorkflow,
2627
ExecutionStatus,
@@ -96,10 +97,12 @@ workflowRoutes.post(
9697

9798
const workflowId = uuid();
9899
const workflowName = data.name || "Untitled Workflow";
100+
const workflowHandle = createHandle(workflowName);
101+
99102
const workflowData = {
100103
id: workflowId,
101104
name: workflowName,
102-
handle: workflowId,
105+
handle: workflowHandle,
103106
type: data.type,
104107
nodes: Array.isArray(data.nodes) ? data.nodes : [],
105108
edges: Array.isArray(data.edges) ? data.edges : [],
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Mail } from "lucide-react";
2+
import { toast } from "sonner";
3+
4+
import { Button } from "@/components/ui/button";
5+
import {
6+
Card,
7+
CardContent,
8+
CardDescription,
9+
CardHeader,
10+
CardTitle,
11+
} from "@/components/ui/card";
12+
import { Input } from "@/components/ui/input";
13+
import { Label } from "@/components/ui/label";
14+
15+
interface EmailIntegrationCardProps {
16+
orgHandle: string;
17+
workflowHandle: string;
18+
deploymentVersion?: string;
19+
emailDomain?: string;
20+
}
21+
22+
export function EmailIntegrationCard({
23+
orgHandle,
24+
workflowHandle,
25+
deploymentVersion,
26+
emailDomain = "dafthunk.com",
27+
}: EmailIntegrationCardProps) {
28+
let emailAddress = `workflow+${orgHandle}+${workflowHandle}`;
29+
if (deploymentVersion && deploymentVersion !== "latest") {
30+
emailAddress += `+${deploymentVersion}`;
31+
}
32+
emailAddress += `@${emailDomain}`;
33+
34+
const handleCopyEmail = () => {
35+
navigator.clipboard.writeText(emailAddress);
36+
toast.success("Email address copied to clipboard");
37+
};
38+
39+
const description = deploymentVersion
40+
? `Send emails to this address to trigger version ${deploymentVersion} of the workflow.`
41+
: "Send emails to this address to trigger the workflow. This will always trigger the latest deployed version of the workflow.";
42+
43+
return (
44+
<Card>
45+
<CardHeader>
46+
<CardTitle className="flex items-center text-xl">
47+
<Mail className="mr-2 h-4 w-4" />
48+
Email Integration
49+
</CardTitle>
50+
<CardDescription>{description}</CardDescription>
51+
</CardHeader>
52+
<CardContent>
53+
<div className="space-y-2">
54+
<Label htmlFor="email-address">Workflow Email Address</Label>
55+
<div className="flex items-center gap-2">
56+
<Input
57+
id="email-address"
58+
value={emailAddress}
59+
readOnly
60+
className="font-mono h-9"
61+
/>
62+
<Button variant="outline" onClick={handleCopyEmail}>
63+
Copy
64+
</Button>
65+
</div>
66+
</div>
67+
<p className="text-sm text-muted-foreground mt-4">
68+
The email subject will be used as the 'subject' input and the email
69+
body (text version) as the 'body' input for the workflow, if your
70+
workflow is configured to accept these inputs.
71+
</p>
72+
</CardContent>
73+
</Card>
74+
);
75+
}

apps/web/src/pages/workflows/deployment-detail-page.tsx

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { toast } from "sonner";
1818
import { useAuth } from "@/components/auth-context";
1919
import { ApiIntegrationCard } from "@/components/deployments/api-integration-card";
2020
import { DeploymentInfoCard } from "@/components/deployments/deployment-info-card";
21+
import { EmailIntegrationCard } from "@/components/deployments/email-integration-card";
2122
import { WorkflowInfoCard } from "@/components/deployments/workflow-info-card";
2223
import { InsetError } from "@/components/inset-error";
2324
import { InsetLoading } from "@/components/inset-loading";
@@ -293,41 +294,11 @@ export function DeploymentDetailPage() {
293294
);
294295

295296
case "email_message": {
296-
const emailAddress = `${workflow.handle}@${orgHandle}.workflows.dafthunk.com`;
297297
return (
298-
<Card>
299-
<CardHeader>
300-
<CardTitle className="flex items-center text-xl">
301-
<Mail className="mr-2 h-4 w-4" />
302-
Email Integration
303-
</CardTitle>
304-
<CardDescription>
305-
Send emails to this address to trigger the workflow
306-
</CardDescription>
307-
</CardHeader>
308-
<CardContent>
309-
<div className="space-y-2">
310-
<Label htmlFor="email-address">Email Address</Label>
311-
<div className="flex items-center gap-2">
312-
<Input
313-
id="email-address"
314-
value={emailAddress}
315-
readOnly
316-
className="font-mono h-9"
317-
/>
318-
<Button
319-
variant="outline"
320-
onClick={() => {
321-
navigator.clipboard.writeText(emailAddress);
322-
toast.success("Email address copied to clipboard");
323-
}}
324-
>
325-
Copy
326-
</Button>
327-
</div>
328-
</div>
329-
</CardContent>
330-
</Card>
298+
<EmailIntegrationCard
299+
orgHandle={orgHandle}
300+
workflowHandle={workflow.handle}
301+
/>
331302
);
332303
}
333304

apps/web/src/pages/workflows/deployment-version-page.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { toast } from "sonner";
77
import { useAuth } from "@/components/auth-context";
88
import { ApiIntegrationCard } from "@/components/deployments/api-integration-card";
99
import { DeploymentInfoCard } from "@/components/deployments/deployment-info-card";
10+
import { EmailIntegrationCard } from "@/components/deployments/email-integration-card";
1011
import { WorkflowInfoCard } from "@/components/deployments/workflow-info-card";
1112
import { InsetLoading } from "@/components/inset-loading";
1213
import { InsetLayout } from "@/components/layouts/inset-layout";
@@ -238,7 +239,7 @@ export function DeploymentVersionPage() {
238239
createdAt={deploymentVersion.createdAt}
239240
/>
240241

241-
{deploymentVersion && workflow && (
242+
{deploymentVersion && workflow && workflow.type === "http_request" && (
242243
<ApiIntegrationCard
243244
orgHandle={orgHandle}
244245
workflowId={workflow.id}
@@ -247,6 +248,14 @@ export function DeploymentVersionPage() {
247248
nodeTemplates={nodeTemplates}
248249
/>
249250
)}
251+
252+
{deploymentVersion && workflow && workflow.type === "email_message" && (
253+
<EmailIntegrationCard
254+
orgHandle={orgHandle}
255+
workflowHandle={workflow.handle}
256+
deploymentVersion={deploymentVersion.version.toString()}
257+
/>
258+
)}
250259
</TabsContent>
251260

252261
<TabsContent value="workflow" className="mt-4">

0 commit comments

Comments
 (0)