feat: Add If/Else node (#16833)
Closes [#1265](https://github.com/twentyhq/core-team-issues/issues/1265)
This commit is contained in:
+2
-2
@@ -10,8 +10,8 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow';
|
||||
import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
|
||||
import { getStepFilterOperands } from '@/workflow/workflow-steps/workflow-actions/filter-action/utils/getStepFilterOperands';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings';
|
||||
import { getStepFilterOperands } from '@/workflow/workflow-steps/filters/utils/getStepFilterOperands';
|
||||
import { useVariableDropdown } from '@/workflow/workflow-variables/hooks/useVariableDropdown';
|
||||
import { isRecordOutputSchemaV2 } from '@/workflow/workflow-variables/types/guards/isRecordOutputSchemaV2';
|
||||
import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2';
|
||||
+12
@@ -15,6 +15,7 @@ import { WorkflowEditActionUpsertRecord } from '@/workflow/workflow-steps/workfl
|
||||
import { WorkflowEditActionDelay } from '@/workflow/workflow-steps/workflow-actions/delay-actions/components/WorkflowEditActionDelay';
|
||||
import { WorkflowEditActionFilter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
|
||||
import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords';
|
||||
import { WorkflowEditActionIfElse } from '@/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElse';
|
||||
import { WorkflowEditActionFormFiller } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller';
|
||||
import { WorkflowEditActionHttpRequest } from '@/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest';
|
||||
import { WorkflowEditActionIterator } from '@/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator';
|
||||
@@ -230,6 +231,17 @@ export const WorkflowRunStepNodeDetail = ({
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'IF_ELSE': {
|
||||
return (
|
||||
<WorkflowEditActionIfElse
|
||||
key={stepId}
|
||||
action={stepDefinition.definition}
|
||||
actionOptions={{
|
||||
readonly: true,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'ITERATOR': {
|
||||
return (
|
||||
<WorkflowEditActionIterator
|
||||
|
||||
+10
@@ -14,6 +14,7 @@ import { WorkflowEditActionUpsertRecord } from '@/workflow/workflow-steps/workfl
|
||||
import { WorkflowEditActionDelay } from '@/workflow/workflow-steps/workflow-actions/delay-actions/components/WorkflowEditActionDelay';
|
||||
import { WorkflowEditActionFilter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
|
||||
import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords';
|
||||
import { WorkflowEditActionIfElse } from '@/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElse';
|
||||
import { WorkflowEditActionFormBuilder } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder';
|
||||
import { WorkflowEditActionHttpRequest } from '@/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest';
|
||||
import { WorkflowEditActionIterator } from '@/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator';
|
||||
@@ -210,6 +211,15 @@ export const WorkflowStepDetail = ({
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'IF_ELSE': {
|
||||
return (
|
||||
<WorkflowEditActionIfElse
|
||||
key={stepId}
|
||||
action={stepDefinition.definition}
|
||||
actionOptions={props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'ITERATOR': {
|
||||
return (
|
||||
<WorkflowEditActionIterator
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState';
|
||||
import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFiltersComponentFamilyState';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState';
|
||||
import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import {
|
||||
type StepFilterGroup,
|
||||
+2
-2
@@ -4,8 +4,8 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings';
|
||||
import {
|
||||
StepLogicalOperator,
|
||||
ViewFilterOperand,
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { useAddRootStepFilter } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useAddRootStepFilter';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { useAddRootStepFilter } from '@/workflow/workflow-steps/filters/hooks/useAddRootStepFilter';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useContext } from 'react';
|
||||
+38
-7
@@ -1,18 +1,24 @@
|
||||
import { AdvancedFilterCommandMenuColumn } from '@/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuColumn';
|
||||
import { WorkflowStepFilterFieldSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
import { WorkflowStepFilterOperandSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterOperandSelect';
|
||||
import { WorkflowStepFilterOptionsDropdown } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterOptionsDropdown';
|
||||
import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueInput';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { WorkflowStepFilterFieldSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
import { WorkflowStepFilterOperandSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterOperandSelect';
|
||||
import { WorkflowStepFilterOptionsDropdown } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterOptionsDropdown';
|
||||
import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type WorkflowStepFilterColumnProps = {
|
||||
stepFilterGroup: StepFilterGroup;
|
||||
stepFilter: StepFilter;
|
||||
stepFilterIndex: number;
|
||||
isIfBranch?: boolean;
|
||||
firstFilterLabel?: string;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@@ -26,17 +32,42 @@ export const WorkflowStepFilterColumn = ({
|
||||
stepFilterGroup,
|
||||
stepFilter,
|
||||
stepFilterIndex,
|
||||
isIfBranch,
|
||||
firstFilterLabel,
|
||||
}: WorkflowStepFilterColumnProps) => {
|
||||
const { readonly } = useContext(WorkflowStepFilterContext);
|
||||
|
||||
const stepFilterGroups = useRecoilComponentValue(
|
||||
currentStepFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const rootStepFilterGroup = stepFilterGroups?.find(
|
||||
(filterGroup) => !isDefined(filterGroup.parentStepFilterGroupId),
|
||||
);
|
||||
|
||||
const { childStepFilters, childStepFilterGroups } =
|
||||
useChildStepFiltersAndChildStepFilterGroups({
|
||||
stepFilterGroupId: rootStepFilterGroup?.id ?? '',
|
||||
});
|
||||
|
||||
const isLastFilterInIfBranch =
|
||||
isIfBranch &&
|
||||
isDefined(rootStepFilterGroup) &&
|
||||
stepFilter.stepFilterGroupId === rootStepFilterGroup.id &&
|
||||
childStepFilters.length === 1 &&
|
||||
childStepFilterGroups.length === 0;
|
||||
|
||||
const shouldShowDropdown = !readonly && !isLastFilterInIfBranch;
|
||||
|
||||
return (
|
||||
<AdvancedFilterCommandMenuColumn>
|
||||
<StyledContainer>
|
||||
<WorkflowStepFilterLogicalOperatorCell
|
||||
index={stepFilterIndex}
|
||||
stepFilterGroup={stepFilterGroup}
|
||||
firstFilterLabel={firstFilterLabel}
|
||||
/>
|
||||
{!readonly && (
|
||||
{shouldShowDropdown && (
|
||||
<WorkflowStepFilterOptionsDropdown stepFilterId={stepFilter.id} />
|
||||
)}
|
||||
</StyledContainer>
|
||||
+2
-2
@@ -2,8 +2,8 @@ import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetada
|
||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { WorkflowDropdownStepOutputItems } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowDropdownStepOutputItems';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowDropdownStepOutputItems } from '@/workflow/workflow-steps/components/WorkflowDropdownStepOutputItems';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowVariablesDropdownSteps } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownSteps';
|
||||
import { useAvailableVariablesInWorkflowStep } from '@/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep';
|
||||
import { useSearchVariable } from '@/workflow/workflow-variables/hooks/useSearchVariable';
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterColumn';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
import { AdvancedFilterCommandMenuColumn } from '@/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuColumn';
|
||||
import { WorkflowStepFilterGroupChildren } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterGroupChildren';
|
||||
import { WorkflowStepFilterGroupOptionsDropdown } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterGroupOptionsDropdown';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowStepFilterGroupChildren } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupChildren';
|
||||
import { WorkflowStepFilterGroupOptionsDropdown } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupOptionsDropdown';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
import { type StepFilterGroup } from 'twenty-shared/types';
|
||||
+2
-2
@@ -2,8 +2,8 @@ import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advance
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useRemoveStepFilterGroup } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useRemoveStepFilterGroup';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { useRemoveStepFilterGroup } from '@/workflow/workflow-steps/filters/hooks/useRemoveStepFilterGroup';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { useContext } from 'react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||
+7
-4
@@ -1,11 +1,11 @@
|
||||
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { StepLogicalOperator, type StepFilterGroup } from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
@@ -27,14 +27,17 @@ const StyledContainer = styled.div`
|
||||
type WorkflowStepFilterLogicalOperatorCellProps = {
|
||||
index: number;
|
||||
stepFilterGroup: StepFilterGroup;
|
||||
firstFilterLabel?: string;
|
||||
};
|
||||
|
||||
export const WorkflowStepFilterLogicalOperatorCell = ({
|
||||
index,
|
||||
stepFilterGroup,
|
||||
firstFilterLabel,
|
||||
}: WorkflowStepFilterLogicalOperatorCellProps) => {
|
||||
const { readonly } = useContext(WorkflowStepFilterContext);
|
||||
const { t } = useLingui();
|
||||
const defaultFirstFilterLabel = t`Where`;
|
||||
|
||||
const { upsertStepFilterSettings } = useUpsertStepFilterSettings();
|
||||
|
||||
@@ -66,7 +69,7 @@ export const WorkflowStepFilterLogicalOperatorCell = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
{index === 0 ? (
|
||||
<StyledText>{t`Where`}</StyledText>
|
||||
<StyledText>{firstFilterLabel ?? defaultFirstFilterLabel}</StyledText>
|
||||
) : index === 1 ? (
|
||||
readonly ? (
|
||||
<Select
|
||||
+3
-3
@@ -5,9 +5,9 @@ import { Select } from '@/ui/input/components/Select';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { WORKFLOW_TIMEZONE } from '@/workflow/constants/WorkflowTimeZone';
|
||||
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { getStepFilterOperands } from '@/workflow/workflow-steps/workflow-actions/filter-action/utils/getStepFilterOperands';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { getStepFilterOperands } from '@/workflow/workflow-steps/filters/utils/getStepFilterOperands';
|
||||
import { useContext } from 'react';
|
||||
import { DEFAULT_RELATIVE_DATE_FILTER_VALUE } from 'twenty-shared/constants';
|
||||
import { ViewFilterOperand, type StepFilter } from 'twenty-shared/types';
|
||||
+2
-2
@@ -2,8 +2,8 @@ import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advance
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useRemoveStepFilter } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useRemoveStepFilter';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { useRemoveStepFilter } from '@/workflow/workflow-steps/filters/hooks/useRemoveStepFilter';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { useContext } from 'react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { FormNumberFieldInput } from '@/object-record/record-field/ui/form-types
|
||||
import { FormSingleRecordPicker } from '@/object-record/record-field/ui/form-types/components/FormSingleRecordPicker';
|
||||
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
|
||||
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
import { useContext } from 'react';
|
||||
import { FieldActorSource, type StepFilter } from 'twenty-shared/types';
|
||||
+3
-3
@@ -12,9 +12,9 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldM
|
||||
import { stringifyRelativeDateFilter } from '@/views/view-filter-value/utils/stringifyRelativeDateFilter';
|
||||
import { WORKFLOW_TIMEZONE } from '@/workflow/constants/WorkflowTimeZone';
|
||||
|
||||
import { WorkflowStepFilterValueCompositeInput } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueCompositeInput';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowStepFilterValueCompositeInput } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterValueCompositeInput';
|
||||
import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isObject, isString } from '@sniptt/guards';
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
|
||||
const STEP_FILTER_GROUP: StepFilterGroup = {
|
||||
id: 'filter-group-1',
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterAddRootStepFilterButton } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddRootStepFilterButton';
|
||||
import { WorkflowStepFilterAddRootStepFilterButton } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton';
|
||||
|
||||
const meta: Meta<typeof WorkflowStepFilterAddRootStepFilterButton> = {
|
||||
title:
|
||||
+1
-1
@@ -12,7 +12,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterColumn';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn';
|
||||
|
||||
const STEP_FILTER_GROUP: StepFilterGroup = {
|
||||
id: 'filter-group-1',
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterFieldSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect';
|
||||
import { WorkflowStepFilterFieldSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect';
|
||||
|
||||
const DEFAULT_STEP_FILTER: StepFilter = {
|
||||
id: 'filter-1',
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell';
|
||||
|
||||
const AND_STEP_FILTER_GROUP: StepFilterGroup = {
|
||||
id: 'filter-group-1',
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { WorkflowStepFilterDecorator } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/decorators/WorkflowStepFilterDecorator';
|
||||
import { WorkflowStepFilterOperandSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterOperandSelect';
|
||||
import { WorkflowStepFilterOperandSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterOperandSelect';
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
import { expect, within } from '@storybook/test';
|
||||
import { type StepFilter, ViewFilterOperand } from 'twenty-shared/types';
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueInput';
|
||||
import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput';
|
||||
|
||||
const TEXT_FILTER: StepFilter = {
|
||||
id: 'filter-1',
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState';
|
||||
import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFiltersComponentFamilyState';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState';
|
||||
import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import {
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
|
||||
export const useRemoveStepFilter = () => {
|
||||
const { onFilterSettingsUpdate } = useContext(WorkflowStepFilterContext);
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types';
|
||||
+4
-2
@@ -1,9 +1,11 @@
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings';
|
||||
import { createContext } from 'react';
|
||||
|
||||
type WorkflowStepFilterContextType = {
|
||||
stepId: string;
|
||||
onFilterSettingsUpdate: (filterSettings: FilterSettings) => void;
|
||||
onFilterSettingsUpdate: (
|
||||
filterSettings: FilterSettings,
|
||||
) => void | Promise<void>;
|
||||
readonly?: boolean;
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { type StepFilterGroup } from 'twenty-shared/types';
|
||||
|
||||
export const currentStepFilterGroupsComponentState = createComponentState<
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFiltersComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext';
|
||||
import { type StepFilter } from 'twenty-shared/types';
|
||||
|
||||
export const currentStepFiltersComponentState = createComponentState<
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
|
||||
export const hasInitializedCurrentStepFilterGroupsComponentFamilyState =
|
||||
createComponentFamilyState<boolean, { stepId: string }>({
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFiltersComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext';
|
||||
|
||||
export const hasInitializedCurrentStepFiltersComponentFamilyState =
|
||||
createComponentFamilyState<boolean, { stepId: string }>({
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const rootLevelStepFilterGroupComponentSelector =
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types';
|
||||
|
||||
export type FilterSettings = {
|
||||
stepFilterGroups?: StepFilterGroup[];
|
||||
stepFilters?: StepFilter[];
|
||||
};
|
||||
@@ -34,12 +34,16 @@ export const useCreateStep = () => {
|
||||
nextStepId,
|
||||
position,
|
||||
connectionOptions,
|
||||
shouldSelectNode = true,
|
||||
workflowVersionId: providedWorkflowVersionId,
|
||||
}: {
|
||||
newStepType: WorkflowActionType;
|
||||
parentStepId: string | undefined;
|
||||
nextStepId: string | undefined;
|
||||
position?: { x: number; y: number };
|
||||
connectionOptions?: WorkflowStepConnectionOptions;
|
||||
shouldSelectNode?: boolean;
|
||||
workflowVersionId?: string;
|
||||
}) => {
|
||||
if (isLoading === true) {
|
||||
return;
|
||||
@@ -48,7 +52,8 @@ export const useCreateStep = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const workflowVersionId = await getUpdatableWorkflowVersion();
|
||||
const workflowVersionId =
|
||||
providedWorkflowVersionId ?? (await getUpdatableWorkflowVersion());
|
||||
const id = v4();
|
||||
|
||||
const workflowVersionStepChanges = (
|
||||
@@ -77,7 +82,9 @@ export const useCreateStep = () => {
|
||||
throw new Error("Couldn't create step");
|
||||
}
|
||||
|
||||
setWorkflowSelectedNode(id);
|
||||
if (shouldSelectNode) {
|
||||
setWorkflowSelectedNode(id);
|
||||
}
|
||||
setWorkflowLastCreatedStepId(id);
|
||||
|
||||
return isDefined(createdFirstStepDiff)
|
||||
|
||||
@@ -3,8 +3,10 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { type WorkflowIfElseAction } from '@/workflow/types/Workflow';
|
||||
import { useDeleteWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useDeleteWorkflowVersionStep';
|
||||
import { useResetWorkflowAiAgentPermissionsStateOnCommandMenuClose } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/hooks/useResetWorkflowAiAgentPermissionsStateOnCommandMenuClose';
|
||||
import { getEmptyChildStepIds } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/getEmptyChildStepIds';
|
||||
import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useStepsOutputSchema';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -25,11 +27,35 @@ export const useDeleteStep = () => {
|
||||
const deleteStep = async (stepId: string) => {
|
||||
const workflowVersionId = await getUpdatableWorkflowVersion();
|
||||
|
||||
const isAiAgentStep =
|
||||
isDefined(workflow?.currentVersion?.steps) &&
|
||||
workflow.currentVersion.steps.some(
|
||||
(step) => step.id === stepId && step.type === 'AI_AGENT',
|
||||
);
|
||||
const steps = workflow?.currentVersion?.steps;
|
||||
const stepToDelete = isDefined(steps)
|
||||
? steps.find((step) => step.id === stepId)
|
||||
: undefined;
|
||||
|
||||
if (
|
||||
isDefined(stepToDelete) &&
|
||||
isDefined(steps) &&
|
||||
stepToDelete.type === 'IF_ELSE'
|
||||
) {
|
||||
const emptyChildStepIds = getEmptyChildStepIds({
|
||||
ifElseAction: stepToDelete as WorkflowIfElseAction,
|
||||
allSteps: steps,
|
||||
});
|
||||
|
||||
for (const emptyChildStepId of emptyChildStepIds) {
|
||||
await deleteWorkflowVersionStep({
|
||||
workflowVersionId,
|
||||
stepId: emptyChildStepId,
|
||||
});
|
||||
}
|
||||
|
||||
if (emptyChildStepIds.length > 0) {
|
||||
deleteStepsOutputSchema({
|
||||
stepIds: emptyChildStepIds,
|
||||
workflowVersionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await deleteWorkflowVersionStep({
|
||||
workflowVersionId,
|
||||
@@ -43,7 +69,7 @@ export const useDeleteStep = () => {
|
||||
workflowVersionId,
|
||||
});
|
||||
|
||||
if (isAiAgentStep) {
|
||||
if (isDefined(stepToDelete) && stepToDelete.type === 'AI_AGENT') {
|
||||
resetPermissionState();
|
||||
}
|
||||
};
|
||||
|
||||
+6
-2
@@ -1,10 +1,14 @@
|
||||
import { type WorkflowActionType } from '@/workflow/types/Workflow';
|
||||
import { DELAY_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/DelayAction';
|
||||
import { FILTER_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/FilterAction';
|
||||
import { IF_ELSE_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/IfElseAction';
|
||||
import { ITERATOR_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/IteratorAction';
|
||||
|
||||
export const FLOW_ACTIONS: Array<{
|
||||
defaultLabel: string;
|
||||
type: Extract<WorkflowActionType, 'ITERATOR' | 'FILTER' | 'DELAY'>;
|
||||
type: Extract<
|
||||
WorkflowActionType,
|
||||
'ITERATOR' | 'FILTER' | 'IF_ELSE' | 'DELAY'
|
||||
>;
|
||||
icon: string;
|
||||
}> = [ITERATOR_ACTION, FILTER_ACTION, DELAY_ACTION];
|
||||
}> = [ITERATOR_ACTION, FILTER_ACTION, IF_ELSE_ACTION, DELAY_ACTION];
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { type WorkflowActionType } from '@/workflow/types/Workflow';
|
||||
|
||||
export const IF_ELSE_ACTION: {
|
||||
defaultLabel: string;
|
||||
type: Extract<WorkflowActionType, 'IF_ELSE'>;
|
||||
icon: string;
|
||||
} = {
|
||||
defaultLabel: 'If/else',
|
||||
type: 'IF_ELSE',
|
||||
icon: 'IconArrowsSplit',
|
||||
};
|
||||
+3
-9
@@ -1,10 +1,9 @@
|
||||
import { type WorkflowFilterAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
import { WorkflowEditActionFilterBodyEffect } from '@/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext';
|
||||
import { WorkflowEditActionFilterBody } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody';
|
||||
import { WorkflowEditActionFilterBodyEffect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBodyEffect';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFiltersComponentInstanceContext';
|
||||
import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types';
|
||||
|
||||
type WorkflowEditActionFilterProps = {
|
||||
action: WorkflowFilterAction;
|
||||
@@ -18,11 +17,6 @@ type WorkflowEditActionFilterProps = {
|
||||
};
|
||||
};
|
||||
|
||||
export type FilterSettings = {
|
||||
stepFilterGroups?: StepFilterGroup[];
|
||||
stepFilters?: StepFilter[];
|
||||
};
|
||||
|
||||
export const WorkflowEditActionFilter = ({
|
||||
action,
|
||||
actionOptions,
|
||||
|
||||
+9
-9
@@ -2,15 +2,15 @@ import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type WorkflowFilterAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterAddRootStepFilterButton } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddRootStepFilterButton';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterColumn';
|
||||
import { WorkflowStepFilterGroupColumn } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterGroupColumn';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
|
||||
import { rootLevelStepFilterGroupComponentSelector } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/rootLevelStepFilterGroupComponentSelector';
|
||||
import { isStepFilterGroupChildAStepFilterGroup } from '@/workflow/workflow-steps/workflow-actions/filter-action/utils/isStepFilterGroupChildAStepFilterGroup';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterAddRootStepFilterButton } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn';
|
||||
import { WorkflowStepFilterGroupColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { rootLevelStepFilterGroupComponentSelector } from '@/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings';
|
||||
import { isStepFilterGroupChildAStepFilterGroup } from '@/workflow/workflow-steps/filters/utils/isStepFilterGroupChildAStepFilterGroup';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/StepFiltersComponentInstanceContext';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext';
|
||||
import { type Decorator } from '@storybook/react';
|
||||
|
||||
export const WorkflowStepFilterDecorator: Decorator = (Story) => {
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { type WorkflowIfElseAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
import { WorkflowEditActionFilterBodyEffect } from '@/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect';
|
||||
import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext';
|
||||
import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext';
|
||||
import { WorkflowEditActionIfElseBody } from '@/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody';
|
||||
|
||||
type WorkflowEditActionIfElseProps = {
|
||||
action: WorkflowIfElseAction;
|
||||
actionOptions:
|
||||
| {
|
||||
readonly: true;
|
||||
}
|
||||
| {
|
||||
readonly?: false;
|
||||
onActionUpdate: (action: WorkflowIfElseAction) => void;
|
||||
};
|
||||
};
|
||||
|
||||
export const WorkflowEditActionIfElse = ({
|
||||
action,
|
||||
actionOptions,
|
||||
}: WorkflowEditActionIfElseProps) => {
|
||||
return (
|
||||
<>
|
||||
<StepFiltersComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: action.id,
|
||||
}}
|
||||
>
|
||||
<StepFilterGroupsComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: action.id,
|
||||
}}
|
||||
>
|
||||
<WorkflowEditActionIfElseBody
|
||||
action={action}
|
||||
actionOptions={actionOptions}
|
||||
/>
|
||||
<WorkflowEditActionFilterBodyEffect
|
||||
stepId={action.id}
|
||||
defaultValue={{
|
||||
stepFilterGroups: action.settings.input.stepFilterGroups,
|
||||
stepFilters: action.settings.input.stepFilters,
|
||||
}}
|
||||
/>
|
||||
</StepFilterGroupsComponentInstanceContext.Provider>
|
||||
</StepFiltersComponentInstanceContext.Provider>
|
||||
{!actionOptions.readonly && <WorkflowStepFooter stepId={action.id} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import {
|
||||
type WorkflowIfElseAction,
|
||||
type WorkflowStep,
|
||||
} from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState';
|
||||
import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings';
|
||||
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
||||
import { useDeleteWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useDeleteWorkflowVersionStep';
|
||||
import { WorkflowIfElseBranchEditor } from '@/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowIfElseBranchEditor';
|
||||
import { calculateElseIfBranchPosition } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/calculateElseIfBranchPosition';
|
||||
import { calculateExistingBranchPositions } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/calculateExistingBranchPositions';
|
||||
import { createElseIfBranch } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/createElseIfBranch';
|
||||
import { getBranchesToDelete } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/getBranchesToDelete';
|
||||
import { getBranchLabel } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/getBranchLabel';
|
||||
import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useStepsOutputSchema';
|
||||
import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Fragment } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type StepIfElseBranch } from 'twenty-shared/workflow';
|
||||
import { HorizontalSeparator, IconPlus } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: start;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledBodyContainer = styled(WorkflowStepBody)`
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type WorkflowEditActionIfElseBodyProps = {
|
||||
action: WorkflowIfElseAction;
|
||||
actionOptions:
|
||||
| {
|
||||
readonly: true;
|
||||
}
|
||||
| {
|
||||
readonly?: false;
|
||||
onActionUpdate: (action: WorkflowIfElseAction) => void;
|
||||
};
|
||||
};
|
||||
|
||||
export const WorkflowEditActionIfElseBody = ({
|
||||
action,
|
||||
actionOptions,
|
||||
}: WorkflowEditActionIfElseBodyProps) => {
|
||||
const branches = action.settings.input.branches;
|
||||
const stepFilterGroups = action.settings.input.stepFilterGroups ?? [];
|
||||
const stepFilters = action.settings.input.stepFilters ?? [];
|
||||
const isReadonly = actionOptions.readonly === true;
|
||||
|
||||
const { createStep } = useCreateStep();
|
||||
const { getUpdatableWorkflowVersion } =
|
||||
useGetUpdatableWorkflowVersionOrThrow();
|
||||
const { updateWorkflowVersionPosition } = useTidyUpWorkflowVersion();
|
||||
const { deleteWorkflowVersionStep } = useDeleteWorkflowVersionStep();
|
||||
const { deleteStepsOutputSchema } = useStepsOutputSchema();
|
||||
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||
workflowVisualizerWorkflowIdComponentState,
|
||||
);
|
||||
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
|
||||
|
||||
const currentStepFilters = useRecoilComponentValue(
|
||||
currentStepFiltersComponentState,
|
||||
);
|
||||
const currentStepFilterGroups = useRecoilComponentValue(
|
||||
currentStepFilterGroupsComponentState,
|
||||
);
|
||||
const setCurrentStepFilters = useSetRecoilComponentState(
|
||||
currentStepFiltersComponentState,
|
||||
);
|
||||
const setCurrentStepFilterGroups = useSetRecoilComponentState(
|
||||
currentStepFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const cleanupEmptyChildStepsFromDeletedBranches = async ({
|
||||
branchesToDelete,
|
||||
allSteps,
|
||||
}: {
|
||||
branchesToDelete: StepIfElseBranch[];
|
||||
allSteps?: WorkflowStep[];
|
||||
}): Promise<void> => {
|
||||
if (branchesToDelete.length === 0 || !isDefined(allSteps)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workflowVersionId = await getUpdatableWorkflowVersion();
|
||||
|
||||
const childStepIdsFromDeletedBranches = branchesToDelete.flatMap(
|
||||
(branch) => branch.nextStepIds,
|
||||
);
|
||||
|
||||
const emptyChildStepIds = childStepIdsFromDeletedBranches.filter(
|
||||
(childStepId) => {
|
||||
const childStep = allSteps.find((step) => step.id === childStepId);
|
||||
return isDefined(childStep) && childStep.type === 'EMPTY';
|
||||
},
|
||||
);
|
||||
|
||||
for (const emptyChildStepId of emptyChildStepIds) {
|
||||
await deleteWorkflowVersionStep({
|
||||
workflowVersionId,
|
||||
stepId: emptyChildStepId,
|
||||
});
|
||||
}
|
||||
|
||||
if (emptyChildStepIds.length > 0) {
|
||||
deleteStepsOutputSchema({
|
||||
stepIds: emptyChildStepIds,
|
||||
workflowVersionId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onFilterSettingsUpdate = async (newFilterSettings: FilterSettings) => {
|
||||
if (isReadonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedStepFilterGroups = newFilterSettings.stepFilterGroups ?? [];
|
||||
const updatedStepFilters = newFilterSettings.stepFilters ?? [];
|
||||
|
||||
const remainingFilterGroupIds = new Set(
|
||||
updatedStepFilterGroups.map((g) => g.id),
|
||||
);
|
||||
|
||||
const branchesToDelete = getBranchesToDelete(
|
||||
branches,
|
||||
remainingFilterGroupIds,
|
||||
);
|
||||
const updatedBranches =
|
||||
branchesToDelete.length > 0
|
||||
? branches.filter((branch) => !branchesToDelete.includes(branch))
|
||||
: branches;
|
||||
|
||||
await cleanupEmptyChildStepsFromDeletedBranches({
|
||||
branchesToDelete,
|
||||
allSteps: workflow?.currentVersion?.steps ?? undefined,
|
||||
});
|
||||
|
||||
setCurrentStepFilterGroups(updatedStepFilterGroups);
|
||||
setCurrentStepFilters(updatedStepFilters);
|
||||
|
||||
actionOptions.onActionUpdate({
|
||||
...action,
|
||||
settings: {
|
||||
...action.settings,
|
||||
input: {
|
||||
...action.settings.input,
|
||||
stepFilterGroups: updatedStepFilterGroups,
|
||||
stepFilters: updatedStepFilters,
|
||||
branches: updatedBranches,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddRoute = async (event?: React.MouseEvent<HTMLElement>) => {
|
||||
if (isDefined(event)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (isReadonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { filterGroup, filter, branchId, filterGroupId } =
|
||||
createElseIfBranch();
|
||||
const totalBranches = branches.length + 1;
|
||||
const elseIfBranchIndex = branches.length - 1;
|
||||
const ifElseStepPosition = action.position ?? { x: 0, y: 0 };
|
||||
|
||||
const workflowVersionId = await getUpdatableWorkflowVersion();
|
||||
|
||||
const existingBranchPositions = calculateExistingBranchPositions({
|
||||
branches,
|
||||
elseIfBranchIndex,
|
||||
totalBranches,
|
||||
ifElseStepPosition,
|
||||
});
|
||||
|
||||
const newEmptyNodePosition = calculateElseIfBranchPosition(
|
||||
elseIfBranchIndex,
|
||||
totalBranches,
|
||||
ifElseStepPosition,
|
||||
);
|
||||
|
||||
if (existingBranchPositions.length > 0) {
|
||||
await updateWorkflowVersionPosition(
|
||||
workflowVersionId,
|
||||
existingBranchPositions,
|
||||
);
|
||||
}
|
||||
|
||||
const emptyNode = await createStep({
|
||||
newStepType: 'EMPTY',
|
||||
parentStepId: undefined,
|
||||
nextStepId: undefined,
|
||||
position: newEmptyNodePosition,
|
||||
shouldSelectNode: false,
|
||||
workflowVersionId,
|
||||
});
|
||||
|
||||
if (!isDefined(emptyNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newBranch = {
|
||||
id: branchId,
|
||||
filterGroupId,
|
||||
nextStepIds: [emptyNode.id],
|
||||
};
|
||||
|
||||
const updatedBranches = [...branches];
|
||||
updatedBranches.splice(branches.length - 1, 0, newBranch);
|
||||
|
||||
const updatedStepFilterGroups = [...stepFilterGroups, filterGroup];
|
||||
const updatedStepFilters = [...stepFilters, filter];
|
||||
|
||||
setCurrentStepFilterGroups([...currentStepFilterGroups, filterGroup]);
|
||||
setCurrentStepFilters([...currentStepFilters, filter]);
|
||||
|
||||
actionOptions.onActionUpdate({
|
||||
...action,
|
||||
settings: {
|
||||
...action.settings,
|
||||
input: {
|
||||
...action.settings.input,
|
||||
stepFilterGroups: updatedStepFilterGroups,
|
||||
stepFilters: updatedStepFilters,
|
||||
branches: updatedBranches,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledBodyContainer>
|
||||
<InputLabel>{t`Conditions`}</InputLabel>
|
||||
<StyledContainer>
|
||||
{branches.map((branch, branchIndex) => {
|
||||
const branchFilterGroup = isDefined(branch.filterGroupId)
|
||||
? stepFilterGroups.find((g) => g.id === branch.filterGroupId)
|
||||
: undefined;
|
||||
|
||||
const isElse =
|
||||
branchIndex === branches.length - 1 &&
|
||||
!isDefined(branch.filterGroupId);
|
||||
|
||||
return (
|
||||
<Fragment key={branch.id}>
|
||||
{branchIndex > 0 && !isElse && <HorizontalSeparator noMargin />}
|
||||
{isElse && !isReadonly && (
|
||||
<>
|
||||
<HorizontalSeparator noMargin />
|
||||
<Button
|
||||
Icon={IconPlus}
|
||||
title={t`Add route`}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
onClick={(event) => handleAddRoute(event)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{isElse && <HorizontalSeparator noMargin />}
|
||||
<WorkflowIfElseBranchEditor
|
||||
action={action}
|
||||
branch={branch}
|
||||
branchIndex={branchIndex}
|
||||
branchLabel={getBranchLabel({
|
||||
branchIndex,
|
||||
totalBranches: branches.length,
|
||||
branch,
|
||||
})}
|
||||
branchFilterGroup={branchFilterGroup}
|
||||
readonly={isReadonly}
|
||||
onFilterSettingsUpdate={onFilterSettingsUpdate}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</StyledContainer>
|
||||
</StyledBodyContainer>
|
||||
);
|
||||
};
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
import { type WorkflowIfElseAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddFilterRuleSelect';
|
||||
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn';
|
||||
import { WorkflowStepFilterGroupColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn';
|
||||
import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups';
|
||||
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings';
|
||||
import { isStepFilterGroupChildAStepFilterGroup } from '@/workflow/workflow-steps/filters/utils/isStepFilterGroupChildAStepFilterGroup';
|
||||
import styled from '@emotion/styled';
|
||||
import { i18n, type MessageDescriptor } from '@lingui/core';
|
||||
import { type StepFilterGroup } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type StepIfElseBranch } from 'twenty-shared/workflow';
|
||||
|
||||
const StyledBranchContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledFiltersContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type WorkflowIfElseBranchEditorProps = {
|
||||
action: WorkflowIfElseAction;
|
||||
branch: StepIfElseBranch;
|
||||
branchIndex: number;
|
||||
branchLabel: MessageDescriptor;
|
||||
branchFilterGroup: StepFilterGroup | undefined;
|
||||
readonly: boolean;
|
||||
onFilterSettingsUpdate: (filterSettings: FilterSettings) => Promise<void>;
|
||||
};
|
||||
|
||||
export const WorkflowIfElseBranchEditor = ({
|
||||
action,
|
||||
branch,
|
||||
branchIndex,
|
||||
branchLabel,
|
||||
branchFilterGroup,
|
||||
readonly,
|
||||
onFilterSettingsUpdate,
|
||||
}: WorkflowIfElseBranchEditorProps) => {
|
||||
const isElseBranch = !isDefined(branch.filterGroupId);
|
||||
|
||||
const { childStepFiltersAndChildStepFilterGroups } =
|
||||
useChildStepFiltersAndChildStepFilterGroups({
|
||||
stepFilterGroupId: branchFilterGroup?.id ?? '',
|
||||
});
|
||||
|
||||
if (isElseBranch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isIfBranch = branchIndex === 0;
|
||||
|
||||
return (
|
||||
<WorkflowStepFilterContext.Provider
|
||||
value={{
|
||||
stepId: action.id,
|
||||
readonly,
|
||||
onFilterSettingsUpdate,
|
||||
}}
|
||||
>
|
||||
<StyledBranchContainer>
|
||||
<StyledFiltersContainer>
|
||||
{isDefined(branchFilterGroup) &&
|
||||
childStepFiltersAndChildStepFilterGroups.map(
|
||||
(stepFilterGroupChild, stepFilterGroupChildIndex) =>
|
||||
isStepFilterGroupChildAStepFilterGroup(stepFilterGroupChild) ? (
|
||||
<WorkflowStepFilterGroupColumn
|
||||
key={stepFilterGroupChild.id}
|
||||
parentStepFilterGroup={branchFilterGroup}
|
||||
stepFilterGroup={stepFilterGroupChild}
|
||||
stepFilterGroupIndex={stepFilterGroupChildIndex}
|
||||
/>
|
||||
) : (
|
||||
<WorkflowStepFilterColumn
|
||||
key={stepFilterGroupChild.id}
|
||||
stepFilterGroup={branchFilterGroup}
|
||||
stepFilter={stepFilterGroupChild}
|
||||
stepFilterIndex={stepFilterGroupChildIndex}
|
||||
isIfBranch={isIfBranch}
|
||||
firstFilterLabel={i18n._(branchLabel)}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</StyledFiltersContainer>
|
||||
|
||||
{!readonly && isDefined(branchFilterGroup) && (
|
||||
<WorkflowStepFilterAddFilterRuleSelect
|
||||
stepFilterGroup={branchFilterGroup}
|
||||
/>
|
||||
)}
|
||||
</StyledBranchContainer>
|
||||
</WorkflowStepFilterContext.Provider>
|
||||
);
|
||||
};
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import { IF_ELSE_BRANCH_POSITION_OFFSETS } from 'twenty-shared/workflow';
|
||||
|
||||
const BRANCH_HORIZONTAL_SPACING = 200;
|
||||
|
||||
export const calculateElseIfBranchPosition = (
|
||||
branchIndex: number,
|
||||
totalBranches: number,
|
||||
ifElseStepPosition: { x: number; y: number },
|
||||
): { x: number; y: number } => {
|
||||
const isIfBranch = branchIndex === 0;
|
||||
const isElseBranch = branchIndex === totalBranches - 1;
|
||||
|
||||
const totalWidth = (totalBranches - 1) * BRANCH_HORIZONTAL_SPACING;
|
||||
|
||||
let positionX: number;
|
||||
|
||||
if (isIfBranch) {
|
||||
positionX = -totalWidth / 2;
|
||||
} else if (isElseBranch) {
|
||||
positionX = totalWidth / 2;
|
||||
} else {
|
||||
const spacing = totalWidth / (totalBranches - 1);
|
||||
positionX = -totalWidth / 2 + branchIndex * spacing;
|
||||
}
|
||||
|
||||
return {
|
||||
x: ifElseStepPosition.x + positionX,
|
||||
y: ifElseStepPosition.y + IF_ELSE_BRANCH_POSITION_OFFSETS.IF.y,
|
||||
};
|
||||
};
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type StepIfElseBranch } from 'twenty-shared/workflow';
|
||||
import { calculateElseIfBranchPosition } from './calculateElseIfBranchPosition';
|
||||
|
||||
export const calculateExistingBranchPositions = ({
|
||||
branches,
|
||||
elseIfBranchIndex,
|
||||
totalBranches,
|
||||
ifElseStepPosition,
|
||||
}: {
|
||||
branches: StepIfElseBranch[];
|
||||
elseIfBranchIndex: number;
|
||||
totalBranches: number;
|
||||
ifElseStepPosition: { x: number; y: number };
|
||||
}): Array<{ id: string; position: { x: number; y: number } }> => {
|
||||
return branches.reduce<
|
||||
Array<{ id: string; position: { x: number; y: number } }>
|
||||
>((acc, branch, branchIndex) => {
|
||||
const firstChildStepId = branch.nextStepIds[0];
|
||||
|
||||
if (!isDefined(firstChildStepId)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const adjustedBranchIndex =
|
||||
branchIndex < elseIfBranchIndex ? branchIndex : branchIndex + 1;
|
||||
|
||||
const branchNodePosition = calculateElseIfBranchPosition(
|
||||
adjustedBranchIndex,
|
||||
totalBranches,
|
||||
ifElseStepPosition,
|
||||
);
|
||||
|
||||
acc.push({
|
||||
id: firstChildStepId,
|
||||
position: branchNodePosition,
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
StepLogicalOperator,
|
||||
ViewFilterOperand,
|
||||
type StepFilter,
|
||||
type StepFilterGroup,
|
||||
} from 'twenty-shared/types';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const createElseIfBranch = (): {
|
||||
filterGroup: StepFilterGroup;
|
||||
filter: StepFilter;
|
||||
branchId: string;
|
||||
filterGroupId: string;
|
||||
} => {
|
||||
const newFilterGroupId = v4();
|
||||
const newFilterId = v4();
|
||||
const newBranchId = v4();
|
||||
|
||||
return {
|
||||
filterGroup: {
|
||||
id: newFilterGroupId,
|
||||
logicalOperator: StepLogicalOperator.AND,
|
||||
positionInStepFilterGroup: 0,
|
||||
},
|
||||
filter: {
|
||||
id: newFilterId,
|
||||
type: 'unknown',
|
||||
stepOutputKey: '',
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: '',
|
||||
stepFilterGroupId: newFilterGroupId,
|
||||
positionInStepFilterGroup: 0,
|
||||
},
|
||||
branchId: newBranchId,
|
||||
filterGroupId: newFilterGroupId,
|
||||
};
|
||||
};
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { type StepIfElseBranch } from 'twenty-shared/workflow';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getBranchLabel = ({
|
||||
branchIndex,
|
||||
totalBranches,
|
||||
branch,
|
||||
}: {
|
||||
branchIndex: number;
|
||||
totalBranches: number;
|
||||
branch?: StepIfElseBranch;
|
||||
}): MessageDescriptor => {
|
||||
if (branchIndex === 0) {
|
||||
return msg`if`;
|
||||
}
|
||||
|
||||
const isElseBranch =
|
||||
branchIndex === totalBranches - 1 &&
|
||||
(!isDefined(branch) || !isDefined(branch.filterGroupId));
|
||||
|
||||
if (isElseBranch) {
|
||||
return msg`else`;
|
||||
}
|
||||
|
||||
return msg`else if`;
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { type StepIfElseBranch } from 'twenty-shared/workflow';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getBranchesToDelete = (
|
||||
branches: StepIfElseBranch[],
|
||||
remainingFilterGroupIds: Set<string>,
|
||||
): StepIfElseBranch[] => {
|
||||
const existingBranchFilterGroupIds = new Set(
|
||||
branches.map((b) => b.filterGroupId).filter(isDefined),
|
||||
);
|
||||
|
||||
return branches.filter((branch, branchIndex) => {
|
||||
const isIfBranch = branchIndex === 0;
|
||||
const isElseBranch =
|
||||
branchIndex === branches.length - 1 && !isDefined(branch.filterGroupId);
|
||||
|
||||
if (isIfBranch || isElseBranch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
isDefined(branch.filterGroupId) &&
|
||||
existingBranchFilterGroupIds.has(branch.filterGroupId) &&
|
||||
!remainingFilterGroupIds.has(branch.filterGroupId)
|
||||
);
|
||||
});
|
||||
};
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
type WorkflowIfElseAction,
|
||||
type WorkflowStep,
|
||||
} from '@/workflow/types/Workflow';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getEmptyChildStepIds = ({
|
||||
ifElseAction,
|
||||
allSteps,
|
||||
}: {
|
||||
ifElseAction: WorkflowIfElseAction;
|
||||
allSteps: WorkflowStep[];
|
||||
}): string[] => {
|
||||
const branches = ifElseAction.settings.input.branches;
|
||||
const childStepIds = branches.flatMap((branch) => branch.nextStepIds);
|
||||
|
||||
return childStepIds.filter((childStepId) => {
|
||||
const childStep = allSteps.find((step) => step.id === childStepId);
|
||||
return isDefined(childStep) && childStep.type === 'EMPTY';
|
||||
});
|
||||
};
|
||||
+1
@@ -24,6 +24,7 @@ export const getActionIcon = (actionType: WorkflowActionType) => {
|
||||
case 'ITERATOR':
|
||||
case 'DELAY':
|
||||
case 'FILTER':
|
||||
case 'IF_ELSE':
|
||||
return FLOW_ACTIONS.find((item) => item.type === actionType)?.icon;
|
||||
case 'EMPTY':
|
||||
return 'IconSettingsAutomation';
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ export const getActionIconColorOrThrow = ({
|
||||
case 'ITERATOR':
|
||||
case 'EMPTY':
|
||||
case 'FILTER':
|
||||
case 'IF_ELSE':
|
||||
case 'DELAY':
|
||||
return theme.color.green12;
|
||||
case 'AI_AGENT':
|
||||
|
||||
Reference in New Issue
Block a user