Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 |

Expand Down
18 changes: 15 additions & 3 deletions frontend/src/pmp_frontend/theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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; }}
</style>
"""

Expand Down Expand Up @@ -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()

Expand All @@ -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}")
Expand All @@ -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.")
17 changes: 15 additions & 2 deletions frontend/src/pmp_frontend/users_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
role_page,
token,
)
from pmp_frontend.theme import BREAK_ANYWHERE
from pmp_frontend.user_import import (
ROLES,
YEARS,
Expand All @@ -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",
Expand Down
13 changes: 13 additions & 0 deletions frontend/tests/test_navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Loading