im-perativa / streamlit-calendar

A Streamlit component to show calendar view using FullCalendar
https://calendar-component.streamlit.app/
Apache License 2.0
119 stars 12 forks source link

Thanks & resource-timeline #2

Closed CHerSun closed 1 year ago

CHerSun commented 1 year ago

I just wanted to tell you - thank you. I was looking for a calendar component for streamlit for ages (can't make one myself unfortunately).

Especially love the resource-timeline view. Could you maybe add a few events to the demo app for resource-timeline view?

CHerSun commented 1 year ago

Ok, found this out. Your demo has a side-effect bug. Any click on calendar gives: image

Note, eventsSet: NULL.

Code in demo:

if "eventsSet" in state:
    st.session_state["events"] = state["eventsSet"]

it doesn't check for None value and just saves to session_state. After that changing to any other view gives empty calendar. Can either remove that (at least I found no reason to keep that, see below). Or should be something like:

if (events_set := state.get("eventsSet", None)):
    st.session_state["events"] = events_set
CHerSun commented 1 year ago

hmm, was trying to play with it to add creation of new event on click. Found 2 problems:

But still, it works, I was able to create new events by clicking in resource-timeline, that's really awesome.

Btw, badly need callbacks to make returned events single-time things (if I don't force redraw by using new key - event returned on streamlit rerun is the same, forcing streamlit into endless loop of the same actions).

Just in case, the code I used to create new event on click:

# change: init events once
if "events" not in st.session_state:
    st.session_state["events"] = get_events()

# change: add counter to key
state = calendar(
    events=st.session_state["events"],
    options=calendar_options,
    key=mode+str(st.session_state.setdefault("calendar_version", 0)),
)

# added: parsing of dateClick event and increase counter to force redraw - effectively making event a single-time thing in streamlit
from random import randint
from datetime import datetime, timedelta
if (date_click := state.get("dateClick", None)):
    if (resource_clicked := date_click.get("resource", None)):
        date_start = datetime.fromisoformat(date_click["date"])
        date_end = date_start + timedelta(days=1)
        new_event_color = '#%02X%02X%02X' % (randint(0,255),randint(0,255),randint(0,255))
        new_event = {
                "title": f'Event {len(st.session_state["events"])+1}',
                "color": new_event_color,
                "start": date_start.isoformat(),
                "end": date_end.isoformat(),
                "resourceId": resource_clicked["id"],
            }
        st.session_state["events"].append(new_event)
        st.session_state["calendar_version"] += 1
        st.experimental_rerun()
im-perativa commented 1 year ago

I just wanted to tell you - thank you. I was looking for a calendar component for streamlit for ages (can't make one myself unfortunately).

Especially love the resource-timeline view. Could you maybe add a few events to the demo app for resource-timeline view?

Hi, thanks for your input. Regarding the bug in resource based view, I just realized the javascript package itself doesn't include the resource id back in events object https://github.com/fullcalendar/fullcalendar/issues/6191. The updated version should fix that.

im-perativa commented 1 year ago

:tada: This issue has been resolved in version 0.5.0 :tada:

The release is available on PyPI and GitHub.

CHerSun commented 1 year ago

@im-perativa cool. Thank you for update, resource ids are nice thing to have. Could you advise on other things? How to add data to existing component without having a full redraw via a new streamlit key? I've read about calendar sources in FullCalendar. It looks like I will be able to make it self-updating if I give it a JSON source via another service (REST API), but don't have that ready at the moment, so if there's a way to update via streamlit directly - that'd be cool.