New Release Hydralit: Multi-page apps even nicer

Hi All, I’m excited to post after alot of work a new release of the Hydralit package for making multi-page applications. With a few new features and now with a dedicated custom responsive Navbar via Hydralit Components.

Latest features

  • Banners
app = HydraApp(title='Hydralit Explorer',
                favicon="🐙",hide_streamlit_markers=True, 
                use_banner_images=["./resources/left_banner.png",None,{'header':"<h1 style='text-align:center;padding: 0px 0px;color:gray;font-size:300%;'>Hydralit Explorer</h1>"},None,"./resources/right_banner.png"], 
                banner_spacing=[30,20,40,30,10]
            )
  • Compression behind download button
self.download_button(
dfdata,'data.zip',
'Download Zip',
use_compression=True,
css_formatting=dload_btn_style,
index=False,
compression='gzip')
  • Hydralit Navbar

The navbar works immediately with existing Hydralit apps, currently it doesn’t support the complex nav feature, however if you can live with a flatter menu, you’ll be rewarded with something alot prettier and configurable.

4 Likes

Just a quick note after a good question regarding using query parameters, Hydralit supports using query parameter navigation too!.

In fact, if you want to use the secure internal navigation as well as query parameter navigation at the same time, 3 lines of code in the parent (see the comment section USE QUERY PARAMETER NAVIGATION below) and 1 line in each of the child applications is all that is required. For example, the Hydralit example application can use query parameter navigation as well as internal by adding the 3 lines shown in the comments and the 1 line shown, at the top of the run method of each child app.

Using query parameters is not recommended if you are creating a secure app, as you are exposing the ability to by-pass any security checks in place, however Hydralit can use this method if you want, it won’t work when using a secure app, as being able to jump straight to a page within a secure app without authentication defeats the purpose of the security.

Using this, you could then bookmark any child app and jump to it directly, for example the parent app code for the Hydralit example with the 3 lines added that will allow query parameter navigation.

You can see the full code and a live running example of the original source below here.

from hydralit import HydraApp
import streamlit as st
import apps


if __name__ == '__main__':
    #this is the host application, we add children to it and that's it!
    app = HydraApp(title='Hydralit Data Explorer',favicon="🐙",nav_horizontal=True,hide_streamlit_markers=True)
  
   # The Home app, this is the default redirect if no target app is specified.
    app.add_app("Home", icon="🏠", app=apps.HomeApp(title='Home'),is_home=True)

    #add all your child apps here
    app.add_app("Cheat Sheet", icon="📚", app=apps.CheatApp(title="Cheat Sheet"))
    app.add_app("Sequency Denoising",icon="🔊", app=apps.WalshApp(title="Sequency Denoising"))
    app.add_app("Sequency (Secure)",icon="🔊🔒", app=apps.WalshAppSecure(title="Sequency (Secure)"))
    app.add_app("Solar Mach", icon="🛰️", app=apps.SolarMach(title="Solar Mach"))
    app.add_app("Spacy NLP", icon="⌨️", app=apps.SpacyNLP(title="Spacy NLP"))
    app.add_app("Uber Pickups", icon="🚖", app=apps.UberNYC(title="Uber Pickups"))
    app.add_app("Solar Mach", icon="🛰️", app=apps.SolarMach(title="Solar Mach"))

    #we want to have secure access for this HydraApp, so we provide a login application
    #optional logout label, can be blank for something nicer!
    #app.add_app("Login", apps.LoginApp(title='Login'),is_login=True) 

    # If the menu is cluttered, just rearrange it into sections!
    # completely optional, but if you have too many entries, you can make it nicer by using accordian menus
    complex_nav = {
        'Home': ['Home'],
        'Intro 🏆': ['Cheat Sheet',"Solar Mach"],
        'Hotstepper 🔥': ["Sequency Denoising","Sequency (Secure)"],
        'Models 🧩': ["Spacy NLP","Uber Pickups"],
    }

    # ----------USE QUERY PARAMETER NAVIGATION----------------------------------------
    # If we want to use query parameters to control the navigation, 
    # for example we could bookmark a specific app and jump straight to it.
    # --------------------------------------------------------------------------------
    query_params = st.experimental_get_query_params()
    if 'selected' in query_params:
      app.session_state.selected_app = (query_params['selected'])[0]
    # --------------------------------------------------------------------------------
    # At the top of the run() method of each child app, just 
    # add this one line and it will also update the query parameter regardless of the source of navigation
    # st.experimental_set_query_params(selected=self.title)

    #create a wrapper class
    # class MySmallApp(HydraHeadApp):

    # #wrap all your code in this method and you should be done
    #     def run(self):
    #         #--------now using query parameter nav as well as internal navigation

              st.experimental_set_query_params(selected=self.title)

    #         #-------------------existing untouched code------------------------------------------
    #         st.title('Small Application with a table and chart.')

    #         st.markdown("### Plot")
    #         df = create_table()

    #         st.line_chart(df)
    # --------------------------------------------------------------------------------

    # Run the Hydra
    app.run(complex_nav)
