CommandMenuItem overridable entity (#21486)

## Context
Second PR of the overridable-entities track (after #21436 for views):
command menu items become overridable so that edits on non-owned items
are stored as overrides instead of mutating the row, and
deletion/deactivation becomes reversible.

 ## What this does

- `CommandMenuItemEntity` now extends
`OverridableEntity<CommandMenuItemOverrides>` (adds `isActive` +
`overrides`). All editable properties are overridable for now (to
discuss).
- **Update**: mutations on a command item not owned by the caller
(standard items) are written into `overrides`; reads merge them in the
DTO. The command palette edit mode (pin,
reorder, shortLabel) now preserves standard values, "Reset label to
default" gains true post-save semantics.
- **Delete**: protected items are deactivated (`isActive = false`)
instead of deleted; custom items still hard-delete.
- **Object deactivate/enable toggle**: now flips `isActive` on the
command item (merged into the main migration call) instead of
delete/recreate; a create-if-missing fallback covers legacy deactivated
objects.
- **Front**: inactive command items are filtered out of the palette
selector.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21486?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Weiko
2026-06-13 14:21:27 +02:00
committed by GitHub
parent 036d9a2bcf
commit f63f053444
34 changed files with 481 additions and 78 deletions
@@ -30,5 +30,6 @@ export const COMMAND_MENU_ITEM_FRAGMENT = gql`
availabilityType
availabilityObjectMetadataId
pageLayoutId
isActive
}
`;
@@ -8,6 +8,7 @@ export const createMockCommandMenuItems =
(): CommandMenuItemFieldsFragment[] => [
{
__typename: 'CommandMenuItem',
isActive: true,
id: 'mock-add-to-favorites',
workflowVersionId: null,
frontComponentId: null,
@@ -26,6 +27,7 @@ export const createMockCommandMenuItems =
},
{
__typename: 'CommandMenuItem',
isActive: true,
id: 'mock-export',
workflowVersionId: null,
frontComponentId: null,
@@ -44,6 +46,7 @@ export const createMockCommandMenuItems =
},
{
__typename: 'CommandMenuItem',
isActive: true,
id: 'mock-delete',
workflowVersionId: null,
frontComponentId: null,
@@ -62,6 +65,7 @@ export const createMockCommandMenuItems =
},
{
__typename: 'CommandMenuItem',
isActive: true,
id: 'mock-go-to-people',
workflowVersionId: null,
frontComponentId: null,
@@ -22,13 +22,15 @@ export const commandMenuItemsSelector = createAtomSelector<
]),
);
return commandMenuItems.map((item) => ({
...item,
frontComponent: isDefined(item.frontComponentId)
? (frontComponentsById.get(item.frontComponentId) ??
item.frontComponent ??
null)
: null,
})) as CommandMenuItemFieldsFragment[];
return commandMenuItems
.filter((item) => item.isActive)
.map((item) => ({
...item,
frontComponent: isDefined(item.frontComponentId)
? (frontComponentsById.get(item.frontComponentId) ??
item.frontComponent ??
null)
: null,
})) as CommandMenuItemFieldsFragment[];
},
});