import gradio as gr from notebook_store import ( create_notebook, delete_notebook as delete_notebook_on_disk, duplicate_notebook as duplicate_notebook_on_disk, list_source_events, rename_notebook as rename_notebook_on_disk, ) def _choices(notebooks: list[dict]) -> list[tuple[str, str]]: return [(n["name"], n["id"]) for n in notebooks] def _sources_table(notebook_id: str) -> list[list[str]]: events = list_source_events(notebook_id) rows: list[list[str]] = [] for e in events: kind = e.get("kind") if kind == "file": rows.append([str(e.get("original_filename") or e.get("source_name") or "")]) elif kind == "url": rows.append([str(e.get("url") or e.get("source_name") or "")]) return [r for r in rows if r and r[0]] def delete_notebook(selected_id, notebooks): selected_id = (selected_id or "").strip() notebooks = list(notebooks or []) if not selected_id: return gr.update(), notebooks, selected_id, _sources_table(selected_id) if selected_id else [] delete_notebook_on_disk(selected_id) notebooks = [n for n in notebooks if n.get("id") != selected_id] if not notebooks: nb = create_notebook("Notebook 1") notebooks = [{"id": nb.id, "name": nb.name}] next_id = notebooks[0]["id"] return gr.update(choices=_choices(notebooks), value=next_id), notebooks, next_id, _sources_table(next_id) def rename_notebook(selected_id, new_name, notebooks): selected_id = (selected_id or "").strip() new_name = (new_name or "").strip() notebooks = list(notebooks or []) if not selected_id or not new_name: return gr.update(), notebooks, "", selected_id, _sources_table(selected_id) if selected_id else [] existing_names = {str(n.get("name")) for n in notebooks} current = next((n for n in notebooks if n.get("id") == selected_id), None) if current is None: return gr.update(), notebooks, "", selected_id, _sources_table(selected_id) if new_name in existing_names and new_name != current.get("name"): return gr.update(), notebooks, "", selected_id, _sources_table(selected_id) meta = rename_notebook_on_disk(selected_id, new_name) current["name"] = meta.name current["id"] = meta.id notebooks.sort(key=lambda n: str(n.get("name", "")).lower()) return gr.update(choices=_choices(notebooks), value=meta.id), notebooks, "", meta.id, _sources_table(meta.id) def duplicate_notebook(selected_id, notebooks): selected_id = (selected_id or "").strip() notebooks = list(notebooks or []) if not selected_id: return gr.update(), notebooks, selected_id, _sources_table(selected_id) if selected_id else [] current = next((n for n in notebooks if n.get("id") == selected_id), None) base_name = str(current.get("name") if current else "Notebook") new_name = make_copy_name(base_name, [str(n.get("name")) for n in notebooks]) meta = duplicate_notebook_on_disk(selected_id, new_name=new_name) notebooks.append({"id": meta.id, "name": meta.name}) notebooks.sort(key=lambda n: str(n.get("name", "")).lower()) return gr.update(choices=_choices(notebooks), value=meta.id), notebooks, meta.id, _sources_table(meta.id) def make_copy_name(base: str, choices: list[str]) -> str: base = (base or "").strip() if not base: return "" candidate = f"{base} (copy)" if candidate not in choices: return candidate i = 2 while True: candidate = f"{base} (copy {i})" if candidate not in choices: return candidate i += 1 def ManageNotebook(notebook, notebooks_state, notebook_id_state, ingested_list): with gr.Accordion("Manage Notebook", open=False, elem_classes=["section-card"]): updated_name = gr.Textbox(label="Update name", interactive=True) rename_nb = gr.Button("Rename", variant="secondary", elem_classes=["full-width"]) delete_nb = gr.Button("Delete", variant="stop", elem_classes=["full-width"]) duplicate_nb = gr.Button("Duplicate", variant="secondary", elem_classes=["full-width"]) delete_nb.click( delete_notebook, inputs=[notebook, notebooks_state], outputs=[notebook, notebooks_state, notebook_id_state, ingested_list], ) rename_nb.click( rename_notebook, inputs=[notebook, updated_name, notebooks_state], outputs=[notebook, notebooks_state, updated_name, notebook_id_state, ingested_list], ) duplicate_nb.click( duplicate_notebook, inputs=[notebook, notebooks_state], outputs=[notebook, notebooks_state, notebook_id_state, ingested_list], )