Skip to content

Commit 5286042

Browse files
committed
Merge branch 'main' into run-py-shiny-template-tests
2 parents 3614b3f + 3055517 commit 5286042

File tree

91 files changed

+2978
-2681
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+2978
-2681
lines changed

CHANGELOG.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### New features
1111

12+
* `ui.sidebar()` is now interactively resizable. (#2020)
13+
14+
* `ui.update_*()` functions now accept `ui.TagChild` (i.e., HTML) as input to the `label` and `icon` arguments. (#2020)
15+
16+
* `playwright.controller.InputActionButton` gains a `expect_icon()` method. As a result, the already existing `expect_label()` no longer includes the icon. (#2020)
17+
1218
### Improvements
1319

20+
* Improved the styling and readability of markdown tables rendered by `ui.Chat()` and `ui.MarkdownStream()`. (#1973)
21+
1422
* `selectize`, `remove_button`, and `options` parameters of `ui.input_select()` have been deprecated; use `ui.input_selectize()` instead. (Thanks, @ErdaradunGaztea!) (#1947)
1523

16-
* Improved the styling and readability of markdown tables rendered by `ui.Chat()` and `ui.MarkdownStream()`. (#1973)
24+
* Added `timeout_secs` parameter to `create_app_fixture` to allow testing apps with longer startup times. (#2033)
1725

1826
### Bug fixes
1927

28+
* Fixed an issue with `ui.Chat()` sometimes wanting to scroll a parent element. (#1996)
29+
2030
* Explicitly call out module usage in UI input bookmark button documentation. (#1983)
2131

2232
* Fix missing session when trying to display an error duing bookmarking. (#1984)
2333

24-
* Fixed an issue with `ui.Chat()` sometimes wanting to scroll a parent element. (#1996)
25-
2634

2735
## [1.4.0] - 2025-04-08
2836

@@ -50,6 +58,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5058

5159
### Bug fixes
5260

61+
* Fixed issue where apps run in Workbench were unexpectedly crashing. Apps running in Workbench will now have `ws_per_message_deflate=False` enforced. (#2005)
62+
5363
* Fixed an issue where the `<main>` areas of `ui.page_sidebar()` and `ui.page_navbar()` (with a `sidebar`) were made to be a fillable containers even when `fillable=False`. (#1816)
5464

5565
* Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891)

js/markdown-stream/markdown-stream.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ class MarkdownElement extends LightElement {
284284
while (el) {
285285
if (el.scrollHeight > el.clientHeight) return el;
286286
el = el.parentElement;
287-
if (el?.tagName === CHAT_CONTAINER_TAG) {
287+
if (el?.tagName?.toLowerCase() === CHAT_CONTAINER_TAG.toLowerCase()) {
288288
// This ensures that we do not accidentally scroll a parent element of the chat
289289
// container. If the chat container itself is scrollable, a scrollable element
290290
// would already have been identified.

shiny/_main.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import re
1010
import sys
1111
import types
12+
import warnings
1213
from pathlib import Path
1314
from typing import Any, Optional
1415

@@ -20,6 +21,7 @@
2021

2122
from . import __version__, _autoreload, _hostenv, _static, _utils
2223
from ._docstring import no_example
24+
from ._hostenv import is_workbench
2325
from ._typing_extensions import NotRequired, TypedDict
2426
from .bookmark._bookmark_state import shiny_bookmarks_folder_name
2527
from .express import is_express_app
@@ -399,6 +401,8 @@ def run_app(
399401

400402
maybe_setup_rsw_proxying(log_config)
401403

404+
_set_workbench_kwargs(kwargs)
405+
402406
uvicorn.run( # pyright: ignore[reportUnknownMemberType]
403407
app,
404408
host=host,
@@ -713,6 +717,18 @@ class ReloadArgs(TypedDict):
713717
reload_dirs: NotRequired[list[str]]
714718

715719

720+
def _set_workbench_kwargs(kwargs: dict[str, Any]) -> None:
721+
if is_workbench():
722+
if kwargs.get("ws_per_message_deflate"):
723+
# Workaround for nginx/uvicorn issue within Workbench
724+
# https://github.com/rstudio/rstudio-pro/issues/7368#issuecomment-2918016088
725+
warnings.warn(
726+
"Overwriting kwarg `ws_per_message_deflate=True` to `False` to avoid breaking issue in Workbench",
727+
stacklevel=2,
728+
)
729+
kwargs["ws_per_message_deflate"] = False
730+
731+
716732
# Check that the version of rsconnect supports Shiny Express; can be removed in the
717733
# future once this version of rsconnect is widely used. The dependency on "packaging"
718734
# can also be removed then, because it is only used here. (Added 2024-03)

shiny/_versions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
shiny_html_deps = "1.10.0.9001"
1+
shiny_html_deps = "1.11.1.9000"
22
bslib = "0.9.0.9000"
33
htmltools = "0.5.8.9000"
44
bootstrap = "5.3.1"

shiny/playwright/controller/_base.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,6 @@ def expect_label(
451451
"""
452452
Expect the label of the input button to have a specific value.
453453
454-
Note: This must include the icon if it is present!
455-
456454
Parameters
457455
----------
458456
value
@@ -461,7 +459,28 @@ def expect_label(
461459
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
462460
"""
463461

464-
self.expect.to_have_text(value, timeout=timeout)
462+
loc_label = self.loc.locator(".action-label")
463+
playwright_expect(loc_label).to_have_text(value, timeout=timeout)
464+
465+
def expect_icon(
466+
self,
467+
value: PatternOrStr,
468+
*,
469+
timeout: Timeout = None,
470+
) -> None:
471+
"""
472+
Expect the icon of the input button to have a specific value.
473+
474+
Parameters
475+
----------
476+
value
477+
The expected value of the icon.
478+
timeout
479+
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
480+
"""
481+
482+
loc_icon = self.loc.locator(".action-icon")
483+
playwright_expect(loc_icon).to_have_text(value, timeout=timeout)
465484

466485
def click(self, *, timeout: Timeout = None, **kwargs: object) -> None:
467486
"""

shiny/pytest/_fixture.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
def create_app_fixture(
3737
app: PurePath | str | list[PurePath | str],
3838
scope: ScopeName = "module",
39+
timeout_secs: float = 30,
3940
):
4041
"""
4142
Create a fixture for a local Shiny app directory.
@@ -70,6 +71,8 @@ def create_app_fixture(
7071
will be created once per module. See [Pytest fixture
7172
scopes](https://docs.pytest.org/en/stable/how-to/fixtures.html#fixture-scopes)
7273
for more details.
74+
timeout_secs
75+
The maximum number of seconds to wait for the app to become ready.
7376
7477
Returns
7578
-------
@@ -133,7 +136,7 @@ def get_app_path(request: pytest.FixtureRequest, app: PurePath | str):
133136
@pytest.fixture(scope=scope, params=app)
134137
def fixture_func(request: pytest.FixtureRequest):
135138
app_path = get_app_path(request, request.param)
136-
sa_gen = shiny_app_gen(app_path)
139+
sa_gen = shiny_app_gen(app_path, timeout_secs=timeout_secs)
137140
yield next(sa_gen)
138141

139142
else:
@@ -142,7 +145,7 @@ def fixture_func(request: pytest.FixtureRequest):
142145
@pytest.fixture(scope=scope)
143146
def fixture_func(request: pytest.FixtureRequest):
144147
app_path = get_app_path(request, app)
145-
sa_gen = shiny_app_gen(app_path)
148+
sa_gen = shiny_app_gen(app_path, timeout_secs=timeout_secs)
146149
yield next(sa_gen)
147150

148151
return fixture_func

shiny/ui/_input_action_button.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ def input_action_button(
6161
if "_add_ws" not in kwargs:
6262
kwargs["_add_ws"] = True
6363

64+
if icon is not None:
65+
icon = tags.span(icon, class_="action-icon")
66+
67+
if label is not None:
68+
label = tags.span(label, class_="action-label")
69+
6470
return tags.button(
6571
{"class": "btn btn-default action-button", "style": css(width=width)},
6672
icon,
67-
None if icon is None else " ",
6873
label,
6974
id=resolve_id(id),
7075
type="button",
@@ -114,8 +119,14 @@ def input_action_link(
114119
* :func:`~shiny.reactive.event`
115120
"""
116121

122+
if icon is not None:
123+
icon = tags.span(icon, class_="action-icon")
124+
125+
if label is not None:
126+
label = tags.span(label, class_="action-label")
127+
117128
return tags.a(
118-
{"class": "action-button"},
129+
{"class": "action-button action-link"},
119130
icon,
120131
label,
121132
id=resolve_id(id),

0 commit comments

Comments
 (0)