Skip to content

Commit ca9b4a8

Browse files
authored
Merge pull request #5298 from Textualize/fix-remove-tab
auto generate tab ids
2 parents 55818c5 + 98cc84d commit ca9b4a8

File tree

4 files changed

+201
-3
lines changed

4 files changed

+201
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Fixed infinite loop in `Widget.anchor` https://github.com/Textualize/textual/pull/5290
1313
- Restores the ability to supply console markup to command list https://github.com/Textualize/textual/pull/5294
1414
- Fixed delayed App Resize event https://github.com/Textualize/textual/pull/5296
15+
- Fixed issue with auto-generated tab IDs https://github.com/Textualize/textual/pull/5298
1516

1617
## [0.87.1] - 2024-11-24
1718

src/textual/widgets/_tabbed_content.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ def __init__(
332332
self.titles = [self.render_str(title) for title in titles]
333333
self._tab_content: list[Widget] = []
334334
self._initial = initial
335+
self._tab_counter = 0
335336
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
336337

337338
@property
@@ -357,6 +358,15 @@ def _set_id(content: TabPane, new_id: int) -> TabPane:
357358
content.id = f"tab-{new_id}"
358359
return content
359360

361+
def _generate_tab_id(self) -> int:
362+
"""Auto generate a new tab id.
363+
364+
Returns:
365+
An auto-incrementing integer.
366+
"""
367+
self._tab_counter += 1
368+
return self._tab_counter
369+
360370
def compose(self) -> ComposeResult:
361371
"""Compose the tabbed content."""
362372

@@ -368,7 +378,7 @@ def compose(self) -> ComposeResult:
368378
if isinstance(content, TabPane)
369379
else TabPane(title or self.render_str(f"Tab {index}"), content)
370380
),
371-
index,
381+
self._generate_tab_id(),
372382
)
373383
for index, (title, content) in enumerate(
374384
zip_longest(self.titles, self._tab_content), 1
@@ -424,7 +434,7 @@ def add_pane(
424434
if isinstance(after, TabPane):
425435
after = after.id
426436
tabs = self.get_child_by_type(ContentTabs)
427-
pane = self._set_id(pane, tabs.tab_count + 1)
437+
pane = self._set_id(pane, self._generate_tab_id())
428438
assert pane.id is not None
429439
pane.display = False
430440
return AwaitComplete(
Lines changed: 156 additions & 0 deletions
Loading

tests/snapshot_tests/test_snapshots.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
Tab,
3636
Tabs,
3737
TextArea,
38+
TabbedContent,
39+
TabPane,
3840
)
3941
from textual.widgets.text_area import BUILTIN_LANGUAGES, Selection, TextAreaTheme
4042
from textual.theme import Theme
@@ -2752,7 +2754,6 @@ async def run_before(pilot: Pilot) -> None:
27522754
snap_compare(TallSelectApp(), run_before=run_before)
27532755

27542756

2755-
27562757
def test_markup_command_list(snap_compare):
27572758
"""Regression test for https://github.com/Textualize/textual/issues/5276
27582759
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:
27692770

27702771
snap_compare(MyApp())
27712772

2773+
27722774
def test_app_resize_order(snap_compare):
27732775
"""Regression test for https://github.com/Textualize/textual/issues/5284
27742776
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:
28102812

28112813
snap_compare(SCApp())
28122814

2815+
2816+
def test_add_remove_tabs(snap_compare):
2817+
"""Regression test for https://github.com/Textualize/textual/issues/5215
2818+
You should see a TabbedContent with three panes, entitled 'tab-2', 'New tab' and 'New tab'"""
2819+
2820+
class ExampleApp(App):
2821+
BINDINGS = [
2822+
("r", "remove_pane", "Remove first pane"),
2823+
("a", "add_pane", "Add pane"),
2824+
]
2825+
2826+
def compose(self) -> ComposeResult:
2827+
with TabbedContent(initial="tab-2"):
2828+
with TabPane("tab-1"):
2829+
yield Label("tab-1")
2830+
with TabPane("tab-2"):
2831+
yield Label("tab-2")
2832+
yield Footer()
2833+
2834+
def action_remove_pane(self) -> None:
2835+
tabbed_content = self.query_one(TabbedContent)
2836+
tabbed_content.remove_pane("tab-1")
2837+
2838+
def action_add_pane(self) -> None:
2839+
tabbed_content = self.query_one(TabbedContent)
2840+
new_pane = TabPane("New tab", Label("new"))
2841+
tabbed_content.add_pane(new_pane)
2842+
2843+
snap_compare(ExampleApp(), press=["a", "r", "a"])

0 commit comments

Comments
 (0)