Skip to content

Commit

Permalink
fix: Add exclusion for disabled choices in checklist select and desel…
Browse files Browse the repository at this point in the history
…ect all (#2428) #2427
  • Loading branch information
buhaytza2005 authored Oct 30, 2024
1 parent fe7f7bd commit bd9f7b9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
8 changes: 7 additions & 1 deletion py/examples/checklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ async def serve(q: Q):
else:
q.page['example'] = ui.form_card(box='1 1 4 7', items=[
ui.checklist(name='checklist', label='Choices',
choices=[ui.choice(name=x, label=x) for x in ['Egg', 'Bacon', 'Spam']]),
choices=[ui.choice(name=x, label=x) for x in ['Egg', 'Bacon', 'Spam']] + [
ui.choice(name="cannot select", label="cannot select", disabled=True),
ui.choice(name="cannot remove", label="cannot remove", disabled=True)
],
values=["cannot remove"]
)
,
ui.button(name='show_inputs', label='Submit', primary=True),
])
await q.page.save()
42 changes: 41 additions & 1 deletion ui/src/checklist.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,44 @@ describe('Checklist.tsx', () => {

expect(pushMock).toHaveBeenCalled()
})
})

it('Keeps selected and disabled choices after select all', () => {
const disabledChoices = [
{ name: 'Choice1', disabled: true },
{ name: 'Choice2', disabled: false },
{ name: 'Choice3', disabled: true },
]
const { getByText } = render(<XChecklist model={{ ...checklistProps, choices: disabledChoices, values: ['Choice1'] }} />)

fireEvent.click(getByText('Select All'))

expect(wave.args[name]).toMatchObject(['Choice1', 'Choice2'])
})

it('Selects only enabled choices when some are disabled', () => {
const choices = [
{ name: 'Choice1', disabled: true },
{ name: 'Choice2', disabled: false },
{ name: 'Choice3', disabled: false },
]
const { getByText } = render(<XChecklist model={{ ...checklistProps, choices }} />)

fireEvent.click(getByText('Select All'))

expect(wave.args[name]).toMatchObject(['Choice2', 'Choice3'])
})

it('Retains unselected and disabled items after deselect all', () => {
const disabledChoices = [
{ name: 'Choice1', disabled: true },
{ name: 'Choice2', disabled: false },
{ name: 'Choice3', disabled: true },
]
const { getByText } = render(<XChecklist model={{ ...checklistProps, choices: disabledChoices, values: ['Choice1'] }} />)

fireEvent.click(getByText('Deselect All'))

expect(wave.args[name]).toMatchObject(['Choice1'])
})

})
18 changes: 14 additions & 4 deletions ui/src/checklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,20 @@ export const
wave.args[m.name] = choices.filter(({ selected }) => selected).map(({ c }) => c.name)
if (m.trigger) wave.push()
},
select = (value: B) => {
const _choices = choices.map(({ c, selected }) => ({ c, selected: c.disabled ? selected : value }))
select = (selectAll: B) => {
const _choices = choices.map(({ c, selected }) => ({ c, selected: c.disabled ? selected : selectAll }))
setChoices(_choices)
capture(_choices)
m.values = value ? _choices.map(({ c }) => c.name) : []

if (selectAll) {
m.values = _choices
.filter(({ c, selected }) => !c.disabled || selected) // Exclude disabled
.map(({ c }) => c.name)
} else {
m.values = _choices
.filter(({ c, selected }) => c.disabled && selected) // Retain selected disabled
.map(({ c }) => c.name)
}
},
selectAll = () => select(true),
deselectAll = () => select(false),
Expand Down Expand Up @@ -126,4 +135,5 @@ export const
<div className={clas(css.items, m.inline ? css.inline : '')}>{items}</div>
</div>
)
}
}

0 comments on commit bd9f7b9

Please sign in to comment.