streamlit-framework-multilit 0.7.12__tar.gz → 0.7.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (14) hide show
  1. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/PKG-INFO +1 -1
  2. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/PKG-INFO +1 -1
  3. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/app_wrapper.py +1 -2
  4. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/loading_engine.py +22 -14
  5. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/multilit.py +116 -199
  6. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/LICENSE +0 -0
  7. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/README.md +0 -0
  8. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/setup.cfg +0 -0
  9. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/setup.py +0 -0
  10. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/SOURCES.txt +0 -0
  11. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/dependency_links.txt +0 -0
  12. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/requires.txt +0 -0
  13. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/top_level.txt +0 -0
  14. {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-framework-multilit
3
- Version: 0.7.12
3
+ Version: 0.7.13
4
4
  Summary: Components and Frameworks to give new features to streamlit
5
5
  Home-page: https://github.com/quiradev/streamlit-plugins
6
6
  Author: Victor Quilon Ranera
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-framework-multilit
3
- Version: 0.7.12
3
+ Version: 0.7.13
4
4
  Summary: Components and Frameworks to give new features to streamlit
5
5
  Home-page: https://github.com/quiradev/streamlit-plugins
6
6
  Author: Victor Quilon Ranera
@@ -13,11 +13,10 @@ class STPageWrapper:
13
13
 
14
14
  """
15
15
 
16
- def __init__(self, st_page: StreamlitPage, with_loader=None, loading_engine: LoadingEngine | None = None):
16
+ def __init__(self, st_page: StreamlitPage, with_loader=None):
17
17
  self.id: str = "unset"
18
18
  self.access_level: int | None = None
19
19
  self.with_loader = with_loader
20
- self.loading_engine = loading_engine
21
20
  self.parent_app = None
22
21
  self.st_page = st_page
23
22
  self.title: str = st_page.title
@@ -1,25 +1,25 @@
1
1
  import logging
2
2
  import traceback
3
- from typing import Callable, Tuple, Optional
3
+ from typing import Callable, Tuple, Optional, Generic
4
4
 
5
5
  from streamlit.runtime.scriptrunner import StopException
6
6
 
7
- from streamlit_plugins.components.loader import LoadersLib, DefaultLoader, LoaderType
7
+ from streamlit_plugins.components.loader import LoadersLib, DefaultLoader, LoaderType, BaseLoader
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
11
 
12
12
  class LoadingWithStatement:
13
13
  def __init__(
14
- self, loading_engine: "LoadingEngine",
14
+ self, loader: BaseLoader,
15
15
  **run_loader_kwargs
16
16
  ):
17
- self.loading_engine = loading_engine
17
+ self.loader = loader
18
18
  self.run_loader_kwargs = run_loader_kwargs
19
19
 
20
20
  def __enter__(self):
21
21
  try:
22
- self.loading_engine.loader.run_loader(
22
+ self.loader.run_loader(
23
23
  **self.run_loader_kwargs
24
24
  )
25
25
  # except RerunException as e:
@@ -31,29 +31,37 @@ class LoadingWithStatement:
31
31
  logger.error(traceback.format_exc())
32
32
 
33
33
  def __exit__(self, exc_type, exc_val, exc_tb):
34
- self.loading_engine.loader.stop_loader()
34
+ self.loader.stop_loader()
35
35
 
36
36
 
37
37
  class LoadingEngine:
38
38
  default_loader_lib: LoadersLib = LoadersLib.book_loader
39
39
 
40
- def __init__(self, loader: LoaderType, loader_kwargs: dict = None):
41
- if loader_kwargs is not None:
42
- loader = loader.recreate_loader_with(**loader_kwargs)
43
- self.loader = loader
40
+ def __init__(self, default_loader: BaseLoader):
41
+ self.selected_loader = default_loader
42
+ self.loaders = {}
43
+ self.loaders_params = {}
44
44
 
45
45
  @classmethod
46
- def get_default_loader(cls, loader_container, loader_params: dict = None, loader_lib: LoadersLib | Callable[..., Tuple[str, str ,str], ] = None) -> DefaultLoader:
46
+ def get_default_loader(cls, loader_container_key: str, loader_params: Optional[dict] = None, loader_lib: LoadersLib | Callable[..., Tuple[str, str ,str], ] = None) -> DefaultLoader:
47
+ loader_params = loader_params or {}
48
+
47
49
  loader_lib = loader_lib or cls.default_loader_lib
48
50
  return DefaultLoader(
49
- loader_container=loader_container,
51
+ loader_container_key=loader_container_key,
50
52
  **loader_params,
51
53
  loader_lib=loader_lib
52
54
  )
53
55
 
54
- def loading(self, **run_loader_kwargs):
56
+ def register_page_loader(self, page_id: str | int, loader: BaseLoader, run_loader_kwargs: Optional[dict] = None):
57
+ self.loaders[page_id] = loader
58
+ self.loaders_params[page_id] = run_loader_kwargs or {}
59
+
60
+ def loading(self, page_id: str | int, **run_loader_kwargs):
61
+ selected_loader = self.loaders.get(page_id, self.selected_loader) or self.selected_loader
62
+ run_loader_kwargs = {**self.loaders_params.get(page_id, run_loader_kwargs), **run_loader_kwargs}
55
63
  return LoadingWithStatement(
56
- self,
64
+ selected_loader,
57
65
  # Any argument that can be changed dinamically
58
66
  **run_loader_kwargs
59
67
  # label=label, height=height,
@@ -4,6 +4,7 @@ from typing import Any, Callable, Dict, Literal, Optional, Tuple
4
4
 
5
5
  import streamlit
6
6
  import streamlit as st
7
+
7
8
  try:
8
9
  from streamlit.web.server.routes import _DEFAULT_ALLOWED_MESSAGE_ORIGINS
9
10
  except ImportError as e:
@@ -18,7 +19,7 @@ try:
18
19
  except ModuleNotFoundError:
19
20
  from streamlit.runtime.scriptrunner_utils.script_requests import ScriptRequestType, RerunData
20
21
 
21
- from streamlit_plugins.components.loader import BaseLoader, LoaderType, LoadersLib
22
+ from streamlit_plugins.components.loader import BaseLoader, LoaderType, LoadersLib, DefaultLoader
22
23
  from streamlit_plugins.components.navbar import (
23
24
  DEFAULT_THEMES,
24
25
  HEADER_HEIGHT,
@@ -26,6 +27,7 @@ from streamlit_plugins.components.navbar import (
26
27
  init_navigation_transition, get_navigation_transition,
27
28
  set_default_page, set_force_next_page, set_navigation_transition,
28
29
  st_navigation, st_switch_page, has_changed_page,
30
+ NAVIGATION_COMPONENT_KEY, NAVIGATION_KEY_PREFIX, NAVBAR_KEY_PREFIX
29
31
  )
30
32
  from .app_wrapper import STPageWrapper
31
33
  from .loading_engine import LoadingEngine
@@ -51,8 +53,8 @@ if major == 1:
51
53
  DEFAULT_NAVBAR_PARENT_SELECTOR_FRAGMENT = """[data-testid="stVerticalBlockBorderWrapper"]:has(> div > [data-testid="stVerticalBlock"] > [data-testid="stVerticalBlockBorderWrapper"] > div > [data-testid="stVerticalBlock"] > [data-testid="stElementContainer"] > iframe[title="streamlit_plugins.components.navbar.nav_bar"])"""
52
54
 
53
55
  if minnor >= 43:
54
- DEFAULT_NAVBAR_PARENT_SELECTOR = """[data-testid="stVerticalBlockBorderWrapper"]:has(> div > [data-testid="stVerticalBlock"] > [data-testid="stElementContainer"].st-key-NavigationComponent > div > iframe[title="streamlit_plugins.components.navbar.nav_bar"])"""
55
- DEFAULT_NAVBAR_PARENT_SELECTOR_FRAGMENT = """[data-testid="stVerticalBlockBorderWrapper"]:has(> div > [data-testid="stVerticalBlock"] > [data-testid="stVerticalBlockBorderWrapper"] > div > [data-testid="stVerticalBlock"] > [data-testid="stElementContainer"].st-key-NavigationComponent > div > iframe[title="streamlit_plugins.components.navbar.nav_bar"])"""
56
+ DEFAULT_NAVBAR_PARENT_SELECTOR = f"""[data-testid="stVerticalBlockBorderWrapper"]:has(> div > [data-testid="stVerticalBlock"] > [data-testid="stElementContainer"].st-key-{NAVIGATION_COMPONENT_KEY} > div > iframe[title="streamlit_plugins.components.navbar.nav_bar"])"""
57
+ DEFAULT_NAVBAR_PARENT_SELECTOR_FRAGMENT = f"""[data-testid="stVerticalBlockBorderWrapper"]:has(> div > [data-testid="stVerticalBlock"] > [data-testid="stVerticalBlockBorderWrapper"] > div > [data-testid="stVerticalBlock"] > [data-testid="stElementContainer"].st-key-{NAVIGATION_COMPONENT_KEY} > div > iframe[title="streamlit_plugins.components.navbar.nav_bar"])"""
56
58
 
57
59
 
58
60
  def add_trusted_url(url: str):
@@ -116,6 +118,7 @@ class FNStreamlitPage(StreamlitPage):
116
118
  def run(self):
117
119
  self._page()
118
120
 
121
+
119
122
  class SectionWithStatement:
120
123
  def __init__(self, name, exit_fn):
121
124
  self.name = name
@@ -131,6 +134,7 @@ class SectionWithStatement:
131
134
  NAVIGATION_MULTILIT_KEY = "multilit_navigation_container"
132
135
  LOADER_MULTILIT_KEY = "multilit_loader_container"
133
136
 
137
+
134
138
  class Multilit:
135
139
  """
136
140
  Class to create a host application for combining multiple streamlit applications.
@@ -148,35 +152,30 @@ class Multilit:
148
152
  # return jwt.decode(token, self._multilit_url_hash, algorithms=["HS256"])
149
153
 
150
154
  def __init__(
151
- self,
152
- title='Multilit Apps',
153
- nav_container=None,
154
- nav_horizontal=True,
155
- layout: Layout = "wide",
156
- favicon="🤹‍♀️",
157
- use_st_navigation_navbar=None,
158
- use_st_navigation=None,
159
- navbar_theme=None,
160
- navbar_sticky=True,
161
- navbar_mode: NavbarPositionType = 'under',
162
- use_cookie_cache=True,
163
- sidebar_state: InitialSideBarState = 'auto',
164
- # allow_url_nav=False,
165
- hide_streamlit_markers=False,
166
- use_banner_images=None,
167
- banner_spacing=None,
168
- clear_cross_page_sessions=True,
169
- session_params=None,
170
- verbose=False,
171
- within_fragment=False,
172
- login_info_session_key="logged_in",
173
- navigation_theme_changer=True,
174
- allowed_origins=None,
175
- use_loader=True,
176
- loader_lib: LoadersLib | Callable[..., Tuple[str, str ,str], ] | None = None,
177
- only_loading_between_pages: bool = True,
178
- loader: LoaderType = None, default_loader_params: Dict[str, Any] = None,
179
- **kwargs
155
+ self,
156
+ title='Multilit Apps',
157
+ nav_container=None,
158
+ layout: Layout = "wide",
159
+ favicon="🤹‍♀️",
160
+ use_st_navigation_navbar=None,
161
+ use_st_navigation=None,
162
+ navbar_theme=None,
163
+ navbar_sticky=True,
164
+ navbar_mode: NavbarPositionType = 'under',
165
+ sidebar_state: InitialSideBarState = 'auto',
166
+ hide_streamlit_markers=False,
167
+ clear_cross_page_sessions=False,
168
+ session_params=None,
169
+ verbose=False,
170
+ within_fragment=False,
171
+ login_info_session_key="logged_in",
172
+ navigation_theme_changer=True,
173
+ allowed_origins=None,
174
+ use_loader=False,
175
+ loader_lib: LoadersLib | Callable[..., Tuple[str, str, str],] | None = None,
176
+ only_loading_between_pages: bool = True,
177
+ loader: Optional[BaseLoader] = None, default_loader_params: Dict[str, Any] = None,
178
+ **kwargs
180
179
  ):
181
180
  """
182
181
  Initializes a Multi-page Streamlit application that allows combining several pages into a single interface, managing navigation, global state, and authentication.
@@ -187,8 +186,6 @@ class Multilit:
187
186
  Title of the main application (appears in the browser tab).
188
187
  nav_container : streamlit.container, optional
189
188
  Container where the navigation bar is rendered. If None, a default one is created.
190
- nav_horizontal : bool, optional (default True)
191
- If True, navigation items are aligned horizontally; if False, vertically.
192
189
  layout : Layout, optional (default "wide")
193
190
  Layout of the main Streamlit page.
194
191
  favicon : str, optional (default "🤹‍♀️")
@@ -203,17 +200,11 @@ class Multilit:
203
200
  If True, the navigation bar remains fixed at the top.
204
201
  navbar_mode : NavbarPositionType, optional (default 'under')
205
202
  Position of the navigation bar: 'top', 'under', 'side', etc.
206
- use_cookie_cache : bool, optional (default True)
207
- If True, uses cookies to store user access state.
208
203
  sidebar_state : InitialSideBarState, optional (default 'auto')
209
204
  Initial state of the Streamlit sidebar.
210
205
  hide_streamlit_markers : bool, optional (default False)
211
206
  Hides the Streamlit menu and watermark.
212
- use_banner_images : str or list, optional
213
- Image or list of images to display as a banner above the navigation bar.
214
- banner_spacing : list, optional
215
- Spacing of the banner images (similar to Streamlit column specification).
216
- clear_cross_page_sessions : bool, optional (default True)
207
+ clear_cross_page_sessions : bool, optional (default False)
217
208
  If True, clears session state when changing pages.
218
209
  session_params : dict, optional
219
210
  Dictionary of additional parameters for the global session state.
@@ -286,30 +277,24 @@ class Multilit:
286
277
  self._nav_item_count = 0
287
278
 
288
279
  if use_st_navigation_navbar is not None:
289
- logger.warning("The use_st_navigation_navbar parameter is deprecated, please use use_st_navigation instead.")
280
+ logger.warning(
281
+ "The use_st_navigation_navbar parameter is deprecated, please use use_st_navigation instead.")
290
282
 
291
283
  if use_st_navigation is None:
292
284
  use_st_navigation = use_st_navigation_navbar
293
285
  else:
294
- logger.warning("Both use_st_navigation_navbar and use_st_navigation parameters are set, using use_st_navigation value.")
286
+ logger.warning(
287
+ "Both use_st_navigation_navbar and use_st_navigation parameters are set, using use_st_navigation value.")
295
288
 
296
289
  self._use_st_navigation = use_st_navigation
297
290
  self._navigation_theme_changer = navigation_theme_changer
298
291
  self._hide_streamlit_markers = hide_streamlit_markers
299
292
  self._navbar_theme = navbar_theme or DEFAULT_THEMES
300
293
 
301
- self._banners = use_banner_images
302
- self._banner_spacing = banner_spacing
303
-
304
- self._use_cookie_cache = use_cookie_cache
305
- self._cookie_manager = None
306
-
307
294
  self._session_attrs = {}
308
- # self._call_queue = []
309
- # self._other_nav = None
295
+
310
296
  # self._guest_name = 'guest'
311
297
  # self._guest_access = 1
312
- # self._multilit_url_hash = 'mULTILIT|-HaShing==seCr8t'
313
298
  self._no_access_level = -1
314
299
 
315
300
  self._user_session_params = session_params
@@ -327,52 +312,29 @@ class Multilit:
327
312
  except Exception as e:
328
313
  pass
329
314
 
330
- # Establecer el tema
331
-
332
- self._nav_horizontal = nav_horizontal
333
-
334
- # self._theme_change_container = st.container()
335
-
336
- if self._banners is not None:
337
- self._banner_container = st.container()
338
-
339
- if nav_container is None:
340
- self._nav_container = st.container(key=NAVIGATION_MULTILIT_KEY)
341
- else:
342
- # hack to stop the beta containers from running set_page_config before MultiApp gets a chance to.
343
- # if we have a beta_columns container, the instance is delayed until the run() method is called, beta components, who knew!
344
- if nav_container.__name__ in ['container']:
345
- self._nav_container = nav_container()
346
- else:
347
- self._nav_container = nav_container
348
-
349
- page_view = st.empty()
350
- self._page_container = page_view.container()
315
+ self._nav_container = nav_container
316
+ self._page_view = None
351
317
 
352
318
  self._user_loader = use_loader
353
319
  self._only_loading_between_pages = only_loading_between_pages
354
320
  if self._user_loader:
355
- self._default_loader = loader
356
321
  if loader is None:
357
- self._loader_container = st.container(key=LOADER_MULTILIT_KEY)
358
- with self._loader_container:
359
- st.markdown(
360
- f"<style>\ndiv:has(>.st-key-{LOADER_MULTILIT_KEY}){{\nheight: 0; position: absolute;\n}}\n</style>",
361
- unsafe_allow_html=True
362
- )
363
- self._default_loader = LoadingEngine.get_default_loader(
364
- self._loader_container,
322
+ default_loader: DefaultLoader = LoadingEngine.get_default_loader(
323
+ LOADER_MULTILIT_KEY,
365
324
  loader_params=default_loader_params or {},
366
325
  loader_lib=loader_lib
367
326
  )
368
- self._loading_engine = LoadingEngine(self._default_loader)
327
+ else:
328
+ default_loader: BaseLoader = loader
329
+
330
+ self._loading_engine = LoadingEngine(default_loader)
369
331
 
370
332
  self.cross_session_clear = clear_cross_page_sessions
371
333
 
372
334
  if clear_cross_page_sessions:
373
- preserve_state = 0
335
+ preserve_state = False
374
336
  else:
375
- preserve_state = 1
337
+ preserve_state = True
376
338
 
377
339
  self.login_info_session_key = login_info_session_key
378
340
  self._session_attrs = {
@@ -400,13 +362,13 @@ class Multilit:
400
362
  self.change_page(page)
401
363
 
402
364
  def add_page(
403
- self,
404
- page: StreamlitPage, title=None, icon: str | None = None,
405
- page_type: Literal["normal", "home", "login", "settings", "account"] = "normal",
406
- access_level: int | None = None,
407
- with_loader: Optional[bool] = None,
408
- page_loader: BaseLoader | None = None,
409
- page_loader_kwargs: dict = None,
365
+ self,
366
+ page: StreamlitPage, title=None, icon: str | None = None,
367
+ page_type: Literal["normal", "home", "login", "settings", "account"] = "normal",
368
+ access_level: int | None = None,
369
+ with_loader: Optional[bool] = None,
370
+ page_loader: BaseLoader | None = None,
371
+ page_loader_kwargs: dict = None,
410
372
  ):
411
373
  """
412
374
  Adds a new page to this MultiApp.
@@ -438,13 +400,13 @@ class Multilit:
438
400
  if with_loader is None:
439
401
  with_loader = self._user_loader
440
402
 
441
- app_wrapper = STPageWrapper(
442
- page, with_loader=with_loader,
443
- loading_engine=LoadingEngine(
444
- page_loader or self._default_loader.recreate_loader_with(label=title),
445
- loader_kwargs=page_loader_kwargs
403
+ if page_loader or self._user_loader:
404
+ page_loader: BaseLoader
405
+ self._loading_engine.register_page_loader(
406
+ page_id, page_loader or self._loading_engine.selected_loader, run_loader_kwargs=page_loader_kwargs
446
407
  )
447
- )
408
+
409
+ app_wrapper = STPageWrapper(page, with_loader=with_loader)
448
410
  app_wrapper.access_level = access_level
449
411
  app_wrapper.id = page_id
450
412
  app_wrapper.title = title
@@ -487,7 +449,9 @@ class Multilit:
487
449
  self._nav_item_count = int(self._login_page is not None) + len(self._pages.keys())
488
450
  # app.assign_session(st.session_state, self)
489
451
 
490
- def page(self, title=None, icon=None, page_type: Literal["normal", "home", "login", "settings", "account"] = "normal", with_loader: Optional[bool] = None, page_loader: Optional[BaseLoader] = None):
452
+ def page(self, title=None, icon=None,
453
+ page_type: Literal["normal", "home", "login", "settings", "account"] = "normal",
454
+ with_loader: Optional[bool] = None, page_loader: Optional[BaseLoader] = None):
491
455
  """
492
456
  This is a decorator to quickly add a function as a child app in a style like a Flask route.
493
457
  You can do everything you can normally do when adding a class based MultiApp to the parent, except you can not add a login or unsecure app using this method, as
@@ -520,7 +484,8 @@ class Multilit:
520
484
  is_default = True
521
485
 
522
486
  wrapped_app = st.Page(func, title=page_title, icon=app_icon, default=is_default)
523
- self.add_page(title=page_title, page=wrapped_app, icon=app_icon, page_type=page_type, with_loader=with_loader, page_loader=page_loader)
487
+ self.add_page(title=page_title, page=wrapped_app, icon=app_icon, page_type=page_type,
488
+ with_loader=with_loader, page_loader=page_loader)
524
489
 
525
490
  return func
526
491
 
@@ -562,11 +527,12 @@ class Multilit:
562
527
 
563
528
  return page
564
529
 
565
- def build_native_pages_data_from(self, home_page, login_page=None, account_page=None, settings_page=None, logout_page=None):
530
+ def build_native_pages_data_from(self, home_page, login_page=None, account_page=None, settings_page=None,
531
+ logout_page=None):
566
532
  native_pages_data = {}
567
533
  if home_page is not None:
568
534
  native_pages_data[""] = [home_page]
569
-
535
+
570
536
  for sect, data in self._complex_nav.items():
571
537
  if sect.startswith("sect_"):
572
538
  data_section: dict = data
@@ -577,29 +543,33 @@ class Multilit:
577
543
  if "" not in native_pages_data:
578
544
  native_pages_data[""] = []
579
545
  native_pages_data[""].append(data_page)
580
-
546
+
581
547
  if any([login_page, account_page, settings_page]):
582
548
  native_pages_data["Account"] = []
583
549
  for page in [account_page, settings_page, logout_page]:
584
550
  if page is not None:
585
551
  native_pages_data["Account"].append(page)
586
-
552
+
587
553
  return native_pages_data
588
554
 
589
555
  @st.fragment
590
- def _fragment_navbar(self, natives_page_data, login_page, account_page, settings_page, logout_page, styles: str | None = None):
591
- new_page_id = self._standalone_navbar(natives_page_data, login_page, account_page, settings_page, logout_page, styles=styles)
556
+ def _fragment_navbar(self, natives_page_data, login_page, account_page, settings_page, logout_page,
557
+ styles: str | None = None):
558
+ new_page_id = self._standalone_navbar(natives_page_data, login_page, account_page, settings_page, logout_page,
559
+ styles=styles)
592
560
 
593
561
  return new_page_id
594
562
 
595
- def _standalone_navbar(self, natives_page_data, login_page, account_page, settings_page, logout_page, styles: str | None = None) -> StreamlitPage:
563
+ def _standalone_navbar(self, natives_page_data, login_page, account_page, settings_page, logout_page,
564
+ styles: str | None = None) -> StreamlitPage:
596
565
  page = st_navigation(
597
566
  natives_page_data,
598
567
  section_info={
599
568
  "Reports": {"icon": ":material/assessment:"},
600
569
  "Tools": {"icon": ":material/extension:"}
601
570
  },
602
- position_mode=self._navbar_mode if self._check_login_callback() else "hidden", sticky_nav=self._navbar_sticky,
571
+ position_mode=self._navbar_mode if self._check_login_callback() else "hidden",
572
+ sticky_nav=self._navbar_sticky,
603
573
  login_page=login_page, logout_page=logout_page,
604
574
  account_page=account_page,
605
575
  settings_page=settings_page,
@@ -609,8 +579,6 @@ class Multilit:
609
579
  themes_data=self._navbar_theme,
610
580
  theme_changer=self._navigation_theme_changer
611
581
  )
612
- if self.cross_session_clear and st.session_state["multilit_preserve_state"]:
613
- self._clear_session_values()
614
582
 
615
583
  return page
616
584
 
@@ -673,11 +641,13 @@ class Multilit:
673
641
  }}
674
642
  """
675
643
 
676
- styles = base_styles+styles
644
+ styles = base_styles + styles
677
645
  if self._within_fragment:
678
- page = self._fragment_navbar(natives_page_data, login_page, account_page, settings_page, logout_page, styles=styles)
646
+ page = self._fragment_navbar(natives_page_data, login_page, account_page, settings_page, logout_page,
647
+ styles=styles)
679
648
  else:
680
- page = self._standalone_navbar(natives_page_data, login_page, account_page, settings_page, logout_page, styles=styles)
649
+ page = self._standalone_navbar(natives_page_data, login_page, account_page, settings_page, logout_page,
650
+ styles=styles)
681
651
 
682
652
  # TODO: Send COI message to the component to update properly if willUmounted
683
653
  # set_page_id_visual("mainMultilitNavbar", new_app_id)
@@ -731,10 +701,9 @@ class Multilit:
731
701
  )
732
702
  raise e
733
703
 
734
- def _run_selected(self, page: STPageWrapper, has_loading=False):
704
+ def _run_selected(self, page: STPageWrapper, need_trigger_loading=False):
735
705
  page_label = page.title
736
706
  try:
737
- # print("Running", app_label)
738
707
  if self._verbose and st.session_state["multilit_uncaught_error"]:
739
708
  st.error(
740
709
  f'😭 Error triggered from page: **{page_label}**\n\n'
@@ -743,19 +712,12 @@ class Multilit:
743
712
  icon="🚨"
744
713
  )
745
714
 
746
- # with self._theme_change_container:
747
- # self._run_change_theme()
748
-
749
- if page.has_loading() and has_loading:
750
- loading_engine = self._loading_engine
751
- if page.loading_engine is not None:
752
- loading_engine = page.loading_engine
753
-
754
- with loading_engine.loading(label=page_label):
755
- with self._page_container:
715
+ if page.has_loading() and need_trigger_loading:
716
+ with self._loading_engine.loading(page.id, label=page_label):
717
+ with self._page_view:
756
718
  page.run()
757
719
  else:
758
- with self._page_container:
720
+ with self._page_view:
759
721
  page.run()
760
722
 
761
723
  st.session_state["multilit_uncaught_error"] = None
@@ -764,7 +726,13 @@ class Multilit:
764
726
 
765
727
  def _clear_session_values(self):
766
728
  for key in st.session_state:
767
- del st.session_state[key]
729
+ if (
730
+ not key.startswith("multilit_") and
731
+ key != self.login_info_session_key and
732
+ not key.startswith(NAVIGATION_KEY_PREFIX) and
733
+ not key.startswith(NAVBAR_KEY_PREFIX)
734
+ ):
735
+ del st.session_state[key]
768
736
 
769
737
  def set_guest(self, guest_name):
770
738
  """
@@ -790,7 +758,7 @@ class Multilit:
790
758
  if no_access_level is not None:
791
759
  self._no_access_level = int(no_access_level)
792
760
 
793
- def set_access(self, allow_access=0, access_user='', cache_access=False):
761
+ def set_access(self, allow_access=0, access_user=''):
794
762
  """
795
763
  Set the access permission and the assigned username for that access during the current session.
796
764
  Parameters
@@ -799,8 +767,6 @@ class Multilit:
799
767
  Value indicating if access has been granted, can be used to create levels of permission.
800
768
  access_user: str, None
801
769
  The username the access has been granted to for this session.
802
- cache_access: bool, False
803
- Save these access details to a browser cookie so the user will auto login when they visit next time.
804
770
  """
805
771
 
806
772
  # Set the global access flag
@@ -837,72 +803,7 @@ class Multilit:
837
803
  if user_access_level == 0 and username is None:
838
804
  self.set_access(guest_access_level, guest_username)
839
805
 
840
- # def get_cookie_manager(self):
841
- # if self._use_cookie_cache and self._cookie_manager is not None:
842
- # return self._cookie_manager
843
- # else:
844
- # return None
845
-
846
- # def _delete_cookie_cache(self):
847
- # if self._use_cookie_cache and self._cookie_manager is not None:
848
- # username_cache = self._cookie_manager.get('hyusername')
849
- # accesslevel_cache = self._cookie_manager.get('hyaccesslevel')
850
-
851
- # if username_cache is not None:
852
- # self._cookie_manager.delete('hyusername')
853
-
854
- # if accesslevel_cache is not None:
855
- # self._cookie_manager.delete('hyaccesslevel')
856
-
857
- # def _write_cookie_cache(self,hyaccesslevel,hyusername):
858
- # if self._use_cookie_cache and self._cookie_manager is not None:
859
- # if hyaccesslevel is not None and hyusername is not None:
860
- # self._cookie_manager.set('hyusername',hyusername)
861
- # self._cookie_manager.set('hyaccesslevel',hyaccesslevel)
862
-
863
- # def _read_cookie_cache(self):
864
- # if self._use_cookie_cache and self._cookie_manager is not None:
865
- # username_cache = self._cookie_manager.get('hyusername')
866
- # accesslevel_cache = self._cookie_manager.get('hyaccesslevel')
867
-
868
- # if username_cache is not None and accesslevel_cache is not None:
869
- # self.set_access(int(accesslevel_cache), str(username_cache))
870
-
871
- def run(self):
872
- """
873
- This method is the entry point for the MultiApp, just like a single Streamlit page, you simply setup the additional apps and then call this method to begin.
874
- """
875
- # process url navigation parameters
876
- # self._do_url_params()
877
-
878
- if self._banners is not None:
879
- if isinstance(self._banners, str):
880
- self._banners = [self._banners]
881
-
882
- if self._banner_spacing is not None and len(self._banner_spacing) == len(self._banners):
883
- cols = self._banner_container.columns(self._banner_spacing)
884
- for idx, im in enumerate(self._banners):
885
- if im is not None:
886
- if isinstance(im, Dict):
887
- cols[idx].markdown(
888
- next(iter(im.values())), unsafe_allow_html=True)
889
- else:
890
- cols[idx].image(im)
891
- else:
892
- if self._banner_spacing is not None and len(self._banner_spacing) != len(self._banners):
893
- logger.warning(
894
- 'Banner spacing spec is a different length to the number of banners supplied, using even spacing for each banner.'
895
- )
896
-
897
- cols = self._banner_container.columns([1] * len(self._banners))
898
- for idx, im in enumerate(self._banners):
899
- if im is not None:
900
- if isinstance(im, Dict):
901
- cols[idx].markdown(
902
- next(iter(im.values())), unsafe_allow_html=True)
903
- else:
904
- cols[idx].image(im)
905
-
806
+ def _main(self):
906
807
  page = self._build_run_nav_menu()
907
808
  page_id = self.get_page_id(page)
908
809
  # Verifico la autenticacion (self.login_info_session_key) y la autorizacion (allow_access)
@@ -932,8 +833,24 @@ class Multilit:
932
833
  raise ValueError(f"App id {page_id} not found in the list of apps")
933
834
 
934
835
  # Llegado a este punto, se ejecuta la pagina seleccionada
935
- has_loading = (has_changed_page() and self._only_loading_between_pages) or not self._only_loading_between_pages
936
- self._run_selected(page_wrapper, has_loading=has_loading)
836
+ page_changed = has_changed_page()
837
+ if page_changed:
838
+ if self.cross_session_clear and not st.session_state["multilit_preserve_state"]:
839
+ self._clear_session_values()
840
+
841
+ has_loading = (page_changed and self._only_loading_between_pages) or not self._only_loading_between_pages
842
+ self._run_selected(page_wrapper, need_trigger_loading=has_loading)
843
+
844
+ def run(self):
845
+ """
846
+ This method is the entry point for the MultiApp, just like a single Streamlit page, you simply setup the additional apps and then call this method to begin.
847
+ """
848
+ if self._nav_container is None:
849
+ self._nav_container = st.container(key=NAVIGATION_MULTILIT_KEY)
850
+
851
+ self._page_view = st.container()
852
+
853
+ self._main()
937
854
 
938
855
  def default_home_dashboard(self):
939
856
  def default_home_wrapper():
@@ -1077,4 +994,4 @@ def my_cool_function():
1077
994
  st_switch_page(self._login_id, native_way=self._use_st_navigation)
1078
995
 
1079
996
  self._do_logout = logout_wrapper
1080
- return logout_wrapper
997
+ return logout_wrapper