Skip to content

Commit

Permalink
Merge pull request #3572 from opensafely-core/staff-user-templates
Browse files Browse the repository at this point in the history
Restyles staff area user templates
  • Loading branch information
tomodwyer authored Sep 18, 2023
2 parents 7dbe691 + 0035654 commit b71d113
Show file tree
Hide file tree
Showing 16 changed files with 695 additions and 1,015 deletions.
36 changes: 11 additions & 25 deletions staff/views/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def post(self, request, *args, **kwargs):
@method_decorator(require_permission("user_manage"), name="dispatch")
class UserCreate(FormView):
form_class = UserCreateForm
template_name = "staff/user_create.html"
template_name = "staff/user/create.html"

def get_initial(self):
initial = {}
Expand Down Expand Up @@ -95,7 +95,7 @@ class UserDetailWithEmail(UpdateView):
model = User
slug_field = "username"
slug_url_kwarg = "username"
template_name = "staff/user_detail_with_email.html"
template_name = "staff/user/detail_with_email.html"

def get_context_data(self, **kwargs):
orgs = [
Expand Down Expand Up @@ -131,7 +131,7 @@ class UserDetailWithOAuth(UpdateView):
model = User
slug_field = "username"
slug_url_kwarg = "username"
template_name = "staff/user_detail_with_oauth.html"
template_name = "staff/user/detail_with_oauth.html"

@transaction.atomic()
def form_valid(self, form):
Expand All @@ -152,24 +152,9 @@ def get_context_data(self, **kwargs):
jobs = Job.objects.filter(job_request__created_by=self.object).order_by(
"-created_at"
)
orgs = [
{
"name": m.org.name,
"roles": sorted(r.display_name for r in m.roles),
"staff_url": m.org.get_staff_url(),
}
for m in self.object.org_memberships.order_by("org__name")
]
projects = [
{
"name": m.project.title,
"roles": sorted(r.display_name for r in m.roles),
"staff_url": m.project.get_staff_url(),
}
for m in self.object.project_memberships.order_by(
"project__number", Lower("project__name")
)
]
orgs = self.object.orgs.order_by(Lower("name"))
projects = self.object.projects.order_by("number", Lower("name"))

return super().get_context_data(**kwargs) | {
"applications": applications,
"copiloted_projects": copiloted_projects,
Expand Down Expand Up @@ -199,7 +184,8 @@ def get_initial(self):
@method_decorator(require_permission("user_manage"), name="dispatch")
class UserList(ListView):
model = User
template_name = "staff/user_list.html"
paginate_by = 25
template_name = "staff/user/list.html"

def get_context_data(self, **kwargs):
all_roles = [name for name, value in inspect.getmembers(roles, inspect.isclass)]
Expand Down Expand Up @@ -229,7 +215,7 @@ def get_queryset(self):
is_github_user=Exists(social_auths),
org_exists=Exists(orgs),
project_exists=Exists(projects),
).order_by(Lower("username"))
).order_by_name()

# filter on the search query
if q := self.request.GET.get("q"):
Expand Down Expand Up @@ -262,7 +248,7 @@ def get_queryset(self):
@method_decorator(require_permission("user_manage"), name="dispatch")
class UserRoleList(FormView):
form_class = RolesForm
template_name = "staff/user_role_list.html"
template_name = "staff/user/role_list.html"

def dispatch(self, request, *args, **kwargs):
self.user = get_object_or_404(User, username=self.kwargs["username"])
Expand Down Expand Up @@ -300,7 +286,7 @@ def get_initial(self):
@method_decorator(require_permission("user_manage"), name="dispatch")
class UserSetOrgs(FormView):
form_class = UserOrgsForm
template_name = "staff/user_set_orgs.html"
template_name = "staff/user/set_orgs.html"

def dispatch(self, request, *args, **kwargs):
self.user = get_object_or_404(User, username=self.kwargs["username"])
Expand Down
2 changes: 1 addition & 1 deletion templates/_components/card/card.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<section {% attrs class id %} {% if title %}aria-labelledby="{{ title | slugify }}-title"{% endif %}>
<div class="bg-white shadow">
{% if title or subtitle or button %}
<div class="flex flex-wrap gap-2 items-center justify-between px-4 py-2 sm:px-6 sm:py-4 sm:flex-nowrap {{ header_class }}">
<div class="flex flex-wrap gap-2 items-center justify-between px-4 py-2 sm:px-6 sm:py-4 {{ header_class }}">
<div>
{% if title %}
<h2 id="{{ title | slugify }}-title" class="text-xl font-semibold tracking-tight text-slate-900">
Expand Down
38 changes: 24 additions & 14 deletions templates/staff/project_create.htmx.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
<div id="modal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create a project</h5>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% #card container=True title="Create an organisation" %}
<form method="POST" hx-post="{{ post_url }}">
{% csrf_token %}

