-
-
Notifications
You must be signed in to change notification settings - Fork 518
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
Add functionality to update browser url with parameters in order for users bookmark their views and settings #811
Comments
I've created a prototype to keep the keep a Parametrized Class in sync with the browser url parameters. This might be usefull for someone therefore I share it here. pnx.py """This module contains functionality to keep a param.Parametrized class
in sync with the browser url
"""
import json
import urllib
import param
import panel as pn
class UrlMixin:
"""This Mixin enables parameters from a param.Parametrized Class to be shown in the url or the
browser. http://example
Mix this class with the param.Parametrized class and add the set_browser_url_parameters HTML pane to
your app in order to get url updates
Example use case
class _Country(pnx.param.UrlMixin, param.Parameterized):
country = param.String()
@param.depends("country")
def set_browser_url_parameters(self):
return super().set_browser_url_parameters()
"""
def __init__(self):
"""Initializes from the browser url parameters"""
for key, value in pn.state.session_args.items():
if key in self._parameter_dict():
value_str = value[0].decode("utf8")
self.set_param(key, value_str)
def set_browser_url_parameters(self) -> pn.pane.HTML:
"""A HTML Pane. Should be included in the app in order
to update the browser url when a parameter changes.
Returns:
pn.pane.HTML -- A pane containing the javascript script to update the browser url
"""
return pn.pane.HTML(self._browser_url_parameters_script())
def _browser_url_parameters_script(self) -> str:
if len(self.get_param_values()) > 1:
state = f'{{param: "{self._urlencode()}"}}'
title = ""
url = f"?{self._urlencode()}"
return f"""<script>window.history.replaceState({state},"{title}","{url}");</script>"""
return ""
def _parameter_dict(self):
return {item[0]: item[1] for item in self.get_param_values() if item[0] != "name"}
def _urlencode(self):
return urllib.parse.urlencode(self._parameter_dict()) and pytests and a manual app to test test_url.py """Tests of the awesome_panel functionality"""
import importlib
import param
import pnx
import panel as pn
class _Country(pnx.param.UrlMixin, param.Parameterized):
country = param.String()
@param.depends("country")
def set_browser_url_parameters(self):
return super().set_browser_url_parameters()
def test_url():
country_url = _Country()
country_url.set_param(country="Denmark")
assert country_url._parameter_dict() == {"country": "Denmark"}
assert country_url._urlencode() == "country=Denmark"
assert (
country_url._browser_url_parameters_script()
== '<script>window.history.replaceState({param: "country=Denmark"},"","?country=Denmark");</script>'
)
def test_pn_url():
"""Manual Test"""
# Given
country_url = _Country()
text = """
Manual Tests
- opening [http://localhost:5006/test_url](http://localhost:5006/test_url) works without error
- opening [http://localhost:5006/test_url?country=](http://localhost:5006/test_url?country=) works without error
- opening [http://localhost:5006/test_url?country=Denmark](http://localhost:5006/test_url?country=Denmark) then the country widget parameter is set to Denmark
- Changing the country widget parameter to Norway changes the browser url to
[http://localhost:5006/test_url?country=Norway](http://localhost:5006/test_url?country=Norway)
"""
panel = pn.Column(country_url.param, text, country_url.set_browser_url_parameters)
panel.servable("test")
if __name__.startswith("bk_script"):
test_pn_url() |
I've just simplified and restated my feature request below. I would like to be able to keep the server app state in sync with the client app state via the browser url. I.e.
|
Making it simple to set parameters using URL arguments seems like a great idea and provides a lot of power. |
I think we should add a bokeh model which syncs the URL parameters and then add it automatically. An API I could imagine is something like: pn.state.url_params.sync(value=some_parameterized_object.param.value) |
Sounds good to me! |
Some inspiration might be found from the JS and the Dash https://dash.plot.ly/dash-core-components/location I would say we should provide a Location component with the same properties as the JS
|
I've added a Work in Progress pull request for this at #1101 |
I don't understand this api so thats why this is not what I've been providing code for. |
The location component has been merged. |
Introduction
I'm trying to build a multipage app using Panel.
My applications are typically some where the user can navigate and configure settings to get "views" most relevant to their specific use case like navigating to a "flow model" and filtering on the country "Norway".
When they have their view of interest they would like to be able to quickly navigate back to that specific view or share their view.
I belive the best way to enable this is to be able to bookmark a "view" and share at direct link. This is currently only partically supported in Panel (see workarounds below).
Solution
Add an Url widget to keep the "view" in sync with the url shown in the browser.
The api to set the browser url could be something like
There would be access to get and set the parameters including the full absolute_url
and the url can be watched for changes and handled in both Python and Javascript using all the normal functionality like
link
,jslink
andwatch
.Workarounds
You can serve multiple apps in Panel to get the
example.com/flow-model
effect. But then you no longer have an integrated, single page application.You can use code to generate a link with parameters and provide it to the user in a textbox or maybe via a "share" button. And then access the parameters the next time the user opens the page via
This should be useable allready now in panel. I just don't know how to watch this without creating a custom widget. And I have not learned how to do that yet. Maybe I should?
I can also get the url in Javascipt
Then I need to figure out how to get it in Python?
Additional Context
If for some reason changing the relative url is not a good idea just being able to set the url parameters in the browser would be very usefull on it's own. Then the page name could just be a parameter like
example.com/?page=flow-model&country=Norway
.The text was updated successfully, but these errors were encountered: