Skip to content

Commit e9c682b

Browse files
authored
feat(bookmarking): Add session.bookmark.show_bookmark_url_modal() (#1922)
1 parent 3f03f93 commit e9c682b

File tree

8 files changed

+255
-465
lines changed

8 files changed

+255
-465
lines changed

shiny/bookmark/_bookmark.py

Lines changed: 194 additions & 370 deletions
Large diffs are not rendered by default.

shiny/bookmark/_save_state.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ def __init__(
4343
self.dir = None # This will be set by external functions.
4444
self.values = {}
4545

46-
self._always_exclude: list[str] = []
47-
4846
async def _call_on_save(self):
4947
# Allow user-supplied save function to do things like add state$values, or
5048
# save data to state dir.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from starlette.requests import Request
2+
3+
from shiny import App, Inputs, Outputs, Session, reactive, ui
4+
5+
6+
def app_ui(request: Request):
7+
return ui.page_fluid(
8+
ui.input_radio_buttons("letter", "Choose a letter", choices=["A", "B", "C"]),
9+
)
10+
11+
12+
def server(input: Inputs, ouput: Outputs, session: Session):
13+
14+
@reactive.effect
15+
@reactive.event(input.letter, ignore_init=True)
16+
async def _():
17+
await session.bookmark()
18+
19+
20+
app = App(app_ui, server, bookmark_store="url")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import re
2+
3+
from playwright.sync_api import Page, expect
4+
5+
from shiny.playwright.controller import InputRadioButtons
6+
from shiny.run import ShinyAppProc
7+
8+
9+
def test_bookmark_modules(page: Page, local_app: ShinyAppProc):
10+
11+
page.goto(local_app.url)
12+
13+
letter = InputRadioButtons(page, "letter")
14+
letter.expect_selected("A")
15+
letter.set("C")
16+
17+
expect(page.locator("div.modal-body > textarea")).to_have_value(
18+
re.compile(r"letter=%22C%22")
19+
)
20+
21+
assert "?" not in page.url

tests/playwright/shiny/bookmark/modules/app-core-recursive.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def mod_btn(idx: int = 1):
2929
width="200px",
3030
),
3131
ui.hr(),
32-
mod_btn(f"sub{idx}", idx - 1) if idx > 0 else None,
32+
mod_btn(f"sub{idx - 1}", idx - 1) if idx > 0 else None,
3333
)
3434

3535

@@ -55,7 +55,6 @@ def value():
5555
@reactive.effect
5656
@reactive.event(input.btn1, input.btn2, input.dyn1, input.dyn2, ignore_init=True)
5757
async def _():
58-
# print("app-Bookmarking!")
5958
await session.bookmark()
6059

6160
session.bookmark.exclude.append("btn2")
@@ -68,7 +67,6 @@ def _(state: BookmarkState) -> None:
6867

6968
@session.bookmark.on_restore
7069
def _(restore_state: RestoreState) -> None:
71-
# print("app-Restore state:", restore_state.values)
7270

7371
if "btn2" in restore_state.values:
7472

@@ -79,14 +77,16 @@ def _(restore_state: RestoreState) -> None:
7977
ui.update_radio_buttons("dyn2", selected=restore_state.values["dyn2"])
8078

8179
if idx > 0:
82-
btn_server(f"sub{idx}", idx - 1)
80+
btn_server(f"sub{idx - 1}", idx - 1)
81+
else:
82+
# Attempt to call on_bookmarked at the very end of the proxy chain
83+
session.bookmark.on_bookmarked(session.bookmark.update_query_string)
8384

8485

85-
k = 2
86+
k = 4
8687

8788

8889
def app_ui(request: Request) -> ui.Tag:
89-
# print("app-Making UI")
9090
return ui.page_fixed(
9191
ui.output_code("bookmark_store"),
9292
"Click Buttons to update bookmark",
@@ -103,23 +103,6 @@ def server(input: Inputs, output: Outputs, session: Session):
103103
def bookmark_store():
104104
return f"{session.bookmark.store}"
105105

106-
@session.bookmark.on_bookmark
107-
async def on_bookmark(state: BookmarkState) -> None:
108-
print(
109-
"app-On Bookmark",
110-
"\nInputs: ",
111-
await state.input._serialize(exclude=state.exclude, state_dir=None),
112-
"\nValues: ",
113-
state.values,
114-
"\n\n",
115-
)
116-
# session.bookmark.update_query_string()
117-
118-
pass
119-
120-
session.bookmark.on_bookmarked(session.bookmark.update_query_string)
121-
# session.bookmark.on_bookmarked(session.bookmark.show_modal)
122-
123106

124107
SHINY_BOOKMARK_STORE: Literal["url", "server"] = os.getenv(
125108
"SHINY_BOOKMARK_STORE", "url"

tests/playwright/shiny/bookmark/modules/app-core.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ def mod_btn(idx: int):
3030
ui.output_ui("ui_html"),
3131
ui.output_code("value"),
3232
width="200px",
33-
# fill=True,
34-
# fillable=True,
35-
# height="75px",
3633
),
3734
ui.hr(),
3835
)
@@ -60,7 +57,6 @@ def value():
6057
@reactive.effect
6158
@reactive.event(input.btn1, input.btn2, input.dyn1, input.dyn2, ignore_init=True)
6259
async def _():
63-
# print("app-Bookmarking!")
6460
await session.bookmark()
6561

