From da5a6cb07e4696c4623cea5cc474ddd0bc5bdcc8 Mon Sep 17 00:00:00 2001 From: Hasan_sh Date: Mon, 27 Nov 2023 17:17:36 +0100 Subject: [PATCH] [UI idea] Tags dropdown (#4759) Fixes #4744 **Structure** - currently, the dropdown displays all tags that: - if used by adventures, at least one adventure must be public, - This ensures that if a teacher uses a tag in private adventures only, this tag won't be visible to other teachers. - are not used by any adventure - (what tag would that be? e.g., a tag is created but then untagged from all adventures that used it) **How to test?** - got to `/customize-adventure/[id]` view - try adding/removing tags **Archive** - the choices we had: - get a tag iff all adventures that use it are public - get a tag iff one or more adventures that use it are public > what would happen if a tag isn't used by any adventure? - hence the choice! - any other thoughts are welcome. --- templates/customize-adventure.html | 21 +++++++++++++----- templates/htmx-tags-dropdown-item.html | 17 ++++++++++++++ templates/htmx-tags-dropdown.html | 12 ++++++++++ templates/htmx-tags-list.html | 22 +++++-------------- .../customize-adventure_page/tags.cy.js | 18 ++++++--------- website/database.py | 12 ++++++++++ website/tags.py | 18 ++++++++++++--- 7 files changed, 83 insertions(+), 37 deletions(-) create mode 100644 templates/htmx-tags-dropdown-item.html create mode 100644 templates/htmx-tags-dropdown.html diff --git a/templates/customize-adventure.html b/templates/customize-adventure.html index bae7ce9968f..405975b773a 100644 --- a/templates/customize-adventure.html +++ b/templates/customize-adventure.html @@ -34,13 +34,14 @@

{{_('general_settings')}}

-
- + + +
{{ render_partial('htmx-tags-list.html', tags=adventure_tags, adventure_id=adventure.id, creator=adventure.creator) }} diff --git a/templates/htmx-tags-dropdown-item.html b/templates/htmx-tags-dropdown-item.html new file mode 100644 index 00000000000..a54f5696725 --- /dev/null +++ b/templates/htmx-tags-dropdown-item.html @@ -0,0 +1,17 @@ + +
{{tag["name"]}}
\ No newline at end of file diff --git a/templates/htmx-tags-dropdown.html b/templates/htmx-tags-dropdown.html new file mode 100644 index 00000000000..0dca89c511a --- /dev/null +++ b/templates/htmx-tags-dropdown.html @@ -0,0 +1,12 @@ + + diff --git a/templates/htmx-tags-list.html b/templates/htmx-tags-list.html index d42bf53425d..26e69c95bab 100644 --- a/templates/htmx-tags-list.html +++ b/templates/htmx-tags-list.html @@ -2,35 +2,23 @@ \ No newline at end of file diff --git a/tests/cypress/e2e/for-teacher_page/customize-adventure_page/tags.cy.js b/tests/cypress/e2e/for-teacher_page/customize-adventure_page/tags.cy.js index f8d7a22973d..39e99a49024 100644 --- a/tests/cypress/e2e/for-teacher_page/customize-adventure_page/tags.cy.js +++ b/tests/cypress/e2e/for-teacher_page/customize-adventure_page/tags.cy.js @@ -8,7 +8,7 @@ describe("Tags of adventures", () => { }) it("has tags input and button", () => { - cy.get("#input_adventure_tags") + cy.get("#search_tags_input") .should("be.visible") .should("be.empty") @@ -18,26 +18,23 @@ describe("Tags of adventures", () => { it("has no tags initially", () => { cy.get("#tags-list") - .should("be.visible") - .get("#no-tags") - .should("be.visible") + .should("be.not.visible") }) it("adds a tag to adventure by pressing enter within the input field", () => { - cy.get("#input_adventure_tags") + cy.get("#search_tags_input") .should("be.empty") .type("statements{enter}") cy.wait(500) cy.get("#tags-list") .should("be.visible") - .get("#no-tags") - .should("be.hidden") + cy.get("#tags-list li") .should("include.text", "statements") }) it("adds a tag to adventure by pressing the add button", () => { - cy.get("#input_adventure_tags") + cy.get("#search_tags_input") .should("be.empty") .type("training") cy.get("#add_adventure_tags") @@ -46,8 +43,7 @@ describe("Tags of adventures", () => { cy.wait(500) cy.get("#tags-list") .should("be.visible") - .get("#no-tags") - .should("be.hidden") + cy.get("#tags-list li") .should("include.text", "training") }) @@ -59,7 +55,7 @@ describe("Tags of adventures", () => { times: 1, }).as("createTag") - cy.get("#input_adventure_tags") + cy.get("#search_tags_input") .should("be.empty") .type("training{enter}") cy.wait("@createTag").should('have.nested.property', 'response.statusCode', 400) diff --git a/website/database.py b/website/database.py index 44c5a11b2b5..4a848564376 100644 --- a/website/database.py +++ b/website/database.py @@ -611,6 +611,15 @@ def read_tag(self, tag_name): def read_tags(self, tags): return [self.read_tag(name) for name in tags] + def read_public_tags(self): + """Public tags are tagged within one or more public adventure or those that aren't in use.""" + all_tags = TAGS.scan() + public_tags = [] + for tag in all_tags: + if not tag["tagged_in"] or any([adv["public"] for adv in tag["tagged_in"]]): + public_tags.append(tag) + return public_tags + def read_tags_by_username(self, username): tags = TAGS.get_many({"creator": username}) return tags if tags else {} @@ -645,6 +654,9 @@ def get_second_teacher_adventures(self, classes, teacher): def all_adventures(self): return ADVENTURES.scan() + def public_adventures(self): + return ADVENTURES.get_many({"public": True}) + def get_student_classes_ids(self, username): ids = USERS.get({"username": username}).get("classes") return list(ids) if ids else [] diff --git a/website/tags.py b/website/tags.py index ce17333eb66..38d2d319b11 100644 --- a/website/tags.py +++ b/website/tags.py @@ -22,6 +22,20 @@ def __init__(self, db: Database, achievements: Achievements): self.db = db self.achievements = achievements + @route("/", methods=["GET"]) + @route("/", methods=["GET"], defaults={"adventure_id": None}) + @requires_teacher + def get_public_tags(self, user, adventure_id): + public_tags = self.db.read_public_tags() + adventure_id = request.args.get("adventure_id") + if adventure_id: + adventure = self.db.get_adventure(adventure_id) + # exclude current adventure's tags + public_tags = list(filter(lambda t: t["name"] not in adventure.get("tags", []), public_tags)) + + return jinja_partials.render_partial('htmx-tags-dropdown.html', + tags=public_tags, adventure_id=adventure_id, creator=user) + @route("/create/", methods=["POST"]) @route("/create//", methods=["POST"]) @requires_teacher @@ -91,6 +105,4 @@ def delete_from_adventure(self, user, tag, adventure_id): adventure_tags = list(filter(lambda name: name != tag_name, adventure_tags)) self.db.update_adventure(adventure_id, {"tags": adventure_tags}) - return adventure_tags, 200 - # return jinja_partials.render_partial('htmx-tags-list.html', tags=adventure_tags, - # adventure_id=adventure_id, creator=user["username"]) + return jinja_partials.render_partial('htmx-tags-dropdown-item.html', tag=db_tag, adventure_id=adventure_id)