From bd9f7b9ba440f7fda5ff69944ec2349aa6aee38f Mon Sep 17 00:00:00 2001 From: Mike Potapenco <44904160+buhaytza2005@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:19:26 +0000 Subject: [PATCH] fix: Add exclusion for disabled choices in checklist select and deselect all (#2428) #2427 --- py/examples/checklist.py | 8 +++++++- ui/src/checklist.test.tsx | 42 ++++++++++++++++++++++++++++++++++++++- ui/src/checklist.tsx | 18 +++++++++++++---- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/py/examples/checklist.py b/py/examples/checklist.py index f17822594c..63b2aebf4b 100644 --- a/py/examples/checklist.py +++ b/py/examples/checklist.py @@ -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() diff --git a/ui/src/checklist.test.tsx b/ui/src/checklist.test.tsx index b957644ade..7c8e68d2dc 100644 --- a/ui/src/checklist.test.tsx +++ b/ui/src/checklist.test.tsx @@ -147,4 +147,44 @@ describe('Checklist.tsx', () => { expect(pushMock).toHaveBeenCalled() }) -}) \ No newline at end of file + + 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() + + 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() + + 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() + + fireEvent.click(getByText('Deselect All')) + + expect(wave.args[name]).toMatchObject(['Choice1']) + }) + +}) diff --git a/ui/src/checklist.tsx b/ui/src/checklist.tsx index fd59f3b3d7..8f9db10608 100644 --- a/ui/src/checklist.tsx +++ b/ui/src/checklist.tsx @@ -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), @@ -126,4 +135,5 @@ export const
{items}
) - } \ No newline at end of file + } +