abdab2fb7e
## Description - Introduces a new engine command execution model that replaces the previous approach of mapping `EngineComponentKey` to React components. Instead, engine commands are now mounted headlessly via `HeadlessEngineCommandMountRoot`, with their execution context populated synchronously before mounting. - Creates new headless command components - Moves error handling from the SDK layer to the host app by wrapping all mounted commands with a new `CommandMenuItemErrorBoundary` The new flow works as follows: - When a command menu item with an `engineComponentKey` is clicked, `useCommandMenuItemFrontComponentCommands` calls `useMountEngineCommand`, which synchronously reads the current context store (object metadata, selected records, filters, view ID, etc.) and writes a `MountedEngineCommandContext` into `mountedEngineCommandsState`. - The command is then mounted into `mountedEngineCommandsState`, which triggers `HeadlessEngineCommandMountRoot` to render the corresponding headless component from `ENGINE_COMPONENT_KEY_HEADLESS_COMPONENT_MAP`, wrapped in `CommandMenuItemErrorBoundary`, `ContextStoreComponentInstanceContext.Provider`, and `EngineCommandComponentInstanceContext.Provider`. - Each command component reads its execution context and delegates to one of the 4 execution patterns: `HeadlessEngineCommandWrapperEffect` (simple actions), `HeadlessConfirmationModalEngineCommandEffect` (destructive actions needing confirmation), `HeadlessNavigateEngineCommand` (GO_TO_* commands), or `HeadlessOpenSidePanelPageEngineCommand` (SEARCH_RECORDS, ASK_AI, VIEW_PREVIOUS_AI_CHATS). - After execution, the command self-unmounts via `useUnmountEngineCommand`, which removes the entry from `mountedEngineCommandsState` and stops rendering the component.
71 lines
2.8 KiB
TypeScript
71 lines
2.8 KiB
TypeScript
import { COMMAND_MENU_CONFIRMATION_MODAL_INSTANCE_ID } from '@/command-menu-item/confirmation-modal/constants/CommandMenuItemConfirmationModalId';
|
|
import { COMMAND_MENU_CONFIRMATION_MODAL_RESULT_BROWSER_EVENT_NAME } from '@/command-menu-item/confirmation-modal/constants/CommandMenuItemConfirmationModalResultBrowserEventName';
|
|
import { commandMenuItemConfirmationModalConfigState } from '@/command-menu-item/confirmation-modal/states/commandMenuItemConfirmationModalState';
|
|
import {
|
|
type CommandMenuConfirmationModalResult,
|
|
type CommandMenuConfirmationModalResultBrowserEventDetail,
|
|
} from '@/command-menu-item/confirmation-modal/types/CommandMenuConfirmationModalResultBrowserEventDetail';
|
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
|
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
|
|
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
|
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
|
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
|
|
export const CommandMenuConfirmationModalManager = () => {
|
|
const commandMenuItemConfirmationModalConfig = useAtomStateValue(
|
|
commandMenuItemConfirmationModalConfigState,
|
|
);
|
|
const isModalOpened = useAtomComponentStateValue(
|
|
isModalOpenedComponentState,
|
|
COMMAND_MENU_CONFIRMATION_MODAL_INSTANCE_ID,
|
|
);
|
|
const setCommandMenuItemConfirmationModalConfig = useSetAtomState(
|
|
commandMenuItemConfirmationModalConfigState,
|
|
);
|
|
|
|
const caller = commandMenuItemConfirmationModalConfig?.caller;
|
|
|
|
const emitConfirmationResult = (
|
|
confirmationResult: CommandMenuConfirmationModalResult,
|
|
) => {
|
|
if (!isDefined(caller)) {
|
|
return;
|
|
}
|
|
|
|
window.dispatchEvent(
|
|
new CustomEvent<CommandMenuConfirmationModalResultBrowserEventDetail>(
|
|
COMMAND_MENU_CONFIRMATION_MODAL_RESULT_BROWSER_EVENT_NAME,
|
|
{
|
|
detail: {
|
|
caller,
|
|
confirmationResult,
|
|
},
|
|
},
|
|
),
|
|
);
|
|
|
|
setCommandMenuItemConfirmationModalConfig(null);
|
|
};
|
|
|
|
if (!commandMenuItemConfirmationModalConfig || !isModalOpened) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<ConfirmationModal
|
|
modalInstanceId={COMMAND_MENU_CONFIRMATION_MODAL_INSTANCE_ID}
|
|
title={commandMenuItemConfirmationModalConfig.title}
|
|
subtitle={commandMenuItemConfirmationModalConfig.subtitle}
|
|
onConfirmClick={() => emitConfirmationResult('confirm')}
|
|
onClose={() => emitConfirmationResult('cancel')}
|
|
confirmButtonText={
|
|
commandMenuItemConfirmationModalConfig.confirmButtonText
|
|
}
|
|
confirmButtonAccent={
|
|
commandMenuItemConfirmationModalConfig.confirmButtonAccent
|
|
}
|
|
/>
|
|
);
|
|
};
|