Skip to content

Commit

Permalink
update textual (#66)
Browse files Browse the repository at this point in the history
* update textual

* add a few more pauses

* fix help-text from reviewer comment

* make ruff happy
  • Loading branch information
shapiromatron authored Aug 29, 2024
1 parent 3bb64ab commit 2ccba35
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 58 deletions.
1 change: 1 addition & 0 deletions bmds_ui/desktop/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


class BmdsDesktopTui(App):
ENABLE_COMMAND_PALETTE = False
CSS_PATH = "components/style.tcss"

BINDINGS: ClassVar = [
Expand Down
10 changes: 8 additions & 2 deletions bmds_ui/desktop/components/database_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from textual.validation import Function
from textual.widget import Widget
from textual.widgets import Button, Input, Label, Markdown
from textual.worker import Worker, WorkerState

from ..actions import create_django_db
from ..config import Config, Database, db_suffixes
Expand Down Expand Up @@ -150,6 +151,7 @@ class DatabaseFormModel(ModalScreen):
"""

def __init__(self, *args, db: Database | None, **kw):
kw.setdefault("name", "db_form")
self.db: Database | None = db
super().__init__(*args, **kw)

Expand Down Expand Up @@ -228,15 +230,19 @@ async def on_db_create(self) -> None:
config = Config.get()
self._create_django_db(config, db)

@work(exclusive=True, thread=True)
@work(exclusive=True, thread=True, group="modify-db")
def _create_django_db(self, config, db):
# sleeps are required for loading indicator to show/hide properly
self.app.call_from_thread(self.set_loading, True)
config.add_db(db)
Config.sync()
create_django_db(db)
self.app.call_from_thread(self.set_loading, False)
self.app.call_from_thread(self.dismiss, True)

def on_worker_state_changed(self, event: Worker.StateChanged) -> None:
"""Called when the worker state changes."""
if event.worker.group == "modify-db" and event.state == WorkerState.SUCCESS:
self.dismiss(True)

@on(Button.Pressed, "#db-update")
async def on_db_update(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/transforms/polyk/OutputTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class OutputTabs extends Component {
textToCopy={copyText}
onCopy={e => {
alert(
'Data copied to your clipboard! You can paste into Excel, or paste into an a BMDS analysis creating a new dataset and pressing the "Load dataset from Excel" button.'
'Data copied to your clipboard! For your Multistage/Multitumor analysis, return to the Data tab, select the "Load dataset from Excel" button, and paste the clipboard contents to create a new dataset. Or, paste the clipboard contents into Excel for further analysis.'
);
}}
className="btn btn-link my-1"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies = [

# desktop
"packaging~=24.0",
"textual==0.72.0",
"textual==0.78.0",
"whitenoise~=6.7.0",
]

Expand Down
92 changes: 38 additions & 54 deletions tests/desktop/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pathlib import Path

import pytest
from textual.widgets import TabbedContent
from textual.widgets import Button, TabbedContent
from textual.widgets._tabbed_content import ContentTab

from bmds_ui.desktop import components
Expand Down Expand Up @@ -125,18 +125,15 @@ async def test_db_form(self, rollback_get_app):
db_items = len(list(app.query(".db-edit")))

# open db modal creation
await pilot.click("#create-db")
await pilot.pause()
await assert_change_screen(pilot, app, app.query_one("#create-db"), "main", "db_form")

# cancel db modal creation
assert isinstance(app.screen, components.database_form.DatabaseFormModel)
await pilot.click("#db-edit-cancel")
await pilot.pause()
assert app.screen.name == "main"
await assert_change_screen(
pilot, app, app.query_one("#db-edit-cancel"), "db_form", "main"
)

# open db modal creation again
await pilot.click("#create-db")
await pilot.pause()
await assert_change_screen(pilot, app, app.query_one("#create-db"), "main", "db_form")

# fill out form w/ valid data
app.query_one("#name").value = f"Test {secrets.token_urlsafe(8)}"
Expand All @@ -146,72 +143,59 @@ async def test_db_form(self, rollback_get_app):
with tempfile.TemporaryDirectory() as temp_dir:
resolved_temp_dir = str(Path(temp_dir).resolve())

# create a new db
# CREATE
app.query_one("#path").value = resolved_temp_dir
await _wait_until_form_closes(pilot, app, "#db-create")
assert isinstance(app.screen, components.main.Main)
await assert_change_screen(
pilot, app, app.query_one("#db-create"), "db_form", "main"
)

# make sure a new one appears on the list page
newly_created = list(app.query(".db-edit"))
first = newly_created[0]
assert len(newly_created) == db_items + 1

# start the application!
start_db = list(app.query(".db-start"))
start_db[0].focus()
await pilot.press("enter")
await pilot.pause()

# stop the application!
stop_db = list(app.query(".db-stop"))
stop_db[0].focus()
await pilot.press("enter")

# edit the newly created db
first.focus()
await pilot.press("enter")
assert isinstance(app.screen, components.database_form.DatabaseFormModel)
# START/STOP APPLICATION
await click_first_button(pilot, app, app.query(".db-start"))
await click_first_button(pilot, app, app.query(".db-stop"))

# CANCEL UPDATE
await assert_change_screen(pilot, app, first, "main", "db_form")
assert app.query_one("#name").value.startswith("Test ")
assert app.query_one("#filename").value == "test-db.db"
assert app.query_one("#path").value == resolved_temp_dir
assert app.query_one("#description").value == "test description"
await assert_change_screen(
pilot, app, app.query_one("#db-edit-cancel"), "db_form", "main"
)

# update it and save (no changes)
await _wait_until_form_closes(pilot, app, "#db-edit-cancel")
assert isinstance(app.screen, components.main.Main)

# edit the newly created db
first.focus()
await pilot.press("enter")
assert isinstance(app.screen, components.database_form.DatabaseFormModel)

# UPDATE
await assert_change_screen(pilot, app, first, "main", "db_form")
app.query_one("#description").value = "test description #2"
await _wait_until_form_closes(pilot, app, "#db-update")
await pilot.pause()
assert isinstance(app.screen, components.main.Main)
await assert_change_screen(
pilot, app, app.query_one("#db-update"), "db_form", "main"
)

# requery; update caused screen layout and removed first attribute
newly_created = list(app.query(".db-edit"))
first = newly_created[0]

# delete it
first.focus()
await pilot.press("enter")
assert isinstance(app.screen, components.database_form.DatabaseFormModel)
await assert_change_screen(pilot, app, first, "main", "db_form")
await assert_change_screen(
pilot, app, app.query_one("#db-delete"), "db_form", "main"
)
assert len(list(app.query(".db-edit"))) == db_items

await pilot.click("#db-delete")
await pilot.pause()

assert len(list(app.query(".db-edit"))) == db_items
async def click_first_button(pilot, app, query):
next(iter(query)).focus()
await pilot.press("enter")
await pilot.pause()


async def _wait_until_form_closes(pilot, app, btn: str):
assert isinstance(app.screen, components.database_form.DatabaseFormModel)
await pilot.click(btn)
# wait for db creation to finish or max of 60 seconds
max = 1
while max < 60 and isinstance(app.screen, components.database_form.DatabaseFormModel):
await pilot.pause(delay=1)
max += 1
assert app.screen.name == "main"
async def assert_change_screen(pilot, app, btn: Button, current_screen: str, new_screen: str):
assert app.screen.name == current_screen
btn.focus()
await pilot.press("enter")
await pilot.pause()
assert app.screen.name == new_screen

0 comments on commit 2ccba35

Please sign in to comment.