From 714a753aed1b96b2e0ea8c4c6bbb4b998ee88ce8 Mon Sep 17 00:00:00 2001
From: ogp-weeloong <135598754+ogp-weeloong@users.noreply.github.com>
Date: Tue, 9 Jun 2026 06:58:23 +0000
Subject: [PATCH] [EMAIL-PREVIEW-4] PLU-386: Enable email previews in
appropriate previous result data (#1655)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Problem
We want pipe owners to be able to preview their email across a variety of email clients (Outlook, Yahoo etc).
# High-level Approach
See #1652 for more details.
# This PR
Updates the "View" button in "Previous Result" section to support email previews for postman's previous result email:
1. Adds `email` to TDataOutMetadatumType
2. Make the "Previous Result" table use the email preview modal to render the "View" button when the type is `email`.
3. Sets postman email's dataout metadatum type to `email`, so that it launches the email modal when "View" is clicked.
### Beedio
# [Screen Recording 2026-06-02 at 10.36.28 PM.mov (uploaded via Graphite)
](https://app.graphite.com/user-attachments/video/637f57ce-3e6d-4d54-a190-55f85d40458d.mov)
# Tests
- [ ] Check that I can preview the previous result's email using the new email preview modal
- [ ] [Regression test] Check that other types of previous result previews (e.g. tiles previews) still use their appropriate modal
- [ ] [Regression test] Check that emails from published pipes have variables substituted correctly
---
.../get-data-out-metadata.ts | 2 +-
.../components/EmailPreviewModal/index.tsx | 4 ++-
.../RichTextEditor/PreviewButton.tsx | 2 +-
.../VariablesList/VariableItemWithModal.tsx | 36 +++++++++++++++++--
.../src/components/VariablesList/index.tsx | 15 ++++++--
packages/frontend/src/helpers/variables.ts | 1 +
packages/types/index.d.ts | 1 +
7 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/packages/backend/src/apps/postman/actions/send-transactional-email/get-data-out-metadata.ts b/packages/backend/src/apps/postman/actions/send-transactional-email/get-data-out-metadata.ts
index 27b4ff4aa..7d71dd0d0 100644
--- a/packages/backend/src/apps/postman/actions/send-transactional-email/get-data-out-metadata.ts
+++ b/packages/backend/src/apps/postman/actions/send-transactional-email/get-data-out-metadata.ts
@@ -16,7 +16,7 @@ async function getDataOutMetadata(
body: {
label: 'Body',
order: 2,
- type: 'html',
+ type: 'email',
displayedValue: 'Preview body',
},
recipient: {
diff --git a/packages/frontend/src/components/EmailPreviewModal/index.tsx b/packages/frontend/src/components/EmailPreviewModal/index.tsx
index 45753dffd..b5848c5ea 100644
--- a/packages/frontend/src/components/EmailPreviewModal/index.tsx
+++ b/packages/frontend/src/components/EmailPreviewModal/index.tsx
@@ -133,12 +133,14 @@ interface EmailPreviewModalProps {
isOpen: boolean
onClose: () => void
html: string
+ title: string
}
export default function EmailPreviewModal({
isOpen,
onClose,
html,
+ title,
}: EmailPreviewModalProps) {
const [selectedClientId, setSelectedClientId] = useState(
'outlook-windows-legacy',
@@ -161,7 +163,7 @@ export default function EmailPreviewModal({
- Preview your email
+ {title}
diff --git a/packages/frontend/src/components/RichTextEditor/PreviewButton.tsx b/packages/frontend/src/components/RichTextEditor/PreviewButton.tsx
index 74c3d4d05..75e195d6d 100644
--- a/packages/frontend/src/components/RichTextEditor/PreviewButton.tsx
+++ b/packages/frontend/src/components/RichTextEditor/PreviewButton.tsx
@@ -38,7 +38,7 @@ function usePreviewer(previewType: TFieldPreviewType | undefined) {
(props: PreviewerProps): ReactNode => {
switch (previewType) {
case 'email':
- return
+ return
}
return null
},
diff --git a/packages/frontend/src/components/VariablesList/VariableItemWithModal.tsx b/packages/frontend/src/components/VariablesList/VariableItemWithModal.tsx
index bb05b5b9c..cbb81dbb5 100644
--- a/packages/frontend/src/components/VariablesList/VariableItemWithModal.tsx
+++ b/packages/frontend/src/components/VariablesList/VariableItemWithModal.tsx
@@ -1,4 +1,4 @@
-import { useContext } from 'react'
+import { lazy, Suspense, useCallback, useContext, useTransition } from 'react'
import { useDisclosure } from '@chakra-ui/react'
import { EditorContext } from '@/contexts/Editor'
@@ -9,6 +9,8 @@ import HtmlVariableModal from './HtmlVariableModal'
import TableVariableModal from './TableVariableModal'
import { VariableItem } from '.'
+const LazyEmailPreviewModal = lazy(() => import('../EmailPreviewModal'))
+
interface VariableItemWithModalProps {
variable: Variable
onClick?: (variable: Variable) => void
@@ -35,7 +37,16 @@ export default function VariableItemWithModal(
const canOpenModal =
// we do not want to show a table preview if there are no rows
(variable.type === 'table' && variable.displayedValue !== '0 rows') ||
- variable.type === 'html'
+ variable.type === 'html' ||
+ variable.type === 'email'
+
+ const preloadModal = useCallback(() => {
+ if (variable.type === 'email') {
+ import('../EmailPreviewModal')
+ }
+ }, [variable.type])
+
+ const [isPending, startTransition] = useTransition()
const handleClick = () => {
if (!onClick) {
@@ -87,6 +98,19 @@ export default function VariableItemWithModal(
onClose={onModalClose}
/>
)
+ case 'email':
+ return (
+
+ {isModalOpen && (
+
+ )}
+
+ )
}
}
@@ -97,8 +121,14 @@ export default function VariableItemWithModal(
startTransition(() => onModalOpen())
+ : undefined
+ }
withViewButton={canOpenModal}
+ onViewButtonPreload={preloadModal}
+ isViewButtonLoading={isPending}
/>
{renderModal()}
>
diff --git a/packages/frontend/src/components/VariablesList/index.tsx b/packages/frontend/src/components/VariablesList/index.tsx
index 067f4c08c..1f18a8bba 100644
--- a/packages/frontend/src/components/VariablesList/index.tsx
+++ b/packages/frontend/src/components/VariablesList/index.tsx
@@ -22,7 +22,7 @@ import { POPOVER_MOTION_PROPS } from '@/theme/constants'
import VariableItemWithModal from './VariableItemWithModal'
-const VARIABLES_WITH_MODALS = ['table', 'html']
+const VARIABLES_WITH_MODALS = ['table', 'html', 'email']
const VARIABLE_ITEM_HEIGHT = 77
const SUGGESTION_VARIABLE_ITEM_HEIGHT = 61
@@ -92,11 +92,15 @@ export function VariableItem({
onClick,
isLast,
withViewButton,
+ onViewButtonPreload,
+ isViewButtonLoading,
}: {
variable: Variable
onClick?: (variable: Variable) => void
isLast?: boolean
withViewButton?: boolean
+ onViewButtonPreload?: () => void
+ isViewButtonLoading?: boolean
}): JSX.Element {
const shouldShowBottomBorder = !withViewButton && (onClick || isLast)
@@ -172,7 +176,14 @@ export function VariableItem({
{onClick && withViewButton && (
-