From dc55fac1d59ba2f32706d9d1f851bead5fc4e36e Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Mon, 10 Mar 2025 15:56:14 +0100 Subject: [PATCH] Wrap all vizualizers into component context (#10755) Steps are broken when a variable is set. This is because component instance is not set for version and run visualizers. Each step viewer should be wrapped by the instance context. Each diagram visualizer should be responsible for populating the output schema. Also fixing a billing error when running workflow. --- .../CommandMenuWorkflowRunViewStep.tsx | 7 +++++-- .../components/CommandMenuWorkflowViewStep.tsx | 18 +++++++++++------- .../form-types/components/VariableChip.tsx | 4 ---- .../record-show/components/CardComponents.tsx | 4 ++-- .../workflow/hooks/useWorkflowVersion.ts | 3 ++- .../src/modules/workflow/states/flowState.ts | 1 + .../components/WorkflowDiagramEffect.tsx | 1 + .../components/WorkflowRunOutputVisualizer.tsx | 0 .../components/WorkflowRunVisualizer.tsx | 13 +++++++++---- .../components/WorkflowRunVisualizerEffect.tsx | 8 +++++++- .../components/WorkflowVersionVisualizer.tsx | 6 +++++- .../WorkflowVersionVisualizerEffect.tsx | 1 + .../RightDrawerWorkflowRunViewStep.tsx | 7 +++++-- .../components/RightDrawerWorkflowViewStep.tsx | 17 +++++++++++------ .../RightDrawerWorkflowRunViewStep.stories.tsx | 8 +++++++- .../utils/searchVariableThroughOutputSchema.ts | 7 +++++++ .../billing/services/billing-usage.service.ts | 6 ++++++ 17 files changed, 80 insertions(+), 31 deletions(-) rename packages/twenty-front/src/modules/workflow/{ => workflow-diagram}/components/WorkflowRunOutputVisualizer.tsx (100%) rename packages/twenty-front/src/modules/workflow/{ => workflow-diagram}/components/WorkflowRunVisualizer.tsx (51%) diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx index 4dd1bf926..9cd5d7fcd 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx @@ -4,6 +4,7 @@ import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; +import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -59,7 +60,9 @@ export const CommandMenuWorkflowRunViewStep = () => { } return ( - <> + { {activeTabId === 'input' ? ( ) : null} - + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx index 93586fdac..554579f96 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx @@ -1,17 +1,21 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; +import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; export const CommandMenuWorkflowViewStep = () => { const flow = useFlowOrThrow(); const workflowSelectedNode = useWorkflowSelectedNodeOrThrow(); - return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx index 23d3b64ce..55f9a29ea 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx @@ -83,10 +83,6 @@ export const VariableChip = ({ const stepOutputSchema = getStepsOutputSchema([stepId])?.[0]; - if (!isDefined(stepOutputSchema)) { - return null; - } - const { variableLabel, variablePathLabel } = searchVariableThroughOutputSchema({ stepOutputSchema, diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx index 7ccfec511..61db5c786 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx @@ -8,8 +8,8 @@ import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableE import { FieldsCard } from '@/object-record/record-show/components/FieldsCard'; import { CardType } from '@/object-record/record-show/types/CardType'; import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer'; -import { WorkflowRunOutputVisualizer } from '@/workflow/components/WorkflowRunOutputVisualizer'; -import { WorkflowRunVisualizer } from '@/workflow/components/WorkflowRunVisualizer'; +import { WorkflowRunOutputVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunOutputVisualizer'; +import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizer'; import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect'; import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer'; import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect'; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts index d16da6983..7c3ce4f07 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersion.ts @@ -2,7 +2,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { Workflow, WorkflowVersion } from '@/workflow/types/Workflow'; -export const useWorkflowVersion = (workflowVersionId: string) => { +export const useWorkflowVersion = (workflowVersionId?: string) => { const { record: workflowVersion } = useFindOneRecord< WorkflowVersion & { workflow: Omit & { @@ -30,6 +30,7 @@ export const useWorkflowVersion = (workflowVersionId: string) => { }, }, }, + skip: !workflowVersionId, }); return workflowVersion; diff --git a/packages/twenty-front/src/modules/workflow/states/flowState.ts b/packages/twenty-front/src/modules/workflow/states/flowState.ts index 21216f77a..228074ff1 100644 --- a/packages/twenty-front/src/modules/workflow/states/flowState.ts +++ b/packages/twenty-front/src/modules/workflow/states/flowState.ts @@ -3,6 +3,7 @@ import { createState } from '@ui/utilities/state/utils/createState'; export const flowState = createState< | { + workflowVersionId: string; trigger: WorkflowTrigger | null; steps: WorkflowAction[] | null; } diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx index f781581fe..3735632b4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx @@ -76,6 +76,7 @@ export const WorkflowDiagramEffect = ({ } setFlow({ + workflowVersionId: currentVersion.id, trigger: currentVersion.trigger, steps: currentVersion.steps, }); diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunOutputVisualizer.tsx similarity index 100% rename from packages/twenty-front/src/modules/workflow/components/WorkflowRunOutputVisualizer.tsx rename to packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunOutputVisualizer.tsx diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowRunVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx similarity index 51% rename from packages/twenty-front/src/modules/workflow/components/WorkflowRunVisualizer.tsx rename to packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx index 63a69fdec..b4890ede3 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowRunVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx @@ -1,9 +1,11 @@ import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; +import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { WorkflowRunDiagramCanvas } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvas'; +import { WorkflowVersionOutputSchemaEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared'; -const StyledSourceCodeContainer = styled.div` +const StyledContainer = styled.div` height: 100%; `; @@ -13,13 +15,16 @@ export const WorkflowRunVisualizer = ({ workflowRunId: string; }) => { const workflowRun = useWorkflowRun({ workflowRunId }); - if (!isDefined(workflowRun)) { + const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId); + + if (!isDefined(workflowRun) || !isDefined(workflowVersion)) { return null; } return ( - + + - + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx index dad655f5c..7db1186b1 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx @@ -31,6 +31,7 @@ export const WorkflowRunVisualizerEffect = ({ } setFlow({ + workflowVersionId: workflowRun.workflowVersionId, trigger: workflowRun.output.flow.trigger, steps: workflowRun.output.flow.steps, }); @@ -42,7 +43,12 @@ export const WorkflowRunVisualizerEffect = ({ }); setWorkflowDiagram(nextWorkflowDiagram); - }, [setFlow, setWorkflowDiagram, workflowRun?.output]); + }, [ + setFlow, + setWorkflowDiagram, + workflowRun?.output, + workflowRun?.workflowVersionId, + ]); return null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx index 9d909a6eb..349812afa 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx @@ -1,5 +1,6 @@ import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { WorkflowDiagramCanvasReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonly'; +import { WorkflowVersionOutputSchemaEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect'; import '@xyflow/react/dist/style.css'; import { isDefined } from 'twenty-shared'; @@ -11,6 +12,9 @@ export const WorkflowVersionVisualizer = ({ const workflowVersion = useWorkflowVersion(workflowVersionId); return isDefined(workflowVersion) ? ( - + <> + + + ) : null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx index 47c0024fe..e73cafc95 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx @@ -25,6 +25,7 @@ export const WorkflowVersionVisualizerEffect = ({ } setFlow({ + workflowVersionId: workflowVersion.id, trigger: workflowVersion.trigger, steps: workflowVersion.steps, }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx index b52f33114..bb628304f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx @@ -4,6 +4,7 @@ import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; +import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail'; import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail'; @@ -65,7 +66,9 @@ export const RightDrawerWorkflowRunViewStep = () => { } return ( - <> + { {activeTabId === 'output' ? ( ) : null} - + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx index 8b7d76b1e..727ddc656 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx @@ -1,4 +1,5 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; +import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -7,11 +8,15 @@ export const RightDrawerWorkflowViewStep = () => { const workflowSelectedNode = useWorkflowSelectedNodeOrThrow(); return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/RightDrawerWorkflowRunViewStep.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/RightDrawerWorkflowRunViewStep.stories.tsx index b95716a05..1a1c8131a 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/RightDrawerWorkflowRunViewStep.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/RightDrawerWorkflowRunViewStep.stories.tsx @@ -40,7 +40,13 @@ const meta: Meta = { ); const setWorkflowRunId = useSetRecoilState(workflowRunIdState); - setFlow(oneFailedWorkflowRunQueryResult.workflowRun.output.flow); + setFlow({ + workflowVersionId: + oneFailedWorkflowRunQueryResult.workflowRun.workflowVersionId, + trigger: + oneFailedWorkflowRunQueryResult.workflowRun.output.flow.trigger, + steps: oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps, + }); setWorkflowSelectedNode( oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps[0].id, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughOutputSchema.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughOutputSchema.ts index dec4d50d0..642677ed6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughOutputSchema.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughOutputSchema.ts @@ -93,6 +93,13 @@ export const searchVariableThroughOutputSchema = ({ rawVariableName: string; isFullRecord?: boolean; }) => { + if (!isDefined(stepOutputSchema)) { + return { + variableLabel: undefined, + variablePathLabel: undefined, + }; + } + const variableWithoutBrackets = rawVariableName.replace( CAPTURE_ALL_VARIABLE_TAG_INNER_REGEX, (_, variableName) => { diff --git a/packages/twenty-server/src/engine/core-modules/billing/services/billing-usage.service.ts b/packages/twenty-server/src/engine/core-modules/billing/services/billing-usage.service.ts index fb7d2732f..c8a51ed3f 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/services/billing-usage.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/services/billing-usage.service.ts @@ -13,6 +13,7 @@ import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billin import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service'; import { StripeBillingMeterEventService } from 'src/engine/core-modules/billing/stripe/services/stripe-billing-meter-event.service'; import { BillingUsageEvent } from 'src/engine/core-modules/billing/types/billing-usage-event.type'; +import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; @Injectable() export class BillingUsageService { @@ -22,9 +23,14 @@ export class BillingUsageService { private readonly billingCustomerRepository: Repository, private readonly billingSubscriptionService: BillingSubscriptionService, private readonly stripeBillingMeterEventService: StripeBillingMeterEventService, + private readonly environmentService: EnvironmentService, ) {} async canFeatureBeUsed(workspaceId: string): Promise { + if (!this.environmentService.get('IS_BILLING_ENABLED')) { + return true; + } + const billingSubscription = await this.billingSubscriptionService.getCurrentBillingSubscriptionOrThrow( {