diff --git a/dashboard/dashboard/static/project-detail.css b/dashboard/dashboard/static/project-detail.css index ce44664..0894d03 100644 --- a/dashboard/dashboard/static/project-detail.css +++ b/dashboard/dashboard/static/project-detail.css @@ -1,4 +1,7 @@ -table.objectives tr.objective td.name {background-color: #205067; color: white; font-weight: bold;} +table.objectives tr.objective td.name {background-color: #205067; color: white; font-weight: bold; cursor: pointer; user-select: none; border: 0.5px solid #366177;} +table.objectives tr.objective td.name::before {content: "▶"; font-size: 0.7em; display: inline-block; transform: rotate(90deg); margin-right: 0.4em;} +table.objectives tbody.collapsed tr.objective td.name::before {content: "▶"; transform: rotate(0deg);} +table.objectives tbody.collapsed tr:not(.objective) {display: none;} table.objectives tr.level {background-color: #f0f0f0; font-weight: bold;} table.objectives td p, th p {margin: .2rem 0} diff --git a/dashboard/dashboard/templates/base.html b/dashboard/dashboard/templates/base.html index 3e4f72a..e08b6f1 100644 --- a/dashboard/dashboard/templates/base.html +++ b/dashboard/dashboard/templates/base.html @@ -12,5 +12,6 @@ {% block content %}{% endblock %} + {% block eventlisteners %}{% endblock %} \ No newline at end of file diff --git a/dashboard/projects/templates/projects/project.html b/dashboard/projects/templates/projects/project.html index 1e5bce4..0fe3f0e 100644 --- a/dashboard/projects/templates/projects/project.html +++ b/dashboard/projects/templates/projects/project.html @@ -58,3 +58,43 @@

{{ project }}

{% endblock content %} + +{% block eventlisteners %} + +{% endblock %} diff --git a/dashboard/staticfiles/project-detail.css b/dashboard/staticfiles/project-detail.css index ce44664..0894d03 100644 --- a/dashboard/staticfiles/project-detail.css +++ b/dashboard/staticfiles/project-detail.css @@ -1,4 +1,7 @@ -table.objectives tr.objective td.name {background-color: #205067; color: white; font-weight: bold;} +table.objectives tr.objective td.name {background-color: #205067; color: white; font-weight: bold; cursor: pointer; user-select: none; border: 0.5px solid #366177;} +table.objectives tr.objective td.name::before {content: "▶"; font-size: 0.7em; display: inline-block; transform: rotate(90deg); margin-right: 0.4em;} +table.objectives tbody.collapsed tr.objective td.name::before {content: "▶"; transform: rotate(0deg);} +table.objectives tbody.collapsed tr:not(.objective) {display: none;} table.objectives tr.level {background-color: #f0f0f0; font-weight: bold;} table.objectives td p, th p {margin: .2rem 0} diff --git a/dashboard/test_browser.py b/dashboard/test_browser.py index 5bc8fa3..ac74082 100644 --- a/dashboard/test_browser.py +++ b/dashboard/test_browser.py @@ -189,3 +189,36 @@ def test_commitment_table(page): def test_last_review(page): expect(page.get_by_role("textbox", name="Last review:")).to_have_value("2024-12-16") + + +def test_collapsing_objectives(page): + """Check that objective rows collapse/expand on click and the state persists in browser's local storage.""" + + storage_key = "collapsed_objectives_1" + tbody = page.locator("tbody#colourfulness") + + # Clear any leftover state. + page.evaluate(f"localStorage.removeItem('{storage_key}')") + + # Colourfulness objective is not collapsed by default. + assert not page.evaluate("document.querySelector('tbody#colourfulness').classList.contains('collapsed')") + + # Click objective name, check that it collapses + tbody.locator("tr.objective td.objective.name").click() + assert page.evaluate("document.querySelector('tbody#colourfulness').classList.contains('collapsed')") + + # Check that it is written to localStorage. + stored = page.evaluate(f"JSON.parse(localStorage.getItem('{storage_key}') || '[]')") + assert "colourfulness" in stored + + # Reload the page, check that the objective remains collapsed. + page.reload() + assert page.evaluate("document.querySelector('tbody#colourfulness').classList.contains('collapsed')") + + # Click objective to expand, check that it is no longer collapsed. + page.locator("tbody#colourfulness tr.objective td.objective.name").click() + assert not page.evaluate("document.querySelector('tbody#colourfulness').classList.contains('collapsed')") + + # Check that it is removed from localStorage. + stored = page.evaluate(f"JSON.parse(localStorage.getItem('{storage_key}') || '[]')") + assert "colourfulness" not in stored