Variables not coming from a Record step should be available in Record Picker (#12708)
We want code and webhook variables available in Record Picker since those can contains uuid. This PR: - update `WorkflowVariablesDropdownObjectItems.tsx` so it manages fields properly - factorise both dropdown into a commun hook - update filterOutputSchema.ts so it does not filter fields that are not FieldMetadata types - set relation fields as record object in variable schema so those can be selected as full record Before https://github.com/user-attachments/assets/f4f85402-c056-4fd8-8474-d86bef9d4bc3 After https://github.com/user-attachments/assets/c6589e18-7dfa-4fc8-a525-3a580e265896
This commit is contained in:
@ -2,32 +2,19 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import {
|
||||
BaseOutputSchema,
|
||||
LinkOutputSchema,
|
||||
StepOutputSchema,
|
||||
} from '@/workflow/workflow-variables/types/StepOutputSchema';
|
||||
import { isBaseOutputSchema } from '@/workflow/workflow-variables/utils/isBaseOutputSchema';
|
||||
import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isRecordOutputSchema';
|
||||
import { StepOutputSchema } from '@/workflow/workflow-variables/types/StepOutputSchema';
|
||||
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
|
||||
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
IconChevronLeft,
|
||||
OverflowingTextWithTooltip,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { MenuItemSelect } from 'twenty-ui/navigation';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useVariableDropdown } from '../hooks/useVariableDropdown';
|
||||
|
||||
type WorkflowVariablesDropdownFieldItemsProps = {
|
||||
step: StepOutputSchema;
|
||||
@ -40,83 +27,19 @@ export const WorkflowVariablesDropdownFieldItems = ({
|
||||
onSelect,
|
||||
onBack,
|
||||
}: WorkflowVariablesDropdownFieldItemsProps) => {
|
||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const { getIcon } = useIcons();
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||
activeTabIdComponentState,
|
||||
'workflow-serverless-function-tab-list-component-id',
|
||||
);
|
||||
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilComponentStateV2(
|
||||
workflowDiagramTriggerNodeSelectionComponentState,
|
||||
);
|
||||
|
||||
const getDisplayedSubStepFields = () => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
|
||||
if (isLinkOutputSchema(currentSubStep)) {
|
||||
return { link: currentSubStep.link };
|
||||
} else if (isRecordOutputSchema(currentSubStep)) {
|
||||
return currentSubStep.fields;
|
||||
} else if (isBaseOutputSchema(currentSubStep)) {
|
||||
return currentSubStep;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectField = (key: string) => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
|
||||
const handleSelectBaseOutputSchema = (
|
||||
baseOutputSchema: BaseOutputSchema,
|
||||
) => {
|
||||
if (!baseOutputSchema[key]?.isLeaf) {
|
||||
setCurrentPath([...currentPath, key]);
|
||||
setSearchInputValue('');
|
||||
} else {
|
||||
onSelect(`{{${step.id}.${[...currentPath, key].join('.')}}}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectLinkOutputSchema = (
|
||||
linkOutputSchema: LinkOutputSchema,
|
||||
) => {
|
||||
setWorkflowSelectedNode(step.id);
|
||||
setWorkflowDiagramTriggerNodeSelection(step.id);
|
||||
if (isDefined(linkOutputSchema.link.tab)) {
|
||||
setActiveTabId(linkOutputSchema.link.tab);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLinkOutputSchema(currentSubStep)) {
|
||||
handleSelectLinkOutputSchema(currentSubStep);
|
||||
} else if (isRecordOutputSchema(currentSubStep)) {
|
||||
handleSelectBaseOutputSchema(currentSubStep.fields);
|
||||
} else if (isBaseOutputSchema(currentSubStep)) {
|
||||
handleSelectBaseOutputSchema(currentSubStep);
|
||||
}
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
if (currentPath.length === 0) {
|
||||
onBack();
|
||||
} else {
|
||||
setCurrentPath(currentPath.slice(0, -1));
|
||||
}
|
||||
};
|
||||
|
||||
const displayedObject = getDisplayedSubStepFields();
|
||||
const options = displayedObject ? Object.entries(displayedObject) : [];
|
||||
|
||||
const filteredOptions = searchInputValue
|
||||
? options.filter(
|
||||
([_, value]) =>
|
||||
value.label &&
|
||||
value.label.toLowerCase().includes(searchInputValue.toLowerCase()),
|
||||
)
|
||||
: options;
|
||||
const {
|
||||
searchInputValue,
|
||||
setSearchInputValue,
|
||||
handleSelectField,
|
||||
goBack,
|
||||
filteredOptions,
|
||||
currentPath,
|
||||
} = useVariableDropdown({
|
||||
step,
|
||||
onSelect,
|
||||
onBack,
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
|
||||
@ -5,19 +5,19 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
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 { isBaseOutputSchema } from '@/workflow/workflow-variables/utils/isBaseOutputSchema';
|
||||
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 { useState } from 'react';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
IconChevronLeft,
|
||||
OverflowingTextWithTooltip,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { MenuItemSelect } from 'twenty-ui/navigation';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useVariableDropdown } from '../hooks/useVariableDropdown';
|
||||
|
||||
type WorkflowVariablesDropdownObjectItemsProps = {
|
||||
step: StepOutputSchema;
|
||||
@ -30,19 +30,19 @@ export const WorkflowVariablesDropdownObjectItems = ({
|
||||
onSelect,
|
||||
onBack,
|
||||
}: WorkflowVariablesDropdownObjectItemsProps) => {
|
||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const getDisplayedSubStepFields = () => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
|
||||
if (isRecordOutputSchema(currentSubStep)) {
|
||||
return currentSubStep.fields;
|
||||
} else if (isBaseOutputSchema(currentSubStep)) {
|
||||
return currentSubStep;
|
||||
}
|
||||
};
|
||||
const {
|
||||
currentPath,
|
||||
filteredOptions,
|
||||
searchInputValue,
|
||||
setSearchInputValue,
|
||||
handleSelectField,
|
||||
goBack,
|
||||
} = useVariableDropdown({
|
||||
step,
|
||||
onSelect,
|
||||
onBack,
|
||||
});
|
||||
|
||||
const getDisplayedSubStepObject = () => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
@ -66,19 +66,6 @@ export const WorkflowVariablesDropdownObjectItems = ({
|
||||
);
|
||||
};
|
||||
|
||||
const handleSelectField = (key: string) => {
|
||||
setCurrentPath([...currentPath, key]);
|
||||
setSearchInputValue('');
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
if (currentPath.length === 0) {
|
||||
onBack();
|
||||
} else {
|
||||
setCurrentPath(currentPath.slice(0, -1));
|
||||
}
|
||||
};
|
||||
|
||||
const displayedSubStepObject = getDisplayedSubStepObject();
|
||||
|
||||
const shouldDisplaySubStepObject = searchInputValue
|
||||
@ -88,16 +75,9 @@ export const WorkflowVariablesDropdownObjectItems = ({
|
||||
.includes(searchInputValue.toLowerCase())
|
||||
: true;
|
||||
|
||||
const displayedFields = getDisplayedSubStepFields();
|
||||
const options = displayedFields ? Object.entries(displayedFields) : [];
|
||||
|
||||
const filteredOptions = searchInputValue
|
||||
? options.filter(
|
||||
([_, value]) =>
|
||||
value.label &&
|
||||
value.label.toLowerCase().includes(searchInputValue.toLowerCase()),
|
||||
)
|
||||
: options;
|
||||
const shouldDisplayObject =
|
||||
shouldDisplaySubStepObject && displayedSubStepObject?.label;
|
||||
const nameSingular = displayedSubStepObject?.nameSingular;
|
||||
|
||||
return (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
@ -120,29 +100,36 @@ export const WorkflowVariablesDropdownObjectItems = ({
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{shouldDisplaySubStepObject && displayedSubStepObject?.label && (
|
||||
{shouldDisplayObject && (
|
||||
<MenuItemSelect
|
||||
selected={false}
|
||||
focused={false}
|
||||
onClick={handleSelectObject}
|
||||
text={displayedSubStepObject.label}
|
||||
text={displayedSubStepObject?.label || ''}
|
||||
hasSubMenu={false}
|
||||
LeftIcon={
|
||||
displayedSubStepObject.icon
|
||||
? getIcon(displayedSubStepObject.icon)
|
||||
: undefined
|
||||
}
|
||||
contextualText={t`Pick a ${nameSingular} record`}
|
||||
/>
|
||||
)}
|
||||
{filteredOptions.map(([key, value]) => (
|
||||
{filteredOptions.length > 0 && shouldDisplayObject && (
|
||||
<DropdownMenuSeparator />
|
||||
)}
|
||||
{filteredOptions.map(([key, option]) => (
|
||||
<MenuItemSelect
|
||||
key={key}
|
||||
selected={false}
|
||||
focused={false}
|
||||
onClick={() => handleSelectField(key)}
|
||||
text={value.label || key}
|
||||
hasSubMenu={!value.isLeaf}
|
||||
LeftIcon={value.icon ? getIcon(value.icon) : undefined}
|
||||
text={option.label || key}
|
||||
hasSubMenu={!option.isLeaf}
|
||||
LeftIcon={option.icon ? getIcon(option.icon) : undefined}
|
||||
contextualText={
|
||||
option.isLeaf ? option?.value?.toString() : undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
|
||||
@ -0,0 +1,123 @@
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
BaseOutputSchema,
|
||||
LinkOutputSchema,
|
||||
StepOutputSchema,
|
||||
} from '../types/StepOutputSchema';
|
||||
import { getCurrentSubStepFromPath } from '../utils/getCurrentSubStepFromPath';
|
||||
import { isBaseOutputSchema } from '../utils/isBaseOutputSchema';
|
||||
import { isLinkOutputSchema } from '../utils/isLinkOutputSchema';
|
||||
import { isRecordOutputSchema } from '../utils/isRecordOutputSchema';
|
||||
|
||||
type UseVariableDropdownProps = {
|
||||
step: StepOutputSchema;
|
||||
onSelect: (value: string) => void;
|
||||
onBack: () => void;
|
||||
};
|
||||
|
||||
type UseVariableDropdownReturn = {
|
||||
currentPath: string[];
|
||||
searchInputValue: string;
|
||||
setSearchInputValue: (value: string) => void;
|
||||
handleSelectField: (key: string) => void;
|
||||
goBack: () => void;
|
||||
filteredOptions: [string, any][];
|
||||
};
|
||||
|
||||
export const useVariableDropdown = ({
|
||||
step,
|
||||
onSelect,
|
||||
onBack,
|
||||
}: UseVariableDropdownProps): UseVariableDropdownReturn => {
|
||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||
activeTabIdComponentState,
|
||||
'workflow-serverless-function-tab-list-component-id',
|
||||
);
|
||||
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilComponentStateV2(
|
||||
workflowDiagramTriggerNodeSelectionComponentState,
|
||||
);
|
||||
|
||||
const getDisplayedSubStepFields = () => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
|
||||
if (isLinkOutputSchema(currentSubStep)) {
|
||||
return { link: currentSubStep.link };
|
||||
} else if (isRecordOutputSchema(currentSubStep)) {
|
||||
return currentSubStep.fields;
|
||||
} else if (isBaseOutputSchema(currentSubStep)) {
|
||||
return currentSubStep;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectField = (key: string) => {
|
||||
const currentSubStep = getCurrentSubStepFromPath(step, currentPath);
|
||||
|
||||
const handleSelectBaseOutputSchema = (
|
||||
baseOutputSchema: BaseOutputSchema,
|
||||
) => {
|
||||
if (!baseOutputSchema[key]?.isLeaf) {
|
||||
setCurrentPath([...currentPath, key]);
|
||||
setSearchInputValue('');
|
||||
} else {
|
||||
onSelect(`{{${step.id}.${[...currentPath, key].join('.')}}}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectLinkOutputSchema = (
|
||||
linkOutputSchema: LinkOutputSchema,
|
||||
) => {
|
||||
setWorkflowSelectedNode(step.id);
|
||||
setWorkflowDiagramTriggerNodeSelection(step.id);
|
||||
if (isDefined(linkOutputSchema.link.tab)) {
|
||||
setActiveTabId(linkOutputSchema.link.tab);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLinkOutputSchema(currentSubStep)) {
|
||||
handleSelectLinkOutputSchema(currentSubStep);
|
||||
} else if (isRecordOutputSchema(currentSubStep)) {
|
||||
handleSelectBaseOutputSchema(currentSubStep.fields);
|
||||
} else if (isBaseOutputSchema(currentSubStep)) {
|
||||
handleSelectBaseOutputSchema(currentSubStep);
|
||||
}
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
if (currentPath.length === 0) {
|
||||
onBack();
|
||||
} else {
|
||||
setCurrentPath(currentPath.slice(0, -1));
|
||||
}
|
||||
};
|
||||
|
||||
const displayedFields = getDisplayedSubStepFields();
|
||||
const options = displayedFields ? Object.entries(displayedFields) : [];
|
||||
|
||||
const filteredOptions = searchInputValue
|
||||
? options.filter(
|
||||
([_, value]) =>
|
||||
value.label &&
|
||||
value.label.toLowerCase().includes(searchInputValue.toLowerCase()),
|
||||
)
|
||||
: options;
|
||||
|
||||
return {
|
||||
currentPath,
|
||||
searchInputValue,
|
||||
setSearchInputValue,
|
||||
handleSelectField,
|
||||
goBack,
|
||||
filteredOptions,
|
||||
};
|
||||
};
|
||||
@ -10,6 +10,7 @@ type Leaf = {
|
||||
|
||||
type Node = {
|
||||
isLeaf: false;
|
||||
type?: InputSchemaPropertyType;
|
||||
icon?: string;
|
||||
label?: string;
|
||||
value: OutputSchema;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { OutputSchema } from '@/workflow/workflow-variables/types/StepOutputSchema';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { filterOutputSchema } from '../filterOutputSchema';
|
||||
|
||||
describe('filterOutputSchema', () => {
|
||||
@ -85,9 +86,10 @@ describe('filterOutputSchema', () => {
|
||||
expect(filterOutputSchema(inputSchema, 'person')).toEqual(expectedSchema);
|
||||
});
|
||||
|
||||
it('should ignore leaf fields', () => {
|
||||
it('should ignore leaf fields that are field metadata types', () => {
|
||||
const inputSchema = createRecordSchema('company', {
|
||||
name: { isLeaf: true, value: 'string' },
|
||||
id: { isLeaf: true, type: FieldMetadataType.UUID },
|
||||
employee: {
|
||||
isLeaf: false,
|
||||
value: createRecordSchema('person'),
|
||||
@ -97,6 +99,7 @@ describe('filterOutputSchema', () => {
|
||||
const expectedSchema = {
|
||||
_outputSchemaType: 'RECORD',
|
||||
fields: {
|
||||
name: { isLeaf: true, value: 'string' },
|
||||
employee: {
|
||||
isLeaf: false,
|
||||
value: createRecordSchema('person'),
|
||||
@ -117,6 +120,7 @@ describe('filterOutputSchema', () => {
|
||||
const inputSchema = createBaseSchema({
|
||||
field1: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
value: 'string',
|
||||
},
|
||||
});
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
RecordOutputSchema,
|
||||
} from '@/workflow/workflow-variables/types/StepOutputSchema';
|
||||
import { isBaseOutputSchema } from '@/workflow/workflow-variables/utils/isBaseOutputSchema';
|
||||
import { isFieldTypeCompatibleWithRecordId } from '@/workflow/workflow-variables/utils/isFieldTypeCompatibleWithRecordId';
|
||||
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
|
||||
import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isRecordOutputSchema';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -33,6 +34,10 @@ const filterRecordOutputSchema = (
|
||||
const field = outputSchema.fields[key];
|
||||
|
||||
if (field.isLeaf) {
|
||||
if (isFieldTypeCompatibleWithRecordId(field.type)) {
|
||||
filteredFields[key] = field;
|
||||
hasValidFields = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -75,6 +80,10 @@ const filterBaseOutputSchema = (
|
||||
const field = outputSchema[key];
|
||||
|
||||
if (field.isLeaf) {
|
||||
if (isFieldTypeCompatibleWithRecordId(field.type)) {
|
||||
filteredSchema[key] = field;
|
||||
hasValidFields = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { InputSchemaPropertyType } from '@/workflow/types/InputSchema';
|
||||
|
||||
export const isFieldTypeCompatibleWithRecordId = (
|
||||
type?: InputSchemaPropertyType,
|
||||
): boolean => {
|
||||
return !type || type === 'string' || type === 'unknown';
|
||||
};
|
||||
@ -94,12 +94,13 @@ const searchCurrentStepOutputSchema = ({
|
||||
}
|
||||
|
||||
return {
|
||||
variableLabel: isFullRecord
|
||||
? getDisplayedSubStepObjectLabel(currentSubStep)
|
||||
: getDisplayedSubStepFieldLabel(
|
||||
isSelectedFieldInNextKey ? nextKey : selectedField,
|
||||
currentSubStep,
|
||||
),
|
||||
variableLabel:
|
||||
isFullRecord && isRecordOutputSchema(currentSubStep)
|
||||
? getDisplayedSubStepObjectLabel(currentSubStep)
|
||||
: getDisplayedSubStepFieldLabel(
|
||||
isSelectedFieldInNextKey ? nextKey : selectedField,
|
||||
currentSubStep,
|
||||
),
|
||||
variablePathLabel,
|
||||
};
|
||||
};
|
||||
|
||||
@ -11,6 +11,7 @@ export type Leaf = {
|
||||
|
||||
export type Node = {
|
||||
isLeaf: false;
|
||||
type?: InputSchemaPropertyType;
|
||||
icon?: string;
|
||||
label?: string;
|
||||
value: OutputSchema;
|
||||
|
||||
@ -128,6 +128,7 @@ describe('generateFakeField', () => {
|
||||
isLeaf: false,
|
||||
icon: undefined,
|
||||
label: 'Links Field',
|
||||
type: FieldMetadataType.LINKS,
|
||||
value: {
|
||||
label: {
|
||||
isLeaf: true,
|
||||
@ -166,6 +167,7 @@ describe('generateFakeField', () => {
|
||||
isLeaf: false,
|
||||
icon: 'IconCurrency',
|
||||
label: 'Currency Field',
|
||||
type: FieldMetadataType.CURRENCY,
|
||||
value: {
|
||||
amount: {
|
||||
isLeaf: true,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { mockObjectMetadataItemsWithFieldMaps } from 'src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps';
|
||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
|
||||
import { generateObjectRecordFields } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields';
|
||||
import { mockObjectMetadataItemsWithFieldMaps } from 'src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps';
|
||||
|
||||
jest.mock(
|
||||
'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields',
|
||||
@ -33,7 +33,7 @@ const objectMetadataInfo = {
|
||||
|
||||
describe('generateFakeObjectRecord', () => {
|
||||
it('should generate a record with correct object metadata', () => {
|
||||
const result = generateFakeObjectRecord(objectMetadataInfo);
|
||||
const result = generateFakeObjectRecord({ objectMetadataInfo });
|
||||
|
||||
expect(result).toEqual({
|
||||
object: {
|
||||
@ -53,10 +53,11 @@ describe('generateFakeObjectRecord', () => {
|
||||
});
|
||||
|
||||
it('should call generateObjectRecordFields with the object metadata', () => {
|
||||
generateFakeObjectRecord(objectMetadataInfo);
|
||||
generateFakeObjectRecord({ objectMetadataInfo });
|
||||
|
||||
expect(generateObjectRecordFields).toHaveBeenCalledWith({
|
||||
objectMetadataInfo,
|
||||
depth: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,6 +22,7 @@ export const generateFakeField = ({
|
||||
if (compositeType) {
|
||||
return {
|
||||
isLeaf: false,
|
||||
type: type,
|
||||
icon: icon,
|
||||
label: label,
|
||||
value: compositeType.properties.reduce((acc, property) => {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import {
|
||||
Leaf,
|
||||
Node,
|
||||
@ -7,8 +9,6 @@ import {
|
||||
import { generateFakeField } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-field';
|
||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
|
||||
import { FormFieldMetadata } from 'src/modules/workflow/workflow-executor/workflow-actions/form/types/workflow-form-action-settings.type';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
|
||||
export const generateFakeFormResponse = async ({
|
||||
formMetadata,
|
||||
@ -40,8 +40,10 @@ export const generateFakeFormResponse = async ({
|
||||
isLeaf: false,
|
||||
label: formFieldMetadata.label,
|
||||
value: generateFakeObjectRecord({
|
||||
objectMetadataMaps,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
objectMetadataInfo: {
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
objectMetadataMaps,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { ObjectMetadataInfo } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { RecordOutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
|
||||
import { generateObjectRecordFields } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields';
|
||||
import { ObjectMetadataInfo } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
export const generateFakeObjectRecord = (
|
||||
objectMetadataInfo: ObjectMetadataInfo,
|
||||
): RecordOutputSchema => {
|
||||
export const generateFakeObjectRecord = ({
|
||||
objectMetadataInfo,
|
||||
depth = 0,
|
||||
}: {
|
||||
objectMetadataInfo: ObjectMetadataInfo;
|
||||
depth?: number;
|
||||
}): RecordOutputSchema => {
|
||||
return {
|
||||
object: {
|
||||
isLeaf: true,
|
||||
@ -15,7 +19,10 @@ export const generateFakeObjectRecord = (
|
||||
objectMetadataInfo.objectMetadataItemWithFieldsMaps.nameSingular,
|
||||
fieldIdName: 'id',
|
||||
},
|
||||
fields: generateObjectRecordFields({ objectMetadataInfo }),
|
||||
fields: generateObjectRecordFields({
|
||||
objectMetadataInfo,
|
||||
depth,
|
||||
}),
|
||||
_outputSchemaType: 'RECORD',
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ObjectMetadataInfo } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { BaseOutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
|
||||
import { generateFakeField } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-field';
|
||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
|
||||
import { shouldGenerateFieldFakeValue } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/should-generate-field-fake-value';
|
||||
import { ObjectMetadataInfo } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
const MAXIMUM_DEPTH = 1;
|
||||
|
||||
@ -45,7 +46,7 @@ export const generateObjectRecordFields = ({
|
||||
isLeaf: false,
|
||||
icon: field.icon,
|
||||
label: field.label,
|
||||
value: generateObjectRecordFields({
|
||||
value: generateFakeObjectRecord({
|
||||
objectMetadataInfo: {
|
||||
objectMetadataItemWithFieldsMaps: relationTargetObjectMetadata,
|
||||
objectMetadataMaps: objectMetadataInfo.objectMetadataMaps,
|
||||
|
||||
@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
||||
import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/utils/check-string-is-database-event-action';
|
||||
import { generateFakeValue } from 'src/engine/utils/generate-fake-value';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { OutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
|
||||
import { generateFakeFormResponse } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-form-response';
|
||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
|
||||
@ -16,7 +17,6 @@ import {
|
||||
WorkflowTrigger,
|
||||
WorkflowTriggerType,
|
||||
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkflowSchemaWorkspaceService {
|
||||
@ -148,7 +148,7 @@ export class WorkflowSchemaWorkspaceService {
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
return generateFakeObjectRecord(objectMetadataInfo);
|
||||
return generateFakeObjectRecord({ objectMetadataInfo });
|
||||
}
|
||||
|
||||
private computeSendEmailActionOutputSchema(): OutputSchema {
|
||||
|
||||
Reference in New Issue
Block a user