Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions products/workflows/frontend/Workflows/firstRunSender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,50 @@ async function provisionSandboxSender(): Promise<number> {
return sandbox.id
}

async function resolveFirstRunSender(allowSandbox: boolean): Promise<DefaultEmailSender | null> {
function teamDefaultSenderId(): number | null | undefined {
const team = teamLogic.findMounted()?.values.currentTeam
const integrations = await loadAllIntegrations()
const ownSender = resolveDefaultEmailSender(
integrations,
team && 'workflows_config' in team ? team.workflows_config?.default_email_integration_id : null
)
if (ownSender || !allowSandbox || !sandboxSenderEnabled() || verifiedOwnEmailSenders(integrations).length > 0) {
return ownSender
}
return team && 'workflows_config' in team ? team.workflows_config?.default_email_integration_id : null
}

function sandboxApplies(integrations: IntegrationType[], sandboxAllowed: boolean): boolean {
return sandboxAllowed && sandboxSenderEnabled() && verifiedOwnEmailSenders(integrations).length === 0
}

function chooseSender(integrations: IntegrationType[], sandboxAllowed: boolean): DefaultEmailSender | null {
const sandbox = integrations.find(isSandboxEmailSender)
return { integrationId: sandbox?.id ?? (await provisionSandboxSender()), reason: 'sandbox_sender' }
return sandbox && sandboxApplies(integrations, sandboxAllowed)
? { integrationId: sandbox.id, reason: 'sandbox_sender' }
: resolveDefaultEmailSender(integrations, teamDefaultSenderId())
}

async function resolveFirstRunSender(allowSandbox: boolean): Promise<DefaultEmailSender | null> {
const unmountIntegrations = integrationsLogic.mount()
try {
const integrations = await loadAllIntegrations()
if (!sandboxApplies(integrations, allowSandbox) || integrations.some(isSandboxEmailSender)) {
return chooseSender(integrations, allowSandbox)
}
return { integrationId: await provisionSandboxSender(), reason: 'sandbox_sender' }
} finally {
unmountIntegrations()
}
}

export async function prepareSandboxSender(): Promise<void> {
if (sandboxSenderEnabled() && !integrationsLogic.findMounted()?.values.sandboxEmailSender) {
await resolveFirstRunSender(true)
}
}

export function withInsertedStepSender(
action: HogFlowAction,
workflow: HogFlow,
integrations: IntegrationType[] | null
): { action: HogFlowAction; sender: DefaultEmailSender | null } {
const sender = takesOwnSender(action)
? chooseSender(integrations ?? [], takesSandboxSender(action, workflow))
: null
return { action: sender ? withSender(action, sender.integrationId) : action, sender }
}

export async function withFirstRunSender(
Expand All @@ -95,10 +127,7 @@ export async function withFirstRunSender(
if (!workflow.actions.some(takesOwnSender)) {
return { workflow, sender: null }
}
const unmountIntegrations = integrationsLogic.mount()
const sender = await resolveFirstRunSender(
workflow.actions.some((action) => takesSandboxSender(action, workflow))
).finally(unmountIntegrations)
const sender = await resolveFirstRunSender(workflow.actions.some((action) => takesSandboxSender(action, workflow)))
if (!sender) {
return { workflow, sender: null }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
TeamType,
UserBasicType,
} from '../../../../../frontend/src/types'
import { resolveDefaultEmailSender } from '../../Channels/defaultEmailSender'
import { optOutCategoriesLogic } from '../../OptOuts/optOutCategoriesLogic'
import type { MessageCategory } from '../../OptOuts/optOutCategoriesLogic'
import { prepareSandboxSender, withInsertedStepSender } from '../firstRunSender'
import { EXIT_NODE_ID, TRIGGER_NODE_ID, WorkflowLogicProps, workflowLogic } from '../workflowLogic'
import { getEdgeId } from './edgeId'
import { getFormattedNodes } from './react_flow_utils/autolayout'
Expand Down Expand Up @@ -99,7 +99,7 @@
/**
* Helper to get branch label with custom name fallback
*/
const getBranchLabel = (action: HogFlowAction | undefined, edge: HogFlow['edges'][0]): string => {

Check warning on line 102 in products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`getBranchLabel` has cyclomatic complexity 14 (warn >10)
if (!action) {
return `If condition #${(edge.index || 0) + 1} matches`
}
Expand Down Expand Up @@ -2074,6 +2074,13 @@
}
payload?: any
} // workflowLogic
setFeatureFlags: (
flags: string[],
variants: Record<string, boolean | string>
) => {
flags: string[]
variants: Record<string, boolean | string>
} // featureFlagLogic
setWorkflowAction: (
actionId: string,
action: HogFlowAction
Expand Down Expand Up @@ -2192,6 +2199,12 @@
onNodesDelete: (deleted: HogFlowActionNode[]) => {
deleted: HogFlowActionNode[]
}
prepareFirstRunSender: () => {
value: true
}
assignInsertedStepSender: (actionId: string) => {
actionId: string
}
resetFlowFromHogFlow: (hogFlow: HogFlow) => {
hogFlow: HogFlow
}
Expand Down Expand Up @@ -2314,12 +2327,16 @@
['setWorkflowInfo', 'setWorkflowAction', 'setWorkflowActionEdges', 'loadWorkflowSuccess'],
optOutCategoriesLogic(),
['loadCategories'],
featureFlagLogic,
['setFeatureFlags'],
],
})),
actions({
onEdgesChange: (edges: EdgeChange<HogFlowActionEdge>[]) => ({ edges }),
onNodesChange: (nodes: NodeChange<HogFlowActionNode>[]) => ({ nodes }),
onNodesDelete: (deleted: HogFlowActionNode[]) => ({ deleted }),
prepareFirstRunSender: true,
assignInsertedStepSender: (actionId: string) => ({ actionId }),
setNodes: (nodes: HogFlowActionNode[]) => ({ nodes }),
setDropzoneNodes: (dropzoneNodes: DropzoneNode[]) => ({
dropzoneNodes,
Expand Down Expand Up @@ -2589,7 +2606,7 @@
},
],
})),
listeners(({ values, actions }) => {
listeners(({ values, actions, cache }) => {
let animationTimeout: ReturnType<typeof setTimeout> | null = null
return {
onEdgesChange: ({ edges }) => {
Expand Down Expand Up @@ -2724,6 +2741,34 @@
actions.setNodesRaw(reconcileById(values.nodes, formattedNodes, (node) => node.id))
},

prepareFirstRunSender: async () => {
// A second setup while one runs would cancel its sender list load, so later calls share the running one.
cache.senderPreparation ??= prepareSandboxSender()
.catch(() => undefined)
.finally(() => {
cache.senderPreparation = null
})
await cache.senderPreparation
},
assignInsertedStepSender: async ({ actionId }) => {
await cache.senderPreparation
if (cache.disposables.isDisposed) {
return
}
const step = values.workflow.actions.find((action) => action.id === actionId)
if (!step) {
return
}
const { action, sender } = withInsertedStepSender(step, values.workflow, values.integrations)
if (sender) {
actions.setWorkflowAction(actionId, action)
// pinned: analytics event name
posthog.capture('email sender preselected', { surface: 'workflow', reason: sender.reason })
}
},
setFeatureFlags: () => {
actions.prepareFirstRunSender()
},
onNodesDelete: ({ deleted }) => {
if (deleted.some((node) => node.id === values.selectedNodeId)) {
actions.setSelectedNodeId(null)
Expand Down Expand Up @@ -2779,7 +2824,7 @@
}
}

edges.forEach((edge) => {

Check warning on line 2827 in products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`<anonymous>` has cyclomatic complexity 11 (warn >10)
if (skipEdgeIds.has(edge.id)) {
return
}
Expand Down Expand Up @@ -2856,7 +2901,7 @@
event.dataTransfer.dropEffect = 'move'
},

onDrop: ({ event, targetEdge, joinEdges }) => {

Check warning on line 2904 in products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`onDrop` has cyclomatic complexity 47 (warn >10)
event?.preventDefault()
const dropzoneNode = values.dropzoneNodes.find((x) => x.id === values.highlightedDropzoneNodeId)

Expand Down Expand Up @@ -2914,35 +2959,7 @@
}
}

if (!isHogFlowActionNode && 'template_id' in config && config.template_id === 'template-email') {
const emailInput = config.inputs?.email
const team = values.currentTeam
const sender = resolveDefaultEmailSender(
values.integrations,
team && 'workflows_config' in team
? team.workflows_config?.default_email_integration_id
: null
)
if (sender && emailInput?.value && !emailInput.value.from?.integrationId) {
config = {
...config,
inputs: {
...config.inputs,
email: {
...emailInput,
value: {
...emailInput.value,
from: { ...emailInput.value.from, integrationId: sender.integrationId },
},
},
},
}
// pinned: analytics event name
posthog.capture('email sender preselected', { surface: 'workflow', reason: sender.reason })
}
}

const newAction = {
const builtAction = {
id: isHogFlowActionNode
? (values.nodeToBeAdded as HogFlowActionNode).id
: `action_${partialNewAction.type}_${uuid()}`,
Expand All @@ -2960,6 +2977,14 @@
: {}),
} as HogFlowAction

const { action: newAction, sender } = isHogFlowActionNode
? { action: builtAction, sender: null }
: withInsertedStepSender(builtAction, values.workflow, values.integrations)
if (sender) {
// pinned: analytics event name
posthog.capture('email sender preselected', { surface: 'workflow', reason: sender.reason })
}

const step = getHogFlowStep(newAction, values.hogFunctionTemplatesById)

const branchEdges = isHogFlowActionNode
Expand Down Expand Up @@ -3059,6 +3084,9 @@
actions.setWorkflowInfo({ actions: newActions, edges: newEdges, variables: updatedVariables })
actions.setNodeToBeAdded(null)
actions.setSelectedNodeId(newAction.id)
if (!sender && !isHogFlowActionNode) {
actions.assignInsertedStepSender(newAction.id)
}
}
// We can clear the dropzones now
actions.hideDropzones()
Expand All @@ -3074,7 +3102,7 @@
actions.fitView({ noZoom: true })
}
},
fitView: ({ duration, noZoom }) => {

Check warning on line 3105 in products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`fitView` has cyclomatic complexity 15 (warn >10)
const { reactFlowWrapper, reactFlowInstance } = values
if (!reactFlowWrapper?.current || !reactFlowInstance) {
return
Expand Down Expand Up @@ -3287,6 +3315,7 @@
actions.setEditorLayout('advanced')
}
actions.resetFlowFromHogFlow(values.workflow)
actions.prepareFirstRunSender()

const handleKeyDown = (e: KeyboardEvent): void => {
if (e.key === 'Escape') {
Expand Down
Loading
Loading