@@ -37,6 +37,18 @@ import type { DisplayColumn } from '../types' |
37 | 37 | * surfaces stay in sync. */ |
38 | 38 | const LIMITED_RUN_PRESETS = [10, 1000] as const |
39 | 39 |
|
| 40 | +/** Labels for the table-scoped run items. With an active filter the run is |
| 41 | + * scoped to matching rows, so the labels say "filtered rows" to make the |
| 42 | + * narrowed target visible. Shared by both menu surfaces. */ |
| 43 | +function runMenuLabels(hasActiveFilter: boolean) { |
| 44 | + const rows = hasActiveFilter ? 'filtered rows' : 'rows' |
| 45 | + return { |
| 46 | + all: `Run all ${rows}`, |
| 47 | + incomplete: `Run empty ${rows}`, |
| 48 | + limited: (max: number) => `Run ${max.toLocaleString()} empty ${rows}`, |
| 49 | + } |
| 50 | +} |
| 51 | + |
40 | 52 | interface ColumnOptionsMenuProps { |
41 | 53 | open: boolean |
42 | 54 | onOpenChange: (open: boolean) => void |
@@ -65,6 +77,9 @@ interface ColumnOptionsMenuProps { |
65 | 77 | /** When set, surfaces a "Run N selected rows" item above Run all. */ |
66 | 78 | onRunColumnSelected?: () => void |
67 | 79 | selectedRowCount?: number |
| 80 | + /** Table-scoped run items honor the active filter; when true the labels say |
| 81 | + * "filtered rows" so the narrowed scope is visible. */ |
| 82 | + hasActiveFilter?: boolean |
68 | 83 | /** When set, the menu surfaces a "View workflow" item that opens a popup |
69 | 84 | * preview of the configured workflow. */ |
70 | 85 | onViewWorkflow?: () => void |
@@ -97,12 +112,14 @@ export function ColumnOptionsMenu({ |
97 | 112 | onRunColumnLimited, |
98 | 113 | onRunColumnSelected, |
99 | 114 | selectedRowCount = 0, |
| 115 | + hasActiveFilter = false, |
100 | 116 | onViewWorkflow, |
101 | 117 | isPinned, |
102 | 118 | onPinToggle, |
103 | 119 | }: ColumnOptionsMenuProps) { |
104 | 120 | const showRunActions = Boolean(onRunColumnAll && onRunColumnIncomplete) |
105 | 121 | const showRunSelected = Boolean(onRunColumnSelected) && selectedRowCount > 0 |
| 122 | + const runLabels = runMenuLabels(hasActiveFilter) |
106 | 123 | return ( |
107 | 124 | <DropdownMenu open={open} onOpenChange={onOpenChange}> |
108 | 125 | <DropdownMenuTrigger asChild> |
@@ -140,15 +157,15 @@ export function ColumnOptionsMenu({ |
140 | 157 | </DropdownMenuItem> |
141 | 158 | )} |
142 | 159 | <DropdownMenuItem onSelect={() => onRunColumnAll?.()}> |
143 | | - Run all rows |
| 160 | + {runLabels.all} |
144 | 161 | </DropdownMenuItem> |
145 | 162 | <DropdownMenuItem onSelect={() => onRunColumnIncomplete?.()}> |
146 | | - Run empty rows |
| 163 | + {runLabels.incomplete} |
147 | 164 | </DropdownMenuItem> |
148 | 165 | {onRunColumnLimited && |
149 | 166 | LIMITED_RUN_PRESETS.map((max) => ( |
150 | 167 | <DropdownMenuItem key={max} onSelect={() => onRunColumnLimited(max)}> |
151 | | - {`Run ${max.toLocaleString()} empty rows`} |
| 168 | + {runLabels.limited(max)} |
152 | 169 | </DropdownMenuItem> |
153 | 170 | ))} |
154 | 171 | </DropdownMenuSubContent> |
@@ -221,6 +238,9 @@ interface WorkflowGroupMetaCellProps { |
221 | 238 | /** Row ids in the user's current multi-row selection; when non-empty the |
222 | 239 | * run menu adds a "Run N selected rows" option. */ |
223 | 240 | selectedRowIds?: string[] | null |
| 241 | + /** True when the grid has an active filter — table-scoped run items apply |
| 242 | + * only to matching rows and are labeled "filtered rows". */ |
| 243 | + hasActiveFilter?: boolean |
224 | 244 | /** Opens a popup preview of the underlying workflow. */ |
225 | 245 | onViewWorkflow?: (workflowId: string) => void |
226 | 246 | /** When set, the meta cell becomes draggable and forwards events through |
@@ -267,6 +287,7 @@ export function WorkflowGroupMetaCell({ |
267 | 287 | onDeleteColumn, |
268 | 288 | onDeleteGroup, |
269 | 289 | selectedRowIds, |
| 290 | + hasActiveFilter = false, |
270 | 291 | onViewWorkflow, |
271 | 292 | onDragStart, |
272 | 293 | onDragOver, |
@@ -292,6 +313,7 @@ export function WorkflowGroupMetaCell({ |
292 | 313 | const didDragRef = useRef(false) |
293 | 314 |
|
294 | 315 | const selectedCount = selectedRowIds?.length ?? 0 |
| 316 | + const runLabels = runMenuLabels(hasActiveFilter) |
295 | 317 |
|
296 | 318 | function handleRunAll() { |
297 | 319 | if (groupId) onRunColumn?.(groupId, 'all') |
@@ -443,11 +465,13 @@ export function WorkflowGroupMetaCell({ |
443 | 465 | {`Run ${selectedCount} selected ${selectedCount === 1 ? 'row' : 'rows'}`} |
444 | 466 | </DropdownMenuItem> |
445 | 467 | )} |
446 | | - <DropdownMenuItem onSelect={handleRunAll}>Run all rows</DropdownMenuItem> |
447 | | - <DropdownMenuItem onSelect={handleRunIncomplete}>Run empty rows</DropdownMenuItem> |
| 468 | + <DropdownMenuItem onSelect={handleRunAll}>{runLabels.all}</DropdownMenuItem> |
| 469 | + <DropdownMenuItem onSelect={handleRunIncomplete}> |
| 470 | + {runLabels.incomplete} |
| 471 | + </DropdownMenuItem> |
448 | 472 | {LIMITED_RUN_PRESETS.map((max) => ( |
449 | 473 | <DropdownMenuItem key={max} onSelect={() => handleRunLimited(max)}> |
450 | | - {`Run ${max.toLocaleString()} empty rows`} |
| 474 | + {runLabels.limited(max)} |
451 | 475 | </DropdownMenuItem> |
452 | 476 | ))} |
453 | 477 | </DropdownMenuContent> |
@@ -470,6 +494,7 @@ export function WorkflowGroupMetaCell({ |
470 | 494 | onRunColumnLimited={onRunColumn ? handleRunLimited : undefined} |
471 | 495 | onRunColumnSelected={onRunColumn && selectedCount > 0 ? handleRunSelected : undefined} |
472 | 496 | selectedRowCount={selectedCount} |
| 497 | + hasActiveFilter={hasActiveFilter} |
473 | 498 | onViewWorkflow={onViewWorkflow ? () => onViewWorkflow(workflowId) : undefined} |
474 | 499 | isPinned={isPinned} |
475 | 500 | onPinToggle={onPinToggle} |
|