From 375b7dc56b8353c41760a72c76097aeefc329959 Mon Sep 17 00:00:00 2001 From: LUIS NOVO Date: Thu, 24 Oct 2024 17:19:22 -0300 Subject: [PATCH] archive notebooks, delete source artifacts and confirm before delete sources --- database/0_0_1_to_0_0_2.surrealql | 7 +++-- database/db_setup.surrealql | 7 +++++ open_notebook/domain.py | 1 + pages/2_📒_Notebooks.py | 49 +++++++++++++++++++++++-------- stream_app/source.py | 15 ++++++++-- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/database/0_0_1_to_0_0_2.surrealql b/database/0_0_1_to_0_0_2.surrealql index a4a94a0..d84d1a5 100644 --- a/database/0_0_1_to_0_0_2.surrealql +++ b/database/0_0_1_to_0_0_2.surrealql @@ -2,7 +2,7 @@ REMOVE TABLE IF EXISTS source_chunk; REMOVE INDEX IF EXISTS idx_source_full ON TABLE source_chunk; - +DEFINE FIELD IF NOT EXISTS archived ON TABLE notebook TYPE option DEFAULT False; DEFINE INDEX idx_source_full ON TABLE source_chunk COLUMNS content SEARCH ANALYZER my_analyzer BM25 HIGHLIGHTS; REMOVE FUNCTION IF EXISTS fn::text_search; @@ -71,7 +71,10 @@ DEFINE FUNCTION IF NOT EXISTS fn::text_search($query_text: string, $match_count: }; - +DEFINE EVENT IF NOT EXISTS source_delete ON TABLE source WHEN ($after == NONE) THEN { + delete source_embedding where source == $before.id; + delete source_insight where source == $before.id; +}; UPDATE open_notebook:database_info SET version= "0.0.2"; diff --git a/database/db_setup.surrealql b/database/db_setup.surrealql index ec00561..32e9492 100644 --- a/database/db_setup.surrealql +++ b/database/db_setup.surrealql @@ -41,6 +41,11 @@ DEFINE FIELD content ON TABLE source_insight TYPE string; DEFINE FIELD embedding ON TABLE source_insight TYPE array; +DEFINE EVENT source_delete ON TABLE source WHEN ($after == NONE) THEN { + delete source_embedding where source == $before.id; + delete source_insight where source == $before.id; +}; + DEFINE TABLE IF NOT EXISTS note SCHEMAFULL; DEFINE FIELD title ON TABLE note TYPE option; @@ -55,6 +60,8 @@ DEFINE TABLE IF NOT EXISTS notebook SCHEMAFULL; DEFINE FIELD name ON TABLE notebook TYPE option; DEFINE FIELD description ON TABLE notebook TYPE option; +DEFINE FIELD archived ON TABLE notebook TYPE option DEFAULT False; + DEFINE FIELD created ON notebook DEFAULT time::now() VALUE $before OR time::now(); DEFINE FIELD updated ON notebook DEFAULT time::now() VALUE time::now(); diff --git a/open_notebook/domain.py b/open_notebook/domain.py index 33fb203..7d19ebd 100644 --- a/open_notebook/domain.py +++ b/open_notebook/domain.py @@ -126,6 +126,7 @@ class Notebook(ObjectModel): table_name: ClassVar[str] = "notebook" name: str description: str + archived: Optional[bool] = False @field_validator("name") @classmethod diff --git a/pages/2_📒_Notebooks.py b/pages/2_📒_Notebooks.py index 60c9d4a..1d77485 100644 --- a/pages/2_📒_Notebooks.py +++ b/pages/2_📒_Notebooks.py @@ -33,12 +33,23 @@ def notebook_header(current_notebook): value=current_description, placeholder="Add as much context as you can as this will be used by the AI to generate insights.", ) - if st.button("Save", icon="💾", key="edit_notebook"): + c1, c2, c3 = st.columns([1, 1, 1]) + if c1.button("Save", icon="💾", key="edit_notebook"): current_notebook.name = notebook_name current_notebook.description = notebook_description current_notebook.save() st.rerun() - if st.button("Delete forever", type="primary", icon="☠️"): + if not current_notebook.archived: + if c2.button("Archive", icon="🗃️"): + current_notebook.archived = True + current_notebook.save() + st.toast("Notebook archived", icon="🗃️") + else: + if c2.button("Unarchive", icon="🗃️"): + current_notebook.archived = False + current_notebook.save() + st.toast("Notebook unarchived", icon="🗃️") + if c3.button("Delete forever", type="primary", icon="☠️"): current_notebook.delete() st.session_state["current_notebook"] = None st.rerun() @@ -79,6 +90,19 @@ def notebook_page(current_notebook_id): chat_sidebar(session_id=session_id) +def notebook_list_item(notebook): + with st.container(border=True): + st.subheader(notebook.name) + st.caption( + f"Created: {naturaltime(notebook.created)}, updated: {naturaltime(notebook.updated)}" + ) + st.write(notebook.description) + if st.button("Open", key=f"open_notebook_{notebook.id}"): + setup_stream_state(notebook.id) + st.session_state["current_notebook"] = notebook.id + st.rerun() + + if "current_notebook" not in st.session_state: st.session_state["current_notebook"] = None @@ -93,18 +117,11 @@ st.caption("Here are all your notebooks") notebooks = Notebook.get_all() for notebook in notebooks: - with st.container(border=True): - st.subheader(notebook.name) - st.caption( - f"Created: {naturaltime(notebook.created)}, updated: {naturaltime(notebook.updated)}" - ) - st.write(notebook.description) - if st.button("Open", key=f"open_notebook_{notebook.id}"): - setup_stream_state(notebook.id) - st.session_state["current_notebook"] = notebook.id - st.rerun() + if notebook.archived: + continue + notebook_list_item(notebook) -with st.container(border=True): +with st.expander("➕ **New Notebook**"): new_notebook_title = st.text_input("New Notebook Name") new_notebook_description = st.text_area("Description") if st.button("Create a new Notebook", icon="➕"): @@ -113,3 +130,9 @@ with st.container(border=True): ) notebook.save() st.rerun() + +archived_notebooks = [nb for nb in notebooks if nb.archived] +if len(archived_notebooks) > 0: + with st.expander(f"**🗃️ {len(archived_notebooks)} archived Notebooks**"): + for notebook in archived_notebooks: + notebook_list_item(notebook) diff --git a/stream_app/source.py b/stream_app/source.py index 9a68f7b..9632b28 100644 --- a/stream_app/source.py +++ b/stream_app/source.py @@ -82,9 +82,18 @@ def source_panel(source_id): source.vectorize() st.success("Embedding complete") - if st.button("Delete", type="primary", icon="🗑️"): - source.delete() - st.rerun() + chk_delete = st.checkbox( + "🗑️ Delete source", key=f"delete_source_{source.id}", value=False + ) + if chk_delete: + st.warning( + "Source will be deleted with all its insights and embeddings" + ) + if st.button( + "Delete", type="primary", key=f"bt_delete_source_{source.id}" + ): + source.delete() + st.rerun() with source_tab: st.subheader("Content")