Separate code pathways for IS_COMMAND_MENU_ITEM_ENABLED flag (#18542)

This commit is contained in:
nitin
2026-03-11 19:00:22 +05:30
committed by GitHub
parent 6cbc7725b7
commit 2c5af2654d
10 changed files with 330 additions and 117 deletions
@@ -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 (
<CommandMenuContextProviderWorkflowObjects
<CommandMenuContextProviderServerItems
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
objectMetadataItem={objectMetadataItem}
>
{children}
</CommandMenuContextProviderWorkflowObjects>
</CommandMenuContextProviderServerItems>
);
}
return (
<CommandMenuContextProviderDefault
<CommandMenuContextProviderLegacy
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
objectMetadataItem={objectMetadataItem}
objectMetadataItemOverride={objectMetadataItemOverride}
>
{children}
</CommandMenuContextProviderDefault>
</CommandMenuContextProviderLegacy>
);
};
@@ -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 (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: isCommandMenuItemEnabled
? commandMenuItemFrontComponentActions
: [
...commandMenuItems,
...runWorkflowRecordCommands,
...runWorkflowRecordAgnosticCommands,
],
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordCommands,
...runWorkflowRecordAgnosticCommands,
],
}}
>
{children}
@@ -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<CommandMenuContextType, 'commandMenuItems'> & {
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 (
<CommandMenuContextProviderWorkflowObjects
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
objectMetadataItem={objectMetadataItem}
>
{children}
</CommandMenuContextProviderWorkflowObjects>
);
}
return (
<CommandMenuContextProviderDefault
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
objectMetadataItem={objectMetadataItem}
>
{children}
</CommandMenuContextProviderDefault>
);
};
@@ -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 (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: isCommandMenuItemEnabled
? commandMenuItemFrontComponentActions
: [...commandMenuItems, ...runWorkflowRecordAgnosticCommands],
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
],
}}
>
{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 (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: isCommandMenuItemEnabled
? commandMenuItemFrontComponentActions
: [...commandMenuItems, ...runWorkflowRecordAgnosticCommands],
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
],
}}
>
{children}
@@ -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 (
<CommandMenuContextProviderServerItemsWithWorkflowEnrichment
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
commandMenuContextApi={commandMenuContextApi}
selectedWorkflowRecordIds={selectedWorkflowRecordIds}
>
{children}
</CommandMenuContextProviderServerItemsWithWorkflowEnrichment>
);
}
return (
<CommandMenuContextProviderServerItemsContent
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
commandMenuContextApi={commandMenuContextApi}
>
{children}
</CommandMenuContextProviderServerItemsContent>
);
};
@@ -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 (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: commandMenuItemFrontComponentActions,
}}
>
{children}
</CommandMenuContext.Provider>
);
};
@@ -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 (
<CommandMenuContextProviderServerItemsContent
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
commandMenuContextApi={enrichedCommandMenuContextApi}
>
{children}
</CommandMenuContextProviderServerItemsContent>
);
};
@@ -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(
@@ -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<Workflow>({
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<WorkflowVersion>({
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);
};