[Command Menu] Fix record-selection command filtering in edit mode (#20034)
https://github.com/user-attachments/assets/fe1461c7-0d5c-4c6f-8c2e-2cf569e7de90 ## What Fix `RECORD_SELECTION` items leaking into the command menu when nothing is selected, and unify how the menu renders in normal vs edit mode. ## The bug `RECORD_SELECTION`-availability items were showing up even when `numberOfSelectedRecords === 0`. New util `doesCommandMenuItemMatchSelectionState` gates them, applied consistently in the runtime provider and the editor. ## The refactor `PinnedCommandMenuItemButtonsEditMode` was a 140-line near-duplicate of `PinnedCommandMenuItemButtons` with its own (drifting) filter logic. Killed it. Edit mode now flows through the same `CommandMenuContextProvider` with a new `isInPreviewMode` flag — one filter chain, one rendering path. ## Behavior in edit mode **Header (pinned buttons in page header):** - Runs the full filter chain — object metadata, page type, selection state, page layout, *and the conditional availability expression* - Buttons render at full styling but are inert via `pointer-events: none` + `cursor: not-allowed` - Preview now reflects exactly what users will see on the live page (not a grayed-out approximation) **Side panel editor:** - New `useEditableCommandMenuItems` hook - Same filters as runtime *minus* the conditional availability expression and `FALLBACK` items — so it surfaces everything that's actually configurable for this page context - Still gates on selection state — if no records selected, `RECORD_SELECTION` items are hidden from the editor too. Open to feedback if we'd rather always show them so users can pin them ahead of time. ## Misc - `usePinnedCommandMenuItemsInlineLayout` — visible count now waits until every item is measured before committing. Fixes a flash of wrong counts on mount/resize - Renamed `useCommandMenuContextApi` → `useCurrentCommandMenuContextApi` — name now conveys it reads from the *current* scoped context store - Copy: "Records selected" → "Record(s) selected"
This commit is contained in:
+36
@@ -0,0 +1,36 @@
|
||||
import { doesCommandMenuItemMatchSelectionState } from '@/command-menu-item/utils/doesCommandMenuItemMatchSelectionState';
|
||||
import {
|
||||
CommandMenuItemAvailabilityType,
|
||||
type CommandMenuItemFieldsFragment,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const buildCommandMenuItem = (
|
||||
availabilityType: CommandMenuItemAvailabilityType,
|
||||
) =>
|
||||
({
|
||||
availabilityType,
|
||||
}) as CommandMenuItemFieldsFragment;
|
||||
|
||||
describe('doesCommandMenuItemMatchSelectionState', () => {
|
||||
it('should keep a non-record-selection item when no records are selected', () => {
|
||||
const item = buildCommandMenuItem(CommandMenuItemAvailabilityType.GLOBAL);
|
||||
|
||||
expect(doesCommandMenuItemMatchSelectionState(false)(item)).toBe(true);
|
||||
});
|
||||
|
||||
it('should hide a record-selection item when no records are selected', () => {
|
||||
const item = buildCommandMenuItem(
|
||||
CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
);
|
||||
|
||||
expect(doesCommandMenuItemMatchSelectionState(false)(item)).toBe(false);
|
||||
});
|
||||
|
||||
it('should keep a record-selection item when records are selected', () => {
|
||||
const item = buildCommandMenuItem(
|
||||
CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
);
|
||||
|
||||
expect(doesCommandMenuItemMatchSelectionState(true)(item)).toBe(true);
|
||||
});
|
||||
});
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import {
|
||||
CommandMenuItemAvailabilityType,
|
||||
type CommandMenuItemFieldsFragment,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const doesCommandMenuItemMatchSelectionState =
|
||||
(hasSelectedRecords: boolean) => (item: CommandMenuItemFieldsFragment) =>
|
||||
item.availabilityType !==
|
||||
CommandMenuItemAvailabilityType.RECORD_SELECTION || hasSelectedRecords;
|
||||
Reference in New Issue
Block a user