diff --git a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProvider.tsx b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProvider.tsx index 0d6205c684..53eaae76dd 100644 --- a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProvider.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProvider.tsx @@ -1,13 +1,9 @@ import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext'; -import { CommandMenuContextProviderDefault } from '@/command-menu-item/contexts/CommandMenuContextProviderDefault'; -import { CommandMenuContextProviderWorkflowObjects } from '@/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { CoreObjectNameSingular } from 'twenty-shared/types'; +import { CommandMenuContextProviderLegacy } from '@/command-menu-item/contexts/CommandMenuContextProviderLegacy'; +import { CommandMenuContextProviderServerItems } from '@/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { isDefined } from 'twenty-shared/utils'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; +import { FeatureFlagKey } from '~/generated-metadata/graphql'; export const CommandMenuContextProvider = ({ children, @@ -19,51 +15,30 @@ export const CommandMenuContextProvider = ({ children: React.ReactNode; objectMetadataItemOverride?: ObjectMetadataItem; }) => { - const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue( - contextStoreCurrentObjectMetadataItemIdComponentState, + const isCommandMenuItemEnabled = useIsFeatureEnabled( + FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED, ); - const objectMetadataItems = useAtomStateValue(objectMetadataItemsState); - - const objectMetadataItem = - objectMetadataItemOverride ?? - objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId, - ); - - if (!isDefined(objectMetadataItem)) { - return null; - } - - const isWorkflowObject = - objectMetadataItem?.nameSingular === CoreObjectNameSingular.Workflow; - - if (!isDefined(objectMetadataItem)) { - return null; - } - - if (isWorkflowObject) { + if (isCommandMenuItemEnabled) { return ( - {children} - + ); } return ( - {children} - + ); }; diff --git a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderDefault.tsx b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderDefault.tsx index 0b46400955..da7e5f4522 100644 --- a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderDefault.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderDefault.tsx @@ -2,8 +2,6 @@ import { CommandMenuContext, type CommandMenuContextType, } from '@/command-menu-item/contexts/CommandMenuContext'; -import { useCommandMenuContextApi } from '@/command-menu-item/hooks/useCommandMenuContextApi'; -import { useCommandMenuItemFrontComponentCommands } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentCommands'; import { useRegisteredCommandMenuItems } from '@/command-menu-item/hooks/useRegisteredCommandMenuItems'; import { useShouldCommandMenuItemBeRegisteredParams } from '@/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams'; import { useRunWorkflowRecordAgnosticCommands } from '@/command-menu-item/record-agnostic/workflow/hooks/useRunWorkflowRecordAgnosticCommands'; @@ -11,8 +9,6 @@ import { useRunWorkflowRecordCommands } from '@/command-menu-item/record/workflo import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; export const CommandMenuContextProviderDefault = ({ objectMetadataItem, @@ -27,14 +23,10 @@ export const CommandMenuContextProviderDefault = ({ containerType: CommandMenuContextType['containerType']; children: React.ReactNode; }) => { - const params = useShouldCommandMenuItemBeRegisteredParams({ + const shouldBeRegisteredParams = useShouldCommandMenuItemBeRegisteredParams({ objectMetadataItem, }); - const shouldBeRegisteredParams = { - ...params, - }; - const commandMenuItems = useRegisteredCommandMenuItems( shouldBeRegisteredParams, ); @@ -55,28 +47,17 @@ export const CommandMenuContextProviderDefault = ({ const runWorkflowRecordAgnosticCommands = useRunWorkflowRecordAgnosticCommands(); - const commandMenuContextApi = useCommandMenuContextApi(); - - const commandMenuItemFrontComponentActions = - useCommandMenuItemFrontComponentCommands(commandMenuContextApi); - - const isCommandMenuItemEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED, - ); - return ( {children} diff --git a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderLegacy.tsx b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderLegacy.tsx new file mode 100644 index 0000000000..f5bb16c5e2 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderLegacy.tsx @@ -0,0 +1,65 @@ +import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext'; +import { CommandMenuContextProviderDefault } from '@/command-menu-item/contexts/CommandMenuContextProviderDefault'; +import { CommandMenuContextProviderWorkflowObjects } from '@/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects'; +import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { CoreObjectNameSingular } from 'twenty-shared/types'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { isDefined } from 'twenty-shared/utils'; + +export const CommandMenuContextProviderLegacy = ({ + children, + isInSidePanel, + displayType, + containerType, + objectMetadataItemOverride, +}: Omit & { + children: React.ReactNode; + objectMetadataItemOverride?: ObjectMetadataItem; +}) => { + const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue( + contextStoreCurrentObjectMetadataItemIdComponentState, + ); + + const objectMetadataItems = useAtomStateValue(objectMetadataItemsState); + + const objectMetadataItem = + objectMetadataItemOverride ?? + objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId, + ); + + if (!isDefined(objectMetadataItem)) { + return null; + } + + const isWorkflowObject = + objectMetadataItem.nameSingular === CoreObjectNameSingular.Workflow; + + if (isWorkflowObject) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects.tsx b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects.tsx index 8901f19141..9d57ecf35a 100644 --- a/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects.tsx @@ -2,8 +2,6 @@ import { CommandMenuContext, type CommandMenuContextType, } from '@/command-menu-item/contexts/CommandMenuContext'; -import { useCommandMenuContextApi } from '@/command-menu-item/hooks/useCommandMenuContextApi'; -import { useCommandMenuItemFrontComponentCommands } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentCommands'; import { useRegisteredCommandMenuItems } from '@/command-menu-item/hooks/useRegisteredCommandMenuItems'; import { useShouldCommandMenuItemBeRegisteredParams } from '@/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams'; import { useRunWorkflowRecordAgnosticCommands } from '@/command-menu-item/record-agnostic/workflow/hooks/useRunWorkflowRecordAgnosticCommands'; @@ -14,9 +12,7 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; type CommandMenuContextProviderWorkflowObjectsProps = { objectMetadataItem: ObjectMetadataItem; @@ -55,42 +51,16 @@ const CommandMenuContextProviderWorkflowObjectsContent = ({ const runWorkflowRecordAgnosticCommands = useRunWorkflowRecordAgnosticCommands(); - const commandMenuContextApi = useCommandMenuContextApi(); - - const enrichedSelectedRecords = isDefined(workflowWithCurrentVersion) - ? commandMenuContextApi.selectedRecords.map((record) => - record.id === workflowWithCurrentVersion.id - ? { - ...record, - currentVersion: workflowWithCurrentVersion.currentVersion, - versions: workflowWithCurrentVersion.versions, - statuses: workflowWithCurrentVersion.statuses, - } - : record, - ) - : commandMenuContextApi.selectedRecords; - - const enrichedCommandMenuContextApi = { - ...commandMenuContextApi, - selectedRecords: enrichedSelectedRecords, - }; - - const commandMenuItemFrontComponentActions = - useCommandMenuItemFrontComponentCommands(enrichedCommandMenuContextApi); - - const isCommandMenuItemEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED, - ); - return ( {children} @@ -123,24 +93,16 @@ const CommandMenuContextProviderWorkflowObjectsWithoutWorkflow = ({ const runWorkflowRecordAgnosticCommands = useRunWorkflowRecordAgnosticCommands(); - const commandMenuContextApi = useCommandMenuContextApi(); - - const commandMenuItemFrontComponentActions = - useCommandMenuItemFrontComponentCommands(commandMenuContextApi); - - const isCommandMenuItemEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED, - ); - return ( {children} diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems.tsx new file mode 100644 index 0000000000..7e525a58b5 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems.tsx @@ -0,0 +1,61 @@ +import { CoreObjectNameSingular } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; + +import { useCommandMenuContextApi } from '@/command-menu-item/server-items/hooks/useCommandMenuContextApi'; +import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext'; + +import { CommandMenuContextProviderServerItemsContent } from './CommandMenuContextProviderServerItemsContent'; +import { CommandMenuContextProviderServerItemsWithWorkflowEnrichment } from './CommandMenuContextProviderServerItemsWithWorkflowEnrichment'; + +type CommandMenuContextProviderServerItemsProps = { + isInSidePanel: CommandMenuContextType['isInSidePanel']; + displayType: CommandMenuContextType['displayType']; + containerType: CommandMenuContextType['containerType']; + children: React.ReactNode; +}; + +export const CommandMenuContextProviderServerItems = ({ + isInSidePanel, + displayType, + containerType, + children, +}: CommandMenuContextProviderServerItemsProps) => { + const commandMenuContextApi = useCommandMenuContextApi(); + + const currentObjectNameSingular = + commandMenuContextApi.objectMetadataItem.nameSingular; + + const isWorkflow = + currentObjectNameSingular === CoreObjectNameSingular.Workflow; + + const selectedWorkflowRecordIds = isWorkflow + ? commandMenuContextApi.selectedRecords + .map((record) => record.id) + .filter(isDefined) + : []; + + if (selectedWorkflowRecordIds.length > 0) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsContent.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsContent.tsx new file mode 100644 index 0000000000..b912281e70 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsContent.tsx @@ -0,0 +1,39 @@ +import { + CommandMenuContext, + type CommandMenuContextType, +} from '@/command-menu-item/contexts/CommandMenuContext'; +import { useCommandMenuItemFrontComponentCommands } from '@/command-menu-item/server-items/hooks/useCommandMenuItemFrontComponentCommands'; +import { type CommandMenuContextApi } from 'twenty-shared/types'; + +type CommandMenuContextProviderServerItemsContentProps = { + isInSidePanel: CommandMenuContextType['isInSidePanel']; + displayType: CommandMenuContextType['displayType']; + containerType: CommandMenuContextType['containerType']; + children: React.ReactNode; +}; + +export const CommandMenuContextProviderServerItemsContent = ({ + isInSidePanel, + displayType, + containerType, + children, + commandMenuContextApi, +}: CommandMenuContextProviderServerItemsContentProps & { + commandMenuContextApi: CommandMenuContextApi; +}) => { + const commandMenuItemFrontComponentActions = + useCommandMenuItemFrontComponentCommands(commandMenuContextApi); + + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx new file mode 100644 index 0000000000..871903e040 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx @@ -0,0 +1,65 @@ +import { type CommandMenuContextApi } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; + +import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext'; +import { useWorkflowsWithCurrentVersions } from '@/command-menu-item/server-items/hooks/useWorkflowsWithCurrentVersions'; + +import { CommandMenuContextProviderServerItemsContent } from './CommandMenuContextProviderServerItemsContent'; + +type CommandMenuContextProviderServerItemsWithWorkflowEnrichmentProps = { + isInSidePanel: CommandMenuContextType['isInSidePanel']; + displayType: CommandMenuContextType['displayType']; + containerType: CommandMenuContextType['containerType']; + children: React.ReactNode; +}; + +export const CommandMenuContextProviderServerItemsWithWorkflowEnrichment = ({ + isInSidePanel, + displayType, + containerType, + children, + commandMenuContextApi, + selectedWorkflowRecordIds, +}: CommandMenuContextProviderServerItemsWithWorkflowEnrichmentProps & { + commandMenuContextApi: CommandMenuContextApi; + selectedWorkflowRecordIds: string[]; +}) => { + const workflowsWithCurrentVersions = useWorkflowsWithCurrentVersions( + selectedWorkflowRecordIds, + ); + + const enrichedSelectedRecords = commandMenuContextApi.selectedRecords.map( + (record) => { + const workflowWithCurrentVersion = workflowsWithCurrentVersions.find( + (workflow) => workflow.id === record.id, + ); + + if (!isDefined(workflowWithCurrentVersion)) { + return record; + } + + return { + ...record, + currentVersion: workflowWithCurrentVersion.currentVersion, + versions: workflowWithCurrentVersion.versions, + statuses: workflowWithCurrentVersion.statuses, + }; + }, + ); + + const enrichedCommandMenuContextApi = { + ...commandMenuContextApi, + selectedRecords: enrichedSelectedRecords, + }; + + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuContextApi.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts similarity index 100% rename from packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuContextApi.ts rename to packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts diff --git a/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentCommands.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuItemFrontComponentCommands.tsx similarity index 96% rename from packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentCommands.tsx rename to packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuItemFrontComponentCommands.tsx index cbd81c13e4..ba746782ac 100644 --- a/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentCommands.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuItemFrontComponentCommands.tsx @@ -10,7 +10,6 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat import { useOpenFrontComponentInSidePanel } from '@/side-panel/hooks/useOpenFrontComponentInSidePanel'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { type CommandMenuContextApi } from 'twenty-shared/types'; import { evaluateConditionalAvailabilityExpression, @@ -23,7 +22,6 @@ import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants import { CommandMenuItemAvailabilityType, type CommandMenuItemFieldsFragment, - FeatureFlagKey, useFindManyCommandMenuItemsQuery, } from '~/generated-metadata/graphql'; @@ -159,13 +157,7 @@ export const useCommandMenuItemFrontComponentCommands = ( } : undefined; - const isCommandMenuItemEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED, - ); - - const { data } = useFindManyCommandMenuItemsQuery({ - skip: !isCommandMenuItemEnabled, - }); + const { data } = useFindManyCommandMenuItemsQuery(); const frontComponentItems = data?.commandMenuItems?.filter( diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useWorkflowsWithCurrentVersions.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useWorkflowsWithCurrentVersions.ts new file mode 100644 index 0000000000..ab77ec02d4 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useWorkflowsWithCurrentVersions.ts @@ -0,0 +1,73 @@ +import { CoreObjectNameSingular } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; + +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { + type Workflow, + type WorkflowVersion, + type WorkflowWithCurrentVersion, +} from '@/workflow/types/Workflow'; + +const getCurrentVersionId = (workflow: Workflow): string | undefined => { + const draftVersion = workflow.versions.find( + (version) => version.status === 'DRAFT', + ); + + const sortedVersions = workflow.versions.toSorted((a, b) => + a.createdAt > b.createdAt ? -1 : 1, + ); + + const latestVersion = sortedVersions[0]; + + return (draftVersion ?? latestVersion)?.id; +}; + +export const useWorkflowsWithCurrentVersions = ( + workflowIds: string[], +): WorkflowWithCurrentVersion[] => { + const { records: workflows } = useFindManyRecords({ + objectNameSingular: CoreObjectNameSingular.Workflow, + filter: { id: { in: workflowIds } }, + recordGqlFields: { + id: true, + name: true, + statuses: true, + lastPublishedVersionId: true, + versions: { + id: true, + status: true, + name: true, + createdAt: true, + }, + }, + skip: workflowIds.length === 0, + }); + + const currentVersionIds = workflows + .map(getCurrentVersionId) + .filter(isDefined); + + const { records: currentVersions } = useFindManyRecords({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + filter: { id: { in: currentVersionIds } }, + skip: currentVersionIds.length === 0, + }); + + return workflows + .map((workflow) => { + const currentVersionId = getCurrentVersionId(workflow); + const currentVersion = currentVersions.find( + (version) => version.id === currentVersionId, + ); + + if (!isDefined(currentVersion)) { + return undefined; + } + + return { + ...workflow, + currentVersion, + }; + }) + .filter(isDefined); +};