Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 8928aafbc0 fix(command-menu-item): show workflow actions in exclusion mode (select all)
https://sonarly.com/issue/19854?type=bug

Custom workflow action buttons disappear from the record index toolbar when using "Select All" because the legacy command menu provider only considers `selection` mode (individual picks) and explicitly skips workflow command loading when the context store is in `exclusion` mode (select all).

Fix: Two changes fix the bug where custom workflow action buttons disappear when using "Select All":

**1. `CommandMenuContextProviderDefault.tsx`** — The `isRecordSelection` guard now treats `exclusion` mode (Select All) as having a record selection, so workflow commands are no longer skipped:
```typescript
// Before: only 'selection' mode was considered
const isRecordSelection =
    contextStoreTargetedRecordsRule.mode === 'selection' &&
    contextStoreTargetedRecordsRule.selectedRecordIds.length > 0;

// After: exclusion mode (Select All) also counts as having a selection
const isRecordSelection =
    contextStoreTargetedRecordsRule.mode === 'exclusion' ||
    (contextStoreTargetedRecordsRule.mode === 'selection' &&
      contextStoreTargetedRecordsRule.selectedRecordIds.length > 0);
```

**2. `useRunWorkflowRecordCommands.tsx`** — Previously, `selectedRecordIds` was set to `undefined` in exclusion mode, making the onClick handler a no-op. Now a `getSelectedRecordIds()` callback lazily resolves record IDs: in `selection` mode it returns the explicit IDs; in `exclusion` mode it reads all loaded record IDs from the record index and filters out excluded ones, using the same `recordIndexAllRecordIdsComponentSelector` that `useSelectAllRows` uses.
2026-03-31 05:56:49 +00:00
2 changed files with 31 additions and 8 deletions
@@ -36,8 +36,9 @@ export const CommandMenuContextProviderDefault = ({
);
const isRecordSelection =
contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length > 0;
contextStoreTargetedRecordsRule.mode === 'exclusion' ||
(contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length > 0);
const runWorkflowRecordCommands = useRunWorkflowRecordCommands({
objectMetadataItem,
@@ -5,9 +5,12 @@ import { CommandMenuItemType } from '@/command-menu-item/types/CommandMenuItemTy
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomComponentSelectorCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorCallbackState';
import { useActiveWorkflowVersionsWithManualTrigger } from '@/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger';
import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion';
@@ -39,10 +42,27 @@ export const useRunWorkflowRecordCommands = ({
contextStoreIsPageInEditModeComponentState,
);
const selectedRecordIds =
contextStoreTargetedRecordsRule.mode === 'selection'
? contextStoreTargetedRecordsRule.selectedRecordIds
: undefined;
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
const recordIndexAllRecordIds = useAtomComponentSelectorCallbackState(
recordIndexAllRecordIdsComponentSelector,
recordIndexId,
);
const getSelectedRecordIds = useCallback(() => {
if (contextStoreTargetedRecordsRule.mode === 'selection') {
return contextStoreTargetedRecordsRule.selectedRecordIds;
}
const allRecordIds = store.get(recordIndexAllRecordIds);
const excludedRecordIds = new Set(
contextStoreTargetedRecordsRule.excludedRecordIds,
);
return allRecordIds.filter(
(recordId) => !excludedRecordIds.has(recordId),
);
}, [contextStoreTargetedRecordsRule, recordIndexAllRecordIds, store]);
const { records: activeWorkflowVersions } =
useActiveWorkflowVersionsWithManualTrigger({
@@ -144,12 +164,14 @@ export const useRunWorkflowRecordCommands = ({
component: (
<Command
onClick={async () => {
if (!isDefined(selectedRecordIds)) {
const resolvedRecordIds = getSelectedRecordIds();
if (resolvedRecordIds.length === 0) {
return;
}
await runWorkflowVersionOnSelectedRecords(
selectedRecordIds,
resolvedRecordIds,
activeWorkflowVersion,
);
}}