6662
session.bookmark.exclude.append("btn2")
@@ -73,7 +69,6 @@ def _(state: BookmarkState) -> None:
7369

7470
@session.bookmark.on_restore
7571
def _(restore_state: RestoreState) -> None:
76-
# print("app-Restore state:", restore_state.values)
7772

7873
if "btn2" in restore_state.values:
7974

@@ -84,53 +79,29 @@ def _(restore_state: RestoreState) -> None:
8479
ui.update_radio_buttons("dyn2", selected=restore_state.values["dyn2"])
8580

8681

87-
k = 2
82+
k = 4
8883

8984

9085
def app_ui(request: Request) -> ui.Tag:
91-
# print("app-Making UI")
9286
return ui.page_fixed(
9387
ui.output_code("bookmark_store"),
9488
"Click Button to update bookmark",
95-
# ui.input_action_button("btn", "Button"),
9689
*[mod_btn(f"mod{i}", i) for i in reversed(range(k))],
97-
# ui.input_radio_buttons("btn", "Button", choices=["a", "b", "c"], selected="a"),
98-
# ui.output_code("code"),
99-
# ui.input_bookmark_button(),
10090
)
10191

10292

10393
# Needs access to the restore context to the dynamic UI
10494
def server(input: Inputs, output: Outputs, session: Session):
10595

96+
session.bookmark.on_bookmarked(session.bookmark.update_query_string)
97+
10698
@render.code
10799
def bookmark_store():
108100
return f"{session.bookmark.store}"
109101

110102
for i in reversed(range(k)):
111103
btn_server(f"mod{i}", i)
112104

113-
@session.bookmark.on_bookmark
114-
async def on_bookmark(state: BookmarkState) -> None:
115-
# print(
116-
# "app-On Bookmark",
117-
# "\nInputs: ",
118-
# await state.input._serialize(exclude=state.exclude, state_dir=None),
119-
# "\nValues: ",
120-
# state.values,
121-
# "\n\n",
122-
# )
123-
# session.bookmark.update_query_string()
124-
125-
pass
126-
127-
session.bookmark.on_bookmarked(session.bookmark.update_query_string)
128-
# session.bookmark.on_bookmarked(session.bookmark.show_modal)
129-
130-
# @render.code
131-
# def code():
132-
# return f"{input.btn()}"
133-
134105

135106
SHINY_BOOKMARK_STORE: Literal["url", "server"] = os.getenv(
136107
"SHINY_BOOKMARK_STORE", "url"

tests/playwright/shiny/bookmark/modules/app-express.py

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@
1515
app_opts(bookmark_store=SHINY_BOOKMARK_STORE)
1616

1717

18+
@session.bookmark.on_bookmarked
19+
async def _(url: str):
20+
await session.bookmark.update_query_string(url)
21+
22+
1823
@render.code
1924
def bookmark_store():
2025
return f"{session.bookmark.store}"
2126

2227

2328
@module
24-
def recursive_mod(input: Inputs, output: Outputs, session: Session, recurse: int = 3):
29+
def ex_mod(input: Inputs, output: Outputs, session: Session, recurse: int = 3):
2530

2631
ui.h3(f"Module {recurse}")
2732
with ui.layout_column_wrap(width="200px"):
@@ -84,38 +89,6 @@ def _(restore_state: RestoreState) -> None:
8489

8590
"Click Button to update bookmark"
8691

87-
k = 2
92+
k = 4
8893
for i in reversed(range(k)):
89-
recursive_mod(f"mod{i}", i)
90-
91-
92-
# ui.input_radio_buttons("btn", "Button", choices=["a", "b", "c"], selected="a")
93-
94-
95-
# @render.code
96-
# def code():
97-
# return f"{input.btn()}"
98-
99-
100-
# ui.input_bookmark_button()
101-
102-
103-
# @session.bookmark.on_bookmark
104-
# async def on_bookmark(state: BookmarkState) -> None:
105-
# print(
106-
# "app-On Bookmark",
107-
# "\nInputs: ",
108-
# await state.input._serialize(exclude=state.exclude, state_dir=None),
109-
# "\nValues: ",
110-
# state.values,
111-
# "\n\n",
112-
# )
113-
# # session.bookmark.update_query_string()
114-
115-
116-
@session.bookmark.on_bookmarked
117-
async def _(url: str):
118-
await session.bookmark.update_query_string(url)
119-
120-
121-
# session.bookmark.on_bookmarked(session.bookmark.show_modal)
94+
ex_mod(f"mod{i}", i)

tests/playwright/shiny/bookmark/modules/test_bookmark_modules.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
"app_name,mod0_key,mod1_key",
1313
[
1414
# Express mode
15-
("app-express.py", "mod0", "mod1"),
15+
("app-express.py", "mod0", "mod3"),
1616
# Core mode
17-
("app-core.py", "mod0", "mod1"),
17+
("app-core.py", "mod0", "mod3"),
1818
# Recursive modules within core mode
19-
("app-core-recursive.py", "mod1-sub1", "mod1"),
19+
("app-core-recursive.py", "mod3", "mod3-sub2-sub1-sub0"),
2020
],
2121
)
2222
@pytest.mark.parametrize("bookmark_store", ["url", "server"])

0 commit comments

Comments
 (0)