From e17ebf30aad1a4854a1f74f94667b27d4171fedc Mon Sep 17 00:00:00 2001 From: Ocean Dekeyser Date: Thu, 22 Oct 2026 10:59:46 +0200 Subject: [PATCH] Tables fit the screen width (#89) The content column (and footer) grows from 896 to 1280 px, table cells wrap between words, and the email and GitHub columns may break anywhere, so the Users table no longer scrolls sideways to show Year and Status. Co-Authored-By: Claude Opus 5.5 --- docs/CHANGELOG.md | 17 +++++++++++++++++ frontend/src/pmp_frontend/theme.py | 18 +++++++++++++++--- frontend/src/pmp_frontend/users_page.py | 17 +++++++++++++++-- frontend/tests/test_navigation.py | 13 +++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8231859..36d0e22 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -16,6 +16,22 @@ Numbers like #24 are GitHub issues or pull requests on [vives-project-xp/Project Newest first. Each request has the same four parts: **Before**, **Asked**, **Changed**, **Where**. +### R13. Tables fit the screen (2026-10-22, #89, PR #90) + +**Before.** Page content was at most 896 px wide, and table cells never wrapped. The **Users** table (Name, Email, GitHub, Role, Programme, Year, Status) was wider than that, so on a laptop you had to **scroll to the right** to see Year and Status. + +**Asked.** *"change users table so it fits the whole screen, we have to go to the right to view year and status good, make it autoscale"*. + +**Changed.** +- **Wider pages:** the content of every page (and the footer) can now be up to 1280 px wide. Forms and cards keep their narrow width; tables and lists use the extra room. +- **Tables adapt to the screen:** + - table cells wrap between words; + - email addresses and GitHub names may break anywhere. + + Every table now fits without scrolling sideways. At 1366 px the Users table fits with one line per row. In an 800 px window it fits too: only the emails and GitHub names break over lines, and words stay whole. + +**Where.** `frontend/src/pmp_frontend/theme.py` (`CONTENT_WIDTH`, `BREAK_ANYWHERE`, table CSS), `users_page.py`; test in `frontend/tests/test_navigation.py`. + ### R12. Tidy the buttons on the Projects screen (2026-10-22, #81, PR #85) **Before.** The Projects screen had the heading and **five buttons on one row**: "Create repos for all Projects", "Check all members", "Create Trello boards for all Projects", "Check all Trello members" and "New Project". On a normal screen they wrapped onto several lines and looked cluttered. On a Project's page, the status, the Archive and Delete buttons and the "Open for choice" switch were **loose under the title**, and in the Members card the "Add a Student" select and the "Add Member" button were on separate lines. @@ -225,6 +241,7 @@ Newest first. "Live" means deployed to the VIVES VM by the Deploy workflow. "Mig |---|---|---|---| | Changed | Footer links and address from the environment (`FOOTER_*`) | #79 | #83 | | New | Top 3 screen: add a Student to a Project outside their Top 3 | #80 | #84 | +| Changed | Tables fit the screen: wider pages (1280 px), cells wrap, emails break (R13) | #89 | #90 | | Changed | Projects screen: GitHub ▾ / Trello ▾ menus; Status card on a Project's page | #81 | #85 | | New | This changelog (`docs/CHANGELOG.md`) | #82 | this PR | diff --git a/frontend/src/pmp_frontend/theme.py b/frontend/src/pmp_frontend/theme.py index 1e20dae..a9819bf 100644 --- a/frontend/src/pmp_frontend/theme.py +++ b/frontend/src/pmp_frontend/theme.py @@ -15,6 +15,12 @@ STATIC_DIR = Path(__file__).parent / "static" +# Wide enough for the tables on a laptop screen (#89); forms keep their own +# narrow cards. +CONTENT_WIDTH = "max-w-7xl" +# Table column classes for long values without spaces, such as email addresses. +BREAK_ANYWHERE = "break-anywhere" + # The footer's social links; their URLs come from the settings (#79). SOCIALS = ["Instagram", "TikTok", "YouTube", "LinkedIn"] # Bootstrap Icons (MIT, see static/icons/LICENSE-bootstrap-icons.txt), inlined so @@ -32,6 +38,10 @@ font-family: 'Poppins', Arial, sans-serif; color: {BLACK}; background: {SAND}; }} b, strong, h1, h2, h3, h4, .text-bold {{ font-weight: 600 !important; }} + /* Tables fit the screen instead of scrolling sideways (#89): cells wrap + between words; columns with BREAK_ANYWHERE (email addresses) anywhere. */ + .q-table td {{ white-space: normal; }} + .q-table td.break-anywhere {{ overflow-wrap: anywhere; }} """ @@ -63,7 +73,7 @@ def frame( if header is not None: ui.space() header() - with ui.column().classes("w-full max-w-4xl mx-auto p-6 gap-6"): + with ui.column().classes(f"w-full {CONTENT_WIDTH} mx-auto p-6 gap-6"): yield footer() @@ -78,7 +88,9 @@ def footer() -> None: .classes(f"bg-[{BLACK}] text-white px-6 py-4") .mark("footer") ): - with ui.row().classes("w-full max-w-4xl mx-auto items-center gap-x-6 gap-y-2"): + with ui.row().classes( + f"w-full {CONTENT_WIDTH} mx-auto items-center gap-x-6 gap-y-2" + ): for label in SOCIALS: name = label.lower() url = getattr(settings, f"footer_{name}") @@ -100,7 +112,7 @@ def footer() -> None: ui.link( "Privacy policy", settings.footer_privacy_url, new_tab=True ).classes("text-white").mark("footer-privacy") - with ui.column().classes("w-full max-w-4xl mx-auto gap-0 text-caption"): + with ui.column().classes(f"w-full {CONTENT_WIDTH} mx-auto gap-0 text-caption"): if settings.footer_address: ui.label(settings.footer_address) ui.label(f"© {date.today().year} VIVES. All rights reserved.") diff --git a/frontend/src/pmp_frontend/users_page.py b/frontend/src/pmp_frontend/users_page.py index 878e394..0f0ebff 100644 --- a/frontend/src/pmp_frontend/users_page.py +++ b/frontend/src/pmp_frontend/users_page.py @@ -16,6 +16,7 @@ role_page, token, ) +from pmp_frontend.theme import BREAK_ANYWHERE from pmp_frontend.user_import import ( ROLES, YEARS, @@ -37,8 +38,20 @@ "sortable": True, "align": "left", }, - {"name": "email", "label": "Email", "field": "email", "align": "left"}, - {"name": "github", "label": "GitHub", "field": "github", "align": "left"}, + { + "name": "email", + "label": "Email", + "field": "email", + "align": "left", + "classes": BREAK_ANYWHERE, + }, + { + "name": "github", + "label": "GitHub", + "field": "github", + "align": "left", + "classes": BREAK_ANYWHERE, + }, { "name": "role", "label": "Role", diff --git a/frontend/tests/test_navigation.py b/frontend/tests/test_navigation.py index 2532c05..a6f9e62 100644 --- a/frontend/tests/test_navigation.py +++ b/frontend/tests/test_navigation.py @@ -117,3 +117,16 @@ async def test_footer_links_come_from_the_environment( await user.should_see("VIVES Kortrijk · Doorniksesteenweg 145") youtube = user.find(marker="footer-youtube").elements.pop() assert youtube.props["href"] == "https://www.youtube.com/vivesvideo" + + +async def test_tables_fit_the_screen(user: User): + await ready_to_work(user, "superuser") + await user.should_see(marker="users", retries=30) + + # The wide content column, and email addresses that may break (#89). + columns = user.find(kind=ui.column).elements + assert any("max-w-7xl" in column.classes for column in columns) + table = user.find(marker="users").elements.pop() + assert isinstance(table, ui.table) + email = next(c for c in table.columns if c["name"] == "email") + assert email["classes"] == "break-anywhere"