refactor(command-menu-item): rename Actions to CommandMenuItem (#18489)

actions are being renamed to command menu item, they will be migrated to
server and will be served as headless front components

---------

Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
This commit is contained in:
nitin
2026-03-09 19:33:12 +05:30
committed by GitHub
parent 06bdb5ad6a
commit 36bcc71f3d
275 changed files with 4544 additions and 4436 deletions
@@ -0,0 +1,6 @@
import { type CommandMenuItemConfig } from '@/command-menu-item/types/CommandMenuItemConfig';
import { createContext } from 'react';
export const CommandConfigContext = createContext<CommandMenuItemConfig | null>(
null,
);
@@ -0,0 +1,17 @@
import { type CommandMenuItemConfig } from '@/command-menu-item/types/CommandMenuItemConfig';
import { type CommandMenuItemContainerType } from '@/command-menu-item/types/CommandMenuItemContainerType';
import { createContext } from 'react';
export type CommandMenuContextType = {
isInSidePanel: boolean;
displayType: 'button' | 'listItem' | 'dropdownItem';
containerType: CommandMenuItemContainerType;
commandMenuItems: CommandMenuItemConfig[];
};
export const CommandMenuContext = createContext<CommandMenuContextType>({
isInSidePanel: false,
containerType: 'command-menu-list',
displayType: 'button',
commandMenuItems: [],
});
@@ -0,0 +1,69 @@
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 CommandMenuContextProvider = ({
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 (!isDefined(objectMetadataItem)) {
return null;
}
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>
);
};
@@ -0,0 +1,78 @@
import { useRunWorkflowRecordCommands } from '@/command-menu-item/record/workflow/hooks/useRunWorkflowRecordCommands';
import { useRunWorkflowRecordAgnosticCommands } from '@/command-menu-item/record-agnostic/workflow/hooks/useRunWorkflowRecordAgnosticCommands';
import {
CommandMenuContext,
type CommandMenuContextType,
} from '@/command-menu-item/contexts/CommandMenuContext';
import { useRegisteredCommandMenuItems } from '@/command-menu-item/hooks/useRegisteredCommandMenuItems';
import { useShouldCommandMenuItemBeRegisteredParams } from '@/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams';
import { useCommandMenuContextApi } from '@/command-menu-item/hooks/useCommandMenuContextApi';
import { useCommandMenuItemFrontComponentActions } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentActions';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
export const CommandMenuContextProviderDefault = ({
objectMetadataItem,
isInSidePanel,
displayType,
containerType,
children,
}: {
objectMetadataItem: ObjectMetadataItem;
isInSidePanel: CommandMenuContextType['isInSidePanel'];
displayType: CommandMenuContextType['displayType'];
containerType: CommandMenuContextType['containerType'];
children: React.ReactNode;
}) => {
const params = useShouldCommandMenuItemBeRegisteredParams({
objectMetadataItem,
});
const shouldBeRegisteredParams = {
...params,
};
const commandMenuItems = useRegisteredCommandMenuItems(
shouldBeRegisteredParams,
);
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
contextStoreTargetedRecordsRuleComponentState,
);
const isRecordSelection =
contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length > 0;
const runWorkflowRecordCommands = useRunWorkflowRecordCommands({
objectMetadataItem,
skip: !isRecordSelection,
});
const runWorkflowRecordAgnosticCommands =
useRunWorkflowRecordAgnosticCommands();
const commandMenuContextApi = useCommandMenuContextApi();
const commandMenuItemFrontComponentActions =
useCommandMenuItemFrontComponentActions(commandMenuContextApi);
return (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordCommands,
...runWorkflowRecordAgnosticCommands,
...commandMenuItemFrontComponentActions,
],
}}
>
{children}
</CommandMenuContext.Provider>
);
};
@@ -0,0 +1,173 @@
import { useRunWorkflowRecordAgnosticCommands } from '@/command-menu-item/record-agnostic/workflow/hooks/useRunWorkflowRecordAgnosticCommands';
import {
CommandMenuContext,
type CommandMenuContextType,
} from '@/command-menu-item/contexts/CommandMenuContext';
import { useRegisteredCommandMenuItems } from '@/command-menu-item/hooks/useRegisteredCommandMenuItems';
import { useShouldCommandMenuItemBeRegisteredParams } from '@/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams';
import { useCommandMenuContextApi } from '@/command-menu-item/hooks/useCommandMenuContextApi';
import { useCommandMenuItemFrontComponentActions } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentActions';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
import { isDefined } from 'twenty-shared/utils';
type CommandMenuContextProviderWorkflowObjectsProps = {
objectMetadataItem: ObjectMetadataItem;
isInSidePanel: CommandMenuContextType['isInSidePanel'];
displayType: CommandMenuContextType['displayType'];
containerType: CommandMenuContextType['containerType'];
children: React.ReactNode;
};
const CommandMenuContextProviderWorkflowObjectsContent = ({
objectMetadataItem,
isInSidePanel,
displayType,
containerType,
children,
selectedRecordId,
}: CommandMenuContextProviderWorkflowObjectsProps & {
selectedRecordId: string;
}) => {
const params = useShouldCommandMenuItemBeRegisteredParams({
objectMetadataItem,
});
const workflowWithCurrentVersion =
useWorkflowWithCurrentVersion(selectedRecordId);
const shouldBeRegisteredParams = {
...params,
workflowWithCurrentVersion,
};
const commandMenuItems = useRegisteredCommandMenuItems(
shouldBeRegisteredParams,
);
const runWorkflowRecordAgnosticCommands =
useRunWorkflowRecordAgnosticCommands();
const commandMenuContextApi = useCommandMenuContextApi();
const commandMenuItemFrontComponentActions =
useCommandMenuItemFrontComponentActions(commandMenuContextApi);
return (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
...commandMenuItemFrontComponentActions,
],
}}
>
{children}
</CommandMenuContext.Provider>
);
};
const CommandMenuContextProviderWorkflowObjectsWithoutWorkflow = ({
objectMetadataItem,
isInSidePanel,
displayType,
containerType,
children,
}: CommandMenuContextProviderWorkflowObjectsProps & {
workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined;
}) => {
const params = useShouldCommandMenuItemBeRegisteredParams({
objectMetadataItem,
});
const shouldBeRegisteredParams = {
...params,
workflowWithCurrentVersion: undefined,
};
const commandMenuItems = useRegisteredCommandMenuItems(
shouldBeRegisteredParams,
);
const runWorkflowRecordAgnosticCommands =
useRunWorkflowRecordAgnosticCommands();
const commandMenuContextApi = useCommandMenuContextApi();
const commandMenuItemFrontComponentActions =
useCommandMenuItemFrontComponentActions(commandMenuContextApi);
return (
<CommandMenuContext.Provider
value={{
isInSidePanel,
displayType,
containerType,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
...commandMenuItemFrontComponentActions,
],
}}
>
{children}
</CommandMenuContext.Provider>
);
};
export const CommandMenuContextProviderWorkflowObjects = ({
objectMetadataItem,
isInSidePanel,
displayType,
containerType,
children,
}: CommandMenuContextProviderWorkflowObjectsProps) => {
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
contextStoreTargetedRecordsRuleComponentState,
);
const recordId =
contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length === 1
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
: undefined;
const selectedRecord =
useAtomFamilyStateValue(recordStoreFamilyState, recordId ?? '') ||
undefined;
if (isDefined(selectedRecord?.id)) {
return (
<CommandMenuContextProviderWorkflowObjectsContent
objectMetadataItem={objectMetadataItem}
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
selectedRecordId={selectedRecord.id}
>
{children}
</CommandMenuContextProviderWorkflowObjectsContent>
);
}
return (
<CommandMenuContextProviderWorkflowObjectsWithoutWorkflow
objectMetadataItem={objectMetadataItem}
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
workflowWithCurrentVersion={undefined}
>
{children}
</CommandMenuContextProviderWorkflowObjectsWithoutWorkflow>
);
};