2 Likes

With the new release of the Hydralit Navbar, it almost seemed an after thought we have a new release of the Hydralit package.

Some new features include:

  • Support for a non-secure app in a secure app (like a signup app)
  • Full integration with the Hydralit Navbar that now supports complex nav! This means animated dropdown menus
  • Some bug fixes where app to app redirect was inconsistent
  • Full backwards compatibility with previous releases.

A requested feature was the ability to have something like a signup app within a secure app, this is now possible by a parameter to indicate a non-secure app and the use of negative access permissions, see the example repository and live demo.

NOTE: The demo only shows the ability to move between the login and a single non-secure app, the implementation of collecting and saving signup data and then validation of the login details needs to be done, see the comments in the code for more information.

I had downloaded your example code from github
when I was running secure_app.py, it reported that navbar_sticky=True in line 9 and is_unsecure=True are unexpected argument error.
And I got other errors:
TypeError: init() got an unexpected keyword argument ‘navbar_sticky’
Error details: [E050] Can’t find model ‘en_core_web_sm’. It doesn’t seem to be a Python package or a valid path to a data directory.
Error details: <urlopen error Tunnel connection failed: 403 URLBlocked>
An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.

It’s because the example uses the latest version of Hydralit (1.0.7), you have to upgrade your local version in order to use the new example, it is even in the requirements.txt of the example repository, the instructions to run the example do state to do a pip install -r requirements.txt before running for this exact reason.

If you either pip the requirements.txt of the example or, pip install -U hydralit, both will fix the issue. The example code isn’t meant to be backwards compatible when showcasing the new features.

Hi, this is great, I’m trying to create a multi page apps following your steps, which navi works wells, but in home page each app’s link looks not working, with error " Error details: There are multiple identical st.slider widgets with the same generated key", is there any workaround for this? thanks

Sounds like you need to run an update, pip install -U hydralit, as there was a bug in the 1.0.7 version where loading via the internal app links double loaded the target app, which makes that error appear. Please update to version 1.0.8 using, pip install -U hydralit and the issue should be resolved.

I am using Hydralit to migrate my publishing company website to Streamlit. Love it! Works great.

1 Like

@Probability , thanks for the suggestions, while when I upgraded hydralit to 1.0.8, problem still exist, looks target App loaded twice, 2nd one show an error message, 1st one did show up but not function, pls advise anything else may went wrong
, thanks again, this is very useful, which I’m able to combine all my small apps

If you could share some code, as that issue was definitely resolved in version 1.0.8, I’ve had 4 people confirm that 1.0.8 resolved that issue. The example project doesn’t double load the apps from those links, you can see it running here, this is the exact code from the example repo.GitHub - TangleSpace/hydralit-example

Hi Probability. I really like this and am exploring using it to replace my nearly two year old multi-page implementation. However I am getting the double load error if I click on the “button” in the Home page body just as described. The menu links work fine and only load once. I have checked that it is v1.0.8 and streamlit 0.88. The following stub prints once from the menu and twice from the button on the page.

class DwellTimeApp(HydraHeadApp):

def __init__(self, title = '', **kwargs):
    self.__dict__.update(kwargs)
    self.title = title
    
def run(self):
    print('running dwell')
    #run_dwell()
    return None

I am unable to reproduce the issue, I have created a new virtualenv, only installed hydralit (pip install -U hydralit), created a single file with the code below that contains two copies of your DwellApp and the most basic parent app with redirect buttons. You can see from the video, the pip freeze shows only the minimum installed from the environment creation and Hydralit install. I added a single line to your app so it would also show a message inside streamlit as well as the terminal, you can see if i hit the internal nav button, it only loads the app once (message in the terminal as well as in Streamlit), the same as if you click the menu, so I am not sure why you appear to have an issue, as you can create a new environment, virtualenv hytest, then pip install -U hydralit, and run the code below and see what happens, as this is the most basic test i could run and was unable to reproduce the error, so let me know how you go.

hytest

