From 1240d39f5643fcd946bd338bb43c4b07e2bc3198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:25:42 +0200 Subject: [PATCH] Introduce hooks to retrieve directly the registered actions without using actionMenuEntriesComponentState (#11359) Introduce two hooks: - `useRegisteredRecordActions` - `useRegisteredRecordAgnosticActions` These hooks will be used to read directly the registered actions according to the context. We will stop to rely on `actionMenuEntriesComponentState` to improve performances and reduce state copies and updates. This PR is part of https://github.com/twentyhq/core-team-issues/issues/683, and at this step, we still save the actions inside `actionMenuEntriesComponentState`. --- .../RecordActionMenuEntriesSetter.tsx | 30 +----------- .../components/RegisterRecordActionEffect.tsx | 18 +------ .../RegisterRecordActionEffects.tsx | 27 +++++++++++ .../RecordAgnosticActionMenuEntriesSetter.tsx | 10 ++-- ...t.tsx => RegisterAgnosticActionEffect.tsx} | 19 ++------ ...wRecordAgnosticActionMenuEntriesSetter.tsx | 4 +- .../hooks/useRegisteredRecordActions.ts | 48 +++++++++++++++++++ .../useRegisteredRecordAgnosticActions.ts | 36 ++++++++++++++ 8 files changed, 128 insertions(+), 64 deletions(-) create mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffects.tsx rename packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/{RegisterAgnosticRecordActionEffect.tsx => RegisterAgnosticActionEffect.tsx} (71%) create mode 100644 packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordActions.ts create mode 100644 packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordAgnosticActions.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index 16c292fa4..f6ad70b7b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -1,10 +1,7 @@ -import { RegisterRecordActionEffect } from '@/action-menu/actions/record-actions/components/RegisterRecordActionEffect'; +import { RegisterRecordActionEffects } from '@/action-menu/actions/record-actions/components/RegisterRecordActionEffects'; import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter'; -import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; -import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -43,10 +40,6 @@ export const RecordActionMenuEntriesSetter = () => { contextStoreTargetedRecordsRuleComponentState, ); - const contextStoreCurrentViewType = useRecoilComponentValueV2( - contextStoreCurrentViewTypeComponentState, - ); - const isWorkflowEnabled = useIsFeatureEnabled( FeatureFlagKey.IsWorkflowEnabled, ); @@ -55,28 +48,9 @@ export const RecordActionMenuEntriesSetter = () => { return null; } - const viewType = getActionViewType( - contextStoreCurrentViewType, - contextStoreTargetedRecordsRule, - ); - - const actionConfig = getActionConfig(objectMetadataItem); - - const actionsToRegister = isDefined(viewType) - ? Object.values(actionConfig ?? {}).filter((action) => - action.availableOn?.includes(viewType), - ) - : []; - return ( <> - {actionsToRegister.map((action) => ( - - ))} + {isWorkflowEnabled && contextStoreTargetedRecordsRule?.mode === 'selection' && diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffect.tsx index 2a4498285..3d79f57d5 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffect.tsx @@ -2,7 +2,6 @@ import { RecordConfigAction } from '@/action-menu/actions/types/RecordConfigActi import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { useShouldActionBeRegisteredParams } from '@/action-menu/hooks/useShouldActionBeRegisteredParams'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useContext, useEffect } from 'react'; @@ -34,26 +33,13 @@ export const RegisterRecordActionEffect = ({ onActionExecutedCallback, }); - const params = useShouldActionBeRegisteredParams({ - objectMetadataItem, - }); - - const shouldBeRegistered = action.shouldBeRegistered(params); - useEffect(() => { - if (shouldBeRegistered) { - addActionMenuEntry(wrappedAction); - } + addActionMenuEntry(wrappedAction); return () => { removeActionMenuEntry(wrappedAction.key); }; - }, [ - addActionMenuEntry, - removeActionMenuEntry, - shouldBeRegistered, - wrappedAction, - ]); + }, [addActionMenuEntry, removeActionMenuEntry, wrappedAction]); return null; }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffects.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffects.tsx new file mode 100644 index 000000000..c9a2f4b84 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RegisterRecordActionEffects.tsx @@ -0,0 +1,27 @@ +import { RegisterRecordActionEffect } from '@/action-menu/actions/record-actions/components/RegisterRecordActionEffect'; +import { useRegisteredRecordActions } from '@/action-menu/hooks/useRegisteredRecordActions'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +type RegisterRecordActionEffectsProps = { + objectMetadataItem: ObjectMetadataItem; +}; + +export const RegisterRecordActionEffects = ({ + objectMetadataItem, +}: RegisterRecordActionEffectsProps) => { + const actionsToRegister = useRegisteredRecordActions({ + objectMetadataItem, + }); + + return ( + <> + {actionsToRegister.map((action) => ( + + ))} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter.tsx index c799a0db6..527f0bae4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter.tsx @@ -1,11 +1,13 @@ -import { RegisterAgnosticRecordActionEffect } from '@/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticRecordActionEffect'; -import { RECORD_AGNOSTIC_ACTIONS_CONFIG } from '@/action-menu/actions/record-agnostic-actions/constants/RecordAgnosticActionsConfig'; +import { RegisterAgnosticActionEffect } from '@/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticActionEffect'; +import { useRegisteredRecordAgnosticActions } from '@/action-menu/hooks/useRegisteredRecordAgnosticActions'; export const RecordAgnosticActionMenuEntriesSetter = () => { + const actionsToRegister = useRegisteredRecordAgnosticActions(); + return ( <> - {Object.values(RECORD_AGNOSTIC_ACTIONS_CONFIG).map((action) => ( - + {actionsToRegister.map((action) => ( + ))} ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticRecordActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticActionEffect.tsx similarity index 71% rename from packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticRecordActionEffect.tsx rename to packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticActionEffect.tsx index e8a664db5..430addb12 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticRecordActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticActionEffect.tsx @@ -4,17 +4,15 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; import { useContext, useEffect } from 'react'; -type RegisterAgnosticRecordActionEffectProps = { +type RegisterAgnosticActionEffectProps = { action: RecordAgnosticConfigAction; }; -export const RegisterAgnosticRecordActionEffect = ({ +export const RegisterAgnosticActionEffect = ({ action, -}: RegisterAgnosticRecordActionEffectProps) => { +}: RegisterAgnosticActionEffectProps) => { const { onClick, ConfirmationModal } = action.useAction(); - const shouldBeRegistered = action.shouldBeRegistered({}); - const { onActionStartedCallback, onActionExecutedCallback } = useContext(ActionMenuContext); @@ -31,19 +29,12 @@ export const RegisterAgnosticRecordActionEffect = ({ }); useEffect(() => { - if (shouldBeRegistered) { - addActionMenuEntry(wrappedAction); - } + addActionMenuEntry(wrappedAction); return () => { removeActionMenuEntry(wrappedAction.key); }; - }, [ - addActionMenuEntry, - removeActionMenuEntry, - shouldBeRegistered, - wrappedAction, - ]); + }, [addActionMenuEntry, removeActionMenuEntry, wrappedAction]); return null; }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter.tsx index 5cc6dfc06..cb0c6e6d0 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter.tsx @@ -1,4 +1,4 @@ -import { RegisterAgnosticRecordActionEffect } from '@/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticRecordActionEffect'; +import { RegisterAgnosticActionEffect } from '@/action-menu/actions/record-agnostic-actions/components/RegisterAgnosticActionEffect'; import { useRunWorkflowActions } from '@/action-menu/actions/record-agnostic-actions/run-workflow-actions/hooks/useRunWorkflowActions'; export const RunWorkflowRecordAgnosticActionMenuEntriesSetter = () => { @@ -7,7 +7,7 @@ export const RunWorkflowRecordAgnosticActionMenuEntriesSetter = () => { return ( <> {runWorkflowActions.map((action) => ( - + ))} ); diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordActions.ts new file mode 100644 index 000000000..8656f3573 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordActions.ts @@ -0,0 +1,48 @@ +import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; +import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; +import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; +import { useShouldActionBeRegisteredParams } from '@/action-menu/hooks/useShouldActionBeRegisteredParams'; +import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isDefined } from 'twenty-shared/utils'; + +export const useRegisteredRecordActions = ({ + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; +}) => { + const params = useShouldActionBeRegisteredParams({ + objectMetadataItem, + }); + + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, + ); + + const contextStoreCurrentViewType = useRecoilComponentValueV2( + contextStoreCurrentViewTypeComponentState, + ); + + const viewType = getActionViewType( + contextStoreCurrentViewType, + contextStoreTargetedRecordsRule, + ); + + const actionConfig = getActionConfig(objectMetadataItem); + + const actionsToRegister = isDefined(viewType) + ? Object.values(actionConfig ?? {}).filter( + (action) => + action.availableOn?.includes(viewType) || + action.availableOn?.includes(ActionViewType.GLOBAL), + ) + : []; + + const actions = actionsToRegister.filter((action) => + action.shouldBeRegistered(params), + ); + + return actions; +}; diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordAgnosticActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordAgnosticActions.ts new file mode 100644 index 000000000..e26080a39 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredRecordAgnosticActions.ts @@ -0,0 +1,36 @@ +import { RECORD_AGNOSTIC_ACTIONS_CONFIG } from '@/action-menu/actions/record-agnostic-actions/constants/RecordAgnosticActionsConfig'; +import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; +import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; +import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isDefined } from 'twenty-shared/utils'; + +export const useRegisteredRecordAgnosticActions = () => { + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, + ); + + const contextStoreCurrentViewType = useRecoilComponentValueV2( + contextStoreCurrentViewTypeComponentState, + ); + + const viewType = getActionViewType( + contextStoreCurrentViewType, + contextStoreTargetedRecordsRule, + ); + + const actionsToRegister = isDefined(viewType) + ? Object.values(RECORD_AGNOSTIC_ACTIONS_CONFIG ?? {}).filter( + (action) => + action.availableOn?.includes(viewType) || + action.availableOn?.includes(ActionViewType.GLOBAL), + ) + : []; + + const actions = actionsToRegister.filter((action) => + action.shouldBeRegistered({}), + ); + + return actions; +};