Email preview in the run
This commit is contained in:
+18
@@ -19,6 +19,7 @@ import type { LoaderArgs } from "@remix-run/server-runtime";
|
||||
import type { Delay, Scheduled } from "@trigger.dev/common-schemas";
|
||||
import classNames from "classnames";
|
||||
import humanizeDuration from "humanize-duration";
|
||||
import { integrations } from "internal-integrations";
|
||||
import type { ReactNode } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
@@ -642,6 +643,12 @@ function IntegrationRequestStep({
|
||||
const organization = useCurrentOrganization();
|
||||
invariant(organization, "Organization must be set");
|
||||
|
||||
const internalIntegration = integrations[request.service.slug];
|
||||
const component = internalIntegration.requests?.renderComponent(
|
||||
request.input,
|
||||
request.output
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header2 size="small" className="text-slate-300 mb-2">
|
||||
@@ -712,6 +719,17 @@ function IntegrationRequestStep({
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
{component !== null && (
|
||||
<>
|
||||
<Body
|
||||
size="extra-small"
|
||||
className={`mt-4 mb-1 ${workflowNodeUppercaseClasses}`}
|
||||
>
|
||||
Preview
|
||||
</Body>
|
||||
<div>{component}</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"devDependencies": {
|
||||
"@trigger.dev/providers": "workspace:*",
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/node": "16",
|
||||
"@trigger.dev/providers": "workspace:*",
|
||||
"@types/react": "^18.0.21",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"scripts": {},
|
||||
@@ -20,6 +21,7 @@
|
||||
"@urql/core": "^3.1.1",
|
||||
"debug": "^4.3.4",
|
||||
"graphql": "^16.6.0",
|
||||
"react": "^18.2.0",
|
||||
"urql": "^3.0.3",
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
|
||||
+57
-1
@@ -10,8 +10,8 @@ import {
|
||||
import { resend } from "@trigger.dev/providers";
|
||||
import debug from "debug";
|
||||
import { getAccessToken } from "../accessInfo";
|
||||
import { z } from "zod";
|
||||
import { SendEmailBodySchema } from "@trigger.dev/providers/providers/resend/schemas";
|
||||
import React from "react";
|
||||
|
||||
const log = debug("trigger:integrations:resend");
|
||||
|
||||
@@ -50,6 +50,7 @@ class ResendRequestIntegration implements RequestIntegration {
|
||||
title: `Send email to ${
|
||||
typeof parsed.to === "string" ? parsed.to : parsed.to.join(", ")
|
||||
}`,
|
||||
properties: [],
|
||||
};
|
||||
}
|
||||
default: {
|
||||
@@ -58,6 +59,42 @@ class ResendRequestIntegration implements RequestIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
renderComponent(input: any, output: any): React.ReactNode {
|
||||
const parsedInput = resend.schemas.SendEmailBodySchema.parse(input);
|
||||
return (
|
||||
<div className="bg-white rounded-md">
|
||||
<div className="flex px-2 h-8 items-center bg-slate-100 rounded-t-md">
|
||||
<div className="flex h-8 gap-2 items-center bg-slate-100 rounded-t-md">
|
||||
<div className="rounded-full bg-rose-500 w-3 h-3"></div>
|
||||
<div className="rounded-full bg-orange-500 w-3 h-3"></div>
|
||||
<div className="rounded-full bg-emerald-500 w-3 h-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-4 py-2 border-b border-slate-300">
|
||||
<h2 className="text-lg text-slate-600 font-bold">
|
||||
{parsedInput.from}
|
||||
</h2>
|
||||
<h2 className="text-slate-600">{parsedInput.subject}</h2>
|
||||
<div className="flex gap-2">
|
||||
<EmailInfo label="to" value={parsedInput.to} />
|
||||
<EmailInfo label="cc" value={parsedInput.cc} />
|
||||
<EmailInfo label="bcc" value={parsedInput.bcc} />
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<EmailInfo label="reply to" value={parsedInput.reply_to} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-4">
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: parsedInput.text ?? parsedInput.html ?? "",
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async #sendEmail(
|
||||
accessInfo: AccessInfo,
|
||||
params: any,
|
||||
@@ -124,3 +161,22 @@ class ResendRequestIntegration implements RequestIntegration {
|
||||
}
|
||||
|
||||
export const requests = new ResendRequestIntegration();
|
||||
|
||||
function EmailInfo({
|
||||
label,
|
||||
value,
|
||||
}: {
|
||||
label: string;
|
||||
value?: string | string[];
|
||||
}) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-slate-500 text-sm flex items-baseline gap-2">
|
||||
<h3 className="text-slate-400">{label}:</h3>
|
||||
{typeof value === "string" ? value : value.join(", ")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import { shopify } from "@trigger.dev/providers";
|
||||
import { Client, createClient } from "@urql/core";
|
||||
import debug from "debug";
|
||||
import { ReactNode } from "react";
|
||||
import {
|
||||
DisplayProperties,
|
||||
PerformedRequestResponse,
|
||||
PerformRequestOptions,
|
||||
RequestIntegration,
|
||||
} from "../types";
|
||||
import { Client, createClient, gql } from "@urql/core";
|
||||
import { shopify } from "@trigger.dev/providers";
|
||||
import {
|
||||
addProductsToCollectionQuery,
|
||||
appendProductImagesQuery,
|
||||
@@ -166,6 +167,10 @@ class ShopifyRequestIntegration implements RequestIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
renderComponent(input: any, output: any): ReactNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #searchProductVariants(
|
||||
client: Client,
|
||||
params: any
|
||||
|
||||
@@ -11,6 +11,7 @@ import { slack } from "@trigger.dev/providers";
|
||||
import debug from "debug";
|
||||
import { getAccessToken } from "../accessInfo";
|
||||
import { z } from "zod";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
const log = debug("trigger:integrations:slack");
|
||||
|
||||
@@ -82,6 +83,10 @@ class SlackRequestIntegration implements RequestIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
renderComponent(input: any, output: any): ReactNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #postMessage(
|
||||
accessInfo: AccessInfo,
|
||||
params: any,
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface RequestIntegration {
|
||||
options: PerformRequestOptions
|
||||
) => Promise<PerformedRequestResponse>;
|
||||
displayProperties: (endpoint: string, params: any) => DisplayProperties;
|
||||
renderComponent(input: any, output: any): React.ReactNode;
|
||||
}
|
||||
|
||||
export interface WebhookIntegration {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/node16.json",
|
||||
"include": ["./src/**/*.ts"],
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"baseUrl": ".",
|
||||
|
||||
Generated
+4
@@ -700,9 +700,11 @@ importers:
|
||||
'@trigger.dev/tsconfig': workspace:*
|
||||
'@types/debug': ^4.1.7
|
||||
'@types/node': '16'
|
||||
'@types/react': ^18.0.21
|
||||
'@urql/core': ^3.1.1
|
||||
debug: ^4.3.4
|
||||
graphql: ^16.6.0
|
||||
react: ^18.2.0
|
||||
typescript: ^4.9.4
|
||||
urql: ^3.0.3
|
||||
zod: ^3.20.2
|
||||
@@ -713,6 +715,7 @@ importers:
|
||||
'@urql/core': 3.1.1_graphql@16.6.0
|
||||
debug: 4.3.4
|
||||
graphql: 16.6.0
|
||||
react: 18.2.0
|
||||
urql: 3.0.3_onqnqwb3ubg5opvemcqf7c2qhy
|
||||
zod: 3.20.2
|
||||
devDependencies:
|
||||
@@ -720,6 +723,7 @@ importers:
|
||||
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
|
||||
'@types/debug': 4.1.7
|
||||
'@types/node': 16.18.11
|
||||
'@types/react': 18.0.26
|
||||
typescript: 4.9.4
|
||||
|
||||
packages/internal-platform:
|
||||
|
||||
Reference in New Issue
Block a user