Remove workflow context + clean action config (#13919)

- Remove create related version and runs from workflow action config
- Remove WorkflowStepContextProvider. Use states instead
This commit is contained in:
Thomas Trompette
2025-08-14 12:17:07 +02:00
committed by GitHub
parent 08bf7b6dca
commit 50c4c50169
14 changed files with 118 additions and 112 deletions
@@ -6,6 +6,7 @@ import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
import { msg } from '@lingui/core/macro';
import React from 'react';
import { isDefined } from 'twenty-shared/utils';
@@ -84,6 +85,7 @@ export const useRelatedRecordActions = ({
(isDefined(selectedRecord) &&
!selectedRecord.isRemote &&
objectPermissions.canUpdateObjectRecords &&
!isWorkflowSubObjectMetadata(targetObjectNameSingular) &&
getTargetObjectWritePermission(
targetObjectNameSingular === CoreObjectNameSingular.TaskTarget
? CoreObjectNameSingular.Task
@@ -1,6 +1,6 @@
import { type ActionMenuContextType } from '@/action-menu/contexts/ActionMenuContext';
import { ActionMenuContextProviderDefault } from '@/action-menu/contexts/ActionMenuContextProviderDefault';
import { ActionMenuContextProviderWorkflowObjects } from '@/action-menu/contexts/ActionMenuContextProviderWorkflowObjects';
import { ActionMenuContextProviderWorkflowsEnabled } from '@/action-menu/contexts/ActionMenuContextProviderWorkflowsEnabled';
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
@@ -27,12 +27,18 @@ export const ActionMenuContextProvider = ({
objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId,
);
const isWorkflowObject =
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Workflow ||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.WorkflowRun ||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.WorkflowVersion;
if (!isDefined(objectMetadataItem)) {
return null;
}
if (isDefined(objectMetadataItem) && isWorkflowObject) {
const isWorkflowObject =
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Workflow;
if (!isDefined(objectMetadataItem)) {
return null;
}
if (isWorkflowObject) {
return (
<ActionMenuContextProviderWorkflowObjects
isInRightDrawer={isInRightDrawer}
@@ -45,18 +51,14 @@ export const ActionMenuContextProvider = ({
);
}
if (!isDefined(objectMetadataItem)) {
return null;
}
return (
<ActionMenuContextProviderWorkflowsEnabled
<ActionMenuContextProviderDefault
isInRightDrawer={isInRightDrawer}
displayType={displayType}
actionMenuType={actionMenuType}
objectMetadataItem={objectMetadataItem}
>
{children}
</ActionMenuContextProviderWorkflowsEnabled>
</ActionMenuContextProviderDefault>
);
};
@@ -10,7 +10,7 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
export const ActionMenuContextProviderWorkflowsEnabled = ({
export const ActionMenuContextProviderDefault = ({
objectMetadataItem,
isInRightDrawer,
displayType,
@@ -1,7 +1,6 @@
import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow';
import { CommandMenuWorkflowEditStepContent } from '@/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { isDefined } from 'twenty-shared/utils';
@@ -22,11 +21,7 @@ export const CommandMenuWorkflowEditStep = () => {
}),
}}
>
<WorkflowStepContextProvider
value={{ workflowVersionId: workflow.currentVersion.id }}
>
<CommandMenuWorkflowEditStepContent />
</WorkflowStepContextProvider>
<CommandMenuWorkflowEditStepContent />
</WorkflowVisualizerComponentInstanceContext.Provider>
);
};
@@ -10,7 +10,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail';
@@ -113,53 +112,46 @@ export const CommandMenuWorkflowRunViewStepContent = () => {
];
return (
<WorkflowStepContextProvider
value={{
workflowVersionId: workflowRun.workflowVersionId,
workflowRunId: workflowRun.id,
}}
>
<StyledContainer>
{shouldFocusNodeTab ? (
<WorkflowRunStepNodeDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
stepExecutionStatus={stepExecutionStatus}
<StyledContainer>
{shouldFocusNodeTab ? (
<WorkflowRunStepNodeDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
stepExecutionStatus={stepExecutionStatus}
/>
) : (
<>
<StyledTabList
tabs={tabs}
behaveAsLinks={false}
componentInstanceId={commandMenuPageComponentInstance.instanceId}
/>
) : (
<>
<StyledTabList
tabs={tabs}
behaveAsLinks={false}
componentInstanceId={commandMenuPageComponentInstance.instanceId}
{activeTabId === WorkflowRunTabId.OUTPUT ? (
<WorkflowRunStepOutputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
{activeTabId === WorkflowRunTabId.OUTPUT ? (
<WorkflowRunStepOutputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
{activeTabId === WorkflowRunTabId.NODE ? (
<WorkflowRunStepNodeDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
stepExecutionStatus={stepExecutionStatus}
/>
) : null}
{activeTabId === WorkflowRunTabId.NODE ? (
<WorkflowRunStepNodeDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
stepExecutionStatus={stepExecutionStatus}
/>
) : null}
{activeTabId === WorkflowRunTabId.INPUT ? (
<WorkflowRunStepInputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
</>
)}
</StyledContainer>
</WorkflowStepContextProvider>
{activeTabId === WorkflowRunTabId.INPUT ? (
<WorkflowRunStepInputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
</>
)}
</StyledContainer>
);
};
@@ -1,6 +1,5 @@
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
import styled from '@emotion/styled';
@@ -23,17 +22,13 @@ export const CommandMenuWorkflowViewStepContent = () => {
}
return (
<WorkflowStepContextProvider
value={{ workflowVersionId: flow.workflowVersionId }}
>
<StyledContainer>
<WorkflowStepDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
readonly
/>
</StyledContainer>
</WorkflowStepContextProvider>
<StyledContainer>
<WorkflowStepDetail
stepId={workflowSelectedNode}
trigger={flow.trigger}
steps={flow.steps}
readonly
/>
</StyledContainer>
);
};
@@ -1,4 +1,4 @@
import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext';
import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow';
import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector';
import { extractRawVariableNamePart } from '@/workflow/workflow-variables/utils/extractRawVariableNamePart';
import { searchVariableThroughOutputSchema } from '@/workflow/workflow-variables/utils/searchVariableThroughOutputSchema';
@@ -82,7 +82,7 @@ export const VariableChip = ({
}: VariableChipProps) => {
const theme = useTheme();
const { t } = useLingui();
const { workflowVersionId } = useWorkflowStepContextOrThrow();
const workflowVersionId = useWorkflowVersionIdOrThrow();
const stepId = extractRawVariableNamePart({
rawVariableName,
@@ -23,12 +23,6 @@ export const useIsRecordFieldReadOnly = ({
(field) => field.id === fieldMetadataId,
);
if (!fieldMetadataItem) {
throw new Error(
`Could not load read only property for field ${fieldMetadataId}`,
);
}
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const objectPermissions = getObjectPermissionsForObject(
@@ -41,6 +35,10 @@ export const useIsRecordFieldReadOnly = ({
objectMetadataId,
});
if (!fieldMetadataItem) {
return false;
}
return isRecordFieldReadOnly({
isRecordReadOnly,
objectPermissions,
@@ -0,0 +1,15 @@
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useWorkflowVersionIdOrThrow = () => {
const workflowVersionId = useRecoilComponentValue(
workflowVisualizerWorkflowVersionIdComponentState,
);
if (!isDefined(workflowVersionId)) {
throw new Error('Expected the workflow version ID to be defined');
}
return workflowVersionId;
};
@@ -1,9 +0,0 @@
import { createRequiredContext } from '~/utils/createRequiredContext';
type WorkflowStepContextType = {
workflowVersionId: string;
workflowRunId?: string;
};
export const [WorkflowStepContextProvider, useWorkflowStepContextOrThrow] =
createRequiredContext<WorkflowStepContextType>('WorkflowStepContext');
@@ -1,6 +1,9 @@
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
import { useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const WorkflowVisualizerEffect = ({
workflowId,
@@ -10,10 +13,21 @@ export const WorkflowVisualizerEffect = ({
const setWorkflowVisualizerWorkflowId = useSetRecoilComponentState(
workflowVisualizerWorkflowIdComponentState,
);
const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentState(
workflowVisualizerWorkflowVersionIdComponentState,
);
const workflow = useWorkflowWithCurrentVersion(workflowId);
useEffect(() => {
setWorkflowVisualizerWorkflowId(workflowId);
}, [setWorkflowVisualizerWorkflowId, workflowId]);
useEffect(() => {
if (isDefined(workflow)) {
setWorkflowVisualizerWorkflowVersionId(workflow.currentVersion.id);
}
}, [setWorkflowVisualizerWorkflowVersionId, workflow]);
return null;
};
@@ -1,6 +1,6 @@
import { SelectControl } from '@/ui/input/components/SelectControl';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext';
import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow';
import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector';
import { useGetFilterFieldMetadataItem } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useGetFilterFieldMetadataItem';
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
@@ -36,7 +36,7 @@ export const WorkflowStepFilterFieldSelect = ({
const { upsertStepFilterSettings } = useUpsertStepFilterSettings();
const { t } = useLingui();
const { workflowVersionId } = useWorkflowStepContextOrThrow();
const workflowVersionId = useWorkflowVersionIdOrThrow();
const stepId = extractRawVariableNamePart({
rawVariableName: stepFilter.stepOutputKey,
@@ -4,7 +4,7 @@ import { FormFieldInput } from '@/object-record/record-field/ui/components/FormF
import { FormSingleRecordPicker } from '@/object-record/record-field/ui/form-types/components/FormSingleRecordPicker';
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext';
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
import { type WorkflowFormAction } from '@/workflow/types/Workflow';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
@@ -36,16 +36,12 @@ export const WorkflowEditActionFormFiller = ({
const { getIcon } = useIcons();
const { submitFormStep } = useSubmitFormStep();
const [formData, setFormData] = useState<FormData>(action.settings.input);
const { workflowRunId } = useWorkflowStepContextOrThrow();
const workflowRunId = useWorkflowRunIdOrThrow();
const { goBackFromCommandMenu } = useCommandMenuHistory();
const { updateWorkflowRunStep } = useUpdateWorkflowRunStep();
const [error, setError] = useState<string | undefined>(undefined);
const canSubmit = !actionOptions.readonly && !isDefined(error);
if (!isDefined(workflowRunId)) {
throw new Error('Form filler action must be used in a workflow run');
}
const headerTitle = isDefined(action.name) ? action.name : `Form`;
const headerIcon = getActionIcon(action.type);
@@ -1,7 +1,8 @@
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
import { flowComponentState } from '@/workflow/states/flowComponentState';
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
import { type WorkflowVersion } from '@/workflow/types/Workflow';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
@@ -30,6 +31,18 @@ export const WorkflowStepDecorator: Decorator = (Story) => {
}),
getWorkflowMock().id,
);
set(
workflowVisualizerWorkflowVersionIdComponentState.atomFamily({
instanceId: workflowVisualizerComponentInstanceId,
}),
workflowVersion.id,
);
set(
workflowVisualizerWorkflowRunIdComponentState.atomFamily({
instanceId: workflowVisualizerComponentInstanceId,
}),
'123',
);
set(
workflowSelectedNodeComponentState.atomFamily({
instanceId: workflowVisualizerComponentInstanceId,
@@ -62,14 +75,7 @@ export const WorkflowStepDecorator: Decorator = (Story) => {
instanceId: workflowVisualizerComponentInstanceId,
}}
>
<WorkflowStepContextProvider
value={{
workflowVersionId: workflowVersion.id,
workflowRunId: '123',
}}
>
{ready && <Story />}
</WorkflowStepContextProvider>
{ready && <Story />}
</WorkflowVisualizerComponentInstanceContext.Provider>
);
};