Skip to content

feat: add command menu item to layout customization#18764

Open
ehconitin wants to merge 57 commits intomainfrom
command-menu-item-edition
Open

feat: add command menu item to layout customization#18764
ehconitin wants to merge 57 commits intomainfrom
command-menu-item-edition

Conversation

@ehconitin
Copy link
Contributor

@ehconitin ehconitin commented Mar 19, 2026

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

…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
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

…ents to support enhanced record selection and preview modes
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

@charlesBochet charlesBochet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :)

@ehconitin ehconitin force-pushed the command-menu-item-edition branch from 21e1fb1 to a8e68c0 Compare March 23, 2026 08:43
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +45 to +47
if (!isDefined(nextContextualItem) && !isDefined(previousContextualItem)) {
return undefined;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

});
};

const makeOptionsDropdownWrapper =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this type of pattern with a function that returns an component in the codebase, directly use a component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

Resolve useEditPageLayoutWidget: keep editing widget id and CommandMenuDisplay fallback.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants