diff --git a/hypha/apply/funds/templates/funds/reviewer_leaderboard.html b/hypha/apply/funds/templates/funds/reviewer_leaderboard.html index e2caa5e493..26b2491d80 100644 --- a/hypha/apply/funds/templates/funds/reviewer_leaderboard.html +++ b/hypha/apply/funds/templates/funds/reviewer_leaderboard.html @@ -9,26 +9,6 @@ {% adminbar %} {% slot header %}{% trans "Reviewer leaderboard" %}{% endslot %} {% slot sub_heading %}{% trans "Track and explore the reviews" %}{% endslot %} - - {% if request.user.is_apply_staff %} - <div class="flex mt-2 md:m-0 gap-3 justify-center items-center font-medium uppercase"> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" - href="{% url 'apply:submissions:list' %}" - title="Goto all submissions list page" - > - {% trans "All" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:staff_assignments' %}"> - {% trans "Staff assignments" %} - </a> - <a class="px-3 py-2 bg-slate-50 rounded text-gray-800" href="{% url 'apply:submissions:reviewer_leaderboard' %} aria-current="page""> - {% trans "Reviews" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:result' %}"> - {% trans "Results" %} - </a> - </div> - {% endif %} {% endadminbar %} <div class="wrapper wrapper--large wrapper--inner-space-medium"> diff --git a/hypha/apply/funds/templates/funds/round.html b/hypha/apply/funds/templates/funds/round.html index 3577b4c7f6..c3b5e925cc 100644 --- a/hypha/apply/funds/templates/funds/round.html +++ b/hypha/apply/funds/templates/funds/round.html @@ -9,7 +9,7 @@ {% if settings.utils.SystemMessagesSettings.nav_content %} {{ settings.utils.SystemMessagesSettings.nav_content|safe }} {% else %} - {% include "includes/primarynav-apply.html" %} + {% include "core/navigation/primarynav-apply.html" %} {% endif %} </section> {% endblock %} diff --git a/hypha/apply/funds/templates/funds/staff_assignments.html b/hypha/apply/funds/templates/funds/staff_assignments.html index 6892be7ea8..bf5bae87f9 100644 --- a/hypha/apply/funds/templates/funds/staff_assignments.html +++ b/hypha/apply/funds/templates/funds/staff_assignments.html @@ -9,23 +9,6 @@ {% adminbar %} {% slot header %}{% trans "Staff assignments" %}{% endslot %} {% slot sub_heading %}{% trans "Track and explore the staff assignments" %}{% endslot %} - - {% if request.user.is_apply_staff %} - <div class="flex mt-2 md:m-0 gap-3 justify-center items-center font-medium uppercase"> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:list' %}"> - {% trans "All" %} - </a> - <a class="px-3 py-2 bg-slate-50 rounded text-gray-800" href="{% url 'apply:submissions:staff_assignments' %}" aria-current="page"> - {% trans "Staff assignments" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:reviewer_leaderboard' %}"> - {% trans "Reviews" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:result' %}"> - {% trans "Results" %} - </a> - </div> - {% endif %} {% endadminbar %} <div class="wrapper wrapper--large wrapper--inner-space-medium"> diff --git a/hypha/apply/funds/templates/funds/submissions_overview.html b/hypha/apply/funds/templates/funds/submissions_overview.html index 7c3a160951..77f2725d0f 100644 --- a/hypha/apply/funds/templates/funds/submissions_overview.html +++ b/hypha/apply/funds/templates/funds/submissions_overview.html @@ -9,31 +9,6 @@ {% slot header %}{% trans "Submissions" %}{% endslot %} {% slot sub_heading %}{% trans "Track and explore recent submissions" %}{% endslot %} - {% if request.user.is_apply_staff %} - <div class="flex mt-2 md:m-0 gap-3 justify-center items-center font-medium uppercase"> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" - href="{% url 'apply:submissions:list' %}" - title="Goto all submissions list page" - > - {% trans "All" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" - href="{% url 'apply:submissions:staff_assignments' %}" - > - {% trans "Staff assignments" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" - href="{% url 'apply:submissions:reviewer_leaderboard' %}" - > - {% trans "Reviews" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" - href="{% url 'apply:submissions:result' %}"> - {% trans "Results" %} - </a> - </div> - {% endif %} - {% endadminbar %} <div class="wrapper wrapper--large wrapper--inner-space-medium"> diff --git a/hypha/apply/funds/templates/funds/submissions_result.html b/hypha/apply/funds/templates/funds/submissions_result.html index 501d5087cf..43d7f5f52c 100644 --- a/hypha/apply/funds/templates/funds/submissions_result.html +++ b/hypha/apply/funds/templates/funds/submissions_result.html @@ -7,23 +7,6 @@ {% adminbar %} {% slot header %}{% trans "Submissions results" %}{% endslot %} {% slot sub_heading %}{% trans "Track and explore submission results" %}{% endslot %} - - {% if request.user.is_apply_staff %} - <div class="flex mt-2 md:m-0 gap-3 justify-center items-center font-medium uppercase" hx-boost="true"> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:list' %}"> - {% trans "All" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:staff_assignments' %}"> - {% trans "Staff assignments" %} - </a> - <a class="px-3 py-2 text-gray-300 transition-colors hover:bg-slate-50 rounded hover:text-gray-800" href="{% url 'apply:submissions:reviewer_leaderboard' %}"> - {% trans "Reviews" %} - </a> - <a class="px-3 py-2 bg-slate-50 rounded text-gray-800" href="{% url 'apply:submissions:result' %}" aria-current="page"> - {% trans "Results" %} - </a> - </div> - {% endif %} {% endadminbar %} diff --git a/hypha/apply/funds/urls.py b/hypha/apply/funds/urls.py index 6b11739e06..b7d8db220a 100644 --- a/hypha/apply/funds/urls.py +++ b/hypha/apply/funds/urls.py @@ -1,4 +1,5 @@ from django.urls import include, path +from django.views.generic import RedirectView from hypha.apply.projects import urls as projects_urls @@ -19,7 +20,6 @@ SubmissionDetailView, SubmissionEditView, SubmissionListView, - SubmissionOverviewView, SubmissionPrivateMediaView, SubmissionResultView, SubmissionsByRound, @@ -74,7 +74,11 @@ submission_urls = ( [ - path("", SubmissionOverviewView.as_view(), name="overview"), + path( + "", + RedirectView.as_view(pattern_name="funds:submissions:list"), + name="overview", + ), path("success/<int:pk>/", submission_success, name="success"), path("all/", SubmissionListView.as_view(), name="list"), path("all-beta/", submission_all_beta, name="list-beta"), diff --git a/hypha/apply/home/templates/apply_home/apply_home_page.html b/hypha/apply/home/templates/apply_home/apply_home_page.html index 5e42e9098e..f389c173e4 100644 --- a/hypha/apply/home/templates/apply_home/apply_home_page.html +++ b/hypha/apply/home/templates/apply_home/apply_home_page.html @@ -6,7 +6,7 @@ {% if settings.utils.SystemMessagesSettings.nav_content %} {{ settings.utils.SystemMessagesSettings.nav_content|safe }} {% else %} - {% include "includes/primarynav-apply.html" %} + {% include "core/navigation/primarynav-apply.html" %} {% endif %} </section> {% endblock %} diff --git a/hypha/apply/projects/urls.py b/hypha/apply/projects/urls.py index 774375ee62..a53e310eb1 100644 --- a/hypha/apply/projects/urls.py +++ b/hypha/apply/projects/urls.py @@ -1,4 +1,5 @@ from django.urls import include, path +from django.views.generic import RedirectView from .views import ( CategoryTemplatePrivateMediaView, @@ -16,7 +17,6 @@ ProjectDetailDownloadView, ProjectDetailView, ProjectListView, - ProjectOverviewView, ProjectPrivateMediaView, ProjectSOWDownloadView, ProjectSOWView, @@ -33,7 +33,7 @@ app_name = "projects" urlpatterns = [ - path("", ProjectOverviewView.as_view(), name="overview"), + path("", RedirectView.as_view(pattern_name="apply:projects:all"), name="overview"), path("all/", ProjectListView.as_view(), name="all"), path("invoices/", InvoiceListView.as_view(), name="invoices"), path( diff --git a/hypha/apply/users/decorators.py b/hypha/apply/users/decorators.py index 5f867287af..00f346be8f 100644 --- a/hypha/apply/users/decorators.py +++ b/hypha/apply/users/decorators.py @@ -39,6 +39,12 @@ def is_apply_staff_or_finance(user): return True +def is_apply_staff_or_reviewer_required(user): + if not (user.is_apply_staff or user.is_reviewer): + raise PermissionDenied + return True + + def is_apply_staff_or_finance_or_contracting(user): if not (user.is_apply_staff or user.is_finance or user.is_contracting): raise PermissionDenied @@ -63,6 +69,11 @@ def is_contracting_approver(user): finance_required = [login_required, user_passes_test(is_finance)] +staff_or_reviewer_required = [ + login_required, + user_passes_test(is_apply_staff_or_reviewer_required), +] + staff_or_finance_required = [ login_required, user_passes_test(is_apply_staff_or_finance), @@ -84,3 +95,7 @@ def is_contracting_approver(user): def superuser_decorator(fn): check = user_passes_test(lambda user: user.is_superuser) return check(fn) + + +def has_dashboard_access(user): + return user.can_access_dashboard diff --git a/hypha/core/navigation.py b/hypha/core/navigation.py new file mode 100644 index 0000000000..7b3382ea09 --- /dev/null +++ b/hypha/core/navigation.py @@ -0,0 +1,68 @@ +from django.conf import settings + +nav_items = [ + { + "title": "My Dashboard", + "url": "dashboard:dashboard", + "permission_method": "has_dashboard_access", + }, + { + "title": "Submissions", + "url": "apply:submissions:overview", # kind of basic url to figure out active tab + "permission_method": "is_apply_staff_or_reviewer_required", + "sub_items": [ + { + "title": "All Submissions", + "url": "apply:submissions:list", + "permission_method": "is_apply_staff_or_reviewer_required", + }, + { + "title": "Staff Assignments", + "url": "apply:submissions:staff_assignments", + "permission_method": "is_apply_staff", + }, + { + "title": "Reviews", + "url": "apply:submissions:reviewer_leaderboard", + "permission_method": "is_apply_staff", + }, + { + "title": "Results", + "url": "apply:submissions:result", + "permission_method": "is_apply_staff", + }, + ], + }, + { + "title": "Projects", + "url": "apply:projects:overview", # kind of basic url to figure out active tab + "permission_method": "is_apply_staff_or_finance_or_contracting", + "sub_items": [ + { + "title": "All Projects", + "url": "apply:projects:all", + "permission_method": "is_apply_staff_or_finance_or_contracting", + }, + { + "title": "Invoices", + "url": "apply:projects:invoices", + "permission_method": "is_apply_staff_or_finance", + }, + { + "title": "Reports", + "url": "apply:projects:reports:all", + "permission_method": "is_apply_staff_or_finance", + }, + ], + }, +] + + +if settings.APPLY_NAV_MENU_ITEMS: + nav_items = settings.APPLY_NAV_MENU_ITEMS + +if settings.APPLY_NAV_SUBMISSIONS_ITEMS: + nav_items[1]["sub_items"] = settings.APPLY_NAV_SUBMISSIONS_ITEMS + +if settings.APPLY_NAV_PROJECTS_ITEMS: + nav_items[2]["sub_items"] = settings.APPLY_NAV_PROJECTS_ITEMS diff --git a/hypha/core/templates/core/navigation/primarynav-apply.html b/hypha/core/templates/core/navigation/primarynav-apply.html new file mode 100644 index 0000000000..03c005f856 --- /dev/null +++ b/hypha/core/templates/core/navigation/primarynav-apply.html @@ -0,0 +1,38 @@ +{% load i18n applynav_tags heroicons %} +{% if request.user.is_authenticated %} + <nav role="navigation" aria-label="Primary" class="w-full"> + <ul class="nav nav--primary" role="menubar"> + {% apply_nav_items request.user as nav_items %} + {% for item in nav_items %} + {% url item.url as target_url%} + <li class="nav__item" role="presentation"> + {% if item.sub_items %} + <div class="relative inline-block" x-data="{open: false}"> + <a class="nav__link {% if target_url in request.path %}nav__link--active{% endif %}" + href="{% url item.url %}" + aria-label="{% trans "Menu Item" %}" + aria-haspopup="menu" + aria-expanded="false" + role="menuitem" + @click.prevent="open = ! open"> + {{ item.title }} + {% heroicon_outline "chevron-down" aria_hidden="true" size=16 stroke_width=3 class="inline align-baseline mr-1" %} + </a> + <div x-cloak x-trap="open" x-on:keydown.escape="open = false" x-show="open" x-transition @click.outside="open = false" class="absolute block bg-white min-w-max shadow-lg z-1 mt-7 "> + {% for sub_item in item.sub_items %} + <a class="text-black px-4 py-3 block font-normal hover:bg-mid-grey focus-visible:ring-2" href="{% url sub_item.url %}"> + {{ sub_item.title }} + </a> + {% endfor %} + </div> + </div> + {% else %} + <a class="nav__link {% if target_url in request.path %}nav__link--active{% endif %}" href="{{ target_url }}" role="menuitem"> + {{ item.title }} + </a> + {% endif %} + </li> + {% endfor %} + </ul> + </nav> +{% endif %} diff --git a/hypha/core/templatetags/applynav_tags.py b/hypha/core/templatetags/applynav_tags.py new file mode 100644 index 0000000000..64e6fe0b61 --- /dev/null +++ b/hypha/core/templatetags/applynav_tags.py @@ -0,0 +1,40 @@ +import copy + +from django import template +from django.core.exceptions import PermissionDenied + +from hypha.apply.users import decorators + +from ..navigation import nav_items + +register = template.Library() + + +def has_permission(user, method): + try: + if getattr(decorators, method)(user): + return True + return False + except PermissionDenied: + return False + except Exception: + # just to handle unknown exceptions + return False + + +@register.simple_tag +def apply_nav_items(user): + temp_nav = copy.deepcopy(nav_items) + item_count = 0 + for item in nav_items: + item_count = +1 + removed = False + if not has_permission(user, item["permission_method"]): + temp_nav.remove(item) + removed = True + item_count = -1 + if not removed and "sub_items" in item.keys(): + for sub_item in item["sub_items"]: + if not has_permission(user, sub_item["permission_method"]): + temp_nav[item_count]["sub_items"].remove(sub_item) + return temp_nav diff --git a/hypha/settings/base.py b/hypha/settings/base.py index 2771487c78..66530bf0cd 100644 --- a/hypha/settings/base.py +++ b/hypha/settings/base.py @@ -473,6 +473,12 @@ AWS_MIGRATION_ACCESS_KEY_ID = env.str("AWS_MIGRATION_ACCESS_KEY_ID", "") AWS_MIGRATION_SECRET_ACCESS_KEY = env.str("AWS_MIGRATION_SECRET_ACCESS_KEY", "") +# Apply nav items settings + +APPLY_NAV_MENU_ITEMS = env.json("APPLY_NAV_MENU_ITEMS", "{}") +APPLY_NAV_SUBMISSIONS_ITEMS = env.json("APPLY_NAV_SUBMISSIONS_ITEMS", "{}") +APPLY_NAV_PROJECTS_ITEMS = env.json("APPLY_NAV_PROJECTS_ITEMS", "{}") + # Basic auth settings if env.bool("BASIC_AUTH_ENABLED", False): MIDDLEWARE.insert(0, "baipw.middleware.BasicAuthIPWhitelistMiddleware") diff --git a/hypha/static_src/src/sass/apply/components/_filters.scss b/hypha/static_src/src/sass/apply/components/_filters.scss index fae37cac5d..7b2783c4b1 100644 --- a/hypha/static_src/src/sass/apply/components/_filters.scss +++ b/hypha/static_src/src/sass/apply/components/_filters.scss @@ -7,7 +7,7 @@ right: 0; bottom: 0; left: 0; - z-index: 20; + z-index: 9; display: block; width: 100%; height: 100vh; diff --git a/hypha/templates/base-apply.html b/hypha/templates/base-apply.html index cd0d9d3ae8..59a8841bb2 100644 --- a/hypha/templates/base-apply.html +++ b/hypha/templates/base-apply.html @@ -50,7 +50,7 @@ {% block header_menu %} <section class="header__menus header__menus--desktop"> - {% include "includes/primarynav-apply.html" %} + {% include "core/navigation/primarynav-apply.html" %} </section> {% endblock header_menu %} @@ -81,7 +81,7 @@ </div> </div> - {% include "includes/primarynav-apply.html" %} + {% include "core/navigation/primarynav-apply.html" %} {% if request.user.is_authenticated %} <a href="{% url 'users:account' %}" class="link link--button-transparent link--mobile-standout"> diff --git a/hypha/templates/includes/primarynav-apply-item.html b/hypha/templates/includes/primarynav-apply-item.html deleted file mode 100644 index 1b4ab0397e..0000000000 --- a/hypha/templates/includes/primarynav-apply-item.html +++ /dev/null @@ -1,6 +0,0 @@ -<li class="nav__item" role="presentation"> - {% url url as target_url%} - <a class="nav__link {% if target_url in request.path %}nav__link--active{% endif %}" href="{{ target_url }}" role="menuitem"> - {{ name }} - </a> -</li> diff --git a/hypha/templates/includes/primarynav-apply.html b/hypha/templates/includes/primarynav-apply.html deleted file mode 100644 index 98b4e08bcf..0000000000 --- a/hypha/templates/includes/primarynav-apply.html +++ /dev/null @@ -1,15 +0,0 @@ -{% if request.user.is_authenticated %} - <nav role="navigation" aria-label="Primary" class="w-full"> - <ul class="nav nav--primary" role="menubar"> - {% if request.user.can_access_dashboard %} - {% include "includes/primarynav-apply-item.html" with name="My dashboard" url="dashboard:dashboard" %} - {% endif %} - {% if request.user.is_apply_staff %} - {% include "includes/primarynav-apply-item.html" with name="Submissions" url="funds:submissions:overview" %} - {% include "includes/primarynav-apply-item.html" with name="Projects" url="apply:projects:overview" %} - {% elif request.user.is_finance or request.user.is_contracting %} - {% include "includes/primarynav-apply-item.html" with name="Projects" url="apply:projects:overview" %} - {% endif %} - </ul> - </nav> -{% endif %}