-
-
Notifications
You must be signed in to change notification settings - Fork 606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce API to build Single Page Applications (SPAs) #2811
base: main
Are you sure you want to change the base?
Conversation
Integrated single page app into Client.open so navigation to SPA pages is redirected. Fixed bug with forward and backwards navigation between SPA pages. Collecting data from original pages to able to apply the original page title.
Integrated single page app into Client.open so navigation to SPA pages is redirected. Fixed bug with forward and backwards navigation between SPA pages. Collecting data from original pages to able to apply the original page title.
Fixed a bug which could occur when open was called before the UI was set up
…s registry in Client. General clean-up Added titles to sample app Added docu to SPA
4b89fb3
to
13f29ac
Compare
…the structure of the root page, the possibility to override the class and implement custom routing and to react to the creation of sessions. * Added samples for the single page router * Refactored the Login sample with the new possibilities and making use of Pydantic as an example for a cleaner code base
Thank you @Alyxion. There are a lot of interesting things in here. While you are right that a certain kind of applications my want to combine SPA and "per tab storage", it would make review and discussions simpler if you could create two separate pull requests for these features. |
…in the current Client instance - which in practice means "per browser tab".
Moved context import to top of the file
Added support for query and URL path parameters such as required by the modularization example. https://github.com/Alyxion/nicegui/blob/feature/client_data/examples/modularization/main.py works really like a charm now in regards of user experience when switching pages. At the moment it still throws a "Found top level layout element "Header" inside element "SinglePageRouterFrame". Top level layout elements should not be nested but must be direct children of the page content. This will be raising an exception in NiceGUI 1.5" warning due to the fact that it does not know yet that it actually is in the page content in that case. Update: Fixed the warning. PageLayout now also accepts the SPA root as valid parent for top level elements. |
Thanks for your explanations @Alyxion. It helped me to further work on the code. Besides more type fixes, I also did some renaming which (hopefully) conveys the purpose of variables/functions better. I also got more insights and gathered some new questions. To help us keep track, here is a list of all my open points at the moment:
|
Sure, I will have a look next weekend.
At least fully agree regarding the "super complex". It were much appreciated though if after all refactoring of the next weeks and removing the official OOP implementation no all preparations were completely wiped and thus making it impossible for us to "attach" (as external component) a way to make it object oriented. Especially the property SinglePageRouterConfig.router_class - which could of course be made protected - and the SinglePageRouter's resolve_target method. As we have already a project using them and I would like to avoid having to fork for another coupls of months it were helpful if had the chance to inofficially add it in the meantime without having to fork or using any dirty global function overwrites etc.
Yes, that should be easily doable.
I get your point and I feel the same, will review it. The thing is here of course that the router by itself can not know about suboulets etc., at least not without e.g. copying some of the data to each new Router from the Outlet so it knows all valid paths.
Actually we only need the "frame" per client. I just tried to separate UI and routing logic here. Regarding the app.storage.client concept: Yes and No. The (per level) current user_data gets automatically wiped if e.g. one outlet "stage" is left, e.g. in /a you add the menu bar, in /a/b you also add a footer and in /a/b/c an add. As they are currently stored in the SinglePageRouter they (e.g. the footer and add also get automatically wiped, once e.g. you navigate back to /a. As it's everything else than unlikely that such things also point to UI components here this implicitly ensures no links to old zombies are kept alive.
I struggled with that one back then but the FastAPI error was so cryptic that I could not figure out why I could not pass the request data directly into the page functions / API endpoints. |
Experiment with allowing outlets without yield statement
…e/client_data # Conflicts: # examples/authentication_spa/main.py
|
Hi! |
# Conflicts: # nicegui/client.py
Hello nistvan and sorry for the very late reply but the non-digital life needs me at the moment at 110%, so the state froze here unfortunately a little bit. At the end of the days its of course zaubezeugs decision if/when it will find its way into the main branch. The "only" two major flaws I still see right now is:
Other than that there was still a discussion going on if there shall be a clean separation between functions which just provide a template (e.g. ui.outlet or Outlet.outlet), so containing a yield, and functions which contain just the final page. (decorated via outlet.view). Rodja provided a suggestion for merging both in one decorator but that one has issues yet. As for now as we cruicially need the feature internally at my company we maintain a separate repo but hopefully find the time soon to finalize it. Anyways I just merged all recent changes yesterday again into the PR so its in synch with the newest main branch state again. |
|
…ence * Caught the case when navigating from a non-SPA page to an SPA page in client.open
any plans for this PR? |
Yes, we really want to merge this. I still need to find the time for another round of review. Especially we need to make a decision about the separation between view and outlet. |
NiceGUI is for us at Lechler a really awesome solution and step forward from Streamlit in regards of the visualization of live and streaming data as it puts the dev far more in control of which sub elements and page regions are updated when.
On the other hand it is still lacking three for us very crucial features Streamlit offers:
This (still work in progress) pull request tries to resolve at least most of the points above. It shall not yet resolve the situation that a user has an unstable internet connection and thus looses the connection to a server completely and needs to reconnect.
Persistent connection
In a scenario where you want to serve your NiceGUI solution not to hundreds of users there is after a certain point no way around scaling the solution over multiple processes, CPUs or over multiple servers.
If you need to load/keep alive large amounts of data per user w/o involving an external database this requires that the whole user session, even between page changes, is bound to one single process on one specific server. Streamlits uses a SPA approach here thus it creates a WebSockets connection once and all follow-up page and tab changes are just virtual thus changing the URL and browser history in the browser using pushstate but never really loading a new page using GET.
As discussed in the Add app.storage.tab or similar (1308) and in Discord there are several use cases where this is crucial to retain in-memory data on a "per session" basis, see below, which consequently requires that there is such a session in the first place.
Per tab storage
A data storage possibility per tab is cruicial to enable the user to create multiple app instances with different login credentials, configurations and views on a per tab basis. This is on purpose volatile so that user-credentials, critical business data etc. are gone once the browser tab was closed and the connection timed out. This shall match the current behavior of st.session_state.
In-memory storage of complex objects
The possibility to store living, non-JSON compatible objects such as Pandas tables, ML model weights etc. on a "per tab" basis and make them as easy accessible among different pages, global helper classes etc. as currently app.storage.user.
Update: Extracted the app.storage.session feature into a separate pull request 2820