h2oai / wave

Realtime Web Apps and Dashboards for Python and R
https://wave.h2o.ai
Apache License 2.0
3.9k stars 327 forks source link

Same value can be picked multiple times in ui.picker #1985

Closed kajanan1212 closed 8 months ago

kajanan1212 commented 1 year ago

Wave SDK Version, OS

Wave SDK: 0.24.2 , OS: MacOs

Actual behavior

https://github.com/h2oai/wave/assets/89178049/6b887789-3500-4d6e-8e3d-16512b97cae9

When using a ui.picker, we can select a choice more than one time. Here, after the selection of a value, the suggestions list doesn't show the selected value when typing that selected value within the box. That is fine. But the selected value still visible and selectable in the suggestions list when clicking on the box.

Expected behavior

When using a ui.picker, we won't be able to select a choice more than one time. After the selection of a value, when clicking on the box,

  1. The selected value should be visible but shouldn't be selectable in the suggestions list. (Disable the selection.)
  2. Or The selected value should be removed from the suggestions list. (If the name of an ui.choice exists in the values list then that choice shouldn't be shown in the suggestions list.)

So far, It works well when typing the selected value within the box.

Steps To Reproduce

from h2o_wave import main, app, Q, ui

@app('/')
async def serve(q: Q):
    q.page['example'] = ui.form_card(
        box='1 1 4 5',
        items=[
            ui.picker(
                name='picker',
                label='Tags:',
                choices=[
                    ui.choice(name='spam', label='Spam'),
                    ui.choice(name='eggs', label='Eggs'),
                    ui.choice(name='ham', label='Ham'),
                    ui.choice(name='cheese', label='Cheese'),
                    ui.choice(name='beans', label='Beans'),
                    ui.choice(name='toast', label='Toast'),
                ],
                values=['eggs'],
            ),
        ]
    )
    await q.page.save()
kajanan1212 commented 1 year ago

When I investigated more on ui.picker, I found another thing. I tried to update the values of the ui.picker by using the trigger of that component. On that time, It works fine at the normal case. It doesn't show the selected values multiple time within the box when a user selects the already selected values from the suggestions list.

But if we tries the same thing in a side panel then it doesn't work like the normal case.

  1. It shows the selected values multiple time within the box when a user selects the already selected values from the suggestions list. [See the later part of the 1st video which has been provided below.]

  2. If we select a different value between a same value (eg: XYX) and try to unpick the 1st occurrence of that same value in the raw then it behaves weirdly. [See the 2nd video which has been provided below.]

Anyway, showing the already selected values in the suggestions list is an unnecessary thing in both the cases.

https://github.com/h2oai/wave/assets/89178049/1e5c3d73-180f-4378-8f51-4d4097b55d74

https://github.com/h2oai/wave/assets/89178049/7c9ccdf6-e3fa-4464-bb8e-520fce8d89a5

Steps To Reproduce

from h2o_wave import main, app, Q, ui

choices=[
    ui.choice(name='spam', label='Spam'),
    ui.choice(name='eggs', label='Eggs'),
    ui.choice(name='ham', label='Ham'),
    ui.choice(name='cheese', label='Cheese'),
    ui.choice(name='beans', label='Beans'),
    ui.choice(name='toast', label='Toast'),
]

@app('/')
async def serve(q: Q):
    main_values = q.args.main_picker if q.args.main_picker else []
    side_panel_values = q.args.side_panel_picker if q.args.side_panel_picker else []

    q.page['card_1'] = ui.form_card(
        box='1 1 4 3',
        items=[
            ui.picker(
                name='main_picker',
                label='Tags:',
                choices=choices,
                values=main_values,
                trigger=True,
            ),
        ]
    )
    q.page['card_2'] = ui.form_card(
        box='5 1 4 3',
        items=[
            ui.button(
                name='show_side_panel',
                label='Open side panel',
                primary=True,
            ),
        ]
    )

    if not q.client.initialized:
        q.page['meta'] = ui.meta_card(box='')
        q.client.initialized = True
    else:
        if q.args.show_side_panel:
            q.page['meta'].side_panel = ui.side_panel(
                title='Side Panel',
                blocking=True,
                items=[
                    ui.picker(
                        name='side_panel_picker',
                        label='Tags:',
                        choices=choices,
                        values=side_panel_values,
                        trigger=True,
                    ),
                    ui.button(
                        name='close_side_panel',
                        label='Close',
                        primary=True,
                    ),
                ]
            )
        elif q.args.close_side_panel:
            q.page['meta'].side_panel = None

    await q.page.save()
kajanan1212 commented 1 year ago

In the above video, you can see that the first input field of the side panel is already active when the side panel is opened. I noticed it with other input fields also when they are in the first position. Is it a bug or a feature of the side panel?

kajanan1212 commented 1 year ago

I tried below code to solve the issue Same value can be picked multiple times in ui.picker. But it didn't work since the already selected choices with the name and label were removed from the choices list of the ui.picker. Here, we can remove the already selected values from the suggestions list. But we cannot see them within the box of the ui.picker, as the selected values.

from h2o_wave import main, app, Q, ui

choices=[
    ui.choice(name='spam', label='Spam'),
    ui.choice(name='eggs', label='Eggs'),
    ui.choice(name='ham', label='Ham'),
    ui.choice(name='cheese', label='Cheese'),
    ui.choice(name='beans', label='Beans'),
    ui.choice(name='toast', label='Toast'),
]

@app('/')
async def serve(q: Q):
    main_values = q.args.main_picker if q.args.main_picker else []

    q.page['card_1'] = ui.form_card(
        box='1 1 4 3',
        items=[
            ui.picker(
                name='main_picker',
                label='Tags:',
                choices=[c for c in choices if c.name not in main_values],
                values=main_values,
                trigger=True,
            ),
        ]
    )

    await q.page.save()

https://github.com/h2oai/wave/assets/89178049/3a2f3c23-0421-4f74-a9ff-59067c46f9fb



But the similar idea works almost fine in the side panel. I have provided the code below. But I have one issue here also. In the below shown case, the initial value of the ui.picker's values is empty list. If the ui.picker's values is not an empty list at the initial stage then the below idea doesn't work. I'll show that in the next comment.

from h2o_wave import main, app, Q, ui

choices=[
    ui.choice(name='spam', label='Spam'),
    ui.choice(name='eggs', label='Eggs'),
    ui.choice(name='ham', label='Ham'),
    ui.choice(name='cheese', label='Cheese'),
    ui.choice(name='beans', label='Beans'),
    ui.choice(name='toast', label='Toast'),
]

@app('/')
async def serve(q: Q):
    side_panel_values = q.args.side_panel_picker if q.args.side_panel_picker else []

    q.page['card_2'] = ui.form_card(
        box='1 1 4 3',
        items=[
            ui.button(
                name='show_side_panel',
                label='Open side panel',
                primary=True,
            ),
        ]
    )

    if not q.client.initialized:
        q.page['meta'] = ui.meta_card(box='')
        q.client.initialized = True
    else:
        if q.args.show_side_panel or q.args.side_panel_picker:
            q.page['meta'].side_panel = ui.side_panel(
                title='Side Panel',
                blocking=True,
                items=[
                    ui.picker(
                        name='side_panel_picker',
                        label='Tags:',
                        choices=[c for c in choices if c.name not in side_panel_values],
                        values=side_panel_values,
                        trigger=True,
                    ),
                    ui.button(
                        name='close_side_panel',
                        label='Close',
                        primary=True,
                    ),
                ]
            )
        elif q.args.close_side_panel:
            q.page['meta'].side_panel = None

    await q.page.save()

https://github.com/h2oai/wave/assets/89178049/fecde270-a3b0-42d0-8dc3-793bd451a871

kajanan1212 commented 1 year ago
from h2o_wave import main, app, Q, ui

choices=[
    ui.choice(name='spam', label='Spam'),
    ui.choice(name='eggs', label='Eggs'),
    ui.choice(name='ham', label='Ham'),
    ui.choice(name='cheese', label='Cheese'),
    ui.choice(name='beans', label='Beans'),
    ui.choice(name='toast', label='Toast'),
]

@app('/')
async def serve(q: Q):
    side_panel_values = q.args.side_panel_picker if q.args.side_panel_picker else ["eggs"]

    q.page['card_2'] = ui.form_card(
        box='1 1 4 3',
        items=[
            ui.button(
                name='show_side_panel',
                label='Open side panel',
                primary=True,
            ),
        ]
    )

    if not q.client.initialized:
        q.page['meta'] = ui.meta_card(box='')
        q.client.initialized = True
    else:
        if q.args.show_side_panel or q.args.side_panel_picker:
            q.page['meta'].side_panel = ui.side_panel(
                title='Side Panel',
                blocking=True,
                items=[
                    ui.picker(
                        name='side_panel_picker',
                        label='Tags:',
                        choices=[c for c in choices if c.name not in side_panel_values],
                        values=side_panel_values,
                        trigger=True,
                    ),
                    ui.button(
                        name='close_side_panel',
                        label='Close',
                        primary=True,
                    ),
                ]
            )
        elif q.args.close_side_panel:
            q.page['meta'].side_panel = None

    await q.page.save()

https://github.com/h2oai/wave/assets/89178049/efe5e12c-0db1-4599-85ef-0dbc96f3f81c