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.
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/PKG-INFO +1 -1
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/PKG-INFO +1 -1
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/app_wrapper.py +1 -2
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/loading_engine.py +22 -14
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/multilit.py +116 -199
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/LICENSE +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/README.md +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/setup.cfg +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/setup.py +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/SOURCES.txt +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/dependency_links.txt +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/requires.txt +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_framework_multilit.egg-info/top_level.txt +0 -0
- {streamlit_framework_multilit-0.7.12 → streamlit_framework_multilit-0.7.13}/streamlit_plugins/framework/multilit/__init__.py +0 -0
|
@@ -13,11 +13,10 @@ class STPageWrapper:
|
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
def __init__(self, st_page: StreamlitPage, with_loader=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,
|
|
14
|
+
self, loader: BaseLoader,
|
|
15
15
|
**run_loader_kwargs
|
|
16
16
|
):
|
|
17
|
-
self.
|
|
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.
|
|
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.
|
|
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,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
self.
|
|
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,
|
|
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
|
-
|
|
51
|
+
loader_container_key=loader_container_key,
|
|
50
52
|
**loader_params,
|
|
51
53
|
loader_lib=loader_lib
|
|
52
54
|
)
|
|
53
55
|
|
|
54
|
-
def
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
358
|
-
|
|
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
|
-
|
|
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 =
|
|
335
|
+
preserve_state = False
|
|
374
336
|
else:
|
|
375
|
-
preserve_state =
|
|
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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
page_loader or self.
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
591
|
-
|
|
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,
|
|
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",
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
747
|
-
|
|
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.
|
|
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
|
-
|
|
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=''
|
|
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
|
-
|
|
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
|
-
|
|
936
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|