From 33af71ccd3fc5bc8818e7bbdb05039fa921995ca Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 12 Feb 2025 11:29:32 +0100 Subject: [PATCH] Create base search record action (#10135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create Search Record action without filters neither sorting Capture d’écran 2025-02-11 à 18 19 25 Capture d’écran 2025-02-11 à 18 19 38 Capture d’écran 2025-02-11 à 18 19 53 --- .../src/modules/workflow/types/Workflow.ts | 15 +- .../components/WorkflowStepDetail.tsx | 13 +- .../WorkflowEditActionFormFindRecords.tsx | 147 ++++++++++++++++++ ...kflowEditActionFormFindRecords.stories.tsx | 92 +++++++++++ .../constants/RecordActions.ts | 5 + .../workflow-actions/utils/getActionIcon.ts | 1 + ...workflow-version-step.workspace-service.ts | 22 ++- 7 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormFindRecords.tsx create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFormFindRecords.stories.tsx diff --git a/packages/twenty-front/src/modules/workflow/types/Workflow.ts b/packages/twenty-front/src/modules/workflow/types/Workflow.ts index 691032a70..3daa533d2 100644 --- a/packages/twenty-front/src/modules/workflow/types/Workflow.ts +++ b/packages/twenty-front/src/modules/workflow/types/Workflow.ts @@ -55,6 +55,13 @@ export type WorkflowDeleteRecordActionSettings = BaseWorkflowActionSettings & { }; }; +export type WorkflowFindRecordsActionSettings = BaseWorkflowActionSettings & { + input: { + objectName: string; + limit?: number; + }; +}; + type BaseWorkflowAction = { id: string; name: string; @@ -86,12 +93,18 @@ export type WorkflowDeleteRecordAction = BaseWorkflowAction & { settings: WorkflowDeleteRecordActionSettings; }; +export type WorkflowFindRecordsAction = BaseWorkflowAction & { + type: 'FIND_RECORDS'; + settings: WorkflowFindRecordsActionSettings; +}; + export type WorkflowAction = | WorkflowCodeAction | WorkflowSendEmailAction | WorkflowCreateRecordAction | WorkflowUpdateRecordAction - | WorkflowDeleteRecordAction; + | WorkflowDeleteRecordAction + | WorkflowFindRecordsAction; export type WorkflowActionType = WorkflowAction['type']; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx index 985b05638..373570359 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx @@ -7,11 +7,12 @@ import { assertUnreachable } from '@/workflow/utils/assertUnreachable'; import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow'; import { WorkflowEditActionFormCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormCreateRecord'; import { WorkflowEditActionFormDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormDeleteRecord'; +import { WorkflowEditActionFormFindRecords } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormFindRecords'; import { WorkflowEditActionFormSendEmail } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormSendEmail'; import { WorkflowEditActionFormUpdateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormUpdateRecord'; +import { WorkflowEditTriggerCronForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm'; import { WorkflowEditTriggerDatabaseEventForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm'; import { WorkflowEditTriggerManualForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerManualForm'; -import { WorkflowEditTriggerCronForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm'; import { Suspense, lazy } from 'react'; import { isDefined } from 'twenty-shared'; import { RightDrawerSkeletonLoader } from '~/loading/components/RightDrawerSkeletonLoader'; @@ -138,6 +139,16 @@ export const WorkflowStepDetail = ({ /> ); } + + case 'FIND_RECORDS': { + return ( + + ); + } } return null; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormFindRecords.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormFindRecords.tsx new file mode 100644 index 000000000..fd1e879f0 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormFindRecords.tsx @@ -0,0 +1,147 @@ +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { Select, SelectOption } from '@/ui/input/components/Select'; +import { WorkflowFindRecordsAction } from '@/workflow/types/Workflow'; +import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader'; +import { useTheme } from '@emotion/react'; +import { useEffect, useState } from 'react'; + +import { FormNumberFieldInput } from '@/object-record/record-field/form-types/components/FormNumberFieldInput'; +import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; +import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; +import { isDefined } from 'twenty-shared'; +import { HorizontalSeparator, useIcons } from 'twenty-ui'; +import { useDebouncedCallback } from 'use-debounce'; + +type WorkflowEditActionFormFindRecordsProps = { + action: WorkflowFindRecordsAction; + actionOptions: + | { + readonly: true; + } + | { + readonly?: false; + onActionUpdate: (action: WorkflowFindRecordsAction) => void; + }; +}; + +type FindRecordsFormData = { + objectName: string; + limit?: number; +}; + +export const WorkflowEditActionFormFindRecords = ({ + action, + actionOptions, +}: WorkflowEditActionFormFindRecordsProps) => { + const theme = useTheme(); + const { getIcon } = useIcons(); + + const { activeObjectMetadataItems } = useFilteredObjectMetadataItems(); + + const availableMetadata: Array> = + activeObjectMetadataItems.map((item) => ({ + Icon: getIcon(item.icon), + label: item.labelPlural, + value: item.nameSingular, + })); + + const [formData, setFormData] = useState({ + objectName: action.settings.input.objectName, + limit: action.settings.input.limit, + }); + const isFormDisabled = actionOptions.readonly; + + const selectedObjectMetadataItemNameSingular = formData.objectName; + + const selectedObjectMetadataItem = activeObjectMetadataItems.find( + (item) => item.nameSingular === selectedObjectMetadataItemNameSingular, + ); + if (!isDefined(selectedObjectMetadataItem)) { + throw new Error('Should have found the metadata item'); + } + + const saveAction = useDebouncedCallback( + async (formData: FindRecordsFormData) => { + if (actionOptions.readonly === true) { + return; + } + + const { objectName: updatedObjectName, limit: updatedLimit } = formData; + + actionOptions.onActionUpdate({ + ...action, + settings: { + ...action.settings, + input: { + objectName: updatedObjectName, + limit: updatedLimit ?? 1, + }, + }, + }); + }, + 1_000, + ); + + useEffect(() => { + return () => { + saveAction.flush(); + }; + }, [saveAction]); + + const headerTitle = isDefined(action.name) ? action.name : `Search Records`; + const headerIcon = getActionIcon(action.type); + + return ( + <> + { + if (actionOptions.readonly === true) { + return; + } + + actionOptions.onActionUpdate({ + ...action, + name: newName, + }); + }} + Icon={getIcon(headerIcon)} + iconColor={theme.font.color.tertiary} + initialTitle={headerTitle} + headerType="Action" + disabled={isFormDisabled} + /> + +