Resolve frontComponent relation on command menu items via selector (#19493)

## Bug description

Headless command menu items were interpreted as non headless command
menu items and opened in the side panel.


https://github.com/user-attachments/assets/44d8b4d3-9ee5-4f12-9ff8-b3ed51e5b3b6

## Fix


https://github.com/user-attachments/assets/9d6eb900-9817-4ceb-87aa-547ad046a5a1

- Command menu items received via SSE lack the nested `frontComponent`
relation (only `frontComponentId` is present), causing
`item.frontComponent?.isHeadless` to always be undefined.
- Add `frontComponents` to the metadata store's stale entity loading
- Rewrite `commandMenuItemsSelector` to join `commandMenuItems` with
`frontComponents` by `frontComponentId`
This commit is contained in:
Raphaël Bosi
2026-04-09 14:15:52 +02:00
committed by GitHub
parent 19f11b1216
commit 086ea644bb
4 changed files with 52 additions and 4 deletions
@@ -1,5 +1,8 @@
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
import { type FlatCommandMenuItem } from '@/metadata-store/types/FlatCommandMenuItem';
import { type FlatFrontComponent } from '@/metadata-store/types/FlatFrontComponent';
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
import { isDefined } from 'twenty-shared/utils';
import { type CommandMenuItemFieldsFragment } from '~/generated-metadata/graphql';
export const commandMenuItemsSelector = createAtomSelector<
@@ -7,8 +10,25 @@ export const commandMenuItemsSelector = createAtomSelector<
>({
key: 'commandMenuItemsSelector',
get: ({ get }) => {
const storeItem = get(metadataStoreState, 'commandMenuItems');
const commandMenuItems = get(metadataStoreState, 'commandMenuItems')
.current as FlatCommandMenuItem[];
const flatFrontComponents = get(metadataStoreState, 'frontComponents')
.current as FlatFrontComponent[];
return storeItem.current as CommandMenuItemFieldsFragment[];
const frontComponentsById = new Map(
flatFrontComponents.map((frontComponent) => [
frontComponent.id,
frontComponent,
]),
);
return commandMenuItems.map((item) => ({
...item,
frontComponent: isDefined(item.frontComponentId)
? (frontComponentsById.get(item.frontComponentId) ??
item.frontComponent ??
null)
: null,
})) as CommandMenuItemFieldsFragment[];
},
});