Skip to content

Commit 51693b8

Browse files
authored
feat(bookmarking): Add await session.bookmark.get_bookmark_url() (#1919)
1 parent 319088e commit 51693b8

File tree

1 file changed

+91
-55
lines changed

1 file changed

+91
-55
lines changed

shiny/bookmark/_bookmark.py

+91-55
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,26 @@ async def update_query_string(
180180
"""
181181
...
182182

183+
@abstractmethod
184+
async def get_bookmark_url(self) -> str | None:
185+
"""
186+
Get the URL of the current bookmark state
187+
188+
This method should return the full URL, including the query string.
189+
190+
As a side effect, all `on_bookmark` callbacks will be invoked to allow the
191+
bookmark state to be modified before it is serialized. This will cause the
192+
bookmark state to be serialized to disk when `session.bookmark.store ==
193+
"server"`.
194+
195+
Returns
196+
-------
197+
:
198+
The full URL of the current bookmark state, including the query string.
199+
`None` if bookmarking is not enabled.
200+
"""
201+
...
202+
183203
@abstractmethod
184204
async def do_bookmark(self) -> None:
185205
"""
@@ -385,66 +405,76 @@ def _get_bookmark_exclude(self) -> list[str]:
385405
# Remove duplicates
386406
return list(set([*self.exclude, *scoped_excludes]))
387407

408+
async def get_bookmark_url(self) -> str | None:
409+
if self.store == "disable":
410+
return None
411+
412+
# ?withLogErrors
413+
from ..bookmark._bookmark import BookmarkState
414+
from ..session import session_context
415+
416+
async def root_state_on_save(state: BookmarkState) -> None:
417+
with session_context(self._session):
418+
await self._on_bookmark_callbacks.invoke(state)
419+
420+
root_state = BookmarkState(
421+
input=self._session.input,
422+
exclude=self._get_bookmark_exclude(),
423+
on_save=root_state_on_save,
424+
)
425+
426+
if self.store == "server":
427+
query_string = await root_state._save_state(app=self._session.app)
428+
elif self.store == "url":
429+
query_string = await root_state._encode_state()
430+
# # Can we have browser storage?
431+
# elif self.store == "browser":
432+
# get_json object
433+
# get consistent storage value (not session id)
434+
# send object to browser storage
435+
# return server-like-id url value
436+
else:
437+
raise ValueError("Unknown bookmark store: " + self.store)
438+
439+
clientdata = self._session.clientdata
440+
441+
port = str(clientdata.url_port())
442+
full_url = "".join(
443+
[
444+
clientdata.url_protocol(),
445+
"//",
446+
clientdata.url_hostname(),
447+
":" if port else "",
448+
port,
449+
clientdata.url_pathname(),
450+
"?",
451+
query_string,
452+
]
453+
)
454+
455+
return full_url
456+
388457
async def do_bookmark(self) -> None:
389458

390-
if self.store == "disable":
391-
# If you have a bookmark button or request a bookmark to be saved,
392-
# then it should be saved. (Present a warning telling author how to fix it)
393-
warnings.warn(
394-
"Saving the bookmark state has been requested. "
395-
'However, bookmarking is current set to `"disable"`. '
396-
"Please enable bookmarking by setting "
397-
"`shiny.App(bookmark_store=)` or "
398-
"`shiny.express.app_opts(bookmark_store=)`",
399-
stacklevel=2,
400-
)
401-
return
459+
from ..session import session_context
402460

403461
try:
404-
# ?withLogErrors
405-
from ..bookmark._bookmark import BookmarkState
406-
from ..session import session_context
462+
full_url = await self.get_bookmark_url()
463+
464+
if full_url is None:
465+
# If you have a bookmark button or request a bookmark to be saved,
466+
# then it should be saved. (Present a warning telling author how to fix it)
467+
warnings.warn(
468+
"Saving the bookmark state has been requested. "
469+
'However, bookmarking is current set to `"disable"`. '
470+
"Please enable bookmarking by setting "
471+
"`shiny.App(bookmark_store=)` or "
472+
"`shiny.express.app_opts(bookmark_store=)`",
473+
stacklevel=2,
474+
)
475+
return
407476

408-
async def root_state_on_save(state: BookmarkState) -> None:
409-
with session_context(self._session):
410-
await self._on_bookmark_callbacks.invoke(state)
411-
412-
root_state = BookmarkState(
413-
input=self._session.input,
414-
exclude=self._get_bookmark_exclude(),
415-
on_save=root_state_on_save,
416-
)
417-
418-
if self.store == "server":
419-
query_string = await root_state._save_state(app=self._session.app)
420-
elif self.store == "url":
421-
query_string = await root_state._encode_state()
422-
# # Can we have browser storage?
423-
# elif self.store == "browser":
424-
# get_json object
425-
# get consistent storage value (not session id)
426-
# send object to browser storage
427-
# return server-like-id url value
428-
else:
429-
raise ValueError("Unknown bookmark store: " + self.store)
430-
431-
clientdata = self._session.clientdata
432-
433-
port = str(clientdata.url_port())
434-
full_url = "".join(
435-
[
436-
clientdata.url_protocol(),
437-
"//",
438-
clientdata.url_hostname(),
439-
":" if port else "",
440-
port,
441-
clientdata.url_pathname(),
442-
"?",
443-
query_string,
444-
]
445-
)
446-
447-
# If onBookmarked callback was provided, invoke it; if not call
477+
# If on_bookmarked callback was provided, invoke it; if not call
448478
# the default.
449479
if self._on_bookmarked_callbacks.count() > 0:
450480
with session_context(self._session):
@@ -573,6 +603,9 @@ async def update_query_string(
573603
) -> None:
574604
await self._session._parent.bookmark.update_query_string(query_string, mode)
575605

606+
async def get_bookmark_url(self) -> str | None:
607+
return await self._session._parent.bookmark.get_bookmark_url()
608+
576609
async def do_bookmark(self) -> None:
577610
await self._session._parent.bookmark.do_bookmark()
578611

@@ -617,6 +650,9 @@ async def update_query_string(
617650
# no-op within ExpressStub
618651
return None
619652

653+
async def get_bookmark_url(self) -> str | None:
654+
return None
655+
620656
async def do_bookmark(self) -> None:
621657
# no-op within ExpressStub
622658
return None

0 commit comments

Comments
 (0)