Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streamlit-sortables bugs out when adding new items to it during runtime. #4

Open
hamishcraze opened this issue Oct 24, 2022 · 1 comment

Comments

@hamishcraze
Copy link

hamishcraze commented Oct 24, 2022

Summary
I am attempting to use streamlit-sortables to create text processing pipelines (a set of interoperable functions). What we do is allow the user to create an operation. This operation is added to the pipeline. However, perhaps a user wishes to change the order that operations run, streamlit-sortables works well for this.

However we are running into when we try to add new items to these lists (via some button press).

Reproducible Code Example

import streamlit as st
from streamlit_sortables import sort_items

if not "pipeline_left" in st.session_state:
    st.session_state.pipeline_left = ['item1', 'item2', 'item3']

if not "pipeline_right" in st.session_state:
    st.session_state.pipeline_right = ['item4', 'item5', 'item6']

button = st.button("ADD", key="BUTTON")

if button:
    st.session_state.pipeline_left.append("ADDED")

items = [
    {'header': 'Pipeline', 'items': st.session_state.pipeline_left},
    {'header': 'Disabled', 'items': st.session_state.pipeline_right},
]

sorted_items = sort_items(items, multi_containers=True, direction='vertical')

Steps To Reproduce
I.E Streamlit starts up. You initialize the streamlit sortable via the following:

items = [
{'header': 'Pipeline', 'items': ["item1","item2,","item3"]},
{'header': 'Disabled', 'items': ["item4","item5,","item6"]},
]

All is well. Items can be moved between lists and reordered as per usual. But we wish for the end-user to be able to assemble a pipeline themselves. Meaning they need to be able to add new elements to the lists.

We thought we'd implement that using session state:

if not "pipeline_left" in st.session_state:
    st.session_state.pipeline_left = ['item1', 'item2', 'item3']

if not "pipeline_right" in st.session_state:
    st.session_state.pipeline_right = ['item4', 'item5', 'item6']

button = st.button("ADD", key="BUTTON")

if button:
    st.session_state.pipeline_left.append("ADDED")

items = [
    {'header': 'Pipeline', 'items': st.session_state.pipeline_left},
    {'header': 'Disabled', 'items': st.session_state.pipeline_right},
]

sorted_items = sort_items(items, multi_containers=True, direction='vertical')

As you can see, when a button element is clicked, the item "ADDED" is added to the pipeline_left list which is stored in session_state. This means that on reload, the sorted_items element should be populated with the new items. This proceeds as expected.

The issue occurs when you then try to reorder the sortable list via the frontend. Something is going wrong that is preventing the sortable list for updating correctly and it becomes unresponsive (i) forgets the added element entirely (ii) if you drag ADD from pipeline_left to pipeline_right, when a new element is added, all previously added items appear in pipeline_left. Ignoring all previous state changes.

Expected Behavior
We expect to be able to add new elements to the sortable_items list during runtime without completely breaking it's functionality

Current Behavior
becomes unresponsive (i)
forgets the added element entirely (ii)
if you drag "ADDED" from pipeline_left to pipeline_right, when a new element is added (via a second button press), all previously added items appear in pipeline_left. Ignoring all previous state changes.

Something in streamlit_sortables is not talking to the streamlit backend correctly.

@ohtaman
Copy link
Owner

ohtaman commented Jan 28, 2023

If key is not specified, st_sortables will look at the contents of items to determine the uniqueness of the component, as same as official widgets. In this case, each time a new item is added, a new st_sortables object is created and it behaves as if it were forgotten.

We should sync session_state with st_sortables' internal state something like code below. Might be a little tricky.

import streamlit as st
from streamlit_sortables import sort_items

if not 'pipeline' in st.session_state:
    st.session_state.pipeline = {
        'left': ['item1', 'item2', 'item3'],
        'right': ['item4', 'item5', 'item6']
    }

pipeline = st.session_state.pipeline
items = [
    {'header': 'Pipeline', 'items': pipeline['left']},
    {'header': 'Disabled', 'items': pipeline['right']},
]

sorted_items = sort_items(items, multi_containers=True, direction='vertical')


if st.button('Add', key='BUTTON'):
    n_items = len(pipeline['left']) + len(pipeline['right'])
    # the item value must be unique.
    new_item = f'item{n_items + 1}'
    # session_state must be sorted
    st.session_state.pipeline = {
        'left': sorted_items[0]['items'] + [new_item],
        'right': sorted_items[1]['items']
    }
    # should rerun to reflect the change of session_state
    st.experimental_rerun()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants