""" FocusTrack - Page 3: Activity Log Searchable, filterable, paginated activity table. """ import streamlit as st import pandas as pd from datetime import datetime, timedelta, date from ui_utils import ( fmt_duration, privacy_badge, page_header, CATEGORY_COLORS, get_db, get_date_range ) PAGE_SIZE = 50 def render(): db = get_db() privacy_badge() page_header("Activity Log", "Browse and search all tracked sessions") # ── Filters ─────────────────────────────────────────────────────────────── col1, col2, col3, col4 = st.columns([1.5, 1, 1, 1]) with col1: search = st.text_input("🔍 Search", placeholder="App, title, or category…") with col2: range_sel = st.selectbox("Range", ["Today", "Yesterday", "Last 7 days", "Last 30 days", "Custom"], index=2) start, end = get_date_range(range_sel) if range_sel == "Custom": with col3: start_d = st.date_input("From", value=date.today() - timedelta(days=6)) with col4: end_d = st.date_input("To", value=date.today()) start = datetime.combine(start_d, datetime.min.time()) end = datetime.combine(end_d, datetime.max.time()) # Filter by category cats = [c["name"] for c in db.get_categories()] with col3 if range_sel != "Custom" else st.columns(1)[0]: pass cat_filter_col, show_idle_col = st.columns([2, 1]) with cat_filter_col: selected_cats = st.multiselect("Filter by category", cats, default=[]) with show_idle_col: show_idle = st.checkbox("Include idle", value=False) # ── Count & Pagination ──────────────────────────────────────────────────── total_count = db.get_activity_count(start, end, search) if "log_page" not in st.session_state: st.session_state.log_page = 0 page = st.session_state.log_page offset = page * PAGE_SIZE total_pages = max(1, (total_count + PAGE_SIZE - 1) // PAGE_SIZE) # ── Fetch Data ──────────────────────────────────────────────────────────── rows = db.get_activities(start, end, search=search, limit=PAGE_SIZE, offset=offset) # Apply local filters if selected_cats: rows = [r for r in rows if r.get("category") in selected_cats] if not show_idle: rows = [r for r in rows if not r.get("is_idle")] # ── Stats bar ───────────────────────────────────────────────────────────── st.markdown( f"

" f"Showing {len(rows)} of {total_count:,} records  |  " f"Page {page + 1} of {total_pages}" f"

", unsafe_allow_html=True, ) # ── Table ───────────────────────────────────────────────────────────────── if rows: html_rows = "" for r in rows: cat = r.get("category", "uncategorized") color = CATEGORY_COLORS.get(cat, "#6366f1") ts = r.get("timestamp", "")[:19].replace("T", " ") is_idle_icon = "💤" if r.get("is_idle") else "●" idle_color = "#374151" if r.get("is_idle") else "#10b981" dur = fmt_duration(r.get("duration_seconds", 0)) app = str(r.get("app_name", ""))[:30] title = str(r.get("window_title", ""))[:60] html_rows += f""" {ts} {app} {title} {dur} {cat} {is_idle_icon} """ st.markdown(f"""
{html_rows}
Time App Window Title Duration Category Status
""", unsafe_allow_html=True) else: st.markdown("""
No activity records found for the selected filters.
""", unsafe_allow_html=True) # ── Pagination controls ─────────────────────────────────────────────────── pc1, pc2, pc3, pc4, pc5 = st.columns([1, 1, 2, 1, 1]) with pc1: if st.button("⏮ First") and page > 0: st.session_state.log_page = 0 st.rerun() with pc2: if st.button("◀ Prev") and page > 0: st.session_state.log_page = page - 1 st.rerun() with pc3: st.markdown( f"
" f"Page {page + 1} / {total_pages}
", unsafe_allow_html=True, ) with pc4: if st.button("Next ▶") and page < total_pages - 1: st.session_state.log_page = page + 1 st.rerun() with pc5: if st.button("Last ⏭") and page < total_pages - 1: st.session_state.log_page = total_pages - 1 st.rerun() # ── Export ──────────────────────────────────────────────────────────────── st.markdown("---") all_rows = db.get_activities(start, end, search=search, limit=100000) if all_rows: df_export = pd.DataFrame(all_rows) col_ex1, col_ex2 = st.columns([1, 1]) with col_ex1: st.download_button( "📥 Export visible data (CSV)", df_export.to_csv(index=False).encode("utf-8"), file_name="focustrack_log.csv", mime="text/csv", use_container_width=True, ) with col_ex2: st.download_button( "📥 Export visible data (JSON)", df_export.to_json(orient="records", indent=2).encode("utf-8"), file_name="focustrack_log.json", mime="application/json", use_container_width=True, )