Skip to content

Commit 4430afa

Browse files
jenstanicakclaude
andcommitted
Ensure 'Other' group always appears last with groupOrder
Implement alternative approach where items without groups ('Other') always appear at the very end, regardless of groupOrder specification. This provides better UX as users expect the fallback 'Other' category to be last. Changes: - Update SelectInput sorting logic to use MAX_SAFE_INTEGER + 1 for ungrouped items - Add comprehensive test demonstrating the new behavior - Update existing test snapshots to reflect the improved ordering 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent b77f139 commit 4430afa

File tree

3 files changed

+59
-25
lines changed

3 files changed

+59
-25
lines changed

.changeset/reorder-extension-templates-grouping.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/cli-kit/src/private/node/ui/components/SelectInput.test.tsx

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,42 @@ describe('SelectInput', async () => {
267267
expect(onChange).not.toHaveBeenCalled()
268268
})
269269

270+
test.skipIf(runningOnWindows)('ensures "Other" group always appears last with groupOrder', async () => {
271+
const onChange = vi.fn()
272+
273+
const items = [
274+
{label: 'item1', value: '1', group: 'GroupA'},
275+
{label: 'item2', value: '2', group: 'GroupC'},
276+
{label: 'item3', value: '3'}, // no group - should be "Other"
277+
{label: 'item4', value: '4', group: 'GroupX'}, // not in groupOrder
278+
{label: 'item5', value: '5'}, // no group - should be "Other"
279+
]
280+
281+
// GroupOrder specifies: GroupC first, then GroupA
282+
// GroupX is not specified, so should come before "Other" but after specified groups
283+
const groupOrder = ['GroupC', 'GroupA']
284+
285+
const renderInstance = render(<SelectInput items={items} onChange={onChange} groupOrder={groupOrder} />)
286+
287+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
288+
" GroupC
289+
> item2
290+
291+
GroupA
292+
item1
293+
294+
GroupX
295+
item4
296+
297+
Other
298+
item3
299+
item5
300+
301+
Press ↑↓ arrows to select, enter to confirm."
302+
`)
303+
expect(onChange).not.toHaveBeenCalled()
304+
})
305+
270306
test('allows disabling shortcuts', async () => {
271307
const onChange = vi.fn()
272308
const items = [
@@ -383,16 +419,16 @@ describe('SelectInput', async () => {
383419
const renderInstance = render(<SelectInput items={items} onChange={() => {}} availableLines={10} />)
384420

385421
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
386-
" Other  
387-
> first  
388-
second  
389-
third  
390-
fourth  
391-
 
392-
Automations  
393-
fifth  
394-
sixth  
422+
" Automations  
423+
> fifth  
424+
sixth  
425+
 
426+
Merchant Admin  
427+
eighth  
428+
ninth  
395429
 
430+
Other  
431+
first  
396432
397433
Press ↑↓ arrows to select, enter to confirm."
398434
`)
@@ -405,16 +441,16 @@ describe('SelectInput', async () => {
405441
await sendInputAndWaitForChange(renderInstance, ARROW_DOWN)
406442

407443
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
408-
" Other  
409-
second  
410-
third  
411-
fourth  
444+
" Automations  
445+
sixth  
412446
 
413-
[1mAutomations[22m [46m [49m
414-
fifth [100m [49m
415-
[36m>[39m [36msixth[39m [100m [49m
447+
[1mMerchant Admin[22m [46m [49m
448+
eighth [46m [49m
449+
ninth [46m [49m
416450
 
417451
Other  
452+
first  
453+
> second  
418454
419455
Press ↑↓ arrows to select, enter to confirm."
420456
`)

packages/cli-kit/src/private/node/ui/components/SelectInput.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,13 @@ function SelectInputInner<T>(
164164

165165
const hasAnyGroup = rawItems.some((item) => typeof item.group !== 'undefined')
166166
const items = sortBy(rawItems, (item) => {
167-
if (!groupOrder || !item.group) return Number.MAX_SAFE_INTEGER
167+
// Items without groups ("Other") always go last
168+
if (!item.group) return Number.MAX_SAFE_INTEGER + 1
169+
170+
// If no groupOrder specified, use default behavior
171+
if (!groupOrder) return Number.MAX_SAFE_INTEGER
172+
173+
// Items with groups get their position from groupOrder, or MAX_SAFE_INTEGER if not specified
168174
const index = groupOrder.indexOf(item.group)
169175
return index === -1 ? Number.MAX_SAFE_INTEGER : index
170176
})

0 commit comments

Comments
 (0)