From a95c37be1e281847514bea2d3daffbbe3ea233ac Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 27 Nov 2024 17:03:22 +0000 Subject: [PATCH 1/3] auto generate tab ids --- src/textual/widgets/_tabbed_content.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/textual/widgets/_tabbed_content.py b/src/textual/widgets/_tabbed_content.py index 37630b05dc..2d625e7cd0 100644 --- a/src/textual/widgets/_tabbed_content.py +++ b/src/textual/widgets/_tabbed_content.py @@ -332,6 +332,7 @@ def __init__( self.titles = [self.render_str(title) for title in titles] self._tab_content: list[Widget] = [] self._initial = initial + self._tab_counter = 0 super().__init__(name=name, id=id, classes=classes, disabled=disabled) @property @@ -357,6 +358,15 @@ def _set_id(content: TabPane, new_id: int) -> TabPane: content.id = f"tab-{new_id}" return content + def _generate_tab_id(self) -> int: + """Auto generate a new tab id. + + Returns: + An auto-incrementing integer. + """ + self._tab_counter += 1 + return self._tab_counter + def compose(self) -> ComposeResult: """Compose the tabbed content.""" @@ -368,7 +378,7 @@ def compose(self) -> ComposeResult: if isinstance(content, TabPane) else TabPane(title or self.render_str(f"Tab {index}"), content) ), - index, + self._generate_tab_id(), ) for index, (title, content) in enumerate( zip_longest(self.titles, self._tab_content), 1 @@ -424,7 +434,7 @@ def add_pane( if isinstance(after, TabPane): after = after.id tabs = self.get_child_by_type(ContentTabs) - pane = self._set_id(pane, tabs.tab_count + 1) + pane = self._set_id(pane, self._generate_tab_id()) assert pane.id is not None pane.display = False return AwaitComplete( From 317019725bc937811a6e93eb266988dadc701cb3 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 27 Nov 2024 17:31:20 +0000 Subject: [PATCH 2/3] snapshot --- CHANGELOG.md | 1 + .../test_snapshots/test_add_remove_tabs.svg | 156 ++++++++++++++++++ tests/snapshot_tests/test_snapshots.py | 33 +++- 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 846f70b2f4..67c010193f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed infinite loop in `Widget.anchor` https://github.com/Textualize/textual/pull/5290 - Restores the ability to supply console markup to command list https://github.com/Textualize/textual/pull/5294 - Fixed delayed App Resize event https://github.com/Textualize/textual/pull/5296 +- Fixed issue with auto-generated tab IDs https://github.com/Textualize/textual/pull/5298 ## [0.87.1] - 2024-11-24 diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg new file mode 100644 index 0000000000..1ee003e694 --- /dev/null +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ExampleApp + + + + + + + + + + tab-2tab-3 +━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +tab-2                                                                            + + + + + + + + + + + + + + + + + + + + + r Remove first pane  a Add pane                                    ^p palette + + + diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index b2fcd41a1d..b8168676c3 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -35,6 +35,8 @@ Tab, Tabs, TextArea, + TabbedContent, + TabPane, ) from textual.widgets.text_area import BUILTIN_LANGUAGES, Selection, TextAreaTheme from textual.theme import Theme @@ -2752,7 +2754,6 @@ async def run_before(pilot: Pilot) -> None: snap_compare(TallSelectApp(), run_before=run_before) - def test_markup_command_list(snap_compare): """Regression test for https://github.com/Textualize/textual/issues/5276 You should see a command list, with console markup applied to the action name and help text.""" @@ -2769,6 +2770,7 @@ def on_mount(self) -> None: snap_compare(MyApp()) + def test_app_resize_order(snap_compare): """Regression test for https://github.com/Textualize/textual/issues/5284 You should see a placeholder with text "BAR", focused and scrolled down so it fills the screen. @@ -2810,3 +2812,32 @@ def on_resize(self) -> None: snap_compare(SCApp()) + +def test_add_remove_tabs(snap_compare): + """Regression test for https://github.com/Textualize/textual/issues/5215 + You should see a TabbedContent with two panes, entitled 'tab-2' and 'tab-3'""" + + class ExampleApp(App): + BINDINGS = [ + ("r", "remove_pane", "Remove first pane"), + ("a", "add_pane", "Add pane"), + ] + + def compose(self) -> ComposeResult: + with TabbedContent(initial="tab-2"): + with TabPane("tab-1"): + yield Label("tab-1") + with TabPane("tab-2"): + yield Label("tab-2") + yield Footer() + + def action_remove_pane(self) -> None: + tabbed_content = self.query_one(TabbedContent) + tabbed_content.remove_pane("tab-1") + + def action_add_pane(self) -> None: + tabbed_content = self.query_one(TabbedContent) + new_pane = TabPane("tab-3", Label("tab-3")) + tabbed_content.add_pane(new_pane) + + snap_compare(ExampleApp(), press=["a", "r"]) From 98cc84dae88dd9964a333b01ff941ade0da7113f Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 27 Nov 2024 18:41:27 +0000 Subject: [PATCH 3/3] better snapshot --- .../test_snapshots/test_add_remove_tabs.svg | 124 +++++++++--------- tests/snapshot_tests/test_snapshots.py | 6 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg index 1ee003e694..7f987a7129 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_add_remove_tabs.svg @@ -19,138 +19,138 @@ font-weight: 700; } - .terminal-1469451834-matrix { + .terminal-43154064-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1469451834-title { + .terminal-43154064-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1469451834-r1 { fill: #c5c8c6 } -.terminal-1469451834-r2 { fill: #ddedf9;font-weight: bold } -.terminal-1469451834-r3 { fill: #797979 } -.terminal-1469451834-r4 { fill: #e0e0e0 } -.terminal-1469451834-r5 { fill: #4f4f4f } -.terminal-1469451834-r6 { fill: #0178d4 } -.terminal-1469451834-r7 { fill: #ffa62b;font-weight: bold } -.terminal-1469451834-r8 { fill: #495259 } + .terminal-43154064-r1 { fill: #c5c8c6 } +.terminal-43154064-r2 { fill: #ddedf9;font-weight: bold } +.terminal-43154064-r3 { fill: #797979 } +.terminal-43154064-r4 { fill: #e0e0e0 } +.terminal-43154064-r5 { fill: #4f4f4f } +.terminal-43154064-r6 { fill: #0178d4 } +.terminal-43154064-r7 { fill: #ffa62b;font-weight: bold } +.terminal-43154064-r8 { fill: #495259 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ExampleApp + ExampleApp - - - - tab-2tab-3 -━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -tab-2                                                                            - - - - - - - - - - - - - - - - - - - - - r Remove first pane  a Add pane                                    ^p palette + + + + tab-2New tabNew tab +━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +tab-2                                                                            + + + + + + + + + + + + + + + + + + + + + r Remove first pane  a Add pane                                    ^p palette diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index b8168676c3..a6f3a8e36d 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2815,7 +2815,7 @@ def on_resize(self) -> None: def test_add_remove_tabs(snap_compare): """Regression test for https://github.com/Textualize/textual/issues/5215 - You should see a TabbedContent with two panes, entitled 'tab-2' and 'tab-3'""" + You should see a TabbedContent with three panes, entitled 'tab-2', 'New tab' and 'New tab'""" class ExampleApp(App): BINDINGS = [ @@ -2837,7 +2837,7 @@ def action_remove_pane(self) -> None: def action_add_pane(self) -> None: tabbed_content = self.query_one(TabbedContent) - new_pane = TabPane("tab-3", Label("tab-3")) + new_pane = TabPane("New tab", Label("new")) tabbed_content.add_pane(new_pane) - snap_compare(ExampleApp(), press=["a", "r"]) + snap_compare(ExampleApp(), press=["a", "r", "a"])