Source code for webinterface.pages.base

import pages.texts.proteobench_builder as pbb
import streamlit as st
from pages.base_pages.banner import display_banner

# The guided tour is an optional driver.js overlay. Importing it can fail when the
# installed streamlit_tour is incompatible with the streamlit version (e.g.
# streamlit_tour 1.1.0 raises at import under streamlit>=1.58). Degrade gracefully:
# disable the tour rather than breaking the whole page.
try:
    from streamlit_tour import Tour
except Exception:  # noqa: BLE001 - any import/component-registration failure
    Tour = None


[docs] class BaseStreamlitUI: """ Streamlit UI for the DDA quantification - precursor ions module. """ def __init__(self, variables, texts, ionmodule, parsesettingsbuilder, uiobjects, page_name): """ Initialize the Streamlit UI for the DDA quantification - precursor ions module. """ self.variables = variables self.texts = texts self.user_input = dict() pbb.proteobench_page_config() if self.variables.submit not in st.session_state: st.session_state[self.variables.submit] = False try: token = st.secrets["gh"]["token"] except KeyError: token = "" self.ionmodule = ionmodule(token=token) self.parsesettingsbuilder = parsesettingsbuilder( module_id=self.ionmodule.module_id, parse_settings_dir=self.variables.parse_settings_dir ) self.uiobjects = uiobjects(self.variables, self.ionmodule, self.parsesettingsbuilder, page_name=page_name) def _render_tab_header(self) -> None: """Render common tab header elements: title, documentation link, and banner.""" st.title(self.variables.title) st.link_button( "Go to module documentation", url=self.variables.doc_url, type="secondary", help="link to the module documentation", ) display_banner(self.variables)
[docs] def get_tab_config(self) -> list: """Return tab configuration as list of (tab_name, method_name) tuples. Override this method in subclasses to customize tabs. """ return [ ("View Public Results", "display_all_data_results_main"), ("Upload New Results (Private)", "display_submission_form"), ("View Single Result", "display_indepth_plots"), ("View Public + New Results", "display_all_data_results_submitted"), ("Compare Two Results", "display_workflow_comparison"), ("Submit New Results", "display_public_submission_ui"), ]
[docs] def main_page(self) -> None: """ Set up the main page layout for the Streamlit application. """ # User navigated away from the homepage without answering: treat as opted out. if "_tour_opted_in" not in st.session_state: st.session_state["_tour_opted_in"] = False # Driver.js sets pointer-events:none on ALL elements (.driver-active *) to lock the page. # This prevents Streamlit selectbox dropdowns from working because they render as body-level # portals outside the highlighted element. We re-enable pointer events on everything, but # keep the SVG overlay itself non-interactive so overlay clicks don't close the tour. if st.session_state.get("_module_tour_in_progress", False): st.markdown( "<style>" ".driver-active * { pointer-events: auto !important; }" ".driver-active svg * { pointer-events: all !important; }" ".driver-active .driver-overlay," ".driver-active .driver-overlay * { pointer-events: none !important; }" "</style>", unsafe_allow_html=True, ) # Get tab configuration tab_config = self.get_tab_config() # ? could also go here: if debug state is set, show debug tab tab_names = [name for name, _ in tab_config] # Create tabs dynamically tabs = st.tabs(tab_names) # Render each tab for tab, (tab_name, method_name) in zip(tabs, tab_config): with tab: self._render_tab_header() # Call the appropriate method on uiobjects getattr(self.uiobjects, method_name)() # Skip tour setup entirely when the streamlit_tour component is unavailable. tour_steps = self.uiobjects.get_tour_steps() if Tour is not None else None if tour_steps: if st.sidebar.button("Take a Tour", key="module_tour_trigger"): st.session_state["start_module_tour"] = True else: # No tour for this module — discard any stale trigger so it doesn't # fire unexpectedly when the user navigates to a module that has a tour. st.session_state.pop("start_module_tour", None) if tour_steps: module_id = getattr(self.ionmodule, "module_id", "module") tour_key = f"onboarding_{module_id}" tour_active_key = f"stTour--{tour_key}-active" tour_in_progress_key = "_module_tour_in_progress" # Detect tour completion: was in progress last render, now inactive. if st.session_state.get(tour_in_progress_key, False) and not st.session_state.get(tour_active_key, False): st.session_state.pop(tour_in_progress_key, None) st.session_state["_module_tour_completed"] = True tour = Tour( tour_steps, key=tour_key, show_progress=True, animate=True, overlay_opacity=0.75, one_time_tour=False, ) auto_key = f"_tour_auto_{tour_key}" if st.session_state.pop("start_module_tour", False): # Manual button: always start regardless of opt-in. st.session_state[tour_in_progress_key] = True tour.start() elif ( "_tour_opted_in" in st.session_state and auto_key not in st.session_state and not st.session_state.get("_module_tour_completed", False) ): # User has made a decision and auto-start has not been handled yet. st.session_state[auto_key] = True if st.session_state["_tour_opted_in"] is True: st.session_state[tour_in_progress_key] = True tour.start()
# Opted out: mark handled, do not start.