#-----------dwell child app----------------------------------------------------------
from hydralit import HydraHeadApp
import streamlit as st

class DwellTimeApp(HydraHeadApp):

    def __init__(self, title = '', **kwargs):
        self.__dict__.update(kwargs)
        self.title = title
        
    def run(self):
        st.info('running dwell')
        print('running dwell')
        #run_dwell()
        return None

#-------------------------------------------------------------------------------------

#-----------dwell 2 child app----------------------------------------------------------
from hydralit import HydraHeadApp
import streamlit as st

class DwellTimeApp2(HydraHeadApp):

    def __init__(self, title = '', **kwargs):
        self.__dict__.update(kwargs)
        self.title = title
        
    def run(self):
        st.info('running dwell 2')
        print('running dwell 2')
        #run_dwell()
        return None

#-------------------------------------------------------------------------------------


#-----------home child app------------------------------------------------------------
import streamlit as st
from hydralit import HydraHeadApp

class HomeApp(HydraHeadApp):


    def __init__(self, title = 'Hydralit Explorer', **kwargs):
        self.__dict__.update(kwargs)
        self.title = title

    def run(self):

        try:
            st.info('Home app')

            _,_,_, col_text,_ = st.columns([1,1,1,7,2])

            if col_text.button('Dwell➡️'):
                self.do_redirect('Dwell')

            if col_text.button('Dwell 2 ➡️'):
                self.do_redirect('Dwell 2')

        except Exception as e:
            st.error('Error details: {}'.format(e))

#--------------------------------------------------------------------------------------


#-----------parent app to run children-------------------------------------------------
from hydralit import HydraApp

if __name__ == '__main__':
    app = HydraApp(title='Hydralit Tester')

    app.add_app("Home", icon="🏠", app=HomeApp(title='Home'),is_home=True)
    app.add_app("Dwell", icon="📚", app=DwellTimeApp(title="Dwell App"))
    app.add_app("Dwell 2", icon="📚", app=DwellTimeApp2(title="Dwell App 2"))

    app.run()

#--------------------------------------------------------------------------------------

@Probability , I found out the problem come from “complex_nav”, if I removed complex_nav, both works, is there any hint for this? thanks

@Probability , correction, even there is no error shows up when I click “button”, but the app not function, whenever change a widget, will back to home page.

without seeing any code or details i am unable to provide any guidance, as you are the only person i’ve encountered to be having such issues, i can see there is a potential issue with the complex nav option when you are not using any login app, but removing the complex nav and leaving to a default, flat menu i am still unable to reproduce your issue. You can also see from the previous example, that using a flat menu with all the default, it works correctly, unless you have reproduced the steps i detailed in the response to knorthover, you must be having a more specific issue.

@Probability , thanks for the reply, after some time try, what I found out:

  1. I use your Github example and run it on local, I can duplicate the problem when change any streamlit widget within the app, which will re-direct to home page.

  2. When I set use_navbar = False, both are working, but navbar layout is totally different, I really like the original one.
    Hopefully this helps narrow down the issues.

That exact code is running here: https://hydralit-secure-sample.herokuapp.com/

The aren’t any issue with the home page buttons in this live running version, it must definitely be something in your environment. please ensure to pip install -r requirements.txt from the example. Like I said, I have no idea, if you are running the exact example from the repo, the same code is running in the live demo link without any issues and using the full complex navbar. What version of Python are you using? Also, if you could do a pip freeze on your environment and share with me, as it definitely sounds like a problem in your environment if you are having issues with the example repo, as there are atleast 30 people that have cloned it and running it locally without any issues.

@Probability , I’m sorry if I’m the only one facing issues, while when I try the live app in heroku above, see the same issue as well(whenever change a streamilt widget, will re-direct to home page), so this app can works totally locally, right? I’m connecting network through VPN though

I have no idea, as it sounds like your connection keeps resetting, if the live demo doesn’t work, that’s nothing to do with the code, or the environment. Yes, the code works fine completely offline. Sorry i can’t help, as it’s not a problem with the code, unless you are referring to the fact that when you nav from a button in an app, the menu moves to home,that is standard behaviour, it will change and load the app, but the menu will select the home item, that is normal as the ability to select items on the menu deep within a child app is unstable. Is that the issue? If that is the case, that is normal, as long as it loads the app, it is working fine then.

@Probability , it’s not that case, when click ‘button’ at home page, can re-direct to child app successfully, the problem is when play around the child app, the app disappeared, but when I set use_navbar=False, it’s working fine, but nav_bar format have changed.