From 9321f9bc3f96d6e946caab944004549368ca7ce8 Mon Sep 17 00:00:00 2001 From: JoeZiminski Date: Thu, 31 Jul 2025 16:24:09 +0100 Subject: [PATCH 1/4] Only refresh data type checkbox on select datatype change. --- datashuttle/tui/tabs/create_folders.py | 17 ++++++++++++++--- datashuttle/tui/tabs/transfer.py | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/datashuttle/tui/tabs/create_folders.py b/datashuttle/tui/tabs/create_folders.py index 2ec76e728..e42430b7c 100644 --- a/datashuttle/tui/tabs/create_folders.py +++ b/datashuttle/tui/tabs/create_folders.py @@ -96,7 +96,8 @@ def compose(self) -> ComposeResult: yield Container( DatatypeCheckboxes( self.interface, id="create_folders_datatype_checkboxes" - ) + ), + id="create_folders_datatype_container", # ) yield Horizontal( Button( @@ -158,8 +159,18 @@ def on_button_pressed(self, event: Button.Pressed) -> None: async def refresh_after_datatypes_changed(self, ignore) -> None: """Redisplay the datatype checkboxes.""" - await self.recompose() - self.on_mount() + container = self.query_one( + "#create_folders_datatype_container", Container + ) + container.query_one("#create_folders_datatype_checkboxes").remove() + + await container.mount( + DatatypeCheckboxes( + self.interface, + create_or_transfer="create", + id="create_folders_datatype_checkboxes", + ) + ) @require_double_click def on_clickable_input_clicked( diff --git a/datashuttle/tui/tabs/transfer.py b/datashuttle/tui/tabs/transfer.py index 63dd78112..adb745f27 100644 --- a/datashuttle/tui/tabs/transfer.py +++ b/datashuttle/tui/tabs/transfer.py @@ -326,10 +326,19 @@ def on_button_pressed(self, event: Button.Pressed) -> None: async def refresh_after_datatype_changed(self, ignore): """Refresh Checkboxes after the shown datatypes have changed.""" - await self.recompose() - self.on_mount() - self.query_one("#transfer_custom_radiobutton").value = True - self.switch_transfer_widgets_display() + """Redisplay the datatype checkboxes.""" + container = self.query_one( + "#create_folders_datatype_container", Container + ) + container.query_one("#create_folders_datatype_checkboxes").remove() + + await container.mount( + DatatypeCheckboxes( + self.interface, + create_or_transfer="transfer", + id="create_folders_datatype_checkboxes", + ) + ) def on_custom_directory_tree_directory_tree_special_key_press( self, event: CustomDirectoryTree.DirectoryTreeSpecialKeyPress From f661a78e0cb8ea097734af0ffd4ab26e20fcb872 Mon Sep 17 00:00:00 2001 From: JoeZiminski Date: Thu, 31 Jul 2025 18:51:26 +0100 Subject: [PATCH 2/4] Only refresh data type checkbox on select datatype change refined. --- datashuttle/tui/tabs/create_folders.py | 9 +++++---- datashuttle/tui/tabs/transfer.py | 26 ++++++++++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/datashuttle/tui/tabs/create_folders.py b/datashuttle/tui/tabs/create_folders.py index e42430b7c..5347d34e5 100644 --- a/datashuttle/tui/tabs/create_folders.py +++ b/datashuttle/tui/tabs/create_folders.py @@ -159,10 +159,11 @@ def on_button_pressed(self, event: Button.Pressed) -> None: async def refresh_after_datatypes_changed(self, ignore) -> None: """Redisplay the datatype checkboxes.""" - container = self.query_one( - "#create_folders_datatype_container", Container - ) - container.query_one("#create_folders_datatype_checkboxes").remove() + container = self.query_one("#create_folders_datatype_container") + + await container.query_one( + "#create_folders_datatype_checkboxes" + ).remove() await container.mount( DatatypeCheckboxes( diff --git a/datashuttle/tui/tabs/transfer.py b/datashuttle/tui/tabs/transfer.py index adb745f27..446efe774 100644 --- a/datashuttle/tui/tabs/transfer.py +++ b/datashuttle/tui/tabs/transfer.py @@ -326,19 +326,33 @@ def on_button_pressed(self, event: Button.Pressed) -> None: async def refresh_after_datatype_changed(self, ignore): """Refresh Checkboxes after the shown datatypes have changed.""" - """Redisplay the datatype checkboxes.""" - container = self.query_one( - "#create_folders_datatype_container", Container + container = self.query_one("#transfer_params_container") + await container.query_one( + "#transfer_custom_datatype_checkboxes" + ).remove() + await container.query_one( + "#transfer_tab_displayed_datatypes_button" + ).remove() + + ( + Button( + "Displayed Datatypes", + id="transfer_tab_displayed_datatypes_button", + ), ) - container.query_one("#create_folders_datatype_checkboxes").remove() - await container.mount( DatatypeCheckboxes( self.interface, create_or_transfer="transfer", - id="create_folders_datatype_checkboxes", + id="transfer_custom_datatype_checkboxes", ) ) + await container.mount( + Button( + "Displayed Datatypes", + id="transfer_tab_displayed_datatypes_button", + ), + ) def on_custom_directory_tree_directory_tree_special_key_press( self, event: CustomDirectoryTree.DirectoryTreeSpecialKeyPress From 27c7d0444253c1b985440939d93231de6b442277 Mon Sep 17 00:00:00 2001 From: JoeZiminski Date: Thu, 31 Jul 2025 21:59:17 +0100 Subject: [PATCH 3/4] Add tests and centralise widget creation. --- datashuttle/tui/tabs/create_folders.py | 23 ++++++------ datashuttle/tui/tabs/transfer.py | 48 ++++++++++++++------------ tests/tests_tui/test_tui_datatypes.py | 18 ++++++++++ 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/datashuttle/tui/tabs/create_folders.py b/datashuttle/tui/tabs/create_folders.py index 5347d34e5..7e6686a23 100644 --- a/datashuttle/tui/tabs/create_folders.py +++ b/datashuttle/tui/tabs/create_folders.py @@ -94,9 +94,7 @@ def compose(self) -> ComposeResult: ) yield Label("Datatype(s)", id="create_folders_datatype_label") yield Container( - DatatypeCheckboxes( - self.interface, id="create_folders_datatype_checkboxes" - ), + self.get_datatype_checkboxes_widget(), id="create_folders_datatype_container", # ) yield Horizontal( @@ -158,20 +156,17 @@ def on_button_pressed(self, event: Button.Pressed) -> None: ) async def refresh_after_datatypes_changed(self, ignore) -> None: - """Redisplay the datatype checkboxes.""" + """Redisplay the datatype checkboxes. + + The widget must be completely removed and reinitialised. + """ container = self.query_one("#create_folders_datatype_container") await container.query_one( "#create_folders_datatype_checkboxes" ).remove() - await container.mount( - DatatypeCheckboxes( - self.interface, - create_or_transfer="create", - id="create_folders_datatype_checkboxes", - ) - ) + await container.mount(self.get_datatype_checkboxes_widget()) @require_double_click def on_clickable_input_clicked( @@ -546,3 +541,9 @@ def run_local_validation(self, prefix: Prefix) -> tuple[bool, str]: def update_directorytree_root(self, new_root_path: Path) -> None: """Refresh the tree through the reactive attribute `path`.""" self.query_one("#create_folders_directorytree").path = new_root_path + + def get_datatype_checkboxes_widget(self): + """Create the datatype checkboxes, centralised as used in multiple places.""" + return DatatypeCheckboxes( + self.interface, id="create_folders_datatype_checkboxes" + ) diff --git a/datashuttle/tui/tabs/transfer.py b/datashuttle/tui/tabs/transfer.py index 446efe774..d72f9200f 100644 --- a/datashuttle/tui/tabs/transfer.py +++ b/datashuttle/tui/tabs/transfer.py @@ -141,15 +141,8 @@ def compose(self) -> ComposeResult: ), # These are almost identical to create tab Label("Datatype(s)", id="transfer_datatype_label"), - DatatypeCheckboxes( - self.interface, - create_or_transfer="transfer", - id="transfer_custom_datatype_checkboxes", - ), - Button( - "Displayed Datatypes", - id="transfer_tab_displayed_datatypes_button", - ), + self.get_datatypes_widget(), + self.get_displayed_datatypes_button(), ] yield TransferStatusTree( @@ -325,7 +318,12 @@ def on_button_pressed(self, event: Button.Pressed) -> None: ) async def refresh_after_datatype_changed(self, ignore): - """Refresh Checkboxes after the shown datatypes have changed.""" + """Refresh Checkboxes after the shown datatypes have changed. + + The widget must be completely removed and reinitialised. + This means the button underneath it must also be removed and + re-added, or it ends up above the datatype checkbox widget. + """ container = self.query_one("#transfer_params_container") await container.query_one( "#transfer_custom_datatype_checkboxes" @@ -340,19 +338,8 @@ async def refresh_after_datatype_changed(self, ignore): id="transfer_tab_displayed_datatypes_button", ), ) - await container.mount( - DatatypeCheckboxes( - self.interface, - create_or_transfer="transfer", - id="transfer_custom_datatype_checkboxes", - ) - ) - await container.mount( - Button( - "Displayed Datatypes", - id="transfer_tab_displayed_datatypes_button", - ), - ) + await container.mount(self.get_datatypes_checkboxes_widget()) + await container.mount(self.get_displayed_datatypes_button()) def on_custom_directory_tree_directory_tree_special_key_press( self, event: CustomDirectoryTree.DirectoryTreeSpecialKeyPress @@ -434,3 +421,18 @@ def transfer_data(self) -> Worker[InterfaceOutput]: self.app.call_from_thread(self.reload_directorytree) return success, output + + def get_datatypes_checkboxes_widget(self): + """Create the datatype checkboxes, centralised as used in multiple places.""" + return DatatypeCheckboxes( + self.interface, + create_or_transfer="transfer", + id="transfer_custom_datatype_checkboxes", + ) + + def get_displayed_datatypes_button(self): + """Create the datatype button, centralised as used in multiple places.""" + return Button( + "Displayed Datatypes", + id="transfer_tab_displayed_datatypes_button", + ) diff --git a/tests/tests_tui/test_tui_datatypes.py b/tests/tests_tui/test_tui_datatypes.py index eafd33a89..a0fff512c 100644 --- a/tests/tests_tui/test_tui_datatypes.py +++ b/tests/tests_tui/test_tui_datatypes.py @@ -24,6 +24,8 @@ async def test_select_displayed_datatypes_create( pilot, project_name ) + self.fill_input(pilot, "#create_folders_subject_input", "sub-001") + # Open the datatypes screen await self.scroll_to_click_pause( pilot, @@ -124,6 +126,14 @@ async def test_select_displayed_datatypes_create( is False ) + # Check that input information is not deleted on refresh + assert ( + pilot.app.screen.query_one( + "#create_folders_subject_input" + ).value + == "sub-001" + ) + # Confirm also that narrow datatypes are not shown. with pytest.raises(BaseException): pilot.app.screen.query_one( @@ -148,6 +158,7 @@ async def test_select_displayed_datatypes_transfer( await self.scroll_to_click_pause( pilot, "#transfer_custom_radiobutton" ) + await self.fill_input(pilot, "#transfer_subject_input", "sub-001") await self.scroll_to_click_pause( pilot, "#transfer_tab_displayed_datatypes_button", @@ -159,6 +170,7 @@ async def test_select_displayed_datatypes_transfer( pilot.app.screen.query_one( "#displayed_datatypes_selection_list" ).toggle_all() + await self.scroll_to_click_pause( pilot, "#displayed_datatypes_save_button" ) @@ -174,6 +186,12 @@ async def test_select_displayed_datatypes_transfer( is False ) + # Check that input information is not deleted on refresh + assert ( + pilot.app.screen.query_one("#transfer_subject_input").value + == "sub-001" + ) + # Turn on a single checkbox and run a transfer, checking that # the underlying function is called correctly (monkeypatch) await self.scroll_to_click_pause( From 8413951d8c81167813909d2b0e8a649e6e801931 Mon Sep 17 00:00:00 2001 From: JoeZiminski Date: Thu, 31 Jul 2025 22:41:21 +0100 Subject: [PATCH 4/4] Fix get_datatypes_checkboxes_widget name. --- datashuttle/tui/tabs/transfer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datashuttle/tui/tabs/transfer.py b/datashuttle/tui/tabs/transfer.py index d72f9200f..a6362ad85 100644 --- a/datashuttle/tui/tabs/transfer.py +++ b/datashuttle/tui/tabs/transfer.py @@ -141,7 +141,7 @@ def compose(self) -> ComposeResult: ), # These are almost identical to create tab Label("Datatype(s)", id="transfer_datatype_label"), - self.get_datatypes_widget(), + self.get_datatypes_checkboxes_widget(), self.get_displayed_datatypes_button(), ]