<div class="modal-body">
{% include "staff/project_create.form.html" %}
</div>
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{% #alert variant="danger" class="mb-6" %}
{{ error }}
{% /alert %}
{% endfor %}
{% endif %}

<div class="flex flex-col items-stretch gap-y-6 w-full max-w-3xl mb-6">
{% form_select field=form.fields.org choices=form.fields.org.choices selected=form.org.value id="id_org" name="org" label="Select an org" %}
{% form_select field=form.fields.copilot choices=form.fields.copilot.choices selected=form.copilot.value id="id_copilot" name="copilot" label="Select a user to co-pilot this project" %}
{% form_input field=form.name label="Project name"%}
{% form_input field=form.application_url label="Application URL" %}
{% form_input field=form.number label="Project number" %}
</div>

<div class="flex flex-row flex-wrap gap-2">
{% #button variant="success" type="submit" %}Add project{% /button %}
{% #button variant="danger" id="closeModal" %}Cancel{% /button %}
</div>
</div>
</div>
</form>
{% /card %}
81 changes: 81 additions & 0 deletions templates/staff/user/create.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{% extends "staff/base-tw.html" %}

{% load static %}

{% block extra_styles %}
<link rel="stylesheet" href="{% static 'vendor/select2.min.css' %}">
<link rel="stylesheet" href="{% static 'vendor/select2-bootstrap4.min.css' %}">
{% endblock %}

{% block metatitle %}Staff Area: Create an interactive user | OpenSAFELY Jobs{% endblock metatitle %}

{% block breadcrumbs %}
{% #breadcrumbs %}
{% url "staff:index" as staff_url %}
{% url "staff:user-list" as staff_user_list_url %}
{% breadcrumb title="Staff area" url=staff_url %}
{% breadcrumb title="Users" url=staff_user_list_url %}
{% breadcrumb title="Create an interactive user" active=True %}
{% /breadcrumbs %}
{% endblock breadcrumbs %}

{% block hero %}
{% #staff_hero title="Create an interactive user" %}
<p>
Creating a user here will set up an account for a user who can only use
the Interactive portion of the site. They will be emailed with a link
to set their password. Please ensure users are part of an
<strong>approved application</strong>.
</p>
{% /staff_hero %}
{% endblock hero %}

{% block content %}
<form method="POST">
{% csrf_token %}

{% #card title="User details" class="max-w-3xl" container=True %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{% #alert variant="danger" class="mb-6" %}
{{ error }}
{% /alert %}
{% endfor %}
{% endif %}

<div class="flex flex-col items-stretch gap-y-6 w-full max-w-3xl mb-6">
{% fragment as select_hint_text %}
If the project doesn't exist, you can
{% url "staff:project-create" as staff_project_create_url %}
{% var new_project_url=staff_project_create_url|add:"?next="|add:request.path %}
{% link href=new_project_url text="add a new project" append_after="." hx-get=new_project_url hx-target="dialog#addNewProject" hx-trigger="click" %}
{% endfragment %}
{% form_select field=form.fields.project choices=form.fields.project.choices selected=form.project.value id="id_project" name="project" label="Select a project" hint_text=select_hint_text %}
{% form_input field=form.name label="Name" %}
{% form_input field=form.email label="Email address" inputmode="email" %}
</div>

{% #button variant="success" type="submit" %}
Create
{% /button %}
{% /card %}
</form>
<dialog class="max-w-lg w-full" id="addNewProject"></dialog>
{% endblock content %}

{% block extra_js %}
<script type="text/javascript" src="{% static 'vendor/htmx.min.js' %}"></script>
<script nonce="{{ request.csp_nonce }}">
htmx.on("htmx:afterSwap", (e) => {
const modal = e.target;
modal.showModal();

const closeModalBtn = document.getElementById("closeModal");
if (closeModalBtn) {
closeModalBtn.addEventListener("click", () => {
closeModalBtn.closest("dialog").close();
});
}
});
</script>
{% endblock %}
72 changes: 72 additions & 0 deletions templates/staff/user/detail_with_email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{% extends "staff/base-tw.html" %}

{% load humanize %}

{% block metatitle %}Staff Area: {{ user.name }} | OpenSAFELY Jobs{% endblock metatitle %}

{% block breadcrumbs %}
{% #breadcrumbs %}
{% url "staff:index" as staff_url %}
{% url "staff:user-list" as staff_user_list_url %}
{% breadcrumb title="Staff area" url=staff_url %}
{% breadcrumb title="Users" url=staff_user_list_url %}
{% breadcrumb title=user.username active=True %}
{% /breadcrumbs %}
{% endblock breadcrumbs %}

{% block hero %}
{% #staff_hero title="User: "|add:user.name %}
<div class="flex flex-row gap-2 mt-2">
{% #button type="link" href=user.get_staff_roles_url variant="danger" %}
Edit roles
{% /button %}
</div>
{% /staff_hero %}
{% endblock hero %}

{% block content %}
<div class="flex flex-col gap-4">
<form method="POST" class="flex flex-col gap-4">
{% csrf_token %}

{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{% #alert variant="danger" class="mb-6" %}
{{ error }}
{% /alert %}
{% endfor %}
{% endif %}

{% #card title="User details" container=True container_class="flex flex-col items-start gap-4" %}
{% form_input field=form.fullname label="Full name" class="max-w-prose w-full" %}
{% form_input field=form.email label="Email" class="max-w-prose w-full" %}
{% #button type="submit" variant="success" %}Update details{% /button %}
{% /card %}
</form>

{% url "staff:user-set-orgs" username=user.username as staff_user_set_orgs_url %}
{% #card title="Organisations" button=True button_text="Add to organisation" button_href=staff_user_set_orgs_url %}
{% #list_group %}
{% for org in orgs %}
{% #list_group_item href=org.get_staff_url %}
{{ org.name }}
{% /list_group_item %}
{% empty %}
{% list_group_empty icon=True title="No organisations" description="This user is not a member of any organisations" %}
{% endfor %}
{% /list_group %}
{% /card %}

{% #card title="Projects" %}
{% #list_group %}
{% for project in projects %}
{% #list_group_item href=project.get_staff_url %}
{{ project.name }}
{% /list_group_item %}
{% empty %}
{% list_group_empty icon=True title="No projects" description="This user is not a member of any projects" %}
{% endfor %}
{% /list_group %}
{% /card %}
</div>
{% endblock content %}
Loading

0 comments on commit b71d113

Please sign in to comment.