diff --git a/src/gui/pages/10_PDF_Extractor.py b/src/gui/pages/10_PDF_Extractor.py index 2a6fdf3..bea18cc 100644 --- a/src/gui/pages/10_PDF_Extractor.py +++ b/src/gui/pages/10_PDF_Extractor.py @@ -65,6 +65,13 @@ render_sticky_footer() K_ROWS = "pdf_scan_rows" K_WARNINGS = "pdf_scan_warnings" K_SOURCE_COUNT = "pdf_scan_source_count" +# Stamped once at scan time. The download button's file_name +# embeds this so the user gets a unique-per-scan filename — but +# crucially, the value is stable across reruns triggered by +# unrelated widget interactions (otherwise the html_download_button +# helper's session-state key drifts every second and the +# "Saved to " banner never gets to render). +K_TIMESTAMP = "pdf_scan_timestamp" # ``pdf_uploads`` is the persistent stash of uploaded PDFs (dict # keyed by filename → {"bytes": ..., "size": ...}). It survives # Streamlit reruns and navigation away from the page. The @@ -386,7 +393,7 @@ with c_clear: ): st.session_state[K_UPLOADS] = {} st.session_state[K_UPLOAD_COUNTER] = upload_counter + 1 - for k in (K_ROWS, K_WARNINGS, K_SOURCE_COUNT): + for k in (K_ROWS, K_WARNINGS, K_SOURCE_COUNT, K_TIMESTAMP): st.session_state.pop(k, None) log_event( "upload", @@ -441,6 +448,7 @@ if scan_clicked and pdf_uploads: st.session_state[K_ROWS] = all_rows st.session_state[K_WARNINGS] = all_warnings st.session_state[K_SOURCE_COUNT] = n_files + st.session_state[K_TIMESTAMP] = datetime.now().strftime("%Y%m%d-%H%M%S") log_event( "tool_run", @@ -606,7 +614,10 @@ else: if selected.empty: st.button("Download CSV", disabled=True) else: - ts = datetime.now().strftime("%Y%m%d-%H%M%S") + # Reuse the timestamp stamped when this scan finished — + # stable across reruns so the download helper's button + # key doesn't drift every second. + ts = st.session_state.get(K_TIMESTAMP) or "results" # Default: drop the internal columns from the download. keep_default = [ c for c in selected.columns