Spaces:
Sleeping
Sleeping
| import calendar | |
| from datetime import datetime | |
| import streamlit as st | |
| from streamlit.errors import StreamlitAPIException | |
| from admin import AuthManager, login | |
| from components import render_dataset_metadata, render_records_by_year | |
| from config import AppConfig | |
| from dashboard_analytics import log_visit | |
| from utils.data_loading import get_dataset_metadata | |
| from utils.session import ensure_session_initialized | |
| ensure_session_initialized() | |
| log_visit("Settings") | |
| col1, col2 = st.columns([2, 1]) | |
| data_manager = st.session_state.data_manager | |
| current_start = st.session_state.get("start_date") | |
| current_end = st.session_state.get("end_date") | |
| reporting_month: int = st.session_state.get( | |
| "reporting_month", AppConfig.DEFAULT_REPORTING_MONTH | |
| ) | |
| st.session_state.data = data_manager.load_data( | |
| start_date=current_start, end_date=current_end, reporting_month=reporting_month | |
| ) | |
| full_metadata = data_manager.metadata | |
| metadata = get_dataset_metadata( | |
| st.session_state.data["raw_df"], reporting_month=reporting_month | |
| ) | |
| # Get the date range from metadata | |
| raw_start = full_metadata["date_range"]["start"] | |
| raw_end = full_metadata["date_range"]["end"] | |
| # Set to first day of start month and last day of end month | |
| min_date = raw_start.replace(day=1) | |
| max_date = raw_end.replace(day=calendar.monthrange(raw_end.year, raw_end.month)[1]) | |
| def on_date_change(): | |
| """Callback for date input changes""" | |
| # Ensure these variables are initialized | |
| if ( | |
| "dataset_start_date" not in st.session_state | |
| or "dataset_end_date" not in st.session_state | |
| ): | |
| return | |
| start = st.session_state.dataset_start_date | |
| end = st.session_state.dataset_end_date | |
| # Check if either date is None or invalid - if so, keep previous values | |
| if start is None or end is None: | |
| st.error("Both start and end dates must be selected") | |
| return | |
| if start > end: | |
| st.error("Start date must be before end date") | |
| return | |
| if start < min_date or end > max_date: | |
| st.error( | |
| f"Dates must be between {min_date.strftime('%m/%d/%Y')} and {max_date.strftime('%m/%d/%Y')}" | |
| ) | |
| if start < min_date: | |
| del st.session_state["dataset_start_date"] | |
| if end > max_date: | |
| del st.session_state["dataset_end_date"] | |
| # Force UI update by toggling a session state variable | |
| st.session_state["force_refresh"] = not st.session_state.get( | |
| "force_refresh", False | |
| ) | |
| return | |
| # Only update if we have valid dates | |
| st.session_state.start_date = start | |
| st.session_state.end_date = end | |
| with col1: | |
| st.subheader("Reporting Period") | |
| # Date filter controls | |
| filter_col1, filter_col2, filter_col3 = st.columns(3, vertical_alignment="bottom") | |
| # Use existing values from session state, or defaults if not set | |
| current_start = st.session_state.get("start_date", min_date) or min_date | |
| current_end = st.session_state.get("end_date", max_date) or max_date | |
| with filter_col1: | |
| try: | |
| start_date = st.date_input( | |
| "Start Date", | |
| value=current_start, | |
| min_value=min_date, | |
| max_value=max_date, | |
| format="MM/DD/YYYY", | |
| key="dataset_start_date", | |
| on_change=on_date_change, | |
| ) | |
| except StreamlitAPIException: | |
| start_date = current_start | |
| st.error( | |
| f"Date must be between {min_date.strftime('%m/%d/%Y')} and {max_date.strftime('%m/%d/%Y')}" | |
| ) | |
| with filter_col2: | |
| try: | |
| end_date = st.date_input( | |
| "End Date", | |
| value=current_end, | |
| min_value=min_date, | |
| max_value=max_date, | |
| format="MM/DD/YYYY", | |
| key="dataset_end_date", | |
| on_change=on_date_change, | |
| ) | |
| except StreamlitAPIException: | |
| end_date = current_end | |
| # Show an error message | |
| st.error( | |
| f"Date must be between {min_date.strftime('%m/%d/%Y')} and {max_date.strftime('%m/%d/%Y')}" | |
| ) | |
| config = st.session_state.get("config") or AppConfig.from_env() | |
| initial_reporting_month = st.session_state.get( | |
| "reporting_month", config.DEFAULT_REPORTING_MONTH | |
| ) | |
| initial_dataset_month = st.session_state.get( | |
| "dataset_reporting_month", initial_reporting_month | |
| ) | |
| def on_reporting_month_change(): | |
| if "dataset_reporting_month" in st.session_state: | |
| st.session_state.reporting_month = st.session_state.dataset_reporting_month | |
| filter_row2_col1, _ = st.columns([1, 2]) | |
| with filter_row2_col1: | |
| reporting_month = st.selectbox( | |
| "Reporting Year End Month", | |
| options=range(1, 13), | |
| format_func=lambda x: datetime(2000, x, 1).strftime("%B"), | |
| index=initial_reporting_month - 1, | |
| key="dataset_reporting_month", | |
| on_change=on_reporting_month_change, | |
| ) | |
| st.subheader("Data Exclusions") | |
| exclusion_col1, exclusion_col2 = st.columns(2) | |
| def on_sector_exclusion_change(): | |
| """Callback for sector exclusion changes""" | |
| if "excluded_sectors_widget" in st.session_state: | |
| # Update the persistent storage with widget values | |
| st.session_state.persistent_excluded_sectors = ( | |
| st.session_state.excluded_sectors_widget | |
| ) | |
| # Reload data with new exclusions | |
| st.session_state.data = st.session_state.data_manager.load_data( | |
| start_date=st.session_state.get("start_date"), | |
| end_date=st.session_state.get("end_date"), | |
| reporting_month=st.session_state.get("reporting_month"), | |
| ) | |
| def on_station_exclusion_change(): | |
| """Callback for station exclusion changes""" | |
| if "excluded_stations_widget" in st.session_state: | |
| # Update the persistent storage with widget values | |
| st.session_state.persistent_excluded_stations = ( | |
| st.session_state.excluded_stations_widget | |
| ) | |
| # Reload data with new exclusions | |
| st.session_state.data = st.session_state.data_manager.load_data( | |
| start_date=st.session_state.get("start_date"), | |
| end_date=st.session_state.get("end_date"), | |
| reporting_month=st.session_state.get("reporting_month"), | |
| ) | |
| # Initialize persistent storage if not exists | |
| if "persistent_excluded_sectors" not in st.session_state: | |
| st.session_state.persistent_excluded_sectors = [] | |
| if "persistent_excluded_stations" not in st.session_state: | |
| st.session_state.persistent_excluded_stations = [] | |
| # Reload data if there are any exclusions | |
| if st.session_state.get("persistent_excluded_sectors") or st.session_state.get( | |
| "persistent_excluded_stations" | |
| ): | |
| st.session_state.data = st.session_state.data_manager.load_data( | |
| start_date=st.session_state.get("start_date"), | |
| end_date=st.session_state.get("end_date"), | |
| reporting_month=st.session_state.get("reporting_month"), | |
| ) | |
| with exclusion_col1: | |
| # Get complete list of sectors from data manager | |
| all_sectors = st.session_state.data_manager.all_sectors | |
| st.multiselect( | |
| "Exclude Sectors", | |
| options=all_sectors, | |
| default=st.session_state.persistent_excluded_sectors, | |
| help="Select sectors to exclude from all analyses", | |
| key="excluded_sectors_widget", | |
| on_change=on_sector_exclusion_change, | |
| ) | |
| with exclusion_col2: | |
| # Get complete list of stations from data manager | |
| all_stations = st.session_state.data_manager.all_stations | |
| st.multiselect( | |
| "Exclude Stations", | |
| options=all_stations, | |
| default=st.session_state.persistent_excluded_stations, | |
| help="Select stations to exclude from all analyses", | |
| key="excluded_stations_widget", | |
| on_change=on_station_exclusion_change, | |
| ) | |
| render_dataset_metadata(metadata, min_date, max_date) | |
| render_records_by_year(st.session_state.data["raw_df"], reporting_month) | |
| # Add the login form in a half-width column | |
| login_col1, _ = st.columns([1, 1]) | |
| with login_col1: | |
| with st.expander("Admin Login"): | |
| login(AuthManager(config)) | |