feat: add command menu item to layout customization#18764
feat: add command menu item to layout customization#18764
Conversation
…mand menus ### What - Added `EditActionsButton` to both `RecordIndexCommandMenu` and `RecordShowCommandMenu` components to enhance user interaction. ### Why - This addition allows users to access edit actions directly from the command menus, improving the overall usability of the application. ### Changes - Updated imports and JSX structure in `RecordIndexCommandMenu.tsx` and `RecordShowCommandMenu.tsx` to include the new button.
Move edit/, graphql mutation, selector state, and CommandMenuItemDraggable into server-items/ so all IS_COMMAND_MENU_ITEM_ENABLED code lives in one directory, cleanly separated from the legacy path.
…pdate SidePanelCommandMenuItemEditPage layout
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
18 issues found across 55 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useResetCommandMenuItemsDraft.ts">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useResetCommandMenuItemsDraft.ts:18">
P1: Limit this reset to the currently edited command-menu context; it currently reverts hidden items from other pages/objects too.</violation>
</file>
<file name="packages/twenty-front/src/modules/side-panel/constants/SidePanelPagesConfig.tsx">
<violation number="1" location="packages/twenty-front/src/modules/side-panel/constants/SidePanelPagesConfig.tsx:40">
P1: Falling back to `SidePanelRootPage` here leaves the side panel in `CommandMenuDisplay` state, so feature-disabled users get the root content rendered under the command-menu search UI.</violation>
</file>
<file name="packages/twenty-front/src/modules/side-panel/hooks/useSidePanelContextChips.tsx">
<violation number="1" location="packages/twenty-front/src/modules/side-panel/hooks/useSidePanelContextChips.tsx:55">
P1: Filtering `CommandMenuDisplay` here shifts breadcrumb indices, so chip/history clicks navigate to the wrong page.</violation>
</file>
<file name="packages/twenty-front/src/pages/object-record/RecordShowPage.tsx">
<violation number="1" location="packages/twenty-front/src/pages/object-record/RecordShowPage.tsx:65">
P1: Don't hide the side-panel button in layout customization mode; on mobile this removes the only close/open control for the customization side panel.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/components/MoreActionsButton.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/components/MoreActionsButton.tsx:104">
P3: This condition is dead in the current implementation: `MoreActionsButton` only mounts when layout customization is disabled, so the `alignWithSidePanelTopBar` branch can never run.</violation>
</file>
<file name="packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx">
<violation number="1" location="packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx:90">
P2: Changing the feature flag after the initial real load will not fetch `commandMenuItems`, because the effect bails out once `loadedState` already matches `desiredLoadState`.</violation>
</file>
<file name="packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts">
<violation number="1" location="packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts:58">
P2: Copy the main context into the side panel before auto-navigating to `CommandMenuEdit`; `navigateSidePanel()` does not refresh that context when the panel is already open, so this path can open the editor with stale side-panel state.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/EditActionsButton.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/EditActionsButton.tsx:105">
P1: This resets the side-panel context to the main page before navigation, so editing from an already-open contextual command menu can switch to the wrong action set.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/components/CommandMenuItemDraggable.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/components/CommandMenuItemDraggable.tsx:15">
P3: Remove the unused required `id` prop from this wrapper; it is never read or forwarded.</violation>
<violation number="2" location="packages/twenty-front/src/modules/command-menu-item/server-items/components/CommandMenuItemDraggable.tsx:50">
P2: `disabled` does not disable the row's icon-button actions, so a disabled item can still be mutated through its trailing buttons.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuEditRecordSelectionDropdown.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuEditRecordSelectionDropdown.tsx:82">
P2: Exclusion mode is a bulk/select-all preview, so setting `numberOfSelectedRecords` to `1` makes bulk-only commands preview incorrectly.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts:25">
P1: This reorder uses the full pinned draft instead of the contextual items the user is dragging, so drops can resolve to the wrong position when hidden pinned items exist.</violation>
</file>
<file name="packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts">
<violation number="1" location="packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts:62">
P2: Saving command-menu drafts before page layouts creates another partial-commit path when a later layout save fails.</violation>
</file>
<file name="packages/twenty-front/src/modules/side-panel/components/SidePanelTopBar.tsx">
<violation number="1" location="packages/twenty-front/src/modules/side-panel/components/SidePanelTopBar.tsx:173">
P2: The new search box on `CommandMenuEdit` is non-functional because the edit page never consumes `sidePanelSearchState` or filters its items.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/components/SidePanelCommandMenuItemDisplayPage.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/components/SidePanelCommandMenuItemDisplayPage.tsx:71">
P2: Only add the reset-context selectable ID when the reset action will actually render; otherwise the side panel can default-select a non-existent item.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx:226">
P2: Only show the label-options dropdown for items with a seeded short label. On commands without an `engineComponentKey`, the dropdown's hide/reset actions cannot change anything.</violation>
</file>
<file name="packages/twenty-shared/src/command-menu/constants/standard-command-menu-item-defaults.constant.ts">
<violation number="1" location="packages/twenty-shared/src/command-menu/constants/standard-command-menu-item-defaults.constant.ts:5">
P2: This introduces a duplicate source of truth for editable command defaults; the server constant still hardcodes many of the same `shortLabel` values and now gets overridden by this shared map.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemOptionsDropdown.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemOptionsDropdown.tsx:44">
P2: Unhiding a label overwrites any custom short-label override with the seeded default.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
...front/src/modules/command-menu-item/server-items/edit/hooks/useResetCommandMenuItemsDraft.ts
Show resolved
Hide resolved
packages/twenty-front/src/modules/side-panel/constants/SidePanelPagesConfig.tsx
Outdated
Show resolved
Hide resolved
packages/twenty-front/src/modules/side-panel/hooks/useSidePanelContextChips.tsx
Show resolved
Hide resolved
packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
Outdated
Show resolved
Hide resolved
...wenty-front/src/modules/command-menu-item/server-items/edit/components/EditActionsButton.tsx
Outdated
Show resolved
Hide resolved
.../modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx
Outdated
Show resolved
Hide resolved
...ges/twenty-shared/src/command-menu/constants/standard-command-menu-item-defaults.constant.ts
Outdated
Show resolved
Hide resolved
...rc/modules/command-menu-item/server-items/edit/components/CommandMenuItemOptionsDropdown.tsx
Show resolved
Hide resolved
...dules/command-menu-item/server-items/display/components/CommandMenuItemMoreActionsButton.tsx
Outdated
Show resolved
Hide resolved
...nty-front/src/modules/command-menu-item/server-items/components/CommandMenuItemDraggable.tsx
Outdated
Show resolved
Hide resolved
…d menu item hooks
…erences in SidePanelCommandMenuItemEditPage
There was a problem hiding this comment.
2 issues found across 12 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx">
<violation number="1" location="packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx:89">
P2: `PageHeaderToggleSidePanelButton` is no longer hidden in layout customization mode when the command-menu feature flag is off.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts:28">
P1: Filtering reorder candidates to `contextualItemIds` makes the new position ignore hidden pinned items, so dragging in one context can reorder the item across other contexts' pinned entries.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
...t/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts
Outdated
Show resolved
Hide resolved
...ges/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx
Show resolved
Hide resolved
...t/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts
Outdated
Show resolved
Hide resolved
…multiple record selection handling
…ents to support enhanced record selection and preview modes
There was a problem hiding this comment.
2 issues found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts:50">
P1: Early return prevents reordering into an empty target context/section, so valid drag operations can be ignored.</violation>
</file>
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/EditActionsButton.tsx">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/EditActionsButton.tsx:105">
P1: Opening Command Menu Edit no longer syncs main context into the side-panel context, which can leave edit mode bound to stale object/view state.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
...t/src/modules/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft.ts
Outdated
Show resolved
Hide resolved
...ont/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx
Outdated
Show resolved
Hide resolved
charlesBochet
left a comment
There was a problem hiding this comment.
This a promising work @ehconitin! I've left comment on the code at this stage and I haven't QAed the front end but let's fix the comment first
@bosiraphael can you assist here :)
...rc/modules/command-menu-item/server-items/edit/components/CommandMenuItemOptionsDropdown.tsx
Outdated
Show resolved
Hide resolved
21e1fb1 to
a8e68c0
Compare
There was a problem hiding this comment.
2 issues found across 38 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/command-menu-item/server-items/common/utils/getCommandMenuPreviewRecordSelection.ts">
<violation number="1" location="packages/twenty-front/src/modules/command-menu-item/server-items/common/utils/getCommandMenuPreviewRecordSelection.ts:43">
P2: Non-auto preview can include excluded records when current targeting is in exclusion mode. Filter out `excludedRecordIds` before slicing so previewed selected records match the active targeting rule.</violation>
</file>
<file name="packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx">
<violation number="1" location="packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx:54">
P1: Removing the command-menu context wrapper here leaves side-panel pages without command menu items; `SidePanelRootPage` then reads the default empty context and renders no actions.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx
Outdated
Show resolved
Hide resolved
.../modules/command-menu-item/server-items/common/utils/getCommandMenuPreviewRecordSelection.ts
Outdated
Show resolved
Hide resolved
…onents and enhance record selection logic
| if (!isDefined(nextContextualItem) && !isDefined(previousContextualItem)) { | ||
| return undefined; | ||
| } |
There was a problem hiding this comment.
Bug: Using Promise.all in saveCommandMenuItemsDraft for batch mutations can lead to partial data loss and an inconsistent state if any single mutation fails.
Severity: MEDIUM
Suggested Fix
Replace Promise.all with Promise.allSettled. This ensures all mutation promises are settled, regardless of individual failures. After Promise.allSettled completes, iterate through the results to identify and handle any rejected promises, allowing for more granular error reporting and preventing partial data loss.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location:
packages/twenty-front/src/modules/command-menu-item/server-items/edit/utils/computeReorderPositionForCommandMenuItemInDraft.ts#L45-L47
Potential issue: The `saveCommandMenuItemsDraft` function uses `Promise.all()` to
execute multiple GraphQL mutations for updating command menu items. The `useMutation`
hook from Apollo Client rejects the promise on any GraphQL error. If a single mutation
fails, `Promise.all()` rejects immediately, halting the entire process. While an outer
`try-catch` block prevents a crash, this behavior leads to a partial failure state. Some
items may be successfully saved while others are not, creating an inconsistency between
the UI and the server. The user only sees a generic failure message, resulting in silent
data loss for the items that failed to update.
packages/twenty-front/src/modules/command-menu-item/components/AnimatedIconCrossfade.tsx
Show resolved
Hide resolved
.../twenty-front/src/modules/command-menu-item/contexts/useCommandMenuContextStoreInstanceId.ts
Outdated
Show resolved
Hide resolved
...y-front/src/modules/command-menu-item/contexts/CommandMenuContextProviderWorkflowObjects.tsx
Outdated
Show resolved
Hide resolved
...modules/command-menu-item/server-items/common/components/SidePanelCommandMenuPageEntries.tsx
Outdated
Show resolved
Hide resolved
...les/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItems.tsx
Outdated
Show resolved
Hide resolved
...server-items/common/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx
Outdated
Show resolved
Hide resolved
...odules/command-menu-item/server-items/display/hooks/usePinnedCommandMenuItemsInlineLayout.ts
Show resolved
Hide resolved
| }); | ||
| }; | ||
|
|
||
| const makeOptionsDropdownWrapper = |
There was a problem hiding this comment.
We don't use this type of pattern with a function that returns an component in the codebase, directly use a component
There was a problem hiding this comment.
umm we actually need the closure here -- the Wrapper render prop on MenuItemIconButton is how twenty-ui supports wrapping icon buttons (defined in MenuItem.tsx, LightIconButtonGroup.tsx).
If we use the component directly, it gets rendered outside MenuItemDraggable and breaks the hover reveal behavior of iconButtons. This is the first usage of Wrapper in the codebase but may be the API exists in twenty ui for exactly this use case?
happy to discuss!
.../modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx
Show resolved
Hide resolved
...front/src/modules/command-menu-item/server-items/edit/hooks/useResetCommandMenuItemsDraft.ts
Outdated
Show resolved
Hide resolved
Resolve useEditPageLayoutWidget: keep editing widget id and CommandMenuDisplay fallback. Made-with: Cursor
figma https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=93630-365000&t=QesAkY3JOyI9D3UU-0
CleanShot.2026-03-20.at.19.53.17.mp4
CleanShot.2026-03-20.at.19.54.31.mp4