Handle relations for filters (#13654)

- Refacto variable dropdown so it can display both objects and fields
- we do not filter on object name anymore to simplify the code
- add relation handler in filters



https://github.com/user-attachments/assets/e4f03f11-45cb-4d3f-b628-e996129dd996
This commit is contained in:
Thomas Trompette
2025-08-06 14:57:10 +02:00
committed by GitHub
parent d74bcbe62b
commit d9dbfc4f7e
21 changed files with 705 additions and 307 deletions
@@ -41,7 +41,8 @@ export const WorkflowVariablePicker: VariablePickerComponent = ({
disabled,
multiline,
onVariableSelect,
objectNameSingularToSelect,
shouldDisplayRecordObjects = false,
shouldDisplayRecordFields = true,
}) => {
return (
<StyledSearchVariablesDropdownContainer
@@ -52,7 +53,8 @@ export const WorkflowVariablePicker: VariablePickerComponent = ({
instanceId={instanceId}
onVariableSelect={onVariableSelect}
disabled={disabled}
objectNameSingularToSelect={objectNameSingularToSelect}
shouldDisplayRecordObjects={shouldDisplayRecordObjects}
shouldDisplayRecordFields={shouldDisplayRecordFields}
multiline={multiline}
/>
</StyledSearchVariablesDropdownContainer>
@@ -3,8 +3,8 @@ import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/S
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { WorkflowVariablesDropdownAllItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownAllItems';
import { WorkflowVariablesDropdownFieldItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems';
import { WorkflowVariablesDropdownObjectItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownObjectItems';
import { WorkflowVariablesDropdownWorkflowStepItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownWorkflowStepItems';
import { SEARCH_VARIABLES_DROPDOWN_ID } from '@/workflow/workflow-variables/constants/SearchVariablesDropdownId';
@@ -35,14 +35,18 @@ export const WorkflowVariablesDropdown = ({
instanceId,
onVariableSelect,
disabled,
objectNameSingularToSelect,
shouldDisplayRecordFields,
shouldDisplayRecordObjects,
shouldEnableSelectRelationObject,
multiline,
clickableComponent,
}: {
instanceId: string;
onVariableSelect: (variableName: string) => void;
shouldDisplayRecordFields: boolean;
shouldDisplayRecordObjects: boolean;
shouldEnableSelectRelationObject?: boolean;
disabled?: boolean;
objectNameSingularToSelect?: string;
multiline?: boolean;
clickableComponent?: React.ReactNode;
}) => {
@@ -55,7 +59,8 @@ export const WorkflowVariablesDropdown = ({
);
const { closeDropdown } = useCloseDropdown();
const availableVariablesInWorkflowStep = useAvailableVariablesInWorkflowStep({
objectNameSingularToSelect,
shouldDisplayRecordFields,
shouldDisplayRecordObjects,
});
const noAvailableVariables = availableVariablesInWorkflowStep.length === 0;
@@ -120,11 +125,12 @@ export const WorkflowVariablesDropdown = ({
steps={availableVariablesInWorkflowStep}
onSelect={handleStepSelect}
/>
) : isDefined(objectNameSingularToSelect) ? (
<WorkflowVariablesDropdownObjectItems
) : shouldDisplayRecordObjects ? (
<WorkflowVariablesDropdownAllItems
step={selectedStep}
onSelect={handleSubItemSelect}
onBack={handleBack}
shouldEnableSelectRelationObject={shouldEnableSelectRelationObject}
/>
) : (
<WorkflowVariablesDropdownFieldItems
@@ -3,14 +3,15 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StepOutputSchema } from '@/workflow/workflow-variables/types/StepOutputSchema';
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isRecordOutputSchema';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
import { t } from '@lingui/core/macro';
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
import { getVariableTemplateFromPath } from '@/workflow/workflow-variables/utils/getVariableTemplateFromPath';
import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isRecordOutputSchema';
import { useLingui } from '@lingui/react/macro';
import {
IconChevronLeft,
OverflowingTextWithTooltip,
@@ -19,25 +20,28 @@ import {
import { MenuItemSelect } from 'twenty-ui/navigation';
import { useVariableDropdown } from '../hooks/useVariableDropdown';
type WorkflowVariablesDropdownObjectItemsProps = {
type WorkflowVariablesDropdownAllItemsProps = {
step: StepOutputSchema;
onSelect: (value: string) => void;
onBack: () => void;
shouldEnableSelectRelationObject?: boolean;
};
export const WorkflowVariablesDropdownObjectItems = ({
export const WorkflowVariablesDropdownAllItems = ({
step,
onSelect,
onBack,
}: WorkflowVariablesDropdownObjectItemsProps) => {
shouldEnableSelectRelationObject,
}: WorkflowVariablesDropdownAllItemsProps) => {
const { t } = useLingui();
const { getIcon } = useIcons();
const {
currentPath,
filteredOptions,
searchInputValue,
setSearchInputValue,
handleSelectField,
goBack,
filteredOptions,
currentPath,
} = useVariableDropdown({
step,
onSelect,
@@ -61,9 +65,25 @@ export const WorkflowVariablesDropdownObjectItems = ({
return;
}
onSelect(
`{{${step.id}.${[...currentPath, currentSubStep.object.fieldIdName].join('.')}}}`,
);
const isRelationField = currentSubStep.object.isRelationField ?? false;
const isRelationObjectSelectable =
shouldEnableSelectRelationObject ?? false;
if (isRelationField && isRelationObjectSelectable) {
onSelect(
getVariableTemplateFromPath({
stepId: step.id,
path: currentPath,
}),
);
} else {
onSelect(
getVariableTemplateFromPath({
stepId: step.id,
path: [...currentPath, currentSubStep.object.fieldIdName],
}),
);
}
};
const displayedSubStepObject = getDisplayedSubStepObject();
@@ -118,17 +138,17 @@ export const WorkflowVariablesDropdownObjectItems = ({
{filteredOptions.length > 0 && shouldDisplayObject && (
<DropdownMenuSeparator />
)}
{filteredOptions.map(([key, option]) => (
{filteredOptions.map(([key, subStep]) => (
<MenuItemSelect
key={key}
selected={false}
focused={false}
onClick={() => handleSelectField(key)}
text={option.label || key}
hasSubMenu={!option.isLeaf}
LeftIcon={option.icon ? getIcon(option.icon) : undefined}
text={subStep.label || key}
hasSubMenu={!subStep.isLeaf}
LeftIcon={subStep.icon ? getIcon(subStep.icon) : undefined}
contextualText={
option.isLeaf ? option?.value?.toString() : undefined
subStep.isLeaf ? subStep?.value?.toString() : undefined
}
/>
))}
@@ -50,7 +50,6 @@ export const WorkflowVariablesDropdownFieldItems = ({
Icon={IconChevronLeft}
/>
}
style={{ position: 'fixed' }}
>
<OverflowingTextWithTooltip
text={getStepHeaderLabel(step, currentPath)}